Install gettext-0.18.1.1.tar.gz
[msysgit.git] / mingw / share / gettext / intl / lock.c
blob561423e0d35ce48d6fa582f23a22c48edf131c18
1 /* Locking in multithreaded situations.
2 Copyright (C) 2005-2008 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify it
5 under the terms of the GNU Library General Public License as published
6 by the Free Software Foundation; either version 2, or (at your option)
7 any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
14 You should have received a copy of the GNU Library General Public
15 License along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
17 USA. */
19 /* Written by Bruno Haible <bruno@clisp.org>, 2005.
20 Based on GCC's gthr-posix.h, gthr-posix95.h, gthr-solaris.h,
21 gthr-win32.h. */
23 #include <config.h>
25 #include "lock.h"
27 /* ========================================================================= */
29 #if USE_POSIX_THREADS
31 /* -------------------------- gl_lock_t datatype -------------------------- */
33 /* ------------------------- gl_rwlock_t datatype ------------------------- */
35 # if HAVE_PTHREAD_RWLOCK
37 # if !defined PTHREAD_RWLOCK_INITIALIZER
39 int
40 glthread_rwlock_init_multithreaded (gl_rwlock_t *lock)
42 int err;
44 err = pthread_rwlock_init (&lock->rwlock, NULL);
45 if (err != 0)
46 return err;
47 lock->initialized = 1;
48 return 0;
51 int
52 glthread_rwlock_rdlock_multithreaded (gl_rwlock_t *lock)
54 if (!lock->initialized)
56 int err;
58 err = pthread_mutex_lock (&lock->guard);
59 if (err != 0)
60 return err;
61 if (!lock->initialized)
63 err = glthread_rwlock_init_multithreaded (lock);
64 if (err != 0)
66 pthread_mutex_unlock (&lock->guard);
67 return err;
70 err = pthread_mutex_unlock (&lock->guard);
71 if (err != 0)
72 return err;
74 return pthread_rwlock_rdlock (&lock->rwlock);
77 int
78 glthread_rwlock_wrlock_multithreaded (gl_rwlock_t *lock)
80 if (!lock->initialized)
82 int err;
84 err = pthread_mutex_lock (&lock->guard);
85 if (err != 0)
86 return err;
87 if (!lock->initialized)
89 err = glthread_rwlock_init_multithreaded (lock);
90 if (err != 0)
92 pthread_mutex_unlock (&lock->guard);
93 return err;
96 err = pthread_mutex_unlock (&lock->guard);
97 if (err != 0)
98 return err;
100 return pthread_rwlock_wrlock (&lock->rwlock);
104 glthread_rwlock_unlock_multithreaded (gl_rwlock_t *lock)
106 if (!lock->initialized)
107 return EINVAL;
108 return pthread_rwlock_unlock (&lock->rwlock);
112 glthread_rwlock_destroy_multithreaded (gl_rwlock_t *lock)
114 int err;
116 if (!lock->initialized)
117 return EINVAL;
118 err = pthread_rwlock_destroy (&lock->rwlock);
119 if (err != 0)
120 return err;
121 lock->initialized = 0;
122 return 0;
125 # endif
127 # else
130 glthread_rwlock_init_multithreaded (gl_rwlock_t *lock)
132 int err;
134 err = pthread_mutex_init (&lock->lock, NULL);
135 if (err != 0)
136 return err;
137 err = pthread_cond_init (&lock->waiting_readers, NULL);
138 if (err != 0)
139 return err;
140 err = pthread_cond_init (&lock->waiting_writers, NULL);
141 if (err != 0)
142 return err;
143 lock->waiting_writers_count = 0;
144 lock->runcount = 0;
145 return 0;
149 glthread_rwlock_rdlock_multithreaded (gl_rwlock_t *lock)
151 int err;
153 err = pthread_mutex_lock (&lock->lock);
154 if (err != 0)
155 return err;
156 /* Test whether only readers are currently running, and whether the runcount
157 field will not overflow. */
158 /* POSIX says: "It is implementation-defined whether the calling thread
159 acquires the lock when a writer does not hold the lock and there are
160 writers blocked on the lock." Let's say, no: give the writers a higher
161 priority. */
162 while (!(lock->runcount + 1 > 0 && lock->waiting_writers_count == 0))
164 /* This thread has to wait for a while. Enqueue it among the
165 waiting_readers. */
166 err = pthread_cond_wait (&lock->waiting_readers, &lock->lock);
167 if (err != 0)
169 pthread_mutex_unlock (&lock->lock);
170 return err;
173 lock->runcount++;
174 return pthread_mutex_unlock (&lock->lock);
178 glthread_rwlock_wrlock_multithreaded (gl_rwlock_t *lock)
180 int err;
182 err = pthread_mutex_lock (&lock->lock);
183 if (err != 0)
184 return err;
185 /* Test whether no readers or writers are currently running. */
186 while (!(lock->runcount == 0))
188 /* This thread has to wait for a while. Enqueue it among the
189 waiting_writers. */
190 lock->waiting_writers_count++;
191 err = pthread_cond_wait (&lock->waiting_writers, &lock->lock);
192 if (err != 0)
194 lock->waiting_writers_count--;
195 pthread_mutex_unlock (&lock->lock);
196 return err;
198 lock->waiting_writers_count--;
200 lock->runcount--; /* runcount becomes -1 */
201 return pthread_mutex_unlock (&lock->lock);
205 glthread_rwlock_unlock_multithreaded (gl_rwlock_t *lock)
207 int err;
209 err = pthread_mutex_lock (&lock->lock);
210 if (err != 0)
211 return err;
212 if (lock->runcount < 0)
214 /* Drop a writer lock. */
215 if (!(lock->runcount == -1))
217 pthread_mutex_unlock (&lock->lock);
218 return EINVAL;
220 lock->runcount = 0;
222 else
224 /* Drop a reader lock. */
225 if (!(lock->runcount > 0))
227 pthread_mutex_unlock (&lock->lock);
228 return EINVAL;
230 lock->runcount--;
232 if (lock->runcount == 0)
234 /* POSIX recommends that "write locks shall take precedence over read
235 locks", to avoid "writer starvation". */
236 if (lock->waiting_writers_count > 0)
238 /* Wake up one of the waiting writers. */
239 err = pthread_cond_signal (&lock->waiting_writers);
240 if (err != 0)
242 pthread_mutex_unlock (&lock->lock);
243 return err;
246 else
248 /* Wake up all waiting readers. */
249 err = pthread_cond_broadcast (&lock->waiting_readers);
250 if (err != 0)
252 pthread_mutex_unlock (&lock->lock);
253 return err;
257 return pthread_mutex_unlock (&lock->lock);
261 glthread_rwlock_destroy_multithreaded (gl_rwlock_t *lock)
263 int err;
265 err = pthread_mutex_destroy (&lock->lock);
266 if (err != 0)
267 return err;
268 err = pthread_cond_destroy (&lock->waiting_readers);
269 if (err != 0)
270 return err;
271 err = pthread_cond_destroy (&lock->waiting_writers);
272 if (err != 0)
273 return err;
274 return 0;
277 # endif
279 /* --------------------- gl_recursive_lock_t datatype --------------------- */
281 # if HAVE_PTHREAD_MUTEX_RECURSIVE
283 # if defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER || defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
286 glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock)
288 pthread_mutexattr_t attributes;
289 int err;
291 err = pthread_mutexattr_init (&attributes);
292 if (err != 0)
293 return err;
294 err = pthread_mutexattr_settype (&attributes, PTHREAD_MUTEX_RECURSIVE);
295 if (err != 0)
297 pthread_mutexattr_destroy (&attributes);
298 return err;
300 err = pthread_mutex_init (lock, &attributes);
301 if (err != 0)
303 pthread_mutexattr_destroy (&attributes);
304 return err;
306 err = pthread_mutexattr_destroy (&attributes);
307 if (err != 0)
308 return err;
309 return 0;
312 # else
315 glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock)
317 pthread_mutexattr_t attributes;
318 int err;
320 err = pthread_mutexattr_init (&attributes);
321 if (err != 0)
322 return err;
323 err = pthread_mutexattr_settype (&attributes, PTHREAD_MUTEX_RECURSIVE);
324 if (err != 0)
326 pthread_mutexattr_destroy (&attributes);
327 return err;
329 err = pthread_mutex_init (&lock->recmutex, &attributes);
330 if (err != 0)
332 pthread_mutexattr_destroy (&attributes);
333 return err;
335 err = pthread_mutexattr_destroy (&attributes);
336 if (err != 0)
337 return err;
338 lock->initialized = 1;
339 return 0;
343 glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock)
345 if (!lock->initialized)
347 int err;
349 err = pthread_mutex_lock (&lock->guard);
350 if (err != 0)
351 return err;
352 if (!lock->initialized)
354 err = glthread_recursive_lock_init_multithreaded (lock);
355 if (err != 0)
357 pthread_mutex_unlock (&lock->guard);
358 return err;
361 err = pthread_mutex_unlock (&lock->guard);
362 if (err != 0)
363 return err;
365 return pthread_mutex_lock (&lock->recmutex);
369 glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock)
371 if (!lock->initialized)
372 return EINVAL;
373 return pthread_mutex_unlock (&lock->recmutex);
377 glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock)
379 int err;
381 if (!lock->initialized)
382 return EINVAL;
383 err = pthread_mutex_destroy (&lock->recmutex);
384 if (err != 0)
385 return err;
386 lock->initialized = 0;
387 return 0;
390 # endif
392 # else
395 glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock)
397 int err;
399 err = pthread_mutex_init (&lock->mutex, NULL);
400 if (err != 0)
401 return err;
402 lock->owner = (pthread_t) 0;
403 lock->depth = 0;
404 return 0;
408 glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock)
410 pthread_t self = pthread_self ();
411 if (lock->owner != self)
413 int err;
415 err = pthread_mutex_lock (&lock->mutex);
416 if (err != 0)
417 return err;
418 lock->owner = self;
420 if (++(lock->depth) == 0) /* wraparound? */
422 lock->depth--;
423 return EAGAIN;
425 return 0;
429 glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock)
431 if (lock->owner != pthread_self ())
432 return EPERM;
433 if (lock->depth == 0)
434 return EINVAL;
435 if (--(lock->depth) == 0)
437 lock->owner = (pthread_t) 0;
438 return pthread_mutex_unlock (&lock->mutex);
440 else
441 return 0;
445 glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock)
447 if (lock->owner != (pthread_t) 0)
448 return EBUSY;
449 return pthread_mutex_destroy (&lock->mutex);
452 # endif
454 /* -------------------------- gl_once_t datatype -------------------------- */
456 static const pthread_once_t fresh_once = PTHREAD_ONCE_INIT;
459 glthread_once_singlethreaded (pthread_once_t *once_control)
461 /* We don't know whether pthread_once_t is an integer type, a floating-point
462 type, a pointer type, or a structure type. */
463 char *firstbyte = (char *)once_control;
464 if (*firstbyte == *(const char *)&fresh_once)
466 /* First time use of once_control. Invert the first byte. */
467 *firstbyte = ~ *(const char *)&fresh_once;
468 return 1;
470 else
471 return 0;
474 #endif
476 /* ========================================================================= */
478 #if USE_PTH_THREADS
480 /* Use the GNU Pth threads library. */
482 /* -------------------------- gl_lock_t datatype -------------------------- */
484 /* ------------------------- gl_rwlock_t datatype ------------------------- */
486 /* --------------------- gl_recursive_lock_t datatype --------------------- */
488 /* -------------------------- gl_once_t datatype -------------------------- */
490 static void
491 glthread_once_call (void *arg)
493 void (**gl_once_temp_addr) (void) = (void (**) (void)) arg;
494 void (*initfunction) (void) = *gl_once_temp_addr;
495 initfunction ();
499 glthread_once_multithreaded (pth_once_t *once_control, void (*initfunction) (void))
501 void (*temp) (void) = initfunction;
502 return (!pth_once (once_control, glthread_once_call, &temp) ? errno : 0);
506 glthread_once_singlethreaded (pth_once_t *once_control)
508 /* We know that pth_once_t is an integer type. */
509 if (*once_control == PTH_ONCE_INIT)
511 /* First time use of once_control. Invert the marker. */
512 *once_control = ~ PTH_ONCE_INIT;
513 return 1;
515 else
516 return 0;
519 #endif
521 /* ========================================================================= */
523 #if USE_SOLARIS_THREADS
525 /* Use the old Solaris threads library. */
527 /* -------------------------- gl_lock_t datatype -------------------------- */
529 /* ------------------------- gl_rwlock_t datatype ------------------------- */
531 /* --------------------- gl_recursive_lock_t datatype --------------------- */
534 glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock)
536 int err;
538 err = mutex_init (&lock->mutex, USYNC_THREAD, NULL);
539 if (err != 0)
540 return err;
541 lock->owner = (thread_t) 0;
542 lock->depth = 0;
543 return 0;
547 glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock)
549 thread_t self = thr_self ();
550 if (lock->owner != self)
552 int err;
554 err = mutex_lock (&lock->mutex);
555 if (err != 0)
556 return err;
557 lock->owner = self;
559 if (++(lock->depth) == 0) /* wraparound? */
561 lock->depth--;
562 return EAGAIN;
564 return 0;
568 glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock)
570 if (lock->owner != thr_self ())
571 return EPERM;
572 if (lock->depth == 0)
573 return EINVAL;
574 if (--(lock->depth) == 0)
576 lock->owner = (thread_t) 0;
577 return mutex_unlock (&lock->mutex);
579 else
580 return 0;
584 glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock)
586 if (lock->owner != (thread_t) 0)
587 return EBUSY;
588 return mutex_destroy (&lock->mutex);
591 /* -------------------------- gl_once_t datatype -------------------------- */
594 glthread_once_multithreaded (gl_once_t *once_control, void (*initfunction) (void))
596 if (!once_control->inited)
598 int err;
600 /* Use the mutex to guarantee that if another thread is already calling
601 the initfunction, this thread waits until it's finished. */
602 err = mutex_lock (&once_control->mutex);
603 if (err != 0)
604 return err;
605 if (!once_control->inited)
607 once_control->inited = 1;
608 initfunction ();
610 return mutex_unlock (&once_control->mutex);
612 else
613 return 0;
617 glthread_once_singlethreaded (gl_once_t *once_control)
619 /* We know that gl_once_t contains an integer type. */
620 if (!once_control->inited)
622 /* First time use of once_control. Invert the marker. */
623 once_control->inited = ~ 0;
624 return 1;
626 else
627 return 0;
630 #endif
632 /* ========================================================================= */
634 #if USE_WIN32_THREADS
636 /* -------------------------- gl_lock_t datatype -------------------------- */
638 void
639 glthread_lock_init_func (gl_lock_t *lock)
641 InitializeCriticalSection (&lock->lock);
642 lock->guard.done = 1;
646 glthread_lock_lock_func (gl_lock_t *lock)
648 if (!lock->guard.done)
650 if (InterlockedIncrement (&lock->guard.started) == 0)
651 /* This thread is the first one to need this lock. Initialize it. */
652 glthread_lock_init (lock);
653 else
654 /* Yield the CPU while waiting for another thread to finish
655 initializing this lock. */
656 while (!lock->guard.done)
657 Sleep (0);
659 EnterCriticalSection (&lock->lock);
660 return 0;
664 glthread_lock_unlock_func (gl_lock_t *lock)
666 if (!lock->guard.done)
667 return EINVAL;
668 LeaveCriticalSection (&lock->lock);
669 return 0;
673 glthread_lock_destroy_func (gl_lock_t *lock)
675 if (!lock->guard.done)
676 return EINVAL;
677 DeleteCriticalSection (&lock->lock);
678 lock->guard.done = 0;
679 return 0;
682 /* ------------------------- gl_rwlock_t datatype ------------------------- */
684 /* In this file, the waitqueues are implemented as circular arrays. */
685 #define gl_waitqueue_t gl_carray_waitqueue_t
687 static inline void
688 gl_waitqueue_init (gl_waitqueue_t *wq)
690 wq->array = NULL;
691 wq->count = 0;
692 wq->alloc = 0;
693 wq->offset = 0;
696 /* Enqueues the current thread, represented by an event, in a wait queue.
697 Returns INVALID_HANDLE_VALUE if an allocation failure occurs. */
698 static HANDLE
699 gl_waitqueue_add (gl_waitqueue_t *wq)
701 HANDLE event;
702 unsigned int index;
704 if (wq->count == wq->alloc)
706 unsigned int new_alloc = 2 * wq->alloc + 1;
707 HANDLE *new_array =
708 (HANDLE *) realloc (wq->array, new_alloc * sizeof (HANDLE));
709 if (new_array == NULL)
710 /* No more memory. */
711 return INVALID_HANDLE_VALUE;
712 /* Now is a good opportunity to rotate the array so that its contents
713 starts at offset 0. */
714 if (wq->offset > 0)
716 unsigned int old_count = wq->count;
717 unsigned int old_alloc = wq->alloc;
718 unsigned int old_offset = wq->offset;
719 unsigned int i;
720 if (old_offset + old_count > old_alloc)
722 unsigned int limit = old_offset + old_count - old_alloc;
723 for (i = 0; i < limit; i++)
724 new_array[old_alloc + i] = new_array[i];
726 for (i = 0; i < old_count; i++)
727 new_array[i] = new_array[old_offset + i];
728 wq->offset = 0;
730 wq->array = new_array;
731 wq->alloc = new_alloc;
733 /* Whether the created event is a manual-reset one or an auto-reset one,
734 does not matter, since we will wait on it only once. */
735 event = CreateEvent (NULL, TRUE, FALSE, NULL);
736 if (event == INVALID_HANDLE_VALUE)
737 /* No way to allocate an event. */
738 return INVALID_HANDLE_VALUE;
739 index = wq->offset + wq->count;
740 if (index >= wq->alloc)
741 index -= wq->alloc;
742 wq->array[index] = event;
743 wq->count++;
744 return event;
747 /* Notifies the first thread from a wait queue and dequeues it. */
748 static inline void
749 gl_waitqueue_notify_first (gl_waitqueue_t *wq)
751 SetEvent (wq->array[wq->offset + 0]);
752 wq->offset++;
753 wq->count--;
754 if (wq->count == 0 || wq->offset == wq->alloc)
755 wq->offset = 0;
758 /* Notifies all threads from a wait queue and dequeues them all. */
759 static inline void
760 gl_waitqueue_notify_all (gl_waitqueue_t *wq)
762 unsigned int i;
764 for (i = 0; i < wq->count; i++)
766 unsigned int index = wq->offset + i;
767 if (index >= wq->alloc)
768 index -= wq->alloc;
769 SetEvent (wq->array[index]);
771 wq->count = 0;
772 wq->offset = 0;
775 void
776 glthread_rwlock_init_func (gl_rwlock_t *lock)
778 InitializeCriticalSection (&lock->lock);
779 gl_waitqueue_init (&lock->waiting_readers);
780 gl_waitqueue_init (&lock->waiting_writers);
781 lock->runcount = 0;
782 lock->guard.done = 1;
786 glthread_rwlock_rdlock_func (gl_rwlock_t *lock)
788 if (!lock->guard.done)
790 if (InterlockedIncrement (&lock->guard.started) == 0)
791 /* This thread is the first one to need this lock. Initialize it. */
792 glthread_rwlock_init (lock);
793 else
794 /* Yield the CPU while waiting for another thread to finish
795 initializing this lock. */
796 while (!lock->guard.done)
797 Sleep (0);
799 EnterCriticalSection (&lock->lock);
800 /* Test whether only readers are currently running, and whether the runcount
801 field will not overflow. */
802 if (!(lock->runcount + 1 > 0))
804 /* This thread has to wait for a while. Enqueue it among the
805 waiting_readers. */
806 HANDLE event = gl_waitqueue_add (&lock->waiting_readers);
807 if (event != INVALID_HANDLE_VALUE)
809 DWORD result;
810 LeaveCriticalSection (&lock->lock);
811 /* Wait until another thread signals this event. */
812 result = WaitForSingleObject (event, INFINITE);
813 if (result == WAIT_FAILED || result == WAIT_TIMEOUT)
814 abort ();
815 CloseHandle (event);
816 /* The thread which signalled the event already did the bookkeeping:
817 removed us from the waiting_readers, incremented lock->runcount. */
818 if (!(lock->runcount > 0))
819 abort ();
820 return 0;
822 else
824 /* Allocation failure. Weird. */
827 LeaveCriticalSection (&lock->lock);
828 Sleep (1);
829 EnterCriticalSection (&lock->lock);
831 while (!(lock->runcount + 1 > 0));
834 lock->runcount++;
835 LeaveCriticalSection (&lock->lock);
836 return 0;
840 glthread_rwlock_wrlock_func (gl_rwlock_t *lock)
842 if (!lock->guard.done)
844 if (InterlockedIncrement (&lock->guard.started) == 0)
845 /* This thread is the first one to need this lock. Initialize it. */
846 glthread_rwlock_init (lock);
847 else
848 /* Yield the CPU while waiting for another thread to finish
849 initializing this lock. */
850 while (!lock->guard.done)
851 Sleep (0);
853 EnterCriticalSection (&lock->lock);
854 /* Test whether no readers or writers are currently running. */
855 if (!(lock->runcount == 0))
857 /* This thread has to wait for a while. Enqueue it among the
858 waiting_writers. */
859 HANDLE event = gl_waitqueue_add (&lock->waiting_writers);
860 if (event != INVALID_HANDLE_VALUE)
862 DWORD result;
863 LeaveCriticalSection (&lock->lock);
864 /* Wait until another thread signals this event. */
865 result = WaitForSingleObject (event, INFINITE);
866 if (result == WAIT_FAILED || result == WAIT_TIMEOUT)
867 abort ();
868 CloseHandle (event);
869 /* The thread which signalled the event already did the bookkeeping:
870 removed us from the waiting_writers, set lock->runcount = -1. */
871 if (!(lock->runcount == -1))
872 abort ();
873 return 0;
875 else
877 /* Allocation failure. Weird. */
880 LeaveCriticalSection (&lock->lock);
881 Sleep (1);
882 EnterCriticalSection (&lock->lock);
884 while (!(lock->runcount == 0));
887 lock->runcount--; /* runcount becomes -1 */
888 LeaveCriticalSection (&lock->lock);
889 return 0;
893 glthread_rwlock_unlock_func (gl_rwlock_t *lock)
895 if (!lock->guard.done)
896 return EINVAL;
897 EnterCriticalSection (&lock->lock);
898 if (lock->runcount < 0)
900 /* Drop a writer lock. */
901 if (!(lock->runcount == -1))
902 abort ();
903 lock->runcount = 0;
905 else
907 /* Drop a reader lock. */
908 if (!(lock->runcount > 0))
910 LeaveCriticalSection (&lock->lock);
911 return EPERM;
913 lock->runcount--;
915 if (lock->runcount == 0)
917 /* POSIX recommends that "write locks shall take precedence over read
918 locks", to avoid "writer starvation". */
919 if (lock->waiting_writers.count > 0)
921 /* Wake up one of the waiting writers. */
922 lock->runcount--;
923 gl_waitqueue_notify_first (&lock->waiting_writers);
925 else
927 /* Wake up all waiting readers. */
928 lock->runcount += lock->waiting_readers.count;
929 gl_waitqueue_notify_all (&lock->waiting_readers);
932 LeaveCriticalSection (&lock->lock);
933 return 0;
937 glthread_rwlock_destroy_func (gl_rwlock_t *lock)
939 if (!lock->guard.done)
940 return EINVAL;
941 if (lock->runcount != 0)
942 return EBUSY;
943 DeleteCriticalSection (&lock->lock);
944 if (lock->waiting_readers.array != NULL)
945 free (lock->waiting_readers.array);
946 if (lock->waiting_writers.array != NULL)
947 free (lock->waiting_writers.array);
948 lock->guard.done = 0;
949 return 0;
952 /* --------------------- gl_recursive_lock_t datatype --------------------- */
954 void
955 glthread_recursive_lock_init_func (gl_recursive_lock_t *lock)
957 lock->owner = 0;
958 lock->depth = 0;
959 InitializeCriticalSection (&lock->lock);
960 lock->guard.done = 1;
964 glthread_recursive_lock_lock_func (gl_recursive_lock_t *lock)
966 if (!lock->guard.done)
968 if (InterlockedIncrement (&lock->guard.started) == 0)
969 /* This thread is the first one to need this lock. Initialize it. */
970 glthread_recursive_lock_init (lock);
971 else
972 /* Yield the CPU while waiting for another thread to finish
973 initializing this lock. */
974 while (!lock->guard.done)
975 Sleep (0);
978 DWORD self = GetCurrentThreadId ();
979 if (lock->owner != self)
981 EnterCriticalSection (&lock->lock);
982 lock->owner = self;
984 if (++(lock->depth) == 0) /* wraparound? */
986 lock->depth--;
987 return EAGAIN;
990 return 0;
994 glthread_recursive_lock_unlock_func (gl_recursive_lock_t *lock)
996 if (lock->owner != GetCurrentThreadId ())
997 return EPERM;
998 if (lock->depth == 0)
999 return EINVAL;
1000 if (--(lock->depth) == 0)
1002 lock->owner = 0;
1003 LeaveCriticalSection (&lock->lock);
1005 return 0;
1009 glthread_recursive_lock_destroy_func (gl_recursive_lock_t *lock)
1011 if (lock->owner != 0)
1012 return EBUSY;
1013 DeleteCriticalSection (&lock->lock);
1014 lock->guard.done = 0;
1015 return 0;
1018 /* -------------------------- gl_once_t datatype -------------------------- */
1020 void
1021 glthread_once_func (gl_once_t *once_control, void (*initfunction) (void))
1023 if (once_control->inited <= 0)
1025 if (InterlockedIncrement (&once_control->started) == 0)
1027 /* This thread is the first one to come to this once_control. */
1028 InitializeCriticalSection (&once_control->lock);
1029 EnterCriticalSection (&once_control->lock);
1030 once_control->inited = 0;
1031 initfunction ();
1032 once_control->inited = 1;
1033 LeaveCriticalSection (&once_control->lock);
1035 else
1037 /* Undo last operation. */
1038 InterlockedDecrement (&once_control->started);
1039 /* Some other thread has already started the initialization.
1040 Yield the CPU while waiting for the other thread to finish
1041 initializing and taking the lock. */
1042 while (once_control->inited < 0)
1043 Sleep (0);
1044 if (once_control->inited <= 0)
1046 /* Take the lock. This blocks until the other thread has
1047 finished calling the initfunction. */
1048 EnterCriticalSection (&once_control->lock);
1049 LeaveCriticalSection (&once_control->lock);
1050 if (!(once_control->inited > 0))
1051 abort ();
1057 #endif
1059 /* ========================================================================= */