1 /* 2 * pthread_cancel.c 3 * 4 * Description: 5 * POSIX thread functions related to thread cancellation. 6 * 7 * -------------------------------------------------------------------------- 8 * 9 * Pthreads-win32 - POSIX Threads Library for Win32 10 * Copyright(C) 1998 John E. Bossom 11 * Copyright(C) 1999,2005 Pthreads-win32 contributors 12 * 13 * Contact Email: rpj (at) callisto.canberra.edu.au 14 * 15 * The current list of contributors is contained 16 * in the file CONTRIBUTORS included with the source 17 * code distribution. The list can also be seen at the 18 * following World Wide Web location: 19 * http://sources.redhat.com/pthreads-win32/contributors.html 20 * 21 * This library is free software; you can redistribute it and/or 22 * modify it under the terms of the GNU Lesser General Public 23 * License as published by the Free Software Foundation; either 24 * version 2 of the License, or (at your option) any later version. 25 * 26 * This library is distributed in the hope that it will be useful, 27 * but WITHOUT ANY WARRANTY; without even the implied warranty of 28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 29 * Lesser General Public License for more details. 30 * 31 * You should have received a copy of the GNU Lesser General Public 32 * License along with this library in the file COPYING.LIB; 33 * if not, write to the Free Software Foundation, Inc., 34 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 35 */ 36 37 #include "pthread.h" 38 #include "implement.h" 39 #include "context.h" 40 41 static void 42 ptw32_cancel_self (void) 43 { 44 ptw32_throw (PTW32_EPS_CANCEL); 45 46 /* Never reached */ 47 } 48 49 static void CALLBACK 50 ptw32_cancel_callback (ULONG_PTR unused) 51 { 52 ptw32_throw (PTW32_EPS_CANCEL); 53 54 /* Never reached */ 55 } 56 57 /* 58 * ptw32_RegisterCancelation() - 59 * Must have args of same type as QueueUserAPCEx because this function 60 * is a substitute for QueueUserAPCEx if it's not available. 61 */ 62 DWORD 63 ptw32_RegisterCancelation (PAPCFUNC unused1, HANDLE threadH, DWORD unused2) 64 { 65 CONTEXT context; 66 67 context.ContextFlags = CONTEXT_CONTROL; 68 GetThreadContext (threadH, &context); 69 PTW32_PROGCTR (context) = (DWORD_PTR) ptw32_cancel_self; 70 SetThreadContext (threadH, &context); 71 return 0; 72 } 73 74 int 75 pthread_cancel (pthread_t thread) 76 /* 77 * ------------------------------------------------------ 78 * DOCPUBLIC 79 * This function requests cancellation of 'thread'. 80 * 81 * PARAMETERS 82 * thread 83 * reference to an instance of pthread_t 84 * 85 * 86 * DESCRIPTION 87 * This function requests cancellation of 'thread'. 88 * NOTE: cancellation is asynchronous; use pthread_join to 89 * wait for termination of 'thread' if necessary. 90 * 91 * RESULTS 92 * 0 successfully requested cancellation, 93 * ESRCH no thread found corresponding to 'thread', 94 * ENOMEM implicit self thread create failed. 95 * ------------------------------------------------------ 96 */ 97 { 98 int result; 99 int cancel_self; 100 pthread_t self; 101 ptw32_thread_t * tp; 102 ptw32_mcs_local_node_t stateLock; 103 104 result = pthread_kill (thread, 0); 105 106 if (0 != result) 107 { 108 return result; 109 } 110 111 if ((self = pthread_self ()).p == NULL) 112 { 113 return ENOMEM; 114 }; 115 116 /* 117 * For self cancellation we need to ensure that a thread can't 118 * deadlock itself trying to cancel itself asynchronously 119 * (pthread_cancel is required to be an async-cancel 120 * safe function). 121 */ 122 cancel_self = pthread_equal (thread, self); 123 124 tp = (ptw32_thread_t *) thread.p; 125 126 /* 127 * Lock for async-cancel safety. 128 */ 129 ptw32_mcs_lock_acquire (&tp->stateLock, &stateLock); 130 131 if (tp->cancelType == PTHREAD_CANCEL_ASYNCHRONOUS 132 && tp->cancelState == PTHREAD_CANCEL_ENABLE 133 && tp->state < PThreadStateCanceling) 134 { 135 if (cancel_self) 136 { 137 tp->state = PThreadStateCanceling; 138 tp->cancelState = PTHREAD_CANCEL_DISABLE; 139 140 ptw32_mcs_lock_release (&stateLock); 141 ptw32_throw (PTW32_EPS_CANCEL); 142 143 /* Never reached */ 144 } 145 else 146 { 147 HANDLE threadH = tp->threadH; 148 149 SuspendThread (threadH); 150 151 if (WaitForSingleObject (threadH, 0) == WAIT_TIMEOUT) 152 { 153 tp->state = PThreadStateCanceling; 154 tp->cancelState = PTHREAD_CANCEL_DISABLE; 155 /* 156 * If alertdrv and QueueUserAPCEx is available then the following 157 * will result in a call to QueueUserAPCEx with the args given, otherwise 158 * this will result in a call to ptw32_RegisterCancelation and only 159 * the threadH arg will be used. 160 */ 161 ptw32_register_cancelation ((PAPCFUNC)ptw32_cancel_callback, threadH, 0); 162 ptw32_mcs_lock_release (&stateLock); 163 ResumeThread (threadH); 164 } 165 } 166 } 167 else 168 { 169 /* 170 * Set for deferred cancellation. 171 */ 172 if (tp->state < PThreadStateCancelPending) 173 { 174 tp->state = PThreadStateCancelPending; 175 if (!SetEvent (tp->cancelEvent)) 176 { 177 result = ESRCH; 178 } 179 } 180 else if (tp->state >= PThreadStateCanceling) 181 { 182 result = ESRCH; 183 } 184 185 ptw32_mcs_lock_release (&stateLock); 186 } 187 188 return (result); 189 } 190