⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 semaphore.c

📁 GNUnet是一个安全的点对点网络框架
💻 C
📖 第 1 页 / 共 2 页
字号:
/*     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 * * TODO: implement non-blocking semaphore down! */#include "platform.h"#include "gnunet_util_os.h"#include "gnunet_util_string.h"#include "gnunet_util_error.h"#include "gnunet_util_threads.h"#include "gnunet_util_disk.h"#if SOLARIS || GNUNET_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 1typedef struct GNUNET_IPC_Semaphore{  struct GNUNET_GE_Context *ectx;#if SOLARIS || GNUNET_freeBSD5 || OSX  sem_t *internal;#elif WINDOWS  HANDLE internal;#elif LINUX  int internal;  char *filename;#elif SOMEBSD  int initialValue;  int fd;  struct GNUNET_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 SOMEBSDstatic voidFLOCK (int fd, int operation){  int ret;  ret = -1;  while (ret == -1)    {      ret = flock (fd, operation);      if (ret == -1)        {          if (errno != EINTR)            {              GNUNET_GE_LOG_STRERROR (NULL,                                      GNUNET_GE_ERROR | GNUNET_GE_USER |                                      GNUNET_GE_ADMIN | GNUNET_GE_BULK,                                      "flock");              return;            }        }    }  fsync (fd);}static intSEMA_LSEEK (int fd, off_t pos, int mode){  int ret;  ret = LSEEK (fd, pos, mode);  if (ret == -1)    GNUNET_GE_LOG_STRERROR (NULL,                            GNUNET_GE_ERROR | GNUNET_GE_USER | GNUNET_GE_ADMIN                            | GNUNET_GE_BULK, "lseek");  return ret;}#endifstruct GNUNET_IPC_Semaphore *GNUNET_IPC_semaphore_create (struct GNUNET_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 || GNUNET_freeBSD5  char *noslashBasename;  int i;  struct GNUNET_IPC_Semaphore *ret;  ret = GNUNET_malloc (sizeof (struct GNUNET_IPC_Semaphore));  ret->ectx = ectx;  noslashBasename = GNUNET_expand_file_name (ectx, 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))    {      char *halfBasename;      if (strlen (noslashBasename) < 4)        break;                  /* definitely OS error... */      /* FIXME: this might cause unintended mapping to same names */      halfBasename = noslashBasename + strlen (noslashBasename) / 2;    /* cut in half */      halfBasename[0] = '/';      ret->internal = sem_open (halfBasename, O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,   /* 660 */                                initialValue);    }  if (ret->internal == (void *) SEM_FAILED)    GNUNET_GE_DIE_STRERROR_FILE (ectx,                                 GNUNET_GE_FATAL | GNUNET_GE_USER |                                 GNUNET_GE_DEVELOPER | GNUNET_GE_IMMEDIATE,                                 "sem_open", noslashBasename);  GNUNET_free (noslashBasename);  return ret;#elif WINDOWS  char *noslashBasename;  int i;  struct GNUNET_IPC_Semaphore *ret;  SECURITY_ATTRIBUTES sec;  DWORD dwErr;  ret = GNUNET_malloc (sizeof (struct GNUNET_IPC_Semaphore));  ret->ectx = ectx;  noslashBasename = GNUNET_expand_file_name (ectx, 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)    {      GNUNET_GE_LOG (ectx,                     GNUNET_GE_FATAL | GNUNET_GE_USER | GNUNET_GE_DEVELOPER |                     GNUNET_GE_BULK, _("Can't create semaphore: %i"), dwErr);      GNUNET_GE_DIE_STRERROR_FILE (ectx,                                   GNUNET_GE_FATAL | GNUNET_GE_USER |                                   GNUNET_GE_DEVELOPER | GNUNET_GE_BULK,                                   "OpenSemaphore", noslashBasename);    }  GNUNET_free (noslashBasename);  return ret;#elif LINUX  union semun  {    int val;    struct semid_ds *buf;    ushort *array;  } semctl_arg;  struct GNUNET_IPC_Semaphore *ret;  key_t key;  FILE *fp;  int pcount;  char *ebasename;  ret = GNUNET_malloc (sizeof (struct GNUNET_IPC_Semaphore));  ret->ectx = ectx;  ebasename = GNUNET_expand_file_name (ectx, basename);  GNUNET_disk_directory_create_for_file (ectx, ebasename);  fp = FOPEN (ebasename, "a+");  if (NULL == fp)    {      GNUNET_GE_LOG_STRERROR_FILE (ectx,                                   GNUNET_GE_ERROR | GNUNET_GE_USER |                                   GNUNET_GE_BULK, "fopen", ebasename);      GNUNET_free (ret);      GNUNET_free (ebasename);      return NULL;    }  fclose (fp);  key = ftok (ebasename, 'g');again:  ret->internal = semget (key,                          3,                          IPC_CREAT | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);  if (ret->internal == -1)    GNUNET_GE_DIE_STRERROR (ectx,                            GNUNET_GE_FATAL | GNUNET_GE_USER |                            GNUNET_GE_IMMEDIATE, "semget");  if (semop (ret->internal, &op_lock[0], 2) < 0)    {      if (errno == EINVAL)        goto again;      else        GNUNET_GE_DIE_STRERROR (ectx,                                GNUNET_GE_FATAL | GNUNET_GE_USER |                                GNUNET_GE_IMMEDIATE, "semop");    }  /* get process count */  if ((pcount = semctl (ret->internal, 1, GETVAL, 0)) < 0)    GNUNET_GE_DIE_STRERROR (ectx,                            GNUNET_GE_FATAL | GNUNET_GE_USER |                            GNUNET_GE_IMMEDIATE, "semctl");  if (pcount == 0)    {      semctl_arg.val = initialValue;      if (semctl (ret->internal, 0, SETVAL, semctl_arg) < 0)        GNUNET_GE_DIE_STRERROR (ectx,                                GNUNET_GE_FATAL | GNUNET_GE_USER |                                GNUNET_GE_IMMEDIATE, "semtcl");      semctl_arg.val = PROCCOUNT;      if (semctl (ret->internal, 1, SETVAL, semctl_arg) < 0)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -