~ubuntu-branches/ubuntu/intrepid/vorbis-tools/intrepid

« back to all changes in this revision

Viewing changes to intl/lock.c

  • Committer: Bazaar Package Importer
  • Author(s): Clint Adams
  • Date: 2008-06-09 21:04:10 UTC
  • mfrom: (4.1.10 intrepid)
  • Revision ID: james.westby@ubuntu.com-20080609210410-h0dkh8f8riyiiv4m
Tags: 1.2.0-5
* Bump to Standards-Version 3.8.0. 
* Refresh upstream_r14957-ogg123_stop_decode_on_closed_buffer.diff and
  upstream_r14982-ogg123_man_page_http_only.diff to -p ab.
  closes: #484961.

Show diffs side-by-side

added added

removed removed

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