[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[GNUnet-SVN] r3028 - GNUnet/src/util/os
From: |
grothoff |
Subject: |
[GNUnet-SVN] r3028 - GNUnet/src/util/os |
Date: |
Fri, 23 Jun 2006 08:05:06 -0700 (PDT) |
Author: grothoff
Date: 2006-06-23 08:05:03 -0700 (Fri, 23 Jun 2006)
New Revision: 3028
Added:
GNUnet/src/util/os/semaphore.c
GNUnet/src/util/os/semaphore.c~
GNUnet/src/util/os/semaphoretest.c
GNUnet/src/util/os/semaphoretest.c~
Log:
more refactoring
Added: GNUnet/src/util/os/semaphore.c
===================================================================
--- GNUnet/src/util/os/semaphore.c 2006-06-23 15:04:37 UTC (rev 3027)
+++ GNUnet/src/util/os/semaphore.c 2006-06-23 15:05:03 UTC (rev 3028)
@@ -0,0 +1,619 @@
+/*
+ This file is part of GNUnet.
+ (C) 2001, 2002, 2003, 2004 Christian Grothoff (and other contributing
authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file util/os/semaphore.c
+ * @brief functions related to IPC synchronization
+ */
+
+#include "gnunet_util_os.h"
+#include "platform.h"
+
+#if SOLARIS || FREEBSD || OSX
+#include <semaphore.h>
+#endif
+#if SOMEBSD
+# include <sys/file.h>
+#endif
+#if LINUX
+# include <sys/ipc.h>
+# include <sys/sem.h>
+#endif
+#ifdef _MSC_VER
+#include <semaphore.h>
+#endif
+
+/**
+ * Shall we use error-checking (slow)
+ * mutexes (e.g. for debugging)
+ */
+#define USE_CHECKING_MUTEX 1
+
+typedef struct IPC_SEMAPHORE {
+ struct GE_Context * ectx;
+#if SOLARIS || FREEBSD5 || OSX
+ sem_t * internal;
+#elif WINDOWS
+ HANDLE internal;
+#elif LINUX
+ int internal;
+ char * filename;
+#elif SOMEBSD
+ int initialValue;
+ int fd;
+ Mutex internalLock;
+ char * filename;
+#elif _MSC_VER
+ int internal; /* KLB_FIX */
+ char * filename;
+#else
+ /* PORT-ME! */
+#endif
+} IPC_Semaphore;
+
+
+#if LINUX
+/* IPC semaphore kludging for linux */
+
+/* Why don't we start at count 0 and increment when opening? */
+#define PROCCOUNT 10000
+
+/**
+ * Implementation for a single semaphore actually uses three :
+ *
+ * 0 : actual semaphore value
+ * 1 : process counter
+ * 2 : lock
+ */
+
+/* Various operations */
+static struct sembuf op_lock[2] = {
+ {2, 0, 0}, /* wait for [2] (lock) to equal 0 */
+ {2, 1, SEM_UNDO} /* then increment [2] to 1 - this locks it */
+ /* UNDO to release the lock if processes exits */
/* before explicitly unlocking */
+};
+static struct sembuf op_unlock[1] = {
+ {2, -1, SEM_UNDO} /* decrement [2] (lock) back to 0 */
+};
+static struct sembuf op_endcreate[2] = {
+ {1, -1, SEM_UNDO},/* decrement [1] (proc counter) with undo on exit */
+ /* UNDO to adjust proc counter if process exits
+ before explicitly calling sem_close() */
+ {2, -1, SEM_UNDO} /* then decrement [2] (lock) back to 0 */
+};
+static struct sembuf op_close[3] = {
+ {2, 0, 0}, /* wait for [2] (lock) to equal 0 */
+ {2, 1, SEM_UNDO}, /* then increment [2] to 1 - this locks it */
+ {1, 1, SEM_UNDO} /* then increment [1] (proc counter) */
+};
+#endif
+
+#if SOMEBSD
+static void FLOCK(int fd,
+ int operation) {
+ int ret;
+
+ ret = -1;
+ while (ret == -1) {
+ ret = flock(fd,
+ operation);
+ if (ret == -1) {
+ if (errno != EINTR) {
+ GE_LOG_STRERROR(NULL,
+ GE_ERROR | GE_USER | GE_ADMIN | GE_BULK,
+ "flock");
+ return;
+ }
+ }
+ }
+ fsync(fd);
+}
+static int LSEEK(int fd,
+ off_t pos,
+ int mode) {
+ int ret;
+ ret = lseek(fd,
+ pos,
+ mode);
+ if (ret == -1)
+ GE_LOG_STRERROR(NULL,
+ GE_ERROR | GE_USER | GE_ADMIN | GE_BULK,
+ "lseek");
+ return ret;
+}
+#endif
+
+IPC_Semaphore *
+IPC_SEMAPHORE_CREATE(struct GE_Context * ectx,
+ const char * basename,
+ const unsigned int initialValue) {
+ /* Could older FreeBSD use this too since this code can shorten the IPC name
*/
+#if SOLARIS || OSX || FREEBSD5
+ char * noslashBasename;
+ int i;
+ IPC_Semaphore * rret;
+ IPC_Semaphore_Internal * ret;
+
+ ret = MALLOC(sizeof(IPC_Semaphore));
+ ret->ectx = ectx;
+ noslashBasename = STRDUP(basename);
+ for (i=strlen(noslashBasename);i>0;i--)
+ if (noslashBasename[i] == '/')
+ noslashBasename[i] = '.'; /* first character MUST be /, but Solaris
+ forbids it afterwards */
+ noslashBasename[0] = '/';
+ ret->internal = sem_open(noslashBasename,
+ O_CREAT,
+ S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP, /* 660 */
+ initialValue);
+ while ( (ret->internal == (void *) SEM_FAILED)
+ && (errno == ENAMETOOLONG) ) {
+ if (strlen(noslashBasename) < 4)
+ break; /* definitely OS error... */
+ noslashBasename[strlen(noslashBasename)/2] = '\0'; /* cut in half */
+ ret->internal = sem_open(noslashBasename,
+ O_CREAT,
+ S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP, /* 660 */
+ initialValue);
+ }
+ if (ret->internal == (void *) SEM_FAILED)
+ GE_DIE_STRERROR_FILE(ectx,
+ GE_FATAL | GE_USER | GE_DEVELOPER | GE_IMMEDIATE,
+ "sem_open",
+ noslashBasename);
+ FREE(noslashBasename);
+ return ret;
+
+ /* *********************** fix from here *********** */
+#elif WINDOWS
+ char * noslashBasename;
+ int i;
+ IPC_Semaphore * rret;
+ IPC_Semaphore_Internal * ret;
+ SECURITY_ATTRIBUTES sec;
+ DWORD dwErr;
+
+ rret = MALLOC(sizeof(IPC_Semaphore));
+ ret = MALLOC(sizeof(IPC_Semaphore_Internal));
+ rret->platform = ret;
+ noslashBasename = STRDUP(basename);
+ for (i=strlen(noslashBasename);i>0;i--)
+ if (noslashBasename[i] == '\\')
+ noslashBasename[i] = '.'; /* must not contain backslashes */
+
+ sec.nLength = sizeof(SECURITY_ATTRIBUTES);
+ sec.bInheritHandle = TRUE;
+ sec.lpSecurityDescriptor = NULL;
+
+ ret->internal = CreateSemaphore(&sec, initialValue, LONG_MAX,
noslashBasename);
+ dwErr = GetLastError();
+ if (! ret->internal && dwErr == ERROR_ALREADY_EXISTS) {
+ ret->internal = OpenSemaphore(SEMAPHORE_MODIFY_STATE, TRUE,
noslashBasename);
+ dwErr = GetLastError();
+ }
+ if (! ret->internal) {
+ LOG(LOG_FAILURE, _("Can't create semaphore: %i"), dwErr);
+ DIE_FILE_STRERROR("sem_open", noslashBasename);
+ }
+ FREE(noslashBasename);
+ return rret;
+#elif LINUX
+ union semun {
+ int val;
+ struct semid_ds *buf;
+ ushort *array;
+ } semctl_arg;
+ IPC_Semaphore * rret;
+ IPC_Semaphore_Internal * ret;
+ key_t key;
+ FILE * fp;
+ int pcount;
+
+ rret = MALLOC(sizeof(IPC_Semaphore));
+ ret = MALLOC(sizeof(IPC_Semaphore_Internal));
+ rret->platform = ret;
+
+ fp = FOPEN(basename, "a+");
+ if (NULL == fp) {
+ LOG_FILE_STRERROR_FL(LOG_FATAL,
+ "fopen",
+ basename,
+ filename,
+ linenumber);
+ FREE(rret);
+ FREE(ret);
+ return NULL;
+ }
+ fclose(fp);
+
+ key = ftok(basename,'g');
+
+again:
+
+ ret->internal = semget(key, 3, IPC_CREAT|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP);
+
+ if (ret->internal == -1)
+ DIE_STRERROR_FL("semget", filename, linenumber);
+ if (semop(ret->internal, &op_lock[0], 2) < 0) {
+ if (errno == EINVAL)
+ goto again;
+ else
+ DIE_STRERROR_FL("semop", filename, linenumber);
+ }
+
+ /* get process count */
+ if ( (pcount = semctl(ret->internal, 1, GETVAL, 0)) < 0)
+ DIE_STRERROR_FL("semctl", filename, linenumber);
+ if (pcount==0) {
+ semctl_arg.val = initialValue;
+ if (semctl(ret->internal, 0, SETVAL, semctl_arg) < 0)
+ DIE_STRERROR_FL("semtcl", filename, linenumber);
+ semctl_arg.val = PROCCOUNT;
+ if (semctl(ret->internal, 1, SETVAL, semctl_arg) < 0)
+ DIE_STRERROR_FL("semtcl", filename, linenumber);
+ }
+
+ if (semop(ret->internal, &op_endcreate[0], 2) < 0)
+ DIE_STRERROR_FL("semop", filename, linenumber);
+
+ ret->filename = STRDUP(basename);
+ return rret;
+#elif SOMEBSD
+ int fd;
+ int cnt;
+ IPC_Semaphore * rret;
+ IPC_Semaphore_Internal * ret;
+
+ rret = MALLOC(sizeof(IPC_Semaphore));
+ ret = MALLOC(sizeof(IPC_Semaphore_Internal));
+ rret->platform = ret;
+
+ MUTEX_CREATE(&ret->internalLock);
+ ret->filename = STRDUP(basename);
+ fd = -1;
+ while (fd == -1) {
+ fd = fileopen(basename,
+ O_CREAT|O_RDWR|O_EXCL,
+ S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP /* 660 */);
+ if ( (fd == -1) &&
+ (errno == EEXIST) ) {
+ /* try without creation */
+ fd = fileopen(basename,
+ O_RDWR,
+ S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP /* 660 */);
+ /* possibly the file was deleted in the meantime,
+ then try again with O_CREAT! */
+ if ( (fd == -1) &&
+ (errno != ENOENT) )
+ break;
+ }
+ }
+ if (fd == -1) {
+ LOG_FILE_STRERROR(LOG_ERROR, "open", ret->filename);
+ MUTEX_DESTROY(&ret->internalLock);
+ FREE(ret->filename);
+ FREE(ret);
+ FREE(rret);
+ return NULL;
+ }
+ FLOCK(fd, LOCK_EX);
+ if (sizeof(int) != READ(fd, &cnt, sizeof(int))) {
+ cnt = htonl(initialValue);
+ LSEEK(fd, 0, SEEK_SET);
+ if (sizeof(int) != WRITE(fd, &cnt, sizeof(int)))
+ LOG_FILE_STRERROR(LOG_WARNING, "write", basename);
+ }
+ LSEEK(fd, sizeof(int), SEEK_SET);
+ if (sizeof(int) != READ(fd, &cnt, sizeof(int)))
+ cnt = htonl(1);
+ else
+ cnt = htonl(ntohl(cnt)+1);
+ LSEEK(fd, sizeof(int), SEEK_SET);
+ if (sizeof(int) != WRITE(fd, &cnt, sizeof(int)))
+ LOG_FILE_STRERROR(LOG_WARNING, "write", basename);
+ FLOCK(fd, LOCK_UN);
+ ret->fd = fd;
+ ret->initialValue = initialValue;
+ return rret;
+#else
+ #ifndef _MSC_VER
+ #warning Port IPC.
+ return NULL;
+ #else
+ return NULL;
+ #endif
+#endif
+}
+
+void ipc_semaphore_up_(IPC_Semaphore * rsem,
+ const char * filename,
+ const int linenumber) {
+ IPC_Semaphore_Internal * sem;
+ if (rsem == NULL) /* error on creation, optimistic execution; good luck */
+ return;
+ sem = rsem->platform;
+#if SOLARIS || OSX || FREEBSD5
+ if (0 != sem_post(sem->internal))
+ LOG(LOG_WARNING,
+ "sem_post signaled error: %s at %s:%d\n",
+ STRERROR(errno),
+ filename,
+ linenumber);
+#elif WINDOWS
+ if (!ReleaseSemaphore(sem->internal, 1, NULL))
+ LOG(LOG_WARNING,
+ "ReleaseSemaphore signaled error: %i at %s:%d\n",
+ GetLastError(),
+ filename,
+ linenumber);
+#elif LINUX
+ {
+ struct sembuf sops = {0,1,SEM_UNDO};
+
+ if (0 != semop(sem->internal,&sops,1))
+ LOG(LOG_WARNING,
+ "semop signaled error: %s at %s:%d\n",
+ STRERROR(errno),
+ filename,
+ linenumber);
+ }
+#elif SOMEBSD
+ {
+ int cnt;
+
+
+ MUTEX_LOCK(&sem->internalLock);
+ FLOCK(sem->fd, LOCK_EX);
+ LSEEK(sem->fd, 0, SEEK_SET);
+ if (sizeof(int) != READ(sem->fd, &cnt, sizeof(int))) {
+ LOG(LOG_WARNING,
+ "could not read IPC semaphore count (%s) at %s:%d!\n",
+ STRERROR(errno),
+ __FILE__,
+ __LINE__);
+ MUTEX_UNLOCK(&sem->internalLock);
+ return;
+ }
+ cnt = htonl(ntohl(cnt)+1);
+ LSEEK(sem->fd, 0, SEEK_SET);
+ if (sizeof(int) != WRITE(sem->fd, &cnt, sizeof(int)))
+ LOG(LOG_WARNING,
+ "could not write to IPC file %s (%s) at %s:%d\n",
+ sem->filename,
+ STRERROR(errno),
+ __FILE__,
+ __LINE__);
+ FLOCK(sem->fd, LOCK_UN);
+ MUTEX_UNLOCK(&sem->internalLock);
+ }
+#endif
+}
+
+void ipc_semaphore_down_(IPC_Semaphore * rsem,
+ const char * filename,
+ const int linenumber) {
+ IPC_Semaphore_Internal * sem;
+
+ if (rsem == NULL) /* error on creation, optimistic execution; good luck */
+ return;
+ sem = rsem->platform;
+#if OSX || SOLARIS || FREEBSD5
+ while (0 != sem_wait(sem->internal)) {
+ switch(errno) {
+ case EINTR:
+ break;
+ case EINVAL:
+ errexit(" ipc_semaphore_down called on invalid semaphore (in %s:%d)\n",
+ filename,
+ linenumber);
+ case EDEADLK:
+ errexit(" ipc_semaphore_down caused deadlock! (in %s:%d)\n",
+ filename,
+ linenumber);
+ case EAGAIN:
+ LOG(LOG_WARNING,
+ "did not expect EAGAIN from sem_wait (in %s:%d).\n",
+ filename,
+ linenumber);
+ break;
+ default:
+ LOG(LOG_ERROR,
+ "did not expect %s from sem_wait at %s:%d\n",
+ STRERROR(errno),
+ filename,
+ linenumber);
+ break;
+ }
+ }
+#elif WINDOWS
+ if (WaitForSingleObject(sem->internal, INFINITE) == WAIT_FAILED)
+ LOG(LOG_WARNING,
+ "WaitForSingleObject signaled error: %s at %s:%d\n",
+ STRERROR(errno),
+ filename,
+ linenumber);
+#elif LINUX
+ {
+ struct sembuf sops = {0,-1,SEM_UNDO};
+
+ while (0 != semop(sem->internal,&sops,1)) {
+ switch(errno) {
+ case EINTR:
+ break;
+ case EINVAL:
+ errexit(" ipc_semaphore_down called on invalid semaphore (in %s:%d)\n",
+ filename,
+ linenumber);
+ case EAGAIN:
+ LOG(LOG_WARNING,
+ "did not expect EAGAIN from sem_wait (in %s:%d).\n",
+ filename,
+ linenumber);
+ break;
+ default:
+ LOG(LOG_ERROR,
+ "did not expect %s from sem_wait at %s:%d\n",
+ STRERROR(errno),
+ filename,
+ linenumber);
+ break;
+ }
+ }
+ }
+#elif SOMEBSD
+ {
+ int cnt;
+
+ MUTEX_LOCK(&sem->internalLock);
+ FLOCK(sem->fd, LOCK_EX);
+ cnt = ntohl(0);
+ while (htonl(cnt) == 0) {
+ LSEEK(sem->fd, 0, SEEK_SET);
+ if (sizeof(int) != READ(sem->fd, &cnt, sizeof(int))) {
+ LOG(LOG_WARNING,
+ "could not read IPC semaphore count (%s) at %s:%d!\n",
+ STRERROR(errno),
+ __FILE__,
+ __LINE__);
+ FLOCK(sem->fd, LOCK_UN);
+ MUTEX_UNLOCK(&sem->internalLock);
+ return;
+ }
+ if (htonl(cnt) == 0) {
+ /* busy wait! */
+ FLOCK(sem->fd, LOCK_UN);
+ gnunet_util_sleep(50 * cronMILLIS);
+ FLOCK(sem->fd, LOCK_EX);
+ }
+ }
+
+ cnt = htonl(ntohl(cnt)-1);
+ LSEEK(sem->fd, 0, SEEK_SET);
+ if (sizeof(int) != WRITE(sem->fd, &cnt, sizeof(int)))
+ LOG(LOG_WARNING,
+ "could not write update to IPC file %s at %s:%d\n",
+ sem->filename,
+ __FILE__,
+ __LINE__);
+ FLOCK(sem->fd, LOCK_UN);
+ MUTEX_UNLOCK(&sem->internalLock);
+ }
+#else
+#endif
+}
+
+void ipc_semaphore_free_(IPC_Semaphore * rsem,
+ const char * filename,
+ const int linenumber) {
+ IPC_Semaphore_Internal * sem;
+ if (rsem == NULL) /* error on creation, optimistic execution; good luck */
+ return;
+ sem = rsem->platform;
+ FREE(rsem);
+#if SOLARIS || OSX || FREEBSD5
+ if (0 != sem_close(sem->internal))
+ LOG(LOG_WARNING,
+ "sem_close signaled error: %s at %s:%d\n",
+ STRERROR(errno),
+ filename,
+ linenumber);
+#elif WINDOWS
+ if (!CloseHandle(sem->internal))
+ LOG(LOG_WARNING,
+ "CloseHandle signaled error: %i at %s:%d\n",
+ GetLastError(),
+ filename,
+ linenumber);
+#elif LINUX
+ {
+ int pcount;
+
+ if (semop(sem->internal, &op_close[0], 3) < 0)
+ LOG(LOG_WARNING,
+ "semop signaled error: %s at %s:%d\n",
+ STRERROR(errno),
+ filename,
+ linenumber);
+
+ if ( (pcount = semctl(sem->internal, 1, GETVAL, 0)) < 0)
+ LOG(LOG_WARNING,
+ "semctl: %s at %s:%d\n",
+ STRERROR(errno),
+ filename,
+ linenumber);
+ if (pcount > PROCCOUNT)
+ LOG(LOG_WARNING,
+ "pcount too large at %s:%d\n",
+ filename,
+ linenumber);
+ else if (pcount == PROCCOUNT) {
+ if (0 != semctl(sem->internal,0,IPC_RMID,0))
+ LOG(LOG_WARNING,
+ "semctl signaled error: %s at %s:%d\n",
+ STRERROR(errno),
+ filename,
+ linenumber);
+ UNLINK(sem->filename);
+ } else {
+ if (semop(sem->internal, &op_unlock[0], 1) < 0)
+ LOG(LOG_WARNING,
+ "semop %s %s:%d\n",
+ STRERROR(errno),
+ filename,
+ linenumber);
+ }
+ FREE(sem->filename);
+ }
+#elif SOMEBSD
+ {
+ int cnt;
+
+ MUTEX_DESTROY(&sem->internalLock);
+ FLOCK(sem->fd, LOCK_EX);
+ LSEEK(sem->fd, sizeof(int), SEEK_SET);
+ if (sizeof(int) == READ(sem->fd, &cnt, sizeof(int))) {
+ cnt = htonl(ntohl(cnt)-1);
+ LSEEK(sem->fd, sizeof(int), SEEK_SET);
+ if (sizeof(int) != WRITE(sem->fd, &cnt, sizeof(int)))
+ LOG(LOG_WARNING,
+ "could not write to IPC file %s at %s:%d\n",
+ sem->filename,
+ __FILE__,
+ __LINE__);
+ if (ntohl(cnt) == 0) {
+ UNLINK(sem->filename);
+ }
+ } else
+ LOG(LOG_WARNING,
+ "could not read process count of IPC %s at %s:%d\n",
+ sem->filename,
+ __FILE__,
+ __LINE__);
+ FREE(sem->filename);
+ FLOCK(sem->fd, LOCK_UN);
+ closefile(sem->fd);
+ }
+#else
+#endif
+ FREE(sem);
+}
+
+
+/* end of semaphore.c */
Added: GNUnet/src/util/os/semaphore.c~
===================================================================
--- GNUnet/src/util/os/semaphore.c~ 2006-06-23 15:04:37 UTC (rev 3027)
+++ GNUnet/src/util/os/semaphore.c~ 2006-06-23 15:05:03 UTC (rev 3028)
@@ -0,0 +1,605 @@
+/*
+ This file is part of GNUnet.
+ (C) 2001, 2002, 2003, 2004 Christian Grothoff (and other contributing
authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file util/os/semaphore.c
+ * @brief functions related to IPC synchronization
+ */
+
+#include "gnunet_util_os.h"
+#include "platform.h"
+
+#if SOLARIS || FREEBSD || OSX
+#include <semaphore.h>
+#endif
+#if SOMEBSD
+# include <sys/file.h>
+#endif
+#if LINUX
+# include <sys/ipc.h>
+# include <sys/sem.h>
+#endif
+#ifdef _MSC_VER
+#include <semaphore.h>
+#endif
+
+/**
+ * Shall we use error-checking (slow)
+ * mutexes (e.g. for debugging)
+ */
+#define USE_CHECKING_MUTEX 1
+
+typedef struct {
+#if SOLARIS || FREEBSD5 || OSX
+ sem_t * internal;
+#elif WINDOWS
+ HANDLE internal;
+#elif LINUX
+ int internal;
+ char * filename;
+#elif SOMEBSD
+ int initialValue;
+ int fd;
+ Mutex internalLock;
+ char * filename;
+#elif _MSC_VER
+ int internal; /* KLB_FIX */
+ char * filename;
+#else
+ /* PORT-ME! */
+#endif
+} IPC_Semaphore_Internal;
+
+
+#if LINUX
+ /* IPC semaphore kludging for linux */
+
+ /* Why don't we start at count 0 and increment when opening? */
+ #define PROCCOUNT 10000
+
+ /**
+ * Implementation for a single semaphore actually uses three :
+ *
+ * 0 : actual semaphore value
+ * 1 : process counter
+ * 2 : lock
+ */
+
+ /* Various operations */
+ static struct sembuf op_lock[2] = {
+ {2, 0, 0}, /* wait for [2] (lock) to equal 0 */
+ {2, 1, SEM_UNDO} /* then increment [2] to 1 - this locks it */
+ /* UNDO to release the lock if processes exits */
/* before explicitly unlocking */
+ };
+ static struct sembuf op_unlock[1] = {
+ {2, -1, SEM_UNDO} /* decrement [2] (lock) back to 0 */
+ };
+ static struct sembuf op_endcreate[2] = {
+ {1, -1, SEM_UNDO},/* decrement [1] (proc counter) with undo on exit */
+ /* UNDO to adjust proc counter if process exits
+ before explicitly calling sem_close() */
+ {2, -1, SEM_UNDO} /* then decrement [2] (lock) back to 0 */
+ };
+ static struct sembuf op_close[3] = {
+ {2, 0, 0}, /* wait for [2] (lock) to equal 0 */
+ {2, 1, SEM_UNDO}, /* then increment [2] to 1 - this locks it */
+ {1, 1, SEM_UNDO} /* then increment [1] (proc counter) */
+ };
+#endif
+
+#if SOMEBSD
+static void FLOCK(int fd,
+ int operation) {
+ int ret;
+
+ ret = -1;
+ while (ret == -1) {
+ ret = flock(fd, operation);
+ if (ret == -1) {
+ if (errno != EINTR) {
+ LOG_STRERROR(LOG_ERROR, "flock");
+ return;
+ }
+ }
+ }
+ fsync(fd);
+}
+static int LSEEK(int fd, off_t pos, int mode) {
+ int ret;
+ ret = lseek(fd, pos, mode);
+ if (ret == -1)
+ LOG_STRERROR(LOG_ERROR, "lseek");
+ return ret;
+}
+#endif
+
+IPC_Semaphore * ipc_semaphore_new_(const char * basename,
+ const unsigned int initialValue,
+ const char * filename,
+ const int linenumber) {
+ /* Could older FreeBSD use this too since this code can shorten the IPC name
*/
+#if SOLARIS || OSX || FREEBSD5
+ char * noslashBasename;
+ int i;
+ IPC_Semaphore * rret;
+ IPC_Semaphore_Internal * ret;
+
+ rret = MALLOC(sizeof(IPC_Semaphore));
+ ret = MALLOC(sizeof(IPC_Semaphore_Internal));
+ rret->platform = ret;
+ noslashBasename = STRDUP(basename);
+ for (i=strlen(noslashBasename);i>0;i--)
+ if (noslashBasename[i] == '/')
+ noslashBasename[i] = '.'; /* first character MUST be /, but Solaris
+ forbids it afterwards */
+ noslashBasename[0] = '/';
+ ret->internal = sem_open(noslashBasename,
+ O_CREAT,
+ S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP, /* 660 */
+ initialValue);
+ while ( (ret->internal == (void *) SEM_FAILED)
+ && (errno == ENAMETOOLONG) ) {
+ if (strlen(noslashBasename) < 4)
+ break; /* definitely OS error... */
+ noslashBasename[strlen(noslashBasename)/2] = '\0'; /* cut in half */
+ ret->internal = sem_open(noslashBasename,
+ O_CREAT,
+ S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP, /* 660 */
+ initialValue);
+ }
+ if (ret->internal == (void *) SEM_FAILED)
+ DIE_FILE_STRERROR("sem_open", noslashBasename);
+ FREE(noslashBasename);
+ return rret;
+#elif WINDOWS
+ char * noslashBasename;
+ int i;
+ IPC_Semaphore * rret;
+ IPC_Semaphore_Internal * ret;
+ SECURITY_ATTRIBUTES sec;
+ DWORD dwErr;
+
+ rret = MALLOC(sizeof(IPC_Semaphore));
+ ret = MALLOC(sizeof(IPC_Semaphore_Internal));
+ rret->platform = ret;
+ noslashBasename = STRDUP(basename);
+ for (i=strlen(noslashBasename);i>0;i--)
+ if (noslashBasename[i] == '\\')
+ noslashBasename[i] = '.'; /* must not contain backslashes */
+
+ sec.nLength = sizeof(SECURITY_ATTRIBUTES);
+ sec.bInheritHandle = TRUE;
+ sec.lpSecurityDescriptor = NULL;
+
+ ret->internal = CreateSemaphore(&sec, initialValue, LONG_MAX,
noslashBasename);
+ dwErr = GetLastError();
+ if (! ret->internal && dwErr == ERROR_ALREADY_EXISTS) {
+ ret->internal = OpenSemaphore(SEMAPHORE_MODIFY_STATE, TRUE,
noslashBasename);
+ dwErr = GetLastError();
+ }
+ if (! ret->internal) {
+ LOG(LOG_FAILURE, _("Can't create semaphore: %i"), dwErr);
+ DIE_FILE_STRERROR("sem_open", noslashBasename);
+ }
+ FREE(noslashBasename);
+ return rret;
+#elif LINUX
+ union semun {
+ int val;
+ struct semid_ds *buf;
+ ushort *array;
+ } semctl_arg;
+ IPC_Semaphore * rret;
+ IPC_Semaphore_Internal * ret;
+ key_t key;
+ FILE * fp;
+ int pcount;
+
+ rret = MALLOC(sizeof(IPC_Semaphore));
+ ret = MALLOC(sizeof(IPC_Semaphore_Internal));
+ rret->platform = ret;
+
+ fp = FOPEN(basename, "a+");
+ if (NULL == fp) {
+ LOG_FILE_STRERROR_FL(LOG_FATAL,
+ "fopen",
+ basename,
+ filename,
+ linenumber);
+ FREE(rret);
+ FREE(ret);
+ return NULL;
+ }
+ fclose(fp);
+
+ key = ftok(basename,'g');
+
+again:
+
+ ret->internal = semget(key, 3, IPC_CREAT|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP);
+
+ if (ret->internal == -1)
+ DIE_STRERROR_FL("semget", filename, linenumber);
+ if (semop(ret->internal, &op_lock[0], 2) < 0) {
+ if (errno == EINVAL)
+ goto again;
+ else
+ DIE_STRERROR_FL("semop", filename, linenumber);
+ }
+
+ /* get process count */
+ if ( (pcount = semctl(ret->internal, 1, GETVAL, 0)) < 0)
+ DIE_STRERROR_FL("semctl", filename, linenumber);
+ if (pcount==0) {
+ semctl_arg.val = initialValue;
+ if (semctl(ret->internal, 0, SETVAL, semctl_arg) < 0)
+ DIE_STRERROR_FL("semtcl", filename, linenumber);
+ semctl_arg.val = PROCCOUNT;
+ if (semctl(ret->internal, 1, SETVAL, semctl_arg) < 0)
+ DIE_STRERROR_FL("semtcl", filename, linenumber);
+ }
+
+ if (semop(ret->internal, &op_endcreate[0], 2) < 0)
+ DIE_STRERROR_FL("semop", filename, linenumber);
+
+ ret->filename = STRDUP(basename);
+ return rret;
+#elif SOMEBSD
+ int fd;
+ int cnt;
+ IPC_Semaphore * rret;
+ IPC_Semaphore_Internal * ret;
+
+ rret = MALLOC(sizeof(IPC_Semaphore));
+ ret = MALLOC(sizeof(IPC_Semaphore_Internal));
+ rret->platform = ret;
+
+ MUTEX_CREATE(&ret->internalLock);
+ ret->filename = STRDUP(basename);
+ fd = -1;
+ while (fd == -1) {
+ fd = fileopen(basename,
+ O_CREAT|O_RDWR|O_EXCL,
+ S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP /* 660 */);
+ if ( (fd == -1) &&
+ (errno == EEXIST) ) {
+ /* try without creation */
+ fd = fileopen(basename,
+ O_RDWR,
+ S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP /* 660 */);
+ /* possibly the file was deleted in the meantime,
+ then try again with O_CREAT! */
+ if ( (fd == -1) &&
+ (errno != ENOENT) )
+ break;
+ }
+ }
+ if (fd == -1) {
+ LOG_FILE_STRERROR(LOG_ERROR, "open", ret->filename);
+ MUTEX_DESTROY(&ret->internalLock);
+ FREE(ret->filename);
+ FREE(ret);
+ FREE(rret);
+ return NULL;
+ }
+ FLOCK(fd, LOCK_EX);
+ if (sizeof(int) != READ(fd, &cnt, sizeof(int))) {
+ cnt = htonl(initialValue);
+ LSEEK(fd, 0, SEEK_SET);
+ if (sizeof(int) != WRITE(fd, &cnt, sizeof(int)))
+ LOG_FILE_STRERROR(LOG_WARNING, "write", basename);
+ }
+ LSEEK(fd, sizeof(int), SEEK_SET);
+ if (sizeof(int) != READ(fd, &cnt, sizeof(int)))
+ cnt = htonl(1);
+ else
+ cnt = htonl(ntohl(cnt)+1);
+ LSEEK(fd, sizeof(int), SEEK_SET);
+ if (sizeof(int) != WRITE(fd, &cnt, sizeof(int)))
+ LOG_FILE_STRERROR(LOG_WARNING, "write", basename);
+ FLOCK(fd, LOCK_UN);
+ ret->fd = fd;
+ ret->initialValue = initialValue;
+ return rret;
+#else
+ #ifndef _MSC_VER
+ #warning Port IPC.
+ return NULL;
+ #else
+ return NULL;
+ #endif
+#endif
+}
+
+void ipc_semaphore_up_(IPC_Semaphore * rsem,
+ const char * filename,
+ const int linenumber) {
+ IPC_Semaphore_Internal * sem;
+ if (rsem == NULL) /* error on creation, optimistic execution; good luck */
+ return;
+ sem = rsem->platform;
+#if SOLARIS || OSX || FREEBSD5
+ if (0 != sem_post(sem->internal))
+ LOG(LOG_WARNING,
+ "sem_post signaled error: %s at %s:%d\n",
+ STRERROR(errno),
+ filename,
+ linenumber);
+#elif WINDOWS
+ if (!ReleaseSemaphore(sem->internal, 1, NULL))
+ LOG(LOG_WARNING,
+ "ReleaseSemaphore signaled error: %i at %s:%d\n",
+ GetLastError(),
+ filename,
+ linenumber);
+#elif LINUX
+ {
+ struct sembuf sops = {0,1,SEM_UNDO};
+
+ if (0 != semop(sem->internal,&sops,1))
+ LOG(LOG_WARNING,
+ "semop signaled error: %s at %s:%d\n",
+ STRERROR(errno),
+ filename,
+ linenumber);
+ }
+#elif SOMEBSD
+ {
+ int cnt;
+
+
+ MUTEX_LOCK(&sem->internalLock);
+ FLOCK(sem->fd, LOCK_EX);
+ LSEEK(sem->fd, 0, SEEK_SET);
+ if (sizeof(int) != READ(sem->fd, &cnt, sizeof(int))) {
+ LOG(LOG_WARNING,
+ "could not read IPC semaphore count (%s) at %s:%d!\n",
+ STRERROR(errno),
+ __FILE__,
+ __LINE__);
+ MUTEX_UNLOCK(&sem->internalLock);
+ return;
+ }
+ cnt = htonl(ntohl(cnt)+1);
+ LSEEK(sem->fd, 0, SEEK_SET);
+ if (sizeof(int) != WRITE(sem->fd, &cnt, sizeof(int)))
+ LOG(LOG_WARNING,
+ "could not write to IPC file %s (%s) at %s:%d\n",
+ sem->filename,
+ STRERROR(errno),
+ __FILE__,
+ __LINE__);
+ FLOCK(sem->fd, LOCK_UN);
+ MUTEX_UNLOCK(&sem->internalLock);
+ }
+#endif
+}
+
+void ipc_semaphore_down_(IPC_Semaphore * rsem,
+ const char * filename,
+ const int linenumber) {
+ IPC_Semaphore_Internal * sem;
+
+ if (rsem == NULL) /* error on creation, optimistic execution; good luck */
+ return;
+ sem = rsem->platform;
+#if OSX || SOLARIS || FREEBSD5
+ while (0 != sem_wait(sem->internal)) {
+ switch(errno) {
+ case EINTR:
+ break;
+ case EINVAL:
+ errexit(" ipc_semaphore_down called on invalid semaphore (in %s:%d)\n",
+ filename,
+ linenumber);
+ case EDEADLK:
+ errexit(" ipc_semaphore_down caused deadlock! (in %s:%d)\n",
+ filename,
+ linenumber);
+ case EAGAIN:
+ LOG(LOG_WARNING,
+ "did not expect EAGAIN from sem_wait (in %s:%d).\n",
+ filename,
+ linenumber);
+ break;
+ default:
+ LOG(LOG_ERROR,
+ "did not expect %s from sem_wait at %s:%d\n",
+ STRERROR(errno),
+ filename,
+ linenumber);
+ break;
+ }
+ }
+#elif WINDOWS
+ if (WaitForSingleObject(sem->internal, INFINITE) == WAIT_FAILED)
+ LOG(LOG_WARNING,
+ "WaitForSingleObject signaled error: %s at %s:%d\n",
+ STRERROR(errno),
+ filename,
+ linenumber);
+#elif LINUX
+ {
+ struct sembuf sops = {0,-1,SEM_UNDO};
+
+ while (0 != semop(sem->internal,&sops,1)) {
+ switch(errno) {
+ case EINTR:
+ break;
+ case EINVAL:
+ errexit(" ipc_semaphore_down called on invalid semaphore (in %s:%d)\n",
+ filename,
+ linenumber);
+ case EAGAIN:
+ LOG(LOG_WARNING,
+ "did not expect EAGAIN from sem_wait (in %s:%d).\n",
+ filename,
+ linenumber);
+ break;
+ default:
+ LOG(LOG_ERROR,
+ "did not expect %s from sem_wait at %s:%d\n",
+ STRERROR(errno),
+ filename,
+ linenumber);
+ break;
+ }
+ }
+ }
+#elif SOMEBSD
+ {
+ int cnt;
+
+ MUTEX_LOCK(&sem->internalLock);
+ FLOCK(sem->fd, LOCK_EX);
+ cnt = ntohl(0);
+ while (htonl(cnt) == 0) {
+ LSEEK(sem->fd, 0, SEEK_SET);
+ if (sizeof(int) != READ(sem->fd, &cnt, sizeof(int))) {
+ LOG(LOG_WARNING,
+ "could not read IPC semaphore count (%s) at %s:%d!\n",
+ STRERROR(errno),
+ __FILE__,
+ __LINE__);
+ FLOCK(sem->fd, LOCK_UN);
+ MUTEX_UNLOCK(&sem->internalLock);
+ return;
+ }
+ if (htonl(cnt) == 0) {
+ /* busy wait! */
+ FLOCK(sem->fd, LOCK_UN);
+ gnunet_util_sleep(50 * cronMILLIS);
+ FLOCK(sem->fd, LOCK_EX);
+ }
+ }
+
+ cnt = htonl(ntohl(cnt)-1);
+ LSEEK(sem->fd, 0, SEEK_SET);
+ if (sizeof(int) != WRITE(sem->fd, &cnt, sizeof(int)))
+ LOG(LOG_WARNING,
+ "could not write update to IPC file %s at %s:%d\n",
+ sem->filename,
+ __FILE__,
+ __LINE__);
+ FLOCK(sem->fd, LOCK_UN);
+ MUTEX_UNLOCK(&sem->internalLock);
+ }
+#else
+#endif
+}
+
+void ipc_semaphore_free_(IPC_Semaphore * rsem,
+ const char * filename,
+ const int linenumber) {
+ IPC_Semaphore_Internal * sem;
+ if (rsem == NULL) /* error on creation, optimistic execution; good luck */
+ return;
+ sem = rsem->platform;
+ FREE(rsem);
+#if SOLARIS || OSX || FREEBSD5
+ if (0 != sem_close(sem->internal))
+ LOG(LOG_WARNING,
+ "sem_close signaled error: %s at %s:%d\n",
+ STRERROR(errno),
+ filename,
+ linenumber);
+#elif WINDOWS
+ if (!CloseHandle(sem->internal))
+ LOG(LOG_WARNING,
+ "CloseHandle signaled error: %i at %s:%d\n",
+ GetLastError(),
+ filename,
+ linenumber);
+#elif LINUX
+ {
+ int pcount;
+
+ if (semop(sem->internal, &op_close[0], 3) < 0)
+ LOG(LOG_WARNING,
+ "semop signaled error: %s at %s:%d\n",
+ STRERROR(errno),
+ filename,
+ linenumber);
+
+ if ( (pcount = semctl(sem->internal, 1, GETVAL, 0)) < 0)
+ LOG(LOG_WARNING,
+ "semctl: %s at %s:%d\n",
+ STRERROR(errno),
+ filename,
+ linenumber);
+ if (pcount > PROCCOUNT)
+ LOG(LOG_WARNING,
+ "pcount too large at %s:%d\n",
+ filename,
+ linenumber);
+ else if (pcount == PROCCOUNT) {
+ if (0 != semctl(sem->internal,0,IPC_RMID,0))
+ LOG(LOG_WARNING,
+ "semctl signaled error: %s at %s:%d\n",
+ STRERROR(errno),
+ filename,
+ linenumber);
+ UNLINK(sem->filename);
+ } else {
+ if (semop(sem->internal, &op_unlock[0], 1) < 0)
+ LOG(LOG_WARNING,
+ "semop %s %s:%d\n",
+ STRERROR(errno),
+ filename,
+ linenumber);
+ }
+ FREE(sem->filename);
+ }
+#elif SOMEBSD
+ {
+ int cnt;
+
+ MUTEX_DESTROY(&sem->internalLock);
+ FLOCK(sem->fd, LOCK_EX);
+ LSEEK(sem->fd, sizeof(int), SEEK_SET);
+ if (sizeof(int) == READ(sem->fd, &cnt, sizeof(int))) {
+ cnt = htonl(ntohl(cnt)-1);
+ LSEEK(sem->fd, sizeof(int), SEEK_SET);
+ if (sizeof(int) != WRITE(sem->fd, &cnt, sizeof(int)))
+ LOG(LOG_WARNING,
+ "could not write to IPC file %s at %s:%d\n",
+ sem->filename,
+ __FILE__,
+ __LINE__);
+ if (ntohl(cnt) == 0) {
+ UNLINK(sem->filename);
+ }
+ } else
+ LOG(LOG_WARNING,
+ "could not read process count of IPC %s at %s:%d\n",
+ sem->filename,
+ __FILE__,
+ __LINE__);
+ FREE(sem->filename);
+ FLOCK(sem->fd, LOCK_UN);
+ closefile(sem->fd);
+ }
+#else
+#endif
+ FREE(sem);
+}
+
+
+/* end of semaphore.c */
Added: GNUnet/src/util/os/semaphoretest.c
===================================================================
--- GNUnet/src/util/os/semaphoretest.c 2006-06-23 15:04:37 UTC (rev 3027)
+++ GNUnet/src/util/os/semaphoretest.c 2006-06-23 15:05:03 UTC (rev 3028)
@@ -0,0 +1,184 @@
+/*
+ This file is part of GNUnet.
+ (C) 2001, 2002, 2003, 2004 Christian Grothoff (and other contributing
authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+/**
+ * @file src/util/os/semaphoretest.c
+ * @brief testcase for util/os/semaphore.c
+ */
+
+#include "gnunet_util.h"
+#include "platform.h"
+
+#include <sys/types.h>
+#ifndef MINGW /* PORT-ME MINGW */
+
+static IPC_Semaphore * ipc;
+
+static int testIPCSemaphore() {
+ pid_t me;
+ int cnt;
+ int i;
+ int j;
+ FILE * fd;
+ int ret;
+ int si;
+ int sw;
+
+ ret = 0;
+ REMOVE("/tmp/gnunet_ipc_xchange");
+ REMOVE("/tmp/gnunet_ipc_semtest");
+ me = fork();
+ sw = me;
+
+ ipc = IPC_SEMAPHORE_NEW("/tmp/gnunet_ipc_semtest",
+ 0);
+ for (cnt=0;cnt<3;cnt++) {
+ if (sw == 0) {
+ for (i=0;i<6;i++) {
+ IPC_SEMAPHORE_DOWN(ipc);
+ fd = FOPEN("/tmp/gnunet_ipc_xchange",
+ "a+");
+ if (fd == NULL) {
+ printf("Could not open testfile for reading: %s\n",
+ STRERROR(errno));
+ ret = 1;
+ goto END;
+ }
+ fseek(fd, 4*i, SEEK_SET);
+ si = GN_FREAD(&j, 4, 1, fd);
+ while (si == 0)
+ si = GN_FREAD(&j, 4, 1, fd);
+ if (si != 1) {
+ printf("Could not read from testfile: %d - %s at %s:%d\n",
+ si,
+ STRERROR(errno),
+ __FILE__,
+ __LINE__);
+ ret = 1;
+ goto END;
+ }
+ fclose(fd);
+ if (j != i+cnt) {
+ printf("IPC test failed at cnt=%d i=%d j=%d %s:%u\n",
+ cnt, i, j, __FILE__, __LINE__);
+ ret = 1;
+ goto END;
+ } else
+ fprintf(stderr, ".");
+ }
+ REMOVE("/tmp/gnunet_ipc_xchange");
+ sw = 1;
+ } else {
+ for (i=0;i<6;i++) {
+ sleep(1);
+ fd = FOPEN("/tmp/gnunet_ipc_xchange",
+ "w+");
+ if (fd == NULL) {
+ printf("Could not open testfile for writing: %s\n",
+ STRERROR(errno));
+ ret = 1;
+ goto END;
+ }
+ fseek(fd, 4*i, SEEK_SET);
+ j=cnt+i;
+ if (1 != GN_FWRITE(&j, 4, 1, fd)) {
+ printf("Could not write to testfile: %s\n",
+ STRERROR(errno));
+ ret = 1;
+ goto END;
+ }
+ fclose(fd);
+ IPC_SEMAPHORE_UP(ipc);
+ }
+ fprintf(stderr, ".");
+ sleep(2); /* give reader ample time to finish */
+ sw = 0;
+ }
+ }
+ END:
+ IPC_SEMAPHORE_FREE(ipc);
+ REMOVE("/tmp/gnunet_ipc_xchange");
+ if (me == 0) {
+ exit(ret);
+ } else {
+ LOG(LOG_DEBUG,
+ " waiting for other process to exit.\n");
+ if (-1 == waitpid(me, &j, 0))
+ LOG(LOG_ERROR,
+ " waitpid failed: %s\n",
+ STRERROR(errno));
+ if ((! WIFEXITED(j)) || WEXITSTATUS(j) == 1)
+ ret = 1; /* error in child */
+ }
+ return ret;
+}
+
+
+/**
+ * Perform option parsing from the command line.
+ */
+static int parseCommandLine(int argc,
+ char * argv[]) {
+ char c;
+
+ while (1) {
+ int option_index = 0;
+ static struct GNoption long_options[] = {
+ { "loglevel",1, 0, 'L' },
+ { "config", 1, 0, 'c' },
+ { 0,0,0,0 }
+ };
+
+ c = GNgetopt_long(argc,
+ argv,
+ "c:L:",
+ long_options,
+ &option_index);
+
+ if (c == -1)
+ break; /* No more flags to process */
+
+ switch(c) {
+ case 'L':
+ FREENONNULL(setConfigurationString("GNUNET",
+ "LOGLEVEL",
+ GNoptarg));
+ break;
+ case 'c':
+ FREENONNULL(setConfigurationString("FILES",
+ "gnunet.conf",
+ GNoptarg));
+ break;
+ } /* end of parsing commandline */
+ }
+ return OK;
+}
+#endif /* PORT-ME MINGW */
+
+int main(int argc, char * argv[]){
+ int ret = 0;
+
+#ifndef MINGW
+ initUtil(argc, argv, &parseCommandLine);
+ ret += testIPCSemaphore();
+ fprintf(stderr, "\n");
+ doneUtil();
+#endif
+ return ret;
+}
Added: GNUnet/src/util/os/semaphoretest.c~
===================================================================
--- GNUnet/src/util/os/semaphoretest.c~ 2006-06-23 15:04:37 UTC (rev 3027)
+++ GNUnet/src/util/os/semaphoretest.c~ 2006-06-23 15:05:03 UTC (rev 3028)
@@ -0,0 +1,339 @@
+/**
+ * @file test/hashtest.c
+ * @brief testcase for util/semaphore.c
+ */
+
+#include "gnunet_util.h"
+#include "platform.h"
+
+#include <sys/types.h>
+#ifndef MINGW /* PORT-ME MINGW */
+
+
+static Mutex lock;
+
+static Semaphore * sem;
+
+static volatile int sv;
+
+static volatile int tv;
+
+static IPC_Semaphore * ipc;
+
+static void lockIt() {
+ sv = 0;
+ fprintf(stderr, ".");
+ while (sv == 0)
+ gnunet_util_sleep(50 * cronMILLIS); /* busy waiting may not always work */
+ MUTEX_LOCK(&lock);
+ sv = 1;
+ MUTEX_UNLOCK(&lock);
+ sv = 2;
+ tv = 2;
+}
+
+static void bigStack() {
+ int i;
+ char big[1024 * 100];
+
+ fprintf(stderr, ".");
+ for (i=0;i<1024*100;i++)
+ big[i] = (char) i;
+}
+
+static int testPTHREAD_CREATE() {
+ PTHREAD_T pt;
+ void * unused;
+
+ sv = -1; tv = 0;
+ fprintf(stderr, ".");
+ MUTEX_CREATE(&lock);
+ PTHREAD_CREATE(&pt,
+ (PThreadMain)&lockIt,
+ NULL,
+ 1024);
+ PTHREAD_DETACH(&pt);
+ while (tv != 2) {
+ sv = 1;
+ gnunet_util_sleep(50 * cronMILLIS); /* busy waiting may not always work */
+ }
+ MUTEX_DESTROY(&lock);
+ PTHREAD_CREATE(&pt,
+ (PThreadMain)&bigStack,
+ NULL,
+ 1024*100 + 25000); /* fails by segfault */
+ PTHREAD_JOIN(&pt, &unused);
+ return 0;
+}
+
+static int testMutex() {
+ PTHREAD_T pt;
+ void * unused;
+ MUTEX_CREATE(&lock);
+
+ sv = 1;
+ tv = 0;
+ PTHREAD_CREATE(&pt,
+ (PThreadMain)&lockIt,
+ NULL,
+ 1024);
+ while (sv == 1)
+ gnunet_util_sleep(50 * cronMILLIS); /* busy waiting may not always work */
+ MUTEX_LOCK(&lock);
+ sv = 5; /* release lockIt from while sv==0 loop,
+ blocks it on lock */
+ fprintf(stderr, ".");
+
+ if (sv != 5) {
+ MUTEX_UNLOCK(&lock);
+ while (tv != 2)
+ gnunet_util_sleep(50 * cronMILLIS); /* busy waiting may not always work
*/
+ MUTEX_DESTROY(&lock);
+ printf("MUTEX test failed at %s:%u\n",
+ __FILE__, __LINE__);
+ return 1; /* error */
+ } else {
+ MUTEX_UNLOCK(&lock);
+ while (tv != 2)
+ gnunet_util_sleep(50 * cronMILLIS); /* busy waiting may not always work
*/
+ PTHREAD_JOIN(&pt, &unused);
+ MUTEX_DESTROY(&lock);
+ return 0; /* ok */
+ }
+}
+
+static int testRecursiveMutex() {
+ int i;
+
+ fprintf(stderr, ".");
+ MUTEX_CREATE_RECURSIVE(&lock);
+ for (i=0;i<50;i++)
+ MUTEX_LOCK(&lock);
+ for (i=0;i<50;i++)
+ MUTEX_UNLOCK(&lock);
+ MUTEX_DESTROY(&lock);
+ return 0; /* ok -- fails by hanging!*/
+}
+
+static void semUpDown() {
+ int i;
+
+ fprintf(stderr, ".");
+ for (i=0;i<42;i++)
+ SEMAPHORE_DOWN(sem); /* fails by blocking */
+ if (SEMAPHORE_DOWN_NONBLOCKING(sem) != SYSERR) {
+ SEMAPHORE_FREE(sem);
+ printf("SEMAPHORE_DOWN_NONBLOCKING failed at %s:%u\n"
+ "Testcase deadlocked.\n",
+ __FILE__, __LINE__);
+ return; /* will halt testcase! */
+ }
+ for (i=0;i<42;i++)
+ SEMAPHORE_UP(sem);
+}
+
+static int testSemaphore() {
+ int i;
+ PTHREAD_T pt;
+ void * unused;
+
+ sem = SEMAPHORE_NEW(42);
+ fprintf(stderr, ".");
+ for (i=0;i<42;i++)
+ SEMAPHORE_DOWN(sem); /* fails by blocking */
+ if (SEMAPHORE_DOWN_NONBLOCKING(sem) != SYSERR) {
+ SEMAPHORE_FREE(sem);
+ printf("SEMAPHORE_DOWN_NONBLOCKING failed at %s:%u\n",
+ __FILE__, __LINE__);
+ return 1;
+ }
+ for (i=0;i<42;i++)
+ SEMAPHORE_UP(sem);
+ for (i=0;i<42;i++)
+ if (OK != SEMAPHORE_DOWN_NONBLOCKING(sem)) {
+ SEMAPHORE_FREE(sem);
+ printf("SEMAPHORE_DOWN_NONBLOCKING failed at %s:%u\n",
+ __FILE__, __LINE__);
+ return 1;
+ }
+ if (SEMAPHORE_DOWN_NONBLOCKING(sem) != SYSERR) {
+ SEMAPHORE_FREE(sem);
+ printf("SEMAPHORE_DOWN_NONBLOCKING failed at %s:%u\n",
+ __FILE__, __LINE__);
+ return 1;
+ }
+ fprintf(stderr, ".");
+ PTHREAD_CREATE(&pt,
+ (PThreadMain)&semUpDown,
+ NULL,
+ 1024);
+ for (i=0;i<42;i++)
+ SEMAPHORE_UP(sem);
+ PTHREAD_JOIN(&pt, &unused);
+ for (i=0;i<42;i++)
+ SEMAPHORE_DOWN(sem);
+ if (SEMAPHORE_DOWN_NONBLOCKING(sem) != SYSERR) {
+ SEMAPHORE_FREE(sem);
+ printf("SEMAPHORE_DOWN_NONBLOCKING failed at %s:%u\n",
+ __FILE__, __LINE__);
+ return 1;
+ }
+ return 0;
+}
+
+static int testIPCSemaphore() {
+ pid_t me;
+ int cnt;
+ int i;
+ int j;
+ FILE * fd;
+ int ret;
+ int si;
+ int sw;
+
+ ret = 0;
+ REMOVE("/tmp/gnunet_ipc_xchange");
+ REMOVE("/tmp/gnunet_ipc_semtest");
+ me = fork();
+ sw = me;
+
+ ipc = IPC_SEMAPHORE_NEW("/tmp/gnunet_ipc_semtest",
+ 0);
+ for (cnt=0;cnt<3;cnt++) {
+ if (sw == 0) {
+ for (i=0;i<6;i++) {
+ IPC_SEMAPHORE_DOWN(ipc);
+ fd = FOPEN("/tmp/gnunet_ipc_xchange",
+ "a+");
+ if (fd == NULL) {
+ printf("Could not open testfile for reading: %s\n",
+ STRERROR(errno));
+ ret = 1;
+ goto END;
+ }
+ fseek(fd, 4*i, SEEK_SET);
+ si = GN_FREAD(&j, 4, 1, fd);
+ while (si == 0)
+ si = GN_FREAD(&j, 4, 1, fd);
+ if (si != 1) {
+ printf("Could not read from testfile: %d - %s at %s:%d\n",
+ si,
+ STRERROR(errno),
+ __FILE__,
+ __LINE__);
+ ret = 1;
+ goto END;
+ }
+ fclose(fd);
+ if (j != i+cnt) {
+ printf("IPC test failed at cnt=%d i=%d j=%d %s:%u\n",
+ cnt, i, j, __FILE__, __LINE__);
+ ret = 1;
+ goto END;
+ } else
+ fprintf(stderr, ".");
+ }
+ REMOVE("/tmp/gnunet_ipc_xchange");
+ sw = 1;
+ } else {
+ for (i=0;i<6;i++) {
+ sleep(1);
+ fd = FOPEN("/tmp/gnunet_ipc_xchange",
+ "w+");
+ if (fd == NULL) {
+ printf("Could not open testfile for writing: %s\n",
+ STRERROR(errno));
+ ret = 1;
+ goto END;
+ }
+ fseek(fd, 4*i, SEEK_SET);
+ j=cnt+i;
+ if (1 != GN_FWRITE(&j, 4, 1, fd)) {
+ printf("Could not write to testfile: %s\n",
+ STRERROR(errno));
+ ret = 1;
+ goto END;
+ }
+ fclose(fd);
+ IPC_SEMAPHORE_UP(ipc);
+ }
+ fprintf(stderr, ".");
+ sleep(2); /* give reader ample time to finish */
+ sw = 0;
+ }
+ }
+ END:
+ IPC_SEMAPHORE_FREE(ipc);
+ REMOVE("/tmp/gnunet_ipc_xchange");
+ if (me == 0) {
+ exit(ret);
+ } else {
+ LOG(LOG_DEBUG,
+ " waiting for other process to exit.\n");
+ if (-1 == waitpid(me, &j, 0))
+ LOG(LOG_ERROR,
+ " waitpid failed: %s\n",
+ STRERROR(errno));
+ if ((! WIFEXITED(j)) || WEXITSTATUS(j) == 1)
+ ret = 1; /* error in child */
+ }
+ return ret;
+}
+
+
+/**
+ * Perform option parsing from the command line.
+ */
+static int parseCommandLine(int argc,
+ char * argv[]) {
+ char c;
+
+ while (1) {
+ int option_index = 0;
+ static struct GNoption long_options[] = {
+ { "loglevel",1, 0, 'L' },
+ { "config", 1, 0, 'c' },
+ { 0,0,0,0 }
+ };
+
+ c = GNgetopt_long(argc,
+ argv,
+ "c:L:",
+ long_options,
+ &option_index);
+
+ if (c == -1)
+ break; /* No more flags to process */
+
+ switch(c) {
+ case 'L':
+ FREENONNULL(setConfigurationString("GNUNET",
+ "LOGLEVEL",
+ GNoptarg));
+ break;
+ case 'c':
+ FREENONNULL(setConfigurationString("FILES",
+ "gnunet.conf",
+ GNoptarg));
+ break;
+ } /* end of parsing commandline */
+ }
+ return OK;
+}
+#endif /* PORT-ME MINGW */
+
+int main(int argc, char * argv[]){
+ int ret = 0;
+
+#ifndef MINGW
+ initUtil(argc, argv, &parseCommandLine);
+ ret += testPTHREAD_CREATE();
+ ret += testMutex();
+ ret += testRecursiveMutex();
+ ret += testSemaphore();
+ ret += testIPCSemaphore();
+ fprintf(stderr, "\n");
+ doneUtil();
+#endif
+ return ret;
+}
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [GNUnet-SVN] r3028 - GNUnet/src/util/os,
grothoff <=