bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

adding once-only initialization to lock module


From: Bruno Haible
Subject: adding once-only initialization to lock module
Date: Mon, 18 Jul 2005 21:54:36 +0200
User-agent: KMail/1.5

Hi,

Libraries that need to protect shared datastructures with locks also often
need once-only initializations. And conversely, all programs that need
thread-safe once-only initialization also need locking.

So I've added support for once-only execution (à la pthread_once) to
lock.h and lock.c.

Bruno


2005-07-16  Bruno Haible  <address@hidden>

        * 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.

diff -c -3 -r1.1 lock.h
*** lib/lock.h  18 Jul 2005 11:35:09 -0000      1.1
--- lib/lock.h  18 Jul 2005 19:51:44 -0000
***************
*** 51,56 ****
--- 51,61 ----
       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,96 ****
--- 96,102 ----
  #  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,306 ****
--- 307,334 ----
  
  # 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,327 ****
--- 350,356 ----
  #  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,388 ****
--- 412,441 ----
  #  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,487 ****
--- 535,567 ----
  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,607 ****
--- 682,702 ----
  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
  
  /* ========================================================================= 
*/
***************
*** 637,641 ****
--- 732,752 ----
  # define gl_recursive_lock_init(NAME)
  # 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
diff -c -3 -r1.1 lock.c
*** lib/lock.c  18 Jul 2005 11:35:09 -0000      1.1
--- lib/lock.c  18 Jul 2005 19:51:44 -0000
***************
*** 322,327 ****
--- 322,347 ----
  
  # 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,341 ****
--- 356,385 ----
  
  /* --------------------- 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,402 ****
--- 441,481 ----
      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
  
  /* ========================================================================= 
*/
***************
*** 762,767 ****
--- 841,885 ----
      abort ();
    DeleteCriticalSection (&lock->lock);
    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





reply via email to

[Prev in Thread] Current Thread [Next in Thread]