Back to index

glibc  2.9
cancel.c
Go to the documentation of this file.
00001 /* Linuxthreads - a simple clone()-based implementation of Posix        */
00002 /* threads for Linux.                                                   */
00003 /* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr)              */
00004 /*                                                                      */
00005 /* This program is free software; you can redistribute it and/or        */
00006 /* modify it under the terms of the GNU Library General Public License  */
00007 /* as published by the Free Software Foundation; either version 2       */
00008 /* of the License, or (at your option) any later version.               */
00009 /*                                                                      */
00010 /* This program is distributed in the hope that it will be useful,      */
00011 /* but WITHOUT ANY WARRANTY; without even the implied warranty of       */
00012 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        */
00013 /* GNU Library General Public License for more details.                 */
00014 
00015 /* Thread cancellation */
00016 
00017 #include <errno.h>
00018 #include <libc-internal.h>
00019 #include "pthread.h"
00020 #include "internals.h"
00021 #include "spinlock.h"
00022 #include "restart.h"
00023 
00024 #ifdef _STACK_GROWS_DOWN
00025 # define FRAME_LEFT(frame, other) ((char *) frame >= (char *) other)
00026 #elif _STACK_GROWS_UP
00027 # define FRAME_LEFT(frame, other) ((char *) frame <= (char *) other)
00028 #else
00029 # error "Define either _STACK_GROWS_DOWN or _STACK_GROWS_UP"
00030 #endif
00031 
00032 
00033 int __pthread_setcancelstate(int state, int * oldstate)
00034 {
00035   pthread_descr self = thread_self();
00036   if (state < PTHREAD_CANCEL_ENABLE || state > PTHREAD_CANCEL_DISABLE)
00037     return EINVAL;
00038   if (oldstate != NULL) *oldstate = THREAD_GETMEM(self, p_cancelstate);
00039   THREAD_SETMEM(self, p_cancelstate, state);
00040   if (THREAD_GETMEM(self, p_canceled) &&
00041       THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE &&
00042       THREAD_GETMEM(self, p_canceltype) == PTHREAD_CANCEL_ASYNCHRONOUS)
00043     __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
00044   return 0;
00045 }
00046 strong_alias (__pthread_setcancelstate, pthread_setcancelstate);
00047 
00048 int __pthread_setcanceltype(int type, int * oldtype)
00049 {
00050   pthread_descr self = thread_self();
00051   if (type < PTHREAD_CANCEL_DEFERRED || type > PTHREAD_CANCEL_ASYNCHRONOUS)
00052     return EINVAL;
00053   if (oldtype != NULL) *oldtype = THREAD_GETMEM(self, p_canceltype);
00054   THREAD_SETMEM(self, p_canceltype, type);
00055   if (THREAD_GETMEM(self, p_canceled) &&
00056       THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE &&
00057       THREAD_GETMEM(self, p_canceltype) == PTHREAD_CANCEL_ASYNCHRONOUS)
00058     __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
00059   return 0;
00060 }
00061 strong_alias (__pthread_setcanceltype, pthread_setcanceltype);
00062 
00063 
00064 /* The next two functions are similar to pthread_setcanceltype() but
00065    more specialized for the use in the cancelable functions like write().
00066    They do not need to check parameters etc.  */
00067 int
00068 attribute_hidden
00069 __pthread_enable_asynccancel (void)
00070 {
00071   pthread_descr self = thread_self();
00072   int oldtype = THREAD_GETMEM(self, p_canceltype);
00073   THREAD_SETMEM(self, p_canceltype, PTHREAD_CANCEL_ASYNCHRONOUS);
00074   if (__builtin_expect (THREAD_GETMEM(self, p_canceled), 0) &&
00075       THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE)
00076     __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
00077   return oldtype;
00078 }
00079 
00080 void
00081 internal_function attribute_hidden
00082 __pthread_disable_asynccancel (int oldtype)
00083 {
00084   pthread_descr self = thread_self();
00085   THREAD_SETMEM(self, p_canceltype, oldtype);
00086 }
00087 
00088 
00089 int pthread_cancel(pthread_t thread)
00090 {
00091   pthread_handle handle = thread_handle(thread);
00092   int pid;
00093   int dorestart = 0;
00094   pthread_descr th;
00095   pthread_extricate_if *pextricate;
00096   int already_canceled;
00097 
00098   __pthread_lock(&handle->h_lock, NULL);
00099   if (invalid_handle(handle, thread)) {
00100     __pthread_unlock(&handle->h_lock);
00101     return ESRCH;
00102   }
00103 
00104   th = handle->h_descr;
00105 
00106   already_canceled = th->p_canceled;
00107   th->p_canceled = 1;
00108 
00109   if (th->p_cancelstate == PTHREAD_CANCEL_DISABLE || already_canceled) {
00110     __pthread_unlock(&handle->h_lock);
00111     return 0;
00112   }
00113 
00114   pextricate = th->p_extricate;
00115   pid = th->p_pid;
00116 
00117   /* If the thread has registered an extrication interface, then
00118      invoke the interface. If it returns 1, then we succeeded in
00119      dequeuing the thread from whatever waiting object it was enqueued
00120      with. In that case, it is our responsibility to wake it up.
00121      And also to set the p_woken_by_cancel flag so the woken thread
00122      can tell that it was woken by cancellation. */
00123 
00124   if (pextricate != NULL) {
00125     dorestart = pextricate->pu_extricate_func(pextricate->pu_object, th);
00126     th->p_woken_by_cancel = dorestart;
00127   }
00128 
00129   __pthread_unlock(&handle->h_lock);
00130 
00131   /* If the thread has suspended or is about to, then we unblock it by
00132      issuing a restart, instead of a cancel signal. Otherwise we send
00133      the cancel signal to unblock the thread from a cancellation point,
00134      or to initiate asynchronous cancellation. The restart is needed so
00135      we have proper accounting of restarts; suspend decrements the thread's
00136      resume count, and restart() increments it.  This also means that suspend's
00137      handling of the cancel signal is obsolete. */
00138 
00139   if (dorestart)
00140     restart(th);
00141   else
00142     kill(pid, __pthread_sig_cancel);
00143 
00144   return 0;
00145 }
00146 
00147 void pthread_testcancel(void)
00148 {
00149   pthread_descr self = thread_self();
00150   if (THREAD_GETMEM(self, p_canceled)
00151       && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE)
00152     __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
00153 }
00154 
00155 void _pthread_cleanup_push(struct _pthread_cleanup_buffer * buffer,
00156                         void (*routine)(void *), void * arg)
00157 {
00158   pthread_descr self = thread_self();
00159   buffer->__routine = routine;
00160   buffer->__arg = arg;
00161   buffer->__prev = THREAD_GETMEM(self, p_cleanup);
00162   if (buffer->__prev != NULL && FRAME_LEFT (buffer, buffer->__prev))
00163     buffer->__prev = NULL;
00164   THREAD_SETMEM(self, p_cleanup, buffer);
00165 }
00166 
00167 void _pthread_cleanup_pop(struct _pthread_cleanup_buffer * buffer,
00168                        int execute)
00169 {
00170   pthread_descr self = thread_self();
00171   if (execute) buffer->__routine(buffer->__arg);
00172   THREAD_SETMEM(self, p_cleanup, buffer->__prev);
00173 }
00174 
00175 void _pthread_cleanup_push_defer(struct _pthread_cleanup_buffer * buffer,
00176                              void (*routine)(void *), void * arg)
00177 {
00178   pthread_descr self = thread_self();
00179   buffer->__routine = routine;
00180   buffer->__arg = arg;
00181   buffer->__canceltype = THREAD_GETMEM(self, p_canceltype);
00182   buffer->__prev = THREAD_GETMEM(self, p_cleanup);
00183   if (buffer->__prev != NULL && FRAME_LEFT (buffer, buffer->__prev))
00184     buffer->__prev = NULL;
00185   THREAD_SETMEM(self, p_canceltype, PTHREAD_CANCEL_DEFERRED);
00186   THREAD_SETMEM(self, p_cleanup, buffer);
00187 }
00188 
00189 void _pthread_cleanup_pop_restore(struct _pthread_cleanup_buffer * buffer,
00190                               int execute)
00191 {
00192   pthread_descr self = thread_self();
00193   if (execute) buffer->__routine(buffer->__arg);
00194   THREAD_SETMEM(self, p_cleanup, buffer->__prev);
00195   THREAD_SETMEM(self, p_canceltype, buffer->__canceltype);
00196   if (THREAD_GETMEM(self, p_canceled) &&
00197       THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE &&
00198       THREAD_GETMEM(self, p_canceltype) == PTHREAD_CANCEL_ASYNCHRONOUS)
00199     __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
00200 }
00201 
00202 void __pthread_perform_cleanup(char *currentframe)
00203 {
00204   pthread_descr self = thread_self();
00205   struct _pthread_cleanup_buffer *c = THREAD_GETMEM(self, p_cleanup);
00206   struct _pthread_cleanup_buffer *last;
00207 
00208   if (c != NULL)
00209     while (FRAME_LEFT (currentframe, c))
00210       {
00211        last = c;
00212        c = c->__prev;
00213 
00214        if (c == NULL || FRAME_LEFT (last, c))
00215          {
00216            c = NULL;
00217            break;
00218          }
00219       }
00220 
00221   while (c != NULL)
00222     {
00223       c->__routine(c->__arg);
00224 
00225       last = c;
00226       c = c->__prev;
00227 
00228       if (FRAME_LEFT (last, c))
00229        break;
00230     }
00231 
00232   /* And the TSD which needs special help.  */
00233   __libc_thread_freeres ();
00234 }