changeset 5998:a1c33b658251

Also support once-execution.
author Bruno Haible <bruno@clisp.org>
date Mon, 18 Jul 2005 19:53:48 +0000
parents 3f79af4480c9
children 9887c4adbd89
files lib/ChangeLog lib/lock.c lib/lock.h
diffstat 3 files changed, 237 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/lib/ChangeLog
+++ b/lib/ChangeLog
@@ -1,3 +1,11 @@
+2005-07-18  Bruno Haible  <bruno@clisp.org>
+
+	* lock.h (gl_once_t): New type.
+	(gl_once_define, gl_once): New macros.
+	* lock.c (fresh_once): New variable.
+	(glthread_once, glthread_once_call, glthread_once_singlethreaded): New
+	functions.
+
 2005-07-18  Simon Josefsson  <jas@extundo.com>
 
 	* check-version.c (check_version): Accept identical versions too.
--- a/lib/lock.c
+++ b/lib/lock.c
@@ -322,6 +322,26 @@
 
 # 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;
+}
+
 #endif
 
 /* ========================================================================= */
@@ -336,6 +356,30 @@
 
 /* --------------------- gl_recursive_lock_t datatype --------------------- */
 
+/* -------------------------- gl_once_t datatype -------------------------- */
+
+void
+glthread_once_call (void *arg)
+{
+  void (**gl_once_temp_addr) (void) = (void (**) (void)) arg;
+  void (*initfunction) (void) = *gl_once_temp_addr;
+  initfunction ();
+}
+
+int
+glthread_once_singlethreaded (pth_once_t *once_control)
+{
+  /* We know that pth_once_t is an integer type.  */
+  if (*once_control == PTH_ONCE_INIT)
+    {
+      /* First time use of once_control.  Invert the marker.  */
+      *once_control = ~ PTH_ONCE_INIT;
+      return 1;
+    }
+  else
+    return 0;
+}
+
 #endif
 
 /* ========================================================================= */
@@ -397,6 +441,41 @@
     abort ();
 }
 
+/* -------------------------- gl_once_t datatype -------------------------- */
+
+void
+glthread_once (gl_once_t *once_control, void (*initfunction) (void))
+{
+  if (!once_control->inited)
+    {
+      /* Use the mutex to guarantee that if another thread is already calling
+	 the initfunction, this thread waits until it's finished.  */
+      if (mutex_lock (&once_control->mutex) != 0)
+	abort ();
+      if (!once_control->inited)
+	{
+	  once_control->inited = 1;
+	  initfunction ();
+	}
+      if (mutex_unlock (&once_control->mutex) != 0)
+	abort ();
+    }
+}
+
+int
+glthread_once_singlethreaded (gl_once_t *once_control)
+{
+  /* We know that gl_once_t contains an integer type.  */
+  if (!once_control->inited)
+    {
+      /* First time use of once_control.  Invert the marker.  */
+      once_control->inited = ~ 0;
+      return 1;
+    }
+  else
+    return 0;
+}
+
 #endif
 
 /* ========================================================================= */
@@ -764,6 +843,45 @@
   lock->guard.done = 0;
 }
 
+/* -------------------------- gl_once_t datatype -------------------------- */
+
+void
+glthread_once (gl_once_t *once_control, void (*initfunction) (void))
+{
+  if (once_control->inited <= 0)
+    {
+      if (InterlockedIncrement (&once_control->started) == 0)
+	{
+	  /* This thread is the first one to come to this once_control.  */
+	  InitializeCriticalSection (&once_control->lock);
+	  EnterCriticalSection (&once_control->lock);
+	  once_control->inited = 0;
+	  initfunction ();
+	  once_control->inited = 1;
+	  LeaveCriticalSection (&once_control->lock);
+	}
+      else
+	{
+	  /* Undo last operation.  */
+	  InterlockedDecrement (&once_control->started);
+	  /* Some other thread has already started the initialization.
+	     Yield the CPU while waiting for the other thread to finish
+	     initializing and taking the lock.  */
+	  while (once_control->inited < 0)
+	    Sleep (0);
+	  if (once_control->inited <= 0)
+	    {
+	      /* Take the lock.  This blocks until the other thread has
+		 finished calling the initfunction.  */
+	      EnterCriticalSection (&once_control->lock);
+	      LeaveCriticalSection (&once_control->lock);
+	      if (!(once_control->inited > 0))
+		abort ();
+	    }
+	}
+    }
+}
+
 #endif
 
 /* ========================================================================= */
--- a/lib/lock.h
+++ b/lib/lock.h
@@ -51,6 +51,11 @@
      Taking the lock:     gl_recursive_lock_lock (name);
      Releasing the lock:  gl_recursive_lock_unlock (name);
      De-initialization:   gl_recursive_lock_destroy (name);
+
+  Once-only execution:
+     Type:                gl_once_t
+     Initializer:         gl_once_define(extern, name)
+     Execution:           gl_once (name, initfunction);
 */
 
 
