New upstream version 2.3.4
This commit is contained in:
		
							parent
							
								
									e7bdd1c6c6
								
							
						
					
					
						commit
						de72f6f588
					
				
					 556 changed files with 90432 additions and 53391 deletions
				
			
		| 
						 | 
				
			
			@ -1,22 +1,21 @@
 | 
			
		|||
/* Locking in multithreaded situations.
 | 
			
		||||
   Copyright (C) 2005-2013 Free Software Foundation, Inc.
 | 
			
		||||
   Copyright (C) 2005-2023 Free Software Foundation, Inc.
 | 
			
		||||
 | 
			
		||||
   This program is free software; you can redistribute it and/or modify
 | 
			
		||||
   it under the terms of the GNU General Public License as published by
 | 
			
		||||
   the Free Software Foundation; either version 3, or (at your option)
 | 
			
		||||
   any later version.
 | 
			
		||||
   This file is free software: you can redistribute it and/or modify
 | 
			
		||||
   it under the terms of the GNU Lesser General Public License as
 | 
			
		||||
   published by the Free Software Foundation; either version 2.1 of the
 | 
			
		||||
   License, or (at your option) any later version.
 | 
			
		||||
 | 
			
		||||
   This program is distributed in the hope that it will be useful,
 | 
			
		||||
   This file is distributed in the hope that it will be useful,
 | 
			
		||||
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
   GNU General Public License for more details.
 | 
			
		||||
   GNU Lesser General Public License for more details.
 | 
			
		||||
 | 
			
		||||
   You should have received a copy of the GNU General Public License
 | 
			
		||||
   along with this program; if not, see <http://www.gnu.org/licenses/>.  */
 | 
			
		||||
   You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 | 
			
		||||
 | 
			
		||||
/* Written by Bruno Haible <bruno@clisp.org>, 2005.
 | 
			
		||||
   Based on GCC's gthr-posix.h, gthr-posix95.h, gthr-solaris.h,
 | 
			
		||||
   gthr-win32.h.  */
 | 
			
		||||
   Based on GCC's gthr-posix.h, gthr-posix95.h.  */
 | 
			
		||||
 | 
			
		||||
#include <config.h>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -24,15 +23,267 @@
 | 
			
		|||
 | 
			
		||||
/* ========================================================================= */
 | 
			
		||||
 | 
			
		||||
#if USE_ISOC_THREADS || USE_ISOC_AND_POSIX_THREADS
 | 
			
		||||
 | 
			
		||||
