[Top][All Lists]
[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
- adding once-only initialization to lock module,
Bruno Haible <=