@@ -91,6 +96,7 @@
 #  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
@@ -301,6 +307,28 @@
 
 # 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;
+# define gl_once(NAME, INITFUNCTION) \
+    do                                                   \
+      {                                                  \
+        if (pthread_in_use ())                           \
+          {                                              \
+            if (pthread_once (&NAME, INITFUNCTION) != 0) \
+              abort ();                                  \
+          }                                              \
+        else                                             \
+          {                                              \
+            if (glthread_once_singlethreaded (&NAME))    \
+              INITFUNCTION ();                           \
+          }                                              \
+      }                                                  \
+    while (0)
+extern int glthread_once_singlethreaded (pthread_once_t *once_control);
+
 #endif
 
 /* ========================================================================= */
@@ -322,6 +350,7 @@
 #  pragma weak pth_rwlock_init
 #  pragma weak pth_rwlock_acquire
 #  pragma weak pth_rwlock_release
+#  pragma weak pth_once
 
 #  pragma weak pth_cancel
 #  define pth_in_use() (pth_cancel != NULL)
@@ -383,6 +412,30 @@
 #  define gl_recursive_lock_destroy(NAME) \
      (void)(&NAME)
 
+/* -------------------------- gl_once_t datatype -------------------------- */
+
+typedef pth_once_t gl_once_t;
+# define gl_once_define(STORAGECLASS, NAME) \
+    STORAGECLASS pth_once_t NAME = PTH_ONCE_INIT;
+# define gl_once(NAME, INITFUNCTION) \
+    do                                                                \
+      {                                                               \
+        if (pth_in_use ())                                            \
+          {                                                           \
+            void (*gl_once_temp) (void) = INITFUNCTION;               \
+            if (!pth_once (&NAME, glthread_once_call, &gl_once_temp)) \
+              abort ();                                               \
+          }                                                           \
+        else                                                          \
+          {                                                           \
+            if (glthread_once_singlethreaded (&NAME))                 \
+              INITFUNCTION ();                                        \
+          }                                                           \
+      }                                                               \
+    while (0)
+extern void glthread_once_call (void *arg);
+extern int glthread_once_singlethreaded (pth_once_t *once_control);
+
 #endif
 
 /* ========================================================================= */
@@ -482,6 +535,33 @@
 extern void glthread_recursive_lock_unlock (gl_recursive_lock_t *lock);
 extern void glthread_recursive_lock_destroy (gl_recursive_lock_t *lock);
 
+/* -------------------------- gl_once_t datatype -------------------------- */
+
+typedef struct
+        {
+          volatile int inited;
+          mutex_t mutex;
+        }
+        gl_once_t;
+# define gl_once_define(STORAGECLASS, NAME) \
+    STORAGECLASS gl_once_t NAME = { 0, DEFAULTMUTEX };
+# define gl_once(NAME, INITFUNCTION) \
+    do                                                \
+      {                                               \
+        if (thread_in_use ())                         \
+          {                                           \
+            glthread_once (&NAME, INITFUNCTION);      \
+          }                                           \
+        else                                          \
+          {                                           \
+            if (glthread_once_singlethreaded (&NAME)) \
+              INITFUNCTION ();                        \
+          }                                           \
+      }                                               \
+    while (0)
+extern void glthread_once (gl_once_t *once_control, void (*initfunction) (void));
+extern int glthread_once_singlethreaded (gl_once_t *once_control);
+
 #endif
 
 /* ========================================================================= */
@@ -602,6 +682,21 @@
 extern void glthread_recursive_lock_unlock (gl_recursive_lock_t *lock);
 extern void glthread_recursive_lock_destroy (gl_recursive_lock_t *lock);
 
+/* -------------------------- gl_once_t datatype -------------------------- */
+
+typedef struct
+        {
+          volatile int inited;
+          volatile long started;
+          CRITICAL_SECTION lock;
+        }
+        gl_once_t;
+# define gl_once_define(STORAGECLASS, NAME) \
+    STORAGECLASS gl_once_t NAME = { -1, -1 };
+# define gl_once(NAME, INITFUNCTION) \
+    glthread_once (&NAME, INITFUNCTION)
+extern void glthread_once (gl_once_t *once_control, void (*initfunction) (void));
+
 #endif
 
 /* ========================================================================= */
@@ -638,4 +733,20 @@
 # define gl_recursive_lock_lock(NAME)
 # define gl_recursive_lock_unlock(NAME)
 
+/* -------------------------- gl_once_t datatype -------------------------- */
+
+typedef int gl_once_t;
+# define gl_once_define(STORAGECLASS, NAME) \
+    STORAGECLASS gl_once_t NAME = 0;
+# define gl_once(NAME, INITFUNCTION) \
+    do                       \
+      {                      \
+        if (NAME == 0)       \
+          {                  \
+            NAME = ~ 0;      \
+            INITFUNCTION (); \
+          }                  \
+      }                      \
+    while (0)
+
 #endif