]> Savannah Git Hosting - gnulib.git/commitdiff
once: New module, extracted from lock.
authorBruno Haible <bruno@clisp.org>
Sun, 4 Aug 2024 21:55:37 +0000 (23:55 +0200)
committerBruno Haible <bruno@clisp.org>
Sun, 4 Aug 2024 21:55:37 +0000 (23:55 +0200)
* lib/glthread/once.h: New file, extracted from lib/glthread/lock.h.
* lib/glthread/once.c: New file, extracted from lib/glthread/lock.c.
* lib/glthread/lock.h: Include glthread/once.h. Don't include
windows-once.h.
(c11_threads_in_use, glthread_in_use, gl_once_t, gl_once_define,
glthread_once): Remove.
(glthread_once_singlethreaded, glthread_once_multithreaded): Remove
declarations.
* lib/glthread/lock.c (fresh_once, glthread_once_singlethreaded,
glthread_once_multithreaded): Remove.
* modules/once: New file.
* modules/lock (Depends-on): Add once. Remove pthread-once,
windows-once.
* tests/test-once.c: Include glthread/once.h instead of glthread/lock.h.
* doc/multithread.texi (Gnulib multithreading): Mention the module
'once'.

ChangeLog
doc/multithread.texi
lib/glthread/lock.c
lib/glthread/lock.h
lib/glthread/once.c [new file with mode: 0644]
lib/glthread/once.h [new file with mode: 0644]
modules/lock
modules/once [new file with mode: 0644]
tests/test-once.c

index 779e593a14371301a881d44e7f1ffde8a95c74eb..67c46542f486efb186b9b02aad8cbf8c3c8548a9 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,23 @@
+2024-08-04  Bruno Haible  <bruno@clisp.org>
+
+       once: New module, extracted from lock.
+       * lib/glthread/once.h: New file, extracted from lib/glthread/lock.h.
+       * lib/glthread/once.c: New file, extracted from lib/glthread/lock.c.
+       * lib/glthread/lock.h: Include glthread/once.h. Don't include
+       windows-once.h.
+       (c11_threads_in_use, glthread_in_use, gl_once_t, gl_once_define,
+       glthread_once): Remove.
+       (glthread_once_singlethreaded, glthread_once_multithreaded): Remove
+       declarations.
+       * lib/glthread/lock.c (fresh_once, glthread_once_singlethreaded,
+       glthread_once_multithreaded): Remove.
+       * modules/once: New file.
+       * modules/lock (Depends-on): Add once. Remove pthread-once,
+       windows-once.
+       * tests/test-once.c: Include glthread/once.h instead of glthread/lock.h.
+       * doc/multithread.texi (Gnulib multithreading): Mention the module
+       'once'.
+
 2024-08-03  Bruno Haible  <bruno@clisp.org>
 
        gnulib-tool.py: Small refactoring.
index db350f344e5ff35a816191a11b398cf4cd490397..ff16caa2268b68926b2790119c3494cf60b1a803 100644 (file)
@@ -182,6 +182,8 @@ The Gnulib multithreading API is documented in the respective include files:
 @item
 @code{<glthread/lock.h>}
 @item
+@code{<glthread/once.h>}
+@item
 @code{<glthread/cond.h>}
 @item
 @code{<glthread/tls.h>}
@@ -195,7 +197,7 @@ To make use of Gnulib multithreading, use the following Gnulib modules:
 @item For thread creation and management:@tie{} @tab @code{thread}
 @item For simple locks, recursive locks, and read-write locks:@tie{}
       @tab @code{lock}
-@item For once-only execution:@tie{} @tab @code{lock}
+@item For once-only execution:@tie{} @tab @code{once}
 @item For ``condition variables'' (wait queues):@tie{} @tab @code{cond}
 @item For thread-local storage:@tie{} @tab @code{tls}
 @item For relinquishing control:@tie{} @tab @code{yield}
index 6661ad6a82c514418474d92414daf461472ebfd9..40b2a5ee4feaa03a0e36d16a27e85fd5d3d7822f 100644 (file)
@@ -240,8 +240,6 @@ glthread_recursive_lock_destroy (gl_recursive_lock_t *lock)
   return 0;
 }
 
-/* -------------------------- gl_once_t datatype -------------------------- */
-
 #endif
 
 /* ========================================================================= */
@@ -698,46 +696,6 @@ glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock)
 
 # endif
 