/* -------------------------- gl_lock_t datatype -------------------------- */
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
glthread_lock_init (gl_lock_t *lock)
 | 
			
		||||
{
 | 
			
		||||
  if (mtx_init (&lock->mutex, mtx_plain) != thrd_success)
 | 
			
		||||
    return ENOMEM;
 | 
			
		||||
  lock->init_needed = 0;
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
glthread_lock_lock (gl_lock_t *lock)
 | 
			
		||||
{
 | 
			
		||||
  if (lock->init_needed)
 | 
			
		||||
    call_once (&lock->init_once, lock->init_func);
 | 
			
		||||
  if (mtx_lock (&lock->mutex) != thrd_success)
 | 
			
		||||
    return EAGAIN;
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
glthread_lock_unlock (gl_lock_t *lock)
 | 
			
		||||
{
 | 
			
		||||
  if (lock->init_needed)
 | 
			
		||||
    call_once (&lock->init_once, lock->init_func);
 | 
			
		||||
  if (mtx_unlock (&lock->mutex) != thrd_success)
 | 
			
		||||
    return EINVAL;
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
glthread_lock_destroy (gl_lock_t *lock)
 | 
			
		||||
{
 | 
			
		||||
  if (lock->init_needed)
 | 
			
		||||
    call_once (&lock->init_once, lock->init_func);
 | 
			
		||||
  mtx_destroy (&lock->mutex);
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* ------------------------- gl_rwlock_t datatype ------------------------- */
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
glthread_rwlock_init (gl_rwlock_t *lock)
 | 
			
		||||
{
 | 
			
		||||
  if (mtx_init (&lock->lock, mtx_plain) != thrd_success
 | 
			
		||||
      || cnd_init (&lock->waiting_readers) != thrd_success
 | 
			
		||||
      || cnd_init (&lock->waiting_writers) != thrd_success)
 | 
			
		||||
    return ENOMEM;
 | 
			
		||||
  lock->waiting_writers_count = 0;
 | 
			
		||||
  lock->runcount = 0;
 | 
			
		||||
  lock->init_needed = 0;
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
glthread_rwlock_rdlock (gl_rwlock_t *lock)
 | 
			
		||||
{
 | 
			
		||||
  if (lock->init_needed)
 | 
			
		||||
    call_once (&lock->init_once, lock->init_func);
 | 
			
		||||
  if (mtx_lock (&lock->lock) != thrd_success)
 | 
			
		||||
    return EAGAIN;
 | 
			
		||||
  /* Test whether only readers are currently running, and whether the runcount
 | 
			
		||||
     field will not overflow, and whether no writer is waiting.  The latter
 | 
			
		||||
     condition is because POSIX recommends that "write locks shall take
 | 
			
		||||
     precedence over read locks", to avoid "writer starvation".  */
 | 
			
		||||
  while (!(lock->runcount + 1 > 0 && lock->waiting_writers_count == 0))
 | 
			
		||||
    {
 | 
			
		||||
      /* This thread has to wait for a while.  Enqueue it among the
 | 
			
		||||
         waiting_readers.  */
 | 
			
		||||
      if (cnd_wait (&lock->waiting_readers, &lock->lock) != thrd_success)
 | 
			
		||||
        {
 | 
			
		||||
          mtx_unlock (&lock->lock);
 | 
			
		||||
          return EINVAL;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
  lock->runcount++;
 | 
			
		||||
  if (mtx_unlock (&lock->lock) != thrd_success)
 | 
			
		||||
    return EINVAL;
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
glthread_rwlock_wrlock (gl_rwlock_t *lock)
 | 
			
		||||
{
 | 
			
		||||
  if (lock->init_needed)
 | 
			
		||||
    call_once (&lock->init_once, lock->init_func);
 | 
			
		||||
  if (mtx_lock (&lock->lock) != thrd_success)
 | 
			
		||||
    return EAGAIN;
 | 
			
		||||
  /* Test whether no readers or writers are currently running.  */
 | 
			
		||||
  while (!(lock->runcount == 0))
 | 
			
		||||
    {
 | 
			
		||||
      /* This thread has to wait for a while.  Enqueue it among the
 | 
			
		||||
         waiting_writers.  */
 | 
			
		||||
      lock->waiting_writers_count++;
 | 
			
		||||
      if (cnd_wait (&lock->waiting_writers, &lock->lock) != thrd_success)
 | 
			
		||||
        {
 | 
			
		||||
          lock->waiting_writers_count--;
 | 
			
		||||
          mtx_unlock (&lock->lock);
 | 
			
		||||
          return EINVAL;
 | 
			
		||||
        }
 | 
			
		||||
      lock->waiting_writers_count--;
 | 
			
		||||
    }
 | 
			
		||||
  lock->runcount--; /* runcount becomes -1 */
 | 
			
		||||
  if (mtx_unlock (&lock->lock) != thrd_success)
 | 
			
		||||
    return EINVAL;
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
glthread_rwlock_unlock (gl_rwlock_t *lock)
 | 
			
		||||
{
 | 
			
		||||
  if (lock->init_needed)
 | 
			
		||||
    call_once (&lock->init_once, lock->init_func);
 | 
			
		||||
  if (mtx_lock (&lock->lock) != thrd_success)
 | 
			
		||||
    return EAGAIN;
 | 
			
		||||
  if (lock->runcount < 0)
 | 
			
		||||
    {
 | 
			
		||||
      /* Drop a writer lock.  */
 | 
			
		||||
      if (!(lock->runcount == -1))
 | 
			
		||||
        {
 | 
			
		||||
          mtx_unlock (&lock->lock);
 | 
			
		||||
          return EINVAL;
 | 
			
		||||
        }
 | 
			
		||||
      lock->runcount = 0;
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      /* Drop a reader lock.  */
 | 
			
		||||
      if (!(lock->runcount > 0))
 | 
			
		||||
        {
 | 
			
		||||
          mtx_unlock (&lock->lock);
 | 
			
		||||
          return EINVAL;
 | 
			
		||||
        }
 | 
			
		||||
      lock->runcount--;
 | 
			
		||||
    }
 | 
			
		||||
  if (lock->runcount == 0)
 | 
			
		||||
    {
 | 
			
		||||
      /* POSIX recommends that "write locks shall take precedence over read
 | 
			
		||||
         locks", to avoid "writer starvation".  */
 | 
			
		||||
      if (lock->waiting_writers_count > 0)
 | 
			
		||||
        {
 | 
			
		||||
          /* Wake up one of the waiting writers.  */
 | 
			
		||||
          if (cnd_signal (&lock->waiting_writers) != thrd_success)
 | 
			
		||||
            {
 | 
			
		||||
              mtx_unlock (&lock->lock);
 | 
			
		||||
              return EINVAL;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
      else
 | 
			
		||||
        {
 | 
			
		||||
          /* Wake up all waiting readers.  */
 | 
			
		||||
          if (cnd_broadcast (&lock->waiting_readers) != thrd_success)
 | 
			
		||||
            {
 | 
			
		||||
              mtx_unlock (&lock->lock);
 | 
			
		||||
              return EINVAL;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
  if (mtx_unlock (&lock->lock) != thrd_success)
 | 
			
		||||
    return EINVAL;
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
glthread_rwlock_destroy (gl_rwlock_t *lock)
 | 
			
		||||
{
 | 
			
		||||
  if (lock->init_needed)
 | 
			
		||||
    call_once (&lock->init_once, lock->init_func);
 | 
			
		||||
  mtx_destroy (&lock->lock);
 | 
			
		||||
  cnd_destroy (&lock->waiting_readers);
 | 
			
		||||
  cnd_destroy (&lock->waiting_writers);
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* --------------------- gl_recursive_lock_t datatype --------------------- */
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
glthread_recursive_lock_init (gl_recursive_lock_t *lock)
 | 
			
		||||
{
 | 
			
		||||
  if (mtx_init (&lock->mutex, mtx_plain | mtx_recursive) != thrd_success)
 | 
			
		||||
    return ENOMEM;
 | 
			
		||||
  lock->init_needed = 0;
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
glthread_recursive_lock_lock (gl_recursive_lock_t *lock)
 | 
			
		||||
{
 | 
			
		||||
  if (lock->init_needed)
 | 
			
		||||
    call_once (&lock->init_once, lock->init_func);
 | 
			
		||||
  if (mtx_lock (&lock->mutex) != thrd_success)
 | 
			
		||||
    return EAGAIN;
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
glthread_recursive_lock_unlock (gl_recursive_lock_t *lock)
 | 
			
		||||
{
 | 
			
		||||
  if (lock->init_needed)
 | 
			
		||||
    call_once (&lock->init_once, lock->init_func);
 | 
			
		||||
  if (mtx_unlock (&lock->mutex) != thrd_success)
 | 
			
		||||
    return EINVAL;
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
glthread_recursive_lock_destroy (gl_recursive_lock_t *lock)
 | 
			
		||||
{
 | 
			
		||||
  if (lock->init_needed)
 | 
			
		||||
    call_once (&lock->init_once, lock->init_func);
 | 
			
		||||
  mtx_destroy (&lock->mutex);
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* -------------------------- gl_once_t datatype -------------------------- */
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* ========================================================================= */
 | 
			
		||||
 | 
			
		||||
#if USE_POSIX_THREADS
 | 
			
		||||
 | 
			
		||||
/* -------------------------- gl_lock_t datatype -------------------------- */
 | 
			
		||||
 | 
			
		||||
/* ------------------------- gl_rwlock_t datatype ------------------------- */
 | 
			
		||||
 | 
			
		||||
# if HAVE_PTHREAD_RWLOCK
 | 
			
		||||
# if HAVE_PTHREAD_RWLOCK && (HAVE_PTHREAD_RWLOCK_RDLOCK_PREFER_WRITER || (defined PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP && (__GNU_LIBRARY__ > 1)))
 | 
			
		||||
 | 
			
		||||
#  if !defined PTHREAD_RWLOCK_INITIALIZER
 | 
			
		||||
#  if defined PTHREAD_RWLOCK_INITIALIZER || defined PTHREAD_RWLOCK_INITIALIZER_NP
 | 
			
		||||
 | 
			
		||||
#   if !HAVE_PTHREAD_RWLOCK_RDLOCK_PREFER_WRITER
 | 
			
		||||
     /* glibc with bug https://sourceware.org/bugzilla/show_bug.cgi?id=13701 */
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
glthread_rwlock_init_for_glibc (pthread_rwlock_t *lock)
 | 
			
		||||
{
 | 
			
		||||
  pthread_rwlockattr_t attributes;
 | 
			
		||||
  int err;
 | 
			
		||||
 | 
			
		||||
  err = pthread_rwlockattr_init (&attributes);
 | 
			
		||||
  if (err != 0)
 | 
			
		||||
    return err;
 | 
			
		||||
  /* Note: PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP is the only value that
 | 
			
		||||
     causes the writer to be preferred. PTHREAD_RWLOCK_PREFER_WRITER_NP does not
 | 
			
		||||
     do this; see
 | 
			
		||||
     http://man7.org/linux/man-pages/man3/pthread_rwlockattr_setkind_np.3.html */
 | 
			
		||||
  err = pthread_rwlockattr_setkind_np (&attributes,
 | 
			
		||||
                                       PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP);
 | 
			
		||||
  if (err == 0)
 | 
			
		||||
    err = pthread_rwlock_init(lock, &attributes);
 | 
			
		||||
  /* pthread_rwlockattr_destroy always returns 0.  It cannot influence the
 | 
			
		||||
     return value.  */
 | 
			
		||||
  pthread_rwlockattr_destroy (&attributes);
 | 
			
		||||
  return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#   endif
 | 
			
		||||
#  else
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
glthread_rwlock_init_multithreaded (gl_rwlock_t *lock)
 | 
			
		||||
| 
						 | 
				
			
			@ -152,11 +403,9 @@ glthread_rwlock_rdlock_multithreaded (gl_rwlock_t *lock)
 | 
			
		|||
  if (err != 0)
 | 
			
		||||
    return err;
 | 
			
		||||
  /* Test whether only readers are currently running, and whether the runcount
 | 
			
		||||
     field will not overflow.  */
 | 
			
		||||
  /* POSIX says: "It is implementation-defined whether the calling thread
 | 
			
		||||
     acquires the lock when a writer does not hold the lock and there are
 | 
			
		||||
     writers blocked on the lock."  Let's say, no: give the writers a higher
 | 
			
		||||
     priority.  */
 | 
			
		||||
     field will not overflow, and whether no writer is waiting.  The latter
 | 
			
		||||
     condition is because POSIX recommends that "write locks shall take
 | 
			
		||||
     precedence over read locks", to avoid "writer starvation".  */
 | 
			
		||||
  while (!(lock->runcount + 1 > 0 && lock->waiting_writers_count == 0))
 | 
			
		||||
    {
 | 
			
		||||
      /* This thread has to wait for a while.  Enqueue it among the
 | 
			
		||||
| 
						 | 
				
			
			@ -469,161 +718,25 @@ glthread_once_singlethreaded (pthread_once_t *once_control)
 | 
			
		|||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* ========================================================================= */
 | 
			
		||||
 | 
			
		||||
#if USE_PTH_THREADS
 | 
			
		||||
 | 
			
		||||
/* Use the GNU Pth threads library.  */
 | 
			
		||||
 | 
			
		||||
/* -------------------------- gl_lock_t datatype -------------------------- */
 | 
			
		||||
 | 
			
		||||
/* ------------------------- gl_rwlock_t datatype ------------------------- */
 | 
			
		||||
 | 
			
		||||
/* --------------------- gl_recursive_lock_t datatype --------------------- */
 | 
			
		||||
 | 
			
		||||
/* -------------------------- gl_once_t datatype -------------------------- */
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
glthread_once_call (void *arg)
 | 
			
		||||
{
 | 
			
		||||
  void (**gl_once_temp_addr) (void) = (void (**) (void)) arg;
 | 
			
		||||
  void (*initfunction) (void) = *gl_once_temp_addr;
 | 
			
		||||
  initfunction ();
 | 
			
		||||
}
 | 
			
		||||
# if !(PTHREAD_IN_USE_DETECTION_HARD || USE_POSIX_THREADS_WEAK)
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
glthread_once_multithreaded (pth_once_t *once_control, void (*initfunction) (void))
 | 
			
		||||
glthread_once_multithreaded (pthread_once_t *once_control,
 | 
			
		||||
                             void (*init_function) (void))
 | 
			
		||||
{
 | 
			
		||||
  void (*temp) (void) = initfunction;
 | 
			
		||||
  return (!pth_once (once_control, glthread_once_call, &temp) ? errno : 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
glthread_once_singlethreaded (pth_once_t *once_control)
 | 
			
		||||
{
 | 
			
		||||
  /* We know that pth_once_t is an integer type.  */
 | 
			
		||||
  if (*once_control == PTH_ONCE_INIT)
 | 
			
		||||
  int err = pthread_once (once_control, init_function);
 | 
			
		||||
  if (err == ENOSYS)
 | 
			
		||||
    {
 | 
			
		||||
      /* First time use of once_control.  Invert the marker.  */
 | 
			
		||||
      *once_control = ~ PTH_ONCE_INIT;
 | 
			
		||||
      return 1;
 | 
			
		||||
      /* This happens on FreeBSD 11: The pthread_once function in libc returns
 | 
			
		||||
         ENOSYS.  */
 | 
			
		||||
      if (glthread_once_singlethreaded (once_control))
 | 
			
		||||
        init_function ();
 | 
			
		||||
      return 0;
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    return 0;
 | 
			
		||||
  return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* ========================================================================= */
 | 
			
		||||
 | 
			
		||||
#if USE_SOLARIS_THREADS
 | 
			
		||||
 | 
			
		||||
/* Use the old Solaris threads library.  */
 | 
			
		||||
 | 
			
		||||
/* -------------------------- gl_lock_t datatype -------------------------- */
 | 
			
		||||
 | 
			
		||||
/* ------------------------- gl_rwlock_t datatype ------------------------- */
 | 
			
		||||
 | 
			
		||||
/* --------------------- gl_recursive_lock_t datatype --------------------- */
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock)
 | 
			
		||||
{
 | 
			
		||||
  int err;
 | 
			
		||||
 | 
			
		||||
  err = mutex_init (&lock->mutex, USYNC_THREAD, NULL);
 | 
			
		||||
  if (err != 0)
 | 
			
		||||
    return err;
 | 
			
		||||
  lock->owner = (thread_t) 0;
 | 
			
		||||
  lock->depth = 0;
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock)
 | 
			
		||||
{
 | 
			
		||||
  thread_t self = thr_self ();
 | 
			
		||||
  if (lock->owner != self)
 | 
			
		||||
    {
 | 
			
		||||
      int err;
 | 
			
		||||
 | 
			
		||||
      err = mutex_lock (&lock->mutex);
 | 
			
		||||
      if (err != 0)
 | 
			
		||||
        return err;
 | 
			
		||||
      lock->owner = self;
 | 
			
		||||
    }
 | 
			
		||||
  if (++(lock->depth) == 0) /* wraparound? */
 | 
			
		||||
    {
 | 
			
		||||
      lock->depth--;
 | 
			
		||||
      return EAGAIN;
 | 
			
		||||
    }
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock)
 | 
			
		||||
{
 | 
			
		||||
  if (lock->owner != thr_self ())
 | 
			
		||||
    return EPERM;
 | 
			
		||||
  if (lock->depth == 0)
 | 
			
		||||
    return EINVAL;
 | 
			
		||||
  if (--(lock->depth) == 0)
 | 
			
		||||
    {
 | 
			
		||||
      lock->owner = (thread_t) 0;
 | 
			
		||||
      return mutex_unlock (&lock->mutex);
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock)
 | 
			
		||||
{
 | 
			
		||||
  if (lock->owner != (thread_t) 0)
 | 
			
		||||
    return EBUSY;
 | 
			
		||||
  return mutex_destroy (&lock->mutex);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* -------------------------- gl_once_t datatype -------------------------- */
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
glthread_once_multithreaded (gl_once_t *once_control, void (*initfunction) (void))
 | 
			
		||||
{
 | 
			
		||||
  if (!once_control->inited)
 | 
			
		||||
    {
 | 
			
		||||
      int err;
 | 
			
		||||
 | 
			
		||||
      /* Use the mutex to guarantee that if another thread is already calling
 | 
			
		||||
         the initfunction, this thread waits until it's finished.  */
 | 
			
		||||
      err = mutex_lock (&once_control->mutex);
 | 
			
		||||
      if (err != 0)
 | 
			
		||||
        return err;
 | 
			
		||||
      if (!once_control->inited)
 | 
			
		||||
        {
 | 
			
		||||
          once_control->inited = 1;
 | 
			
		||||
          initfunction ();
 | 
			
		||||
        }
 | 
			
		||||
      return mutex_unlock (&once_control->mutex);
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
glthread_once_singlethreaded (gl_once_t *once_control)
 | 
			
		||||
{
 | 
			
		||||
  /* We know that gl_once_t contains an integer type.  */
 | 
			
		||||
  if (!once_control->inited)
 | 
			
		||||
    {
 | 
			
		||||
      /* First time use of once_control.  Invert the marker.  */
 | 
			
		||||
      once_control->inited = ~ 0;
 | 
			
		||||
      return 1;
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
# endif
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -631,427 +744,6 @@ glthread_once_singlethreaded (gl_once_t *once_control)
 | 
			
		|||
 | 
			
		||||
#if USE_WINDOWS_THREADS
 | 
			
		||||
 | 
			
		||||
/* -------------------------- gl_lock_t datatype -------------------------- */
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
glthread_lock_init_func (gl_lock_t *lock)
 | 
			
		||||
{
 | 
			
		||||
  InitializeCriticalSection (&lock->lock);
 | 
			
		||||
  lock->guard.done = 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
glthread_lock_lock_func (gl_lock_t *lock)
 | 
			
		||||
{
 | 
			
		||||
  if (!lock->guard.done)
 | 
			
		||||
    {
 | 
			
		||||
      if (InterlockedIncrement (&lock->guard.started) == 0)
 | 
			
		||||
        /* This thread is the first one to need this lock.  Initialize it.  */
 | 
			
		||||
        glthread_lock_init (lock);
 | 
			
		||||
      else
 | 
			
		||||
        /* Yield the CPU while waiting for another thread to finish
 | 
			
		||||
           initializing this lock.  */
 | 
			
		||||
        while (!lock->guard.done)
 | 
			
		||||
          Sleep (0);
 | 
			
		||||
    }
 | 
			
		||||
  EnterCriticalSection (&lock->lock);
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
glthread_lock_unlock_func (gl_lock_t *lock)
 | 
			
		||||
{
 | 
			
		||||
  if (!lock->guard.done)
 | 
			
		||||
    return EINVAL;
 | 
			
		||||
  LeaveCriticalSection (&lock->lock);
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
glthread_lock_destroy_func (gl_lock_t *lock)
 | 
			
		||||
{
 | 
			
		||||
  if (!lock->guard.done)
 | 
			
		||||
    return EINVAL;
 | 
			
		||||
  DeleteCriticalSection (&lock->lock);
 | 
			
		||||
  lock->guard.done = 0;
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* ------------------------- gl_rwlock_t datatype ------------------------- */
 | 
			
		||||
 | 
			
		||||
/* In this file, the waitqueues are implemented as circular arrays.  */
 | 
			
		||||
#define gl_waitqueue_t gl_carray_waitqueue_t
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
gl_waitqueue_init (gl_waitqueue_t *wq)
 | 
			
		||||
{
 | 
			
		||||
  wq->array = NULL;
 | 
			
		||||
  wq->count = 0;
 | 
			
		||||
  wq->alloc = 0;
 | 
			
		||||
  wq->offset = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Enqueues the current thread, represented by an event, in a wait queue.
 | 
			
		||||
   Returns INVALID_HANDLE_VALUE if an allocation failure occurs.  */
 | 
			
		||||
static HANDLE
 | 
			
		||||
gl_waitqueue_add (gl_waitqueue_t *wq)
 | 
			
		||||
{
 | 
			
		||||
  HANDLE event;
 | 
			
		||||
  unsigned int index;
 | 
			
		||||
 | 
			
		||||
  if (wq->count == wq->alloc)
 | 
			
		||||
    {
 | 
			
		||||
      unsigned int new_alloc = 2 * wq->alloc + 1;
 | 
			
		||||
      HANDLE *new_array =
 | 
			
		||||
        (HANDLE *) realloc (wq->array, new_alloc * sizeof (HANDLE));
 | 
			
		||||
      if (new_array == NULL)
 | 
			
		||||
        /* No more memory.  */
 | 
			
		||||
        return INVALID_HANDLE_VALUE;
 | 
			
		||||
      /* Now is a good opportunity to rotate the array so that its contents
 | 
			
		||||
         starts at offset 0.  */
 | 
			
		||||
      if (wq->offset > 0)
 | 
			
		||||
        {
 | 
			
		||||
          unsigned int old_count = wq->count;
 | 
			
		||||
          unsigned int old_alloc = wq->alloc;
 | 
			
		||||
          unsigned int old_offset = wq->offset;
 | 
			
		||||
          unsigned int i;
 | 
			
		||||
          if (old_offset + old_count > old_alloc)
 | 
			
		||||
            {
 | 
			
		||||
              unsigned int limit = old_offset + old_count - old_alloc;
 | 
			
		||||
              for (i = 0; i < limit; i++)
 | 
			
		||||
                new_array[old_alloc + i] = new_array[i];
 | 
			
		||||
            }
 | 
			
		||||
          for (i = 0; i < old_count; i++)
 | 
			
		||||
            new_array[i] = new_array[old_offset + i];
 | 
			
		||||
          wq->offset = 0;
 | 
			
		||||
        }
 | 
			
		||||
      wq->array = new_array;
 | 
			
		||||
      wq->alloc = new_alloc;
 | 
			
		||||
    }
 | 
			
		||||
  /* Whether the created event is a manual-reset one or an auto-reset one,
 | 
			
		||||
     does not matter, since we will wait on it only once.  */
 | 
			
		||||
  event = CreateEvent (NULL, TRUE, FALSE, NULL);
 | 
			
		||||
  if (event == INVALID_HANDLE_VALUE)
 | 
			
		||||
    /* No way to allocate an event.  */
 | 
			
		||||
    return INVALID_HANDLE_VALUE;
 | 
			
		||||
  index = wq->offset + wq->count;
 | 
			
		||||
  if (index >= wq->alloc)
 | 
			
		||||
    index -= wq->alloc;
 | 
			
		||||
  wq->array[index] = event;
 | 
			
		||||
  wq->count++;
 | 
			
		||||
  return event;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Notifies the first thread from a wait queue and dequeues it.  */
 | 
			
		||||
static void
 | 
			
		||||
gl_waitqueue_notify_first (gl_waitqueue_t *wq)
 | 
			
		||||
{
 | 
			
		||||
  SetEvent (wq->array[wq->offset + 0]);
 | 
			
		||||
  wq->offset++;
 | 
			
		||||
  wq->count--;
 | 
			
		||||
  if (wq->count == 0 || wq->offset == wq->alloc)
 | 
			
		||||
    wq->offset = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Notifies all threads from a wait queue and dequeues them all.  */
 | 
			
		||||
static void
 | 
			
		||||
gl_waitqueue_notify_all (gl_waitqueue_t *wq)
 | 
			
		||||
{
 | 
			
		||||
  unsigned int i;
 | 
			
		||||
 | 
			
		||||
  for (i = 0; i < wq->count; i++)
 | 
			
		||||
    {
 | 
			
		||||
      unsigned int index = wq->offset + i;
 | 
			
		||||
      if (index >= wq->alloc)
 | 
			
		||||
        index -= wq->alloc;
 | 
			
		||||
      SetEvent (wq->array[index]);
 | 
			
		||||
    }
 | 
			
		||||
  wq->count = 0;
 | 
			
		||||
  wq->offset = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
glthread_rwlock_init_func (gl_rwlock_t *lock)
 | 
			
		||||
{
 | 
			
		||||
  InitializeCriticalSection (&lock->lock);
 | 
			
		||||
  gl_waitqueue_init (&lock->waiting_readers);
 | 
			
		||||
  gl_waitqueue_init (&lock->waiting_writers);
 | 
			
		||||
  lock->runcount = 0;
 | 
			
		||||
  lock->guard.done = 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
glthread_rwlock_rdlock_func (gl_rwlock_t *lock)
 | 
			
		||||
{
 | 
			
		||||
  if (!lock->guard.done)
 | 
			
		||||
    {
 | 
			
		||||
      if (InterlockedIncrement (&lock->guard.started) == 0)
 | 
			
		||||
        /* This thread is the first one to need this lock.  Initialize it.  */
 | 
			
		||||
        glthread_rwlock_init (lock);
 | 
			
		||||
      else
 | 
			
		||||
        /* Yield the CPU while waiting for another thread to finish
 | 
			
		||||
           initializing this lock.  */
 | 
			
		||||
        while (!lock->guard.done)
 | 
			
		||||
          Sleep (0);
 | 
			
		||||
    }
 | 
			
		||||
  EnterCriticalSection (&lock->lock);
 | 
			
		||||
  /* Test whether only readers are currently running, and whether the runcount
 | 
			
		||||
     field will not overflow.  */
 | 
			
		||||
  if (!(lock->runcount + 1 > 0))
 | 
			
		||||
    {
 | 
			
		||||
      /* This thread has to wait for a while.  Enqueue it among the
 | 
			
		||||
         waiting_readers.  */
 | 
			
		||||
      HANDLE event = gl_waitqueue_add (&lock->waiting_readers);
 | 
			
		||||
      if (event != INVALID_HANDLE_VALUE)
 | 
			
		||||
        {
 | 
			
		||||
          DWORD result;
 | 
			
		||||
          LeaveCriticalSection (&lock->lock);
 | 
			
		||||
          /* Wait until another thread signals this event.  */
 | 
			
		||||
          result = WaitForSingleObject (event, INFINITE);
 | 
			
		||||
          if (result == WAIT_FAILED || result == WAIT_TIMEOUT)
 | 
			
		||||
            abort ();
 | 
			
		||||
          CloseHandle (event);
 | 
			
		||||
          /* The thread which signalled the event already did the bookkeeping:
 | 
			
		||||
             removed us from the waiting_readers, incremented lock->runcount.  */
 | 
			
		||||
          if (!(lock->runcount > 0))
 | 
			
		||||
            abort ();
 | 
			
		||||
          return 0;
 | 
			
		||||
        }
 | 
			
		||||
      else
 | 
			
		||||
        {
 | 
			
		||||
          /* Allocation failure.  Weird.  */
 | 
			
		||||
          do
 | 
			
		||||
            {
 | 
			
		||||
              LeaveCriticalSection (&lock->lock);
 | 
			
		||||
              Sleep (1);
 | 
			
		||||
              EnterCriticalSection (&lock->lock);
 | 
			
		||||
            }
 | 
			
		||||
          while (!(lock->runcount + 1 > 0));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
  lock->runcount++;
 | 
			
		||||
  LeaveCriticalSection (&lock->lock);
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
glthread_rwlock_wrlock_func (gl_rwlock_t *lock)
 | 
			
		||||
{
 | 
			
		||||
  if (!lock->guard.done)
 | 
			
		||||
    {
 | 
			
		||||
      if (InterlockedIncrement (&lock->guard.started) == 0)
 | 
			
		||||
        /* This thread is the first one to need this lock.  Initialize it.  */
 | 
			
		||||
        glthread_rwlock_init (lock);
 | 
			
		||||
      else
 | 
			
		||||
        /* Yield the CPU while waiting for another thread to finish
 | 
			
		||||
           initializing this lock.  */
 | 
			
		||||
        while (!lock->guard.done)
 | 
			
		||||
          Sleep (0);
 | 
			
		||||
    }
 | 
			
		||||
  EnterCriticalSection (&lock->lock);
 | 
			
		||||
  /* Test whether no readers or writers are currently running.  */
 | 
			
		||||
  if (!(lock->runcount == 0))
 | 
			
		||||
    {
 | 
			
		||||
      /* This thread has to wait for a while.  Enqueue it among the
 | 
			
		||||
         waiting_writers.  */
 | 
			
		||||
      HANDLE event = gl_waitqueue_add (&lock->waiting_writers);
 | 
			
		||||
      if (event != INVALID_HANDLE_VALUE)
 | 
			
		||||
        {
 | 
			
		||||
          DWORD result;
 | 
			
		||||
          LeaveCriticalSection (&lock->lock);
 | 
			
		||||
          /* Wait until another thread signals this event.  */
 | 
			
		||||
          result = WaitForSingleObject (event, INFINITE);
 | 
			
		||||
          if (result == WAIT_FAILED || result == WAIT_TIMEOUT)
 | 
			
		||||
            abort ();
 | 
			
		||||
          CloseHandle (event);
 | 
			
		||||
          /* The thread which signalled the event already did the bookkeeping:
 | 
			
		||||
             removed us from the waiting_writers, set lock->runcount = -1.  */
 | 
			
		||||
          if (!(lock->runcount == -1))
 | 
			
		||||
            abort ();
 | 
			
		||||
          return 0;
 | 
			
		||||
        }
 | 
			
		||||
      else
 | 
			
		||||
        {
 | 
			
		||||
          /* Allocation failure.  Weird.  */
 | 
			
		||||
          do
 | 
			
		||||
            {
 | 
			
		||||
              LeaveCriticalSection (&lock->lock);
 | 
			
		||||
              Sleep (1);
 | 
			
		||||
              EnterCriticalSection (&lock->lock);
 | 
			
		||||
            }
 | 
			
		||||
          while (!(lock->runcount == 0));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
  lock->runcount--; /* runcount becomes -1 */
 | 
			
		||||
  LeaveCriticalSection (&lock->lock);
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
glthread_rwlock_unlock_func (gl_rwlock_t *lock)
 | 
			
		||||
{
 | 
			
		||||
  if (!lock->guard.done)
 | 
			
		||||
    return EINVAL;
 | 
			
		||||
  EnterCriticalSection (&lock->lock);
 | 
			
		||||
  if (lock->runcount < 0)
 | 
			
		||||
    {
 | 
			
		||||
      /* Drop a writer lock.  */
 | 
			
		||||
      if (!(lock->runcount == -1))
 | 
			
		||||
        abort ();
 | 
			
		||||
      lock->runcount = 0;
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      /* Drop a reader lock.  */
 | 
			
		||||
      if (!(lock->runcount > 0))
 | 
			
		||||
        {
 | 
			
		||||
          LeaveCriticalSection (&lock->lock);
 | 
			
		||||
          return EPERM;
 | 
			
		||||
        }
 | 
			
		||||
      lock->runcount--;
 | 
			
		||||
    }
 | 
			
		||||
  if (lock->runcount == 0)
 | 
			
		||||
    {
 | 
			
		||||
      /* POSIX recommends that "write locks shall take precedence over read
 | 
			
		||||
         locks", to avoid "writer starvation".  */
 | 
			
		||||
      if (lock->waiting_writers.count > 0)
 | 
			
		||||
        {
 | 
			
		||||
          /* Wake up one of the waiting writers.  */
 | 
			
		||||
          lock->runcount--;
 | 
			
		||||
          gl_waitqueue_notify_first (&lock->waiting_writers);
 | 
			
		||||
        }
 | 
			
		||||
      else
 | 
			
		||||
        {
 | 
			
		||||
          /* Wake up all waiting readers.  */
 | 
			
		||||
          lock->runcount += lock->waiting_readers.count;
 | 
			
		||||
          gl_waitqueue_notify_all (&lock->waiting_readers);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
  LeaveCriticalSection (&lock->lock);
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
glthread_rwlock_destroy_func (gl_rwlock_t *lock)
 | 
			
		||||
{
 | 
			
		||||
  if (!lock->guard.done)
 | 
			
		||||
    return EINVAL;
 | 
			
		||||
  if (lock->runcount != 0)
 | 
			
		||||
    return EBUSY;
 | 
			
		||||
  DeleteCriticalSection (&lock->lock);
 | 
			
		||||
  if (lock->waiting_readers.array != NULL)
 | 
			
		||||
    free (lock->waiting_readers.array);
 | 
			
		||||
  if (lock->waiting_writers.array != NULL)
 | 
			
		||||
    free (lock->waiting_writers.array);
 | 
			
		||||
  lock->guard.done = 0;
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* --------------------- gl_recursive_lock_t datatype --------------------- */
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
glthread_recursive_lock_init_func (gl_recursive_lock_t *lock)
 | 
			
		||||
{
 | 
			
		||||
  lock->owner = 0;
 | 
			
		||||
  lock->depth = 0;
 | 
			
		||||
  InitializeCriticalSection (&lock->lock);
 | 
			
		||||
  lock->guard.done = 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
glthread_recursive_lock_lock_func (gl_recursive_lock_t *lock)
 | 
			
		||||
{
 | 
			
		||||
  if (!lock->guard.done)
 | 
			
		||||
    {
 | 
			
		||||
      if (InterlockedIncrement (&lock->guard.started) == 0)
 | 
			
		||||
        /* This thread is the first one to need this lock.  Initialize it.  */
 | 
			
		||||
        glthread_recursive_lock_init (lock);
 | 
			
		||||
      else
 | 
			
		||||
        /* Yield the CPU while waiting for another thread to finish
 | 
			
		||||
           initializing this lock.  */
 | 
			
		||||
        while (!lock->guard.done)
 | 
			
		||||
          Sleep (0);
 | 
			
		||||
    }
 | 
			
		||||
  {
 | 
			
		||||
    DWORD self = GetCurrentThreadId ();
 | 
			
		||||
    if (lock->owner != self)
 | 
			
		||||
      {
 | 
			
		||||
        EnterCriticalSection (&lock->lock);
 | 
			
		||||
        lock->owner = self;
 | 
			
		||||
      }
 | 
			
		||||
    if (++(lock->depth) == 0) /* wraparound? */
 | 
			
		||||
      {
 | 
			
		||||
        lock->depth--;
 | 
			
		||||
        return EAGAIN;
 | 
			
		||||
      }
 | 
			
		||||
  }
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
glthread_recursive_lock_unlock_func (gl_recursive_lock_t *lock)
 | 
			
		||||
{
 | 
			
		||||
  if (lock->owner != GetCurrentThreadId ())
 | 
			
		||||
    return EPERM;
 | 
			
		||||
  if (lock->depth == 0)
 | 
			
		||||
    return EINVAL;
 | 
			
		||||
  if (--(lock->depth) == 0)
 | 
			
		||||
    {
 | 
			
		||||
      lock->owner = 0;
 | 
			
		||||
      LeaveCriticalSection (&lock->lock);
 | 
			
		||||
    }
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
glthread_recursive_lock_destroy_func (gl_recursive_lock_t *lock)
 | 
			
		||||
{
 | 
			
		||||
  if (lock->owner != 0)
 | 
			
		||||
    return EBUSY;
 | 
			
		||||
  DeleteCriticalSection (&lock->lock);
 | 
			
		||||
  lock->guard.done = 0;
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* -------------------------- gl_once_t datatype -------------------------- */
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
glthread_once_func (gl_once_t *once_control, void (*initfunction) (void))
 | 
			
		||||
{
 | 
			
		||||
  if (once_control->inited <= 0)
 | 
			
		||||
    {
 | 
			
		||||
      if (InterlockedIncrement (&once_control->started) == 0)
 | 
			
		||||
        {
 | 
			
		||||
          /* This thread is the first one to come to this once_control.  */
 | 
			
		||||
          InitializeCriticalSection (&once_control->lock);
 | 
			
		||||
          EnterCriticalSection (&once_control->lock);
 | 
			
		||||
          once_control->inited = 0;
 | 
			
		||||
          initfunction ();
 | 
			
		||||
          once_control->inited = 1;
 | 
			
		||||
          LeaveCriticalSection (&once_control->lock);
 | 
			
		||||
        }
 | 
			
		||||
      else
 | 
			
		||||
        {
 | 
			
		||||
          /* Undo last operation.  */
 | 
			
		||||
          InterlockedDecrement (&once_control->started);
 | 
			
		||||
          /* Some other thread has already started the initialization.
 | 
			
		||||
             Yield the CPU while waiting for the other thread to finish
 | 
			
		||||
             initializing and taking the lock.  */
 | 
			
		||||
          while (once_control->inited < 0)
 | 
			
		||||
            Sleep (0);
 | 
			
		||||
          if (once_control->inited <= 0)
 | 
			
		||||
            {
 | 
			
		||||
              /* Take the lock.  This blocks until the other thread has
 | 
			
		||||
                 finished calling the initfunction.  */
 | 
			
		||||
              EnterCriticalSection (&once_control->lock);
 | 
			
		||||
              LeaveCriticalSection (&once_control->lock);
 | 
			
		||||
              if (!(once_control->inited > 0))
 | 
			
		||||
                abort ();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* ========================================================================= */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,22 +1,21 @@
 | 
			
		|||
/* Locking in multithreaded situations.
 | 
			
		||||
   Copyright (C) 2005-2013 Free Software Foundation, Inc.
 | 
			
		||||
   Copyright (C) 2005-2023 Free Software Foundation, Inc.
 | 
			
		||||
 | 
			
		||||
   This program is free software; you can redistribute it and/or modify
 | 
			
		||||
   it under the terms of the GNU General Public License as published by
 | 
			
		||||
   the Free Software Foundation; either version 3, or (at your option)
 | 
			
		||||
   any later version.
 | 
			
		||||
   This file is free software: you can redistribute it and/or modify
 | 
			
		||||
   it under the terms of the GNU Lesser General Public License as
 | 
			
		||||
   published by the Free Software Foundation; either version 2.1 of the
 | 
			
		||||
   License, or (at your option) any later version.
 | 
			
		||||
 | 
			
		||||
   This program is distributed in the hope that it will be useful,
 | 
			
		||||
   This file is distributed in the hope that it will be useful,
 | 
			
		||||
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
   GNU General Public License for more details.
 | 
			
		||||
   GNU Lesser General Public License for more details.
 | 
			
		||||
 | 
			
		||||
   You should have received a copy of the GNU General Public License
 | 
			
		||||
   along with this program; if not, see <http://www.gnu.org/licenses/>.  */
 | 
			
		||||
   You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 | 
			
		||||
 | 
			
		||||
/* Written by Bruno Haible <bruno@clisp.org>, 2005.
 | 
			
		||||
   Based on GCC's gthr-posix.h, gthr-posix95.h, gthr-solaris.h,
 | 
			
		||||
   gthr-win32.h.  */
 | 
			
		||||
   Based on GCC's gthr-posix.h, gthr-posix95.h, gthr-win32.h.  */
 | 
			
		||||
 | 
			
		||||
/* This file contains locking primitives for use with a given thread library.
 | 
			
		||||
   It does not contain primitives for creating threads or for other
 | 
			
		||||
| 
						 | 
				
			
			@ -81,6 +80,127 @@
 | 
			
		|||
#include <errno.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
 | 
			
		||||
#if !defined c11_threads_in_use
 | 
			
		||||
# if HAVE_THREADS_H && USE_POSIX_THREADS_FROM_LIBC
 | 
			
		||||
#  define c11_threads_in_use() 1
 | 
			
		||||
# elif HAVE_THREADS_H && USE_POSIX_THREADS_WEAK
 | 
			
		||||
#  include <threads.h>
 | 
			
		||||
#  pragma weak thrd_exit
 | 
			
		||||
#  define c11_threads_in_use() (thrd_exit != NULL)
 | 
			
		||||
# else
 | 
			
		||||
#  define c11_threads_in_use() 0
 | 
			
		||||
# endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* ========================================================================= */
 | 
			
		||||
 | 
			
		||||
#if USE_ISOC_THREADS || USE_ISOC_AND_POSIX_THREADS
 | 
			
		||||
 | 
			
		||||
/* Use the ISO C threads library.  */
 | 
			
		||||
 | 
			
		||||
# include <threads.h>
 | 
			
		||||
 | 
			
		||||
# ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
# endif
 | 
			
		||||
 | 
			
		||||
/* -------------------------- gl_lock_t datatype -------------------------- */
 | 
			
		||||
 | 
			
		||||
typedef struct
 | 
			
		||||
        {
 | 
			
		||||
          int volatile init_needed;
 | 
			
		||||
          once_flag init_once;
 | 
			
		||||
          void (*init_func) (void);
 | 
			
		||||
          mtx_t mutex;
 | 
			
		||||
        }
 | 
			
		||||
        gl_lock_t;
 | 
			
		||||
# define gl_lock_define(STORAGECLASS, NAME) \
 | 
			
		||||
    STORAGECLASS gl_lock_t NAME;
 | 
			
		||||
# define gl_lock_define_initialized(STORAGECLASS, NAME) \
 | 
			
		||||
    static void _atomic_init_##NAME (void);       \
 | 
			
		||||
    STORAGECLASS gl_lock_t NAME =                 \
 | 
			
		||||
      { 1, ONCE_FLAG_INIT, _atomic_init_##NAME }; \
 | 
			
		||||
    static void _atomic_init_##NAME (void)        \
 | 
			
		||||
    {                                             \
 | 
			
		||||
      if (glthread_lock_init (&(NAME)))           \
 | 
			
		||||
        abort ();                                 \
 | 
			
		||||
    }
 | 
			
		||||
extern int glthread_lock_init (gl_lock_t *lock);
 | 
			
		||||
extern int glthread_lock_lock (gl_lock_t *lock);
 | 
			
		||||
extern int glthread_lock_unlock (gl_lock_t *lock);
 | 
			
		||||
extern int glthread_lock_destroy (gl_lock_t *lock);
 | 
			
		||||
 | 
			
		||||
/* ------------------------- gl_rwlock_t datatype ------------------------- */
 | 
			
		||||
 | 
			
		||||
typedef struct
 | 
			
		||||
        {
 | 
			
		||||
          int volatile init_needed;
 | 
			
		||||
          once_flag init_once;
 | 
			
		||||
          void (*init_func) (void);
 | 
			
		||||
          mtx_t lock; /* protects the remaining fields */
 | 
			
		||||
          cnd_t waiting_readers; /* waiting readers */
 | 
			
		||||
          cnd_t waiting_writers; /* waiting writers */
 | 
			
		||||
          unsigned int waiting_writers_count; /* number of waiting writers */
 | 
			
		||||
          int runcount; /* number of readers running, or -1 when a writer runs */
 | 
			
		||||
        }
 | 
			
		||||
        gl_rwlock_t;
 | 
			
		||||
# define gl_rwlock_define(STORAGECLASS, NAME) \
 | 
			
		||||
    STORAGECLASS gl_rwlock_t NAME;
 | 
			
		||||
# define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
 | 
			
		||||
    static void _atomic_init_##NAME (void);       \
 | 
			
		||||
    STORAGECLASS gl_rwlock_t NAME =               \
 | 
			
		||||
      { 1, ONCE_FLAG_INIT, _atomic_init_##NAME }; \
 | 
			
		||||
    static void _atomic_init_##NAME (void)        \
 | 
			
		||||
    {                                             \
 | 
			
		||||
      if (glthread_rwlock_init (&(NAME)))         \
 | 
			
		||||
        abort ();                                 \
 | 
			
		||||
    }
 | 
			
		||||
extern int glthread_rwlock_init (gl_rwlock_t *lock);
 | 
			
		||||
extern int glthread_rwlock_rdlock (gl_rwlock_t *lock);
 | 
			
		||||
extern int glthread_rwlock_wrlock (gl_rwlock_t *lock);
 | 
			
		||||
extern int glthread_rwlock_unlock (gl_rwlock_t *lock);
 | 
			
		||||
extern int glthread_rwlock_destroy (gl_rwlock_t *lock);
 | 
			
		||||
 | 
			
		||||
/* --------------------- gl_recursive_lock_t datatype --------------------- */
 | 
			
		||||
 | 
			
		||||
typedef struct
 | 
			
		||||
        {
 | 
			
		||||
          int volatile init_needed;
 | 
			
		||||
          once_flag init_once;
 | 
			
		||||
          void (*init_func) (void);
 | 
			
		||||
          mtx_t mutex;
 | 
			
		||||
        }
 | 
			
		||||
        gl_recursive_lock_t;
 | 
			
		||||
# define gl_recursive_lock_define(STORAGECLASS, NAME) \
 | 
			
		||||
    STORAGECLASS gl_recursive_lock_t NAME;
 | 
			
		||||
# define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
 | 
			
		||||
    static void _atomic_init_##NAME (void);       \
 | 
			
		||||
    STORAGECLASS gl_recursive_lock_t NAME =       \
 | 
			
		||||
      { 1, ONCE_FLAG_INIT, _atomic_init_##NAME }; \
 | 
			
		||||
    static void _atomic_init_##NAME (void)        \
 | 
			
		||||
    {                                             \
 | 
			
		||||
      if (glthread_recursive_lock_init (&(NAME))) \
 | 
			
		||||
        abort ();                                 \
 | 
			
		||||
    }
 | 
			
		||||
extern int glthread_recursive_lock_init (gl_recursive_lock_t *lock);
 | 
			
		||||
extern int glthread_recursive_lock_lock (gl_recursive_lock_t *lock);
 | 
			
		||||
extern int glthread_recursive_lock_unlock (gl_recursive_lock_t *lock);
 | 
			
		||||
extern int glthread_recursive_lock_destroy (gl_recursive_lock_t *lock);
 | 
			
		||||
 | 
			
		||||
/* -------------------------- gl_once_t datatype -------------------------- */
 | 
			
		||||
 | 
			
		||||
typedef once_flag gl_once_t;
 | 
			
		||||
# define gl_once_define(STORAGECLASS, NAME) \
 | 
			
		||||
    STORAGECLASS once_flag NAME = ONCE_FLAG_INIT;
 | 
			
		||||
# define glthread_once(ONCE_CONTROL, INITFUNCTION) \
 | 
			
		||||
    (call_once (ONCE_CONTROL, INITFUNCTION), 0)
 | 
			
		||||
 | 
			
		||||
# ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
# endif
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* ========================================================================= */
 | 
			
		||||
 | 
			
		||||
#if USE_POSIX_THREADS
 | 
			
		||||
| 
						 | 
				
			
			@ -139,13 +259,25 @@ extern int glthread_in_use (void);
 | 
			
		|||
#  pragma weak pthread_mutexattr_init
 | 
			
		||||
#  pragma weak pthread_mutexattr_settype
 | 
			
		||||
#  pragma weak pthread_mutexattr_destroy
 | 
			
		||||
#  pragma weak pthread_rwlockattr_init
 | 
			
		||||
#  if __GNU_LIBRARY__ > 1
 | 
			
		||||
#   pragma weak pthread_rwlockattr_setkind_np
 | 
			
		||||
#  endif
 | 
			
		||||
#  pragma weak pthread_rwlockattr_destroy
 | 
			
		||||
#  ifndef pthread_self
 | 
			
		||||
#   pragma weak pthread_self
 | 
			
		||||
#  endif
 | 
			
		||||
 | 
			
		||||
#  if !PTHREAD_IN_USE_DETECTION_HARD
 | 
			
		||||
#   pragma weak pthread_cancel
 | 
			
		||||
#   define pthread_in_use() (pthread_cancel != NULL)
 | 
			
		||||
    /* Considering all platforms with USE_POSIX_THREADS_WEAK, only few symbols
 | 
			
		||||
       can be used to determine whether libpthread is in use.  These are:
 | 
			
		||||
         pthread_mutexattr_gettype
 | 
			
		||||
         pthread_rwlockattr_destroy
 | 
			
		||||
         pthread_rwlockattr_init
 | 
			
		||||
     */
 | 
			
		||||
#   pragma weak pthread_mutexattr_gettype
 | 
			
		||||
#   define pthread_in_use() \
 | 
			
		||||
      (pthread_mutexattr_gettype != NULL || c11_threads_in_use ())
 | 
			
		||||
#  endif
 | 
			
		||||
 | 
			
		||||
# else
 | 
			
		||||
| 
						 | 
				
			
			@ -176,19 +308,32 @@ typedef pthread_mutex_t gl_lock_t;
 | 
			
		|||
 | 
			
		||||
/* ------------------------- gl_rwlock_t datatype ------------------------- */
 | 
			
		||||
 | 
			
		||||
# if HAVE_PTHREAD_RWLOCK
 | 
			
		||||
# if HAVE_PTHREAD_RWLOCK && (HAVE_PTHREAD_RWLOCK_RDLOCK_PREFER_WRITER || (defined PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP && (__GNU_LIBRARY__ > 1)))
 | 
			
		||||
 | 
			
		||||
#  ifdef PTHREAD_RWLOCK_INITIALIZER
 | 
			
		||||
#  if defined PTHREAD_RWLOCK_INITIALIZER || defined PTHREAD_RWLOCK_INITIALIZER_NP
 | 
			
		||||
 | 
			
		||||
typedef pthread_rwlock_t gl_rwlock_t;
 | 
			
		||||
#   define gl_rwlock_define(STORAGECLASS, NAME) \
 | 
			
		||||
      STORAGECLASS pthread_rwlock_t NAME;
 | 
			
		||||
#   define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
 | 
			
		||||
      STORAGECLASS pthread_rwlock_t NAME = gl_rwlock_initializer;
 | 
			
		||||
#   define gl_rwlock_initializer \
 | 
			
		||||
      PTHREAD_RWLOCK_INITIALIZER
 | 
			
		||||
#   define glthread_rwlock_init(LOCK) \
 | 
			
		||||
      (pthread_in_use () ? pthread_rwlock_init (LOCK, NULL) : 0)
 | 
			
		||||
#   if HAVE_PTHREAD_RWLOCK_RDLOCK_PREFER_WRITER
 | 
			
		||||
#    if defined PTHREAD_RWLOCK_INITIALIZER
 | 
			
		||||
#     define gl_rwlock_initializer \
 | 
			
		||||
        PTHREAD_RWLOCK_INITIALIZER
 | 
			
		||||
#    else
 | 
			
		||||
#     define gl_rwlock_initializer \
 | 
			
		||||
        PTHREAD_RWLOCK_INITIALIZER_NP
 | 
			
		||||
#    endif
 | 
			
		||||
#    define glthread_rwlock_init(LOCK) \
 | 
			
		||||
       (pthread_in_use () ? pthread_rwlock_init (LOCK, NULL) : 0)
 | 
			
		||||
#   else /* glibc with bug https://sourceware.org/bugzilla/show_bug.cgi?id=13701 */
 | 
			
		||||
#    define gl_rwlock_initializer \
 | 
			
		||||
       PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP
 | 
			
		||||
#    define glthread_rwlock_init(LOCK) \
 | 
			
		||||
       (pthread_in_use () ? glthread_rwlock_init_for_glibc (LOCK) : 0)
 | 
			
		||||
extern int glthread_rwlock_init_for_glibc (pthread_rwlock_t *lock);
 | 
			
		||||
#   endif
 | 
			
		||||
#   define glthread_rwlock_rdlock(LOCK) \
 | 
			
		||||
      (pthread_in_use () ? pthread_rwlock_rdlock (LOCK) : 0)
 | 
			
		||||
#   define glthread_rwlock_wrlock(LOCK) \
 | 
			
		||||
| 
						 | 
				
			
			@ -362,10 +507,19 @@ extern int glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *l
 | 
			
		|||
typedef pthread_once_t gl_once_t;
 | 
			
		||||
# define gl_once_define(STORAGECLASS, NAME) \
 | 
			
		||||
    STORAGECLASS pthread_once_t NAME = PTHREAD_ONCE_INIT;
 | 
			
		||||
# define glthread_once(ONCE_CONTROL, INITFUNCTION) \
 | 
			
		||||
    (pthread_in_use ()                                                         \
 | 
			
		||||
     ? pthread_once (ONCE_CONTROL, INITFUNCTION)                               \
 | 
			
		||||
     : (glthread_once_singlethreaded (ONCE_CONTROL) ? (INITFUNCTION (), 0) : 0))
 | 
			
		||||
# if PTHREAD_IN_USE_DETECTION_HARD || USE_POSIX_THREADS_WEAK
 | 
			
		||||
#  define glthread_once(ONCE_CONTROL, INITFUNCTION) \
 | 
			
		||||
     (pthread_in_use ()                                                        \
 | 
			
		||||
      ? pthread_once (ONCE_CONTROL, INITFUNCTION)                              \
 | 
			
		||||
      : (glthread_once_singlethreaded (ONCE_CONTROL) ? (INITFUNCTION (), 0) : 0))
 | 
			
		||||
# else
 | 
			
		||||
#  define glthread_once(ONCE_CONTROL, INITFUNCTION) \
 | 
			
		||||
     (pthread_in_use ()                                                        \
 | 
			
		||||
      ? glthread_once_multithreaded (ONCE_CONTROL, INITFUNCTION)               \
 | 
			
		||||
      : (glthread_once_singlethreaded (ONCE_CONTROL) ? (INITFUNCTION (), 0) : 0))
 | 
			
		||||
extern int glthread_once_multithreaded (pthread_once_t *once_control,
 | 
			
		||||
                                        void (*init_function) (void));
 | 
			
		||||
# endif
 | 
			
		||||
extern int glthread_once_singlethreaded (pthread_once_t *once_control);
 | 
			
		||||
 | 
			
		||||
# ifdef __cplusplus
 | 
			
		||||
| 
						 | 
				
			
			@ -376,248 +530,16 @@ extern int glthread_once_singlethreaded (pthread_once_t *once_control);
 | 
			
		|||
 | 
			
		||||
/* ========================================================================= */
 | 
			
		||||
 | 
			
		||||
#if USE_PTH_THREADS
 | 
			
		||||
 | 
			
		||||
/* Use the GNU Pth threads library.  */
 | 
			
		||||
 | 
			
		||||
# include <pth.h>
 | 
			
		||||
 | 
			
		||||
# ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
# endif
 | 
			
		||||
 | 
			
		||||
# if USE_PTH_THREADS_WEAK
 | 
			
		||||
 | 
			
		||||
/* Use weak references to the GNU Pth threads library.  */
 | 
			
		||||
 | 
			
		||||
#  pragma weak pth_mutex_init
 | 
			
		||||
#  pragma weak pth_mutex_acquire
 | 
			
		||||
#  pragma weak pth_mutex_release
 | 
			
		||||
#  pragma weak pth_rwlock_init
 | 
			
		||||
#  pragma weak pth_rwlock_acquire
 | 
			
		||||
#  pragma weak pth_rwlock_release
 | 
			
		||||
#  pragma weak pth_once
 | 
			
		||||
 | 
			
		||||
#  pragma weak pth_cancel
 | 
			
		||||
#  define pth_in_use() (pth_cancel != NULL)
 | 
			
		||||
 | 
			
		||||
# else
 | 
			
		||||
 | 
			
		||||
#  define pth_in_use() 1
 | 
			
		||||
 | 
			
		||||
# endif
 | 
			
		||||
 | 
			
		||||
/* -------------------------- gl_lock_t datatype -------------------------- */
 | 
			
		||||
 | 
			
		||||
typedef pth_mutex_t gl_lock_t;
 | 
			
		||||
# define gl_lock_define(STORAGECLASS, NAME) \
 | 
			
		||||
    STORAGECLASS pth_mutex_t NAME;
 | 
			
		||||
# define gl_lock_define_initialized(STORAGECLASS, NAME) \
 | 
			
		||||
    STORAGECLASS pth_mutex_t NAME = gl_lock_initializer;
 | 
			
		||||
# define gl_lock_initializer \
 | 
			
		||||
    PTH_MUTEX_INIT
 | 
			
		||||
# define glthread_lock_init(LOCK) \
 | 
			
		||||
    (pth_in_use () && !pth_mutex_init (LOCK) ? errno : 0)
 | 
			
		||||
# define glthread_lock_lock(LOCK) \
 | 
			
		||||
    (pth_in_use () && !pth_mutex_acquire (LOCK, 0, NULL) ? errno : 0)
 | 
			
		||||
# define glthread_lock_unlock(LOCK) \
 | 
			
		||||
    (pth_in_use () && !pth_mutex_release (LOCK) ? errno : 0)
 | 
			
		||||
# define glthread_lock_destroy(LOCK) \
 | 
			
		||||
    ((void)(LOCK), 0)
 | 
			
		||||
 | 
			
		||||
/* ------------------------- gl_rwlock_t datatype ------------------------- */
 | 
			
		||||
 | 
			
		||||
typedef pth_rwlock_t gl_rwlock_t;
 | 
			
		||||
#  define gl_rwlock_define(STORAGECLASS, NAME) \
 | 
			
		||||
     STORAGECLASS pth_rwlock_t NAME;
 | 
			
		||||
#  define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
 | 
			
		||||
     STORAGECLASS pth_rwlock_t NAME = gl_rwlock_initializer;
 | 
			
		||||
#  define gl_rwlock_initializer \
 | 
			
		||||
     PTH_RWLOCK_INIT
 | 
			
		||||
#  define glthread_rwlock_init(LOCK) \
 | 
			
		||||
     (pth_in_use () && !pth_rwlock_init (LOCK) ? errno : 0)
 | 
			
		||||
#  define glthread_rwlock_rdlock(LOCK) \
 | 
			
		||||
     (pth_in_use () && !pth_rwlock_acquire (LOCK, PTH_RWLOCK_RD, 0, NULL) ? errno : 0)
 | 
			
		||||
#  define glthread_rwlock_wrlock(LOCK) \
 | 
			
		||||
     (pth_in_use () && !pth_rwlock_acquire (LOCK, PTH_RWLOCK_RW, 0, NULL) ? errno : 0)
 | 
			
		||||
#  define glthread_rwlock_unlock(LOCK) \
 | 
			
		||||
     (pth_in_use () && !pth_rwlock_release (LOCK) ? errno : 0)
 | 
			
		||||
#  define glthread_rwlock_destroy(LOCK) \
 | 
			
		||||
     ((void)(LOCK), 0)
 | 
			
		||||
 | 
			
		||||
/* --------------------- gl_recursive_lock_t datatype --------------------- */
 | 
			
		||||
 | 
			
		||||
/* In Pth, mutexes are recursive by default.  */
 | 
			
		||||
typedef pth_mutex_t gl_recursive_lock_t;
 | 
			
		||||
#  define gl_recursive_lock_define(STORAGECLASS, NAME) \
 | 
			
		||||
     STORAGECLASS pth_mutex_t NAME;
 | 
			
		||||
#  define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
 | 
			
		||||
     STORAGECLASS pth_mutex_t NAME = gl_recursive_lock_initializer;
 | 
			
		||||
#  define gl_recursive_lock_initializer \
 | 
			
		||||
     PTH_MUTEX_INIT
 | 
			
		||||
#  define glthread_recursive_lock_init(LOCK) \
 | 
			
		||||
     (pth_in_use () && !pth_mutex_init (LOCK) ? errno : 0)
 | 
			
		||||
#  define glthread_recursive_lock_lock(LOCK) \
 | 
			
		||||
     (pth_in_use () && !pth_mutex_acquire (LOCK, 0, NULL) ? errno : 0)
 | 
			
		||||
#  define glthread_recursive_lock_unlock(LOCK) \
 | 
			
		||||
     (pth_in_use () && !pth_mutex_release (LOCK) ? errno : 0)
 | 
			
		||||
#  define glthread_recursive_lock_destroy(LOCK) \
 | 
			
		||||
     ((void)(LOCK), 0)
 | 
			
		||||
 | 
			
		||||
/* -------------------------- gl_once_t datatype -------------------------- */
 | 
			
		||||
 | 
			
		||||
typedef pth_once_t gl_once_t;
 | 
			
		||||
# define gl_once_define(STORAGECLASS, NAME) \
 | 
			
		||||
    STORAGECLASS pth_once_t NAME = PTH_ONCE_INIT;
 | 
			
		||||
# define glthread_once(ONCE_CONTROL, INITFUNCTION) \
 | 
			
		||||
    (pth_in_use ()                                                             \
 | 
			
		||||
     ? glthread_once_multithreaded (ONCE_CONTROL, INITFUNCTION)                \
 | 
			
		||||
     : (glthread_once_singlethreaded (ONCE_CONTROL) ? (INITFUNCTION (), 0) : 0))
 | 
			
		||||
extern int glthread_once_multithreaded (pth_once_t *once_control, void (*initfunction) (void));
 | 
			
		||||
extern int glthread_once_singlethreaded (pth_once_t *once_control);
 | 
			
		||||
 | 
			
		||||
# ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
# endif
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* ========================================================================= */
 | 
			
		||||
 | 
			
		||||
#if USE_SOLARIS_THREADS
 | 
			
		||||
 | 
			
		||||
/* Use the old Solaris threads library.  */
 | 
			
		||||
 | 
			
		||||
# include <thread.h>
 | 
			
		||||
# include <synch.h>
 | 
			
		||||
 | 
			
		||||
# ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
# endif
 | 
			
		||||
 | 
			
		||||
# if USE_SOLARIS_THREADS_WEAK
 | 
			
		||||
 | 
			
		||||
/* Use weak references to the old Solaris threads library.  */
 | 
			
		||||
 | 
			
		||||
#  pragma weak mutex_init
 | 
			
		||||
#  pragma weak mutex_lock
 | 
			
		||||
#  pragma weak mutex_unlock
 | 
			
		||||
#  pragma weak mutex_destroy
 | 
			
		||||
#  pragma weak rwlock_init
 | 
			
		||||
#  pragma weak rw_rdlock
 | 
			
		||||
#  pragma weak rw_wrlock
 | 
			
		||||
#  pragma weak rw_unlock
 | 
			
		||||
#  pragma weak rwlock_destroy
 | 
			
		||||
#  pragma weak thr_self
 | 
			
		||||
 | 
			
		||||
#  pragma weak thr_suspend
 | 
			
		||||
#  define thread_in_use() (thr_suspend != NULL)
 | 
			
		||||
 | 
			
		||||
# else
 | 
			
		||||
 | 
			
		||||
#  define thread_in_use() 1
 | 
			
		||||
 | 
			
		||||
# endif
 | 
			
		||||
 | 
			
		||||
/* -------------------------- gl_lock_t datatype -------------------------- */
 | 
			
		||||
 | 
			
		||||
typedef mutex_t gl_lock_t;
 | 
			
		||||
# define gl_lock_define(STORAGECLASS, NAME) \
 | 
			
		||||
    STORAGECLASS mutex_t NAME;
 | 
			
		||||
# define gl_lock_define_initialized(STORAGECLASS, NAME) \
 | 
			
		||||
    STORAGECLASS mutex_t NAME = gl_lock_initializer;
 | 
			
		||||
# define gl_lock_initializer \
 | 
			
		||||
    DEFAULTMUTEX
 | 
			
		||||
# define glthread_lock_init(LOCK) \
 | 
			
		||||
    (thread_in_use () ? mutex_init (LOCK, USYNC_THREAD, NULL) : 0)
 | 
			
		||||
# define glthread_lock_lock(LOCK) \
 | 
			
		||||
    (thread_in_use () ? mutex_lock (LOCK) : 0)
 | 
			
		||||
# define glthread_lock_unlock(LOCK) \
 | 
			
		||||
    (thread_in_use () ? mutex_unlock (LOCK) : 0)
 | 
			
		||||
# define glthread_lock_destroy(LOCK) \
 | 
			
		||||
    (thread_in_use () ? mutex_destroy (LOCK) : 0)
 | 
			
		||||
 | 
			
		||||
/* ------------------------- gl_rwlock_t datatype ------------------------- */
 | 
			
		||||
 | 
			
		||||
typedef rwlock_t gl_rwlock_t;
 | 
			
		||||
# define gl_rwlock_define(STORAGECLASS, NAME) \
 | 
			
		||||
    STORAGECLASS rwlock_t NAME;
 | 
			
		||||
# define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
 | 
			
		||||
    STORAGECLASS rwlock_t NAME = gl_rwlock_initializer;
 | 
			
		||||
# define gl_rwlock_initializer \
 | 
			
		||||
    DEFAULTRWLOCK
 | 
			
		||||
# define glthread_rwlock_init(LOCK) \
 | 
			
		||||
    (thread_in_use () ? rwlock_init (LOCK, USYNC_THREAD, NULL) : 0)
 | 
			
		||||
# define glthread_rwlock_rdlock(LOCK) \
 | 
			
		||||
    (thread_in_use () ? rw_rdlock (LOCK) : 0)
 | 
			
		||||
# define glthread_rwlock_wrlock(LOCK) \
 | 
			
		||||
    (thread_in_use () ? rw_wrlock (LOCK) : 0)
 | 
			
		||||
# define glthread_rwlock_unlock(LOCK) \
 | 
			
		||||
    (thread_in_use () ? rw_unlock (LOCK) : 0)
 | 
			
		||||
# define glthread_rwlock_destroy(LOCK) \
 | 
			
		||||
    (thread_in_use () ? rwlock_destroy (LOCK) : 0)
 | 
			
		||||
 | 
			
		||||
/* --------------------- gl_recursive_lock_t datatype --------------------- */
 | 
			
		||||
 | 
			
		||||
/* Old Solaris threads did not have recursive locks.
 | 
			
		||||
   We have to implement them ourselves.  */
 | 
			
		||||
 | 
			
		||||
typedef struct
 | 
			
		||||
        {
 | 
			
		||||
          mutex_t mutex;
 | 
			
		||||
          thread_t owner;
 | 
			
		||||
          unsigned long depth;
 | 
			
		||||
        }
 | 
			
		||||
        gl_recursive_lock_t;
 | 
			
		||||
# define gl_recursive_lock_define(STORAGECLASS, NAME) \
 | 
			
		||||
    STORAGECLASS gl_recursive_lock_t NAME;
 | 
			
		||||
# define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
 | 
			
		||||
    STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
 | 
			
		||||
# define gl_recursive_lock_initializer \
 | 
			
		||||
    { DEFAULTMUTEX, (thread_t) 0, 0 }
 | 
			
		||||
# define glthread_recursive_lock_init(LOCK) \
 | 
			
		||||
    (thread_in_use () ? glthread_recursive_lock_init_multithreaded (LOCK) : 0)
 | 
			
		||||
# define glthread_recursive_lock_lock(LOCK) \
 | 
			
		||||
    (thread_in_use () ? glthread_recursive_lock_lock_multithreaded (LOCK) : 0)
 | 
			
		||||
# define glthread_recursive_lock_unlock(LOCK) \
 | 
			
		||||
    (thread_in_use () ? glthread_recursive_lock_unlock_multithreaded (LOCK) : 0)
 | 
			
		||||
# define glthread_recursive_lock_destroy(LOCK) \
 | 
			
		||||
    (thread_in_use () ? glthread_recursive_lock_destroy_multithreaded (LOCK) : 0)
 | 
			
		||||
extern int glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock);
 | 
			
		||||
extern int glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock);
 | 
			
		||||
extern int glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock);
 | 
			
		||||
extern int glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock);
 | 
			
		||||
 | 
			
		||||
/* -------------------------- gl_once_t datatype -------------------------- */
 | 
			
		||||
 | 
			
		||||
typedef struct
 | 
			
		||||
        {
 | 
			
		||||
          volatile int inited;
 | 
			
		||||
          mutex_t mutex;
 | 
			
		||||
        }
 | 
			
		||||
        gl_once_t;
 | 
			
		||||
# define gl_once_define(STORAGECLASS, NAME) \
 | 
			
		||||
    STORAGECLASS gl_once_t NAME = { 0, DEFAULTMUTEX };
 | 
			
		||||
# define glthread_once(ONCE_CONTROL, INITFUNCTION) \
 | 
			
		||||
    (thread_in_use ()                                                          \
 | 
			
		||||
     ? glthread_once_multithreaded (ONCE_CONTROL, INITFUNCTION)                \
 | 
			
		||||
     : (glthread_once_singlethreaded (ONCE_CONTROL) ? (INITFUNCTION (), 0) : 0))
 | 
			
		||||
extern int glthread_once_multithreaded (gl_once_t *once_control, void (*initfunction) (void));
 | 
			
		||||
extern int glthread_once_singlethreaded (gl_once_t *once_control);
 | 
			
		||||
 | 
			
		||||
# ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
# endif
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* ========================================================================= */
 | 
			
		||||
 | 
			
		||||
#if USE_WINDOWS_THREADS
 | 
			
		||||
 | 
			
		||||
# define WIN32_LEAN_AND_MEAN  /* avoid including junk */
 | 
			
		||||
# include <windows.h>
 | 
			
		||||
 | 
			
		||||
# include "windows-mutex.h"
 | 
			
		||||
# include "windows-rwlock.h"
 | 
			
		||||
# include "windows-recmutex.h"
 | 
			
		||||
# include "windows-once.h"
 | 
			
		||||
 | 
			
		||||
# ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
# endif
 | 
			
		||||
| 
						 | 
				
			
			@ -633,127 +555,69 @@ extern "C" {
 | 
			
		|||
/* There is no way to statically initialize a CRITICAL_SECTION.  It needs
 | 
			
		||||
   to be done lazily, once only.  For this we need spinlocks.  */
 | 
			
		||||
 | 
			
		||||
typedef struct { volatile int done; volatile long started; } gl_spinlock_t;
 | 
			
		||||
 | 
			
		||||
/* -------------------------- gl_lock_t datatype -------------------------- */
 | 
			
		||||
 | 
			
		||||
typedef struct
 | 
			
		||||
        {
 | 
			
		||||
          gl_spinlock_t guard; /* protects the initialization */
 | 
			
		||||
          CRITICAL_SECTION lock;
 | 
			
		||||
        }
 | 
			
		||||
        gl_lock_t;
 | 
			
		||||
typedef glwthread_mutex_t gl_lock_t;
 | 
			
		||||
# define gl_lock_define(STORAGECLASS, NAME) \
 | 
			
		||||
    STORAGECLASS gl_lock_t NAME;
 | 
			
		||||
# define gl_lock_define_initialized(STORAGECLASS, NAME) \
 | 
			
		||||
    STORAGECLASS gl_lock_t NAME = gl_lock_initializer;
 | 
			
		||||
# define gl_lock_initializer \
 | 
			
		||||
    { { 0, -1 } }
 | 
			
		||||
    GLWTHREAD_MUTEX_INIT
 | 
			
		||||
# define glthread_lock_init(LOCK) \
 | 
			
		||||
    (glthread_lock_init_func (LOCK), 0)
 | 
			
		||||
    (glwthread_mutex_init (LOCK), 0)
 | 
			
		||||
# define glthread_lock_lock(LOCK) \
 | 
			
		||||
    glthread_lock_lock_func (LOCK)
 | 
			
		||||
    glwthread_mutex_lock (LOCK)
 | 
			
		||||
# define glthread_lock_unlock(LOCK) \
 | 
			
		||||
    glthread_lock_unlock_func (LOCK)
 | 
			
		||||
    glwthread_mutex_unlock (LOCK)
 | 
			
		||||
# define glthread_lock_destroy(LOCK) \
 | 
			
		||||
    glthread_lock_destroy_func (LOCK)
 | 
			
		||||
extern void glthread_lock_init_func (gl_lock_t *lock);
 | 
			
		||||
extern int glthread_lock_lock_func (gl_lock_t *lock);
 | 
			
		||||
extern int glthread_lock_unlock_func (gl_lock_t *lock);
 | 
			
		||||
extern int glthread_lock_destroy_func (gl_lock_t *lock);
 | 
			
		||||
    glwthread_mutex_destroy (LOCK)
 | 
			
		||||
 | 
			
		||||
/* ------------------------- gl_rwlock_t datatype ------------------------- */
 | 
			
		||||
 | 
			
		||||
/* It is impossible to implement read-write locks using plain locks, without
 | 
			
		||||
   introducing an extra thread dedicated to managing read-write locks.
 | 
			
		||||
   Therefore here we need to use the low-level Event type.  */
 | 
			
		||||
 | 
			
		||||
typedef struct
 | 
			
		||||
        {
 | 
			
		||||
          HANDLE *array; /* array of waiting threads, each represented by an event */
 | 
			
		||||
          unsigned int count; /* number of waiting threads */
 | 
			
		||||
          unsigned int alloc; /* length of allocated array */
 | 
			
		||||
          unsigned int offset; /* index of first waiting thread in array */
 | 
			
		||||
        }
 | 
			
		||||
        gl_carray_waitqueue_t;
 | 
			
		||||
typedef struct
 | 
			
		||||
        {
 | 
			
		||||
          gl_spinlock_t guard; /* protects the initialization */
 | 
			
		||||
          CRITICAL_SECTION lock; /* protects the remaining fields */
 | 
			
		||||
          gl_carray_waitqueue_t waiting_readers; /* waiting readers */
 | 
			
		||||
          gl_carray_waitqueue_t waiting_writers; /* waiting writers */
 | 
			
		||||
          int runcount; /* number of readers running, or -1 when a writer runs */
 | 
			
		||||
        }
 | 
			
		||||
        gl_rwlock_t;
 | 
			
		||||
typedef glwthread_rwlock_t gl_rwlock_t;
 | 
			
		||||
# define gl_rwlock_define(STORAGECLASS, NAME) \
 | 
			
		||||
    STORAGECLASS gl_rwlock_t NAME;
 | 
			
		||||
# define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
 | 
			
		||||
    STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
 | 
			
		||||
# define gl_rwlock_initializer \
 | 
			
		||||
    { { 0, -1 } }
 | 
			
		||||
    GLWTHREAD_RWLOCK_INIT
 | 
			
		||||
# define glthread_rwlock_init(LOCK) \
 | 
			
		||||
    (glthread_rwlock_init_func (LOCK), 0)
 | 
			
		||||
    (glwthread_rwlock_init (LOCK), 0)
 | 
			
		||||
# define glthread_rwlock_rdlock(LOCK) \
 | 
			
		||||
    glthread_rwlock_rdlock_func (LOCK)
 | 
			
		||||
    glwthread_rwlock_rdlock (LOCK)
 | 
			
		||||
# define glthread_rwlock_wrlock(LOCK) \
 | 
			
		||||
    glthread_rwlock_wrlock_func (LOCK)
 | 
			
		||||
    glwthread_rwlock_wrlock (LOCK)
 | 
			
		||||
# define glthread_rwlock_unlock(LOCK) \
 | 
			
		||||
    glthread_rwlock_unlock_func (LOCK)
 | 
			
		||||
    glwthread_rwlock_unlock (LOCK)
 | 
			
		||||
# define glthread_rwlock_destroy(LOCK) \
 | 
			
		||||
    glthread_rwlock_destroy_func (LOCK)
 | 
			
		||||
extern void glthread_rwlock_init_func (gl_rwlock_t *lock);
 | 
			
		||||
extern int glthread_rwlock_rdlock_func (gl_rwlock_t *lock);
 | 
			
		||||
extern int glthread_rwlock_wrlock_func (gl_rwlock_t *lock);
 | 
			
		||||
extern int glthread_rwlock_unlock_func (gl_rwlock_t *lock);
 | 
			
		||||
extern int glthread_rwlock_destroy_func (gl_rwlock_t *lock);
 | 
			
		||||
    glwthread_rwlock_destroy (LOCK)
 | 
			
		||||
 | 
			
		||||
/* --------------------- gl_recursive_lock_t datatype --------------------- */
 | 
			
		||||
 | 
			
		||||
/* The native Windows documentation says that CRITICAL_SECTION already
 | 
			
		||||
   implements a recursive lock.  But we need not rely on it: It's easy to
 | 
			
		||||
   implement a recursive lock without this assumption.  */
 | 
			
		||||
 | 
			
		||||
typedef struct
 | 
			
		||||
        {
 | 
			
		||||
          gl_spinlock_t guard; /* protects the initialization */
 | 
			
		||||
          DWORD owner;
 | 
			
		||||
          unsigned long depth;
 | 
			
		||||
          CRITICAL_SECTION lock;
 | 
			
		||||
        }
 | 
			
		||||
        gl_recursive_lock_t;
 | 
			
		||||
typedef glwthread_recmutex_t gl_recursive_lock_t;
 | 
			
		||||
# define gl_recursive_lock_define(STORAGECLASS, NAME) \
 | 
			
		||||
    STORAGECLASS gl_recursive_lock_t NAME;
 | 
			
		||||
# define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
 | 
			
		||||
    STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
 | 
			
		||||
# define gl_recursive_lock_initializer \
 | 
			
		||||
    { { 0, -1 }, 0, 0 }
 | 
			
		||||
    GLWTHREAD_RECMUTEX_INIT
 | 
			
		||||
# define glthread_recursive_lock_init(LOCK) \
 | 
			
		||||
    (glthread_recursive_lock_init_func (LOCK), 0)
 | 
			
		||||
    (glwthread_recmutex_init (LOCK), 0)
 | 
			
		||||
# define glthread_recursive_lock_lock(LOCK) \
 | 
			
		||||
    glthread_recursive_lock_lock_func (LOCK)
 | 
			
		||||
    glwthread_recmutex_lock (LOCK)
 | 
			
		||||
# define glthread_recursive_lock_unlock(LOCK) \
 | 
			
		||||
    glthread_recursive_lock_unlock_func (LOCK)
 | 
			
		||||
    glwthread_recmutex_unlock (LOCK)
 | 
			
		||||
# define glthread_recursive_lock_destroy(LOCK) \
 | 
			
		||||
    glthread_recursive_lock_destroy_func (LOCK)
 | 
			
		||||
extern void glthread_recursive_lock_init_func (gl_recursive_lock_t *lock);
 | 
			
		||||
extern int glthread_recursive_lock_lock_func (gl_recursive_lock_t *lock);
 | 
			
		||||
extern int glthread_recursive_lock_unlock_func (gl_recursive_lock_t *lock);
 | 
			
		||||
extern int glthread_recursive_lock_destroy_func (gl_recursive_lock_t *lock);
 | 
			
		||||
    glwthread_recmutex_destroy (LOCK)
 | 
			
		||||
 | 
			
		||||
/* -------------------------- gl_once_t datatype -------------------------- */
 | 
			
		||||
 | 
			
		||||
typedef struct
 | 
			
		||||
        {
 | 
			
		||||
          volatile int inited;
 | 
			
		||||
          volatile long started;
 | 
			
		||||
          CRITICAL_SECTION lock;
 | 
			
		||||
        }
 | 
			
		||||
        gl_once_t;
 | 
			
		||||
typedef glwthread_once_t gl_once_t;
 | 
			
		||||
# define gl_once_define(STORAGECLASS, NAME) \
 | 
			
		||||
    STORAGECLASS gl_once_t NAME = { -1, -1 };
 | 
			
		||||
    STORAGECLASS gl_once_t NAME = GLWTHREAD_ONCE_INIT;
 | 
			
		||||
# define glthread_once(ONCE_CONTROL, INITFUNCTION) \
 | 
			
		||||
    (glthread_once_func (ONCE_CONTROL, INITFUNCTION), 0)
 | 
			
		||||
extern void glthread_once_func (gl_once_t *once_control, void (*initfunction) (void));
 | 
			
		||||
    (glwthread_once (ONCE_CONTROL, INITFUNCTION), 0)
 | 
			
		||||
 | 
			
		||||
# ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -763,7 +627,7 @@ extern void glthread_once_func (gl_once_t *once_control, void (*initfunction) (v
 | 
			
		|||
 | 
			
		||||
/* ========================================================================= */
 | 
			
		||||
 | 
			
		||||
#if !(USE_POSIX_THREADS || USE_PTH_THREADS || USE_SOLARIS_THREADS || USE_WINDOWS_THREADS)
 | 
			
		||||
#if !(USE_ISOC_THREADS || USE_POSIX_THREADS || USE_ISOC_AND_POSIX_THREADS || USE_WINDOWS_THREADS)
 | 
			
		||||
 | 
			
		||||
/* Provide dummy implementation if threads are not supported.  */
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,18 +1,18 @@
 | 
			
		|||
/* Multithreading primitives.
 | 
			
		||||
   Copyright (C) 2005-2013 Free Software Foundation, Inc.
 | 
			
		||||
   Copyright (C) 2005-2023 Free Software Foundation, Inc.
 | 
			
		||||
 | 
			
		||||
   This program is free software; you can redistribute it and/or modify
 | 
			
		||||
   it under the terms of the GNU General Public License as published by
 | 
			
		||||
   the Free Software Foundation; either version 3, or (at your option)
 | 
			
		||||
   any later version.
 | 
			
		||||
   This file is free software: you can redistribute it and/or modify
 | 
			
		||||
   it under the terms of the GNU Lesser General Public License as
 | 
			
		||||
   published by the Free Software Foundation; either version 2.1 of the
 | 
			
		||||
   License, or (at your option) any later version.
 | 
			
		||||
 | 
			
		||||
   This program is distributed in the hope that it will be useful,
 | 
			
		||||
   This file is distributed in the hope that it will be useful,
 | 
			
		||||
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
   GNU General Public License for more details.
 | 
			
		||||
   GNU Lesser General Public License for more details.
 | 
			
		||||
 | 
			
		||||
   You should have received a copy of the GNU General Public License
 | 
			
		||||
   along with this program; if not, see <http://www.gnu.org/licenses/>.  */
 | 
			
		||||
   You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 | 
			
		||||
 | 
			
		||||
/* Written by Bruno Haible <bruno@clisp.org>, 2005.  */
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -20,15 +20,48 @@
 | 
			
		|||
 | 
			
		||||
/* ========================================================================= */
 | 
			
		||||
 | 
			
		||||
#if USE_POSIX_THREADS
 | 
			
		||||
#if USE_POSIX_THREADS || USE_ISOC_AND_POSIX_THREADS
 | 
			
		||||
 | 
			
		||||
/* Use the POSIX threads library.  */
 | 
			
		||||
 | 
			
		||||
# include <errno.h>
 | 
			
		||||
# include <pthread.h>
 | 
			
		||||
# include <stdlib.h>
 | 
			
		||||
 | 
			
		||||
# if PTHREAD_IN_USE_DETECTION_HARD
 | 
			
		||||
 | 
			
		||||
#  if defined __FreeBSD__ || defined __DragonFly__                 /* FreeBSD */
 | 
			
		||||
 | 
			
		||||
/* Test using pthread_key_create.  */
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
glthread_in_use (void)
 | 
			
		||||
{
 | 
			
		||||
  static int tested;
 | 
			
		||||
  static int result; /* 1: linked with -lpthread, 0: only with libc */
 | 
			
		||||
 | 
			
		||||
  if (!tested)
 | 
			
		||||
    {
 | 
			
		||||
      pthread_key_t key;
 | 
			
		||||
      int err = pthread_key_create (&key, NULL);
 | 
			
		||||
 | 
			
		||||
      if (err == ENOSYS)
 | 
			
		||||
        result = 0;
 | 
			
		||||
      else
 | 
			
		||||
        {
 | 
			
		||||
          result = 1;
 | 
			
		||||
          if (err == 0)
 | 
			
		||||
            pthread_key_delete (key);
 | 
			
		||||
        }
 | 
			
		||||
      tested = 1;
 | 
			
		||||
    }
 | 
			
		||||
  return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#  else                                                     /* Solaris, HP-UX */
 | 
			
		||||
 | 
			
		||||
/* Test using pthread_create.  */
 | 
			
		||||
 | 
			
		||||
/* The function to be executed by a dummy thread.  */
 | 
			
		||||
static void *
 | 
			
		||||
dummy_thread_func (void *arg)
 | 
			
		||||
| 
						 | 
				
			
			@ -62,6 +95,8 @@ glthread_in_use (void)
 | 
			
		|||
  return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#  endif
 | 
			
		||||
 | 
			
		||||
# endif
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue