crit.cpp 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. /** BEGIN COPYRIGHT BLOCK
  2. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  3. * Copyright (C) 2005 Red Hat, Inc.
  4. * All rights reserved.
  5. *
  6. * License: GPL (version 3 or any later version).
  7. * See LICENSE for details.
  8. * END COPYRIGHT BLOCK **/
  9. #ifdef HAVE_CONFIG_H
  10. # include <config.h>
  11. #endif
  12. /*
  13. * crit.c: Critical section abstraction. Used in threaded servers to protect
  14. * areas where two threads can interfere with each other.
  15. *
  16. * Condvars are condition variables that are used for thread-thread
  17. * synchronization.
  18. *
  19. * Rob McCool
  20. */
  21. #include "systems.h"
  22. #include "netsite.h"
  23. #include "crit.h"
  24. #include "pool.h"
  25. #ifdef USE_NSPR
  26. #include "nspr.h"
  27. #include "prthread.h"
  28. #include "prlock.h"
  29. #include "prcvar.h"
  30. #include "prinrval.h"
  31. /*
  32. * Defined to replace PR_Monitor() with PR_Lock().
  33. */
  34. typedef struct critical {
  35. PRLock *lock;
  36. PRUint32 count;
  37. PRThread *owner;
  38. } ns_critical_t;
  39. typedef struct condvar {
  40. ns_critical_t *lock;
  41. PRCondVar *cvar;
  42. } ns_condvar_t;
  43. #endif
  44. /* -------------------------- critical sections --------------------------- */
  45. /* Useful for ASSERTs only. Returns non-zero if the current thread is the owner.
  46. */
  47. NSAPI_PUBLIC int crit_owner_is_me(CRITICAL id)
  48. {
  49. #ifdef USE_NSPR
  50. ns_critical_t *crit = (ns_critical_t*)id;
  51. return (crit->owner == PR_GetCurrentThread());
  52. #else
  53. return 1;
  54. #endif
  55. }
  56. NSAPI_PUBLIC CRITICAL crit_init(void)
  57. {
  58. #ifdef USE_NSPR
  59. ns_critical_t *crit = (ns_critical_t*)PERM_MALLOC(sizeof(ns_critical_t)) ;
  60. if (crit) {
  61. if (!(crit->lock = PR_NewLock())) {
  62. PERM_FREE(crit);
  63. return NULL;
  64. }
  65. crit->count = 0;
  66. crit->owner = 0;
  67. }
  68. return (void *) crit;
  69. #else
  70. return NULL;
  71. #endif
  72. }
  73. NSAPI_PUBLIC void crit_enter(CRITICAL id)
  74. {
  75. #ifdef USE_NSPR
  76. ns_critical_t *crit = (ns_critical_t*)id;
  77. PRThread *me = PR_GetCurrentThread();
  78. if ( crit->owner == me) {
  79. PR_ASSERT(crit->count > 0);
  80. crit->count++;
  81. }
  82. else {
  83. PR_Lock(crit->lock);
  84. PR_ASSERT(crit->count == 0);
  85. crit->count = 1;
  86. crit->owner = me;
  87. }
  88. #endif
  89. }
  90. NSAPI_PUBLIC void crit_exit(CRITICAL id)
  91. {
  92. #ifdef USE_NSPR
  93. ns_critical_t *crit = (ns_critical_t*)id;
  94. if (crit->owner != PR_GetCurrentThread())
  95. return;
  96. if ( --crit->count == 0) {
  97. crit->owner = 0;
  98. PR_Unlock(crit->lock);
  99. }
  100. #endif
  101. }
  102. NSAPI_PUBLIC void crit_terminate(CRITICAL id)
  103. {
  104. #ifdef USE_NSPR
  105. ns_critical_t *crit = (ns_critical_t*)id;
  106. PR_DestroyLock((PRLock*)crit->lock);
  107. PERM_FREE(crit);
  108. #endif
  109. }
  110. /* ------------------------- condition variables -------------------------- */
  111. NSAPI_PUBLIC CONDVAR condvar_init(CRITICAL id)
  112. {
  113. #ifdef USE_NSPR
  114. ns_critical_t *crit = (ns_critical_t*)id;
  115. ns_condvar_t *cvar = (ns_condvar_t*)PERM_MALLOC(sizeof(ns_condvar_t)) ;
  116. if (crit) {
  117. cvar->lock = crit;
  118. if ((cvar->cvar = PR_NewCondVar((PRLock *)cvar->lock->lock)) == 0) {
  119. PERM_FREE(cvar);
  120. return NULL;
  121. }
  122. }
  123. return (void *) cvar;
  124. #endif
  125. }
  126. NSAPI_PUBLIC void condvar_wait(CONDVAR _cv)
  127. {
  128. #ifdef USE_NSPR
  129. ns_condvar_t *cv = (ns_condvar_t *)_cv;
  130. /* Save away recursion count so we can restore it after the wait */
  131. int saveCount = cv->lock->count;
  132. PRThread *saveOwner = cv->lock->owner;
  133. PR_ASSERT(cv->lock->owner == PR_GetCurrentThread());
  134. cv->lock->count = 0;
  135. cv->lock->owner = 0;
  136. PR_WaitCondVar(cv->cvar, PR_INTERVAL_NO_TIMEOUT);
  137. cv->lock->count = saveCount;
  138. cv->lock->owner = saveOwner;
  139. #endif
  140. }
  141. NSAPI_PUBLIC void ns_condvar_timed_wait(CONDVAR _cv, long secs)
  142. {
  143. #ifdef USE_NSPR
  144. ns_condvar_t *cv = (ns_condvar_t *)_cv;
  145. /* Save away recursion count so we can restore it after the wait */
  146. int saveCount = cv->lock->count;
  147. PRThread *saveOwner = cv->lock->owner;
  148. PR_ASSERT(cv->lock->owner == PR_GetCurrentThread());
  149. cv->lock->count = 0;
  150. cv->lock->owner = 0;
  151. PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT;
  152. if (secs > 0)
  153. timeout = PR_SecondsToInterval(secs);
  154. PR_WaitCondVar(cv->cvar, timeout);
  155. cv->lock->count = saveCount;
  156. cv->lock->owner = saveOwner;
  157. #endif
  158. }
  159. NSAPI_PUBLIC void condvar_notify(CONDVAR _cv)
  160. {
  161. #ifdef USE_NSPR
  162. ns_condvar_t *cv = (ns_condvar_t *)_cv;
  163. PR_ASSERT(cv->lock->owner == PR_GetCurrentThread());
  164. PR_NotifyCondVar(cv->cvar);
  165. #endif
  166. }
  167. NSAPI_PUBLIC void condvar_notifyAll(CONDVAR _cv)
  168. {
  169. #ifdef USE_NSPR
  170. ns_condvar_t *cv = (ns_condvar_t *)_cv;
  171. PR_ASSERT(cv->lock->owner == PR_GetCurrentThread());
  172. PR_NotifyAllCondVar(cv->cvar);
  173. #endif
  174. }
  175. NSAPI_PUBLIC void ns_condvar_terminate(CONDVAR _cv)
  176. {
  177. #ifdef USE_NSPR
  178. ns_condvar_t *cv = (ns_condvar_t *)_cv;
  179. PR_DestroyCondVar(cv->cvar);
  180. PERM_FREE(cv);
  181. #endif
  182. }
  183. /* ----------------------- Counting semaphores ---------------------------- */
  184. /* These are currently not listed in crit.h because they aren't yet used;
  185. * although they do work.
  186. */
  187. /*
  188. * XXXMB - these should be in NSPR.
  189. *
  190. */
  191. #if defined(SOLARIS) && defined(HW_THREADS)
  192. #include <synch.h>
  193. typedef sema_t counting_sem_t;
  194. #elif defined(IRIX) && defined(HW_THREADS)
  195. #include <ulocks.h>
  196. typedef usema_t *counting_sem_t;
  197. #else
  198. typedef struct counting_sem_t {
  199. CRITICAL lock;
  200. CRITICAL cv_lock;
  201. CONDVAR cv;
  202. int count;
  203. int max;
  204. } counting_sem_t;
  205. #endif
  206. NSAPI_PUBLIC COUNTING_SEMAPHORE
  207. cs_init(int initial_count)
  208. {
  209. counting_sem_t *cs = (counting_sem_t *)PERM_MALLOC(sizeof(counting_sem_t));
  210. #if defined(SOLARIS) && defined(HW_THREADS)
  211. if ( sema_init(cs, initial_count, USYNC_THREAD, NULL) < 0) {
  212. ereport(LOG_FAILURE, XP_GetAdminStr(DBT_csInitFailureS_), system_errmsg());
  213. PERM_FREE(cs);
  214. return NULL;
  215. }
  216. return (COUNTING_SEMAPHORE)cs;
  217. #elif defined(IRIX) && defined(HW_THREADS)
  218. usptr_t *arena;
  219. usconfig(CONF_INITSIZE, 64*1024);
  220. if ( (arena = usinit("/tmp/cs.locks")) == NULL)
  221. return NULL;
  222. if ( (cs = (counting_sem_t *)usnewsema(arena, 0)) == NULL)
  223. return NULL;
  224. return cs;
  225. #else
  226. cs->count = initial_count;
  227. cs->lock = crit_init();
  228. cs->cv_lock = crit_init();
  229. cs->cv = condvar_init(cs->cv_lock);
  230. return (COUNTING_SEMAPHORE)cs;
  231. #endif
  232. }
  233. NSAPI_PUBLIC void
  234. cs_terminate(COUNTING_SEMAPHORE csp)
  235. {
  236. counting_sem_t *cs = (counting_sem_t *)csp;
  237. #if defined(SOLARIS) && defined(HW_THREADS)
  238. if ( sema_destroy(cs) < 0 ) {
  239. ereport(LOG_FAILURE, XP_GetAdminStr(DBT_csTerminateFailureS_), system_errmsg());
  240. }
  241. PERM_FREE(cs);
  242. return;
  243. #elif defined(IRIX) && defined(HW_THREADS)
  244. /* usfreesema() */
  245. return;
  246. #else
  247. ns_condvar_terminate(cs->cv);
  248. crit_terminate(cs->cv_lock);
  249. crit_terminate(cs->lock);
  250. PERM_FREE(cs);
  251. return;
  252. #endif
  253. }
  254. NSAPI_PUBLIC int
  255. cs_wait(COUNTING_SEMAPHORE csp)
  256. {
  257. counting_sem_t *cs = (counting_sem_t *)csp;
  258. #if defined(SOLARIS) && defined(HW_THREADS)
  259. int ret;
  260. if ( (ret = sema_wait(cs)) < 0 ) {
  261. ereport(LOG_FAILURE, XP_GetAdminStr(DBT_csWaitFailureS_), system_errmsg());
  262. return -1;
  263. }
  264. return ret;
  265. #elif defined(IRIX) && defined(HW_THREADS)
  266. uspsema(cs);
  267. return 0;
  268. #else
  269. crit_enter(cs->lock);
  270. while ( cs->count == 0 ) {
  271. crit_enter(cs->cv_lock);
  272. crit_exit(cs->lock);
  273. condvar_wait(cs->cv);
  274. crit_exit(cs->cv_lock);
  275. crit_enter(cs->lock);
  276. }
  277. --(cs->count);
  278. crit_exit(cs->lock);
  279. return 0;
  280. #endif
  281. }
  282. NSAPI_PUBLIC int
  283. cs_trywait(COUNTING_SEMAPHORE csp)
  284. {
  285. counting_sem_t *cs = (counting_sem_t *)csp;
  286. #if defined(SOLARIS) && defined(HW_THREADS)
  287. int ret;
  288. ret = sema_trywait(cs)?-1:0;
  289. return ret;
  290. #elif defined(IRIX) && defined(HW_THREADS)
  291. int ret;
  292. ret = uscpsema(cs);
  293. return (ret == 1)?0:-1;
  294. #else
  295. crit_enter(cs->lock);
  296. if (cs->count > 0) {
  297. --(cs->count);
  298. crit_exit(cs->lock);
  299. return 0;
  300. }
  301. crit_exit(cs->lock);
  302. return -1;
  303. #endif
  304. }
  305. NSAPI_PUBLIC int
  306. cs_release(COUNTING_SEMAPHORE csp)
  307. {
  308. counting_sem_t *cs = (counting_sem_t *)csp;
  309. #if defined(SOLARIS) && defined(HW_THREADS)
  310. int ret;
  311. if ( (ret = sema_post(cs)) < 0 ) {
  312. ereport(LOG_FAILURE, XP_GetAdminStr(DBT_csPostFailureS_), system_errmsg());
  313. return -1;
  314. }
  315. return ret;
  316. #elif defined(IRIX) && defined(HW_THREADS)
  317. usvsema(cs);
  318. return 0;
  319. #else
  320. crit_enter(cs->lock);
  321. ++(cs->count);
  322. if (cs->count == 1) {
  323. crit_enter(cs->cv_lock);
  324. condvar_notify(cs->cv);
  325. crit_exit(cs->cv_lock);
  326. }
  327. crit_exit(cs->lock);
  328. return 0;
  329. #endif
  330. }