-/* -------------------------- gl_once_t datatype -------------------------- */
-
-static const pthread_once_t fresh_once = PTHREAD_ONCE_INIT;
-
-int
-glthread_once_singlethreaded (pthread_once_t *once_control)
-{
-  /* We don't know whether pthread_once_t is an integer type, a floating-point
-     type, a pointer type, or a structure type.  */
-  char *firstbyte = (char *)once_control;
-  if (*firstbyte == *(const char *)&fresh_once)
-    {
-      /* First time use of once_control.  Invert the first byte.  */
-      *firstbyte = ~ *(const char *)&fresh_once;
-      return 1;
-    }
-  else
-    return 0;
-}
-
-# if !(PTHREAD_IN_USE_DETECTION_HARD || USE_POSIX_THREADS_WEAK)
-
-int
-glthread_once_multithreaded (pthread_once_t *once_control,
-                             void (*init_function) (void))
-{
-  int err = pthread_once (once_control, init_function);
-  if (err == ENOSYS)
-    {
-      /* This happens on FreeBSD 11: The pthread_once function in libc returns
-         ENOSYS.  */
-      if (glthread_once_singlethreaded (once_control))
-        init_function ();
-      return 0;
-    }
-  return err;
-}
-
-# endif
-
 #endif
 
 /* ========================================================================= */
index 2d5cb3209c5fb28c965fd459af86d3b29f20cc27..2b9c0f2e1442e51024cdaeafafa1e9c5385ad247 100644 (file)
      Taking the lock:     err = glthread_recursive_lock_lock (&name);
      Releasing the lock:  err = glthread_recursive_lock_unlock (&name);
      De-initialization:   err = glthread_recursive_lock_destroy (&name);
-
-  Once-only execution:
-     Type:                gl_once_t
-     Initializer:         gl_once_define(extern, name)
-     Execution:           gl_once (name, initfunction);
-   Equivalent functions with control of error handling:
-     Execution:           err = glthread_once (&name, initfunction);
 */
 
 
 #include <errno.h>
 #include <stdlib.h>
 
-#if !defined c11_threads_in_use
-# if HAVE_THREADS_H && USE_POSIX_THREADS_FROM_LIBC
-#  define c11_threads_in_use() 1
-# elif HAVE_THREADS_H && USE_POSIX_THREADS_WEAK
-#  include <threads.h>
-#  pragma weak thrd_exit
-#  define c11_threads_in_use() (thrd_exit != NULL)
-# else
-#  define c11_threads_in_use() 0
-# endif
-#endif
+#include "glthread/once.h"
+
+/* c11_threads_in_use() is defined in glthread/once.h.  */
 
 /* ========================================================================= */
 
