From: Bruno Haible Date: Mon, 18 Jul 2005 19:53:48 +0000 (+0000) Subject: Also support once-execution. X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b5e2473ba6261543c2808f17dea46dc32da83412;p=pspp Also support once-execution. --- diff --git a/lib/ChangeLog b/lib/ChangeLog index 99f4424527..ac752517d5 100644 --- a/lib/ChangeLog +++ b/lib/ChangeLog @@ -1,3 +1,11 @@ +2005-07-18 Bruno Haible + + * 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 * check-version.c (check_version): Accept identical versions too. diff --git a/lib/lock.c b/lib/lock.c index cbf9f11632..5c14fa3a3e 100644 --- a/lib/lock.c +++ b/lib/lock.c @@ -322,6 +322,26 @@ glthread_recursive_lock_destroy (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; +} + #endif /* ========================================================================= */ @@ -336,6 +356,30 @@ glthread_recursive_lock_destroy (gl_recursive_lock_t *lock) /* --------------------- 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 @@ glthread_recursive_lock_destroy (gl_recursive_lock_t *lock) 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 @@ glthread_recursive_lock_destroy (gl_recursive_lock_t *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 /* ========================================================================= */ diff --git a/lib/lock.h b/lib/lock.h index 9ca33debcd..cdddf6cd43 100644 --- 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 @@ extern void glthread_recursive_lock_destroy (gl_recursive_lock_t *lock); # 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 @@ extern void glthread_recursive_lock_destroy (gl_recursive_lock_t *lock); # 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 @@ typedef pth_mutex_t gl_recursive_lock_t; # 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_lock (gl_recursive_lock_t *lock); 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_lock (gl_recursive_lock_t *lock); 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 @@ typedef int gl_recursive_lock_t; # 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