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