@@ -195,14 +180,6 @@ 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
@@ -221,80 +198,7 @@ typedef once_flag gl_once_t;
 extern "C" {
 # endif
 
-# if PTHREAD_IN_USE_DETECTION_HARD
-
-/* The pthread_in_use() detection needs to be done at runtime.  */
-#  define pthread_in_use() \
-     glthread_in_use ()
-extern int glthread_in_use (void);
-
-# endif
-
-# if USE_POSIX_THREADS_WEAK
-
-/* Use weak references to the POSIX threads library.  */
-
-/* Weak references avoid dragging in external libraries if the other parts
-   of the program don't use them.  Here we use them, because we don't want
-   every program that uses libintl to depend on libpthread.  This assumes
-   that libpthread would not be loaded after libintl; i.e. if libintl is
-   loaded first, by an executable that does not depend on libpthread, and
-   then a module is dynamically loaded that depends on libpthread, libintl
-   will not be multithread-safe.  */
-
-/* The way to test at runtime whether libpthread is present is to test
-   whether a function pointer's value, such as &pthread_mutex_init, is
-   non-NULL.  However, some versions of GCC have a bug through which, in
-   PIC mode, &foo != NULL always evaluates to true if there is a direct
-   call to foo(...) in the same function.  To avoid this, we test the
-   address of a function in libpthread that we don't use.  */
-
-#  pragma weak pthread_mutex_init
-#  pragma weak pthread_mutex_lock
-#  pragma weak pthread_mutex_unlock
-#  pragma weak pthread_mutex_destroy
-#  pragma weak pthread_rwlock_init
-#  pragma weak pthread_rwlock_rdlock
-#  pragma weak pthread_rwlock_wrlock
-#  pragma weak pthread_rwlock_unlock
-#  pragma weak pthread_rwlock_destroy
-#  pragma weak pthread_once
-#  pragma weak pthread_cond_init
-#  pragma weak pthread_cond_wait
-#  pragma weak pthread_cond_signal
-#  pragma weak pthread_cond_broadcast
-#  pragma weak pthread_cond_destroy
-#  pragma weak pthread_mutexattr_init
-#  pragma weak pthread_mutexattr_settype
-#  pragma weak pthread_mutexattr_destroy
-#  pragma weak pthread_rwlockattr_init
-#  if __GNU_LIBRARY__ > 1
-#   pragma weak pthread_rwlockattr_setkind_np
-#  endif
-#  pragma weak pthread_rwlockattr_destroy
-#  ifndef pthread_self
-#   pragma weak pthread_self
-#  endif
-
-#  if !PTHREAD_IN_USE_DETECTION_HARD
-    /* Considering all platforms with USE_POSIX_THREADS_WEAK, only few symbols
-       can be used to determine whether libpthread is in use.  These are:
-         pthread_mutexattr_gettype
-         pthread_rwlockattr_destroy
-         pthread_rwlockattr_init
-     */
-#   pragma weak pthread_mutexattr_gettype
-#   define pthread_in_use() \
-      (pthread_mutexattr_gettype != NULL || c11_threads_in_use ())
-#  endif
-
-# else
-
-#  if !PTHREAD_IN_USE_DETECTION_HARD
-#   define pthread_in_use() 1
-#  endif
-
-# endif
+/* pthread_in_use() is defined in glthread/once.h.  */
 
 /* -------------------------- gl_lock_t datatype -------------------------- */
 
@@ -510,26 +414,6 @@ extern int glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *l
 
 # endif
 
-/* -------------------------- gl_once_t datatype -------------------------- */
-
-typedef pthread_once_t gl_once_t;
-# define gl_once_define(STORAGECLASS, NAME) \
-    STORAGECLASS pthread_once_t NAME = PTHREAD_ONCE_INIT;
-# if PTHREAD_IN_USE_DETECTION_HARD || USE_POSIX_THREADS_WEAK
-#  define glthread_once(ONCE_CONTROL, INITFUNCTION) \
-     (pthread_in_use ()                                                        \
-      ? pthread_once (ONCE_CONTROL, INITFUNCTION)                              \
-      : (glthread_once_singlethreaded (ONCE_CONTROL) ? (INITFUNCTION (), 0) : 0))
-# else
-#  define glthread_once(ONCE_CONTROL, INITFUNCTION) \
-     (pthread_in_use ()                                                        \
-      ? glthread_once_multithreaded (ONCE_CONTROL, INITFUNCTION)               \
-      : (glthread_once_singlethreaded (ONCE_CONTROL) ? (INITFUNCTION (), 0) : 0))
-extern int glthread_once_multithreaded (pthread_once_t *once_control,
-                                        void (*init_function) (void));
-# endif
-extern int glthread_once_singlethreaded (pthread_once_t *once_control);
-
 # ifdef __cplusplus
 }
 # endif
@@ -546,7 +430,6 @@ extern int glthread_once_singlethreaded (pthread_once_t *once_control);
 # include "windows-mutex.h"
 # include "windows-rwlock.h"
 # include "windows-recmutex.h"
-# include "windows-once.h"
 
 # ifdef __cplusplus
 extern "C" {
@@ -619,14 +502,6 @@ typedef glwthread_recmutex_t gl_recursive_lock_t;
 # define glthread_recursive_lock_destroy(LOCK) \
     glwthread_recmutex_destroy (LOCK)
 
-/* -------------------------- gl_once_t datatype -------------------------- */
-
-typedef glwthread_once_t gl_once_t;
-# define gl_once_define(STORAGECLASS, NAME) \
-    STORAGECLASS gl_once_t NAME = GLWTHREAD_ONCE_INIT;
-# define glthread_once(ONCE_CONTROL, INITFUNCTION) \
-    (glwthread_once (ONCE_CONTROL, INITFUNCTION), 0)
-
 # ifdef __cplusplus
 }
 # endif
@@ -670,14 +545,6 @@ typedef int gl_recursive_lock_t;
 # define glthread_recursive_lock_unlock(NAME) 0
 # define glthread_recursive_lock_destroy(NAME) 0
 
-/* -------------------------- gl_once_t datatype -------------------------- */
-
-typedef int gl_once_t;
-# define gl_once_define(STORAGECLASS, NAME) \
-    STORAGECLASS gl_once_t NAME = 0;
-# define glthread_once(ONCE_CONTROL, INITFUNCTION) \
-    (*(ONCE_CONTROL) == 0 ? (*(ONCE_CONTROL) = ~ 0, INITFUNCTION (), 0) : 0)
-
 #endif
 
 /* ========================================================================= */
