1 | /* Linuxthreads - a simple clone()-based implementation of Posix */ |
---|
2 | /* threads for Linux. */ |
---|
3 | /* Copyright (C) 1998 Xavier Leroy (Xavier.Leroy@inria.fr) */ |
---|
4 | /* */ |
---|
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. */ |
---|
9 | /* */ |
---|
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. */ |
---|
14 | |
---|
15 | /* Redefine siglongjmp and longjmp so that they interact correctly |
---|
16 | with cleanup handlers */ |
---|
17 | |
---|
18 | #include <setjmp.h> |
---|
19 | #include "pthread.h" |
---|
20 | #include "internals.h" |
---|
21 | |
---|
22 | /* These functions are not declared anywhere since they shouldn't be |
---|
23 | used at another place but here. */ |
---|
24 | extern void __libc_siglongjmp (sigjmp_buf env, int val) |
---|
25 | __attribute__ ((noreturn)); |
---|
26 | extern void __libc_longjmp (jmp_buf env, int val) |
---|
27 | __attribute__ ((noreturn)); |
---|
28 | |
---|
29 | |
---|
30 | static void pthread_cleanup_upto(jmp_buf target) |
---|
31 | { |
---|
32 | pthread_descr self = thread_self(); |
---|
33 | struct _pthread_cleanup_buffer * c; |
---|
34 | char *currentframe = CURRENT_STACK_FRAME; |
---|
35 | |
---|
36 | for (c = THREAD_GETMEM(self, p_cleanup); |
---|
37 | c != NULL && _JMPBUF_UNWINDS(target, c); |
---|
38 | c = c->__prev) |
---|
39 | { |
---|
40 | #if _STACK_GROWS_DOWN |
---|
41 | if ((char *) c <= currentframe) |
---|
42 | { |
---|
43 | c = NULL; |
---|
44 | break; |
---|
45 | } |
---|
46 | #elif _STACK_GROWS_UP |
---|
47 | if ((char *) c >= currentframe) |
---|
48 | { |
---|
49 | c = NULL; |
---|
50 | break; |
---|
51 | } |
---|
52 | #else |
---|
53 | # error "Define either _STACK_GROWS_DOWN or _STACK_GROWS_UP" |
---|
54 | #endif |
---|
55 | c->__routine(c->__arg); |
---|
56 | } |
---|
57 | THREAD_SETMEM(self, p_cleanup, c); |
---|
58 | if (THREAD_GETMEM(self, p_in_sighandler) |
---|
59 | && _JMPBUF_UNWINDS(target, THREAD_GETMEM(self, p_in_sighandler))) |
---|
60 | THREAD_SETMEM(self, p_in_sighandler, NULL); |
---|
61 | } |
---|
62 | |
---|
63 | void siglongjmp(sigjmp_buf env, int val) |
---|
64 | { |
---|
65 | pthread_cleanup_upto(env.__buf); |
---|
66 | __libc_siglongjmp(env, val); |
---|
67 | } |
---|
68 | |
---|
69 | void longjmp(jmp_buf env, int val) |
---|
70 | { |
---|
71 | pthread_cleanup_upto(env); |
---|
72 | __libc_longjmp(env, val); |
---|
73 | } |
---|