Blame gnulib/lib/glthread/lock.c

Packit Service a2ae7a
/* Locking in multithreaded situations.
Packit Service a2ae7a
   Copyright (C) 2005-2019 Free Software Foundation, Inc.
Packit Service a2ae7a
Packit Service a2ae7a
   This program is free software; you can redistribute it and/or modify
Packit Service a2ae7a
   it under the terms of the GNU Lesser General Public License as published by
Packit Service a2ae7a
   the Free Software Foundation; either version 2.1, or (at your option)
Packit Service a2ae7a
   any later version.
Packit Service a2ae7a
Packit Service a2ae7a
   This program is distributed in the hope that it will be useful,
Packit Service a2ae7a
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service a2ae7a
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service a2ae7a
   GNU Lesser General Public License for more details.
Packit Service a2ae7a
Packit Service a2ae7a
   You should have received a copy of the GNU Lesser General Public License
Packit Service a2ae7a
   along with this program; if not, see <https://www.gnu.org/licenses/>.  */
Packit Service a2ae7a
Packit Service a2ae7a
/* Written by Bruno Haible <bruno@clisp.org>, 2005.
Packit Service a2ae7a
   Based on GCC's gthr-posix.h, gthr-posix95.h, gthr-solaris.h,
Packit Service a2ae7a
   gthr-win32.h.  */
Packit Service a2ae7a
Packit Service a2ae7a
#include <config.h>
Packit Service a2ae7a
Packit Service a2ae7a
#include "glthread/lock.h"
Packit Service a2ae7a
Packit Service a2ae7a
/* ========================================================================= */
Packit Service a2ae7a
Packit Service a2ae7a
#if USE_POSIX_THREADS
Packit Service a2ae7a
Packit Service a2ae7a
/* -------------------------- gl_lock_t datatype -------------------------- */
Packit Service a2ae7a
Packit Service a2ae7a
/* ------------------------- gl_rwlock_t datatype ------------------------- */
Packit Service a2ae7a
Packit Service a2ae7a
# if HAVE_PTHREAD_RWLOCK && (HAVE_PTHREAD_RWLOCK_RDLOCK_PREFER_WRITER || (defined PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP && (__GNU_LIBRARY__ > 1)))
Packit Service a2ae7a
Packit Service a2ae7a
#  ifdef PTHREAD_RWLOCK_INITIALIZER
Packit Service a2ae7a
Packit Service a2ae7a
#   if !HAVE_PTHREAD_RWLOCK_RDLOCK_PREFER_WRITER
Packit Service a2ae7a
     /* glibc with bug https://sourceware.org/bugzilla/show_bug.cgi?id=13701 */
