diff options
author | rpj <rpj> | 1999-02-12 08:19:34 +0000 |
---|---|---|
committer | rpj <rpj> | 1999-02-12 08:19:34 +0000 |
commit | 44f6c8a35ca491b1f04d6b460ab5d0d8a3cf6083 (patch) | |
tree | 43343d58f15346fea6d09371c7d6abb090fa8842 /misc.c | |
parent | eb222bd25ddfc39ac156d59331f1dd4c3ef5df9b (diff) |
Sat Feb 13 03:03:30 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
* 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.
Diffstat (limited to 'misc.c')
-rw-r--r-- | misc.c | 105 |
1 files changed, 84 insertions, 21 deletions
@@ -8,39 +8,102 @@ #include "pthread.h" #include "implement.h" +/* + * Code contributed by John E. Bossom <JEB>. + */ + 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 <JEB>. - */ + /* + * Fall through Intentionally + */ + + /* + * ------------ + * Failure Code + * ------------ + */ +FAIL0: + return (result); + +} /* pthread_once */ + pthread_t pthread_self (void) |