summary refs log tree commit diff
path: root/linuxthreads/mutex.c
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2000-03-15 07:12:44 +0000
committerUlrich Drepper <drepper@redhat.com>2000-03-15 07:12:44 +0000
commit30b416ea87471a739763966fddc37f6273be58e0 (patch)
tree20dd7212f92013093211f0c23655625012c9cbe7 /linuxthreads/mutex.c
parentd9cb1a7dad1f2638cdaa12ff8ade54f9c24c64bc (diff)
downloadglibc-30b416ea87471a739763966fddc37f6273be58e0.tar.gz
glibc-30b416ea87471a739763966fddc37f6273be58e0.tar.xz
glibc-30b416ea87471a739763966fddc37f6273be58e0.zip
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.c28
1 files changed, 27 insertions, 1 deletions
diff --git a/linuxthreads/mutex.c b/linuxthreads/mutex.c
index cd7ace2617..06d97df03f 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)