summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog11
-rw-r--r--doc/posix-headers/threads.texi14
-rw-r--r--lib/threads.in.h649
-rw-r--r--m4/threads.m4126
-rw-r--r--m4/yield.m44
-rw-r--r--modules/threads-h73
-rw-r--r--modules/yield2
7 files changed, 872 insertions, 7 deletions
diff --git a/ChangeLog b/ChangeLog
index ab97f37093..22b942ba63 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,16 @@
2019-06-20 Bruno Haible <bruno@clisp.org>
+ threads-h: New module.
+ * lib/threads.in.h: New file.
+ * m4/threads.m4: New file.
+ * m4/yield.m4 (gl_YIELD): Update comment.
+ * modules/threads-h: New file.
+ * modules/yields (configure.ac): Use AC_REQUIRE.
+ * doc/posix-headers/threads.texi: Mention the new module and the AIX
+ bugs.
+
+2019-06-20 Bruno Haible <bruno@clisp.org>
+
windows-thread: New module.
* lib/windows-thread.h: New file, based on lib/glthread/thread.h.
* lib/windows-thread.c: New file, based on lib/glthread/thread.c.
diff --git a/doc/posix-headers/threads.texi b/doc/posix-headers/threads.texi
index 9892539182..71ae43a48b 100644
--- a/doc/posix-headers/threads.texi
+++ b/doc/posix-headers/threads.texi
@@ -3,15 +3,21 @@
Defines the multithreading facility of ISO C11.
-Gnulib module: ---
+Gnulib module: threads-h
Portability problems fixed by Gnulib:
@itemize
+@item
+This header file 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 header file defines @code{thrd_start_t} incorrectly on some platforms:
+AIX 7.2.
+@item
+This header file does not define @code{TSS_DTOR_ITERATIONS} on some platforms:
+AIX 7.2.
@end itemize
Portability problems not fixed by Gnulib:
@itemize
-@item
-This header file 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/threads.in.h b/lib/threads.in.h
new file mode 100644
index 0000000000..a18d64b4be
--- /dev/null
+++ b/lib/threads.in.h
@@ -0,0 +1,649 @@
+/* An ISO C 11 compatible <threads.h>.
+
+ Copyright (C) 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/>. */
+
+#if __GNUC__ >= 3
+@PRAGMA_SYSTEM_HEADER@
+#endif
+@PRAGMA_COLUMNS@
+
+#ifndef _@GUARD_PREFIX@_THREADS_H
+
+/* The include_next requires a split double-inclusion guard. */
+#if @HAVE_THREADS_H@
+# @INCLUDE_NEXT@ @NEXT_THREADS_H@
+#endif
+
+#ifndef _@GUARD_PREFIX@_THREADS_H
+#define _@GUARD_PREFIX@_THREADS_H
+
+#if !@HAVE_THREADS_H@
+
+# include <time.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>
+
+# endif
+
+#endif
+
+/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */
+
+/* The definition of _Noreturn is copied here. */
+
+/* The definition of _GL_ARG_NONNULL is copied here. */
+
+/* The definition of _GL_WARN_ON_USE is copied here. */
+
+
+/* Storage class specifier for thread-local storage. */
+#ifdef _AIX
+/* The macro definition from AIX 7.1..7.2 <threads.h> is unusable, because
+ its expansion ends in a semicolon. */
+# undef thread_local
+#endif
+#if !@HAVE_THREADS_H@ || !defined thread_local
+# define thread_local _Thread_local
+#endif
+
+
+/* =========== ISO C 11 7.26.5 Thread functions =========== */
+
+#if !@HAVE_THREADS_H@
+
+/* Return codes. */
+enum
+{
+ thrd_success = 0,
+ thrd_timedout = 1,
+ thrd_busy = 2,
+ thrd_nomem = 3,
+ thrd_error = 4
+};
+
+# if defined _WIN32 && ! defined __CYGWIN__
+/* Use Windows threads. */
+
+# include "windows-thread.h"
+
+typedef glwthread_thread_t thrd_t;
+
+# else
+/* Use POSIX threads. */
+
+typedef pthread_t thrd_t;
+
+# endif
+
+#endif
+
+#if @BROKEN_THRD_START_T@
+/* Need to override thrd_start_t, to make thrd_create work. */
+# define thrd_start_t rpl_thrd_start_t
+/* Need to override thrd_t, to make thrd_join work. */
+struct thrd_with_exitcode
+{
+ thrd_t volatile tid;
+ int volatile detached;
+ int volatile exitcode;
+};
+typedef struct thrd_with_exitcode *rpl_thrd_t;
+# define thrd_t rpl_thrd_t
+#endif
+/* Type of the main function of a thread. */
+#if !@HAVE_THREADS_H@ || @BROKEN_THRD_START_T@
+typedef int (* thrd_start_t) (void *);
+#endif
+
+#if @GNULIB_THRD@
+# if @REPLACE_THRD_CREATE@
+# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+# define thrd_create rpl_thrd_create
+# endif
+_GL_FUNCDECL_RPL (thrd_create, int, (thrd_t *, thrd_start_t, void *)
+ _GL_ARG_NONNULL ((1, 2)));
+_GL_CXXALIAS_RPL (thrd_create, int, (thrd_t *, thrd_start_t, void *));
+# else
+# if !@HAVE_THREADS_H@
+_GL_FUNCDECL_SYS (thrd_create, int, (thrd_t *, thrd_start_t, void *)
+ _GL_ARG_NONNULL ((1, 2)));
+# endif
+_GL_CXXALIAS_SYS (thrd_create, int, (thrd_t *, thrd_start_t, void *));
+# endif
+_GL_CXXALIASWARN (thrd_create);
+#elif defined GNULIB_POSIXCHECK
+# undef thrd_create
+# if HAVE_RAW_DECL_THRD_CREATE
+_GL_WARN_ON_USE (thrd_create, "thrd_create is unportable - "
+ "use gnulib module thrd for portability");
+# endif
+#endif
+
+#if @GNULIB_THRD@
+# if @REPLACE_THRD_CURRENT@
+# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+# define thrd_current rpl_thrd_current
+# endif
+_GL_FUNCDECL_RPL (thrd_current, thrd_t, (void) _GL_ATTRIBUTE_PURE);
+_GL_CXXALIAS_RPL (thrd_current, thrd_t, (void));
+# else
+# if !@HAVE_THREADS_H@
+_GL_FUNCDECL_SYS (thrd_current, thrd_t, (void) _GL_ATTRIBUTE_PURE);
+# endif
+_GL_CXXALIAS_SYS (thrd_current, thrd_t, (void));
+# endif
+_GL_CXXALIASWARN (thrd_current);
+#elif defined GNULIB_POSIXCHECK
+# undef thrd_current
+# if HAVE_RAW_DECL_THRD_CURRENT
+_GL_WARN_ON_USE (thrd_current, "thrd_current is unportable - "
+ "use gnulib module thrd for portability");
+# endif
+#endif
+
+#if @GNULIB_THRD@
+# if @REPLACE_THRD_EQUAL@
+# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+# define thrd_equal rpl_thrd_equal
+# endif
+_GL_FUNCDECL_RPL (thrd_equal, int, (thrd_t, thrd_t) _GL_ATTRIBUTE_PURE);
+_GL_CXXALIAS_RPL (thrd_equal, int, (thrd_t, thrd_t));
+# else
+# if !@HAVE_THREADS_H@
+_GL_FUNCDECL_SYS (thrd_equal, int, (thrd_t, thrd_t) _GL_ATTRIBUTE_PURE);
+# endif
+_GL_CXXALIAS_SYS (thrd_equal, int, (thrd_t, thrd_t));
+# endif
+_GL_CXXALIASWARN (thrd_equal);
+#elif defined GNULIB_POSIXCHECK
+# undef thrd_equal
+# if HAVE_RAW_DECL_THRD_EQUAL
+_GL_WARN_ON_USE (thrd_equal, "thrd_equal is unportable - "
+ "use gnulib module thrd for portability");
+# endif
+#endif
+
+#if @GNULIB_THRD@
+# if !@HAVE_THREADS_H@
+_GL_FUNCDECL_SYS (thrd_sleep, int,
+ (const struct timespec *, struct timespec *)
+ _GL_ARG_NONNULL ((1)));
+# endif
+_GL_CXXALIAS_SYS (thrd_sleep, int,
+ (const struct timespec *, struct timespec *));
+_GL_CXXALIASWARN (thrd_sleep);
+#elif defined GNULIB_POSIXCHECK
+# undef thrd_sleep
+# if HAVE_RAW_DECL_THRD_SLEEP
+_GL_WARN_ON_USE (thrd_sleep, "thrd_sleep is unportable - "
+ "use gnulib module thrd for portability");
+# endif
+#endif
+
+#if @GNULIB_THRD@
+# if !@HAVE_THREADS_H@
+_GL_FUNCDECL_SYS (thrd_yield, void, (void));
+# endif
+_GL_CXXALIAS_SYS (thrd_yield, void, (void));
+_GL_CXXALIASWARN (thrd_yield);
+#elif defined GNULIB_POSIXCHECK
+# undef thrd_yield
+# if HAVE_RAW_DECL_THRD_YIELD
+_GL_WARN_ON_USE (thrd_yield, "thrd_yield is unportable - "
+ "use gnulib module thrd for portability");
+# endif
+#endif
+
+#if @GNULIB_THRD@
+# if @REPLACE_THRD_DETACH@
+# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+# define thrd_detach rpl_thrd_detach
+# endif
+_GL_FUNCDECL_RPL (thrd_detach, int, (thrd_t));
+_GL_CXXALIAS_RPL (thrd_detach, int, (thrd_t));
+# else
+# if !@HAVE_THREADS_H@
+_GL_FUNCDECL_SYS (thrd_detach, int, (thrd_t));
+# endif
+_GL_CXXALIAS_SYS (thrd_detach, int, (thrd_t));
+# endif
+_GL_CXXALIASWARN (thrd_detach);
+#elif defined GNULIB_POSIXCHECK
+# undef thrd_detach
+# if HAVE_RAW_DECL_THRD_DETACH
+_GL_WARN_ON_USE (thrd_detach, "thrd_detach is unportable - "
+ "use gnulib module thrd for portability");
+# endif
+#endif
+
+#if @GNULIB_THRD@
+# if @REPLACE_THRD_JOIN@
+# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+# define thrd_join rpl_thrd_join
+# endif
+_GL_FUNCDECL_RPL (thrd_join, int, (thrd_t, int *));
+_GL_CXXALIAS_RPL (thrd_join, int, (thrd_t, int *));
+# else
+# if !@HAVE_THREADS_H@
+_GL_FUNCDECL_SYS (thrd_join, int, (thrd_t, int *));
+# endif
+_GL_CXXALIAS_SYS (thrd_join, int, (thrd_t, int *));
+# endif
+_GL_CXXALIASWARN (thrd_join);
+#elif defined GNULIB_POSIXCHECK
+# undef thrd_join
+# if HAVE_RAW_DECL_THRD_JOIN
+_GL_WARN_ON_USE (thrd_join, "thrd_join is unportable - "
+ "use gnulib module thrd for portability");
+# endif
+#endif
+
+#if @GNULIB_THRD@
+# if !@HAVE_THREADS_H@
+_GL_FUNCDECL_SYS (thrd_exit, _Noreturn void, (int));
+# endif
+_GL_CXXALIAS_SYS (thrd_exit, _Noreturn void, (int));
+_GL_CXXALIASWARN (thrd_exit);
+#elif defined GNULIB_POSIXCHECK
+# undef thrd_exit
+# if HAVE_RAW_DECL_THRD_EXIT
+_GL_WARN_ON_USE (thrd_exit, "thrd_exit is unportable - "
+ "use gnulib module thrd for portability");
+# endif
+#endif
+
+
+/* =========== ISO C 11 7.26.4 Mutex functions =========== */
+
+#if !@HAVE_THREADS_H@
+
+/* Types of mutexes. */
+enum
+{
+ mtx_plain = 0,
+ mtx_timed = 1,
+ mtx_recursive = 2
+};
+
+# if defined _WIN32 && ! defined __CYGWIN__
+/* Use Windows threads. */
+
+# include "windows-mutex.h"
+# include "windows-recmutex.h"
+# include "windows-timedmutex.h"
+# include "windows-timedrecmutex.h"
+
+typedef struct
+ {
+ int type;
+ union
+ {
+ glwthread_mutex_t u_mutex;
+ glwthread_recmutex_t u_recmutex;
+ glwthread_timedmutex_t u_timedmutex;
+ glwthread_timedrecmutex_t u_timedrecmutex;
+ }
+ u;
+ }
+ mtx_t;
+
+# else
+/* Use POSIX threads. */
+
+typedef pthread_mutex_t mtx_t;
+
+# endif
+
+#endif
+
+#if @GNULIB_MTX@
+# if !@HAVE_THREADS_H@
+_GL_FUNCDECL_SYS (mtx_init, int, (mtx_t *, int) _GL_ARG_NONNULL ((1)));
+# endif
+_GL_CXXALIAS_SYS (mtx_init, int, (mtx_t *, int));
+_GL_CXXALIASWARN (mtx_init);
+#elif defined GNULIB_POSIXCHECK
+# undef mtx_init
+# if HAVE_RAW_DECL_MTX_INIT
+_GL_WARN_ON_USE (mtx_init, "mtx_init is unportable - "
+ "use gnulib module mtx for portability");
+# endif
+#endif
+
+#if @GNULIB_MTX@
+# if !@HAVE_THREADS_H@
+_GL_FUNCDECL_SYS (mtx_lock, int, (mtx_t *) _GL_ARG_NONNULL ((1)));
+# endif
+_GL_CXXALIAS_SYS (mtx_lock, int, (mtx_t *));
+_GL_CXXALIASWARN (mtx_lock);
+#elif defined GNULIB_POSIXCHECK
+# undef mtx_lock
+# if HAVE_RAW_DECL_MTX_LOCK
+_GL_WARN_ON_USE (mtx_lock, "mtx_lock is unportable - "
+ "use gnulib module mtx for portability");
+# endif
+#endif
+
+#if @GNULIB_MTX@
+# if !@HAVE_THREADS_H@
+_GL_FUNCDECL_SYS (mtx_trylock, int, (mtx_t *) _GL_ARG_NONNULL ((1)));
+# endif
+_GL_CXXALIAS_SYS (mtx_trylock, int, (mtx_t *));
+_GL_CXXALIASWARN (mtx_trylock);
+#elif defined GNULIB_POSIXCHECK
+# undef mtx_trylock
+# if HAVE_RAW_DECL_MTX_TRYLOCK
+_GL_WARN_ON_USE (mtx_trylock, "mtx_trylock is unportable - "
+ "use gnulib module mtx for portability");
+# endif
+#endif
+
+#if @GNULIB_MTX@
+# if !@HAVE_THREADS_H@
+_GL_FUNCDECL_SYS (mtx_timedlock, int, (mtx_t *, const struct timespec *)
+ _GL_ARG_NONNULL ((1, 2)));
+# endif
+_GL_CXXALIAS_SYS (mtx_timedlock, int, (mtx_t *, const struct timespec *));
+_GL_CXXALIASWARN (mtx_timedlock);
+#elif defined GNULIB_POSIXCHECK
+# undef mtx_timedlock
+# if HAVE_RAW_DECL_MTX_TIMEDLOCK
+_GL_WARN_ON_USE (mtx_timedlock, "mtx_timedlock is unportable - "
+ "use gnulib module mtx for portability");
+# endif
+#endif
+
+#if @GNULIB_MTX@
+# if !@HAVE_THREADS_H@
+_GL_FUNCDECL_SYS (mtx_unlock, int, (mtx_t *) _GL_ARG_NONNULL ((1)));
+# endif
+_GL_CXXALIAS_SYS (mtx_unlock, int, (mtx_t *));
+_GL_CXXALIASWARN (mtx_unlock);
+#elif defined GNULIB_POSIXCHECK
+# undef mtx_unlock
+# if HAVE_RAW_DECL_MTX_UNLOCK
+_GL_WARN_ON_USE (mtx_unlock, "mtx_unlock is unportable - "
+ "use gnulib module mtx for portability");
+# endif
+#endif
+
+#if @GNULIB_MTX@
+# if !@HAVE_THREADS_H@
+_GL_FUNCDECL_SYS (mtx_destroy, void, (mtx_t *) _GL_ARG_NONNULL ((1)));
+# endif
+_GL_CXXALIAS_SYS (mtx_destroy, void, (mtx_t *));
+_GL_CXXALIASWARN (mtx_destroy);
+#elif defined GNULIB_POSIXCHECK
+# undef mtx_destroy
+# if HAVE_RAW_DECL_MTX_DESTROY
+_GL_WARN_ON_USE (mtx_destroy, "mtx_destroy is unportable - "
+ "use gnulib module mtx for portability");
+# endif
+#endif
+
+
+/* =========== ISO C 11 7.26.2 Initialization functions =========== */
+
+#if !@HAVE_THREADS_H@
+
+/* Type that contains a flag for use by call_once. */
+# if defined _WIN32 && ! defined __CYGWIN__
+/* Use Windows threads. */
+
+# include "windows-once.h"
+
+typedef glwthread_once_t once_flag;
+# define ONCE_FLAG_INIT GLWTHREAD_ONCE_INIT
+
+# else
+/* Use POSIX threads. */
+
+typedef pthread_once_t once_flag;
+# define ONCE_FLAG_INIT PTHREAD_ONCE_INIT
+
+# endif
+
+#endif
+
+#if @GNULIB_MTX@
+# if !@HAVE_THREADS_H@
+_GL_FUNCDECL_SYS (call_once, void, (once_flag *, void (*) (void))
+ _GL_ARG_NONNULL ((1, 2)));
+# endif
+_GL_CXXALIAS_SYS (call_once, void, (once_flag *, void (*) (void)));
+_GL_CXXALIASWARN (call_once);
+#elif defined GNULIB_POSIXCHECK
+# undef call_once
+# if HAVE_RAW_DECL_CALL_ONCE
+_GL_WARN_ON_USE (call_once, "call_once is unportable - "
+ "use gnulib module mtx for portability");
+# endif
+#endif
+
+
+/* =========== ISO C 11 7.26.3 Condition variable functions =========== */
+
+#if !@HAVE_THREADS_H@
+
+# if defined _WIN32 && ! defined __CYGWIN__
+/* Use Windows threads. */
+
+# include "windows-cond.h"
+
+typedef glwthread_cond_t cnd_t;
+
+# else
+/* Use POSIX threads. */
+
+typedef pthread_cond_t cnd_t;
+
+# endif
+
+#endif
+
+#if @GNULIB_CND@
+# if !@HAVE_THREADS_H@
+_GL_FUNCDECL_SYS (cnd_init, int, (cnd_t *) _GL_ARG_NONNULL ((1)));
+# endif
+_GL_CXXALIAS_SYS (cnd_init, int, (cnd_t *));
+_GL_CXXALIASWARN (cnd_init);
+#elif defined GNULIB_POSIXCHECK
+# undef cnd_init
+# if HAVE_RAW_DECL_CND_INIT
+_GL_WARN_ON_USE (cnd_init, "cnd_init is unportable - "
+ "use gnulib module cnd for portability");
+# endif
+#endif
+
+#if @GNULIB_CND@
+# if !@HAVE_THREADS_H@
+_GL_FUNCDECL_SYS (cnd_wait, int, (cnd_t *, mtx_t *) _GL_ARG_NONNULL ((1, 2)));
+# endif
+_GL_CXXALIAS_SYS (cnd_wait, int, (cnd_t *, mtx_t *));
+_GL_CXXALIASWARN (cnd_wait);
+#elif defined GNULIB_POSIXCHECK
+# undef cnd_wait
+# if HAVE_RAW_DECL_CND_WAIT
+_GL_WARN_ON_USE (cnd_wait, "cnd_wait is unportable - "
+ "use gnulib module cnd for portability");
+# endif
+#endif
+
+#if @GNULIB_CND@
+# if !@HAVE_THREADS_H@
+_GL_FUNCDECL_SYS (cnd_timedwait, int,
+ (cnd_t *, mtx_t *, const struct timespec *)
+ _GL_ARG_NONNULL ((1, 2, 3)));
+# endif
+_GL_CXXALIAS_SYS (cnd_timedwait, int,
+ (cnd_t *, mtx_t *, const struct timespec *));
+_GL_CXXALIASWARN (cnd_timedwait);
+#elif defined GNULIB_POSIXCHECK
+# undef cnd_timedwait
+# if HAVE_RAW_DECL_CND_TIMEDWAIT
+_GL_WARN_ON_USE (cnd_timedwait, "cnd_timedwait is unportable - "
+ "use gnulib module cnd for portability");
+# endif
+#endif
+
+#if @GNULIB_CND@
+# if !@HAVE_THREADS_H@
+_GL_FUNCDECL_SYS (cnd_signal, int, (cnd_t *) _GL_ARG_NONNULL ((1)));
+# endif
+_GL_CXXALIAS_SYS (cnd_signal, int, (cnd_t *));
+_GL_CXXALIASWARN (cnd_signal);
+#elif defined GNULIB_POSIXCHECK
+# undef cnd_signal
+# if HAVE_RAW_DECL_CND_SIGNAL
+_GL_WARN_ON_USE (cnd_signal, "cnd_signal is unportable - "
+ "use gnulib module cnd for portability");
+# endif
+#endif
+
+#if @GNULIB_CND@
+# if !@HAVE_THREADS_H@
+_GL_FUNCDECL_SYS (cnd_broadcast, int, (cnd_t *) _GL_ARG_NONNULL ((1)));
+# endif
+_GL_CXXALIAS_SYS (cnd_broadcast, int, (cnd_t *));
+_GL_CXXALIASWARN (cnd_broadcast);
+#elif defined GNULIB_POSIXCHECK
+# undef cnd_broadcast
+# if HAVE_RAW_DECL_CND_BROADCAST
+_GL_WARN_ON_USE (cnd_broadcast, "cnd_broadcast is unportable - "
+ "use gnulib module cnd for portability");
+# endif
+#endif
+
+#if @GNULIB_CND@
+# if !@HAVE_THREADS_H@
+_GL_FUNCDECL_SYS (cnd_destroy, void, (cnd_t *) _GL_ARG_NONNULL ((1)));
+# endif
+_GL_CXXALIAS_SYS (cnd_destroy, void, (cnd_t *));
+_GL_CXXALIASWARN (cnd_destroy);
+#elif defined GNULIB_POSIXCHECK
+# undef cnd_destroy
+# if HAVE_RAW_DECL_CND_DESTROY
+_GL_WARN_ON_USE (cnd_destroy, "cnd_destroy is unportable - "
+ "use gnulib module cnd for portability");
+# endif
+#endif
+
+
+/* =========== ISO C 11 7.26.6 Thread-specific storage functions =========== */
+
+#if !@HAVE_THREADS_H@
+
+# if defined _WIN32 && ! defined __CYGWIN__
+/* Use Windows threads. */
+
+# include "windows-tls.h"
+
+typedef glwthread_tls_key_t tss_t;
+# define TSS_DTOR_ITERATIONS 0 /* Destructors are currently unsupported. */
+
+# else
+/* Use POSIX threads. */
+
+# include <limits.h>
+
+typedef pthread_key_t tss_t;
+
+# endif
+
+/* Type for the destructor of a thread-specific storage pointer. */
+typedef void (*tss_dtor_t) (void *);
+
+#endif
+
+/* AIX 7.1 <threads.h> does not define TSS_DTOR_ITERATIONS. */
+#ifndef TSS_DTOR_ITERATIONS
+# ifdef PTHREAD_DESTRUCTOR_ITERATIONS
+# define TSS_DTOR_ITERATIONS PTHREAD_DESTRUCTOR_ITERATIONS
+# else
+ /* IRIX 6.5 does not define PTHREAD_DESTRUCTOR_ITERATIONS.
+ This value is a wild guess. */
+# define TSS_DTOR_ITERATIONS 1
+# endif
+#endif
+
+#if @GNULIB_TSS@
+# if !@HAVE_THREADS_H@
+_GL_FUNCDECL_SYS (tss_create, int, (tss_t *, tss_dtor_t) _GL_ARG_NONNULL ((1)));
+# endif
+_GL_CXXALIAS_SYS (tss_create, int, (tss_t *, tss_dtor_t));
+_GL_CXXALIASWARN (tss_create);
+#elif defined GNULIB_POSIXCHECK
+# undef tss_create
+# if HAVE_RAW_DECL_TSS_CREATE
+_GL_WARN_ON_USE (tss_create, "tss_create is unportable - "
+ "use gnulib module tss for portability");
+# endif
+#endif
+
+#if @GNULIB_TSS@
+# if !@HAVE_THREADS_H@
+_GL_FUNCDECL_SYS (tss_set, int, (tss_t, void *));
+# endif
+_GL_CXXALIAS_SYS (tss_set, int, (tss_t, void *));
+_GL_CXXALIASWARN (tss_set);
+#elif defined GNULIB_POSIXCHECK
+# undef tss_set
+# if HAVE_RAW_DECL_TSS_SET
+_GL_WARN_ON_USE (tss_set, "tss_set is unportable - "
+ "use gnulib module tss for portability");
+# endif
+#endif
+
+#if @GNULIB_TSS@
+# if !@HAVE_THREADS_H@
+_GL_FUNCDECL_SYS (tss_get, void *, (tss_t));
+# endif
+_GL_CXXALIAS_SYS (tss_get, void *, (tss_t));
+_GL_CXXALIASWARN (tss_get);
+#elif defined GNULIB_POSIXCHECK
+# undef tss_get
+# if HAVE_RAW_DECL_TSS_GET
+_GL_WARN_ON_USE (tss_get, "tss_get is unportable - "
+ "use gnulib module tss for portability");
+# endif
+#endif
+
+#if @GNULIB_TSS@
+# if !@HAVE_THREADS_H@
+_GL_FUNCDECL_SYS (tss_delete, void, (tss_t));
+# endif
+_GL_CXXALIAS_SYS (tss_delete, void, (tss_t));
+_GL_CXXALIASWARN (tss_delete);
+#elif defined GNULIB_POSIXCHECK
+# undef tss_delete
+# if HAVE_RAW_DECL_TSS_DELETE
+_GL_WARN_ON_USE (tss_delete, "tss_delete is unportable - "
+ "use gnulib module tss for portability");
+# endif
+#endif
+
+
+#endif /* _@GUARD_PREFIX@_THREADS_H */
+#endif /* _@GUARD_PREFIX@_THREADS_H */
diff --git a/m4/threads.m4 b/m4/threads.m4
new file mode 100644
index 0000000000..3cb3ae1d3f
--- /dev/null
+++ b/m4/threads.m4
@@ -0,0 +1,126 @@
+# threads.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_THREADS_H],
+[
+ AC_REQUIRE([gl_THREADS_H_DEFAULTS])
+ AC_REQUIRE([AC_CANONICAL_HOST])
+ AC_REQUIRE([gl_THREADLIB_BODY])
+ AC_REQUIRE([gl_YIELD])
+
+ gl_CHECK_NEXT_HEADERS([threads.h])
+ if test $ac_cv_header_threads_h = yes; then
+ HAVE_THREADS_H=1
+ else
+ HAVE_THREADS_H=0
+ fi
+ AC_SUBST([HAVE_THREADS_H])
+
+ if test $HAVE_THREADS_H = 1; then
+ dnl AIX 7.1..7.2 defines thrd_start_t incorrectly, namely as
+ dnl 'void * (*) (void *)' instead of 'int (*) (void *)'.
+ AC_CACHE_CHECK([whether thrd_start_t is correct],
+ [gl_cv_thrd_start_t_correct],
+ [AC_COMPILE_IFELSE(
+ [AC_LANG_PROGRAM([[
+ #include <threads.h>
+ #ifdef __cplusplus
+ extern "C" {
+ #endif
+ extern void foo (thrd_start_t);
+ extern void foo (int (*) (void *));
+ #ifdef __cplusplus
+ }
+ #endif
+ ]], [[]])],
+ [gl_cv_thrd_start_t_correct=yes],
+ [gl_cv_thrd_start_t_correct=no])
+ ])
+ if test $gl_cv_thrd_start_t_correct != yes; then
+ BROKEN_THRD_START_T=1
+ fi
+ fi
+
+ case "$host_os" in
+ mingw*)
+ LIBSTDTHREAD=
+ LTLIBSTDTHREAD=
+ ;;
+ *)
+ if test $ac_cv_header_threads_h = yes; then
+ dnl glibc >= 2.29 has thrd_create in libpthread.
+ dnl FreeBSD >= 10 has thrd_create in libstdthreads.
+ dnl AIX >= 7.1 and Solaris >= 11.4 have thrd_create in libc.
+ AC_CHECK_FUNCS([thrd_create])
+ if test $ac_cv_func_thrd_create = yes; then
+ LIBSTDTHREAD=
+ LTLIBSTDTHREAD=
+ else
+ AC_CHECK_LIB([stdthreads], [thrd_create], [
+ LIBSTDTHREAD='-lstdthreads'
+ LTLIBSTDTHREAD='-lstdthreads'
+ ], [
+ dnl Guess that thrd_create is in libpthread.
+ LIBSTDTHREAD="$LIBMULTITHREAD"
+ LTLIBSTDTHREAD="$LTLIBMULTITHREAD"
+ ])
+ fi
+ else
+ dnl Libraries needed by thrd.c, mtx.c, cnd.c, tss.c.
+ LIBSTDTHREAD="$LIBMULTITHREAD $YIELD_LIB"
+ LTLIBSTDTHREAD="$LTLIBMULTITHREAD $YIELD_LIB"
+ fi
+ ;;
+ esac
+ AC_SUBST([LIBSTDTHREAD])
+ AC_SUBST([LTLIBSTDTHREAD])
+
+ AH_VERBATIM([thread_local],
+[/* The _Thread_local keyword of C11. */
+#ifndef _Thread_local
+# if defined __GNUC__
+# define _Thread_local __thread
+# elif defined _MSC_VER
+# define _Thread_local __declspec (thread)
+# endif
+#endif
+])
+
+ dnl Check for declarations of anything we want to poison if the
+ dnl corresponding gnulib module is not in use, and which is not
+ dnl guaranteed by C89.
+ gl_WARN_ON_USE_PREPARE([[#include <threads.h>
+ ]], [call_once
+ cnd_broadcast cnd_destroy cnd_init cnd_signal cnd_timedwait cnd_wait
+ mtx_destroy mtx_init mtx_lock mtx_timedlock mtx_trylock mtx_unlock
+ thrd_create thrd_current thrd_detach thrd_equal thrd_exit thrd_join
+ thrd_sleep thrd_yield
+ tss_create tss_delete tss_get tss_set])
+])
+
+AC_DEFUN([gl_THREADS_MODULE_INDICATOR],
+[
+ dnl Use AC_REQUIRE here, so that the default settings are expanded once only.
+ AC_REQUIRE([gl_THREADS_H_DEFAULTS])
+ gl_MODULE_INDICATOR_SET_VARIABLE([$1])
+ dnl Define it also as a C macro, for the benefit of the unit tests.
+ gl_MODULE_INDICATOR_FOR_TESTS([$1])
+])
+
+AC_DEFUN([gl_THREADS_H_DEFAULTS],
+[
+ GNULIB_CND=0; AC_SUBST([GNULIB_CND])
+ GNULIB_MTX=0; AC_SUBST([GNULIB_MTX])
+ GNULIB_THRD=0; AC_SUBST([GNULIB_THRD])
+ GNULIB_TSS=0; AC_SUBST([GNULIB_TSS])
+ dnl Assume proper GNU behavior unless another module says otherwise.
+ BROKEN_THRD_START_T=0; AC_SUBST([BROKEN_THRD_START_T])
+ REPLACE_THRD_CREATE=0; AC_SUBST([REPLACE_THRD_CREATE])
+ REPLACE_THRD_CURRENT=0; AC_SUBST([REPLACE_THRD_CURRENT])
+ REPLACE_THRD_DETACH=0; AC_SUBST([REPLACE_THRD_DETACH])
+ REPLACE_THRD_EQUAL=0; AC_SUBST([REPLACE_THRD_EQUAL])
+ REPLACE_THRD_JOIN=0; AC_SUBST([REPLACE_THRD_JOIN])
+])
diff --git a/m4/yield.m4 b/m4/yield.m4
index 13f6f204a5..59c8c38eb4 100644
--- a/m4/yield.m4
+++ b/m4/yield.m4
@@ -1,4 +1,4 @@
-# yield.m4 serial 2
+# yield.m4 serial 3
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,
@@ -10,7 +10,7 @@ AC_DEFUN([gl_YIELD],
dnl On some systems, sched_yield is in librt, rather than in libpthread.
YIELD_LIB=
if test $gl_threads_api = posix; then
- dnl Solaris has sched_yield in librt, not in libpthread or libc.
+ dnl Solaris 7...10 has sched_yield in librt, not in libpthread or libc.
AC_CHECK_LIB([rt], [sched_yield], [YIELD_LIB=-lrt],
[dnl Solaris 2.5.1, 2.6 has sched_yield in libposix4, not librt.
AC_CHECK_LIB([posix4], [sched_yield], [YIELD_LIB=-lposix4])])
diff --git a/modules/threads-h b/modules/threads-h
new file mode 100644
index 0000000000..238955c6b5
--- /dev/null
+++ b/modules/threads-h
@@ -0,0 +1,73 @@
+Description:
+An ISO C 11 compatible <threads.h>.
+
+Files:
+lib/threads.in.h
+lib/windows-thread.h
+lib/windows-mutex.h
+lib/windows-recmutex.h
+lib/windows-timedmutex.h
+lib/windows-timedrecmutex.h
+lib/windows-once.h
+lib/windows-cond.h
+lib/windows-tls.h
+lib/windows-spinlock.h
+m4/threads.m4
+m4/threadlib.m4
+m4/yield.m4
+build-aux/config.rpath
+
+Depends-on:
+include_next
+snippet/c++defs
+snippet/_Noreturn
+snippet/arg-nonnull
+snippet/warn-on-use
+time
+havelib
+
+configure.ac-early:
+gl_THREADLIB_EARLY
+
+configure.ac:
+AC_REQUIRE([gl_THREADS_H])
+
+Makefile.am:
+BUILT_SOURCES += threads.h
+
+# We need the following in order to create <threads.h> when the system
+# doesn't have one.
+threads.h: threads.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(_NORETURN_H) $(ARG_NONNULL_H) $(WARN_ON_USE_H)
+ $(AM_V_GEN)rm -f $@-t $@ && \
+ { echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */' && \
+ sed -e 's|@''GUARD_PREFIX''@|${gl_include_guard_prefix}|g' \
+ -e 's|@''HAVE_THREADS_H''@|$(HAVE_THREADS_H)|g' \
+ -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \
+ -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \
+ -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \
+ -e 's|@''NEXT_THREADS_H''@|$(NEXT_THREADS_H)|g' \
+ -e 's/@''GNULIB_CND''@/$(GNULIB_CND)/g' \
+ -e 's/@''GNULIB_MTX''@/$(GNULIB_MTX)/g' \
+ -e 's/@''GNULIB_THRD''@/$(GNULIB_THRD)/g' \
+ -e 's/@''GNULIB_TSS''@/$(GNULIB_TSS)/g' \
+ -e 's|@''BROKEN_THRD_START_T''@|$(BROKEN_THRD_START_T)|g' \
+ -e 's|@''REPLACE_THRD_CREATE''@|$(REPLACE_THRD_CREATE)|g' \
+ -e 's|@''REPLACE_THRD_CURRENT''@|$(REPLACE_THRD_CURRENT)|g' \
+ -e 's|@''REPLACE_THRD_DETACH''@|$(REPLACE_THRD_DETACH)|g' \
+ -e 's|@''REPLACE_THRD_EQUAL''@|$(REPLACE_THRD_EQUAL)|g' \
+ -e 's|@''REPLACE_THRD_JOIN''@|$(REPLACE_THRD_JOIN)|g' \
+ < $(srcdir)/threads.in.h; \
+ } > $@-t && \
+ mv $@-t $@
+MOSTLYCLEANFILES += threads.h threads.h-t
+
+Include:
+<threads.h>
+
+Link:
+
+License:
+LGPLv2+
+
+Maintainer:
+all
diff --git a/modules/yield b/modules/yield
index 24ffcdd243..71e00ea73d 100644
--- a/modules/yield
+++ b/modules/yield
@@ -9,7 +9,7 @@ Depends-on:
threadlib
configure.ac:
-gl_YIELD
+AC_REQUIRE([gl_YIELD])
Makefile.am:
lib_SOURCES += glthread/yield.h