diff options
author | Ulrich Drepper <drepper@redhat.com> | 2000-03-15 07:12:44 +0000 |
---|---|---|
committer | Ulrich Drepper <drepper@redhat.com> | 2000-03-15 07:12:44 +0000 |
commit | 30b416ea87471a739763966fddc37f6273be58e0 (patch) | |
tree | 20dd7212f92013093211f0c23655625012c9cbe7 /linuxthreads/mutex.c | |
parent | d9cb1a7dad1f2638cdaa12ff8ade54f9c24c64bc (diff) | |
download | glibc-30b416ea87471a739763966fddc37f6273be58e0.zip glibc-30b416ea87471a739763966fddc37f6273be58e0.tar.gz glibc-30b416ea87471a739763966fddc37f6273be58e0.tar.bz2 |
Update.
2000-03-14 Ulrich Drepper <drepper@redhat.com>
* mutex.c (__pthread_once): Handle cancelled init function correctly.
(pthread_once_cancelhandler): New function.
Patch by Kaz Kylheku <kaz@ashi.footprints.net>.
Diffstat (limited to 'linuxthreads/mutex.c')
-rw-r--r-- | linuxthreads/mutex.c | 28 |
1 files changed, 27 insertions, 1 deletions
diff --git a/linuxthreads/mutex.c b/linuxthreads/mutex.c index cd7ace2..06d97df 100644 --- a/linuxthreads/mutex.c +++ b/linuxthreads/mutex.c @@ -173,11 +173,31 @@ static pthread_cond_t once_finished = PTHREAD_COND_INITIALIZER; enum { NEVER = 0, IN_PROGRESS = 1, DONE = 2 }; +/* If a thread is canceled while calling the init_routine out of + pthread once, this handler will reset the once_control variable + to the NEVER state. */ + +static void pthread_once_cancelhandler(void *arg) +{ + pthread_once_t *once_control = arg; + + pthread_mutex_lock(&once_masterlock); + *once_control = NEVER; + pthread_mutex_unlock(&once_masterlock); + pthread_cond_broadcast(&once_finished); +} + int __pthread_once(pthread_once_t * once_control, void (*init_routine)(void)) { + /* flag for doing the condition broadcast outside of mutex */ + int state_changed; + /* Test without locking first for speed */ if (*once_control == DONE) return 0; /* Lock and test again */ + + state_changed = 0; + pthread_mutex_lock(&once_masterlock); /* If init_routine is being called from another routine, wait until it completes. */ @@ -188,12 +208,18 @@ int __pthread_once(pthread_once_t * once_control, void (*init_routine)(void)) if (*once_control == NEVER) { *once_control = IN_PROGRESS; pthread_mutex_unlock(&once_masterlock); + pthread_cleanup_push(pthread_once_cancelhandler, once_control); init_routine(); + pthread_cleanup_pop(0); pthread_mutex_lock(&once_masterlock); *once_control = DONE; - pthread_cond_broadcast(&once_finished); + state_changed = 1; } pthread_mutex_unlock(&once_masterlock); + + if (state_changed) + pthread_cond_broadcast(&once_finished); + return 0; } strong_alias (__pthread_once, pthread_once) |