Blame lib/glthread/lock.c

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