summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog17
-rw-r--r--doc/posix-functions/thrd_create.texi11
-rw-r--r--doc/posix-functions/thrd_current.texi8
-rw-r--r--doc/posix-functions/thrd_detach.texi8
-rw-r--r--doc/posix-functions/thrd_equal.texi8
-rw-r--r--doc/posix-functions/thrd_exit.texi8
-rw-r--r--doc/posix-functions/thrd_join.texi14
-rw-r--r--doc/posix-functions/thrd_sleep.texi8
-rw-r--r--doc/posix-functions/thrd_yield.texi8
-rw-r--r--lib/thrd.c427
-rw-r--r--m4/thrd.m463
-rw-r--r--modules/thrd33
12 files changed, 581 insertions, 32 deletions
diff --git a/ChangeLog b/ChangeLog
index b536bcbd7b..5d96988342 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,22 @@
2019-06-20 Bruno Haible <bruno@clisp.org>
+ thrd: New module.
+ * lib/thrd.c: New file.
+ * m4/thrd.m4: New file.
+ * modules/thrd: New file.
+ * doc/posix-functions/thrd_current.texi: Mention the new module.
+ * doc/posix-functions/thrd_detach.texi: Likewise.
+ * doc/posix-functions/thrd_equal.texi: Likewise.
+ * doc/posix-functions/thrd_exit.texi: Likewise.
+ * doc/posix-functions/thrd_sleep.texi: Likewise.
+ * doc/posix-functions/thrd_yield.texi: Likewise.
+ * doc/posix-functions/thrd_create.texi: Mention the new module and the
+ AIX bug.
+ * doc/posix-functions/thrd_join.texi: Mention the new module and the
+ AIX and Solaris bugs.
+
+2019-06-20 Bruno Haible <bruno@clisp.org>
+
threads-h: Add tests.
* tests/test-threads.c: New file.
* modules/threads-h-tests: New file.
diff --git a/doc/posix-functions/thrd_create.texi b/doc/posix-functions/thrd_create.texi
index eb3fd5049b..9fe35f489c 100644
--- a/doc/posix-functions/thrd_create.texi
+++ b/doc/posix-functions/thrd_create.texi
@@ -10,15 +10,18 @@ Documentation:@*
@url{https://www.gnu.org/software/libc/manual/html_node/ISO-C-Thread-Management.html}.
@end ifnotinfo
-Gnulib module: ---
+Gnulib module: thrd
Portability problems fixed by Gnulib:
@itemize
+@item
+This function is missing on many platforms:
+glibc 2.27, Mac OS X 10.5, FreeBSD 9.3, NetBSD 5.0, OpenBSD 3.8, Minix 3.1.8, AIX 7.1, HP-UX 11.31, IRIX 6.5, OSF/1 5.1, Solaris 11.3, Cygwin, mingw, MSVC 14, Interix 3.5, BeOS, Android 9.0.
+@item
+This function uses an incorrectly defined @code{thrd_start_t} on some platforms:
+AIX 7.2.
@end itemize
Portability problems not fixed by Gnulib:
@itemize
-@item
-This function is missing on many platforms:
-glibc 2.27, Mac OS X 10.5, FreeBSD 9.3, NetBSD 5.0, OpenBSD 3.8, Minix 3.1.8, AIX 7.1, HP-UX 11.31, IRIX 6.5, OSF/1 5.1, Solaris 11.3, Cygwin, mingw, MSVC 14, Interix 3.5, BeOS, Android 9.0.
@end itemize
diff --git a/doc/posix-functions/thrd_current.texi b/doc/posix-functions/thrd_current.texi
index 03f33a5d7e..ea81185313 100644
--- a/doc/posix-functions/thrd_current.texi
+++ b/doc/posix-functions/thrd_current.texi
@@ -10,15 +10,15 @@ Documentation:@*
@url{https://www.gnu.org/software/libc/manual/html_node/ISO-C-Thread-Management.html}.
@end ifnotinfo
-Gnulib module: ---
+Gnulib module: thrd
Portability problems fixed by Gnulib:
@itemize
+@item
+This function is missing on many platforms:
+glibc 2.27, Mac OS X 10.5, FreeBSD 9.3, NetBSD 5.0, OpenBSD 3.8, Minix 3.1.8, AIX 7.1, HP-UX 11.31, IRIX 6.5, OSF/1 5.1, Solaris 11.3, Cygwin, mingw, MSVC 14, Interix 3.5, BeOS, Android 9.0.
@end itemize
Portability problems not fixed by Gnulib:
@itemize
-@item
-This function is missing on many platforms:
-glibc 2.27, Mac OS X 10.5, FreeBSD 9.3, NetBSD 5.0, OpenBSD 3.8, Minix 3.1.8, AIX 7.1, HP-UX 11.31, IRIX 6.5, OSF/1 5.1, Solaris 11.3, Cygwin, mingw, MSVC 14, Interix 3.5, BeOS, Android 9.0.
@end itemize
diff --git a/doc/posix-functions/thrd_detach.texi b/doc/posix-functions/thrd_detach.texi
index 3cfb318167..bb8f6c316a 100644
--- a/doc/posix-functions/thrd_detach.texi
+++ b/doc/posix-functions/thrd_detach.texi
@@ -10,15 +10,15 @@ Documentation:@*
@url{https://www.gnu.org/software/libc/manual/html_node/ISO-C-Thread-Management.html}.
@end ifnotinfo
-Gnulib module: ---
+Gnulib module: thrd
Portability problems fixed by Gnulib:
@itemize
+@item
+This function is missing on many platforms:
+glibc 2.27, Mac OS X 10.5, FreeBSD 9.3, NetBSD 5.0, OpenBSD 3.8, Minix 3.1.8, AIX 7.1, HP-UX 11.31, IRIX 6.5, OSF/1 5.1, Solaris 11.3, Cygwin, mingw, MSVC 14, Interix 3.5, BeOS, Android 9.0.
@end itemize
Portability problems not fixed by Gnulib:
@itemize
-@item
-This function is missing on many platforms:
-glibc 2.27, Mac OS X 10.5, FreeBSD 9.3, NetBSD 5.0, OpenBSD 3.8, Minix 3.1.8, AIX 7.1, HP-UX 11.31, IRIX 6.5, OSF/1 5.1, Solaris 11.3, Cygwin, mingw, MSVC 14, Interix 3.5, BeOS, Android 9.0.
@end itemize
diff --git a/doc/posix-functions/thrd_equal.texi b/doc/posix-functions/thrd_equal.texi
index 58f5a02377..185550244c 100644
--- a/doc/posix-functions/thrd_equal.texi
+++ b/doc/posix-functions/thrd_equal.texi
@@ -10,15 +10,15 @@ Documentation:@*
@url{https://www.gnu.org/software/libc/manual/html_node/ISO-C-Thread-Management.html}.
@end ifnotinfo
-Gnulib module: ---
+Gnulib module: thrd
Portability problems fixed by Gnulib:
@itemize
+@item
+This function is missing on many platforms:
+glibc 2.27, Mac OS X 10.5, FreeBSD 9.3, NetBSD 5.0, OpenBSD 3.8, Minix 3.1.8, AIX 7.1, HP-UX 11.31, IRIX 6.5, OSF/1 5.1, Solaris 11.3, Cygwin, mingw, MSVC 14, Interix 3.5, BeOS, Android 9.0.
@end itemize
Portability problems not fixed by Gnulib:
@itemize
-@item
-This function is missing on many platforms:
-glibc 2.27, Mac OS X 10.5, FreeBSD 9.3, NetBSD 5.0, OpenBSD 3.8, Minix 3.1.8, AIX 7.1, HP-UX 11.31, IRIX 6.5, OSF/1 5.1, Solaris 11.3, Cygwin, mingw, MSVC 14, Interix 3.5, BeOS, Android 9.0.
@end itemize
diff --git a/doc/posix-functions/thrd_exit.texi b/doc/posix-functions/thrd_exit.texi
index a2683b6a7d..75ae888936 100644
--- a/doc/posix-functions/thrd_exit.texi
+++ b/doc/posix-functions/thrd_exit.texi
@@ -10,15 +10,15 @@ Documentation:@*
@url{https://www.gnu.org/software/libc/manual/html_node/ISO-C-Thread-Management.html}.
@end ifnotinfo
-Gnulib module: ---
+Gnulib module: thrd
Portability problems fixed by Gnulib:
@itemize
+@item
+This function is missing on many platforms:
+glibc 2.27, Mac OS X 10.5, FreeBSD 9.3, NetBSD 5.0, OpenBSD 3.8, Minix 3.1.8, AIX 7.1, HP-UX 11.31, IRIX 6.5, OSF/1 5.1, Solaris 11.3, Cygwin, mingw, MSVC 14, Interix 3.5, BeOS, Android 9.0.
@end itemize
Portability problems not fixed by Gnulib:
@itemize
-@item
-This function is missing on many platforms:
-glibc 2.27, Mac OS X 10.5, FreeBSD 9.3, NetBSD 5.0, OpenBSD 3.8, Minix 3.1.8, AIX 7.1, HP-UX 11.31, IRIX 6.5, OSF/1 5.1, Solaris 11.3, Cygwin, mingw, MSVC 14, Interix 3.5, BeOS, Android 9.0.
@end itemize
diff --git a/doc/posix-functions/thrd_join.texi b/doc/posix-functions/thrd_join.texi
index 2199a8f110..51b2ec9df3 100644
--- a/doc/posix-functions/thrd_join.texi
+++ b/doc/posix-functions/thrd_join.texi
@@ -10,15 +10,21 @@ Documentation:@*
@url{https://www.gnu.org/software/libc/manual/html_node/ISO-C-Thread-Management.html}.
@end ifnotinfo
-Gnulib module: ---
+Gnulib module: thrd
Portability problems fixed by Gnulib:
@itemize
+@item
+This function is missing on many platforms:
+glibc 2.27, Mac OS X 10.5, FreeBSD 9.3, NetBSD 5.0, OpenBSD 3.8, Minix 3.1.8, AIX 7.1, HP-UX 11.31, IRIX 6.5, OSF/1 5.1, Solaris 11.3, Cygwin, mingw, MSVC 14, Interix 3.5, BeOS, Android 9.0.
+@item
+This function never stores an exit code on some platforms:
+AIX 7.2.
+@item
+This function crashes when the second argument is NULL on some platforms:
+Solaris 11.4.
@end itemize
Portability problems not fixed by Gnulib:
@itemize
-@item
-This function is missing on many platforms:
-glibc 2.27, Mac OS X 10.5, FreeBSD 9.3, NetBSD 5.0, OpenBSD 3.8, Minix 3.1.8, AIX 7.1, HP-UX 11.31, IRIX 6.5, OSF/1 5.1, Solaris 11.3, Cygwin, mingw, MSVC 14, Interix 3.5, BeOS, Android 9.0.
@end itemize
diff --git a/doc/posix-functions/thrd_sleep.texi b/doc/posix-functions/thrd_sleep.texi
index afdb3ea6a1..5e02eb1e4e 100644
--- a/doc/posix-functions/thrd_sleep.texi
+++ b/doc/posix-functions/thrd_sleep.texi
@@ -10,15 +10,15 @@ Documentation:@*
@url{https://www.gnu.org/software/libc/manual/html_node/ISO-C-Thread-Management.html}.
@end ifnotinfo
-Gnulib module: ---
+Gnulib module: thrd
Portability problems fixed by Gnulib:
@itemize
+@item
+This function is missing on many platforms:
+glibc 2.27, Mac OS X 10.5, FreeBSD 9.3, NetBSD 5.0, OpenBSD 3.8, Minix 3.1.8, AIX 7.1, HP-UX 11.31, IRIX 6.5, OSF/1 5.1, Solaris 11.3, Cygwin, mingw, MSVC 14, Interix 3.5, BeOS, Android 9.0.
@end itemize
Portability problems not fixed by Gnulib:
@itemize
-@item
-This function is missing on many platforms:
-glibc 2.27, Mac OS X 10.5, FreeBSD 9.3, NetBSD 5.0, OpenBSD 3.8, Minix 3.1.8, AIX 7.1, HP-UX 11.31, IRIX 6.5, OSF/1 5.1, Solaris 11.3, Cygwin, mingw, MSVC 14, Interix 3.5, BeOS, Android 9.0.
@end itemize
diff --git a/doc/posix-functions/thrd_yield.texi b/doc/posix-functions/thrd_yield.texi
index a787a69708..dde2a718e8 100644
--- a/doc/posix-functions/thrd_yield.texi
+++ b/doc/posix-functions/thrd_yield.texi
@@ -10,15 +10,15 @@ Documentation:@*
@url{https://www.gnu.org/software/libc/manual/html_node/ISO-C-Thread-Management.html}.
@end ifnotinfo
-Gnulib module: ---
+Gnulib module: thrd
Portability problems fixed by Gnulib:
@itemize
+@item
+This function is missing on many platforms:
+glibc 2.27, Mac OS X 10.5, FreeBSD 9.3, NetBSD 5.0, OpenBSD 3.8, Minix 3.1.8, AIX 7.1, HP-UX 11.31, IRIX 6.5, OSF/1 5.1, Solaris 11.3, Cygwin, mingw, MSVC 14, Interix 3.5, BeOS, Android 9.0.
@end itemize
Portability problems not fixed by Gnulib:
@itemize
-@item
-This function is missing on many platforms:
-glibc 2.27, Mac OS X 10.5, FreeBSD 9.3, NetBSD 5.0, OpenBSD 3.8, Minix 3.1.8, AIX 7.1, HP-UX 11.31, IRIX 6.5, OSF/1 5.1, Solaris 11.3, Cygwin, mingw, MSVC 14, Interix 3.5, BeOS, Android 9.0.
@end itemize
diff --git a/lib/thrd.c b/lib/thrd.c
new file mode 100644
index 0000000000..e8f29bc09c
--- /dev/null
+++ b/lib/thrd.c
@@ -0,0 +1,427 @@
+/* Creating and controlling ISO C 11 threads.
+ Copyright (C) 2005-2019 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 2, or (at your option)
+ any later version.
+
+ This program 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.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <https://www.gnu.org/licenses/>. */
+
+/* Written by Bruno Haible <bruno@clisp.org>, 2005, 2019.
+ Based on GCC's gthr-posix.h, gthr-posix95.h, gthr-win32.h. */
+
+#include <config.h>
+
+#include <threads.h>
+
+#include <stdlib.h>
+
+#if HAVE_THREADS_H
+/* Provide workarounds. */
+
+# if BROKEN_THRD_START_T
+
+# undef thrd_t
+
+/* AIX 7.1..7.2 defines thrd_start_t incorrectly, namely as
+ 'void * (*) (void *)' instead of 'int (*) (void *)'.
+ As a consequence, its thrd_join function never stores an exit code. */
+
+/* The Thread-Specific Storage (TSS) key that allows to access each thread's
+ 'struct thrd_with_exitcode *' pointer. */
+static tss_t thrd_with_exitcode_key;
+
+/* Initializes thrd_with_exitcode_key.
+ This function must only be called once. */
+static void
+do_init_thrd_with_exitcode_key (void)
+{
+ if (tss_create (&thrd_with_exitcode_key, NULL) != thrd_success)
+ abort ();
+}
+
+/* Initializes thrd_with_exitcode_key. */
+static void
+init_thrd_with_exitcode_key (void)
+{
+ static once_flag once = ONCE_FLAG_INIT;
+ call_once (&once, do_init_thrd_with_exitcode_key);
+}
+
+typedef union
+ {
+ struct thrd_with_exitcode t;
+ struct
+ {
+ thrd_t tid; /* reserve memory for t.tid */
+ int detached; /* reserve memory for t.detached */
+ thrd_start_t mainfunc;
+ void *arg;
+ } a;
+ }
+ main_arg_t;
+
+static void *
+thrd_main_func (void *pmarg)
+{
+ /* Unpack the object that combines mainfunc and arg. */
+ main_arg_t *main_arg = (main_arg_t *) pmarg;
+ thrd_start_t mainfunc = main_arg->a.mainfunc;
+ void *arg = main_arg->a.arg;
+
+ if (tss_set (thrd_with_exitcode_key, &main_arg->t) != thrd_success)
+ abort ();
+
+ /* Execute mainfunc, with arg as argument. */
+ {
+ int exitcode = mainfunc (arg);
+ /* Store the exitcode, for use by thrd_join(). */
+ main_arg->t.exitcode = exitcode;
+ if (main_arg->t.detached)
+ {
+ /* Clean up the thread, like thrd_join would do. */
+ free (&main_arg->t);
+ }
+ return NULL;
+ }
+}
+
+int
+rpl_thrd_create (rpl_thrd_t *threadp, thrd_start_t mainfunc, void *arg)
+# undef thrd_create
+{
+ init_thrd_with_exitcode_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 pthread_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 thrd_nomem;
+ main_arg->a.mainfunc = mainfunc;
+ main_arg->a.arg = arg;
+ main_arg->t.detached = 0;
+ {
+ int err =
+ thrd_create ((thrd_t *) &main_arg->t.tid, thrd_main_func, main_arg);
+ if (err == thrd_success)
+ *threadp = &main_arg->t;
+ else
+ free (main_arg);
+ return err;
+ }
+ }
+}
+
+rpl_thrd_t
+rpl_thrd_current (void)
+# undef thrd_current
+{
+ init_thrd_with_exitcode_key ();
+ {
+ rpl_thrd_t thread =
+ (struct thrd_with_exitcode *) tss_get (thrd_with_exitcode_key);
+ if (thread == NULL)
+ {
+ /* This happens only in threads that have not been created through
+ thrd_create(), such as the main thread. */
+ for (;;)
+ {
+ thread =
+ (struct thrd_with_exitcode *)
+ malloc (sizeof (struct thrd_with_exitcode));
+ 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->detached = 0; /* This can lead to a memory leak. */
+ thread->exitcode = 0; /* just to be deterministic */
+ if (tss_set (thrd_with_exitcode_key, thread) != thrd_success)
+ abort ();
+ }
+ return thread;
+ }
+}
+
+int
+rpl_thrd_equal (rpl_thrd_t thread1, rpl_thrd_t thread2)
+{
+ return thread1 == thread2;
+}
+
+int
+rpl_thrd_detach (rpl_thrd_t thread)
+# undef thrd_detach
+{
+ if (thread->detached)
+ return thrd_error;
+ {
+ int err =
+ thrd_detach (thread == rpl_thrd_current ()
+ ? /* thread->tid may not be initialized at this point. */
+ thrd_current ()
+ : thread->tid);
+ if (err == thrd_success)
+ thread->detached = 1;
+ return err;
+ }
+}
+
+int
+rpl_thrd_join (rpl_thrd_t thread, int *exitcodep)
+# undef thrd_join
+{
+ if (thread == rpl_thrd_current () || thread->detached)
+ return thrd_error;
+ {
+ int err = thrd_join (thread->tid, NULL);
+ if (err == thrd_success)
+ {
+ if (exitcodep != NULL)
+ *exitcodep = thread->exitcode;
+ free (thread);
+ }
+ return err;
+ }
+}
+
+# endif
+
+# if BROKEN_THRD_JOIN
+
+/* On Solaris 11.4, thrd_join crashes when the second argument is NULL. */
+int
+rpl_thrd_join (thrd_t thread, int *exitcodep)
+# undef thrd_join
+{
+ int exitcode;
+ int err = thrd_join (thread, &exitcode);
+ if (err == 0 && exitcodep != NULL)
+ *exitcodep = exitcode;
+ return err;
+}
+
+# endif
+
+#else
+
+# include <errno.h>
+# include <stdint.h>
+
+# if defined _WIN32 && ! defined __CYGWIN__
+/* Use Windows threads. */
+
+# define WIN32_LEAN_AND_MEAN /* avoid including junk */
+# include <windows.h>
+
+# else
+/* Use POSIX threads. */
+
+# include <pthread.h>
+# include <sched.h>
+
+# endif
+
+/* The main functions passed to thrd_create and
+ pthread_create/glwthread_thread_create have different return types:
+ 'int' vs. 'void *'. */
+
+struct pthread_main_arg_t
+{
+ thrd_start_t mainfunc;
+ void *arg;
+};
+
+static void *
+pthread_main_func (void *pmarg)
+{
+ /* Unpack the object that combines mainfunc and arg. */
+ struct pthread_main_arg_t *pthread_main_arg =
+ (struct pthread_main_arg_t *) pmarg;
+ thrd_start_t mainfunc = pthread_main_arg->mainfunc;
+ void *arg = pthread_main_arg->arg;
+
+ /* Free it. */
+ free (pmarg);
+
+ /* Execute mainfunc, with arg as argument. */
+ {
+ int exitcode = mainfunc (arg);
+ return (void *) (intptr_t) exitcode;
+ }
+}
+
+# if defined _WIN32 && ! defined __CYGWIN__
+/* Use Windows threads. */
+
+int
+thrd_create (thrd_t *threadp, thrd_start_t mainfunc, void *arg)
+{
+ /* 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 pthread_main_func is
+ entered. So, allocate it in the heap. */
+ struct pthread_main_arg_t *pthread_main_arg =
+ (struct pthread_main_arg_t *) malloc (sizeof (struct pthread_main_arg_t));
+ if (pthread_main_arg == NULL)
+ return thrd_nomem;
+ pthread_main_arg->mainfunc = mainfunc;
+ pthread_main_arg->arg = arg;
+
+ {
+ int err = glwthread_thread_create (threadp,
+ pthread_main_func, pthread_main_arg);
+ if (err != 0)
+ free (pthread_main_arg);
+ return (err == 0 ? thrd_success :
+ err == ENOMEM /* || err == EAGAIN */ ? thrd_nomem :
+ thrd_error);
+ }
+}
+
+thrd_t
+thrd_current (void)
+{
+ return glwthread_thread_self ();
+}
+
+int
+thrd_equal (thrd_t thread1, thrd_t thread2)
+{
+ return thread1 == thread2;
+}
+
+void
+thrd_yield (void)
+{
+ Sleep (0);
+}
+
+int
+thrd_detach (thrd_t thread)
+{
+ int err = glwthread_thread_detach (thread);
+ return (err == 0 ? thrd_success : thrd_error);
+}
+
+int
+thrd_join (thrd_t thread, int *exitcodep)
+{
+ void *exitptr;
+ int err = glwthread_thread_join (thread, &exitptr);
+ if (err == 0)
+ {
+ if (exitcodep != NULL)
+ *exitcodep = (int) (intptr_t) exitptr;
+ return thrd_success;
+ }
+ else
+ return thrd_error;
+}
+
+_Noreturn void
+thrd_exit (int exitcode)
+{
+ glwthread_thread_exit ((void *) (intptr_t) exitcode);
+}
+
+# else
+/* Use POSIX threads. */
+
+int
+thrd_create (thrd_t *threadp, thrd_start_t mainfunc, void *arg)
+{
+ /* 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 pthread_main_func is
+ entered. So, allocate it in the heap. */
+ struct pthread_main_arg_t *pthread_main_arg =
+ (struct pthread_main_arg_t *) malloc (sizeof (struct pthread_main_arg_t));
+ if (pthread_main_arg == NULL)
+ return thrd_nomem;
+ pthread_main_arg->mainfunc = mainfunc;
+ pthread_main_arg->arg = arg;
+
+ {
+ int err = pthread_create (threadp, NULL,
+ pthread_main_func, pthread_main_arg);
+ if (err != 0)
+ free (pthread_main_arg);
+ return (err == 0 ? thrd_success :
+ err == ENOMEM /* || err == EAGAIN */ ? thrd_nomem :
+ thrd_error);
+ }
+}
+
+thrd_t
+thrd_current (void)
+{
+ return pthread_self ();
+}
+
+int
+thrd_equal (thrd_t thread1, thrd_t thread2)
+{
+ return pthread_equal (thread1, thread2);
+}
+
+void
+thrd_yield (void)
+{
+ sched_yield ();
+}
+
+int
+thrd_detach (thrd_t thread)
+{
+ int err = pthread_detach (thread);
+ return (err == 0 ? thrd_success : thrd_error);
+}
+
+int
+thrd_join (thrd_t thread, int *exitcodep)
+{
+ void *exitptr;
+ int err = pthread_join (thread, &exitptr);
+ if (err == 0)
+ {
+ if (exitcodep != NULL)
+ *exitcodep = (int) (intptr_t) exitptr;
+ return thrd_success;
+ }
+ else
+ return thrd_error;
+}
+
+_Noreturn void
+thrd_exit (int exitcode)
+{
+ pthread_exit ((void *) (intptr_t) exitcode);
+}
+
+# endif
+
+int
+thrd_sleep (const struct timespec *duration, struct timespec *remaining)
+{
+ int ret = nanosleep (duration, remaining);
+ return (ret == 0 ? 0 : errno == EINTR ? -1 : -2);
+}
+
+#endif
diff --git a/m4/thrd.m4 b/m4/thrd.m4
new file mode 100644
index 0000000000..6e9c8f44cc
--- /dev/null
+++ b/m4/thrd.m4
@@ -0,0 +1,63 @@
+# thrd.m4 serial 1
+dnl Copyright (C) 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,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_THRD_JOIN],
+[
+ AC_REQUIRE([gl_THREADS_H])
+ AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
+
+ if test $ac_cv_header_threads_h = yes; then
+ if test $BROKEN_THRD_START_T = 1; then
+ REPLACE_THRD_CREATE=1
+ REPLACE_THRD_CURRENT=1
+ REPLACE_THRD_DETACH=1
+ REPLACE_THRD_EQUAL=1
+ REPLACE_THRD_JOIN=1
+ AC_DEFINE([BROKEN_THRD_START_T], [1],
+ [Define if the thrd_start_t type is not as described in ISO C 11.])
+ fi
+
+ dnl On Solaris 11.4, thrd_join crashes when the second argument is NULL.
+ AC_CACHE_CHECK([whether thrd_join works],
+ [gl_cv_func_thrd_join_works],
+ [save_LIBS="$LIBS"
+ LIBS="$LIBS $LIBSTDTHREAD"
+ AC_RUN_IFELSE(
+ [AC_LANG_PROGRAM(
+ [[#include <stddef.h>
+ #include <threads.h>
+ static int func (void *arg)
+ {
+ return (arg != NULL);
+ }
+ ]],
+ [[thrd_t thread;
+ if (thrd_create (&thread, func, NULL) != thrd_success)
+ return 1;
+ if (thrd_join (thread, NULL) != thrd_success)
+ return 2;
+ return 0;
+ ]])],
+ [gl_cv_func_thrd_join_works=yes],
+ [gl_cv_func_thrd_join_works=no],
+ [case "$host_os" in
+ # Only Solaris is known to be broken.
+ solaris*) gl_cv_func_thrd_join_works="guessing no" ;;
+ *) gl_cv_func_thrd_join_works="guessing yes" ;;
+ esac
+ ])
+ LIBS="$save_LIBS"
+ ])
+ case "$gl_cv_func_thrd_join_works" in
+ *yes) ;;
+ *)
+ REPLACE_THRD_JOIN=1
+ AC_DEFINE([BROKEN_THRD_JOIN], [1],
+ [Define if the thrd_join function does not behave as in ISO C 11.])
+ ;;
+ esac
+ fi
+])
diff --git a/modules/thrd b/modules/thrd
new file mode 100644
index 0000000000..3fd606305d
--- /dev/null
+++ b/modules/thrd
@@ -0,0 +1,33 @@
+Description:
+ISO C 11 thread functions.
+
+Files:
+lib/thrd.c
+m4/thrd.m4
+
+Depends-on:
+threads-h
+windows-thread
+nanosleep
+
+configure.ac:
+AC_REQUIRE([gl_THREADS_H])
+gl_FUNC_THRD_JOIN
+if test $HAVE_THREADS_H = 0 || test $REPLACE_THRD_CREATE = 1 || test $REPLACE_THRD_JOIN = 1; then
+ AC_LIBOBJ([thrd])
+fi
+gl_THREADS_MODULE_INDICATOR([thrd])
+
+Makefile.am:
+
+Include:
+<threads.h>
+
+Link:
+$(LTLIBSTDTHREAD) when linking with libtool, $(LIBSTDTHREAD) otherwise
+
+License:
+LGPLv2+
+
+Maintainer:
+all