crit.cpp 10 KB

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