crit.cpp 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  1. /** BEGIN COPYRIGHT BLOCK
  2. * This Program is free software; you can redistribute it and/or modify it under
  3. * the terms of the GNU General Public License as published by the Free Software
  4. * Foundation; version 2 of the License.
  5. *
  6. * This Program is distributed in the hope that it will be useful, but WITHOUT
  7. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  8. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  9. *
  10. * You should have received a copy of the GNU General Public License along with
  11. * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
  12. * Place, Suite 330, Boston, MA 02111-1307 USA.
  13. *
  14. * In addition, as a special exception, Red Hat, Inc. gives You the additional
  15. * right to link the code of this Program with code not covered under the GNU
  16. * General Public License ("Non-GPL Code") and to distribute linked combinations
  17. * including the two, subject to the limitations in this paragraph. Non-GPL Code
  18. * permitted under this exception must only link to the code of this Program
  19. * through those well defined interfaces identified in the file named EXCEPTION
  20. * found in the source code files (the "Approved Interfaces"). The files of
  21. * Non-GPL Code may instantiate templates or use macros or inline functions from
  22. * the Approved Interfaces without causing the resulting work to be covered by
  23. * the GNU General Public License. Only Red Hat, Inc. may make changes or
  24. * additions to the list of Approved Interfaces. You must obey the GNU General
  25. * Public License in all respects for all of the Program code and other code used
  26. * in conjunction with the Program except the Non-GPL Code covered by this
  27. * exception. If you modify this file, you may extend this exception to your
  28. * version of the file, but you are not obligated to do so. If you do not wish to
  29. * provide this exception without modification, you must delete this exception
  30. * statement from your version and license this file solely under the GPL without
  31. * exception.
  32. *
  33. *
  34. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  35. * Copyright (C) 2005 Red Hat, Inc.
  36. * All rights reserved.
  37. * END COPYRIGHT BLOCK **/
  38. #ifdef HAVE_CONFIG_H
  39. # include <config.h>
  40. #endif
  41. /*
  42. * crit.c: Critical section abstraction. Used in threaded servers to protect
  43. * areas where two threads can interfere with each other.
  44. *
  45. * Condvars are condition variables that are used for thread-thread
  46. * synchronization.
  47. *
  48. * Rob McCool
  49. */
  50. #include "systems.h"
  51. #include "netsite.h"
  52. #include "crit.h"
  53. #include "pool.h"
  54. #ifdef USE_NSPR
  55. #include "nspr.h"
  56. #include "prthread.h"
  57. #include "prlock.h"
  58. #include "prcvar.h"
  59. #include "prinrval.h"
  60. /*
  61. * Defined to replace PR_Monitor() with PR_Lock().
  62. */
  63. typedef struct critical {
  64. PRLock *lock;
  65. PRUint32 count;
  66. PRThread *owner;
  67. } critical_t;
  68. typedef struct condvar {
  69. critical_t *lock;
  70. PRCondVar *cvar;
  71. } condvar_t;
  72. #endif
  73. /* -------------------------- critical sections --------------------------- */
  74. /* Useful for ASSERTs only. Returns non-zero if the current thread is the owner.
  75. */
  76. NSAPI_PUBLIC int crit_owner_is_me(CRITICAL id)
  77. {
  78. #ifdef USE_NSPR
  79. critical_t *crit = (critical_t*)id;
  80. return (crit->owner == PR_GetCurrentThread());
  81. #else
  82. return 1;
  83. #endif
  84. }
  85. NSAPI_PUBLIC CRITICAL crit_init(void)
  86. {
  87. #ifdef USE_NSPR
  88. critical_t *crit = (critical_t*)PERM_MALLOC(sizeof(critical_t)) ;
  89. if (crit) {
  90. if (!(crit->lock = PR_NewLock())) {
  91. PERM_FREE(crit);
  92. return NULL;
  93. }
  94. crit->count = 0;
  95. crit->owner = 0;
  96. }
  97. return (void *) crit;
  98. #else
  99. return NULL;
  100. #endif
  101. }
  102. NSAPI_PUBLIC void crit_enter(CRITICAL id)
  103. {
  104. #ifdef USE_NSPR
  105. critical_t *crit = (critical_t*)id;
  106. PRThread *me = PR_GetCurrentThread();
  107. if ( crit->owner == me) {
  108. PR_ASSERT(crit->count > 0);
  109. crit->count++;
  110. }
  111. else {
  112. PR_Lock(crit->lock);
  113. PR_ASSERT(crit->count == 0);
  114. crit->count = 1;
  115. crit->owner = me;
  116. }
  117. #endif
  118. }
  119. NSAPI_PUBLIC void crit_exit(CRITICAL id)
  120. {
  121. #ifdef USE_NSPR
  122. critical_t *crit = (critical_t*)id;
  123. if (crit->owner != PR_GetCurrentThread())
  124. return;
  125. if ( --crit->count == 0) {
  126. crit->owner = 0;
  127. PR_Unlock(crit->lock);
  128. }
  129. #endif
  130. }
  131. NSAPI_PUBLIC void crit_terminate(CRITICAL id)
  132. {
  133. #ifdef USE_NSPR
  134. critical_t *crit = (critical_t*)id;
  135. PR_DestroyLock((PRLock*)crit->lock);
  136. PERM_FREE(crit);
  137. #endif
  138. }
  139. /* ------------------------- condition variables -------------------------- */
  140. NSAPI_PUBLIC CONDVAR condvar_init(CRITICAL id)
  141. {
  142. #ifdef USE_NSPR
  143. critical_t *crit = (critical_t*)id;
  144. condvar_t *cvar = (condvar_t*)PERM_MALLOC(sizeof(condvar_t)) ;
  145. if (crit) {
  146. cvar->lock = crit;
  147. if ((cvar->cvar = PR_NewCondVar((PRLock *)cvar->lock->lock)) == 0) {
  148. PERM_FREE(cvar);
  149. return NULL;
  150. }
  151. }
  152. return (void *) cvar;
  153. #endif
  154. }
  155. NSAPI_PUBLIC void condvar_wait(CONDVAR _cv)
  156. {
  157. #ifdef USE_NSPR
  158. condvar_t *cv = (condvar_t *)_cv;
  159. /* Save away recursion count so we can restore it after the wait */
  160. int saveCount = cv->lock->count;
  161. PRThread *saveOwner = cv->lock->owner;
  162. PR_ASSERT(cv->lock->owner == PR_GetCurrentThread());
  163. cv->lock->count = 0;
  164. cv->lock->owner = 0;
  165. PR_WaitCondVar(cv->cvar, PR_INTERVAL_NO_TIMEOUT);
  166. cv->lock->count = saveCount;
  167. cv->lock->owner = saveOwner;
  168. #endif
  169. }
  170. NSAPI_PUBLIC void condvar_timed_wait(CONDVAR _cv, long secs)
  171. {
  172. #ifdef USE_NSPR
  173. condvar_t *cv = (condvar_t *)_cv;
  174. /* Save away recursion count so we can restore it after the wait */
  175. int saveCount = cv->lock->count;
  176. PRThread *saveOwner = cv->lock->owner;
  177. PR_ASSERT(cv->lock->owner == PR_GetCurrentThread());
  178. cv->lock->count = 0;
  179. cv->lock->owner = 0;
  180. PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT;
  181. if (secs > 0)
  182. timeout = PR_SecondsToInterval(secs);
  183. PR_WaitCondVar(cv->cvar, timeout);
  184. cv->lock->count = saveCount;
  185. cv->lock->owner = saveOwner;
  186. #endif
  187. }
  188. NSAPI_PUBLIC void condvar_notify(CONDVAR _cv)
  189. {
  190. #ifdef USE_NSPR
  191. condvar_t *cv = (condvar_t *)_cv;
  192. PR_ASSERT(cv->lock->owner == PR_GetCurrentThread());
  193. PR_NotifyCondVar(cv->cvar);
  194. #endif
  195. }
  196. NSAPI_PUBLIC void condvar_notifyAll(CONDVAR _cv)
  197. {
  198. #ifdef USE_NSPR
  199. condvar_t *cv = (condvar_t *)_cv;
  200. PR_ASSERT(cv->lock->owner == PR_GetCurrentThread());
  201. PR_NotifyAllCondVar(cv->cvar);
  202. #endif
  203. }
  204. NSAPI_PUBLIC void condvar_terminate(CONDVAR _cv)
  205. {
  206. #ifdef USE_NSPR
  207. condvar_t *cv = (condvar_t *)_cv;
  208. PR_DestroyCondVar(cv->cvar);
  209. PERM_FREE(cv);
  210. #endif
  211. }
  212. /* ----------------------- Counting semaphores ---------------------------- */
  213. /* These are currently not listed in crit.h because they aren't yet used;
  214. * although they do work.
  215. */
  216. /*
  217. * XXXMB - these should be in NSPR.
  218. *
  219. */
  220. #if defined(SOLARIS) && defined(HW_THREADS)
  221. #include <synch.h>
  222. typedef sema_t counting_sem_t;
  223. #elif defined(IRIX) && defined(HW_THREADS)
  224. #include <ulocks.h>
  225. typedef usema_t *counting_sem_t;
  226. #else
  227. typedef struct counting_sem_t {
  228. CRITICAL lock;
  229. CRITICAL cv_lock;
  230. CONDVAR cv;
  231. int count;
  232. int max;
  233. } counting_sem_t;
  234. #endif
  235. NSAPI_PUBLIC COUNTING_SEMAPHORE
  236. cs_init(int initial_count)
  237. {
  238. counting_sem_t *cs = (counting_sem_t *)PERM_MALLOC(sizeof(counting_sem_t));
  239. #if defined(SOLARIS) && defined(HW_THREADS)
  240. if ( sema_init(cs, initial_count, USYNC_THREAD, NULL) < 0) {
  241. ereport(LOG_FAILURE, XP_GetAdminStr(DBT_csInitFailureS_), system_errmsg());
  242. PERM_FREE(cs);
  243. return NULL;
  244. }
  245. return (COUNTING_SEMAPHORE)cs;
  246. #elif defined(IRIX) && defined(HW_THREADS)
  247. usptr_t *arena;
  248. usconfig(CONF_INITSIZE, 64*1024);
  249. if ( (arena = usinit("/tmp/cs.locks")) == NULL)
  250. return NULL;
  251. if ( (cs = (counting_sem_t *)usnewsema(arena, 0)) == NULL)
  252. return NULL;
  253. return cs;
  254. #else
  255. cs->count = initial_count;
  256. cs->lock = crit_init();
  257. cs->cv_lock = crit_init();
  258. cs->cv = condvar_init(cs->cv_lock);
  259. return (COUNTING_SEMAPHORE)cs;
  260. #endif
  261. }
  262. NSAPI_PUBLIC void
  263. cs_terminate(COUNTING_SEMAPHORE csp)
  264. {
  265. counting_sem_t *cs = (counting_sem_t *)csp;
  266. #if defined(SOLARIS) && defined(HW_THREADS)
  267. if ( sema_destroy(cs) < 0 ) {
  268. ereport(LOG_FAILURE, XP_GetAdminStr(DBT_csTerminateFailureS_), system_errmsg());
  269. }
  270. PERM_FREE(cs);
  271. return;
  272. #elif defined(IRIX) && defined(HW_THREADS)
  273. /* usfreesema() */
  274. return;
  275. #else
  276. condvar_terminate(cs->cv);
  277. crit_terminate(cs->cv_lock);
  278. crit_terminate(cs->lock);
  279. PERM_FREE(cs);
  280. return;
  281. #endif
  282. }
  283. NSAPI_PUBLIC int
  284. cs_wait(COUNTING_SEMAPHORE csp)
  285. {
  286. counting_sem_t *cs = (counting_sem_t *)csp;
  287. #if defined(SOLARIS) && defined(HW_THREADS)
  288. int ret;
  289. if ( (ret = sema_wait(cs)) < 0 ) {
  290. ereport(LOG_FAILURE, XP_GetAdminStr(DBT_csWaitFailureS_), system_errmsg());
  291. return -1;
  292. }
  293. return ret;
  294. #elif defined(IRIX) && defined(HW_THREADS)
  295. uspsema(cs);
  296. return 0;
  297. #else
  298. crit_enter(cs->lock);
  299. while ( cs->count == 0 ) {
  300. crit_enter(cs->cv_lock);
  301. crit_exit(cs->lock);
  302. condvar_wait(cs->cv);
  303. crit_exit(cs->cv_lock);
  304. crit_enter(cs->lock);
  305. }
  306. --(cs->count);
  307. crit_exit(cs->lock);
  308. return 0;
  309. #endif
  310. }
  311. NSAPI_PUBLIC int
  312. cs_trywait(COUNTING_SEMAPHORE csp)
  313. {
  314. counting_sem_t *cs = (counting_sem_t *)csp;
  315. #if defined(SOLARIS) && defined(HW_THREADS)
  316. int ret;
  317. ret = sema_trywait(cs)?-1:0;
  318. return ret;
  319. #elif defined(IRIX) && defined(HW_THREADS)
  320. int ret;
  321. ret = uscpsema(cs);
  322. return (ret == 1)?0:-1;
  323. #else
  324. crit_enter(cs->lock);
  325. if (cs->count > 0) {
  326. --(cs->count);
  327. crit_exit(cs->lock);
  328. return 0;
  329. }
  330. crit_exit(cs->lock);
  331. return -1;
  332. #endif
  333. }
  334. NSAPI_PUBLIC int
  335. cs_release(COUNTING_SEMAPHORE csp)
  336. {
  337. counting_sem_t *cs = (counting_sem_t *)csp;
  338. #if defined(SOLARIS) && defined(HW_THREADS)
  339. int ret;
  340. if ( (ret = sema_post(cs)) < 0 ) {
  341. ereport(LOG_FAILURE, XP_GetAdminStr(DBT_csPostFailureS_), system_errmsg());
  342. return -1;
  343. }
  344. return ret;
  345. #elif defined(IRIX) && defined(HW_THREADS)
  346. usvsema(cs);
  347. return 0;
  348. #else
  349. crit_enter(cs->lock);
  350. ++(cs->count);
  351. if (cs->count == 1) {
  352. crit_enter(cs->cv_lock);
  353. condvar_notify(cs->cv);
  354. crit_exit(cs->cv_lock);
  355. }
  356. crit_exit(cs->lock);
  357. return 0;
  358. #endif
  359. }