From 44f6c8a35ca491b1f04d6b460ab5d0d8a3cf6083 Mon Sep 17 00:00:00 2001 From: rpj Date: Fri, 12 Feb 1999 08:19:34 +0000 Subject: Sat Feb 13 03:03:30 1999 Ross Johnson * pthread.h (struct pthread_once_t_): Replaced. * misc.c (pthread_once): Replace with John Bossom's version; has lighter weight serialisation; fixes problem of not holding competing threads until after the init_routine completes. --- misc.c | 105 ++++++++++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 84 insertions(+), 21 deletions(-) (limited to 'misc.c') diff --git a/misc.c b/misc.c index b3c5246..1b558f4 100644 --- a/misc.c +++ b/misc.c @@ -8,39 +8,102 @@ #include "pthread.h" #include "implement.h" +/* + * Code contributed by John E. Bossom . + */ + int -pthread_once(pthread_once_t *once_control, - void (*init_routine)(void)) +pthread_once ( + pthread_once_t * once_control, + void (*init_routine) (void) +) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * If any thread in a process with a once_control parameter + * makes a call to pthread_once(), the first call will summon + * the init_routine(), but subsequent calls will not. The + * once_control parameter determines whether the associated + * initialization routine has been called. The init_routine() + * is complete upon return of pthread_once(). + * This function guarantees that one and only one thread + * executes the initialization routine, init_routine when + * access is controlled by the pthread_once_t control + * key. + * + * PARAMETERS + * once_control + * pointer to an instance of pthread_once_t + * + * init_routine + * pointer to an initialization routine + * + * + * DESCRIPTION + * See above. + * + * RESULTS + * 0 success, + * EINVAL once_control or init_routine is NULL + * + * ------------------------------------------------------ + */ { - /* A flag, allocated per invocation, that indicates if the atomic - test-and-set occured. */ - unsigned short flag = 0; + int result; if (once_control == NULL || init_routine == NULL) { - return EINVAL; - } - /* An atomic test-and-set of the "once" flag. */ - pthread_mutex_lock(&once_control->lock); - if (once_control->flag == 0) + result = EINVAL; + goto FAIL0; + + } + else { - flag = once_control->flag = 1; + result = 0; } - pthread_mutex_unlock(&once_control->lock); - if (flag) + if (!once_control->done) { - /* Run the init routine. */ - init_routine(); + if (InterlockedIncrement (&(once_control->started)) == 0) + { + /* + * First thread to increment the started variable + */ + (*init_routine) (); + once_control->done = TRUE; + + } + else + { + /* + * Block until other thread finishes executing the onceRoutine + */ + while (!(once_control->done)) + { + /* + * The following gives up CPU cycles without pausing + * unnecessarily + */ + Sleep (0); + } + } } - - return 0; -} -/* - * Code contributed by John E. Bossom . - */ + /* + * Fall through Intentionally + */ + + /* + * ------------ + * Failure Code + * ------------ + */ +FAIL0: + return (result); + +} /* pthread_once */ + pthread_t pthread_self (void) -- cgit v1.2.3