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