crit.cpp 10 KB

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