lock.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922
  1. /* Locking in multithreaded situations.
  2. Copyright (C) 2005-2006 Free Software Foundation, Inc.
  3. This program is free software; you can redistribute it and/or modify it
  4. under the terms of the GNU Library General Public License as published
  5. by the Free Software Foundation; either version 2, or (at your option)
  6. any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  10. Library General Public License for more details.
  11. You should have received a copy of the GNU Library General Public
  12. License along with this program; if not, write to the Free Software
  13. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
  14. USA. */
  15. /* Written by Bruno Haible <bruno@clisp.org>, 2005.
  16. Based on GCC's gthr-posix.h, gthr-posix95.h, gthr-solaris.h,
  17. gthr-win32.h. */
  18. #include <config.h>
  19. #include "lock.h"
  20. /* ========================================================================= */
  21. #if USE_POSIX_THREADS
  22. /* Use the POSIX threads library. */
  23. # if PTHREAD_IN_USE_DETECTION_HARD
  24. /* The function to be executed by a dummy thread. */
  25. static void *
  26. dummy_thread_func (void *arg)
  27. {
  28. return arg;
  29. }
  30. int
  31. glthread_in_use (void)
  32. {
  33. static int tested;
  34. static int result; /* 1: linked with -lpthread, 0: only with libc */
  35. if (!tested)
  36. {
  37. pthread_t thread;
  38. if (pthread_create (&thread, NULL, dummy_thread_func, NULL) != 0)
  39. /* Thread creation failed. */
  40. result = 0;
  41. else
  42. {
  43. /* Thread creation works. */
  44. void *retval;
  45. if (pthread_join (thread, &retval) != 0)
  46. abort ();
  47. result = 1;
  48. }
  49. tested = 1;
  50. }
  51. return result;
  52. }
  53. # endif
  54. /* -------------------------- gl_lock_t datatype -------------------------- */
  55. /* ------------------------- gl_rwlock_t datatype ------------------------- */
  56. # if HAVE_PTHREAD_RWLOCK
  57. # if !defined PTHREAD_RWLOCK_INITIALIZER
  58. void
  59. glthread_rwlock_init (gl_rwlock_t *lock)
  60. {
  61. if (pthread_rwlock_init (&lock->rwlock, NULL) != 0)
  62. abort ();
  63. lock->initialized = 1;
  64. }
  65. void
  66. glthread_rwlock_rdlock (gl_rwlock_t *lock)
  67. {
  68. if (!lock->initialized)
  69. {
  70. if (pthread_mutex_lock (&lock->guard) != 0)
  71. abort ();
  72. if (!lock->initialized)
  73. glthread_rwlock_init (lock);
  74. if (pthread_mutex_unlock (&lock->guard) != 0)
  75. abort ();
  76. }
  77. if (pthread_rwlock_rdlock (&lock->rwlock) != 0)
  78. abort ();
  79. }
  80. void
  81. glthread_rwlock_wrlock (gl_rwlock_t *lock)
  82. {
  83. if (!lock->initialized)
  84. {
  85. if (pthread_mutex_lock (&lock->guard) != 0)
  86. abort ();
  87. if (!lock->initialized)
  88. glthread_rwlock_init (lock);
  89. if (pthread_mutex_unlock (&lock->guard) != 0)
  90. abort ();
  91. }
  92. if (pthread_rwlock_wrlock (&lock->rwlock) != 0)
  93. abort ();
  94. }
  95. void
  96. glthread_rwlock_unlock (gl_rwlock_t *lock)
  97. {
  98. if (!lock->initialized)
  99. abort ();
  100. if (pthread_rwlock_unlock (&lock->rwlock) != 0)
  101. abort ();
  102. }
  103. void
  104. glthread_rwlock_destroy (gl_rwlock_t *lock)
  105. {
  106. if (!lock->initialized)
  107. abort ();
  108. if (pthread_rwlock_destroy (&lock->rwlock) != 0)
  109. abort ();
  110. lock->initialized = 0;
  111. }
  112. # endif
  113. # else
  114. void
  115. glthread_rwlock_init (gl_rwlock_t *lock)
  116. {
  117. if (pthread_mutex_init (&lock->lock, NULL) != 0)
  118. abort ();
  119. if (pthread_cond_init (&lock->waiting_readers, NULL) != 0)
  120. abort ();
  121. if (pthread_cond_init (&lock->waiting_writers, NULL) != 0)
  122. abort ();
  123. lock->waiting_writers_count = 0;
  124. lock->runcount = 0;
  125. }
  126. void
  127. glthread_rwlock_rdlock (gl_rwlock_t *lock)
  128. {
  129. if (pthread_mutex_lock (&lock->lock) != 0)
  130. abort ();
  131. /* Test whether only readers are currently running, and whether the runcount
  132. field will not overflow. */
  133. /* POSIX says: "It is implementation-defined whether the calling thread
  134. acquires the lock when a writer does not hold the lock and there are
  135. writers blocked on the lock." Let's say, no: give the writers a higher
  136. priority. */
  137. while (!(lock->runcount + 1 > 0 && lock->waiting_writers_count == 0))
  138. {
  139. /* This thread has to wait for a while. Enqueue it among the
  140. waiting_readers. */
  141. if (pthread_cond_wait (&lock->waiting_readers, &lock->lock) != 0)
  142. abort ();
  143. }
  144. lock->runcount++;
  145. if (pthread_mutex_unlock (&lock->lock) != 0)
  146. abort ();
  147. }
  148. void
  149. glthread_rwlock_wrlock (gl_rwlock_t *lock)
  150. {
  151. if (pthread_mutex_lock (&lock->lock) != 0)
  152. abort ();
  153. /* Test whether no readers or writers are currently running. */
  154. while (!(lock->runcount == 0))
  155. {
  156. /* This thread has to wait for a while. Enqueue it among the
  157. waiting_writers. */
  158. lock->waiting_writers_count++;
  159. if (pthread_cond_wait (&lock->waiting_writers, &lock->lock) != 0)
  160. abort ();
  161. lock->waiting_writers_count--;
  162. }
  163. lock->runcount--; /* runcount becomes -1 */
  164. if (pthread_mutex_unlock (&lock->lock) != 0)
  165. abort ();
  166. }
  167. void
  168. glthread_rwlock_unlock (gl_rwlock_t *lock)
  169. {
  170. if (pthread_mutex_lock (&lock->lock) != 0)
  171. abort ();
  172. if (lock->runcount < 0)
  173. {
  174. /* Drop a writer lock. */
  175. if (!(lock->runcount == -1))
  176. abort ();
  177. lock->runcount = 0;
  178. }
  179. else
  180. {
  181. /* Drop a reader lock. */
  182. if (!(lock->runcount > 0))
  183. abort ();
  184. lock->runcount--;
  185. }
  186. if (lock->runcount == 0)
  187. {
  188. /* POSIX recommends that "write locks shall take precedence over read
  189. locks", to avoid "writer starvation". */
  190. if (lock->waiting_writers_count > 0)
  191. {
  192. /* Wake up one of the waiting writers. */
  193. if (pthread_cond_signal (&lock->waiting_writers) != 0)
  194. abort ();
  195. }
  196. else
  197. {
  198. /* Wake up all waiting readers. */
  199. if (pthread_cond_broadcast (&lock->waiting_readers) != 0)
  200. abort ();
  201. }
  202. }
  203. if (pthread_mutex_unlock (&lock->lock) != 0)
  204. abort ();
  205. }
  206. void
  207. glthread_rwlock_destroy (gl_rwlock_t *lock)
  208. {
  209. if (pthread_mutex_destroy (&lock->lock) != 0)
  210. abort ();
  211. if (pthread_cond_destroy (&lock->waiting_readers) != 0)
  212. abort ();
  213. if (pthread_cond_destroy (&lock->waiting_writers) != 0)
  214. abort ();
  215. }
  216. # endif
  217. /* --------------------- gl_recursive_lock_t datatype --------------------- */
  218. # if HAVE_PTHREAD_MUTEX_RECURSIVE
  219. # if !(defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER || defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP)
  220. void
  221. glthread_recursive_lock_init (gl_recursive_lock_t *lock)
  222. {
  223. pthread_mutexattr_t attributes;
  224. if (pthread_mutexattr_init (&attributes) != 0)
  225. abort ();
  226. if (pthread_mutexattr_settype (&attributes, PTHREAD_MUTEX_RECURSIVE) != 0)
  227. abort ();
  228. if (pthread_mutex_init (&lock->recmutex, &attributes) != 0)
  229. abort ();
  230. if (pthread_mutexattr_destroy (&attributes) != 0)
  231. abort ();
  232. lock->initialized = 1;
  233. }
  234. void
  235. glthread_recursive_lock_lock (gl_recursive_lock_t *lock)
  236. {
  237. if (!lock->initialized)
  238. {
  239. if (pthread_mutex_lock (&lock->guard) != 0)
  240. abort ();
  241. if (!lock->initialized)
  242. glthread_recursive_lock_init (lock);
  243. if (pthread_mutex_unlock (&lock->guard) != 0)
  244. abort ();
  245. }
  246. if (pthread_mutex_lock (&lock->recmutex) != 0)
  247. abort ();
  248. }
  249. void
  250. glthread_recursive_lock_unlock (gl_recursive_lock_t *lock)
  251. {
  252. if (!lock->initialized)
  253. abort ();
  254. if (pthread_mutex_unlock (&lock->recmutex) != 0)
  255. abort ();
  256. }
  257. void
  258. glthread_recursive_lock_destroy (gl_recursive_lock_t *lock)
  259. {
  260. if (!lock->initialized)
  261. abort ();
  262. if (pthread_mutex_destroy (&lock->recmutex) != 0)
  263. abort ();
  264. lock->initialized = 0;
  265. }
  266. # endif
  267. # else
  268. void
  269. glthread_recursive_lock_init (gl_recursive_lock_t *lock)
  270. {
  271. if (pthread_mutex_init (&lock->mutex, NULL) != 0)
  272. abort ();
  273. lock->owner = (pthread_t) 0;
  274. lock->depth = 0;
  275. }
  276. void
  277. glthread_recursive_lock_lock (gl_recursive_lock_t *lock)
  278. {
  279. pthread_t self = pthread_self ();
  280. if (lock->owner != self)
  281. {
  282. if (pthread_mutex_lock (&lock->mutex) != 0)
  283. abort ();
  284. lock->owner = self;
  285. }
  286. if (++(lock->depth) == 0) /* wraparound? */
  287. abort ();
  288. }
  289. void
  290. glthread_recursive_lock_unlock (gl_recursive_lock_t *lock)
  291. {
  292. if (lock->owner != pthread_self ())
  293. abort ();
  294. if (lock->depth == 0)
  295. abort ();
  296. if (--(lock->depth) == 0)
  297. {
  298. lock->owner = (pthread_t) 0;
  299. if (pthread_mutex_unlock (&lock->mutex) != 0)
  300. abort ();
  301. }
  302. }
  303. void
  304. glthread_recursive_lock_destroy (gl_recursive_lock_t *lock)
  305. {
  306. if (lock->owner != (pthread_t) 0)
  307. abort ();
  308. if (pthread_mutex_destroy (&lock->mutex) != 0)
  309. abort ();
  310. }
  311. # endif
  312. /* -------------------------- gl_once_t datatype -------------------------- */
  313. static const pthread_once_t fresh_once = PTHREAD_ONCE_INIT;
  314. int
  315. glthread_once_singlethreaded (pthread_once_t *once_control)
  316. {
  317. /* We don't know whether pthread_once_t is an integer type, a floating-point
  318. type, a pointer type, or a structure type. */
  319. char *firstbyte = (char *)once_control;
  320. if (*firstbyte == *(const char *)&fresh_once)
  321. {
  322. /* First time use of once_control. Invert the first byte. */
  323. *firstbyte = ~ *(const char *)&fresh_once;
  324. return 1;
  325. }
  326. else
  327. return 0;
  328. }
  329. #endif
  330. /* ========================================================================= */
  331. #if USE_PTH_THREADS
  332. /* Use the GNU Pth threads library. */
  333. /* -------------------------- gl_lock_t datatype -------------------------- */
  334. /* ------------------------- gl_rwlock_t datatype ------------------------- */
  335. /* --------------------- gl_recursive_lock_t datatype --------------------- */
  336. /* -------------------------- gl_once_t datatype -------------------------- */
  337. void
  338. glthread_once_call (void *arg)
  339. {
  340. void (**gl_once_temp_addr) (void) = (void (**) (void)) arg;
  341. void (*initfunction) (void) = *gl_once_temp_addr;
  342. initfunction ();
  343. }
  344. int
  345. glthread_once_singlethreaded (pth_once_t *once_control)
  346. {
  347. /* We know that pth_once_t is an integer type. */
  348. if (*once_control == PTH_ONCE_INIT)
  349. {
  350. /* First time use of once_control. Invert the marker. */
  351. *once_control = ~ PTH_ONCE_INIT;
  352. return 1;
  353. }
  354. else
  355. return 0;
  356. }
  357. #endif
  358. /* ========================================================================= */
  359. #if USE_SOLARIS_THREADS
  360. /* Use the old Solaris threads library. */
  361. /* -------------------------- gl_lock_t datatype -------------------------- */
  362. /* ------------------------- gl_rwlock_t datatype ------------------------- */
  363. /* --------------------- gl_recursive_lock_t datatype --------------------- */
  364. void
  365. glthread_recursive_lock_init (gl_recursive_lock_t *lock)
  366. {
  367. if (mutex_init (&lock->mutex, USYNC_THREAD, NULL) != 0)
  368. abort ();
  369. lock->owner = (thread_t) 0;
  370. lock->depth = 0;
  371. }
  372. void
  373. glthread_recursive_lock_lock (gl_recursive_lock_t *lock)
  374. {
  375. thread_t self = thr_self ();
  376. if (lock->owner != self)
  377. {
  378. if (mutex_lock (&lock->mutex) != 0)
  379. abort ();
  380. lock->owner = self;
  381. }
  382. if (++(lock->depth) == 0) /* wraparound? */
  383. abort ();
  384. }
  385. void
  386. glthread_recursive_lock_unlock (gl_recursive_lock_t *lock)
  387. {
  388. if (lock->owner != thr_self ())
  389. abort ();
  390. if (lock->depth == 0)
  391. abort ();
  392. if (--(lock->depth) == 0)
  393. {
  394. lock->owner = (thread_t) 0;
  395. if (mutex_unlock (&lock->mutex) != 0)
  396. abort ();
  397. }
  398. }
  399. void
  400. glthread_recursive_lock_destroy (gl_recursive_lock_t *lock)
  401. {
  402. if (lock->owner != (thread_t) 0)
  403. abort ();
  404. if (mutex_destroy (&lock->mutex) != 0)
  405. abort ();
  406. }
  407. /* -------------------------- gl_once_t datatype -------------------------- */
  408. void
  409. glthread_once (gl_once_t *once_control, void (*initfunction) (void))
  410. {
  411. if (!once_control->inited)
  412. {
  413. /* Use the mutex to guarantee that if another thread is already calling
  414. the initfunction, this thread waits until it's finished. */
  415. if (mutex_lock (&once_control->mutex) != 0)
  416. abort ();
  417. if (!once_control->inited)
  418. {
  419. once_control->inited = 1;
  420. initfunction ();
  421. }
  422. if (mutex_unlock (&once_control->mutex) != 0)
  423. abort ();
  424. }
  425. }
  426. int
  427. glthread_once_singlethreaded (gl_once_t *once_control)
  428. {
  429. /* We know that gl_once_t contains an integer type. */
  430. if (!once_control->inited)
  431. {
  432. /* First time use of once_control. Invert the marker. */
  433. once_control->inited = ~ 0;
  434. return 1;
  435. }
  436. else
  437. return 0;
  438. }
  439. #endif
  440. /* ========================================================================= */
  441. #if USE_WIN32_THREADS
  442. /* -------------------------- gl_lock_t datatype -------------------------- */
  443. void
  444. glthread_lock_init (gl_lock_t *lock)
  445. {
  446. InitializeCriticalSection (&lock->lock);
  447. lock->guard.done = 1;
  448. }
  449. void
  450. glthread_lock_lock (gl_lock_t *lock)
  451. {
  452. if (!lock->guard.done)
  453. {
  454. if (InterlockedIncrement (&lock->guard.started) == 0)
  455. /* This thread is the first one to need this lock. Initialize it. */
  456. glthread_lock_init (lock);
  457. else
  458. /* Yield the CPU while waiting for another thread to finish
  459. initializing this lock. */
  460. while (!lock->guard.done)
  461. Sleep (0);
  462. }
  463. EnterCriticalSection (&lock->lock);
  464. }
  465. void
  466. glthread_lock_unlock (gl_lock_t *lock)
  467. {
  468. if (!lock->guard.done)
  469. abort ();
  470. LeaveCriticalSection (&lock->lock);
  471. }
  472. void
  473. glthread_lock_destroy (gl_lock_t *lock)
  474. {
  475. if (!lock->guard.done)
  476. abort ();
  477. DeleteCriticalSection (&lock->lock);
  478. lock->guard.done = 0;
  479. }
  480. /* ------------------------- gl_rwlock_t datatype ------------------------- */
  481. static inline void
  482. gl_waitqueue_init (gl_waitqueue_t *wq)
  483. {
  484. wq->array = NULL;
  485. wq->count = 0;
  486. wq->alloc = 0;
  487. wq->offset = 0;
  488. }
  489. /* Enqueues the current thread, represented by an event, in a wait queue.
  490. Returns INVALID_HANDLE_VALUE if an allocation failure occurs. */
  491. static HANDLE
  492. gl_waitqueue_add (gl_waitqueue_t *wq)
  493. {
  494. HANDLE event;
  495. unsigned int index;
  496. if (wq->count == wq->alloc)
  497. {
  498. unsigned int new_alloc = 2 * wq->alloc + 1;
  499. HANDLE *new_array =
  500. (HANDLE *) realloc (wq->array, new_alloc * sizeof (HANDLE));
  501. if (new_array == NULL)
  502. /* No more memory. */
  503. return INVALID_HANDLE_VALUE;
  504. /* Now is a good opportunity to rotate the array so that its contents
  505. starts at offset 0. */
  506. if (wq->offset > 0)
  507. {
  508. unsigned int old_count = wq->count;
  509. unsigned int old_alloc = wq->alloc;
  510. unsigned int old_offset = wq->offset;
  511. unsigned int i;
  512. if (old_offset + old_count > old_alloc)
  513. {
  514. unsigned int limit = old_offset + old_count - old_alloc;
  515. for (i = 0; i < limit; i++)
  516. new_array[old_alloc + i] = new_array[i];
  517. }
  518. for (i = 0; i < old_count; i++)
  519. new_array[i] = new_array[old_offset + i];
  520. wq->offset = 0;
  521. }
  522. wq->array = new_array;
  523. wq->alloc = new_alloc;
  524. }
  525. event = CreateEvent (NULL, TRUE, FALSE, NULL);
  526. if (event == INVALID_HANDLE_VALUE)
  527. /* No way to allocate an event. */
  528. return INVALID_HANDLE_VALUE;
  529. index = wq->offset + wq->count;
  530. if (index >= wq->alloc)
  531. index -= wq->alloc;
  532. wq->array[index] = event;
  533. wq->count++;
  534. return event;
  535. }
  536. /* Notifies the first thread from a wait queue and dequeues it. */
  537. static inline void
  538. gl_waitqueue_notify_first (gl_waitqueue_t *wq)
  539. {
  540. SetEvent (wq->array[wq->offset + 0]);
  541. wq->offset++;
  542. wq->count--;
  543. if (wq->count == 0 || wq->offset == wq->alloc)
  544. wq->offset = 0;
  545. }
  546. /* Notifies all threads from a wait queue and dequeues them all. */
  547. static inline void
  548. gl_waitqueue_notify_all (gl_waitqueue_t *wq)
  549. {
  550. unsigned int i;
  551. for (i = 0; i < wq->count; i++)
  552. {
  553. unsigned int index = wq->offset + i;
  554. if (index >= wq->alloc)
  555. index -= wq->alloc;
  556. SetEvent (wq->array[index]);
  557. }
  558. wq->count = 0;
  559. wq->offset = 0;
  560. }
  561. void
  562. glthread_rwlock_init (gl_rwlock_t *lock)
  563. {
  564. InitializeCriticalSection (&lock->lock);
  565. gl_waitqueue_init (&lock->waiting_readers);
  566. gl_waitqueue_init (&lock->waiting_writers);
  567. lock->runcount = 0;
  568. lock->guard.done = 1;
  569. }
  570. void
  571. glthread_rwlock_rdlock (gl_rwlock_t *lock)
  572. {
  573. if (!lock->guard.done)
  574. {
  575. if (InterlockedIncrement (&lock->guard.started) == 0)
  576. /* This thread is the first one to need this lock. Initialize it. */
  577. glthread_rwlock_init (lock);
  578. else
  579. /* Yield the CPU while waiting for another thread to finish
  580. initializing this lock. */
  581. while (!lock->guard.done)
  582. Sleep (0);
  583. }
  584. EnterCriticalSection (&lock->lock);
  585. /* Test whether only readers are currently running, and whether the runcount
  586. field will not overflow. */
  587. if (!(lock->runcount + 1 > 0))
  588. {
  589. /* This thread has to wait for a while. Enqueue it among the
  590. waiting_readers. */
  591. HANDLE event = gl_waitqueue_add (&lock->waiting_readers);
  592. if (event != INVALID_HANDLE_VALUE)
  593. {
  594. DWORD result;
  595. LeaveCriticalSection (&lock->lock);
  596. /* Wait until another thread signals this event. */
  597. result = WaitForSingleObject (event, INFINITE);
  598. if (result == WAIT_FAILED || result == WAIT_TIMEOUT)
  599. abort ();
  600. CloseHandle (event);
  601. /* The thread which signalled the event already did the bookkeeping:
  602. removed us from the waiting_readers, incremented lock->runcount. */
  603. if (!(lock->runcount > 0))
  604. abort ();
  605. return;
  606. }
  607. else
  608. {
  609. /* Allocation failure. Weird. */
  610. do
  611. {
  612. LeaveCriticalSection (&lock->lock);
  613. Sleep (1);
  614. EnterCriticalSection (&lock->lock);
  615. }
  616. while (!(lock->runcount + 1 > 0));
  617. }
  618. }
  619. lock->runcount++;
  620. LeaveCriticalSection (&lock->lock);
  621. }
  622. void
  623. glthread_rwlock_wrlock (gl_rwlock_t *lock)
  624. {
  625. if (!lock->guard.done)
  626. {
  627. if (InterlockedIncrement (&lock->guard.started) == 0)
  628. /* This thread is the first one to need this lock. Initialize it. */
  629. glthread_rwlock_init (lock);
  630. else
  631. /* Yield the CPU while waiting for another thread to finish
  632. initializing this lock. */
  633. while (!lock->guard.done)
  634. Sleep (0);
  635. }
  636. EnterCriticalSection (&lock->lock);
  637. /* Test whether no readers or writers are currently running. */
  638. if (!(lock->runcount == 0))
  639. {
  640. /* This thread has to wait for a while. Enqueue it among the
  641. waiting_writers. */
  642. HANDLE event = gl_waitqueue_add (&lock->waiting_writers);
  643. if (event != INVALID_HANDLE_VALUE)
  644. {
  645. DWORD result;
  646. LeaveCriticalSection (&lock->lock);
  647. /* Wait until another thread signals this event. */
  648. result = WaitForSingleObject (event, INFINITE);
  649. if (result == WAIT_FAILED || result == WAIT_TIMEOUT)
  650. abort ();
  651. CloseHandle (event);
  652. /* The thread which signalled the event already did the bookkeeping:
  653. removed us from the waiting_writers, set lock->runcount = -1. */
  654. if (!(lock->runcount == -1))
  655. abort ();
  656. return;
  657. }
  658. else
  659. {
  660. /* Allocation failure. Weird. */
  661. do
  662. {
  663. LeaveCriticalSection (&lock->lock);
  664. Sleep (1);
  665. EnterCriticalSection (&lock->lock);
  666. }
  667. while (!(lock->runcount == 0));
  668. }
  669. }
  670. lock->runcount--; /* runcount becomes -1 */
  671. LeaveCriticalSection (&lock->lock);
  672. }
  673. void
  674. glthread_rwlock_unlock (gl_rwlock_t *lock)
  675. {
  676. if (!lock->guard.done)
  677. abort ();
  678. EnterCriticalSection (&lock->lock);
  679. if (lock->runcount < 0)
  680. {
  681. /* Drop a writer lock. */
  682. if (!(lock->runcount == -1))
  683. abort ();
  684. lock->runcount = 0;
  685. }
  686. else
  687. {
  688. /* Drop a reader lock. */
  689. if (!(lock->runcount > 0))
  690. abort ();
  691. lock->runcount--;
  692. }
  693. if (lock->runcount == 0)
  694. {
  695. /* POSIX recommends that "write locks shall take precedence over read
  696. locks", to avoid "writer starvation". */
  697. if (lock->waiting_writers.count > 0)
  698. {
  699. /* Wake up one of the waiting writers. */
  700. lock->runcount--;
  701. gl_waitqueue_notify_first (&lock->waiting_writers);
  702. }
  703. else
  704. {
  705. /* Wake up all waiting readers. */
  706. lock->runcount += lock->waiting_readers.count;
  707. gl_waitqueue_notify_all (&lock->waiting_readers);
  708. }
  709. }
  710. LeaveCriticalSection (&lock->lock);
  711. }
  712. void
  713. glthread_rwlock_destroy (gl_rwlock_t *lock)
  714. {
  715. if (!lock->guard.done)
  716. abort ();
  717. if (lock->runcount != 0)
  718. abort ();
  719. DeleteCriticalSection (&lock->lock);
  720. if (lock->waiting_readers.array != NULL)
  721. free (lock->waiting_readers.array);
  722. if (lock->waiting_writers.array != NULL)
  723. free (lock->waiting_writers.array);
  724. lock->guard.done = 0;
  725. }
  726. /* --------------------- gl_recursive_lock_t datatype --------------------- */
  727. void
  728. glthread_recursive_lock_init (gl_recursive_lock_t *lock)
  729. {
  730. lock->owner = 0;
  731. lock->depth = 0;
  732. InitializeCriticalSection (&lock->lock);
  733. lock->guard.done = 1;
  734. }
  735. void
  736. glthread_recursive_lock_lock (gl_recursive_lock_t *lock)
  737. {
  738. if (!lock->guard.done)
  739. {
  740. if (InterlockedIncrement (&lock->guard.started) == 0)
  741. /* This thread is the first one to need this lock. Initialize it. */
  742. glthread_recursive_lock_init (lock);
  743. else
  744. /* Yield the CPU while waiting for another thread to finish
  745. initializing this lock. */
  746. while (!lock->guard.done)
  747. Sleep (0);
  748. }
  749. {
  750. DWORD self = GetCurrentThreadId ();
  751. if (lock->owner != self)
  752. {
  753. EnterCriticalSection (&lock->lock);
  754. lock->owner = self;
  755. }
  756. if (++(lock->depth) == 0) /* wraparound? */
  757. abort ();
  758. }
  759. }
  760. void
  761. glthread_recursive_lock_unlock (gl_recursive_lock_t *lock)
  762. {
  763. if (lock->owner != GetCurrentThreadId ())
  764. abort ();
  765. if (lock->depth == 0)
  766. abort ();
  767. if (--(lock->depth) == 0)
  768. {
  769. lock->owner = 0;
  770. LeaveCriticalSection (&lock->lock);
  771. }
  772. }
  773. void
  774. glthread_recursive_lock_destroy (gl_recursive_lock_t *lock)
  775. {
  776. if (lock->owner != 0)
  777. abort ();
  778. DeleteCriticalSection (&lock->lock);
  779. lock->guard.done = 0;
  780. }
  781. /* -------------------------- gl_once_t datatype -------------------------- */
  782. void
  783. glthread_once (gl_once_t *once_control, void (*initfunction) (void))
  784. {
  785. if (once_control->inited <= 0)
  786. {
  787. if (InterlockedIncrement (&once_control->started) == 0)
  788. {
  789. /* This thread is the first one to come to this once_control. */
  790. InitializeCriticalSection (&once_control->lock);
  791. EnterCriticalSection (&once_control->lock);
  792. once_control->inited = 0;
  793. initfunction ();
  794. once_control->inited = 1;
  795. LeaveCriticalSection (&once_control->lock);
  796. }
  797. else
  798. {
  799. /* Undo last operation. */
  800. InterlockedDecrement (&once_control->started);
  801. /* Some other thread has already started the initialization.
  802. Yield the CPU while waiting for the other thread to finish
  803. initializing and taking the lock. */
  804. while (once_control->inited < 0)
  805. Sleep (0);
  806. if (once_control->inited <= 0)
  807. {
  808. /* Take the lock. This blocks until the other thread has
  809. finished calling the initfunction. */
  810. EnterCriticalSection (&once_control->lock);
  811. LeaveCriticalSection (&once_control->lock);
  812. if (!(once_control->inited > 0))
  813. abort ();
  814. }
  815. }
  816. }
  817. }
  818. #endif
  819. /* ========================================================================= */