Browse Source

import some fixes from glibc

Mike Frysinger 20 years ago
parent
commit
8fd79c518f
1 changed files with 17 additions and 1 deletions
  1. 17 1
      libpthread/linuxthreads/cancel.c

+ 17 - 1
libpthread/linuxthreads/cancel.c

@@ -26,6 +26,14 @@
 extern void __rpc_thread_destroy(void);
 #endif
 
+#ifdef _STACK_GROWS_DOWN
+# define FRAME_LEFT(frame, other) ((char *) frame >= (char *) other)
+#elif _STACK_GROWS_UP
+# define FRAME_LEFT(frame, other) ((char *) frame <= (char *) other)
+#else
+# error "Define either _STACK_GROWS_DOWN or _STACK_GROWS_UP"
+#endif
+
 
 int pthread_setcancelstate(int state, int * oldstate)
 {
@@ -62,6 +70,7 @@ int pthread_cancel(pthread_t thread)
   int dorestart = 0;
   pthread_descr th;
   pthread_extricate_if *pextricate;
+  int already_canceled;
 
   __pthread_lock(&handle->h_lock, NULL);
   if (invalid_handle(handle, thread)) {
@@ -71,7 +80,10 @@ int pthread_cancel(pthread_t thread)
 
   th = handle->h_descr;
 
-  if (th->p_canceled) {
+  already_canceled = th->p_canceled;
+  th->p_canceled = 1;
+
+  if (th->p_cancelstate == PTHREAD_CANCEL_DISABLE || already_canceled) {
     __pthread_unlock(&handle->h_lock);
     return 0;
   }
@@ -125,6 +137,8 @@ void _pthread_cleanup_push(struct _pthread_cleanup_buffer * buffer,
   buffer->__routine = routine;
   buffer->__arg = arg;
   buffer->__prev = THREAD_GETMEM(self, p_cleanup);
+  if (buffer->__prev != NULL && FRAME_LEFT (buffer, buffer->__prev))
+    buffer->__prev = NULL;
   THREAD_SETMEM(self, p_cleanup, buffer);
 }
 
@@ -144,6 +158,8 @@ void _pthread_cleanup_push_defer(struct _pthread_cleanup_buffer * buffer,
   buffer->__arg = arg;
   buffer->__canceltype = THREAD_GETMEM(self, p_canceltype);
   buffer->__prev = THREAD_GETMEM(self, p_cleanup);
+  if (buffer->__prev != NULL && FRAME_LEFT (buffer, buffer->__prev))
+    buffer->__prev = NULL;
   THREAD_SETMEM(self, p_canceltype, PTHREAD_CANCEL_DEFERRED);
   THREAD_SETMEM(self, p_cleanup, buffer);
 }