Packit Service a2ae7a
Packit Service a2ae7a
int
Packit Service a2ae7a
glthread_rwlock_init_for_glibc (pthread_rwlock_t *lock)
Packit Service a2ae7a
{
Packit Service a2ae7a
  pthread_rwlockattr_t attributes;
Packit Service a2ae7a
  int err;
Packit Service a2ae7a
Packit Service a2ae7a
  err = pthread_rwlockattr_init (&attributes);
Packit Service a2ae7a
  if (err != 0)
Packit Service a2ae7a
    return err;
Packit Service a2ae7a
  /* Note: PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP is the only value that
Packit Service a2ae7a
     causes the writer to be preferred. PTHREAD_RWLOCK_PREFER_WRITER_NP does not
Packit Service a2ae7a
     do this; see
Packit Service a2ae7a
     http://man7.org/linux/man-pages/man3/pthread_rwlockattr_setkind_np.3.html */
Packit Service a2ae7a
  err = pthread_rwlockattr_setkind_np (&attributes,
Packit Service a2ae7a
                                       PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP);
Packit Service a2ae7a
  if (err == 0)
Packit Service a2ae7a
    err = pthread_rwlock_init(lock, &attributes);
Packit Service a2ae7a
  /* pthread_rwlockattr_destroy always returns 0.  It cannot influence the
Packit Service a2ae7a
     return value.  */
Packit Service a2ae7a
  pthread_rwlockattr_destroy (&attributes);
Packit Service a2ae7a
  return err;
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
#   endif
Packit Service a2ae7a
#  else
Packit Service a2ae7a
Packit Service a2ae7a
int
Packit Service a2ae7a
glthread_rwlock_init_multithreaded (gl_rwlock_t *lock)
Packit Service a2ae7a
{
Packit Service a2ae7a
  int err;
Packit Service a2ae7a
Packit Service a2ae7a
  err = pthread_rwlock_init (&lock->rwlock, NULL);
Packit Service a2ae7a
  if (err != 0)
Packit Service a2ae7a
    return err;
Packit Service a2ae7a
  lock->initialized = 1;
Packit Service a2ae7a
  return 0;
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
int
Packit Service a2ae7a
glthread_rwlock_rdlock_multithreaded (gl_rwlock_t *lock)
Packit Service a2ae7a
{
Packit Service a2ae7a
  if (!lock->initialized)
Packit Service a2ae7a
    {
Packit Service a2ae7a
      int err;
Packit Service a2ae7a
Packit Service a2ae7a
      err = pthread_mutex_lock (&lock->guard);
Packit Service a2ae7a
      if (err != 0)
Packit Service a2ae7a
        return err;
Packit Service a2ae7a
      if (!lock->initialized)
Packit Service a2ae7a
        {
Packit Service a2ae7a
          err = glthread_rwlock_init_multithreaded (lock);
Packit Service a2ae7a
          if (err != 0)
Packit Service a2ae7a
            {
Packit Service a2ae7a
              pthread_mutex_unlock (&lock->guard);
Packit Service a2ae7a
              return err;
Packit Service a2ae7a
            }
Packit Service a2ae7a
        }
Packit Service a2ae7a
      err = pthread_mutex_unlock (&lock->guard);
Packit Service a2ae7a
      if (err != 0)
Packit Service a2ae7a
        return err;
Packit Service a2ae7a
    }
Packit Service a2ae7a
  return pthread_rwlock_rdlock (&lock->rwlock);
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
int
Packit Service a2ae7a
glthread_rwlock_wrlock_multithreaded (gl_rwlock_t *lock)
Packit Service a2ae7a
{
Packit Service a2ae7a
  if (!lock->initialized)
Packit Service a2ae7a
    {
Packit Service a2ae7a
      int err;
Packit Service a2ae7a
Packit Service a2ae7a
      err = pthread_mutex_lock (&lock->guard);
Packit Service a2ae7a
      if (err != 0)
Packit Service a2ae7a
        return err;
Packit Service a2ae7a
      if (!lock->initialized)
Packit Service a2ae7a
        {
Packit Service a2ae7a
          err = glthread_rwlock_init_multithreaded (lock);
Packit Service a2ae7a
          if (err != 0)
Packit Service a2ae7a
            {
Packit Service a2ae7a
              pthread_mutex_unlock (&lock->guard);
Packit Service a2ae7a
              return err;
Packit Service a2ae7a
            }
Packit Service a2ae7a
        }
Packit Service a2ae7a
      err = pthread_mutex_unlock (&lock->guard);
Packit Service a2ae7a
      if (err != 0)
Packit Service a2ae7a
        return err;
Packit Service a2ae7a
    }
Packit Service a2ae7a
  return pthread_rwlock_wrlock (&lock->rwlock);
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
int
Packit Service a2ae7a
glthread_rwlock_unlock_multithreaded (gl_rwlock_t *lock)
Packit Service a2ae7a
{
Packit Service a2ae7a
  if (!lock->initialized)
Packit Service a2ae7a
    return EINVAL;
Packit Service a2ae7a
  return pthread_rwlock_unlock (&lock->rwlock);
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
int
Packit Service a2ae7a
glthread_rwlock_destroy_multithreaded (gl_rwlock_t *lock)
Packit Service a2ae7a
{
Packit Service a2ae7a
  int err;
Packit Service a2ae7a
Packit Service a2ae7a
  if (!lock->initialized)
Packit Service a2ae7a
    return EINVAL;
Packit Service a2ae7a
  err = pthread_rwlock_destroy (&lock->rwlock);
Packit Service a2ae7a
  if (err != 0)
Packit Service a2ae7a
    return err;
Packit Service a2ae7a
  lock->initialized = 0;
Packit Service a2ae7a
  return 0;
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
#  endif
Packit Service a2ae7a
Packit Service a2ae7a
# else
Packit Service a2ae7a
Packit Service a2ae7a
int
Packit Service a2ae7a
glthread_rwlock_init_multithreaded (gl_rwlock_t *lock)
Packit Service a2ae7a
{
Packit Service a2ae7a
  int err;
Packit Service a2ae7a
Packit Service a2ae7a
  err = pthread_mutex_init (&lock->lock, NULL);
Packit Service a2ae7a
  if (err != 0)
Packit Service a2ae7a
    return err;
Packit Service a2ae7a
  err = pthread_cond_init (&lock->waiting_readers, NULL);
Packit Service a2ae7a
  if (err != 0)
Packit Service a2ae7a
    return err;
Packit Service a2ae7a
  err = pthread_cond_init (&lock->waiting_writers, NULL);
Packit Service a2ae7a
  if (err != 0)
Packit Service a2ae7a
    return err;
Packit Service a2ae7a
  lock->waiting_writers_count = 0;
Packit Service a2ae7a
  lock->runcount = 0;
Packit Service a2ae7a
  return 0;
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
int
Packit Service a2ae7a
glthread_rwlock_rdlock_multithreaded (gl_rwlock_t *lock)
Packit Service a2ae7a
{
Packit Service a2ae7a
  int err;
Packit Service a2ae7a
Packit Service a2ae7a
  err = pthread_mutex_lock (&lock->lock);
Packit Service a2ae7a
  if (err != 0)
Packit Service a2ae7a
    return err;
Packit Service a2ae7a
  /* Test whether only readers are currently running, and whether the runcount
Packit Service a2ae7a
     field will not overflow, and whether no writer is waiting.  The latter
Packit Service a2ae7a
     condition is because POSIX recommends that "write locks shall take
Packit Service a2ae7a
     precedence over read locks", to avoid "writer starvation".  */
Packit Service a2ae7a
  while (!(lock->runcount + 1 > 0 && lock->waiting_writers_count == 0))
Packit Service a2ae7a
    {
Packit Service a2ae7a
      /* This thread has to wait for a while.  Enqueue it among the
Packit Service a2ae7a
         waiting_readers.  */
Packit Service a2ae7a
      err = pthread_cond_wait (&lock->waiting_readers, &lock->lock);
Packit Service a2ae7a
      if (err != 0)
Packit Service a2ae7a
        {
Packit Service a2ae7a
          pthread_mutex_unlock (&lock->lock);
Packit Service a2ae7a
          return err;
Packit Service a2ae7a
        }
Packit Service a2ae7a
    }
Packit Service a2ae7a
  lock->runcount++;
Packit Service a2ae7a
  return pthread_mutex_unlock (&lock->lock);
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
int
Packit Service a2ae7a
glthread_rwlock_wrlock_multithreaded (gl_rwlock_t *lock)
Packit Service a2ae7a
{
Packit Service a2ae7a
  int err;
Packit Service a2ae7a
Packit Service a2ae7a
  err = pthread_mutex_lock (&lock->lock);
Packit Service a2ae7a
  if (err != 0)
Packit Service a2ae7a
    return err;
Packit Service a2ae7a
  /* Test whether no readers or writers are currently running.  */
Packit Service a2ae7a
  while (!(lock->runcount == 0))
Packit Service a2ae7a
    {
Packit Service a2ae7a
      /* This thread has to wait for a while.  Enqueue it among the
Packit Service a2ae7a
         waiting_writers.  */
Packit Service a2ae7a
      lock->waiting_writers_count++;
Packit Service a2ae7a
      err = pthread_cond_wait (&lock->waiting_writers, &lock->lock);
Packit Service a2ae7a
      if (err != 0)
Packit Service a2ae7a
        {
Packit Service a2ae7a
          lock->waiting_writers_count--;
Packit Service a2ae7a
          pthread_mutex_unlock (&lock->lock);
Packit Service a2ae7a
          return err;
Packit Service a2ae7a
        }
Packit Service a2ae7a
      lock->waiting_writers_count--;
Packit Service a2ae7a
    }
Packit Service a2ae7a
  lock->runcount--; /* runcount becomes -1 */
Packit Service a2ae7a
  return pthread_mutex_unlock (&lock->lock);
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
int
Packit Service a2ae7a
glthread_rwlock_unlock_multithreaded (gl_rwlock_t *lock)
Packit Service a2ae7a
{
Packit Service a2ae7a
  int err;
Packit Service a2ae7a
Packit Service a2ae7a
  err = pthread_mutex_lock (&lock->lock);
Packit Service a2ae7a
  if (err != 0)
Packit Service a2ae7a
    return err;
Packit Service a2ae7a
  if (lock->runcount < 0)
Packit Service a2ae7a
    {
Packit Service a2ae7a
      /* Drop a writer lock.  */
Packit Service a2ae7a
      if (!(lock->runcount == -1))
Packit Service a2ae7a
        {
Packit Service a2ae7a
          pthread_mutex_unlock (&lock->lock);
Packit Service a2ae7a
          return EINVAL;
Packit Service a2ae7a
        }
Packit Service a2ae7a
      lock->runcount = 0;
Packit Service a2ae7a
    }
Packit Service a2ae7a
  else
Packit Service a2ae7a
    {
Packit Service a2ae7a
      /* Drop a reader lock.  */
Packit Service a2ae7a
      if (!(lock->runcount > 0))
Packit Service a2ae7a
        {
Packit Service a2ae7a
          pthread_mutex_unlock (&lock->lock);
Packit Service a2ae7a
          return EINVAL;
Packit Service a2ae7a
        }
Packit Service a2ae7a
      lock->runcount--;
Packit Service a2ae7a
    }
Packit Service a2ae7a
  if (lock->runcount == 0)
Packit Service a2ae7a
    {
Packit Service a2ae7a
      /* POSIX recommends that "write locks shall take precedence over read
Packit Service a2ae7a
         locks", to avoid "writer starvation".  */
Packit Service a2ae7a
      if (lock->waiting_writers_count > 0)
Packit Service a2ae7a
        {
Packit Service a2ae7a
          /* Wake up one of the waiting writers.  */
Packit Service a2ae7a
          err = pthread_cond_signal (&lock->waiting_writers);
Packit Service a2ae7a
          if (err != 0)
Packit Service a2ae7a
            {
Packit Service a2ae7a
              pthread_mutex_unlock (&lock->lock);
Packit Service a2ae7a
              return err;
Packit Service a2ae7a
            }
Packit Service a2ae7a
        }
Packit Service a2ae7a
      else
Packit Service a2ae7a
        {
Packit Service a2ae7a
          /* Wake up all waiting readers.  */
Packit Service a2ae7a
          err = pthread_cond_broadcast (&lock->waiting_readers);
Packit Service a2ae7a
          if (err != 0)
Packit Service a2ae7a
            {
Packit Service a2ae7a
              pthread_mutex_unlock (&lock->lock);
Packit Service a2ae7a
              return err;
Packit Service a2ae7a
            }
Packit Service a2ae7a
        }
Packit Service a2ae7a
    }
Packit Service a2ae7a
  return pthread_mutex_unlock (&lock->lock);
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
int
Packit Service a2ae7a
glthread_rwlock_destroy_multithreaded (gl_rwlock_t *lock)
Packit Service a2ae7a
{
Packit Service a2ae7a
  int err;
Packit Service a2ae7a
Packit Service a2ae7a
  err = pthread_mutex_destroy (&lock->lock);
Packit Service a2ae7a
  if (err != 0)
Packit Service a2ae7a
    return err;
Packit Service a2ae7a
  err = pthread_cond_destroy (&lock->waiting_readers);
Packit Service a2ae7a
  if (err != 0)
Packit Service a2ae7a
    return err;
Packit Service a2ae7a
  err = pthread_cond_destroy (&lock->waiting_writers);
Packit Service a2ae7a
  if (err != 0)
Packit Service a2ae7a
    return err;
Packit Service a2ae7a
  return 0;
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
# endif
Packit Service a2ae7a
Packit Service a2ae7a
/* --------------------- gl_recursive_lock_t datatype --------------------- */
Packit Service a2ae7a
Packit Service a2ae7a
# if HAVE_PTHREAD_MUTEX_RECURSIVE
Packit Service a2ae7a
Packit Service a2ae7a
#  if defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER || defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
Packit Service a2ae7a
Packit Service a2ae7a
int
Packit Service a2ae7a
glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock)
Packit Service a2ae7a
{
Packit Service a2ae7a
  pthread_mutexattr_t attributes;
Packit Service a2ae7a
  int err;
Packit Service a2ae7a
Packit Service a2ae7a
  err = pthread_mutexattr_init (&attributes);
Packit Service a2ae7a
  if (err != 0)
Packit Service a2ae7a
    return err;
Packit Service a2ae7a
  err = pthread_mutexattr_settype (&attributes, PTHREAD_MUTEX_RECURSIVE);
Packit Service a2ae7a
  if (err != 0)
Packit Service a2ae7a
    {
Packit Service a2ae7a
      pthread_mutexattr_destroy (&attributes);
Packit Service a2ae7a
      return err;
Packit Service a2ae7a
    }
Packit Service a2ae7a
  err = pthread_mutex_init (lock, &attributes);
Packit Service a2ae7a
  if (err != 0)
Packit Service a2ae7a
    {
Packit Service a2ae7a
      pthread_mutexattr_destroy (&attributes);
Packit Service a2ae7a
      return err;
Packit Service a2ae7a
    }
Packit Service a2ae7a
  err = pthread_mutexattr_destroy (&attributes);
Packit Service a2ae7a
  if (err != 0)
Packit Service a2ae7a
    return err;
Packit Service a2ae7a
  return 0;
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
#  else
Packit Service a2ae7a
Packit Service a2ae7a
int
Packit Service a2ae7a
glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock)
Packit Service a2ae7a
{
Packit Service a2ae7a
  pthread_mutexattr_t attributes;
Packit Service a2ae7a
  int err;
Packit Service a2ae7a
Packit Service a2ae7a
  err = pthread_mutexattr_init (&attributes);
Packit Service a2ae7a
  if (err != 0)
Packit Service a2ae7a
    return err;
Packit Service a2ae7a
  err = pthread_mutexattr_settype (&attributes, PTHREAD_MUTEX_RECURSIVE);
Packit Service a2ae7a
  if (err != 0)
Packit Service a2ae7a
    {
Packit Service a2ae7a
      pthread_mutexattr_destroy (&attributes);
Packit Service a2ae7a
      return err;
Packit Service a2ae7a
    }
Packit Service a2ae7a
  err = pthread_mutex_init (&lock->recmutex, &attributes);
Packit Service a2ae7a
  if (err != 0)
Packit Service a2ae7a
    {
Packit Service a2ae7a
      pthread_mutexattr_destroy (&attributes);
Packit Service a2ae7a
      return err;
Packit Service a2ae7a
    }
Packit Service a2ae7a
  err = pthread_mutexattr_destroy (&attributes);
Packit Service a2ae7a
  if (err != 0)
Packit Service a2ae7a
    return err;
Packit Service a2ae7a
  lock->initialized = 1;
Packit Service a2ae7a
  return 0;
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
int
Packit Service a2ae7a
glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock)
Packit Service a2ae7a
{
Packit Service a2ae7a
  if (!lock->initialized)
Packit Service a2ae7a
    {
Packit Service a2ae7a
      int err;
Packit Service a2ae7a
Packit Service a2ae7a
      err = pthread_mutex_lock (&lock->guard);
Packit Service a2ae7a
      if (err != 0)
Packit Service a2ae7a
        return err;
Packit Service a2ae7a
      if (!lock->initialized)
Packit Service a2ae7a
        {
Packit Service a2ae7a
          err = glthread_recursive_lock_init_multithreaded (lock);
Packit Service a2ae7a
          if (err != 0)
Packit Service a2ae7a
            {
Packit Service a2ae7a
              pthread_mutex_unlock (&lock->guard);
Packit Service a2ae7a
              return err;
Packit Service a2ae7a
            }
Packit Service a2ae7a
        }
Packit Service a2ae7a
      err = pthread_mutex_unlock (&lock->guard);
Packit Service a2ae7a
      if (err != 0)
Packit Service a2ae7a
        return err;
Packit Service a2ae7a
    }
Packit Service a2ae7a
  return pthread_mutex_lock (&lock->recmutex);
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
int
Packit Service a2ae7a
glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock)
Packit Service a2ae7a
{
Packit Service a2ae7a
  if (!lock->initialized)
Packit Service a2ae7a
    return EINVAL;
Packit Service a2ae7a
  return pthread_mutex_unlock (&lock->recmutex);
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
int
Packit Service a2ae7a
glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock)
Packit Service a2ae7a
{
Packit Service a2ae7a
  int err;
Packit Service a2ae7a
Packit Service a2ae7a
  if (!lock->initialized)
Packit Service a2ae7a
    return EINVAL;
Packit Service a2ae7a
  err = pthread_mutex_destroy (&lock->recmutex);
Packit Service a2ae7a
  if (err != 0)
Packit Service a2ae7a
    return err;
Packit Service a2ae7a
  lock->initialized = 0;
Packit Service a2ae7a
  return 0;
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
#  endif
Packit Service a2ae7a
Packit Service a2ae7a
# else
Packit Service a2ae7a
Packit Service a2ae7a
int
Packit Service a2ae7a
glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock)
Packit Service a2ae7a
{
Packit Service a2ae7a
  int err;
Packit Service a2ae7a
Packit Service a2ae7a
  err = pthread_mutex_init (&lock->mutex, NULL);
Packit Service a2ae7a
  if (err != 0)
Packit Service a2ae7a
    return err;
Packit Service a2ae7a
  lock->owner = (pthread_t) 0;
Packit Service a2ae7a
  lock->depth = 0;
Packit Service a2ae7a
  return 0;
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
int
Packit Service a2ae7a
glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock)
Packit Service a2ae7a
{
Packit Service a2ae7a
  pthread_t self = pthread_self ();
Packit Service a2ae7a
  if (lock->owner != self)
Packit Service a2ae7a
    {
Packit Service a2ae7a
      int err;
Packit Service a2ae7a
Packit Service a2ae7a
      err = pthread_mutex_lock (&lock->mutex);
Packit Service a2ae7a
      if (err != 0)
Packit Service a2ae7a
        return err;
Packit Service a2ae7a
      lock->owner = self;
Packit Service a2ae7a
    }
Packit Service a2ae7a
  if (++(lock->depth) == 0) /* wraparound? */
Packit Service a2ae7a
    {
Packit Service a2ae7a
      lock->depth--;
Packit Service a2ae7a
      return EAGAIN;
Packit Service a2ae7a
    }
Packit Service a2ae7a
  return 0;
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
int
Packit Service a2ae7a
glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock)
Packit Service a2ae7a
{
Packit Service a2ae7a
  if (lock->owner != pthread_self ())
Packit Service a2ae7a
    return EPERM;
Packit Service a2ae7a
  if (lock->depth == 0)
Packit Service a2ae7a
    return EINVAL;
Packit Service a2ae7a
  if (--(lock->depth) == 0)
Packit Service a2ae7a
    {
Packit Service a2ae7a
      lock->owner = (pthread_t) 0;
Packit Service a2ae7a
      return pthread_mutex_unlock (&lock->mutex);
Packit Service a2ae7a
    }
Packit Service a2ae7a
  else
Packit Service a2ae7a
    return 0;
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
int
Packit Service a2ae7a
glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock)
Packit Service a2ae7a
{
Packit Service a2ae7a
  if (lock->owner != (pthread_t) 0)
Packit Service a2ae7a
    return EBUSY;
Packit Service a2ae7a
  return pthread_mutex_destroy (&lock->mutex);
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
# endif
Packit Service a2ae7a
Packit Service a2ae7a
/* -------------------------- gl_once_t datatype -------------------------- */
Packit Service a2ae7a
Packit Service a2ae7a
static const pthread_once_t fresh_once = PTHREAD_ONCE_INIT;
Packit Service a2ae7a
Packit Service a2ae7a
int
Packit Service a2ae7a
glthread_once_singlethreaded (pthread_once_t *once_control)
Packit Service a2ae7a
{
Packit Service a2ae7a
  /* We don't know whether pthread_once_t is an integer type, a floating-point
Packit Service a2ae7a
     type, a pointer type, or a structure type.  */
Packit Service a2ae7a
  char *firstbyte = (char *)once_control;
Packit Service a2ae7a
  if (*firstbyte == *(const char *)&fresh_once)
Packit Service a2ae7a
    {
Packit Service a2ae7a
      /* First time use of once_control.  Invert the first byte.  */
Packit Service a2ae7a
      *firstbyte = ~ *(const char *)&fresh_once;
Packit Service a2ae7a
      return 1;
Packit Service a2ae7a
    }
Packit Service a2ae7a
  else
Packit Service a2ae7a
    return 0;
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
#endif
Packit Service a2ae7a
Packit Service a2ae7a
/* ========================================================================= */
Packit Service a2ae7a
Packit Service a2ae7a
#if USE_PTH_THREADS
Packit Service a2ae7a
Packit Service a2ae7a
/* Use the GNU Pth threads library.  */
Packit Service a2ae7a
Packit Service a2ae7a
/* -------------------------- gl_lock_t datatype -------------------------- */
Packit Service a2ae7a
Packit Service a2ae7a
/* ------------------------- gl_rwlock_t datatype ------------------------- */
Packit Service a2ae7a
Packit Service a2ae7a
# if !HAVE_PTH_RWLOCK_ACQUIRE_PREFER_WRITER
Packit Service a2ae7a
Packit Service a2ae7a
int
Packit Service a2ae7a
glthread_rwlock_init_multithreaded (gl_rwlock_t *lock)
Packit Service a2ae7a
{
Packit Service a2ae7a
  if (!pth_mutex_init (&lock->lock))
Packit Service a2ae7a
    return errno;
Packit Service a2ae7a
  if (!pth_cond_init (&lock->waiting_readers))
Packit Service a2ae7a
    return errno;
Packit Service a2ae7a
  if (!pth_cond_init (&lock->waiting_writers))
Packit Service a2ae7a
    return errno;
Packit Service a2ae7a
  lock->waiting_writers_count = 0;
Packit Service a2ae7a
  lock->runcount = 0;
Packit Service a2ae7a
  lock->initialized = 1;
Packit Service a2ae7a
  return 0;
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
int
Packit Service a2ae7a
glthread_rwlock_rdlock_multithreaded (gl_rwlock_t *lock)
Packit Service a2ae7a
{
Packit Service a2ae7a
  if (!lock->initialized)
Packit Service a2ae7a
    glthread_rwlock_init_multithreaded (lock);
Packit Service a2ae7a
  if (!pth_mutex_acquire (&lock->lock, 0, NULL))
Packit Service a2ae7a
    return errno;
Packit Service a2ae7a
  /* Test whether only readers are currently running, and whether the runcount
Packit Service a2ae7a
     field will not overflow, and whether no writer is waiting.  The latter
Packit Service a2ae7a
     condition is because POSIX recommends that "write locks shall take
Packit Service a2ae7a
     precedence over read locks", to avoid "writer starvation".  */
Packit Service a2ae7a
  while (!(lock->runcount + 1 > 0 && lock->waiting_writers_count == 0))
Packit Service a2ae7a
    {
Packit Service a2ae7a
      /* This thread has to wait for a while.  Enqueue it among the
Packit Service a2ae7a
         waiting_readers.  */
Packit Service a2ae7a
      if (!pth_cond_await (&lock->waiting_readers, &lock->lock, NULL))
Packit Service a2ae7a
        {
Packit Service a2ae7a
          int err = errno;
Packit Service a2ae7a
          pth_mutex_release (&lock->lock);
Packit Service a2ae7a
          return err;
Packit Service a2ae7a
        }
Packit Service a2ae7a
    }
Packit Service a2ae7a
  lock->runcount++;
Packit Service a2ae7a
  return (!pth_mutex_release (&lock->lock) ? errno : 0);
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
int
Packit Service a2ae7a
glthread_rwlock_wrlock_multithreaded (gl_rwlock_t *lock)
Packit Service a2ae7a
{
Packit Service a2ae7a
  if (!lock->initialized)
Packit Service a2ae7a
    glthread_rwlock_init_multithreaded (lock);
Packit Service a2ae7a
  if (!pth_mutex_acquire (&lock->lock, 0, NULL))
Packit Service a2ae7a
    return errno;
Packit Service a2ae7a
  /* Test whether no readers or writers are currently running.  */
Packit Service a2ae7a
  while (!(lock->runcount == 0))
Packit Service a2ae7a
    {
Packit Service a2ae7a
      /* This thread has to wait for a while.  Enqueue it among the
Packit Service a2ae7a
         waiting_writers.  */
Packit Service a2ae7a
      lock->waiting_writers_count++;
Packit Service a2ae7a
      if (!pth_cond_await (&lock->waiting_writers, &lock->lock, NULL))
Packit Service a2ae7a
        {
Packit Service a2ae7a
          int err = errno;
Packit Service a2ae7a
          lock->waiting_writers_count--;
Packit Service a2ae7a
          pth_mutex_release (&lock->lock);
Packit Service a2ae7a
          return err;
Packit Service a2ae7a
        }
Packit Service a2ae7a
      lock->waiting_writers_count--;
Packit Service a2ae7a
    }
Packit Service a2ae7a
  lock->runcount--; /* runcount becomes -1 */
Packit Service a2ae7a
  return (!pth_mutex_release (&lock->lock) ? errno : 0);
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
int
Packit Service a2ae7a
glthread_rwlock_unlock_multithreaded (gl_rwlock_t *lock)
Packit Service a2ae7a
{
Packit Service a2ae7a
  int err;
Packit Service a2ae7a
Packit Service a2ae7a
  if (!lock->initialized)
Packit Service a2ae7a
    return EINVAL;
Packit Service a2ae7a
  if (!pth_mutex_acquire (&lock->lock, 0, NULL))
Packit Service a2ae7a
    return errno;
Packit Service a2ae7a
  if (lock->runcount < 0)
Packit Service a2ae7a
    {
Packit Service a2ae7a
      /* Drop a writer lock.  */
Packit Service a2ae7a
      if (!(lock->runcount == -1))
Packit Service a2ae7a
        {
Packit Service a2ae7a
          pth_mutex_release (&lock->lock);
Packit Service a2ae7a
          return EINVAL;
Packit Service a2ae7a
        }
Packit Service a2ae7a
      lock->runcount = 0;
Packit Service a2ae7a
    }
Packit Service a2ae7a
  else
Packit Service a2ae7a
    {
Packit Service a2ae7a
      /* Drop a reader lock.  */
Packit Service a2ae7a
      if (!(lock->runcount > 0))
Packit Service a2ae7a
        {
Packit Service a2ae7a
          pth_mutex_release (&lock->lock);
Packit Service a2ae7a
          return EINVAL;
Packit Service a2ae7a
        }
Packit Service a2ae7a
      lock->runcount--;
Packit Service a2ae7a
    }
Packit Service a2ae7a
  if (lock->runcount == 0)
Packit Service a2ae7a
    {
Packit Service a2ae7a
      /* POSIX recommends that "write locks shall take precedence over read
Packit Service a2ae7a
         locks", to avoid "writer starvation".  */
Packit Service a2ae7a
      if (lock->waiting_writers_count > 0)
Packit Service a2ae7a
        {
Packit Service a2ae7a
          /* Wake up one of the waiting writers.  */
Packit Service a2ae7a
          if (!pth_cond_notify (&lock->waiting_writers, FALSE))
Packit Service a2ae7a
            {
Packit Service a2ae7a
              int err = errno;
Packit Service a2ae7a
              pth_mutex_release (&lock->lock);
Packit Service a2ae7a
              return err;
Packit Service a2ae7a
            }
Packit Service a2ae7a
        }
Packit Service a2ae7a
      else
Packit Service a2ae7a
        {
Packit Service a2ae7a
          /* Wake up all waiting readers.  */
Packit Service a2ae7a
          if (!pth_cond_notify (&lock->waiting_readers, TRUE))
Packit Service a2ae7a
            {
Packit Service a2ae7a
              int err = errno;
Packit Service a2ae7a
              pth_mutex_release (&lock->lock);
Packit Service a2ae7a
              return err;
Packit Service a2ae7a
            }
Packit Service a2ae7a
        }
Packit Service a2ae7a
    }
Packit Service a2ae7a
  return (!pth_mutex_release (&lock->lock) ? errno : 0);
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
int
Packit Service a2ae7a
glthread_rwlock_destroy_multithreaded (gl_rwlock_t *lock)
Packit Service a2ae7a
{
Packit Service a2ae7a
  lock->initialized = 0;
Packit Service a2ae7a
  return 0;
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
# endif
Packit Service a2ae7a
Packit Service a2ae7a
/* --------------------- gl_recursive_lock_t datatype --------------------- */
Packit Service a2ae7a
Packit Service a2ae7a
/* -------------------------- gl_once_t datatype -------------------------- */
Packit Service a2ae7a
Packit Service a2ae7a
static void
Packit Service a2ae7a
glthread_once_call (void *arg)
Packit Service a2ae7a
{
Packit Service a2ae7a
  void (**gl_once_temp_addr) (void) = (void (**) (void)) arg;
Packit Service a2ae7a
  void (*initfunction) (void) = *gl_once_temp_addr;
Packit Service a2ae7a
  initfunction ();
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
int
Packit Service a2ae7a
glthread_once_multithreaded (pth_once_t *once_control, void (*initfunction) (void))
Packit Service a2ae7a
{
Packit Service a2ae7a
  void (*temp) (void) = initfunction;
Packit Service a2ae7a
  return (!pth_once (once_control, glthread_once_call, &temp) ? errno : 0);
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
int
Packit Service a2ae7a
glthread_once_singlethreaded (pth_once_t *once_control)
Packit Service a2ae7a
{
Packit Service a2ae7a
  /* We know that pth_once_t is an integer type.  */
Packit Service a2ae7a
  if (*once_control == PTH_ONCE_INIT)
Packit Service a2ae7a
    {
Packit Service a2ae7a
      /* First time use of once_control.  Invert the marker.  */
Packit Service a2ae7a
      *once_control = ~ PTH_ONCE_INIT;
Packit Service a2ae7a
      return 1;
Packit Service a2ae7a
    }
Packit Service a2ae7a
  else
Packit Service a2ae7a
    return 0;
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
#endif
Packit Service a2ae7a
Packit Service a2ae7a
/* ========================================================================= */
Packit Service a2ae7a
Packit Service a2ae7a
#if USE_SOLARIS_THREADS
Packit Service a2ae7a
Packit Service a2ae7a
/* Use the old Solaris threads library.  */
Packit Service a2ae7a
Packit Service a2ae7a
/* -------------------------- gl_lock_t datatype -------------------------- */
Packit Service a2ae7a
Packit Service a2ae7a
/* ------------------------- gl_rwlock_t datatype ------------------------- */
Packit Service a2ae7a
Packit Service a2ae7a
/* --------------------- gl_recursive_lock_t datatype --------------------- */
Packit Service a2ae7a
Packit Service a2ae7a
int
Packit Service a2ae7a
glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock)
Packit Service a2ae7a
{
Packit Service a2ae7a
  int err;
Packit Service a2ae7a
Packit Service a2ae7a
  err = mutex_init (&lock->mutex, USYNC_THREAD, NULL);
Packit Service a2ae7a
  if (err != 0)
Packit Service a2ae7a
    return err;
Packit Service a2ae7a
  lock->owner = (thread_t) 0;
Packit Service a2ae7a
  lock->depth = 0;
Packit Service a2ae7a
  return 0;
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
int
Packit Service a2ae7a
glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock)
Packit Service a2ae7a
{
Packit Service a2ae7a
  thread_t self = thr_self ();
Packit Service a2ae7a
  if (lock->owner != self)
Packit Service a2ae7a
    {
Packit Service a2ae7a
      int err;
Packit Service a2ae7a
Packit Service a2ae7a
      err = mutex_lock (&lock->mutex);
Packit Service a2ae7a
      if (err != 0)
Packit Service a2ae7a
        return err;
Packit Service a2ae7a
      lock->owner = self;
Packit Service a2ae7a
    }
Packit Service a2ae7a
  if (++(lock->depth) == 0) /* wraparound? */
Packit Service a2ae7a
    {
Packit Service a2ae7a
      lock->depth--;
Packit Service a2ae7a
      return EAGAIN;
Packit Service a2ae7a
    }
Packit Service a2ae7a
  return 0;
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
int
Packit Service a2ae7a
glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock)
Packit Service a2ae7a
{
Packit Service a2ae7a
  if (lock->owner != thr_self ())
Packit Service a2ae7a
    return EPERM;
Packit Service a2ae7a
  if (lock->depth == 0)
Packit Service a2ae7a
    return EINVAL;
Packit Service a2ae7a
  if (--(lock->depth) == 0)
Packit Service a2ae7a
    {
Packit Service a2ae7a
      lock->owner = (thread_t) 0;
Packit Service a2ae7a
      return mutex_unlock (&lock->mutex);
Packit Service a2ae7a
    }
Packit Service a2ae7a
  else
Packit Service a2ae7a
    return 0;
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
int
Packit Service a2ae7a
glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock)
Packit Service a2ae7a
{
Packit Service a2ae7a
  if (lock->owner != (thread_t) 0)
Packit Service a2ae7a
    return EBUSY;
Packit Service a2ae7a
  return mutex_destroy (&lock->mutex);
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
/* -------------------------- gl_once_t datatype -------------------------- */
Packit Service a2ae7a
Packit Service a2ae7a
int
Packit Service a2ae7a
glthread_once_multithreaded (gl_once_t *once_control, void (*initfunction) (void))
Packit Service a2ae7a
{
Packit Service a2ae7a
  if (!once_control->inited)
Packit Service a2ae7a
    {
Packit Service a2ae7a
      int err;
Packit Service a2ae7a
Packit Service a2ae7a
      /* Use the mutex to guarantee that if another thread is already calling
Packit Service a2ae7a
         the initfunction, this thread waits until it's finished.  */
Packit Service a2ae7a
      err = mutex_lock (&once_control->mutex);
Packit Service a2ae7a
      if (err != 0)
Packit Service a2ae7a
        return err;
Packit Service a2ae7a
      if (!once_control->inited)
Packit Service a2ae7a
        {
Packit Service a2ae7a
          once_control->inited = 1;
Packit Service a2ae7a
          initfunction ();
Packit Service a2ae7a
        }
Packit Service a2ae7a
      return mutex_unlock (&once_control->mutex);
Packit Service a2ae7a
    }
Packit Service a2ae7a
  else
Packit Service a2ae7a
    return 0;
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
int
Packit Service a2ae7a
glthread_once_singlethreaded (gl_once_t *once_control)
Packit Service a2ae7a
{
Packit Service a2ae7a
  /* We know that gl_once_t contains an integer type.  */
Packit Service a2ae7a
  if (!once_control->inited)
Packit Service a2ae7a
    {
Packit Service a2ae7a
      /* First time use of once_control.  Invert the marker.  */
Packit Service a2ae7a
      once_control->inited = ~ 0;
Packit Service a2ae7a
      return 1;
Packit Service a2ae7a
    }
Packit Service a2ae7a
  else
Packit Service a2ae7a
    return 0;
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
#endif
Packit Service a2ae7a
Packit Service a2ae7a
/* ========================================================================= */
Packit Service a2ae7a
Packit Service a2ae7a
#if USE_WINDOWS_THREADS
Packit Service a2ae7a
Packit Service a2ae7a
/* -------------------------- gl_lock_t datatype -------------------------- */
Packit Service a2ae7a
Packit Service a2ae7a
void
Packit Service a2ae7a
glthread_lock_init_func (gl_lock_t *lock)
Packit Service a2ae7a
{
Packit Service a2ae7a
  InitializeCriticalSection (&lock->lock);
Packit Service a2ae7a
  lock->guard.done = 1;
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
int
Packit Service a2ae7a
glthread_lock_lock_func (gl_lock_t *lock)
Packit Service a2ae7a
{
Packit Service a2ae7a
  if (!lock->guard.done)
Packit Service a2ae7a
    {
Packit Service a2ae7a
      if (InterlockedIncrement (&lock->guard.started) == 0)
Packit Service a2ae7a
        /* This thread is the first one to need this lock.  Initialize it.  */
Packit Service a2ae7a
        glthread_lock_init (lock);
Packit Service a2ae7a
      else
Packit Service a2ae7a
        /* Yield the CPU while waiting for another thread to finish
Packit Service a2ae7a
           initializing this lock.  */
Packit Service a2ae7a
        while (!lock->guard.done)
Packit Service a2ae7a
          Sleep (0);
Packit Service a2ae7a
    }
Packit Service a2ae7a
  EnterCriticalSection (&lock->lock);
Packit Service a2ae7a
  return 0;
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
int
Packit Service a2ae7a
glthread_lock_unlock_func (gl_lock_t *lock)
Packit Service a2ae7a
{
Packit Service a2ae7a
  if (!lock->guard.done)
Packit Service a2ae7a
    return EINVAL;
Packit Service a2ae7a
  LeaveCriticalSection (&lock->lock);
Packit Service a2ae7a
  return 0;
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
int
Packit Service a2ae7a
glthread_lock_destroy_func (gl_lock_t *lock)
Packit Service a2ae7a
{
Packit Service a2ae7a
  if (!lock->guard.done)
Packit Service a2ae7a
    return EINVAL;
Packit Service a2ae7a
  DeleteCriticalSection (&lock->lock);
Packit Service a2ae7a
  lock->guard.done = 0;
Packit Service a2ae7a
  return 0;
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
/* ------------------------- gl_rwlock_t datatype ------------------------- */
Packit Service a2ae7a
Packit Service a2ae7a
/* In this file, the waitqueues are implemented as circular arrays.  */
Packit Service a2ae7a
#define gl_waitqueue_t gl_carray_waitqueue_t
Packit Service a2ae7a
Packit Service a2ae7a
static void
Packit Service a2ae7a
gl_waitqueue_init (gl_waitqueue_t *wq)
Packit Service a2ae7a
{
Packit Service a2ae7a
  wq->array = NULL;
Packit Service a2ae7a
  wq->count = 0;
Packit Service a2ae7a
  wq->alloc = 0;
Packit Service a2ae7a
  wq->offset = 0;
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
/* Enqueues the current thread, represented by an event, in a wait queue.
Packit Service a2ae7a
   Returns INVALID_HANDLE_VALUE if an allocation failure occurs.  */
Packit Service a2ae7a
static HANDLE
Packit Service a2ae7a
gl_waitqueue_add (gl_waitqueue_t *wq)
Packit Service a2ae7a
{
Packit Service a2ae7a
  HANDLE event;
Packit Service a2ae7a
  unsigned int index;
Packit Service a2ae7a
Packit Service a2ae7a
  if (wq->count == wq->alloc)
Packit Service a2ae7a
    {
Packit Service a2ae7a
      unsigned int new_alloc = 2 * wq->alloc + 1;
Packit Service a2ae7a
      HANDLE *new_array =
Packit Service a2ae7a
        (HANDLE *) realloc (wq->array, new_alloc * sizeof (HANDLE));
Packit Service a2ae7a
      if (new_array == NULL)
Packit Service a2ae7a
        /* No more memory.  */
Packit Service a2ae7a
        return INVALID_HANDLE_VALUE;
Packit Service a2ae7a
      /* Now is a good opportunity to rotate the array so that its contents
Packit Service a2ae7a
         starts at offset 0.  */
Packit Service a2ae7a
      if (wq->offset > 0)
Packit Service a2ae7a
        {
Packit Service a2ae7a
          unsigned int old_count = wq->count;
Packit Service a2ae7a
          unsigned int old_alloc = wq->alloc;
Packit Service a2ae7a
          unsigned int old_offset = wq->offset;
Packit Service a2ae7a
          unsigned int i;
Packit Service a2ae7a
          if (old_offset + old_count > old_alloc)
Packit Service a2ae7a
            {
Packit Service a2ae7a
              unsigned int limit = old_offset + old_count - old_alloc;
Packit Service a2ae7a
              for (i = 0; i < limit; i++)
Packit Service a2ae7a
                new_array[old_alloc + i] = new_array[i];
Packit Service a2ae7a
            }
Packit Service a2ae7a
          for (i = 0; i < old_count; i++)
Packit Service a2ae7a
            new_array[i] = new_array[old_offset + i];
Packit Service a2ae7a
          wq->offset = 0;
Packit Service a2ae7a
        }
Packit Service a2ae7a
      wq->array = new_array;
Packit Service a2ae7a
      wq->alloc = new_alloc;
Packit Service a2ae7a
    }
Packit Service a2ae7a
  /* Whether the created event is a manual-reset one or an auto-reset one,
Packit Service a2ae7a
     does not matter, since we will wait on it only once.  */
Packit Service a2ae7a
  event = CreateEvent (NULL, TRUE, FALSE, NULL);
Packit Service a2ae7a
  if (event == INVALID_HANDLE_VALUE)
Packit Service a2ae7a
    /* No way to allocate an event.  */
Packit Service a2ae7a
    return INVALID_HANDLE_VALUE;
Packit Service a2ae7a
  index = wq->offset + wq->count;
Packit Service a2ae7a
  if (index >= wq->alloc)
Packit Service a2ae7a
    index -= wq->alloc;
Packit Service a2ae7a
  wq->array[index] = event;
Packit Service a2ae7a
  wq->count++;
Packit Service a2ae7a
  return event;
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
/* Notifies the first thread from a wait queue and dequeues it.  */
Packit Service a2ae7a
static void
Packit Service a2ae7a
gl_waitqueue_notify_first (gl_waitqueue_t *wq)
Packit Service a2ae7a
{
Packit Service a2ae7a
  SetEvent (wq->array[wq->offset + 0]);
Packit Service a2ae7a
  wq->offset++;
Packit Service a2ae7a
  wq->count--;
Packit Service a2ae7a
  if (wq->count == 0 || wq->offset == wq->alloc)
Packit Service a2ae7a
    wq->offset = 0;
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
/* Notifies all threads from a wait queue and dequeues them all.  */
Packit Service a2ae7a
static void
Packit Service a2ae7a
gl_waitqueue_notify_all (gl_waitqueue_t *wq)
Packit Service a2ae7a
{
Packit Service a2ae7a
  unsigned int i;
Packit Service a2ae7a
Packit Service a2ae7a
  for (i = 0; i < wq->count; i++)
Packit Service a2ae7a
    {
Packit Service a2ae7a
      unsigned int index = wq->offset + i;
Packit Service a2ae7a
      if (index >= wq->alloc)
Packit Service a2ae7a
        index -= wq->alloc;
Packit Service a2ae7a
      SetEvent (wq->array[index]);
Packit Service a2ae7a
    }
Packit Service a2ae7a
  wq->count = 0;
Packit Service a2ae7a
  wq->offset = 0;
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
void
Packit Service a2ae7a
glthread_rwlock_init_func (gl_rwlock_t *lock)
Packit Service a2ae7a
{
Packit Service a2ae7a
  InitializeCriticalSection (&lock->lock);
Packit Service a2ae7a
  gl_waitqueue_init (&lock->waiting_readers);
Packit Service a2ae7a
  gl_waitqueue_init (&lock->waiting_writers);
Packit Service a2ae7a
  lock->runcount = 0;
Packit Service a2ae7a
  lock->guard.done = 1;
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
int
Packit Service a2ae7a
glthread_rwlock_rdlock_func (gl_rwlock_t *lock)
Packit Service a2ae7a
{
Packit Service a2ae7a
  if (!lock->guard.done)
Packit Service a2ae7a
    {
Packit Service a2ae7a
      if (InterlockedIncrement (&lock->guard.started) == 0)
Packit Service a2ae7a
        /* This thread is the first one to need this lock.  Initialize it.  */
Packit Service a2ae7a
        glthread_rwlock_init (lock);
Packit Service a2ae7a
      else
Packit Service a2ae7a
        /* Yield the CPU while waiting for another thread to finish
Packit Service a2ae7a
           initializing this lock.  */
Packit Service a2ae7a
        while (!lock->guard.done)
Packit Service a2ae7a
          Sleep (0);
Packit Service a2ae7a
    }
Packit Service a2ae7a
  EnterCriticalSection (&lock->lock);
Packit Service a2ae7a
  /* Test whether only readers are currently running, and whether the runcount
Packit Service a2ae7a
     field will not overflow, and whether no writer is waiting.  The latter
Packit Service a2ae7a
     condition is because POSIX recommends that "write locks shall take
Packit Service a2ae7a
     precedence over read locks", to avoid "writer starvation".  */
Packit Service a2ae7a
  if (!(lock->runcount + 1 > 0 && lock->waiting_writers.count == 0))
Packit Service a2ae7a
    {
Packit Service a2ae7a
      /* This thread has to wait for a while.  Enqueue it among the
Packit Service a2ae7a
         waiting_readers.  */
Packit Service a2ae7a
      HANDLE event = gl_waitqueue_add (&lock->waiting_readers);
Packit Service a2ae7a
      if (event != INVALID_HANDLE_VALUE)
Packit Service a2ae7a
        {
Packit Service a2ae7a
          DWORD result;
Packit Service a2ae7a
          LeaveCriticalSection (&lock->lock);
Packit Service a2ae7a
          /* Wait until another thread signals this event.  */
Packit Service a2ae7a
          result = WaitForSingleObject (event, INFINITE);
Packit Service a2ae7a
          if (result == WAIT_FAILED || result == WAIT_TIMEOUT)
Packit Service a2ae7a
            abort ();
Packit Service a2ae7a
          CloseHandle (event);
Packit Service a2ae7a
          /* The thread which signalled the event already did the bookkeeping:
Packit Service a2ae7a
             removed us from the waiting_readers, incremented lock->runcount.  */
Packit Service a2ae7a
          if (!(lock->runcount > 0))
Packit Service a2ae7a
            abort ();
Packit Service a2ae7a
          return 0;
Packit Service a2ae7a
        }
Packit Service a2ae7a
      else
Packit Service a2ae7a
        {
Packit Service a2ae7a
          /* Allocation failure.  Weird.  */
Packit Service a2ae7a
          do
Packit Service a2ae7a
            {
Packit Service a2ae7a
              LeaveCriticalSection (&lock->lock);
Packit Service a2ae7a
              Sleep (1);
Packit Service a2ae7a
              EnterCriticalSection (&lock->lock);
Packit Service a2ae7a
            }
Packit Service a2ae7a
          while (!(lock->runcount + 1 > 0));
Packit Service a2ae7a
        }
Packit Service a2ae7a
    }
Packit Service a2ae7a
  lock->runcount++;
Packit Service a2ae7a
  LeaveCriticalSection (&lock->lock);
Packit Service a2ae7a
  return 0;
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
int
Packit Service a2ae7a
glthread_rwlock_wrlock_func (gl_rwlock_t *lock)
Packit Service a2ae7a
{
Packit Service a2ae7a
  if (!lock->guard.done)
Packit Service a2ae7a
    {
Packit Service a2ae7a
      if (InterlockedIncrement (&lock->guard.started) == 0)
Packit Service a2ae7a
        /* This thread is the first one to need this lock.  Initialize it.  */
Packit Service a2ae7a
        glthread_rwlock_init (lock);
Packit Service a2ae7a
      else
Packit Service a2ae7a
        /* Yield the CPU while waiting for another thread to finish
Packit Service a2ae7a
           initializing this lock.  */
Packit Service a2ae7a
        while (!lock->guard.done)
Packit Service a2ae7a
          Sleep (0);
Packit Service a2ae7a
    }
Packit Service a2ae7a
  EnterCriticalSection (&lock->lock);
Packit Service a2ae7a
  /* Test whether no readers or writers are currently running.  */
Packit Service a2ae7a
  if (!(lock->runcount == 0))
Packit Service a2ae7a
    {
Packit Service a2ae7a
      /* This thread has to wait for a while.  Enqueue it among the
Packit Service a2ae7a
         waiting_writers.  */
Packit Service a2ae7a
      HANDLE event = gl_waitqueue_add (&lock->waiting_writers);
Packit Service a2ae7a
      if (event != INVALID_HANDLE_VALUE)
Packit Service a2ae7a
        {
Packit Service a2ae7a
          DWORD result;
Packit Service a2ae7a
          LeaveCriticalSection (&lock->lock);
Packit Service a2ae7a
          /* Wait until another thread signals this event.  */
Packit Service a2ae7a
          result = WaitForSingleObject (event, INFINITE);
Packit Service a2ae7a
          if (result == WAIT_FAILED || result == WAIT_TIMEOUT)
Packit Service a2ae7a
            abort ();
Packit Service a2ae7a
          CloseHandle (event);
Packit Service a2ae7a
          /* The thread which signalled the event already did the bookkeeping:
Packit Service a2ae7a
             removed us from the waiting_writers, set lock->runcount = -1.  */
Packit Service a2ae7a
          if (!(lock->runcount == -1))
Packit Service a2ae7a
            abort ();
Packit Service a2ae7a
          return 0;
Packit Service a2ae7a
        }
Packit Service a2ae7a
      else
Packit Service a2ae7a
        {
Packit Service a2ae7a
          /* Allocation failure.  Weird.  */
Packit Service a2ae7a
          do
Packit Service a2ae7a
            {
Packit Service a2ae7a
              LeaveCriticalSection (&lock->lock);
Packit Service a2ae7a
              Sleep (1);
Packit Service a2ae7a
              EnterCriticalSection (&lock->lock);
Packit Service a2ae7a
            }
Packit Service a2ae7a
          while (!(lock->runcount == 0));
Packit Service a2ae7a
        }
Packit Service a2ae7a
    }
Packit Service a2ae7a
  lock->runcount--; /* runcount becomes -1 */
Packit Service a2ae7a
  LeaveCriticalSection (&lock->lock);
Packit Service a2ae7a
  return 0;
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
int
Packit Service a2ae7a
glthread_rwlock_unlock_func (gl_rwlock_t *lock)
Packit Service a2ae7a
{
Packit Service a2ae7a
  if (!lock->guard.done)
Packit Service a2ae7a
    return EINVAL;
Packit Service a2ae7a
  EnterCriticalSection (&lock->lock);
Packit Service a2ae7a
  if (lock->runcount < 0)
Packit Service a2ae7a
    {
Packit Service a2ae7a
      /* Drop a writer lock.  */
Packit Service a2ae7a
      if (!(lock->runcount == -1))
Packit Service a2ae7a
        abort ();
Packit Service a2ae7a
      lock->runcount = 0;
Packit Service a2ae7a
    }
Packit Service a2ae7a
  else
Packit Service a2ae7a
    {
Packit Service a2ae7a
      /* Drop a reader lock.  */
Packit Service a2ae7a
      if (!(lock->runcount > 0))
Packit Service a2ae7a
        {
Packit Service a2ae7a
          LeaveCriticalSection (&lock->lock);
Packit Service a2ae7a
          return EPERM;
Packit Service a2ae7a
        }
Packit Service a2ae7a
      lock->runcount--;
Packit Service a2ae7a
    }
Packit Service a2ae7a
  if (lock->runcount == 0)
Packit Service a2ae7a
    {
Packit Service a2ae7a
      /* POSIX recommends that "write locks shall take precedence over read
Packit Service a2ae7a
         locks", to avoid "writer starvation".  */
Packit Service a2ae7a
      if (lock->waiting_writers.count > 0)
Packit Service a2ae7a
        {
Packit Service a2ae7a
          /* Wake up one of the waiting writers.  */
Packit Service a2ae7a
          lock->runcount--;
Packit Service a2ae7a
          gl_waitqueue_notify_first (&lock->waiting_writers);
Packit Service a2ae7a
        }
Packit Service a2ae7a
      else
Packit Service a2ae7a
        {
Packit Service a2ae7a
          /* Wake up all waiting readers.  */
Packit Service a2ae7a
          lock->runcount += lock->waiting_readers.count;
Packit Service a2ae7a
          gl_waitqueue_notify_all (&lock->waiting_readers);
Packit Service a2ae7a
        }
Packit Service a2ae7a
    }
Packit Service a2ae7a
  LeaveCriticalSection (&lock->lock);
Packit Service a2ae7a
  return 0;
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
int
Packit Service a2ae7a
glthread_rwlock_destroy_func (gl_rwlock_t *lock)
Packit Service a2ae7a
{
Packit Service a2ae7a
  if (!lock->guard.done)
Packit Service a2ae7a
    return EINVAL;
Packit Service a2ae7a
  if (lock->runcount != 0)
Packit Service a2ae7a
    return EBUSY;
Packit Service a2ae7a
  DeleteCriticalSection (&lock->lock);
Packit Service a2ae7a
  if (lock->waiting_readers.array != NULL)
Packit Service a2ae7a
    free (lock->waiting_readers.array);
Packit Service a2ae7a
  if (lock->waiting_writers.array != NULL)
Packit Service a2ae7a
    free (lock->waiting_writers.array);
Packit Service a2ae7a
  lock->guard.done = 0;
Packit Service a2ae7a
  return 0;
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
/* --------------------- gl_recursive_lock_t datatype --------------------- */
Packit Service a2ae7a
Packit Service a2ae7a
void
Packit Service a2ae7a
glthread_recursive_lock_init_func (gl_recursive_lock_t *lock)
Packit Service a2ae7a
{
Packit Service a2ae7a
  lock->owner = 0;
Packit Service a2ae7a
  lock->depth = 0;
Packit Service a2ae7a
  InitializeCriticalSection (&lock->lock);
Packit Service a2ae7a
  lock->guard.done = 1;
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
int
Packit Service a2ae7a
glthread_recursive_lock_lock_func (gl_recursive_lock_t *lock)
Packit Service a2ae7a
{
Packit Service a2ae7a
  if (!lock->guard.done)
Packit Service a2ae7a
    {
Packit Service a2ae7a
      if (InterlockedIncrement (&lock->guard.started) == 0)
Packit Service a2ae7a
        /* This thread is the first one to need this lock.  Initialize it.  */
Packit Service a2ae7a
        glthread_recursive_lock_init (lock);
Packit Service a2ae7a
      else
Packit Service a2ae7a
        /* Yield the CPU while waiting for another thread to finish
Packit Service a2ae7a
           initializing this lock.  */
Packit Service a2ae7a
        while (!lock->guard.done)
Packit Service a2ae7a
          Sleep (0);
Packit Service a2ae7a
    }
Packit Service a2ae7a
  {
Packit Service a2ae7a
    DWORD self = GetCurrentThreadId ();
Packit Service a2ae7a
    if (lock->owner != self)
Packit Service a2ae7a
      {
Packit Service a2ae7a
        EnterCriticalSection (&lock->lock);
Packit Service a2ae7a
        lock->owner = self;
Packit Service a2ae7a
      }
Packit Service a2ae7a
    if (++(lock->depth) == 0) /* wraparound? */
Packit Service a2ae7a
      {
Packit Service a2ae7a
        lock->depth--;
Packit Service a2ae7a
        return EAGAIN;
Packit Service a2ae7a
      }
Packit Service a2ae7a
  }
Packit Service a2ae7a
  return 0;
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
int
Packit Service a2ae7a
glthread_recursive_lock_unlock_func (gl_recursive_lock_t *lock)
Packit Service a2ae7a
{
Packit Service a2ae7a
  if (lock->owner != GetCurrentThreadId ())
Packit Service a2ae7a
    return EPERM;
Packit Service a2ae7a
  if (lock->depth == 0)
Packit Service a2ae7a
    return EINVAL;
Packit Service a2ae7a
  if (--(lock->depth) == 0)
Packit Service a2ae7a
    {
Packit Service a2ae7a
      lock->owner = 0;
Packit Service a2ae7a
      LeaveCriticalSection (&lock->lock);
Packit Service a2ae7a
    }
Packit Service a2ae7a
  return 0;
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
int
Packit Service a2ae7a
glthread_recursive_lock_destroy_func (gl_recursive_lock_t *lock)
Packit Service a2ae7a
{
Packit Service a2ae7a
  if (lock->owner != 0)
Packit Service a2ae7a
    return EBUSY;
Packit Service a2ae7a
  DeleteCriticalSection (&lock->lock);
Packit Service a2ae7a
  lock->guard.done = 0;
Packit Service a2ae7a
  return 0;
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
/* -------------------------- gl_once_t datatype -------------------------- */
Packit Service a2ae7a
Packit Service a2ae7a
void
Packit Service a2ae7a
glthread_once_func (gl_once_t *once_control, void (*initfunction) (void))
Packit Service a2ae7a
{
Packit Service a2ae7a
  if (once_control->inited <= 0)
Packit Service a2ae7a
    {
Packit Service a2ae7a
      if (InterlockedIncrement (&once_control->started) == 0)
Packit Service a2ae7a
        {
Packit Service a2ae7a
          /* This thread is the first one to come to this once_control.  */
Packit Service a2ae7a
          InitializeCriticalSection (&once_control->lock);
Packit Service a2ae7a
          EnterCriticalSection (&once_control->lock);
Packit Service a2ae7a
          once_control->inited = 0;
Packit Service a2ae7a
          initfunction ();
Packit Service a2ae7a
          once_control->inited = 1;
Packit Service a2ae7a
          LeaveCriticalSection (&once_control->lock);
Packit Service a2ae7a
        }
Packit Service a2ae7a
      else
Packit Service a2ae7a
        {
Packit Service a2ae7a
          /* Undo last operation.  */
Packit Service a2ae7a
          InterlockedDecrement (&once_control->started);
Packit Service a2ae7a
          /* Some other thread has already started the initialization.
Packit Service a2ae7a
             Yield the CPU while waiting for the other thread to finish
Packit Service a2ae7a
             initializing and taking the lock.  */
Packit Service a2ae7a
          while (once_control->inited < 0)
Packit Service a2ae7a
            Sleep (0);
Packit Service a2ae7a
          if (once_control->inited <= 0)
Packit Service a2ae7a
            {
Packit Service a2ae7a
              /* Take the lock.  This blocks until the other thread has
Packit Service a2ae7a
                 finished calling the initfunction.  */
Packit Service a2ae7a
              EnterCriticalSection (&once_control->lock);
Packit Service a2ae7a
              LeaveCriticalSection (&once_control->lock);
Packit Service a2ae7a
              if (!(once_control->inited > 0))
Packit Service a2ae7a
                abort ();
Packit Service a2ae7a
            }
Packit Service a2ae7a
        }
Packit Service a2ae7a
    }
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
#endif
Packit Service a2ae7a
Packit Service a2ae7a
/* ========================================================================= */