summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruno Haible <bruno@clisp.org>2019-11-27 06:03:21 +0100
committerBruno Haible <bruno@clisp.org>2019-11-27 06:03:21 +0100
commit721d00b4505054875aa5530c230ca9ede5452d96 (patch)
treeb540f6c499f77f67ccd084610ad321c44409f855
parent42a045242f9d156becfb4d3fb63dcc607230369a (diff)
downloadgnulib-721d00b4505054875aa5530c230ca9ede5452d96.tar.gz
New options --enable-threads=isoc and --enable-threads=isoc+posix.
* m4/threadlib.m4 (gl_THREADLIB_EARLY_BODY): Accept the options --enable-threads=isoc and --enable-threads=isoc+posix. (gl_THREADLIB_BODY): Test whether the ISO C threads API is available. When both the ISO C and the POSIX threads API are available, choose USE_ISOC_AND_POSIX_THREADS instead of USE_POSIX_THREADS if --enable-threads=isoc+posix was specified. When only the ISO C threads API is available and --enable-threads=iso was specified, choose USE_ISOC_THREADS. * lib/glthread/lock.h: Add new code for USE_ISOC_THREADS || USE_ISOC_AND_POSIX_THREADS. * lib/glthread/lock.c: Likewise. * lib/glthread/cond.h: Likewise. * lib/glthread/cond.c: Likewise. * lib/glthread/tls.h: Likewise. * lib/glthread/tls.c: Likewise. * lib/glthread/yield.h: Likewise. * lib/glthread/thread.h: Add new code for USE_ISOC_THREADS. Treat USE_ISOC_AND_POSIX_THREADS like USE_POSIX_THREADS. * lib/glthread/thread.c: Likewise. * lib/glthread/threadlib.c: Likewise. * tests/test-lock.c: Save and restore the values of USE_ISOC_THREADS and USE_ISOC_AND_POSIX_THREADS. * tests/test-cond.c: Consider USE_ISOC_THREADS and USE_ISOC_AND_POSIX_THREADS. * tests/test-tls.c: Likewise. * tests/test-thread_create.c (main): Likewise. * tests/test-pthread-cond.c: Likewise. * tests/test-pthread-mutex.c: Likewise. * tests/test-pthread-once2.c: Likewise. * tests/test-pthread-rwlock.c: Likewise. * tests/test-pthread-tss.c: Likewise. * tests/test-pthread_sigmask2.c: Treat USE_ISOC_AND_POSIX_THREADS like USE_POSIX_THREADS.
-rw-r--r--ChangeLog37
-rw-r--r--lib/glthread/cond.c82
-rw-r--r--lib/glthread/cond.h49
-rw-r--r--lib/glthread/lock.c223
-rw-r--r--lib/glthread/lock.h111
-rw-r--r--lib/glthread/thread.c158
-rw-r--r--lib/glthread/thread.h36
-rw-r--r--lib/glthread/threadlib.c2
-rw-r--r--lib/glthread/tls.c6
-rw-r--r--lib/glthread/tls.h24
-rw-r--r--lib/glthread/yield.h23
-rw-r--r--m4/threadlib.m473
-rw-r--r--tests/test-cond.c2
-rw-r--r--tests/test-lock.c16
-rw-r--r--tests/test-pthread-cond.c2
-rw-r--r--tests/test-pthread-mutex.c2
-rw-r--r--tests/test-pthread-once2.c2
-rw-r--r--tests/test-pthread-rwlock.c2
-rw-r--r--tests/test-pthread-tss.c2
-rw-r--r--tests/test-pthread_sigmask2.c2
-rw-r--r--tests/test-thread_create.c2
-rw-r--r--tests/test-tls.c5
22 files changed, 827 insertions, 34 deletions
diff --git a/ChangeLog b/ChangeLog
index d612dce921..bd2330e95e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,40 @@
+2019-11-27 Bruno Haible <bruno@clisp.org>
+
+ New options --enable-threads=isoc and --enable-threads=isoc+posix.
+ * m4/threadlib.m4 (gl_THREADLIB_EARLY_BODY): Accept the options
+ --enable-threads=isoc and --enable-threads=isoc+posix.
+ (gl_THREADLIB_BODY): Test whether the ISO C threads API is available.
+ When both the ISO C and the POSIX threads API are available, choose
+ USE_ISOC_AND_POSIX_THREADS instead of USE_POSIX_THREADS if
+ --enable-threads=isoc+posix was specified. When only the ISO C threads
+ API is available and --enable-threads=iso was specified, choose
+ USE_ISOC_THREADS.
+ * lib/glthread/lock.h: Add new code for USE_ISOC_THREADS ||
+ USE_ISOC_AND_POSIX_THREADS.
+ * lib/glthread/lock.c: Likewise.
+ * lib/glthread/cond.h: Likewise.
+ * lib/glthread/cond.c: Likewise.
+ * lib/glthread/tls.h: Likewise.
+ * lib/glthread/tls.c: Likewise.
+ * lib/glthread/yield.h: Likewise.
+ * lib/glthread/thread.h: Add new code for USE_ISOC_THREADS. Treat
+ USE_ISOC_AND_POSIX_THREADS like USE_POSIX_THREADS.
+ * lib/glthread/thread.c: Likewise.
+ * lib/glthread/threadlib.c: Likewise.
+ * tests/test-lock.c: Save and restore the values of USE_ISOC_THREADS and
+ USE_ISOC_AND_POSIX_THREADS.
+ * tests/test-cond.c: Consider USE_ISOC_THREADS and
+ USE_ISOC_AND_POSIX_THREADS.
+ * tests/test-tls.c: Likewise.
+ * tests/test-thread_create.c (main): Likewise.
+ * tests/test-pthread-cond.c: Likewise.
+ * tests/test-pthread-mutex.c: Likewise.
+ * tests/test-pthread-once2.c: Likewise.
+ * tests/test-pthread-rwlock.c: Likewise.
+ * tests/test-pthread-tss.c: Likewise.
+ * tests/test-pthread_sigmask2.c: Treat USE_ISOC_AND_POSIX_THREADS like
+ USE_POSIX_THREADS.
+
2019-11-24 Bruno Haible <bruno@clisp.org>
mbrtowc: Modernize autoconf test.
diff --git a/lib/glthread/cond.c b/lib/glthread/cond.c
index f6a06cc9fa..df166bfe4b 100644
--- a/lib/glthread/cond.c
+++ b/lib/glthread/cond.c
@@ -24,6 +24,88 @@
/* ========================================================================= */
+#if USE_ISOC_THREADS || USE_ISOC_AND_POSIX_THREADS
+
+int
+glthread_cond_init (gl_cond_t *condition)
+{
+ if (cnd_init (&condition->condition) != thrd_success)
+ return ENOMEM;
+ condition->init_needed = 0;
+ return 0;
+}
+
+int
+glthread_cond_wait (gl_cond_t *condition, gl_lock_t *lock)
+{
+ if (condition->init_needed)
+ call_once (&condition->init_once, condition->init_func);
+ if (lock->init_needed)
+ call_once (&lock->init_once, lock->init_func);
+ if (cnd_wait (&condition->condition, &lock->mutex) != thrd_success)
+ return EINVAL;
+ return 0;
+}
+
+int
+glthread_cond_timedwait (gl_cond_t *condition, gl_lock_t *lock,
+ const struct timespec *abstime)
+{
+ if (condition->init_needed)
+ call_once (&condition->init_once, condition->init_func);
+ if (lock->init_needed)
+ call_once (&lock->init_once, lock->init_func);
+ switch (cnd_timedwait (&condition->condition, &lock->mutex, abstime))
+ {
+ case thrd_success:
+ break;
+ case thrd_timedout:
+ return ETIMEDOUT;
+ default:
+ return EINVAL;
+ }
+ return 0;
+}
+
+int
+glthread_cond_signal (gl_cond_t *condition)
+{
+ if (condition->init_needed)
+ call_once (&condition->init_once, condition->init_func);
+ if (cnd_signal (&condition->condition) != thrd_success)
+ return EINVAL;
+ return 0;
+}
+
+int
+glthread_cond_broadcast (gl_cond_t *condition)
+{
+ if (condition->init_needed)
+ call_once (&condition->init_once, condition->init_func);
+ if (cnd_broadcast (&condition->condition) != thrd_success)
+ return EINVAL;
+ return 0;
+}
+
+int
+glthread_cond_destroy (gl_cond_t *condition)
+{
+ if (condition->init_needed)
+ call_once (&condition->init_once, condition->init_func);
+ cnd_destroy (&condition->condition);
+ return 0;
+}
+
+#endif
+
+/* ========================================================================= */
+
+#if USE_POSIX_THREADS
+
+#endif
+
+/* ========================================================================= */
+
#if USE_WINDOWS_THREADS
#endif
diff --git a/lib/glthread/cond.h b/lib/glthread/cond.h
index 4c6f4d94c0..cd1ec98ec8 100644
--- a/lib/glthread/cond.h
+++ b/lib/glthread/cond.h
@@ -76,6 +76,53 @@ _GL_INLINE_HEADER_BEGIN
/* ========================================================================= */
+#if USE_ISOC_THREADS || USE_ISOC_AND_POSIX_THREADS
+
+/* Use the ISO C threads library. */
+
+# include <threads.h>
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+/* -------------------------- gl_cond_t datatype -------------------------- */
+
+typedef struct
+ {
+ int volatile init_needed;
+ once_flag init_once;
+ void (*init_func) (void);
+ cnd_t condition;
+ }
+ gl_cond_t;
+# define gl_cond_define(STORAGECLASS, NAME) \
+ STORAGECLASS gl_cond_t NAME;
+# define gl_cond_define_initialized(STORAGECLASS, NAME) \
+ static void _atomic_init_##NAME (void); \
+ STORAGECLASS gl_cond_t NAME = \
+ { 1, ONCE_FLAG_INIT, _atomic_init_##NAME }; \
+ static void _atomic_init_##NAME (void) \
+ { \
+ if (glthread_cond_init (&(NAME))) \
+ abort (); \
+ }
+extern int glthread_cond_init (gl_cond_t *condition);
+extern int glthread_cond_wait (gl_cond_t *condition, gl_lock_t *lock);
+extern int glthread_cond_timedwait (gl_cond_t *condition, gl_lock_t *lock,
+ const struct timespec *abstime);
+extern int glthread_cond_signal (gl_cond_t *condition);
+extern int glthread_cond_broadcast (gl_cond_t *condition);
+extern int glthread_cond_destroy (gl_cond_t *condition);
+
+# ifdef __cplusplus
+}
+# endif
+
+#endif
+
+/* ========================================================================= */
+
#if USE_POSIX_THREADS
/* Use the POSIX threads library. */
@@ -214,7 +261,7 @@ typedef glwthread_cond_t gl_cond_t;
/* ========================================================================= */
-#if !(USE_POSIX_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. */
diff --git a/lib/glthread/lock.c b/lib/glthread/lock.c
index 852d84d3bb..2537839de5 100644
--- a/lib/glthread/lock.c
+++ b/lib/glthread/lock.c
@@ -23,6 +23,229 @@
/* ========================================================================= */
+#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 -------------------------- */
diff --git a/lib/glthread/lock.h b/lib/glthread/lock.h
index 78dd67f29f..ffbec15143 100644
--- a/lib/glthread/lock.h
+++ b/lib/glthread/lock.h
@@ -92,6 +92,115 @@
/* ========================================================================= */
+#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
/* Use the POSIX threads library. */
@@ -502,7 +611,7 @@ typedef glwthread_once_t gl_once_t;
/* ========================================================================= */
-#if !(USE_POSIX_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. */
diff --git a/lib/glthread/thread.c b/lib/glthread/thread.c
index 776bfb6bf4..18e7b237d6 100644
--- a/lib/glthread/thread.c
+++ b/lib/glthread/thread.c
@@ -28,7 +28,163 @@
/* ========================================================================= */
-#if USE_POSIX_THREADS
+#if USE_ISOC_THREADS
+
+struct thrd_with_exitvalue
+{
+ thrd_t volatile tid;
+ void * volatile exitvalue;
+};
+
+/* The Thread-Specific Storage (TSS) key that allows to access each thread's
+ 'struct thrd_with_exitvalue *' pointer. */
+static tss_t thrd_with_exitvalue_key;
+
+/* Initializes thrd_with_exitvalue_key.
+ This function must only be called once. */
+static void
+do_init_thrd_with_exitvalue_key (void)
+{
+ if (tss_create (&thrd_with_exitvalue_key, NULL) != thrd_success)
+ abort ();
+}
+
+/* Initializes thrd_with_exitvalue_key. */
+static void
+init_thrd_with_exitvalue_key (void)
+{
+ static once_flag once = ONCE_FLAG_INIT;
+ call_once (&once, do_init_thrd_with_exitvalue_key);
+}
+
+typedef union
+ {
+ struct thrd_with_exitvalue t;
+ struct
+ {
+ thrd_t tid; /* reserve memory for t.tid */
+ void *(*mainfunc) (void *);
+ void *arg;
+ } a;
+ }
+ main_arg_t;
+
+static int
+thrd_main_func (void *pmarg)
+{
+ /* Unpack the object that combines mainfunc and arg. */
+ main_arg_t *main_arg = (main_arg_t *) pmarg;
+ void *(*mainfunc) (void *) = main_arg->a.mainfunc;
+ void *arg = main_arg->a.arg;
+
+ if (tss_set (thrd_with_exitvalue_key, &main_arg->t) != thrd_success)
+ abort ();
+
+ /* Execute mainfunc, with arg as argument. */
+ {
+ void *exitvalue = mainfunc (arg);
+ /* Store the exitvalue, for use by glthread_join(). */
+ main_arg->t.exitvalue = exitvalue;
+ return 0;
+ }
+}
+
+int
+glthread_create (gl_thread_t *threadp, void *(*mainfunc) (void *), void *arg)
+{
+ init_thrd_with_exitvalue_key ();
+ {
+ /* Combine mainfunc and arg in a single object.
+ A stack-allocated object does not work, because it would be out of
+ existence when thrd_create returns before thrd_main_func is
+ entered. So, allocate it in the heap. */
+ main_arg_t *main_arg = (main_arg_t *) malloc (sizeof (main_arg_t));
+ if (main_arg == NULL)
+ return ENOMEM;
+ main_arg->a.mainfunc = mainfunc;
+ main_arg->a.arg = arg;
+ switch (thrd_create ((thrd_t *) &main_arg->t.tid, thrd_main_func, main_arg))
+ {
+ case thrd_success:
+ break;
+ case thrd_nomem:
+ free (main_arg);
+ return ENOMEM;
+ default:
+ free (main_arg);
+ return EAGAIN;
+ }
+ *threadp = &main_arg->t;
+ return 0;
+ }
+}
+
+gl_thread_t
+gl_thread_self (void)
+{
+ init_thrd_with_exitvalue_key ();
+ {
+ gl_thread_t thread =
+ (struct thrd_with_exitvalue *) tss_get (thrd_with_exitvalue_key);
+ if (thread == NULL)
+ {
+ /* This happens only in threads that have not been created through
+ glthread_create(), such as the main thread. */
+ for (;;)
+ {
+ thread =
+ (struct thrd_with_exitvalue *)
+ malloc (sizeof (struct thrd_with_exitvalue));
+ if (thread != NULL)
+ break;
+ /* Memory allocation failed. There is not much we can do. Have to
+ busy-loop, waiting for the availability of memory. */
+ {
+ struct timespec ts;
+ ts.tv_sec = 1;
+ ts.tv_nsec = 0;
+ thrd_sleep (&ts, NULL);
+ }
+ }
+ thread->tid = thrd_current ();
+ thread->exitvalue = NULL; /* just to be deterministic */
+ if (tss_set (thrd_with_exitvalue_key, thread) != thrd_success)
+ abort ();
+ }
+ return thread;
+ }
+}
+
+int
+glthread_join (gl_thread_t thread, void **return_value_ptr)
+{
+ /* On Solaris 11.4, thrd_join crashes when the second argument we pass is
+ NULL. */
+ int dummy;
+
+ if (thread == gl_thread_self ())
+ return EINVAL;
+ if (thrd_join (thread->tid, &dummy) != thrd_success)
+ return EINVAL;
+ if (return_value_ptr != NULL)
+ *return_value_ptr = thread->exitvalue;
+ free (thread);
+ return 0;
+}
+
+_Noreturn void
+gl_thread_exit (void *return_value)
+{
+ gl_thread_t thread = gl_thread_self ();
+ thread->exitvalue = return_value;
+ thrd_exit (0);
+}
+
+#endif
+
+/* ========================================================================= */
+
+#if USE_POSIX_THREADS || USE_ISOC_AND_POSIX_THREADS
#include <pthread.h>
diff --git a/lib/glthread/thread.h b/lib/glthread/thread.h
index 2c72cc5cdb..c68a99b648 100644
--- a/lib/glthread/thread.h
+++ b/lib/glthread/thread.h
@@ -93,7 +93,39 @@ _GL_INLINE_HEADER_BEGIN
/* ========================================================================= */
-#if USE_POSIX_THREADS
+#if USE_ISOC_THREADS
+
+/* Use the ISO C threads library. */
+
+# include <threads.h>
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+/* -------------------------- gl_thread_t datatype -------------------------- */
+
+typedef struct thrd_with_exitvalue *gl_thread_t;
+extern int glthread_create (gl_thread_t *threadp,
+ void *(*func) (void *), void *arg);
+# define glthread_sigmask(HOW, SET, OSET) \
+ pthread_sigmask (HOW, SET, OSET)
+extern int glthread_join (gl_thread_t thread, void **return_value_ptr);
+extern gl_thread_t gl_thread_self (void);
+# define gl_thread_self_pointer() \
+ (void *) gl_thread_self ()
+extern _Noreturn void gl_thread_exit (void *return_value);
+# define glthread_atfork(PREPARE_FUNC, PARENT_FUNC, CHILD_FUNC) 0
+
+# ifdef __cplusplus
+}
+# endif
+
+#endif
+
+/* ========================================================================= */
+
+#if USE_POSIX_THREADS || USE_ISOC_AND_POSIX_THREADS
/* Use the POSIX threads library. */
@@ -258,7 +290,7 @@ typedef glwthread_thread_t gl_thread_t;
/* ========================================================================= */
-#if !(USE_POSIX_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. */
diff --git a/lib/glthread/threadlib.c b/lib/glthread/threadlib.c
index bca14d9739..4455ffc929 100644
--- a/lib/glthread/threadlib.c
+++ b/lib/glthread/threadlib.c
@@ -20,7 +20,7 @@
/* ========================================================================= */
-#if USE_POSIX_THREADS
+#if USE_POSIX_THREADS || USE_ISOC_AND_POSIX_THREADS
/* Use the POSIX threads library. */
diff --git a/lib/glthread/tls.c b/lib/glthread/tls.c
index d182266c56..90a50e9e69 100644
--- a/lib/glthread/tls.c
+++ b/lib/glthread/tls.c
@@ -22,6 +22,12 @@
/* ========================================================================= */
+#if USE_ISOC_THREADS || USE_ISOC_AND_POSIX_THREADS
+
+#endif
+
+/* ========================================================================= */
+
#if USE_POSIX_THREADS
#endif
diff --git a/lib/glthread/tls.h b/lib/glthread/tls.h
index cfc96061c1..32775fc6bc 100644
--- a/lib/glthread/tls.h
+++ b/lib/glthread/tls.h
@@ -58,6 +58,28 @@
/* ========================================================================= */
+#if USE_ISOC_THREADS || USE_ISOC_AND_POSIX_THREADS
+
+/* Use the ISO C threads library. */
+
+# include <threads.h>
+
+/* ------------------------- gl_tls_key_t datatype ------------------------- */
+
+typedef tss_t gl_tls_key_t;
+# define glthread_tls_key_init(KEY, DESTRUCTOR) \
+ (tss_create (KEY, DESTRUCTOR) != thrd_success ? EAGAIN : 0)
+# define gl_tls_get(NAME) \
+ tss_get (NAME)
+# define glthread_tls_set(KEY, POINTER) \
+ (tss_set (*(KEY), (POINTER)) != thrd_success ? ENOMEM : 0)
+# define glthread_tls_key_destroy(KEY) \
+ (tss_delete (*(KEY)), 0)
+
+#endif
+
+/* ========================================================================= */
+
#if USE_POSIX_THREADS
/* Use the POSIX threads library. */
@@ -149,7 +171,7 @@ typedef glwthread_tls_key_t gl_tls_key_t;
/* ========================================================================= */
-#if !(USE_POSIX_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. */
diff --git a/lib/glthread/yield.h b/lib/glthread/yield.h
index 27bca55b79..a707bf5e62 100644
--- a/lib/glthread/yield.h
+++ b/lib/glthread/yield.h
@@ -25,6 +25,27 @@
/* ========================================================================= */
+#if USE_ISOC_THREADS || USE_ISOC_AND_POSIX_THREADS
+
+/* Use the ISO C threads library. */
+
+# include <threads.h>
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+# define gl_thread_yield() \
+ thrd_yield ()
+
+# ifdef __cplusplus
+}
+# endif
+
+#endif
+
+/* ========================================================================= */
+
#if USE_POSIX_THREADS
/* Use the POSIX threads library. */
@@ -66,7 +87,7 @@ extern "C" {
/* ========================================================================= */
-#if !(USE_POSIX_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. */
diff --git a/m4/threadlib.m4 b/m4/threadlib.m4
index 045d9dad29..7972cfaebc 100644
--- a/m4/threadlib.m4
+++ b/m4/threadlib.m4
@@ -1,4 +1,4 @@
-# threadlib.m4 serial 20
+# threadlib.m4 serial 21
dnl Copyright (C) 2005-2019 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
@@ -16,7 +16,13 @@ dnl (it must be placed before the invocation of gl_THREADLIB_EARLY!), then the
dnl default is 'no', otherwise it is system dependent. In both cases, the user
dnl can change the choice through the options --enable-threads=choice or
dnl --disable-threads.
-dnl Defines at most one of the macros USE_POSIX_THREADS, USE_WINDOWS_THREADS.
+dnl Defines at most one of the macros USE_ISOC_THREADS, USE_POSIX_THREADS,
+dnl USE_ISOC_AND_POSIX_THREADS, USE_WINDOWS_THREADS.
+dnl The choice --enable-threads=isoc+posix is available only on platforms that
+dnl have both the ISO C and the POSIX threads APIs. It has the effect of using
+dnl the ISO C API for most things and the POSIX API only for creating and
+dnl controlling threads (because there is no equivalent to pthread_atfork in
+dnl the ISO C API).
dnl Sets the variables LIBTHREAD and LTLIBTHREAD to the linker options for use
dnl in a Makefile (LIBTHREAD for use without libtool, LTLIBTHREAD for use with
dnl libtool).
@@ -54,7 +60,7 @@ AC_DEFUN([gl_THREADLIB_EARLY_BODY],
[m4_divert_text([DEFAULTS], [gl_use_threads_default=])])
m4_divert_text([DEFAULTS], [gl_use_winpthreads_default=])
AC_ARG_ENABLE([threads],
-AC_HELP_STRING([--enable-threads={posix|windows}], [specify multithreading API])m4_ifdef([gl_THREADLIB_DEFAULT_NO], [], [
+AC_HELP_STRING([--enable-threads={isoc|posix|isoc+posix|windows}], [specify multithreading API])m4_ifdef([gl_THREADLIB_DEFAULT_NO], [], [
AC_HELP_STRING([--disable-threads], [build without multithread safety])]),
[gl_use_threads=$enableval],
[if test -n "$gl_use_threads_default"; then
@@ -88,8 +94,11 @@ changequote(,)dnl
changequote([,])dnl
fi
])
- if test "$gl_use_threads" = yes || test "$gl_use_threads" = posix; then
- # For using <pthread.h>:
+ if test "$gl_use_threads" = yes \
+ || test "$gl_use_threads" = isoc \
+ || test "$gl_use_threads" = posix \
+ || test "$gl_use_threads" = isoc+posix; then
+ # For using <threads.h> or <pthread.h>:
case "$host_os" in
osf*)
# On OSF/1, the compiler needs the flag -D_REENTRANT so that it
@@ -169,7 +178,26 @@ int main ()
AC_CHECK_HEADERS_ONCE([threads.h])
:
fi
- if test "$gl_use_threads" = yes || test "$gl_use_threads" = posix; then
+ if test "$gl_use_threads" = isoc || test "$gl_use_threads" = isoc+posix; then
+ AC_CHECK_HEADERS_ONCE([threads.h])
+ if test $ac_cv_header_threads_h = yes; then
+ gl_have_isoc_threads=
+ # Test whether both mtx_lock and cnd_timedwait exist in libc.
+ AC_LINK_IFELSE(
+ [AC_LANG_PROGRAM(
+ [[#include <threads.h>
+ #include <stddef.h>
+ mtx_t m;
+ cnd_t c;
+ ]],
+ [[mtx_lock (&m);
+ cnd_timedwait (&c, &m, NULL);]])],
+ [gl_have_isoc_threads=yes])
+ fi
+ fi
+ if test "$gl_use_threads" = yes \
+ || test "$gl_use_threads" = posix \
+ || test "$gl_use_threads" = isoc+posix; then
# On OSF/1, the compiler needs the flag -pthread or -D_REENTRANT so that
# it groks <pthread.h>. It's added above, in gl_THREADLIB_EARLY_BODY.
AC_CHECK_HEADER([pthread.h],
@@ -238,21 +266,34 @@ int main ()
fi
fi
if test -n "$gl_have_pthread"; then
- gl_threads_api=posix
- AC_DEFINE([USE_POSIX_THREADS], [1],
- [Define if the POSIX multithreading library can be used.])
- if test -n "$LIBMULTITHREAD" || test -n "$LTLIBMULTITHREAD"; then
- if case "$gl_cv_have_weak" in *yes) true;; *) false;; esac; then
- AC_DEFINE([USE_POSIX_THREADS_WEAK], [1],
- [Define if references to the POSIX multithreading library should be made weak.])
- LIBTHREAD=
- LTLIBTHREAD=
+ if test "$gl_use_threads" = isoc+posix && test "$gl_have_isoc_threads" = yes; then
+ gl_threads_api='isoc+posix'
+ AC_DEFINE([USE_ISOC_AND_POSIX_THREADS], [1],
+ [Define if the combination of the ISO C and POSIX multithreading APIs can be used.])
+ LIBTHREAD= LTLIBTHREAD=
+ else
+ gl_threads_api=posix
+ AC_DEFINE([USE_POSIX_THREADS], [1],
+ [Define if the POSIX multithreading library can be used.])
+ if test -n "$LIBMULTITHREAD" || test -n "$LTLIBMULTITHREAD"; then
+ if case "$gl_cv_have_weak" in *yes) true;; *) false;; esac; then
+ AC_DEFINE([USE_POSIX_THREADS_WEAK], [1],
+ [Define if references to the POSIX multithreading library should be made weak.])
+ LIBTHREAD= LTLIBTHREAD=
+ fi
fi
fi
fi
fi
fi
- if test -z "$gl_have_pthread"; then
+ if test $gl_threads_api = none; then
+ if test "$gl_use_threads" = isoc && test "$gl_have_isoc_threads" = yes; then
+ gl_threads_api=isoc
+ AC_DEFINE([USE_ISOC_THREADS], [1],
+ [Define if the ISO C multithreading library can be used.])
+ fi
+ fi
+ if test $gl_threads_api = none; then
case "$gl_use_threads" in
yes | windows | win32) # The 'win32' is for backward compatibility.
if { case "$host_os" in
diff --git a/tests/test-cond.c b/tests/test-cond.c
index 794fb2d314..f1374f4350 100644
--- a/tests/test-cond.c
+++ b/tests/test-cond.c
@@ -16,7 +16,7 @@
#include <config.h>
-#if USE_POSIX_THREADS || USE_WINDOWS_THREADS
+#if USE_ISOC_THREADS || USE_POSIX_THREADS || USE_ISOC_AND_POSIX_THREADS || USE_WINDOWS_THREADS
/* Which tests to perform.
Uncomment some of these, to verify that all tests crash if no locking
diff --git a/tests/test-lock.c b/tests/test-lock.c
index 844e5d52e3..1ea81008cd 100644
--- a/tests/test-lock.c
+++ b/tests/test-lock.c
@@ -18,11 +18,17 @@
#include <config.h>
-#if USE_POSIX_THREADS || USE_WINDOWS_THREADS
+#if USE_ISOC_THREADS || USE_POSIX_THREADS || USE_ISOC_AND_POSIX_THREADS || USE_WINDOWS_THREADS
+#if USE_ISOC_THREADS
+# define TEST_ISOC_THREADS 1
+#endif
#if USE_POSIX_THREADS
# define TEST_POSIX_THREADS 1
#endif
+#if USE_ISOC_AND_POSIX_THREADS
+# define TEST_ISOC_AND_POSIX_THREADS 1
+#endif
#if USE_WINDOWS_THREADS
# define TEST_WINDOWS_THREADS 1
#endif
@@ -83,15 +89,23 @@
#include <string.h>
#if !ENABLE_LOCKING
+# undef USE_ISOC_THREADS
# undef USE_POSIX_THREADS
+# undef USE_ISOC_AND_POSIX_THREADS
# undef USE_WINDOWS_THREADS
#endif
#include "glthread/lock.h"
#if !ENABLE_LOCKING
+# if TEST_ISOC_THREADS
+# define USE_ISOC_THREADS 1
+# endif
# if TEST_POSIX_THREADS
# define USE_POSIX_THREADS 1
# endif
+# if TEST_ISOC_AND_POSIX_THREADS
+# define USE_ISOC_AND_POSIX_THREADS 1
+# endif
# if TEST_WINDOWS_THREADS
# define USE_WINDOWS_THREADS 1
# endif
diff --git a/tests/test-pthread-cond.c b/tests/test-pthread-cond.c
index 201b1e15ba..79fc2dcfc6 100644
--- a/tests/test-pthread-cond.c
+++ b/tests/test-pthread-cond.c
@@ -16,7 +16,7 @@
#include <config.h>
-#if USE_POSIX_THREADS || USE_WINDOWS_THREADS
+#if USE_ISOC_THREADS || USE_POSIX_THREADS || USE_ISOC_AND_POSIX_THREADS || USE_WINDOWS_THREADS
/* Which tests to perform.
Uncomment some of these, to verify that all tests crash if no locking
diff --git a/tests/test-pthread-mutex.c b/tests/test-pthread-mutex.c
index 3ea0df6edc..b7aad02ef1 100644
--- a/tests/test-pthread-mutex.c
+++ b/tests/test-pthread-mutex.c
@@ -18,7 +18,7 @@
#include <config.h>
-#if USE_POSIX_THREADS || USE_WINDOWS_THREADS
+#if USE_ISOC_THREADS || USE_POSIX_THREADS || USE_ISOC_AND_POSIX_THREADS || USE_WINDOWS_THREADS
/* Whether to enable locking.
Uncomment this to get a test program without locking, to verify that
diff --git a/tests/test-pthread-once2.c b/tests/test-pthread-once2.c
index 101ee52f2b..6a19c57f2f 100644
--- a/tests/test-pthread-once2.c
+++ b/tests/test-pthread-once2.c
@@ -18,7 +18,7 @@
#include <config.h>
-#if USE_POSIX_THREADS || USE_WINDOWS_THREADS
+#if USE_ISOC_THREADS || USE_POSIX_THREADS || USE_ISOC_AND_POSIX_THREADS || USE_WINDOWS_THREADS
/* Whether to enable locking.
Uncomment this to get a test program without locking, to verify that
diff --git a/tests/test-pthread-rwlock.c b/tests/test-pthread-rwlock.c
index 5d771060e7..c956f6dc9d 100644
--- a/tests/test-pthread-rwlock.c
+++ b/tests/test-pthread-rwlock.c
@@ -18,7 +18,7 @@
#include <config.h>
-#if USE_POSIX_THREADS || USE_WINDOWS_THREADS
+#if USE_ISOC_THREADS || USE_POSIX_THREADS || USE_ISOC_AND_POSIX_THREADS || USE_WINDOWS_THREADS
/* Whether to enable locking.
Uncomment this to get a test program without locking, to verify that
diff --git a/tests/test-pthread-tss.c b/tests/test-pthread-tss.c
index fe13a2d0d8..a421a947b7 100644
--- a/tests/test-pthread-tss.c
+++ b/tests/test-pthread-tss.c
@@ -18,7 +18,7 @@
#include <config.h>
-#if USE_POSIX_THREADS || USE_WINDOWS_THREADS
+#if USE_ISOC_THREADS || USE_POSIX_THREADS || USE_ISOC_AND_POSIX_THREADS || USE_WINDOWS_THREADS
/* Whether to help the scheduler through explicit sched_yield().
Uncomment this to see if the operating system has a fair scheduler. */
diff --git a/tests/test-pthread_sigmask2.c b/tests/test-pthread_sigmask2.c
index 0e5d4dda0f..7209014131 100644
--- a/tests/test-pthread_sigmask2.c
+++ b/tests/test-pthread_sigmask2.c
@@ -27,7 +27,7 @@
#include "macros.h"
-#if USE_POSIX_THREADS
+#if USE_POSIX_THREADS || USE_ISOC_AND_POSIX_THREADS
static pthread_t main_thread;
static pthread_t killer_thread;
diff --git a/tests/test-thread_create.c b/tests/test-thread_create.c
index 0465b2ba81..baaa5d1679 100644
--- a/tests/test-thread_create.c
+++ b/tests/test-thread_create.c
@@ -67,7 +67,7 @@ main ()
}
else
{
-#if USE_POSIX_THREADS || USE_WINDOWS_THREADS
+#if USE_ISOC_THREADS || USE_POSIX_THREADS || USE_ISOC_AND_POSIX_THREADS || USE_WINDOWS_THREADS
fputs ("glthread_create failed\n", stderr);
return 1;
#else
diff --git a/tests/test-tls.c b/tests/test-tls.c
index 9babfe6ad1..d08c605e14 100644
--- a/tests/test-tls.c
+++ b/tests/test-tls.c
@@ -18,8 +18,11 @@
#include <config.h>
-#if USE_POSIX_THREADS || USE_WINDOWS_THREADS
+#if USE_ISOC_THREADS || USE_POSIX_THREADS || USE_ISOC_AND_POSIX_THREADS || USE_WINDOWS_THREADS
+#if USE_ISOC_THREADS || USE_ISOC_AND_POSIX_THREADS
+# define TEST_ISOC_THREADS 1
+#endif
#if USE_POSIX_THREADS
# define TEST_POSIX_THREADS 1
#endif