about summary refs log tree commit diff
path: root/nptl
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2009-05-15 10:12:35 -0700
committerUlrich Drepper <drepper@redhat.com>2009-05-15 19:37:12 -0700
commit1a7f254b4b0590bfab1baa1400705265b1b23b97 (patch)
treefb7ce319a3acac401040d173397132e8ea8ae765 /nptl
parent2e180a26222caf478f29e272c9d1b5d9c6299752 (diff)
downloadglibc-1a7f254b4b0590bfab1baa1400705265b1b23b97.tar.gz
glibc-1a7f254b4b0590bfab1baa1400705265b1b23b97.tar.xz
glibc-1a7f254b4b0590bfab1baa1400705265b1b23b97.zip
No cancel signal in unsafe places.
When disabling async cancellation we cannot return from the function
call if the thread is canceled.  This happens when the cancel bits
have been set before async cancel is disabled but the signal hasn't
been sent/received yet.  Delay for as long as necessary since
otherwise the signal might be received in an unsafe context.
Diffstat (limited to 'nptl')
-rw-r--r--nptl/ChangeLog6
-rw-r--r--nptl/cancellation.c14
-rw-r--r--nptl/libc-cancellation.c14
3 files changed, 32 insertions, 2 deletions
diff --git a/nptl/ChangeLog b/nptl/ChangeLog
index b83dfd0c9d..74a2a73666 100644
--- a/nptl/ChangeLog
+++ b/nptl/ChangeLog
@@ -1,3 +1,9 @@
+2009-05-15  Ulrich Drepper  <drepper@redhat.com>
+
+	* cancellation.c (__pthread_disable_asynccancel): Don't return if
+	thread is canceled.
+	* libc-cancellation.c (__libc_disable_asynccancel): Likewise.
+
 2009-04-27  Ulrich Drepper  <drepper@redhat.com>
 
 	* cancellation.c (__pthread_disable_asynccancel): Use THREAD_ATOMIC_AND
diff --git a/nptl/cancellation.c b/nptl/cancellation.c
index 81134a679a..4d528cfc2f 100644
--- a/nptl/cancellation.c
+++ b/nptl/cancellation.c
@@ -70,15 +70,17 @@ __pthread_disable_asynccancel (int oldtype)
     return;
 
   struct pthread *self = THREAD_SELF;
+  int newval;
 
 #ifdef THREAD_ATOMIC_AND
   THREAD_ATOMIC_AND (self, cancelhandling, ~CANCELTYPE_BITMASK);
+  newval = THREAD_GETMEM (self, cancelhandling);
 #else
   int oldval = THREAD_GETMEM (self, cancelhandling);
 
   while (1)
     {
-      int newval = oldval & ~CANCELTYPE_BITMASK;
+      newval = oldval & ~CANCELTYPE_BITMASK;
 
       if (newval == oldval)
 	break;
@@ -92,4 +94,14 @@ __pthread_disable_asynccancel (int oldtype)
       oldval = curval;
     }
 #endif
+
+  /* We cannot return when we are being canceled.  Upon return the
+     thread might be things which would have to be undone.  The
+     following loop should loop until the cancellation signal is
+     delivered.  */
+  while (__builtin_expect (newval & CANCELED_BITMASK, 0))
+    {
+      lll_futex_wait (&self->cancelhandling, newval, LLL_PRIVATE);
+      newval = THREAD_GETMEM (self, cancelhandling);
+    }
 }
diff --git a/nptl/libc-cancellation.c b/nptl/libc-cancellation.c
index cf24f1c0f2..35ac82b3d1 100644
--- a/nptl/libc-cancellation.c
+++ b/nptl/libc-cancellation.c
@@ -86,15 +86,17 @@ __libc_disable_asynccancel (int oldtype)
     return;
 
   struct pthread *self = THREAD_SELF;
+  int newval;
 
 #ifdef THREAD_ATOMIC_AND
   THREAD_ATOMIC_AND (self, cancelhandling, ~CANCELTYPE_BITMASK);
+  newval = THREAD_GETMEM (self, cancelhandling);
 #else
   int oldval = THREAD_GETMEM (self, cancelhandling);
 
   while (1)
     {
-      int newval = oldval & ~CANCELTYPE_BITMASK;
+      newval = oldval & ~CANCELTYPE_BITMASK;
 
       if (newval == oldval)
 	break;
@@ -108,6 +110,16 @@ __libc_disable_asynccancel (int oldtype)
       oldval = curval;
     }
 #endif
+
+  /* We cannot return when we are being canceled.  Upon return the
+     thread might be things which would have to be undone.  The
+     following loop should loop until the cancellation signal is
+     delivered.  */
+  while (__builtin_expect (newval & CANCELED_BITMASK, 0))
+    {
+      lll_futex_wait (&self->cancelhandling, newval, LLL_PRIVATE);
+      newval = THREAD_GETMEM (self, cancelhandling);
+    }
 }