@@ -784,16 +651,6 @@ typedef int gl_once_t;
      }                                              \
    while (0)
 
-/* -------------------------- gl_once_t datatype -------------------------- */
-
-#define gl_once(NAME, INITFUNCTION) \
-   do                                           \
-     {                                          \
-       if (glthread_once (&NAME, INITFUNCTION)) \
-         abort ();                              \
-     }                                          \
-   while (0)
-
 /* ========================================================================= */
 
 #endif /* _LOCK_H */
diff --git a/lib/glthread/once.c b/lib/glthread/once.c
new file mode 100644 (file)
index 0000000..869ba3b
--- /dev/null
@@ -0,0 +1,80 @@
+/* Once-only initialization in multithreaded situations.
+   Copyright (C) 2005-2024 Free Software Foundation, Inc.
+
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   This file 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 Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
+/* Written by Bruno Haible <bruno@clisp.org>, 2005.
+   Based on GCC's gthr-posix.h, gthr-posix95.h.  */
+
+#include <config.h>
+
+#include "glthread/once.h"
+
+/* ========================================================================= */
+
+#if USE_ISOC_THREADS || USE_ISOC_AND_POSIX_THREADS
+
+#endif
+
+/* ========================================================================= */
+
+#if USE_POSIX_THREADS
+
+static const pthread_once_t fresh_once = PTHREAD_ONCE_INIT;
+
+int
+glthread_once_singlethreaded (pthread_once_t *once_control)
+{
+  /* We don't know whether pthread_once_t is an integer type, a floating-point
+     type, a pointer type, or a structure type.  */
+  char *firstbyte = (char *)once_control;
+  if (*firstbyte == *(const char *)&fresh_once)
+    {
+      /* First time use of once_control.  Invert the first byte.  */
+      *firstbyte = ~ *(const char *)&fresh_once;
+      return 1;
+    }
+  else
+    return 0;
+}
+
+# if !(PTHREAD_IN_USE_DETECTION_HARD || USE_POSIX_THREADS_WEAK)
+
+int
+glthread_once_multithreaded (pthread_once_t *once_control,
+                             void (*init_function) (void))
+{
+  int err = pthread_once (once_control, init_function);
+  if (err == ENOSYS)
+    {
+      /* This happens on FreeBSD 11: The pthread_once function in libc returns
+         ENOSYS.  */
+      if (glthread_once_singlethreaded (once_control))
+        init_function ();
+      return 0;
+    }
+  return err;
+}
+
+# endif
+
+#endif
+
+/* ========================================================================= */
+
+#if USE_WINDOWS_THREADS
+
+#endif
+
+/* ========================================================================= */
diff --git a/lib/glthread/once.h b/lib/glthread/once.h
new file mode 100644 (file)
index 0000000..fd00e42
--- /dev/null
@@ -0,0 +1,266 @@
+/* Once-only initialization in multithreaded situations.
+   Copyright (C) 2005-2024 Free Software Foundation, Inc.
+
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   This file 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 Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
+/* Written by Bruno Haible <bruno@clisp.org>, 2005.
+   Based on GCC's gthr-posix.h, gthr-posix95.h, gthr-win32.h.  */
+
+/* This file contains once-only initialization primitives for use with a given
+   thread library.
+   It does not contain primitives for creating threads or for other
+   synchronization primitives.
+
+  Once-only execution:
+     Type:                gl_once_t
+     Initializer:         gl_once_define(extern, name)
+     Execution:           gl_once (name, initfunction);
+   Equivalent functions with control of error handling:
+     Execution:           err = glthread_once (&name, initfunction);
+*/
+
+
+#ifndef _ONCE_H
+#define _ONCE_H
+
+/* This file uses HAVE_THREADS_H.  */
+#if !_GL_CONFIG_H_INCLUDED
+ #error "Please include config.h first."
+#endif
+
+#include <errno.h>
+#include <stdlib.h>
+
+#if !defined c11_threads_in_use
+# if HAVE_THREADS_H && USE_POSIX_THREADS_FROM_LIBC
+#  define c11_threads_in_use() 1
+# elif HAVE_THREADS_H && USE_POSIX_THREADS_WEAK
+#  include <threads.h>
+#  pragma weak thrd_exit
+#  define c11_threads_in_use() (thrd_exit != NULL)
+# else
+#  define c11_threads_in_use() 0
+# endif
+#endif
+
+/* ========================================================================= */
+
+#if USE_ISOC_THREADS || USE_ISOC_AND_POSIX_THREADS
+
+/* Use the ISO C threads library.  */
+
+# include <threads.h>
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+/* -------------------------- 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.  */
+
+# include <pthread.h>
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+# if PTHREAD_IN_USE_DETECTION_HARD
+
+/* The pthread_in_use() detection needs to be done at runtime.  */
+#  define pthread_in_use() \
+     glthread_in_use ()
+extern int glthread_in_use (void);
+
+# endif
+
+# if USE_POSIX_THREADS_WEAK
+
+/* Use weak references to the POSIX threads library.  */
+
+/* Weak references avoid dragging in external libraries if the other parts
+   of the program don't use them.  Here we use them, because we don't want
+   every program that uses libintl to depend on libpthread.  This assumes
+   that libpthread would not be loaded after libintl; i.e. if libintl is
+   loaded first, by an executable that does not depend on libpthread, and
+   then a module is dynamically loaded that depends on libpthread, libintl
+   will not be multithread-safe.  */
+
+/* The way to test at runtime whether libpthread is present is to test
+   whether a function pointer's value, such as &pthread_mutex_init, is
+   non-NULL.  However, some versions of GCC have a bug through which, in
+   PIC mode, &foo != NULL always evaluates to true if there is a direct
+   call to foo(...) in the same function.  To avoid this, we test the
+   address of a function in libpthread that we don't use.  */
+
+#  pragma weak pthread_mutex_init
+#  pragma weak pthread_mutex_lock
+#  pragma weak pthread_mutex_unlock
+#  pragma weak pthread_mutex_destroy
+#  pragma weak pthread_rwlock_init
+#  pragma weak pthread_rwlock_rdlock
+#  pragma weak pthread_rwlock_wrlock
+#  pragma weak pthread_rwlock_unlock
+#  pragma weak pthread_rwlock_destroy
+#  pragma weak pthread_once
+#  pragma weak pthread_cond_init
+#  pragma weak pthread_cond_wait
+#  pragma weak pthread_cond_signal
+#  pragma weak pthread_cond_broadcast
+#  pragma weak pthread_cond_destroy
+#  pragma weak pthread_mutexattr_init
+#  pragma weak pthread_mutexattr_settype
+#  pragma weak pthread_mutexattr_destroy
+#  pragma weak pthread_rwlockattr_init
+#  if __GNU_LIBRARY__ > 1
+#   pragma weak pthread_rwlockattr_setkind_np
+#  endif
+#  pragma weak pthread_rwlockattr_destroy
+#  ifndef pthread_self
+#   pragma weak pthread_self
+#  endif
+
+#  if !PTHREAD_IN_USE_DETECTION_HARD
+    /* Considering all platforms with USE_POSIX_THREADS_WEAK, only few symbols
+       can be used to determine whether libpthread is in use.  These are:
+         pthread_mutexattr_gettype
+         pthread_rwlockattr_destroy
+         pthread_rwlockattr_init
+     */
+#   pragma weak pthread_mutexattr_gettype
+#   define pthread_in_use() \
+      (pthread_mutexattr_gettype != NULL || c11_threads_in_use ())
+#  endif
+
+# else
+
+#  if !PTHREAD_IN_USE_DETECTION_HARD
+#   define pthread_in_use() 1
+#  endif
+
+# endif
+
+/* -------------------------- gl_once_t datatype -------------------------- */
+
+typedef pthread_once_t gl_once_t;
+# define gl_once_define(STORAGECLASS, NAME) \
+    STORAGECLASS pthread_once_t NAME = PTHREAD_ONCE_INIT;
+# if PTHREAD_IN_USE_DETECTION_HARD || USE_POSIX_THREADS_WEAK
+#  define glthread_once(ONCE_CONTROL, INITFUNCTION) \
+     (pthread_in_use ()                                                        \
+      ? pthread_once (ONCE_CONTROL, INITFUNCTION)                              \
+      : (glthread_once_singlethreaded (ONCE_CONTROL) ? (INITFUNCTION (), 0) : 0))
+# else
+#  define glthread_once(ONCE_CONTROL, INITFUNCTION) \
+     (pthread_in_use ()                                                        \
+      ? glthread_once_multithreaded (ONCE_CONTROL, INITFUNCTION)               \
+      : (glthread_once_singlethreaded (ONCE_CONTROL) ? (INITFUNCTION (), 0) : 0))
+extern int glthread_once_multithreaded (pthread_once_t *once_control,
+                                        void (*init_function) (void));
+# endif
+extern int glthread_once_singlethreaded (pthread_once_t *once_control);
+
+# ifdef __cplusplus
+}
+# endif
+
+#endif
+
+/* ========================================================================= */
+
+#if USE_WINDOWS_THREADS
+
+# define WIN32_LEAN_AND_MEAN  /* avoid including junk */
+# include <windows.h>
+
+# include "windows-once.h"
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+/* We can use CRITICAL_SECTION directly, rather than the native Windows Event,
+   Mutex, Semaphore types, because
+     - we need only to synchronize inside a single process (address space),
+       not inter-process locking,
+     - we don't need to support trylock operations.  (TryEnterCriticalSection
+       does not work on Windows 95/98/ME.  Packages that need trylock usually
+       define their own mutex type.)  */
+
+/* There is no way to statically initialize a CRITICAL_SECTION.  It needs
+   to be done lazily, once only.  For this we need spinlocks.  */
+
+/* -------------------------- gl_once_t datatype -------------------------- */
+
+typedef glwthread_once_t gl_once_t;
+# define gl_once_define(STORAGECLASS, NAME) \
+    STORAGECLASS gl_once_t NAME = GLWTHREAD_ONCE_INIT;
+# define glthread_once(ONCE_CONTROL, INITFUNCTION) \
+    (glwthread_once (ONCE_CONTROL, INITFUNCTION), 0)
+
+# ifdef __cplusplus
+}
+# endif
+
+#endif
+
+/* ========================================================================= */
+
+#if !(USE_ISOC_THREADS || USE_POSIX_THREADS || USE_ISOC_AND_POSIX_THREADS || USE_WINDOWS_THREADS)
+
+/* Provide dummy implementation if threads are not supported.  */
+
+/* -------------------------- gl_once_t datatype -------------------------- */
+
+typedef int gl_once_t;
+# define gl_once_define(STORAGECLASS, NAME) \
+    STORAGECLASS gl_once_t NAME = 0;
+# define glthread_once(ONCE_CONTROL, INITFUNCTION) \
+    (*(ONCE_CONTROL) == 0 ? (*(ONCE_CONTROL) = ~ 0, INITFUNCTION (), 0) : 0)
+
+#endif
+
+/* ========================================================================= */
+
+/* Macros with built-in error handling.  */
+
+/* -------------------------- gl_once_t datatype -------------------------- */
+
+#define gl_once(NAME, INITFUNCTION) \
+   do                                           \
+     {                                          \
+       if (glthread_once (&NAME, INITFUNCTION)) \
+         abort ();                              \
+     }                                          \
+   while (0)
+
+/* ========================================================================= */
+
+#endif /* _ONCE_H */
index 245252498757844bb204dde13f4e64bbd5e5fe14..34ab02f996d5f2793f16ced15fc8b035ec667a0d 100644 (file)
@@ -10,11 +10,10 @@ m4/pthread_rwlock_rdlock.m4
 Depends-on:
 extensions
 threadlib
