]> Savannah Git Hosting - gnulib.git/commitdiff
thrd: New module.
authorBruno Haible <bruno@clisp.org>
Thu, 20 Jun 2019 02:26:31 +0000 (04:26 +0200)
committerBruno Haible <bruno@clisp.org>
Thu, 20 Jun 2019 02:46:38 +0000 (04:46 +0200)
* 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.

12 files changed:
ChangeLog
doc/posix-functions/thrd_create.texi
doc/posix-functions/thrd_current.texi
doc/posix-functions/thrd_detach.texi
doc/posix-functions/thrd_equal.texi
doc/posix-functions/thrd_exit.texi
doc/posix-functions/thrd_join.texi
doc/posix-functions/thrd_sleep.texi
doc/posix-functions/thrd_yield.texi
lib/thrd.c [new file with mode: 0644]
m4/thrd.m4 [new file with mode: 0644]
modules/thrd [new file with mode: 0644]

index b536bcbd7bfcf1ca20636a28f4c02b539fd23f0d..5d96988342f110d51a9c8ba6f1eaffde984e2f04 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,20 @@
+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.
index eb3fd5049b13fa08cb8521ba6fff8ce5acd1bd68..9fe35f489c36ae67807dcc5d358b94a2ba440aa4 100644 (file)
@@ -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
index 03f33a5d7ef8efb9bcf03ad93ccbb5b2a9b4232b..ea81185313c5db3bb07cbebf3f29389b72d40a2e 100644 (file)
@@ -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
index 3cfb318167cacc2528ac22446fec2c81e46f6063..bb8f6c316aef82cdfc3b4b305173094589389c5e 100644 (file)
@@ -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
index 58f5a023773e36a0ff76411e2cb31fc892bbea11..185550244c6357dbd7edc8084ed3d14232b3b06e 100644 (file)
@@ -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
index a2683b6a7d3bcee364069ff515f77718fcb68d79..75ae888936eedf636a691aa8f1841425c1704381 100644 (file)
@@ -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
index 2199a8f1100fa1224b9561476c042a2622049d20..51b2ec9df304739437af0a39e418b4f5bc13cd0b 100644 (file)
@@ -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
index afdb3ea6a13faa3812879608b47c4e0311288c77..5e02eb1e4e9f450df6d8b36b8ea69f383c1c8af8 100644 (file)
@@ -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
index a787a6970898bf7281f0711f34a6658eedacbdec..dde2a718e897ef40c898b5f6fff9173e306b01ba 100644 (file)
@@ -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 (file)
index 0000000..e8f29bc
--- /dev/null
@@ -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 (file)
index 0000000..6e9c8f4
--- /dev/null
@@ -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 (file)
index 0000000..3fd6063
--- /dev/null
@@ -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