1 /* Linuxthreads - a simple clone()-based implementation of Posix */
2 /* threads for Linux. */
3 /* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */
5 /* This program is free software; you can redistribute it and/or */
6 /* modify it under the terms of the GNU Library General Public License */
7 /* as published by the Free Software Foundation; either version 2 */
8 /* of the License, or (at your option) any later version. */
10 /* This program is distributed in the hope that it will be useful, */
11 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
12 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
13 /* GNU Library General Public License for more details. */
15 /* Thread cancellation */
18 #include <libc-internal.h>
20 #include "internals.h"
24 #include <l4/sys/kdebug.h>
26 #ifdef _STACK_GROWS_DOWN
27 # define FRAME_LEFT(frame, other) ((char *) frame >= (char *) other)
29 # define FRAME_LEFT(frame, other) ((char *) frame <= (char *) other)
31 # error "Define either _STACK_GROWS_DOWN or _STACK_GROWS_UP"
37 __pthread_setcancelstate(int state, int * oldstate)
39 pthread_descr self = thread_self();
40 if (state < PTHREAD_CANCEL_ENABLE || state > PTHREAD_CANCEL_DISABLE)
42 if (oldstate != NULL) *oldstate = THREAD_GETMEM(self, p_cancelstate);
43 THREAD_SETMEM(self, p_cancelstate, state);
44 if (THREAD_GETMEM(self, p_canceled) &&
45 THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE &&
46 THREAD_GETMEM(self, p_canceltype) == PTHREAD_CANCEL_ASYNCHRONOUS)
47 __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
50 strong_alias (__pthread_setcancelstate, pthread_setcancelstate)
54 __pthread_setcanceltype(int type, int * oldtype)
56 pthread_descr self = thread_self();
57 if (type < PTHREAD_CANCEL_DEFERRED || type > PTHREAD_CANCEL_ASYNCHRONOUS)
59 if (oldtype != NULL) *oldtype = THREAD_GETMEM(self, p_canceltype);
60 THREAD_SETMEM(self, p_canceltype, type);
61 if (THREAD_GETMEM(self, p_canceled) &&
62 THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE &&
63 THREAD_GETMEM(self, p_canceltype) == PTHREAD_CANCEL_ASYNCHRONOUS)
64 __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
67 strong_alias (__pthread_setcanceltype, pthread_setcanceltype)
70 /* The next two functions are similar to pthread_setcanceltype() but
71 more specialized for the use in the cancelable functions like write().
72 They do not need to check parameters etc. */
75 __pthread_enable_asynccancel (void)
77 pthread_descr self = thread_self();
78 int oldtype = THREAD_GETMEM(self, p_canceltype);
79 THREAD_SETMEM(self, p_canceltype, PTHREAD_CANCEL_ASYNCHRONOUS);
80 if (__builtin_expect (THREAD_GETMEM(self, p_canceled), 0) &&
81 THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE)
82 __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
87 internal_function attribute_hidden
88 __pthread_disable_asynccancel (int oldtype)
90 pthread_descr self = thread_self();
91 THREAD_SETMEM(self, p_canceltype, oldtype);
96 static void pthread_handle_sigcancel(void)
98 pthread_descr self = check_thread_self();
101 if (self == __manager_thread)
103 enter_kdebug("cancel of the manager hooooo");
105 __pthread_manager_sighandler(sig);
109 if (__builtin_expect (__pthread_exit_requested, 0)) {
111 /* Main thread should accumulate times for thread manager and its
112 children, so that timings for main thread account for all threads. */
113 if (self == __pthread_main_thread) {
115 waitpid(manager_thread->p_pid, NULL, __WCLONE);
117 waitpid(__pthread_manager_thread.p_pid, NULL, __WCLONE);
121 _exit(__pthread_exit_code);
123 if (__builtin_expect (THREAD_GETMEM(self, p_canceled), 0)
124 && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) {
125 if (THREAD_GETMEM(self, p_canceltype) == PTHREAD_CANCEL_ASYNCHRONOUS)
126 __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
127 jmpbuf = THREAD_GETMEM(self, p_cancel_jmp);
128 if (jmpbuf != NULL) {
129 THREAD_SETMEM(self, p_cancel_jmp, NULL);
130 siglongjmp(*jmpbuf, 1);
136 int pthread_cancel(pthread_t thread)
138 pthread_handle handle = thread_handle(thread);
141 pthread_extricate_if *pextricate;
142 int already_canceled;
144 __pthread_lock(handle_to_lock(handle), NULL);
145 if (invalid_handle(handle, thread)) {
146 __pthread_unlock(handle_to_lock(handle));
150 th = handle_to_descr(handle);
152 already_canceled = th->p_canceled;
155 if (th->p_cancelstate == PTHREAD_CANCEL_DISABLE || already_canceled) {
156 __pthread_unlock(handle_to_lock(handle));
160 pextricate = th->p_extricate;
162 /* If the thread has registered an extrication interface, then
163 invoke the interface. If it returns 1, then we succeeded in
164 dequeuing the thread from whatever waiting object it was enqueued
165 with. In that case, it is our responsibility to wake it up.
166 And also to set the p_woken_by_cancel flag so the woken thread
167 can tell that it was woken by cancellation. */
169 if (pextricate != NULL) {
170 dorestart = pextricate->pu_extricate_func(pextricate->pu_object, th);
171 th->p_woken_by_cancel = dorestart;
174 __pthread_unlock(handle_to_lock(handle));
176 /* If the thread has suspended or is about to, then we unblock it by
177 issuing a restart, instead of a cancel signal. Otherwise we send
178 the cancel signal to unblock the thread from a cancellation point,
179 or to initiate asynchronous cancellation. The restart is needed so
180 we have proper accounting of restarts; suspend decrements the thread's
181 resume count, and restart() increments it. This also means that suspend's
182 handling of the cancel signal is obsolete. */
186 else if (th->p_canceltype == PTHREAD_CANCEL_ASYNCHRONOUS)
188 l4_thread_ex_regs(th->p_th_cap, (l4_umword_t)&pthread_handle_sigcancel,
189 ~0UL, L4_THREAD_EX_REGS_CANCEL);
195 void pthread_testcancel(void)
197 pthread_descr self = thread_self();
198 if (THREAD_GETMEM(self, p_canceled)
199 && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE)
200 __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
205 __pthread_cleanup_push(struct _pthread_cleanup_buffer * buffer,
206 void (*routine)(void *), void * arg)
208 pthread_descr self = thread_self();
209 buffer->__routine = routine;
211 buffer->__prev = THREAD_GETMEM(self, p_cleanup);
212 if (buffer->__prev != NULL && FRAME_LEFT (buffer, buffer->__prev))
213 buffer->__prev = NULL;
214 THREAD_SETMEM(self, p_cleanup, buffer);
217 strong_alias(__pthread_cleanup_push, _pthread_cleanup_push)
221 __pthread_cleanup_pop(struct _pthread_cleanup_buffer * buffer,
224 pthread_descr self = thread_self();
225 if (execute) buffer->__routine(buffer->__arg);
226 THREAD_SETMEM(self, p_cleanup, buffer->__prev);
229 strong_alias(__pthread_cleanup_pop, _pthread_cleanup_pop)
233 __pthread_cleanup_push_defer(struct _pthread_cleanup_buffer * buffer,
234 void (*routine)(void *), void * arg)
236 pthread_descr self = thread_self();
237 buffer->__routine = routine;
239 buffer->__canceltype = THREAD_GETMEM(self, p_canceltype);
240 buffer->__prev = THREAD_GETMEM(self, p_cleanup);
241 if (buffer->__prev != NULL && FRAME_LEFT (buffer, buffer->__prev))
242 buffer->__prev = NULL;
243 THREAD_SETMEM(self, p_canceltype, PTHREAD_CANCEL_DEFERRED);
244 THREAD_SETMEM(self, p_cleanup, buffer);
247 strong_alias(__pthread_cleanup_push_defer, _pthread_cleanup_push_defer)
251 __pthread_cleanup_pop_restore(struct _pthread_cleanup_buffer * buffer,
254 pthread_descr self = thread_self();
255 if (execute) buffer->__routine(buffer->__arg);
256 THREAD_SETMEM(self, p_cleanup, buffer->__prev);
257 THREAD_SETMEM(self, p_canceltype, buffer->__canceltype);
258 if (THREAD_GETMEM(self, p_canceled) &&
259 THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE &&
260 THREAD_GETMEM(self, p_canceltype) == PTHREAD_CANCEL_ASYNCHRONOUS)
261 __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
264 strong_alias(__pthread_cleanup_pop_restore, _pthread_cleanup_pop_restore)
266 extern void __rpc_thread_destroy(void);
268 attribute_hidden internal_function
269 __pthread_perform_cleanup(char *currentframe)
271 pthread_descr self = thread_self();
272 struct _pthread_cleanup_buffer *c = THREAD_GETMEM(self, p_cleanup);
273 struct _pthread_cleanup_buffer *last;
276 while (FRAME_LEFT (currentframe, c))
281 if (c == NULL || FRAME_LEFT (last, c))
290 c->__routine(c->__arg);
295 if (FRAME_LEFT (last, c))
299 #ifdef __UCLIBC_HAS_RPC__
300 /* And the TSD which needs special help. */
301 if (THREAD_GETMEM(self, p_libc_specific[_LIBC_TSD_KEY_RPC_VARS]) != NULL)
302 __rpc_thread_destroy ();