sem_inc.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. /*
  2. * DUMA - Red-Zone memory allocator.
  3. * Copyright (C) 2002-2008 Hayati Ayguen <h_ayguen@web.de>, Procitec GmbH
  4. * License: GNU LGPL (GNU Lesser General Public License, see COPYING-GPL)
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2.1 of the License, or (at your option) any later version.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with this library; if not, write to the Free Software
  18. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  19. *
  20. * FILE CONTENTS:
  21. * internal implementation file
  22. * contains thread safety functions (semaphore lock/release)
  23. */
  24. #include "duma_config.h"
  25. #include "duma_sem.h"
  26. #include "print.h"
  27. #ifndef DUMA_NO_THREAD_SAFETY
  28. /* check for pthread library */
  29. /* use WIN32_SEMAPHORES on Win32-Cygwin,
  30. * with this configuration testmt.c works either with pthreads and with the Win32 API
  31. */
  32. /* || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__)) */
  33. #if (!defined(WIN32))
  34. #define HAVE_PTHREADS 1
  35. #define USE_WIN32_SEMAPHORES 0
  36. #define USE_WIN32_CRIT_SECT 0
  37. #else
  38. #define HAVE_PTHREADS 0
  39. #define USE_WIN32_SEMAPHORES 1
  40. #define USE_WIN32_CRIT_SECT 0
  41. #endif
  42. #if HAVE_PTHREADS
  43. #include <pthread.h>
  44. #include <semaphore.h>
  45. #elif USE_WIN32_SEMAPHORES || USE_WIN32_CRIT_SECT
  46. #define WIN32_LEAN_AND_MEAN 1
  47. #include <windows.h>
  48. #include <winbase.h>
  49. #endif
  50. /*
  51. * DUMA_sem is a semaphore used to allow one thread at a time into
  52. * these routines.
  53. * Also, we use semInited as a boolean to see if we should be
  54. * using the semaphore.
  55. * semThread is set to the thread id of the thread that currently
  56. * has the semaphore so that when/if it tries to get the semaphore
  57. * again (realloc calling malloc/free) - nothing will happen to the
  58. * semaphore.
  59. * semDepth is used to keep track of how many times the same thread
  60. * gets the semaphore - so we know when it is actually freed.
  61. */
  62. #if HAVE_PTHREADS
  63. #define DUMA_thread_self() pthread_self()
  64. #ifndef DUMA_SEMAPHORES
  65. static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
  66. static pthread_t mutextid=0;
  67. static int locknr=0;
  68. #else
  69. static sem_t DUMA_sem = { 0 };
  70. static pthread_t semThread = (pthread_t) 0;
  71. #endif
  72. #elif USE_WIN32_SEMAPHORES
  73. #define DUMA_thread_self() GetCurrentThreadId()
  74. #ifndef UNICODE
  75. #define SEM_NAME_TYPE char
  76. #define SEM_STRCPY strcpy
  77. #define SEM_STRCAT strcat
  78. static char semObjectName[] = "DUMA_";
  79. #else
  80. #define SEM_NAME_TYPE wchar_t
  81. #define SEM_STRCPY wcscpy
  82. #define SEM_STRCAT wcscat
  83. static wchar_t semObjectName[] = L"DUMA_";
  84. #endif
  85. static SECURITY_ATTRIBUTES semSecAttr;
  86. static DWORD semThread = 0;
  87. static HANDLE semHandle = 0;
  88. #elif USE_WIN32_CRIT_SECT
  89. /* see http://msdn.microsoft.com/en-us/library/ms682530(VS.85).aspx */
  90. static CRITICAL_SECTION critsect;
  91. #endif
  92. static int semInInit = 0;
  93. #if HAVE_PTHREADS && !defined(DUMA_SEMAPHORES)
  94. static int semInited = 1;
  95. static int semDepth = 0;
  96. #elif USE_WIN32_SEMAPHORES
  97. static int semInited = 0;
  98. static int semDepth = 0;
  99. #elif USE_WIN32_CRIT_SECT
  100. static int semInited = 0;
  101. #endif
  102. #if HAVE_PTHREADS
  103. #ifndef DUMA_SEMAPHORES
  104. static void lock()
  105. {
  106. if (pthread_mutex_trylock(&mutex))
  107. {
  108. if ( mutextid==pthread_self() )
  109. {
  110. ++locknr;
  111. return;
  112. }
  113. else
  114. {
  115. pthread_mutex_lock(&mutex);
  116. }
  117. }
  118. mutextid=pthread_self();
  119. locknr=1;
  120. }
  121. static void unlock()
  122. {
  123. --locknr;
  124. if (!locknr)
  125. {
  126. mutextid=0;
  127. pthread_mutex_unlock(&mutex);
  128. }
  129. }
  130. #endif
  131. #endif
  132. void
  133. DUMA_init_sem(void)
  134. {
  135. #if USE_WIN32_SEMAPHORES
  136. SEM_NAME_TYPE semLocalName[32];
  137. SEM_NAME_TYPE acPID[16];
  138. DWORD pid;
  139. #endif
  140. /* avoid recursive call to sem_init(),
  141. * when sem_init() calls malloc() or other allocation function
  142. */
  143. if (semInited || semInInit)
  144. return;
  145. semInInit = 1;
  146. #if HAVE_PTHREADS
  147. #ifndef DUMA_SEMAPHORES
  148. pthread_mutex_init(&mutex, NULL);
  149. semInited = 1;
  150. #else
  151. if (sem_init(&DUMA_sem, 0, 1) >= 0)
  152. semInited = 1;
  153. #endif
  154. #elif USE_WIN32_SEMAPHORES
  155. pid = GetCurrentProcessId();
  156. SEM_STRCPY(semLocalName, semObjectName);
  157. /* append ProcessId() to get inter-process unique semaphore name */
  158. acPID[0] = 'A' + (SEM_NAME_TYPE)( (pid >> 28) & 0x0F );
  159. acPID[1] = 'A' + (SEM_NAME_TYPE)( (pid >> 24) & 0x0F );
  160. acPID[2] = 'A' + (SEM_NAME_TYPE)( (pid >> 20) & 0x0F );
  161. acPID[3] = 'A' + (SEM_NAME_TYPE)( (pid >> 16) & 0x0F );
  162. acPID[4] = 'A' + (SEM_NAME_TYPE)( (pid >> 12) & 0x0F );
  163. acPID[5] = 'A' + (SEM_NAME_TYPE)( (pid >> 8) & 0x0F );
  164. acPID[6] = 'A' + (SEM_NAME_TYPE)( (pid >> 4) & 0x0F );
  165. acPID[7] = 'A' + (SEM_NAME_TYPE)( (pid ) & 0x0F );
  166. acPID[8] = 0;
  167. SEM_STRCAT( semLocalName, acPID );
  168. semSecAttr.nLength = sizeof(semSecAttr);
  169. semSecAttr.lpSecurityDescriptor = NULL;
  170. semSecAttr.bInheritHandle = FALSE;
  171. semHandle = CreateSemaphore( &semSecAttr /* pointer to security attributes */
  172. , 1 /* initial count */
  173. , 1 /* maximum count */
  174. , semLocalName /* pointer to semaphore-object name */
  175. );
  176. semInited = 1;
  177. #elif USE_WIN32_CRIT_SECT
  178. InitializeCriticalSection(&critsect);
  179. semInited = 1;
  180. #endif
  181. semInInit = 0;
  182. if (!semInited) DUMA_Abort("\nCouldn't initialise semaphore");
  183. }
  184. void DUMA_get_sem(void)
  185. {
  186. if (semInInit) return; /* avoid recursion */
  187. if (!semInited) DUMA_init_sem(); /* initialize if necessary */
  188. #if HAVE_PTHREADS
  189. #ifndef DUMA_SEMAPHORES
  190. lock();
  191. #else
  192. if (semThread != DUMA_thread_self())
  193. {
  194. while (sem_wait(&DUMA_sem) < 0); /* wait for the semaphore. */
  195. semThread = DUMA_thread_self(); /* let everyone know who has the semaphore. */
  196. }
  197. #endif
  198. ++semDepth; /* increment semDepth - push one stack level */
  199. #elif USE_WIN32_SEMAPHORES
  200. if (semThread != DUMA_thread_self())
  201. {
  202. while (WaitForSingleObject(semHandle, 1000) != WAIT_OBJECT_0) ; /* wait for the semaphore. */
  203. semThread = DUMA_thread_self(); /* let everyone know who has the semaphore. */
  204. }
  205. ++semDepth; /* increment semDepth - push one stack level */
  206. #elif USE_WIN32_CRIT_SECT
  207. EnterCriticalSection(&critsect);
  208. #endif
  209. }
  210. int DUMA_rel_sem(int retval)
  211. {
  212. if (semInInit) return retval; /* avoid recursion */
  213. if (!semInited) DUMA_Abort("\nSemaphore isn't initialised");
  214. #ifdef DUMA_SEMAPHORES
  215. if (!semThread) DUMA_Abort("\nSemaphore isn't owned by this thread");
  216. #endif
  217. #if HAVE_PTHREADS || USE_WIN32_SEMAPHORES
  218. if (semDepth <= 0) DUMA_Abort("\nSemaphore isn't locked");
  219. #endif
  220. --semDepth; /* decrement semDepth - popping one stack level */
  221. #if HAVE_PTHREADS
  222. #ifndef DUMA_SEMAPHORES
  223. unlock();
  224. #else
  225. semThread = (pthread_t) 0; /* zero this before actually free'ing the semaphore. */
  226. if (sem_post(&DUMA_sem) < 0)
  227. DUMA_Abort("Failed to post the semaphore.");
  228. #endif
  229. #elif USE_WIN32_SEMAPHORES
  230. semThread = 0; /* zero this before actually free'ing the semaphore. */
  231. if (0 == ReleaseSemaphore(semHandle, 1 /* amount to add to current count */, NULL) )
  232. DUMA_Abort("Failed to post the semaphore.");
  233. #elif USE_WIN32_CRIT_SECT
  234. LeaveCriticalSection(&critsect);
  235. #endif
  236. return retval;
  237. }
  238. #else
  239. /* for not having an empty file */
  240. static int dummy = 0;
  241. #endif /* DUMA_NO_THREAD_SAFETY */