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@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 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
35 */
36
37 #include "pthread.h"
38 #include "implement.h"
39 #include "context.h"
40
41 static void
ptw32_cancel_self(void)42 ptw32_cancel_self (void)
43 {
44 ptw32_throw (PTW32_EPS_CANCEL);
45
46 /* Never reached */
47 }
48
49 static void CALLBACK
ptw32_cancel_callback(ULONG_PTR unused)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
ptw32_RegisterCancelation(PAPCFUNC unused1,HANDLE threadH,DWORD unused2)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
pthread_cancel(pthread_t thread)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