summaryrefslogtreecommitdiffstats
path: root/gl/glthread/once.h
diff options
context:
space:
mode:
Diffstat (limited to 'gl/glthread/once.h')
-rw-r--r--gl/glthread/once.h272
1 files changed, 272 insertions, 0 deletions
diff --git a/gl/glthread/once.h b/gl/glthread/once.h
new file mode 100644
index 00000000..943bd7a2
--- /dev/null
+++ b/gl/glthread/once.h
@@ -0,0 +1,272 @@
1/* Once-only initialization in multithreaded situations.
2 Copyright (C) 2005-2025 Free Software Foundation, Inc.
3
4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 2.1 of the
7 License, or (at your option) any later version.
8
9 This file is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
16
17/* Written by Bruno Haible <bruno@clisp.org>, 2005.
18 Based on GCC's gthr-posix.h, gthr-posix95.h, gthr-win32.h. */
19
20/* This file contains once-only initialization primitives for use with a given
21 thread library.
22 It does not contain primitives for creating threads or for other
23 synchronization primitives.
24
25 Once-only execution:
26 Type: gl_once_t
27 Initializer: gl_once_define(extern, name)
28 Execution: gl_once (name, initfunction);
29 Equivalent functions with control of error handling:
30 Execution: err = glthread_once (&name, initfunction);
31*/
32
33
34#ifndef _ONCE_H
35#define _ONCE_H
36
37/* This file uses HAVE_THREADS_H. */
38#if !_GL_CONFIG_H_INCLUDED
39 #error "Please include config.h first."
40#endif
41
42#include <errno.h>
43#include <stdlib.h>
44
45#if !defined c11_threads_in_use
46# if HAVE_THREADS_H && USE_POSIX_THREADS_FROM_LIBC
47# define c11_threads_in_use() 1
48# elif HAVE_THREADS_H && USE_POSIX_THREADS_WEAK
49# include <threads.h>
50# pragma weak thrd_exit
51# define c11_threads_in_use() (thrd_exit != NULL)
52# else
53# define c11_threads_in_use() 0
54# endif
55#endif
56
57/* ========================================================================= */
58
59#if USE_ISOC_THREADS || USE_ISOC_AND_POSIX_THREADS
60
61/* Use the ISO C threads library. */
62
63# include <threads.h>
64
65# ifdef __cplusplus
66extern "C" {
67# endif
68
69/* -------------------------- gl_once_t datatype -------------------------- */
70
71typedef once_flag gl_once_t;
72# define gl_once_define(STORAGECLASS, NAME) \
73 STORAGECLASS once_flag NAME = ONCE_FLAG_INIT;
74# define glthread_once(ONCE_CONTROL, INITFUNCTION) \
75 (call_once (ONCE_CONTROL, INITFUNCTION), 0)
76
77# ifdef __cplusplus
78}
79# endif
80
81#endif
82
83/* ========================================================================= */
84
85#if USE_POSIX_THREADS
86
87/* Use the POSIX threads library. */
88
89# include <pthread.h>
90
91# ifdef __cplusplus
92extern "C" {
93# endif
94
95# if PTHREAD_IN_USE_DETECTION_HARD
96
97/* The pthread_in_use() detection needs to be done at runtime. */
98# define pthread_in_use() \
99 glthread_in_use ()
100extern int glthread_in_use (void);
101
102# endif
103
104# if USE_POSIX_THREADS_WEAK
105
106/* Use weak references to the POSIX threads library. */
107
108/* Weak references avoid dragging in external libraries if the other parts
109 of the program don't use them. Here we use them, because we don't want
110 every program that uses libintl to depend on libpthread. This assumes
111 that libpthread would not be loaded after libintl; i.e. if libintl is
112 loaded first, by an executable that does not depend on libpthread, and
113 then a module is dynamically loaded that depends on libpthread, libintl
114 will not be multithread-safe. */
115
116/* The way to test at runtime whether libpthread is present is to test
117 whether a function pointer's value, such as &pthread_mutex_init, is
118 non-NULL. However, some versions of GCC have a bug through which, in
119 PIC mode, &foo != NULL always evaluates to true if there is a direct
120 call to foo(...) in the same function. To avoid this, we test the
121 address of a function in libpthread that we don't use. */
122
123# pragma weak pthread_mutex_init
124# pragma weak pthread_mutex_lock
125# pragma weak pthread_mutex_unlock
126# pragma weak pthread_mutex_destroy
127/* Work around clang bug <https://github.com/llvm/llvm-project/issues/104670> */
128# ifndef pthread_rwlock_init
129# pragma weak pthread_rwlock_init
130# endif
131# pragma weak pthread_rwlock_rdlock
132# pragma weak pthread_rwlock_wrlock
133# pragma weak pthread_rwlock_unlock
134# pragma weak pthread_rwlock_destroy
135# pragma weak pthread_once
136# pragma weak pthread_cond_init
137# pragma weak pthread_cond_wait
138# pragma weak pthread_cond_signal
139# pragma weak pthread_cond_broadcast
140# pragma weak pthread_cond_destroy
141# pragma weak pthread_mutexattr_init
142# pragma weak pthread_mutexattr_settype
143# pragma weak pthread_mutexattr_destroy
144/* Work around clang bug <https://github.com/llvm/llvm-project/issues/104670> */
145# ifndef pthread_rwlockattr_init
146# pragma weak pthread_rwlockattr_init
147# endif
148# if __GNU_LIBRARY__ > 1
149# pragma weak pthread_rwlockattr_setkind_np
150# endif
151# pragma weak pthread_rwlockattr_destroy
152# ifndef pthread_self
153# pragma weak pthread_self
154# endif
155
156# if !PTHREAD_IN_USE_DETECTION_HARD
157 /* Considering all platforms with USE_POSIX_THREADS_WEAK, only few symbols
158 can be used to determine whether libpthread is in use. These are:
159 pthread_mutexattr_gettype
160 pthread_rwlockattr_destroy
161 pthread_rwlockattr_init
162 */
163# pragma weak pthread_mutexattr_gettype
164# define pthread_in_use() \
165 (pthread_mutexattr_gettype != NULL || c11_threads_in_use ())
166# endif
167
168# else
169
170# if !PTHREAD_IN_USE_DETECTION_HARD
171# define pthread_in_use() 1
172# endif
173
174# endif
175
176/* -------------------------- gl_once_t datatype -------------------------- */
177
178typedef pthread_once_t gl_once_t;
179# define gl_once_define(STORAGECLASS, NAME) \
180 STORAGECLASS pthread_once_t NAME = PTHREAD_ONCE_INIT;
181# if PTHREAD_IN_USE_DETECTION_HARD || USE_POSIX_THREADS_WEAK
182# define glthread_once(ONCE_CONTROL, INITFUNCTION) \
183 (pthread_in_use () \
184 ? pthread_once (ONCE_CONTROL, INITFUNCTION) \
185 : (glthread_once_singlethreaded (ONCE_CONTROL) ? (INITFUNCTION (), 0) : 0))
186# else
187# define glthread_once(ONCE_CONTROL, INITFUNCTION) \
188 (pthread_in_use () \
189 ? glthread_once_multithreaded (ONCE_CONTROL, INITFUNCTION) \
190 : (glthread_once_singlethreaded (ONCE_CONTROL) ? (INITFUNCTION (), 0) : 0))
191extern int glthread_once_multithreaded (pthread_once_t *once_control,
192 void (*init_function) (void));
193# endif
194extern int glthread_once_singlethreaded (pthread_once_t *once_control);
195
196# ifdef __cplusplus
197}
198# endif
199
200#endif
201
202/* ========================================================================= */
203
204#if USE_WINDOWS_THREADS
205
206# define WIN32_LEAN_AND_MEAN /* avoid including junk */
207# include <windows.h>
208
209# include "windows-once.h"
210
211# ifdef __cplusplus
212extern "C" {
213# endif
214
215/* We can use CRITICAL_SECTION directly, rather than the native Windows Event,
216 Mutex, Semaphore types, because
217 - we need only to synchronize inside a single process (address space),
218 not inter-process locking,
219 - we don't need to support trylock operations. (TryEnterCriticalSection
220 does not work on Windows 95/98/ME. Packages that need trylock usually
221 define their own mutex type.) */
222
223/* There is no way to statically initialize a CRITICAL_SECTION. It needs
224 to be done lazily, once only. For this we need spinlocks. */
225
226/* -------------------------- gl_once_t datatype -------------------------- */
227
228typedef glwthread_once_t gl_once_t;
229# define gl_once_define(STORAGECLASS, NAME) \
230 STORAGECLASS gl_once_t NAME = GLWTHREAD_ONCE_INIT;
231# define glthread_once(ONCE_CONTROL, INITFUNCTION) \
232 (glwthread_once (ONCE_CONTROL, INITFUNCTION), 0)
233
234# ifdef __cplusplus
235}
236# endif
237
238#endif
239
240/* ========================================================================= */
241
242#if !(USE_ISOC_THREADS || USE_POSIX_THREADS || USE_ISOC_AND_POSIX_THREADS || USE_WINDOWS_THREADS)
243
244/* Provide dummy implementation if threads are not supported. */
245
246/* -------------------------- gl_once_t datatype -------------------------- */
247
248typedef int gl_once_t;
249# define gl_once_define(STORAGECLASS, NAME) \
250 STORAGECLASS gl_once_t NAME = 0;
251# define glthread_once(ONCE_CONTROL, INITFUNCTION) \
252 (*(ONCE_CONTROL) == 0 ? (*(ONCE_CONTROL) = ~ 0, INITFUNCTION (), 0) : 0)
253
254#endif
255
256/* ========================================================================= */
257
258/* Macros with built-in error handling. */
259
260/* -------------------------- gl_once_t datatype -------------------------- */
261
262#define gl_once(NAME, INITFUNCTION) \
263 do \
264 { \
265 if (glthread_once (&NAME, INITFUNCTION)) \
266 abort (); \
267 } \
268 while (0)
269
270/* ========================================================================= */
271
272#endif /* _ONCE_H */