105436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Locking in multithreaded situations.
205436638acc7c010349a69c3395f1a57c642dc62Ying Wang   Copyright (C) 2005-2012 Free Software Foundation, Inc.
305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
405436638acc7c010349a69c3395f1a57c642dc62Ying Wang   This program is free software; you can redistribute it and/or modify
505436638acc7c010349a69c3395f1a57c642dc62Ying Wang   it under the terms of the GNU General Public License as published by
605436638acc7c010349a69c3395f1a57c642dc62Ying Wang   the Free Software Foundation; either version 3, or (at your option)
705436638acc7c010349a69c3395f1a57c642dc62Ying Wang   any later version.
805436638acc7c010349a69c3395f1a57c642dc62Ying Wang
905436638acc7c010349a69c3395f1a57c642dc62Ying Wang   This program is distributed in the hope that it will be useful,
1005436638acc7c010349a69c3395f1a57c642dc62Ying Wang   but WITHOUT ANY WARRANTY; without even the implied warranty of
1105436638acc7c010349a69c3395f1a57c642dc62Ying Wang   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1205436638acc7c010349a69c3395f1a57c642dc62Ying Wang   GNU General Public License for more details.
1305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
1405436638acc7c010349a69c3395f1a57c642dc62Ying Wang   You should have received a copy of the GNU General Public License
1505436638acc7c010349a69c3395f1a57c642dc62Ying Wang   along with this program; if not, see <http://www.gnu.org/licenses/>.  */
1605436638acc7c010349a69c3395f1a57c642dc62Ying Wang
1705436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Written by Bruno Haible <bruno@clisp.org>, 2005.
1805436638acc7c010349a69c3395f1a57c642dc62Ying Wang   Based on GCC's gthr-posix.h, gthr-posix95.h, gthr-solaris.h,
1905436638acc7c010349a69c3395f1a57c642dc62Ying Wang   gthr-win32.h.  */
2005436638acc7c010349a69c3395f1a57c642dc62Ying Wang
2105436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <config.h>
2205436638acc7c010349a69c3395f1a57c642dc62Ying Wang
2305436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include "glthread/lock.h"
2405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
2505436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* ========================================================================= */
2605436638acc7c010349a69c3395f1a57c642dc62Ying Wang
2705436638acc7c010349a69c3395f1a57c642dc62Ying Wang#if USE_POSIX_THREADS
2805436638acc7c010349a69c3395f1a57c642dc62Ying Wang
2905436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* -------------------------- gl_lock_t datatype -------------------------- */
3005436638acc7c010349a69c3395f1a57c642dc62Ying Wang
3105436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* ------------------------- gl_rwlock_t datatype ------------------------- */
3205436638acc7c010349a69c3395f1a57c642dc62Ying Wang
3305436638acc7c010349a69c3395f1a57c642dc62Ying Wang# if HAVE_PTHREAD_RWLOCK
3405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
3505436638acc7c010349a69c3395f1a57c642dc62Ying Wang#  if !defined PTHREAD_RWLOCK_INITIALIZER
3605436638acc7c010349a69c3395f1a57c642dc62Ying Wang
3705436638acc7c010349a69c3395f1a57c642dc62Ying Wangint
3805436638acc7c010349a69c3395f1a57c642dc62Ying Wangglthread_rwlock_init_multithreaded (gl_rwlock_t *lock)
3905436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
4005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  int err;
4105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
4205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  err = pthread_rwlock_init (&lock->rwlock, NULL);
4305436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (err != 0)
4405436638acc7c010349a69c3395f1a57c642dc62Ying Wang    return err;
4505436638acc7c010349a69c3395f1a57c642dc62Ying Wang  lock->initialized = 1;
4605436638acc7c010349a69c3395f1a57c642dc62Ying Wang  return 0;
4705436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
4805436638acc7c010349a69c3395f1a57c642dc62Ying Wang
4905436638acc7c010349a69c3395f1a57c642dc62Ying Wangint
5005436638acc7c010349a69c3395f1a57c642dc62Ying Wangglthread_rwlock_rdlock_multithreaded (gl_rwlock_t *lock)
5105436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
5205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (!lock->initialized)
5305436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
5405436638acc7c010349a69c3395f1a57c642dc62Ying Wang      int err;
5505436638acc7c010349a69c3395f1a57c642dc62Ying Wang
5605436638acc7c010349a69c3395f1a57c642dc62Ying Wang      err = pthread_mutex_lock (&lock->guard);
5705436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (err != 0)
5805436638acc7c010349a69c3395f1a57c642dc62Ying Wang        return err;
5905436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (!lock->initialized)
6005436638acc7c010349a69c3395f1a57c642dc62Ying Wang        {
6105436638acc7c010349a69c3395f1a57c642dc62Ying Wang          err = glthread_rwlock_init_multithreaded (lock);
6205436638acc7c010349a69c3395f1a57c642dc62Ying Wang          if (err != 0)
6305436638acc7c010349a69c3395f1a57c642dc62Ying Wang            {
6405436638acc7c010349a69c3395f1a57c642dc62Ying Wang              pthread_mutex_unlock (&lock->guard);
6505436638acc7c010349a69c3395f1a57c642dc62Ying Wang              return err;
6605436638acc7c010349a69c3395f1a57c642dc62Ying Wang            }
6705436638acc7c010349a69c3395f1a57c642dc62Ying Wang        }
6805436638acc7c010349a69c3395f1a57c642dc62Ying Wang      err = pthread_mutex_unlock (&lock->guard);
6905436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (err != 0)
7005436638acc7c010349a69c3395f1a57c642dc62Ying Wang        return err;
7105436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
7205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  return pthread_rwlock_rdlock (&lock->rwlock);
7305436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
7405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
7505436638acc7c010349a69c3395f1a57c642dc62Ying Wangint
7605436638acc7c010349a69c3395f1a57c642dc62Ying Wangglthread_rwlock_wrlock_multithreaded (gl_rwlock_t *lock)
7705436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
7805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (!lock->initialized)
7905436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
8005436638acc7c010349a69c3395f1a57c642dc62Ying Wang      int err;
8105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
8205436638acc7c010349a69c3395f1a57c642dc62Ying Wang      err = pthread_mutex_lock (&lock->guard);
8305436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (err != 0)
8405436638acc7c010349a69c3395f1a57c642dc62Ying Wang        return err;
8505436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (!lock->initialized)
8605436638acc7c010349a69c3395f1a57c642dc62Ying Wang        {
8705436638acc7c010349a69c3395f1a57c642dc62Ying Wang          err = glthread_rwlock_init_multithreaded (lock);
8805436638acc7c010349a69c3395f1a57c642dc62Ying Wang          if (err != 0)
8905436638acc7c010349a69c3395f1a57c642dc62Ying Wang            {
9005436638acc7c010349a69c3395f1a57c642dc62Ying Wang              pthread_mutex_unlock (&lock->guard);
9105436638acc7c010349a69c3395f1a57c642dc62Ying Wang              return err;
9205436638acc7c010349a69c3395f1a57c642dc62Ying Wang            }
9305436638acc7c010349a69c3395f1a57c642dc62Ying Wang        }
9405436638acc7c010349a69c3395f1a57c642dc62Ying Wang      err = pthread_mutex_unlock (&lock->guard);
9505436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (err != 0)
9605436638acc7c010349a69c3395f1a57c642dc62Ying Wang        return err;
9705436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
9805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  return pthread_rwlock_wrlock (&lock->rwlock);
9905436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
10005436638acc7c010349a69c3395f1a57c642dc62Ying Wang
10105436638acc7c010349a69c3395f1a57c642dc62Ying Wangint
10205436638acc7c010349a69c3395f1a57c642dc62Ying Wangglthread_rwlock_unlock_multithreaded (gl_rwlock_t *lock)
10305436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
10405436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (!lock->initialized)
10505436638acc7c010349a69c3395f1a57c642dc62Ying Wang    return EINVAL;
10605436638acc7c010349a69c3395f1a57c642dc62Ying Wang  return pthread_rwlock_unlock (&lock->rwlock);
10705436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
10805436638acc7c010349a69c3395f1a57c642dc62Ying Wang
10905436638acc7c010349a69c3395f1a57c642dc62Ying Wangint
11005436638acc7c010349a69c3395f1a57c642dc62Ying Wangglthread_rwlock_destroy_multithreaded (gl_rwlock_t *lock)
11105436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
11205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  int err;
11305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
11405436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (!lock->initialized)
11505436638acc7c010349a69c3395f1a57c642dc62Ying Wang    return EINVAL;
11605436638acc7c010349a69c3395f1a57c642dc62Ying Wang  err = pthread_rwlock_destroy (&lock->rwlock);
11705436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (err != 0)
11805436638acc7c010349a69c3395f1a57c642dc62Ying Wang    return err;
11905436638acc7c010349a69c3395f1a57c642dc62Ying Wang  lock->initialized = 0;
12005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  return 0;
12105436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
12205436638acc7c010349a69c3395f1a57c642dc62Ying Wang
12305436638acc7c010349a69c3395f1a57c642dc62Ying Wang#  endif
12405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
12505436638acc7c010349a69c3395f1a57c642dc62Ying Wang# else
12605436638acc7c010349a69c3395f1a57c642dc62Ying Wang
12705436638acc7c010349a69c3395f1a57c642dc62Ying Wangint
12805436638acc7c010349a69c3395f1a57c642dc62Ying Wangglthread_rwlock_init_multithreaded (gl_rwlock_t *lock)
12905436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
13005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  int err;
13105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
13205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  err = pthread_mutex_init (&lock->lock, NULL);
13305436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (err != 0)
13405436638acc7c010349a69c3395f1a57c642dc62Ying Wang    return err;
13505436638acc7c010349a69c3395f1a57c642dc62Ying Wang  err = pthread_cond_init (&lock->waiting_readers, NULL);
13605436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (err != 0)
13705436638acc7c010349a69c3395f1a57c642dc62Ying Wang    return err;
13805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  err = pthread_cond_init (&lock->waiting_writers, NULL);
13905436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (err != 0)
14005436638acc7c010349a69c3395f1a57c642dc62Ying Wang    return err;
14105436638acc7c010349a69c3395f1a57c642dc62Ying Wang  lock->waiting_writers_count = 0;
14205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  lock->runcount = 0;
14305436638acc7c010349a69c3395f1a57c642dc62Ying Wang  return 0;
14405436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
14505436638acc7c010349a69c3395f1a57c642dc62Ying Wang
14605436638acc7c010349a69c3395f1a57c642dc62Ying Wangint
14705436638acc7c010349a69c3395f1a57c642dc62Ying Wangglthread_rwlock_rdlock_multithreaded (gl_rwlock_t *lock)
14805436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
14905436638acc7c010349a69c3395f1a57c642dc62Ying Wang  int err;
15005436638acc7c010349a69c3395f1a57c642dc62Ying Wang
15105436638acc7c010349a69c3395f1a57c642dc62Ying Wang  err = pthread_mutex_lock (&lock->lock);
15205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (err != 0)
15305436638acc7c010349a69c3395f1a57c642dc62Ying Wang    return err;
15405436638acc7c010349a69c3395f1a57c642dc62Ying Wang  /* Test whether only readers are currently running, and whether the runcount
15505436638acc7c010349a69c3395f1a57c642dc62Ying Wang     field will not overflow.  */
15605436638acc7c010349a69c3395f1a57c642dc62Ying Wang  /* POSIX says: "It is implementation-defined whether the calling thread
15705436638acc7c010349a69c3395f1a57c642dc62Ying Wang     acquires the lock when a writer does not hold the lock and there are
15805436638acc7c010349a69c3395f1a57c642dc62Ying Wang     writers blocked on the lock."  Let's say, no: give the writers a higher
15905436638acc7c010349a69c3395f1a57c642dc62Ying Wang     priority.  */
16005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  while (!(lock->runcount + 1 > 0 && lock->waiting_writers_count == 0))
16105436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
16205436638acc7c010349a69c3395f1a57c642dc62Ying Wang      /* This thread has to wait for a while.  Enqueue it among the
16305436638acc7c010349a69c3395f1a57c642dc62Ying Wang         waiting_readers.  */
16405436638acc7c010349a69c3395f1a57c642dc62Ying Wang      err = pthread_cond_wait (&lock->waiting_readers, &lock->lock);
16505436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (err != 0)
16605436638acc7c010349a69c3395f1a57c642dc62Ying Wang        {
16705436638acc7c010349a69c3395f1a57c642dc62Ying Wang          pthread_mutex_unlock (&lock->lock);
16805436638acc7c010349a69c3395f1a57c642dc62Ying Wang          return err;
16905436638acc7c010349a69c3395f1a57c642dc62Ying Wang        }
17005436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
17105436638acc7c010349a69c3395f1a57c642dc62Ying Wang  lock->runcount++;
17205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  return pthread_mutex_unlock (&lock->lock);
17305436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
17405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
17505436638acc7c010349a69c3395f1a57c642dc62Ying Wangint
17605436638acc7c010349a69c3395f1a57c642dc62Ying Wangglthread_rwlock_wrlock_multithreaded (gl_rwlock_t *lock)
17705436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
17805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  int err;
17905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
18005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  err = pthread_mutex_lock (&lock->lock);
18105436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (err != 0)
18205436638acc7c010349a69c3395f1a57c642dc62Ying Wang    return err;
18305436638acc7c010349a69c3395f1a57c642dc62Ying Wang  /* Test whether no readers or writers are currently running.  */
18405436638acc7c010349a69c3395f1a57c642dc62Ying Wang  while (!(lock->runcount == 0))
18505436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
18605436638acc7c010349a69c3395f1a57c642dc62Ying Wang      /* This thread has to wait for a while.  Enqueue it among the
18705436638acc7c010349a69c3395f1a57c642dc62Ying Wang         waiting_writers.  */
18805436638acc7c010349a69c3395f1a57c642dc62Ying Wang      lock->waiting_writers_count++;
18905436638acc7c010349a69c3395f1a57c642dc62Ying Wang      err = pthread_cond_wait (&lock->waiting_writers, &lock->lock);
19005436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (err != 0)
19105436638acc7c010349a69c3395f1a57c642dc62Ying Wang        {
19205436638acc7c010349a69c3395f1a57c642dc62Ying Wang          lock->waiting_writers_count--;
19305436638acc7c010349a69c3395f1a57c642dc62Ying Wang          pthread_mutex_unlock (&lock->lock);
19405436638acc7c010349a69c3395f1a57c642dc62Ying Wang          return err;
19505436638acc7c010349a69c3395f1a57c642dc62Ying Wang        }
19605436638acc7c010349a69c3395f1a57c642dc62Ying Wang      lock->waiting_writers_count--;
19705436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
19805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  lock->runcount--; /* runcount becomes -1 */
19905436638acc7c010349a69c3395f1a57c642dc62Ying Wang  return pthread_mutex_unlock (&lock->lock);
20005436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
20105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
20205436638acc7c010349a69c3395f1a57c642dc62Ying Wangint
20305436638acc7c010349a69c3395f1a57c642dc62Ying Wangglthread_rwlock_unlock_multithreaded (gl_rwlock_t *lock)
20405436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
20505436638acc7c010349a69c3395f1a57c642dc62Ying Wang  int err;
20605436638acc7c010349a69c3395f1a57c642dc62Ying Wang
20705436638acc7c010349a69c3395f1a57c642dc62Ying Wang  err = pthread_mutex_lock (&lock->lock);
20805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (err != 0)
20905436638acc7c010349a69c3395f1a57c642dc62Ying Wang    return err;
21005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (lock->runcount < 0)
21105436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
21205436638acc7c010349a69c3395f1a57c642dc62Ying Wang      /* Drop a writer lock.  */
21305436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (!(lock->runcount == -1))
21405436638acc7c010349a69c3395f1a57c642dc62Ying Wang        {
21505436638acc7c010349a69c3395f1a57c642dc62Ying Wang          pthread_mutex_unlock (&lock->lock);
21605436638acc7c010349a69c3395f1a57c642dc62Ying Wang          return EINVAL;
21705436638acc7c010349a69c3395f1a57c642dc62Ying Wang        }
21805436638acc7c010349a69c3395f1a57c642dc62Ying Wang      lock->runcount = 0;
21905436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
22005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  else
22105436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
22205436638acc7c010349a69c3395f1a57c642dc62Ying Wang      /* Drop a reader lock.  */
22305436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (!(lock->runcount > 0))
22405436638acc7c010349a69c3395f1a57c642dc62Ying Wang        {
22505436638acc7c010349a69c3395f1a57c642dc62Ying Wang          pthread_mutex_unlock (&lock->lock);
22605436638acc7c010349a69c3395f1a57c642dc62Ying Wang          return EINVAL;
22705436638acc7c010349a69c3395f1a57c642dc62Ying Wang        }
22805436638acc7c010349a69c3395f1a57c642dc62Ying Wang      lock->runcount--;
22905436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
23005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (lock->runcount == 0)
23105436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
23205436638acc7c010349a69c3395f1a57c642dc62Ying Wang      /* POSIX recommends that "write locks shall take precedence over read
23305436638acc7c010349a69c3395f1a57c642dc62Ying Wang         locks", to avoid "writer starvation".  */
23405436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (lock->waiting_writers_count > 0)
23505436638acc7c010349a69c3395f1a57c642dc62Ying Wang        {
23605436638acc7c010349a69c3395f1a57c642dc62Ying Wang          /* Wake up one of the waiting writers.  */
23705436638acc7c010349a69c3395f1a57c642dc62Ying Wang          err = pthread_cond_signal (&lock->waiting_writers);
23805436638acc7c010349a69c3395f1a57c642dc62Ying Wang          if (err != 0)
23905436638acc7c010349a69c3395f1a57c642dc62Ying Wang            {
24005436638acc7c010349a69c3395f1a57c642dc62Ying Wang              pthread_mutex_unlock (&lock->lock);
24105436638acc7c010349a69c3395f1a57c642dc62Ying Wang              return err;
24205436638acc7c010349a69c3395f1a57c642dc62Ying Wang            }
24305436638acc7c010349a69c3395f1a57c642dc62Ying Wang        }
24405436638acc7c010349a69c3395f1a57c642dc62Ying Wang      else
24505436638acc7c010349a69c3395f1a57c642dc62Ying Wang        {
24605436638acc7c010349a69c3395f1a57c642dc62Ying Wang          /* Wake up all waiting readers.  */
24705436638acc7c010349a69c3395f1a57c642dc62Ying Wang          err = pthread_cond_broadcast (&lock->waiting_readers);
24805436638acc7c010349a69c3395f1a57c642dc62Ying Wang          if (err != 0)
24905436638acc7c010349a69c3395f1a57c642dc62Ying Wang            {
25005436638acc7c010349a69c3395f1a57c642dc62Ying Wang              pthread_mutex_unlock (&lock->lock);
25105436638acc7c010349a69c3395f1a57c642dc62Ying Wang              return err;
25205436638acc7c010349a69c3395f1a57c642dc62Ying Wang            }
25305436638acc7c010349a69c3395f1a57c642dc62Ying Wang        }
25405436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
25505436638acc7c010349a69c3395f1a57c642dc62Ying Wang  return pthread_mutex_unlock (&lock->lock);
25605436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
25705436638acc7c010349a69c3395f1a57c642dc62Ying Wang
25805436638acc7c010349a69c3395f1a57c642dc62Ying Wangint
25905436638acc7c010349a69c3395f1a57c642dc62Ying Wangglthread_rwlock_destroy_multithreaded (gl_rwlock_t *lock)
26005436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
26105436638acc7c010349a69c3395f1a57c642dc62Ying Wang  int err;
26205436638acc7c010349a69c3395f1a57c642dc62Ying Wang
26305436638acc7c010349a69c3395f1a57c642dc62Ying Wang  err = pthread_mutex_destroy (&lock->lock);
26405436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (err != 0)
26505436638acc7c010349a69c3395f1a57c642dc62Ying Wang    return err;
26605436638acc7c010349a69c3395f1a57c642dc62Ying Wang  err = pthread_cond_destroy (&lock->waiting_readers);
26705436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (err != 0)
26805436638acc7c010349a69c3395f1a57c642dc62Ying Wang    return err;
26905436638acc7c010349a69c3395f1a57c642dc62Ying Wang  err = pthread_cond_destroy (&lock->waiting_writers);
27005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (err != 0)
27105436638acc7c010349a69c3395f1a57c642dc62Ying Wang    return err;
27205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  return 0;
27305436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
27405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
27505436638acc7c010349a69c3395f1a57c642dc62Ying Wang# endif
27605436638acc7c010349a69c3395f1a57c642dc62Ying Wang
27705436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* --------------------- gl_recursive_lock_t datatype --------------------- */
27805436638acc7c010349a69c3395f1a57c642dc62Ying Wang
27905436638acc7c010349a69c3395f1a57c642dc62Ying Wang# if HAVE_PTHREAD_MUTEX_RECURSIVE
28005436638acc7c010349a69c3395f1a57c642dc62Ying Wang
28105436638acc7c010349a69c3395f1a57c642dc62Ying Wang#  if defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER || defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
28205436638acc7c010349a69c3395f1a57c642dc62Ying Wang
28305436638acc7c010349a69c3395f1a57c642dc62Ying Wangint
28405436638acc7c010349a69c3395f1a57c642dc62Ying Wangglthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock)
28505436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
28605436638acc7c010349a69c3395f1a57c642dc62Ying Wang  pthread_mutexattr_t attributes;
28705436638acc7c010349a69c3395f1a57c642dc62Ying Wang  int err;
28805436638acc7c010349a69c3395f1a57c642dc62Ying Wang
28905436638acc7c010349a69c3395f1a57c642dc62Ying Wang  err = pthread_mutexattr_init (&attributes);
29005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (err != 0)
29105436638acc7c010349a69c3395f1a57c642dc62Ying Wang    return err;
29205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  err = pthread_mutexattr_settype (&attributes, PTHREAD_MUTEX_RECURSIVE);
29305436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (err != 0)
29405436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
29505436638acc7c010349a69c3395f1a57c642dc62Ying Wang      pthread_mutexattr_destroy (&attributes);
29605436638acc7c010349a69c3395f1a57c642dc62Ying Wang      return err;
29705436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
29805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  err = pthread_mutex_init (lock, &attributes);
29905436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (err != 0)
30005436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
30105436638acc7c010349a69c3395f1a57c642dc62Ying Wang      pthread_mutexattr_destroy (&attributes);
30205436638acc7c010349a69c3395f1a57c642dc62Ying Wang      return err;
30305436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
30405436638acc7c010349a69c3395f1a57c642dc62Ying Wang  err = pthread_mutexattr_destroy (&attributes);
30505436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (err != 0)
30605436638acc7c010349a69c3395f1a57c642dc62Ying Wang    return err;
30705436638acc7c010349a69c3395f1a57c642dc62Ying Wang  return 0;
30805436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
30905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
31005436638acc7c010349a69c3395f1a57c642dc62Ying Wang#  else
31105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
31205436638acc7c010349a69c3395f1a57c642dc62Ying Wangint
31305436638acc7c010349a69c3395f1a57c642dc62Ying Wangglthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock)
31405436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
31505436638acc7c010349a69c3395f1a57c642dc62Ying Wang  pthread_mutexattr_t attributes;
31605436638acc7c010349a69c3395f1a57c642dc62Ying Wang  int err;
31705436638acc7c010349a69c3395f1a57c642dc62Ying Wang
31805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  err = pthread_mutexattr_init (&attributes);
31905436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (err != 0)
32005436638acc7c010349a69c3395f1a57c642dc62Ying Wang    return err;
32105436638acc7c010349a69c3395f1a57c642dc62Ying Wang  err = pthread_mutexattr_settype (&attributes, PTHREAD_MUTEX_RECURSIVE);
32205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (err != 0)
32305436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
32405436638acc7c010349a69c3395f1a57c642dc62Ying Wang      pthread_mutexattr_destroy (&attributes);
32505436638acc7c010349a69c3395f1a57c642dc62Ying Wang      return err;
32605436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
32705436638acc7c010349a69c3395f1a57c642dc62Ying Wang  err = pthread_mutex_init (&lock->recmutex, &attributes);
32805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (err != 0)
32905436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
33005436638acc7c010349a69c3395f1a57c642dc62Ying Wang      pthread_mutexattr_destroy (&attributes);
33105436638acc7c010349a69c3395f1a57c642dc62Ying Wang      return err;
33205436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
33305436638acc7c010349a69c3395f1a57c642dc62Ying Wang  err = pthread_mutexattr_destroy (&attributes);
33405436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (err != 0)
33505436638acc7c010349a69c3395f1a57c642dc62Ying Wang    return err;
33605436638acc7c010349a69c3395f1a57c642dc62Ying Wang  lock->initialized = 1;
33705436638acc7c010349a69c3395f1a57c642dc62Ying Wang  return 0;
33805436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
33905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
34005436638acc7c010349a69c3395f1a57c642dc62Ying Wangint
34105436638acc7c010349a69c3395f1a57c642dc62Ying Wangglthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock)
34205436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
34305436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (!lock->initialized)
34405436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
34505436638acc7c010349a69c3395f1a57c642dc62Ying Wang      int err;
34605436638acc7c010349a69c3395f1a57c642dc62Ying Wang
34705436638acc7c010349a69c3395f1a57c642dc62Ying Wang      err = pthread_mutex_lock (&lock->guard);
34805436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (err != 0)
34905436638acc7c010349a69c3395f1a57c642dc62Ying Wang        return err;
35005436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (!lock->initialized)
35105436638acc7c010349a69c3395f1a57c642dc62Ying Wang        {
35205436638acc7c010349a69c3395f1a57c642dc62Ying Wang          err = glthread_recursive_lock_init_multithreaded (lock);
35305436638acc7c010349a69c3395f1a57c642dc62Ying Wang          if (err != 0)
35405436638acc7c010349a69c3395f1a57c642dc62Ying Wang            {
35505436638acc7c010349a69c3395f1a57c642dc62Ying Wang              pthread_mutex_unlock (&lock->guard);
35605436638acc7c010349a69c3395f1a57c642dc62Ying Wang              return err;
35705436638acc7c010349a69c3395f1a57c642dc62Ying Wang            }
35805436638acc7c010349a69c3395f1a57c642dc62Ying Wang        }
35905436638acc7c010349a69c3395f1a57c642dc62Ying Wang      err = pthread_mutex_unlock (&lock->guard);
36005436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (err != 0)
36105436638acc7c010349a69c3395f1a57c642dc62Ying Wang        return err;
36205436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
36305436638acc7c010349a69c3395f1a57c642dc62Ying Wang  return pthread_mutex_lock (&lock->recmutex);
36405436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
36505436638acc7c010349a69c3395f1a57c642dc62Ying Wang
36605436638acc7c010349a69c3395f1a57c642dc62Ying Wangint
36705436638acc7c010349a69c3395f1a57c642dc62Ying Wangglthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock)
36805436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
36905436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (!lock->initialized)
37005436638acc7c010349a69c3395f1a57c642dc62Ying Wang    return EINVAL;
37105436638acc7c010349a69c3395f1a57c642dc62Ying Wang  return pthread_mutex_unlock (&lock->recmutex);
37205436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
37305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
37405436638acc7c010349a69c3395f1a57c642dc62Ying Wangint
37505436638acc7c010349a69c3395f1a57c642dc62Ying Wangglthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock)
37605436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
37705436638acc7c010349a69c3395f1a57c642dc62Ying Wang  int err;
37805436638acc7c010349a69c3395f1a57c642dc62Ying Wang
37905436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (!lock->initialized)
38005436638acc7c010349a69c3395f1a57c642dc62Ying Wang    return EINVAL;
38105436638acc7c010349a69c3395f1a57c642dc62Ying Wang  err = pthread_mutex_destroy (&lock->recmutex);
38205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (err != 0)
38305436638acc7c010349a69c3395f1a57c642dc62Ying Wang    return err;
38405436638acc7c010349a69c3395f1a57c642dc62Ying Wang  lock->initialized = 0;
38505436638acc7c010349a69c3395f1a57c642dc62Ying Wang  return 0;
38605436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
38705436638acc7c010349a69c3395f1a57c642dc62Ying Wang
38805436638acc7c010349a69c3395f1a57c642dc62Ying Wang#  endif
38905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
39005436638acc7c010349a69c3395f1a57c642dc62Ying Wang# else
39105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
39205436638acc7c010349a69c3395f1a57c642dc62Ying Wangint
39305436638acc7c010349a69c3395f1a57c642dc62Ying Wangglthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock)
39405436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
39505436638acc7c010349a69c3395f1a57c642dc62Ying Wang  int err;
39605436638acc7c010349a69c3395f1a57c642dc62Ying Wang
39705436638acc7c010349a69c3395f1a57c642dc62Ying Wang  err = pthread_mutex_init (&lock->mutex, NULL);
39805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (err != 0)
39905436638acc7c010349a69c3395f1a57c642dc62Ying Wang    return err;
40005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  lock->owner = (pthread_t) 0;
40105436638acc7c010349a69c3395f1a57c642dc62Ying Wang  lock->depth = 0;
40205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  return 0;
40305436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
40405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
40505436638acc7c010349a69c3395f1a57c642dc62Ying Wangint
40605436638acc7c010349a69c3395f1a57c642dc62Ying Wangglthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock)
40705436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
40805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  pthread_t self = pthread_self ();
40905436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (lock->owner != self)
41005436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
41105436638acc7c010349a69c3395f1a57c642dc62Ying Wang      int err;
41205436638acc7c010349a69c3395f1a57c642dc62Ying Wang
41305436638acc7c010349a69c3395f1a57c642dc62Ying Wang      err = pthread_mutex_lock (&lock->mutex);
41405436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (err != 0)
41505436638acc7c010349a69c3395f1a57c642dc62Ying Wang        return err;
41605436638acc7c010349a69c3395f1a57c642dc62Ying Wang      lock->owner = self;
41705436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
41805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (++(lock->depth) == 0) /* wraparound? */
41905436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
42005436638acc7c010349a69c3395f1a57c642dc62Ying Wang      lock->depth--;
42105436638acc7c010349a69c3395f1a57c642dc62Ying Wang      return EAGAIN;
42205436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
42305436638acc7c010349a69c3395f1a57c642dc62Ying Wang  return 0;
42405436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
42505436638acc7c010349a69c3395f1a57c642dc62Ying Wang
42605436638acc7c010349a69c3395f1a57c642dc62Ying Wangint
42705436638acc7c010349a69c3395f1a57c642dc62Ying Wangglthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock)
42805436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
42905436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (lock->owner != pthread_self ())
43005436638acc7c010349a69c3395f1a57c642dc62Ying Wang    return EPERM;
43105436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (lock->depth == 0)
43205436638acc7c010349a69c3395f1a57c642dc62Ying Wang    return EINVAL;
43305436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (--(lock->depth) == 0)
43405436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
43505436638acc7c010349a69c3395f1a57c642dc62Ying Wang      lock->owner = (pthread_t) 0;
43605436638acc7c010349a69c3395f1a57c642dc62Ying Wang      return pthread_mutex_unlock (&lock->mutex);
43705436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
43805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  else
43905436638acc7c010349a69c3395f1a57c642dc62Ying Wang    return 0;
44005436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
44105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
44205436638acc7c010349a69c3395f1a57c642dc62Ying Wangint
44305436638acc7c010349a69c3395f1a57c642dc62Ying Wangglthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock)
44405436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
44505436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (lock->owner != (pthread_t) 0)
44605436638acc7c010349a69c3395f1a57c642dc62Ying Wang    return EBUSY;
44705436638acc7c010349a69c3395f1a57c642dc62Ying Wang  return pthread_mutex_destroy (&lock->mutex);
44805436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
44905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
45005436638acc7c010349a69c3395f1a57c642dc62Ying Wang# endif
45105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
45205436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* -------------------------- gl_once_t datatype -------------------------- */
45305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
45405436638acc7c010349a69c3395f1a57c642dc62Ying Wangstatic const pthread_once_t fresh_once = PTHREAD_ONCE_INIT;
45505436638acc7c010349a69c3395f1a57c642dc62Ying Wang
45605436638acc7c010349a69c3395f1a57c642dc62Ying Wangint
45705436638acc7c010349a69c3395f1a57c642dc62Ying Wangglthread_once_singlethreaded (pthread_once_t *once_control)
45805436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
45905436638acc7c010349a69c3395f1a57c642dc62Ying Wang  /* We don't know whether pthread_once_t is an integer type, a floating-point
46005436638acc7c010349a69c3395f1a57c642dc62Ying Wang     type, a pointer type, or a structure type.  */
46105436638acc7c010349a69c3395f1a57c642dc62Ying Wang  char *firstbyte = (char *)once_control;
46205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (*firstbyte == *(const char *)&fresh_once)
46305436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
46405436638acc7c010349a69c3395f1a57c642dc62Ying Wang      /* First time use of once_control.  Invert the first byte.  */
46505436638acc7c010349a69c3395f1a57c642dc62Ying Wang      *firstbyte = ~ *(const char *)&fresh_once;
46605436638acc7c010349a69c3395f1a57c642dc62Ying Wang      return 1;
46705436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
46805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  else
46905436638acc7c010349a69c3395f1a57c642dc62Ying Wang    return 0;
47005436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
47105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
47205436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
47305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
47405436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* ========================================================================= */
47505436638acc7c010349a69c3395f1a57c642dc62Ying Wang
47605436638acc7c010349a69c3395f1a57c642dc62Ying Wang#if USE_PTH_THREADS
47705436638acc7c010349a69c3395f1a57c642dc62Ying Wang
47805436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Use the GNU Pth threads library.  */
47905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
48005436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* -------------------------- gl_lock_t datatype -------------------------- */
48105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
48205436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* ------------------------- gl_rwlock_t datatype ------------------------- */
48305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
48405436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* --------------------- gl_recursive_lock_t datatype --------------------- */
48505436638acc7c010349a69c3395f1a57c642dc62Ying Wang
48605436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* -------------------------- gl_once_t datatype -------------------------- */
48705436638acc7c010349a69c3395f1a57c642dc62Ying Wang
48805436638acc7c010349a69c3395f1a57c642dc62Ying Wangstatic void
48905436638acc7c010349a69c3395f1a57c642dc62Ying Wangglthread_once_call (void *arg)
49005436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
49105436638acc7c010349a69c3395f1a57c642dc62Ying Wang  void (**gl_once_temp_addr) (void) = (void (**) (void)) arg;
49205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  void (*initfunction) (void) = *gl_once_temp_addr;
49305436638acc7c010349a69c3395f1a57c642dc62Ying Wang  initfunction ();
49405436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
49505436638acc7c010349a69c3395f1a57c642dc62Ying Wang
49605436638acc7c010349a69c3395f1a57c642dc62Ying Wangint
49705436638acc7c010349a69c3395f1a57c642dc62Ying Wangglthread_once_multithreaded (pth_once_t *once_control, void (*initfunction) (void))
49805436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
49905436638acc7c010349a69c3395f1a57c642dc62Ying Wang  void (*temp) (void) = initfunction;
50005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  return (!pth_once (once_control, glthread_once_call, &temp) ? errno : 0);
50105436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
50205436638acc7c010349a69c3395f1a57c642dc62Ying Wang
50305436638acc7c010349a69c3395f1a57c642dc62Ying Wangint
50405436638acc7c010349a69c3395f1a57c642dc62Ying Wangglthread_once_singlethreaded (pth_once_t *once_control)
50505436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
50605436638acc7c010349a69c3395f1a57c642dc62Ying Wang  /* We know that pth_once_t is an integer type.  */
50705436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (*once_control == PTH_ONCE_INIT)
50805436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
50905436638acc7c010349a69c3395f1a57c642dc62Ying Wang      /* First time use of once_control.  Invert the marker.  */
51005436638acc7c010349a69c3395f1a57c642dc62Ying Wang      *once_control = ~ PTH_ONCE_INIT;
51105436638acc7c010349a69c3395f1a57c642dc62Ying Wang      return 1;
51205436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
51305436638acc7c010349a69c3395f1a57c642dc62Ying Wang  else
51405436638acc7c010349a69c3395f1a57c642dc62Ying Wang    return 0;
51505436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
51605436638acc7c010349a69c3395f1a57c642dc62Ying Wang
51705436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
51805436638acc7c010349a69c3395f1a57c642dc62Ying Wang
51905436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* ========================================================================= */
52005436638acc7c010349a69c3395f1a57c642dc62Ying Wang
52105436638acc7c010349a69c3395f1a57c642dc62Ying Wang#if USE_SOLARIS_THREADS
52205436638acc7c010349a69c3395f1a57c642dc62Ying Wang
52305436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Use the old Solaris threads library.  */
52405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
52505436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* -------------------------- gl_lock_t datatype -------------------------- */
52605436638acc7c010349a69c3395f1a57c642dc62Ying Wang
52705436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* ------------------------- gl_rwlock_t datatype ------------------------- */
52805436638acc7c010349a69c3395f1a57c642dc62Ying Wang
52905436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* --------------------- gl_recursive_lock_t datatype --------------------- */
53005436638acc7c010349a69c3395f1a57c642dc62Ying Wang
53105436638acc7c010349a69c3395f1a57c642dc62Ying Wangint
53205436638acc7c010349a69c3395f1a57c642dc62Ying Wangglthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock)
53305436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
53405436638acc7c010349a69c3395f1a57c642dc62Ying Wang  int err;
53505436638acc7c010349a69c3395f1a57c642dc62Ying Wang
53605436638acc7c010349a69c3395f1a57c642dc62Ying Wang  err = mutex_init (&lock->mutex, USYNC_THREAD, NULL);
53705436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (err != 0)
53805436638acc7c010349a69c3395f1a57c642dc62Ying Wang    return err;
53905436638acc7c010349a69c3395f1a57c642dc62Ying Wang  lock->owner = (thread_t) 0;
54005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  lock->depth = 0;
54105436638acc7c010349a69c3395f1a57c642dc62Ying Wang  return 0;
54205436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
54305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
54405436638acc7c010349a69c3395f1a57c642dc62Ying Wangint
54505436638acc7c010349a69c3395f1a57c642dc62Ying Wangglthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock)
54605436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
54705436638acc7c010349a69c3395f1a57c642dc62Ying Wang  thread_t self = thr_self ();
54805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (lock->owner != self)
54905436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
55005436638acc7c010349a69c3395f1a57c642dc62Ying Wang      int err;
55105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
55205436638acc7c010349a69c3395f1a57c642dc62Ying Wang      err = mutex_lock (&lock->mutex);
55305436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (err != 0)
55405436638acc7c010349a69c3395f1a57c642dc62Ying Wang        return err;
55505436638acc7c010349a69c3395f1a57c642dc62Ying Wang      lock->owner = self;
55605436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
55705436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (++(lock->depth) == 0) /* wraparound? */
55805436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
55905436638acc7c010349a69c3395f1a57c642dc62Ying Wang      lock->depth--;
56005436638acc7c010349a69c3395f1a57c642dc62Ying Wang      return EAGAIN;
56105436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
56205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  return 0;
56305436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
56405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
56505436638acc7c010349a69c3395f1a57c642dc62Ying Wangint
56605436638acc7c010349a69c3395f1a57c642dc62Ying Wangglthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock)
56705436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
56805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (lock->owner != thr_self ())
56905436638acc7c010349a69c3395f1a57c642dc62Ying Wang    return EPERM;
57005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (lock->depth == 0)
57105436638acc7c010349a69c3395f1a57c642dc62Ying Wang    return EINVAL;
57205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (--(lock->depth) == 0)
57305436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
57405436638acc7c010349a69c3395f1a57c642dc62Ying Wang      lock->owner = (thread_t) 0;
57505436638acc7c010349a69c3395f1a57c642dc62Ying Wang      return mutex_unlock (&lock->mutex);
57605436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
57705436638acc7c010349a69c3395f1a57c642dc62Ying Wang  else
57805436638acc7c010349a69c3395f1a57c642dc62Ying Wang    return 0;
57905436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
58005436638acc7c010349a69c3395f1a57c642dc62Ying Wang
58105436638acc7c010349a69c3395f1a57c642dc62Ying Wangint
58205436638acc7c010349a69c3395f1a57c642dc62Ying Wangglthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock)
58305436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
58405436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (lock->owner != (thread_t) 0)
58505436638acc7c010349a69c3395f1a57c642dc62Ying Wang    return EBUSY;
58605436638acc7c010349a69c3395f1a57c642dc62Ying Wang  return mutex_destroy (&lock->mutex);
58705436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
58805436638acc7c010349a69c3395f1a57c642dc62Ying Wang
58905436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* -------------------------- gl_once_t datatype -------------------------- */
59005436638acc7c010349a69c3395f1a57c642dc62Ying Wang
59105436638acc7c010349a69c3395f1a57c642dc62Ying Wangint
59205436638acc7c010349a69c3395f1a57c642dc62Ying Wangglthread_once_multithreaded (gl_once_t *once_control, void (*initfunction) (void))
59305436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
59405436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (!once_control->inited)
59505436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
59605436638acc7c010349a69c3395f1a57c642dc62Ying Wang      int err;
59705436638acc7c010349a69c3395f1a57c642dc62Ying Wang
59805436638acc7c010349a69c3395f1a57c642dc62Ying Wang      /* Use the mutex to guarantee that if another thread is already calling
59905436638acc7c010349a69c3395f1a57c642dc62Ying Wang         the initfunction, this thread waits until it's finished.  */
60005436638acc7c010349a69c3395f1a57c642dc62Ying Wang      err = mutex_lock (&once_control->mutex);
60105436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (err != 0)
60205436638acc7c010349a69c3395f1a57c642dc62Ying Wang        return err;
60305436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (!once_control->inited)
60405436638acc7c010349a69c3395f1a57c642dc62Ying Wang        {
60505436638acc7c010349a69c3395f1a57c642dc62Ying Wang          once_control->inited = 1;
60605436638acc7c010349a69c3395f1a57c642dc62Ying Wang          initfunction ();
60705436638acc7c010349a69c3395f1a57c642dc62Ying Wang        }
60805436638acc7c010349a69c3395f1a57c642dc62Ying Wang      return mutex_unlock (&once_control->mutex);
60905436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
61005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  else
61105436638acc7c010349a69c3395f1a57c642dc62Ying Wang    return 0;
61205436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
61305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
61405436638acc7c010349a69c3395f1a57c642dc62Ying Wangint
61505436638acc7c010349a69c3395f1a57c642dc62Ying Wangglthread_once_singlethreaded (gl_once_t *once_control)
61605436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
61705436638acc7c010349a69c3395f1a57c642dc62Ying Wang  /* We know that gl_once_t contains an integer type.  */
61805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (!once_control->inited)
61905436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
62005436638acc7c010349a69c3395f1a57c642dc62Ying Wang      /* First time use of once_control.  Invert the marker.  */
62105436638acc7c010349a69c3395f1a57c642dc62Ying Wang      once_control->inited = ~ 0;
62205436638acc7c010349a69c3395f1a57c642dc62Ying Wang      return 1;
62305436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
62405436638acc7c010349a69c3395f1a57c642dc62Ying Wang  else
62505436638acc7c010349a69c3395f1a57c642dc62Ying Wang    return 0;
62605436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
62705436638acc7c010349a69c3395f1a57c642dc62Ying Wang
62805436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
62905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
63005436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* ========================================================================= */
63105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
63205436638acc7c010349a69c3395f1a57c642dc62Ying Wang#if USE_WINDOWS_THREADS
63305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
63405436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* -------------------------- gl_lock_t datatype -------------------------- */
63505436638acc7c010349a69c3395f1a57c642dc62Ying Wang
63605436638acc7c010349a69c3395f1a57c642dc62Ying Wangvoid
63705436638acc7c010349a69c3395f1a57c642dc62Ying Wangglthread_lock_init_func (gl_lock_t *lock)
63805436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
63905436638acc7c010349a69c3395f1a57c642dc62Ying Wang  InitializeCriticalSection (&lock->lock);
64005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  lock->guard.done = 1;
64105436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
64205436638acc7c010349a69c3395f1a57c642dc62Ying Wang
64305436638acc7c010349a69c3395f1a57c642dc62Ying Wangint
64405436638acc7c010349a69c3395f1a57c642dc62Ying Wangglthread_lock_lock_func (gl_lock_t *lock)
64505436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
64605436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (!lock->guard.done)
64705436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
64805436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (InterlockedIncrement (&lock->guard.started) == 0)
64905436638acc7c010349a69c3395f1a57c642dc62Ying Wang        /* This thread is the first one to need this lock.  Initialize it.  */
65005436638acc7c010349a69c3395f1a57c642dc62Ying Wang        glthread_lock_init (lock);
65105436638acc7c010349a69c3395f1a57c642dc62Ying Wang      else
65205436638acc7c010349a69c3395f1a57c642dc62Ying Wang        /* Yield the CPU while waiting for another thread to finish
65305436638acc7c010349a69c3395f1a57c642dc62Ying Wang           initializing this lock.  */
65405436638acc7c010349a69c3395f1a57c642dc62Ying Wang        while (!lock->guard.done)
65505436638acc7c010349a69c3395f1a57c642dc62Ying Wang          Sleep (0);
65605436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
65705436638acc7c010349a69c3395f1a57c642dc62Ying Wang  EnterCriticalSection (&lock->lock);
65805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  return 0;
65905436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
66005436638acc7c010349a69c3395f1a57c642dc62Ying Wang
66105436638acc7c010349a69c3395f1a57c642dc62Ying Wangint
66205436638acc7c010349a69c3395f1a57c642dc62Ying Wangglthread_lock_unlock_func (gl_lock_t *lock)
66305436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
66405436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (!lock->guard.done)
66505436638acc7c010349a69c3395f1a57c642dc62Ying Wang    return EINVAL;
66605436638acc7c010349a69c3395f1a57c642dc62Ying Wang  LeaveCriticalSection (&lock->lock);
66705436638acc7c010349a69c3395f1a57c642dc62Ying Wang  return 0;
66805436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
66905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
67005436638acc7c010349a69c3395f1a57c642dc62Ying Wangint
67105436638acc7c010349a69c3395f1a57c642dc62Ying Wangglthread_lock_destroy_func (gl_lock_t *lock)
67205436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
67305436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (!lock->guard.done)
67405436638acc7c010349a69c3395f1a57c642dc62Ying Wang    return EINVAL;
67505436638acc7c010349a69c3395f1a57c642dc62Ying Wang  DeleteCriticalSection (&lock->lock);
67605436638acc7c010349a69c3395f1a57c642dc62Ying Wang  lock->guard.done = 0;
67705436638acc7c010349a69c3395f1a57c642dc62Ying Wang  return 0;
67805436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
67905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
68005436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* ------------------------- gl_rwlock_t datatype ------------------------- */
68105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
68205436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* In this file, the waitqueues are implemented as circular arrays.  */
68305436638acc7c010349a69c3395f1a57c642dc62Ying Wang#define gl_waitqueue_t gl_carray_waitqueue_t
68405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
68505436638acc7c010349a69c3395f1a57c642dc62Ying Wangstatic void
68605436638acc7c010349a69c3395f1a57c642dc62Ying Wanggl_waitqueue_init (gl_waitqueue_t *wq)
68705436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
68805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  wq->array = NULL;
68905436638acc7c010349a69c3395f1a57c642dc62Ying Wang  wq->count = 0;
69005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  wq->alloc = 0;
69105436638acc7c010349a69c3395f1a57c642dc62Ying Wang  wq->offset = 0;
69205436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
69305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
69405436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Enqueues the current thread, represented by an event, in a wait queue.
69505436638acc7c010349a69c3395f1a57c642dc62Ying Wang   Returns INVALID_HANDLE_VALUE if an allocation failure occurs.  */
69605436638acc7c010349a69c3395f1a57c642dc62Ying Wangstatic HANDLE
69705436638acc7c010349a69c3395f1a57c642dc62Ying Wanggl_waitqueue_add (gl_waitqueue_t *wq)
69805436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
69905436638acc7c010349a69c3395f1a57c642dc62Ying Wang  HANDLE event;
70005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  unsigned int index;
70105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
70205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (wq->count == wq->alloc)
70305436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
70405436638acc7c010349a69c3395f1a57c642dc62Ying Wang      unsigned int new_alloc = 2 * wq->alloc + 1;
70505436638acc7c010349a69c3395f1a57c642dc62Ying Wang      HANDLE *new_array =
70605436638acc7c010349a69c3395f1a57c642dc62Ying Wang        (HANDLE *) realloc (wq->array, new_alloc * sizeof (HANDLE));
70705436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (new_array == NULL)
70805436638acc7c010349a69c3395f1a57c642dc62Ying Wang        /* No more memory.  */
70905436638acc7c010349a69c3395f1a57c642dc62Ying Wang        return INVALID_HANDLE_VALUE;
71005436638acc7c010349a69c3395f1a57c642dc62Ying Wang      /* Now is a good opportunity to rotate the array so that its contents
71105436638acc7c010349a69c3395f1a57c642dc62Ying Wang         starts at offset 0.  */
71205436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (wq->offset > 0)
71305436638acc7c010349a69c3395f1a57c642dc62Ying Wang        {
71405436638acc7c010349a69c3395f1a57c642dc62Ying Wang          unsigned int old_count = wq->count;
71505436638acc7c010349a69c3395f1a57c642dc62Ying Wang          unsigned int old_alloc = wq->alloc;
71605436638acc7c010349a69c3395f1a57c642dc62Ying Wang          unsigned int old_offset = wq->offset;
71705436638acc7c010349a69c3395f1a57c642dc62Ying Wang          unsigned int i;
71805436638acc7c010349a69c3395f1a57c642dc62Ying Wang          if (old_offset + old_count > old_alloc)
71905436638acc7c010349a69c3395f1a57c642dc62Ying Wang            {
72005436638acc7c010349a69c3395f1a57c642dc62Ying Wang              unsigned int limit = old_offset + old_count - old_alloc;
72105436638acc7c010349a69c3395f1a57c642dc62Ying Wang              for (i = 0; i < limit; i++)
72205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                new_array[old_alloc + i] = new_array[i];
72305436638acc7c010349a69c3395f1a57c642dc62Ying Wang            }
72405436638acc7c010349a69c3395f1a57c642dc62Ying Wang          for (i = 0; i < old_count; i++)
72505436638acc7c010349a69c3395f1a57c642dc62Ying Wang            new_array[i] = new_array[old_offset + i];
72605436638acc7c010349a69c3395f1a57c642dc62Ying Wang          wq->offset = 0;
72705436638acc7c010349a69c3395f1a57c642dc62Ying Wang        }
72805436638acc7c010349a69c3395f1a57c642dc62Ying Wang      wq->array = new_array;
72905436638acc7c010349a69c3395f1a57c642dc62Ying Wang      wq->alloc = new_alloc;
73005436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
73105436638acc7c010349a69c3395f1a57c642dc62Ying Wang  /* Whether the created event is a manual-reset one or an auto-reset one,
73205436638acc7c010349a69c3395f1a57c642dc62Ying Wang     does not matter, since we will wait on it only once.  */
73305436638acc7c010349a69c3395f1a57c642dc62Ying Wang  event = CreateEvent (NULL, TRUE, FALSE, NULL);
73405436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (event == INVALID_HANDLE_VALUE)
73505436638acc7c010349a69c3395f1a57c642dc62Ying Wang    /* No way to allocate an event.  */
73605436638acc7c010349a69c3395f1a57c642dc62Ying Wang    return INVALID_HANDLE_VALUE;
73705436638acc7c010349a69c3395f1a57c642dc62Ying Wang  index = wq->offset + wq->count;
73805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (index >= wq->alloc)
73905436638acc7c010349a69c3395f1a57c642dc62Ying Wang    index -= wq->alloc;
74005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  wq->array[index] = event;
74105436638acc7c010349a69c3395f1a57c642dc62Ying Wang  wq->count++;
74205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  return event;
74305436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
74405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
74505436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Notifies the first thread from a wait queue and dequeues it.  */
74605436638acc7c010349a69c3395f1a57c642dc62Ying Wangstatic void
74705436638acc7c010349a69c3395f1a57c642dc62Ying Wanggl_waitqueue_notify_first (gl_waitqueue_t *wq)
74805436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
74905436638acc7c010349a69c3395f1a57c642dc62Ying Wang  SetEvent (wq->array[wq->offset + 0]);
75005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  wq->offset++;
75105436638acc7c010349a69c3395f1a57c642dc62Ying Wang  wq->count--;
75205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (wq->count == 0 || wq->offset == wq->alloc)
75305436638acc7c010349a69c3395f1a57c642dc62Ying Wang    wq->offset = 0;
75405436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
75505436638acc7c010349a69c3395f1a57c642dc62Ying Wang
75605436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Notifies all threads from a wait queue and dequeues them all.  */
75705436638acc7c010349a69c3395f1a57c642dc62Ying Wangstatic void
75805436638acc7c010349a69c3395f1a57c642dc62Ying Wanggl_waitqueue_notify_all (gl_waitqueue_t *wq)
75905436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
76005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  unsigned int i;
76105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
76205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  for (i = 0; i < wq->count; i++)
76305436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
76405436638acc7c010349a69c3395f1a57c642dc62Ying Wang      unsigned int index = wq->offset + i;
76505436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (index >= wq->alloc)
76605436638acc7c010349a69c3395f1a57c642dc62Ying Wang        index -= wq->alloc;
76705436638acc7c010349a69c3395f1a57c642dc62Ying Wang      SetEvent (wq->array[index]);
76805436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
76905436638acc7c010349a69c3395f1a57c642dc62Ying Wang  wq->count = 0;
77005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  wq->offset = 0;
77105436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
77205436638acc7c010349a69c3395f1a57c642dc62Ying Wang
77305436638acc7c010349a69c3395f1a57c642dc62Ying Wangvoid
77405436638acc7c010349a69c3395f1a57c642dc62Ying Wangglthread_rwlock_init_func (gl_rwlock_t *lock)
77505436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
77605436638acc7c010349a69c3395f1a57c642dc62Ying Wang  InitializeCriticalSection (&lock->lock);
77705436638acc7c010349a69c3395f1a57c642dc62Ying Wang  gl_waitqueue_init (&lock->waiting_readers);
77805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  gl_waitqueue_init (&lock->waiting_writers);
77905436638acc7c010349a69c3395f1a57c642dc62Ying Wang  lock->runcount = 0;
78005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  lock->guard.done = 1;
78105436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
78205436638acc7c010349a69c3395f1a57c642dc62Ying Wang
78305436638acc7c010349a69c3395f1a57c642dc62Ying Wangint
78405436638acc7c010349a69c3395f1a57c642dc62Ying Wangglthread_rwlock_rdlock_func (gl_rwlock_t *lock)
78505436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
78605436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (!lock->guard.done)
78705436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
78805436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (InterlockedIncrement (&lock->guard.started) == 0)
78905436638acc7c010349a69c3395f1a57c642dc62Ying Wang        /* This thread is the first one to need this lock.  Initialize it.  */
79005436638acc7c010349a69c3395f1a57c642dc62Ying Wang        glthread_rwlock_init (lock);
79105436638acc7c010349a69c3395f1a57c642dc62Ying Wang      else
79205436638acc7c010349a69c3395f1a57c642dc62Ying Wang        /* Yield the CPU while waiting for another thread to finish
79305436638acc7c010349a69c3395f1a57c642dc62Ying Wang           initializing this lock.  */
79405436638acc7c010349a69c3395f1a57c642dc62Ying Wang        while (!lock->guard.done)
79505436638acc7c010349a69c3395f1a57c642dc62Ying Wang          Sleep (0);
79605436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
79705436638acc7c010349a69c3395f1a57c642dc62Ying Wang  EnterCriticalSection (&lock->lock);
79805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  /* Test whether only readers are currently running, and whether the runcount
79905436638acc7c010349a69c3395f1a57c642dc62Ying Wang     field will not overflow.  */
80005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (!(lock->runcount + 1 > 0))
80105436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
80205436638acc7c010349a69c3395f1a57c642dc62Ying Wang      /* This thread has to wait for a while.  Enqueue it among the
80305436638acc7c010349a69c3395f1a57c642dc62Ying Wang         waiting_readers.  */
80405436638acc7c010349a69c3395f1a57c642dc62Ying Wang      HANDLE event = gl_waitqueue_add (&lock->waiting_readers);
80505436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (event != INVALID_HANDLE_VALUE)
80605436638acc7c010349a69c3395f1a57c642dc62Ying Wang        {
80705436638acc7c010349a69c3395f1a57c642dc62Ying Wang          DWORD result;
80805436638acc7c010349a69c3395f1a57c642dc62Ying Wang          LeaveCriticalSection (&lock->lock);
80905436638acc7c010349a69c3395f1a57c642dc62Ying Wang          /* Wait until another thread signals this event.  */
81005436638acc7c010349a69c3395f1a57c642dc62Ying Wang          result = WaitForSingleObject (event, INFINITE);
81105436638acc7c010349a69c3395f1a57c642dc62Ying Wang          if (result == WAIT_FAILED || result == WAIT_TIMEOUT)
81205436638acc7c010349a69c3395f1a57c642dc62Ying Wang            abort ();
81305436638acc7c010349a69c3395f1a57c642dc62Ying Wang          CloseHandle (event);
81405436638acc7c010349a69c3395f1a57c642dc62Ying Wang          /* The thread which signalled the event already did the bookkeeping:
81505436638acc7c010349a69c3395f1a57c642dc62Ying Wang             removed us from the waiting_readers, incremented lock->runcount.  */
81605436638acc7c010349a69c3395f1a57c642dc62Ying Wang          if (!(lock->runcount > 0))
81705436638acc7c010349a69c3395f1a57c642dc62Ying Wang            abort ();
81805436638acc7c010349a69c3395f1a57c642dc62Ying Wang          return 0;
81905436638acc7c010349a69c3395f1a57c642dc62Ying Wang        }
82005436638acc7c010349a69c3395f1a57c642dc62Ying Wang      else
82105436638acc7c010349a69c3395f1a57c642dc62Ying Wang        {
82205436638acc7c010349a69c3395f1a57c642dc62Ying Wang          /* Allocation failure.  Weird.  */
82305436638acc7c010349a69c3395f1a57c642dc62Ying Wang          do
82405436638acc7c010349a69c3395f1a57c642dc62Ying Wang            {
82505436638acc7c010349a69c3395f1a57c642dc62Ying Wang              LeaveCriticalSection (&lock->lock);
82605436638acc7c010349a69c3395f1a57c642dc62Ying Wang              Sleep (1);
82705436638acc7c010349a69c3395f1a57c642dc62Ying Wang              EnterCriticalSection (&lock->lock);
82805436638acc7c010349a69c3395f1a57c642dc62Ying Wang            }
82905436638acc7c010349a69c3395f1a57c642dc62Ying Wang          while (!(lock->runcount + 1 > 0));
83005436638acc7c010349a69c3395f1a57c642dc62Ying Wang        }
83105436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
83205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  lock->runcount++;
83305436638acc7c010349a69c3395f1a57c642dc62Ying Wang  LeaveCriticalSection (&lock->lock);
83405436638acc7c010349a69c3395f1a57c642dc62Ying Wang  return 0;
83505436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
83605436638acc7c010349a69c3395f1a57c642dc62Ying Wang
83705436638acc7c010349a69c3395f1a57c642dc62Ying Wangint
83805436638acc7c010349a69c3395f1a57c642dc62Ying Wangglthread_rwlock_wrlock_func (gl_rwlock_t *lock)
83905436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
84005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (!lock->guard.done)
84105436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
84205436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (InterlockedIncrement (&lock->guard.started) == 0)
84305436638acc7c010349a69c3395f1a57c642dc62Ying Wang        /* This thread is the first one to need this lock.  Initialize it.  */
84405436638acc7c010349a69c3395f1a57c642dc62Ying Wang        glthread_rwlock_init (lock);
84505436638acc7c010349a69c3395f1a57c642dc62Ying Wang      else
84605436638acc7c010349a69c3395f1a57c642dc62Ying Wang        /* Yield the CPU while waiting for another thread to finish
84705436638acc7c010349a69c3395f1a57c642dc62Ying Wang           initializing this lock.  */
84805436638acc7c010349a69c3395f1a57c642dc62Ying Wang        while (!lock->guard.done)
84905436638acc7c010349a69c3395f1a57c642dc62Ying Wang          Sleep (0);
85005436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
85105436638acc7c010349a69c3395f1a57c642dc62Ying Wang  EnterCriticalSection (&lock->lock);
85205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  /* Test whether no readers or writers are currently running.  */
85305436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (!(lock->runcount == 0))
85405436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
85505436638acc7c010349a69c3395f1a57c642dc62Ying Wang      /* This thread has to wait for a while.  Enqueue it among the
85605436638acc7c010349a69c3395f1a57c642dc62Ying Wang         waiting_writers.  */
85705436638acc7c010349a69c3395f1a57c642dc62Ying Wang      HANDLE event = gl_waitqueue_add (&lock->waiting_writers);
85805436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (event != INVALID_HANDLE_VALUE)
85905436638acc7c010349a69c3395f1a57c642dc62Ying Wang        {
86005436638acc7c010349a69c3395f1a57c642dc62Ying Wang          DWORD result;
86105436638acc7c010349a69c3395f1a57c642dc62Ying Wang          LeaveCriticalSection (&lock->lock);
86205436638acc7c010349a69c3395f1a57c642dc62Ying Wang          /* Wait until another thread signals this event.  */
86305436638acc7c010349a69c3395f1a57c642dc62Ying Wang          result = WaitForSingleObject (event, INFINITE);
86405436638acc7c010349a69c3395f1a57c642dc62Ying Wang          if (result == WAIT_FAILED || result == WAIT_TIMEOUT)
86505436638acc7c010349a69c3395f1a57c642dc62Ying Wang            abort ();
86605436638acc7c010349a69c3395f1a57c642dc62Ying Wang          CloseHandle (event);
86705436638acc7c010349a69c3395f1a57c642dc62Ying Wang          /* The thread which signalled the event already did the bookkeeping:
86805436638acc7c010349a69c3395f1a57c642dc62Ying Wang             removed us from the waiting_writers, set lock->runcount = -1.  */
86905436638acc7c010349a69c3395f1a57c642dc62Ying Wang          if (!(lock->runcount == -1))
87005436638acc7c010349a69c3395f1a57c642dc62Ying Wang            abort ();
87105436638acc7c010349a69c3395f1a57c642dc62Ying Wang          return 0;
87205436638acc7c010349a69c3395f1a57c642dc62Ying Wang        }
87305436638acc7c010349a69c3395f1a57c642dc62Ying Wang      else
87405436638acc7c010349a69c3395f1a57c642dc62Ying Wang        {
87505436638acc7c010349a69c3395f1a57c642dc62Ying Wang          /* Allocation failure.  Weird.  */
87605436638acc7c010349a69c3395f1a57c642dc62Ying Wang          do
87705436638acc7c010349a69c3395f1a57c642dc62Ying Wang            {
87805436638acc7c010349a69c3395f1a57c642dc62Ying Wang              LeaveCriticalSection (&lock->lock);
87905436638acc7c010349a69c3395f1a57c642dc62Ying Wang              Sleep (1);
88005436638acc7c010349a69c3395f1a57c642dc62Ying Wang              EnterCriticalSection (&lock->lock);
88105436638acc7c010349a69c3395f1a57c642dc62Ying Wang            }
88205436638acc7c010349a69c3395f1a57c642dc62Ying Wang          while (!(lock->runcount == 0));
88305436638acc7c010349a69c3395f1a57c642dc62Ying Wang        }
88405436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
88505436638acc7c010349a69c3395f1a57c642dc62Ying Wang  lock->runcount--; /* runcount becomes -1 */
88605436638acc7c010349a69c3395f1a57c642dc62Ying Wang  LeaveCriticalSection (&lock->lock);
88705436638acc7c010349a69c3395f1a57c642dc62Ying Wang  return 0;
88805436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
88905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
89005436638acc7c010349a69c3395f1a57c642dc62Ying Wangint
89105436638acc7c010349a69c3395f1a57c642dc62Ying Wangglthread_rwlock_unlock_func (gl_rwlock_t *lock)
89205436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
89305436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (!lock->guard.done)
89405436638acc7c010349a69c3395f1a57c642dc62Ying Wang    return EINVAL;
89505436638acc7c010349a69c3395f1a57c642dc62Ying Wang  EnterCriticalSection (&lock->lock);
89605436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (lock->runcount < 0)
89705436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
89805436638acc7c010349a69c3395f1a57c642dc62Ying Wang      /* Drop a writer lock.  */
89905436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (!(lock->runcount == -1))
90005436638acc7c010349a69c3395f1a57c642dc62Ying Wang        abort ();
90105436638acc7c010349a69c3395f1a57c642dc62Ying Wang      lock->runcount = 0;
90205436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
90305436638acc7c010349a69c3395f1a57c642dc62Ying Wang  else
90405436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
90505436638acc7c010349a69c3395f1a57c642dc62Ying Wang      /* Drop a reader lock.  */
90605436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (!(lock->runcount > 0))
90705436638acc7c010349a69c3395f1a57c642dc62Ying Wang        {
90805436638acc7c010349a69c3395f1a57c642dc62Ying Wang          LeaveCriticalSection (&lock->lock);
90905436638acc7c010349a69c3395f1a57c642dc62Ying Wang          return EPERM;
91005436638acc7c010349a69c3395f1a57c642dc62Ying Wang        }
91105436638acc7c010349a69c3395f1a57c642dc62Ying Wang      lock->runcount--;
91205436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
91305436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (lock->runcount == 0)
91405436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
91505436638acc7c010349a69c3395f1a57c642dc62Ying Wang      /* POSIX recommends that "write locks shall take precedence over read
91605436638acc7c010349a69c3395f1a57c642dc62Ying Wang         locks", to avoid "writer starvation".  */
91705436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (lock->waiting_writers.count > 0)
91805436638acc7c010349a69c3395f1a57c642dc62Ying Wang        {
91905436638acc7c010349a69c3395f1a57c642dc62Ying Wang          /* Wake up one of the waiting writers.  */
92005436638acc7c010349a69c3395f1a57c642dc62Ying Wang          lock->runcount--;
92105436638acc7c010349a69c3395f1a57c642dc62Ying Wang          gl_waitqueue_notify_first (&lock->waiting_writers);
92205436638acc7c010349a69c3395f1a57c642dc62Ying Wang        }
92305436638acc7c010349a69c3395f1a57c642dc62Ying Wang      else
92405436638acc7c010349a69c3395f1a57c642dc62Ying Wang        {
92505436638acc7c010349a69c3395f1a57c642dc62Ying Wang          /* Wake up all waiting readers.  */
92605436638acc7c010349a69c3395f1a57c642dc62Ying Wang          lock->runcount += lock->waiting_readers.count;
92705436638acc7c010349a69c3395f1a57c642dc62Ying Wang          gl_waitqueue_notify_all (&lock->waiting_readers);
92805436638acc7c010349a69c3395f1a57c642dc62Ying Wang        }
92905436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
93005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  LeaveCriticalSection (&lock->lock);
93105436638acc7c010349a69c3395f1a57c642dc62Ying Wang  return 0;
93205436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
93305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
93405436638acc7c010349a69c3395f1a57c642dc62Ying Wangint
93505436638acc7c010349a69c3395f1a57c642dc62Ying Wangglthread_rwlock_destroy_func (gl_rwlock_t *lock)
93605436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
93705436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (!lock->guard.done)
93805436638acc7c010349a69c3395f1a57c642dc62Ying Wang    return EINVAL;
93905436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (lock->runcount != 0)
94005436638acc7c010349a69c3395f1a57c642dc62Ying Wang    return EBUSY;
94105436638acc7c010349a69c3395f1a57c642dc62Ying Wang  DeleteCriticalSection (&lock->lock);
94205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (lock->waiting_readers.array != NULL)
94305436638acc7c010349a69c3395f1a57c642dc62Ying Wang    free (lock->waiting_readers.array);
94405436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (lock->waiting_writers.array != NULL)
94505436638acc7c010349a69c3395f1a57c642dc62Ying Wang    free (lock->waiting_writers.array);
94605436638acc7c010349a69c3395f1a57c642dc62Ying Wang  lock->guard.done = 0;
94705436638acc7c010349a69c3395f1a57c642dc62Ying Wang  return 0;
94805436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
94905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
95005436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* --------------------- gl_recursive_lock_t datatype --------------------- */
95105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
95205436638acc7c010349a69c3395f1a57c642dc62Ying Wangvoid
95305436638acc7c010349a69c3395f1a57c642dc62Ying Wangglthread_recursive_lock_init_func (gl_recursive_lock_t *lock)
95405436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
95505436638acc7c010349a69c3395f1a57c642dc62Ying Wang  lock->owner = 0;
95605436638acc7c010349a69c3395f1a57c642dc62Ying Wang  lock->depth = 0;
95705436638acc7c010349a69c3395f1a57c642dc62Ying Wang  InitializeCriticalSection (&lock->lock);
95805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  lock->guard.done = 1;
95905436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
96005436638acc7c010349a69c3395f1a57c642dc62Ying Wang
96105436638acc7c010349a69c3395f1a57c642dc62Ying Wangint
96205436638acc7c010349a69c3395f1a57c642dc62Ying Wangglthread_recursive_lock_lock_func (gl_recursive_lock_t *lock)
96305436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
96405436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (!lock->guard.done)
96505436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
96605436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (InterlockedIncrement (&lock->guard.started) == 0)
96705436638acc7c010349a69c3395f1a57c642dc62Ying Wang        /* This thread is the first one to need this lock.  Initialize it.  */
96805436638acc7c010349a69c3395f1a57c642dc62Ying Wang        glthread_recursive_lock_init (lock);
96905436638acc7c010349a69c3395f1a57c642dc62Ying Wang      else
97005436638acc7c010349a69c3395f1a57c642dc62Ying Wang        /* Yield the CPU while waiting for another thread to finish
97105436638acc7c010349a69c3395f1a57c642dc62Ying Wang           initializing this lock.  */
97205436638acc7c010349a69c3395f1a57c642dc62Ying Wang        while (!lock->guard.done)
97305436638acc7c010349a69c3395f1a57c642dc62Ying Wang          Sleep (0);
97405436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
97505436638acc7c010349a69c3395f1a57c642dc62Ying Wang  {
97605436638acc7c010349a69c3395f1a57c642dc62Ying Wang    DWORD self = GetCurrentThreadId ();
97705436638acc7c010349a69c3395f1a57c642dc62Ying Wang    if (lock->owner != self)
97805436638acc7c010349a69c3395f1a57c642dc62Ying Wang      {
97905436638acc7c010349a69c3395f1a57c642dc62Ying Wang        EnterCriticalSection (&lock->lock);
98005436638acc7c010349a69c3395f1a57c642dc62Ying Wang        lock->owner = self;
98105436638acc7c010349a69c3395f1a57c642dc62Ying Wang      }
98205436638acc7c010349a69c3395f1a57c642dc62Ying Wang    if (++(lock->depth) == 0) /* wraparound? */
98305436638acc7c010349a69c3395f1a57c642dc62Ying Wang      {
98405436638acc7c010349a69c3395f1a57c642dc62Ying Wang        lock->depth--;
98505436638acc7c010349a69c3395f1a57c642dc62Ying Wang        return EAGAIN;
98605436638acc7c010349a69c3395f1a57c642dc62Ying Wang      }
98705436638acc7c010349a69c3395f1a57c642dc62Ying Wang  }
98805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  return 0;
98905436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
99005436638acc7c010349a69c3395f1a57c642dc62Ying Wang
99105436638acc7c010349a69c3395f1a57c642dc62Ying Wangint
99205436638acc7c010349a69c3395f1a57c642dc62Ying Wangglthread_recursive_lock_unlock_func (gl_recursive_lock_t *lock)
99305436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
99405436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (lock->owner != GetCurrentThreadId ())
99505436638acc7c010349a69c3395f1a57c642dc62Ying Wang    return EPERM;
99605436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (lock->depth == 0)
99705436638acc7c010349a69c3395f1a57c642dc62Ying Wang    return EINVAL;
99805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (--(lock->depth) == 0)
99905436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
100005436638acc7c010349a69c3395f1a57c642dc62Ying Wang      lock->owner = 0;
100105436638acc7c010349a69c3395f1a57c642dc62Ying Wang      LeaveCriticalSection (&lock->lock);
100205436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
100305436638acc7c010349a69c3395f1a57c642dc62Ying Wang  return 0;
100405436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
100505436638acc7c010349a69c3395f1a57c642dc62Ying Wang
100605436638acc7c010349a69c3395f1a57c642dc62Ying Wangint
100705436638acc7c010349a69c3395f1a57c642dc62Ying Wangglthread_recursive_lock_destroy_func (gl_recursive_lock_t *lock)
100805436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
100905436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (lock->owner != 0)
101005436638acc7c010349a69c3395f1a57c642dc62Ying Wang    return EBUSY;
101105436638acc7c010349a69c3395f1a57c642dc62Ying Wang  DeleteCriticalSection (&lock->lock);
101205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  lock->guard.done = 0;
101305436638acc7c010349a69c3395f1a57c642dc62Ying Wang  return 0;
101405436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
101505436638acc7c010349a69c3395f1a57c642dc62Ying Wang
101605436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* -------------------------- gl_once_t datatype -------------------------- */
101705436638acc7c010349a69c3395f1a57c642dc62Ying Wang
101805436638acc7c010349a69c3395f1a57c642dc62Ying Wangvoid
101905436638acc7c010349a69c3395f1a57c642dc62Ying Wangglthread_once_func (gl_once_t *once_control, void (*initfunction) (void))
102005436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
102105436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (once_control->inited <= 0)
102205436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
102305436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (InterlockedIncrement (&once_control->started) == 0)
102405436638acc7c010349a69c3395f1a57c642dc62Ying Wang        {
102505436638acc7c010349a69c3395f1a57c642dc62Ying Wang          /* This thread is the first one to come to this once_control.  */
102605436638acc7c010349a69c3395f1a57c642dc62Ying Wang          InitializeCriticalSection (&once_control->lock);
102705436638acc7c010349a69c3395f1a57c642dc62Ying Wang          EnterCriticalSection (&once_control->lock);
102805436638acc7c010349a69c3395f1a57c642dc62Ying Wang          once_control->inited = 0;
102905436638acc7c010349a69c3395f1a57c642dc62Ying Wang          initfunction ();
103005436638acc7c010349a69c3395f1a57c642dc62Ying Wang          once_control->inited = 1;
103105436638acc7c010349a69c3395f1a57c642dc62Ying Wang          LeaveCriticalSection (&once_control->lock);
103205436638acc7c010349a69c3395f1a57c642dc62Ying Wang        }
103305436638acc7c010349a69c3395f1a57c642dc62Ying Wang      else
103405436638acc7c010349a69c3395f1a57c642dc62Ying Wang        {
103505436638acc7c010349a69c3395f1a57c642dc62Ying Wang          /* Undo last operation.  */
103605436638acc7c010349a69c3395f1a57c642dc62Ying Wang          InterlockedDecrement (&once_control->started);
103705436638acc7c010349a69c3395f1a57c642dc62Ying Wang          /* Some other thread has already started the initialization.
103805436638acc7c010349a69c3395f1a57c642dc62Ying Wang             Yield the CPU while waiting for the other thread to finish
103905436638acc7c010349a69c3395f1a57c642dc62Ying Wang             initializing and taking the lock.  */
104005436638acc7c010349a69c3395f1a57c642dc62Ying Wang          while (once_control->inited < 0)
104105436638acc7c010349a69c3395f1a57c642dc62Ying Wang            Sleep (0);
104205436638acc7c010349a69c3395f1a57c642dc62Ying Wang          if (once_control->inited <= 0)
104305436638acc7c010349a69c3395f1a57c642dc62Ying Wang            {
104405436638acc7c010349a69c3395f1a57c642dc62Ying Wang              /* Take the lock.  This blocks until the other thread has
104505436638acc7c010349a69c3395f1a57c642dc62Ying Wang                 finished calling the initfunction.  */
104605436638acc7c010349a69c3395f1a57c642dc62Ying Wang              EnterCriticalSection (&once_control->lock);
104705436638acc7c010349a69c3395f1a57c642dc62Ying Wang              LeaveCriticalSection (&once_control->lock);
104805436638acc7c010349a69c3395f1a57c642dc62Ying Wang              if (!(once_control->inited > 0))
104905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                abort ();
105005436638acc7c010349a69c3395f1a57c642dc62Ying Wang            }
105105436638acc7c010349a69c3395f1a57c642dc62Ying Wang        }
105205436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
105305436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
105405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
105505436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
105605436638acc7c010349a69c3395f1a57c642dc62Ying Wang
105705436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* ========================================================================= */
1058