00001 /*
00002      This file is part of GNUnet.
00003      (C) 2001, 2002, 2003, 2004, 2006 Christian Grothoff (and other contributing authors)
00004 
00005      GNUnet is free software; you can redistribute it and/or modify
00006      it under the terms of the GNU General Public License as published
00007      by the Free Software Foundation; either version 2, or (at your
00008      option) any later version.
00009 
00010      GNUnet is distributed in the hope that it will be useful, but
00011      WITHOUT ANY WARRANTY; without even the implied warranty of
00012      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013      General Public License for more details.
00014 
00015      You should have received a copy of the GNU General Public License
00016      along with GNUnet; see the file COPYING.  If not, write to the
00017      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00018      Boston, MA 02111-1307, USA.
00019 */
00020 
00021 /**
00022  * @file util/threads/semaphore.c
00023  * @brief functions related to threading and synchronization
00024  *
00025  * In particular, functions for mutexes, semaphores
00026  * and thread creation are provided.
00027  */
00028 
00029 #include "platform.h"
00030 #include "gnunet_util_threads.h"
00031 #include "gnunet_util_error.h"
00032 #include "gnunet_util_string.h"
00033 
00034 #if SOLARIS || GNUNET_freeBSD || OSX
00035 #include 
00036 #include 
00037 #endif
00038 #if SOMEBSD
00039 #include 
00040 #endif
00041 #if LINUX
00042 #include 
00043 #endif
00044 #ifdef _MSC_VER
00045 #include 
00046 #include 
00047 #endif
00048 
00049 /**
00050  * @brief Internal state of a semaphore.
00051  */
00052 typedef struct GNUNET_Semaphore
00053 {
00054   /**
00055    * Counter
00056    */
00057   int v;
00058 
00059   /**
00060    * Mutex
00061    */
00062   pthread_mutex_t mutex;
00063 
00064   /**
00065    * Wrapper for pthread condition variable.
00066    */
00067   pthread_cond_t cond;
00068 } Semaphore;
00069 
00070 #ifndef PTHREAD_MUTEX_NORMAL
00071 #ifdef PTHREAD_MUTEX_TIMED_NP
00072 #define PTHREAD_MUTEX_NORMAL PTHREAD_MUTEX_TIMED_NP
00073 #else
00074 #define PTHREAD_MUTEX_NORMAL NULL
00075 #endif
00076 #endif
00077 
00078 /**
00079  * This prototype is somehow missing in various Linux pthread
00080  * include files. But we need it and it seems to be available
00081  * on all pthread-systems so far. Odd.
00082  */
00083 #ifndef _MSC_VER
00084 extern int pthread_mutexattr_setkind_np (pthread_mutexattr_t * attr,
00085                                          int kind);
00086 #endif
00087 
00088 /**
00089  * function must be called prior to semaphore use -- handles
00090  * setup and initialization.  semaphore destroy (below) should
00091  * be called when the semaphore is no longer needed.
00092  */
00093 Semaphore *
00094 GNUNET_semaphore_create (int value)
00095 {
00096   Semaphore *s;
00097   pthread_mutexattr_t attr;
00098 #if WINDOWS
00099   attr = NULL;
00100 #endif
00101 
00102   pthread_mutexattr_init (&attr);
00103 #if LINUX
00104   GNUNET_GE_ASSERT (NULL,
00105                     0 == pthread_mutexattr_setkind_np
00106                     (&attr, PTHREAD_MUTEX_ERRORCHECK_NP));
00107 #else
00108   GNUNET_GE_ASSERT (NULL,
00109                     0 == pthread_mutexattr_settype
00110                     (&attr, PTHREAD_MUTEX_ERRORCHECK));
00111 #endif
00112   s = GNUNET_malloc (sizeof (Semaphore));
00113   s->v = value;
00114   GNUNET_GE_ASSERT (NULL, 0 == pthread_mutex_init (&s->mutex, &attr));
00115   GNUNET_GE_ASSERT (NULL, 0 == pthread_cond_init (&s->cond, NULL));
00116   return s;
00117 }
00118 
00119 void
00120 GNUNET_semaphore_destroy (Semaphore * s)
00121 {
00122   GNUNET_GE_ASSERT (NULL, s != NULL);
00123   GNUNET_GE_ASSERT (NULL, 0 == pthread_cond_destroy (&s->cond));
00124   GNUNET_GE_ASSERT (NULL, 0 == pthread_mutex_destroy (&s->mutex));
00125   GNUNET_free (s);
00126 }
00127 
00128 int
00129 GNUNET_semaphore_up (Semaphore * s)
00130 {
00131   int ret;
00132 
00133   GNUNET_GE_ASSERT (NULL, s != NULL);
00134   GNUNET_GE_ASSERT (NULL, 0 == pthread_mutex_lock (&s->mutex));
00135   ret = ++(s->v);
00136   GNUNET_GE_ASSERT (NULL, 0 == pthread_cond_signal (&s->cond));
00137   GNUNET_GE_ASSERT (NULL, 0 == pthread_mutex_unlock (&s->mutex));
00138   return ret;
00139 }
00140 
00141 int
00142 GNUNET_semaphore_down_at_file_line_ (Semaphore * s,
00143                                      int mayblock,
00144                                      int longwait, const char *file,
00145                                      unsigned int line)
00146 {
00147   int ret;
00148   GNUNET_CronTime start;
00149   GNUNET_CronTime end;
00150 
00151   GNUNET_GE_ASSERT (NULL, s != NULL);
00152   start = GNUNET_get_time ();
00153   GNUNET_GE_ASSERT (NULL, 0 == pthread_mutex_lock (&s->mutex));
00154   while ((s->v <= 0) && mayblock)
00155     GNUNET_GE_ASSERT (NULL, 0 == pthread_cond_wait (&s->cond, &s->mutex));
00156   if (s->v > 0)
00157     ret = --(s->v);
00158   else
00159     ret = GNUNET_SYSERR;
00160   GNUNET_GE_ASSERT (NULL, 0 == pthread_mutex_unlock (&s->mutex));
00161   end = GNUNET_get_time ();
00162   if ((longwait == GNUNET_NO) &&
00163       (end - start > GNUNET_REALTIME_LIMIT) && (GNUNET_REALTIME_LIMIT != 0))
00164     {
00165       GNUNET_GE_LOG (NULL,
00166                      GNUNET_GE_DEVELOPER | GNUNET_GE_WARNING |
00167                      GNUNET_GE_IMMEDIATE,
00168                      _("Real-time delay violation (%llu ms) at %s:%u\n"),
00169                      end - start, file, line);
00170     }
00171   return ret;
00172 }
00173 
00174 /* end of semaphore.c */