-pthread-once     [test $gl_threads_api = posix]
+once
 windows-mutex    [test $gl_threads_api = windows]
 windows-rwlock   [test $gl_threads_api = windows]
 windows-recmutex [test $gl_threads_api = windows]
-windows-once     [test $gl_threads_api = windows]
 
 configure.ac:
 gl_LOCK
diff --git a/modules/once b/modules/once
new file mode 100644 (file)
index 0000000..d17197b
--- /dev/null
@@ -0,0 +1,31 @@
+Description:
+Once-only initialization in multithreaded situations.
+
+Files:
+lib/glthread/once.h
+lib/glthread/once.c
+m4/once.m4
+
+Depends-on:
+extensions
+threadlib
+pthread-once     [test $gl_threads_api = posix]
+windows-once     [test $gl_threads_api = windows]
+
+configure.ac:
+gl_ONCE
+
+Makefile.am:
+lib_SOURCES += glthread/once.h glthread/once.c
+
+Include:
+"glthread/once.h"
+
+Link:
+$(LIBTHREAD)
+
+License:
+LGPLv2+
+
+Maintainer:
+all
index 332c86e5eb81314673d0340a621aed4946bb7099..f23eae514dccc8593abea78620614a6efb5084c5 100644 (file)
@@ -18,7 +18,7 @@
 
 #include <config.h>
 
-#include "glthread/lock.h"
+#include "glthread/once.h"
 
 #include "macros.h"