gnunet-svn
[Top][All Lists]
Advanced

[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;
+}





reply via email to

[Prev in Thread] Current Thread [Next in Thread]