Blame gnulib/lib/glthread/lock.c

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