| lh | 9ed821d | 2023-04-07 01:36:19 -0700 | [diff] [blame] | 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 | #include <bits/stackinfo.h> | 
|  | 22 |  | 
|  | 23 | /* These functions are not declared anywhere since they shouldn't be | 
|  | 24 | used at another place but here.  */ | 
|  | 25 | extern __typeof(siglongjmp) __libc_siglongjmp attribute_noreturn; | 
|  | 26 | extern __typeof(longjmp) __libc_longjmp attribute_noreturn; | 
|  | 27 |  | 
|  | 28 | static void pthread_cleanup_upto(__jmp_buf target) | 
|  | 29 | { | 
|  | 30 | pthread_descr self = thread_self(); | 
|  | 31 | struct _pthread_cleanup_buffer * c; | 
|  | 32 | char *currentframe = CURRENT_STACK_FRAME; | 
|  | 33 |  | 
|  | 34 | for (c = THREAD_GETMEM(self, p_cleanup); | 
|  | 35 | c != NULL && _JMPBUF_UNWINDS(target, c); | 
|  | 36 | c = c->__prev) | 
|  | 37 | { | 
|  | 38 | #ifdef _STACK_GROWS_DOWN | 
|  | 39 | if ((char *) c <= currentframe) | 
|  | 40 | { | 
|  | 41 | c = NULL; | 
|  | 42 | break; | 
|  | 43 | } | 
|  | 44 | #elif defined _STACK_GROWS_UP | 
|  | 45 | if ((char *) c >= currentframe) | 
|  | 46 | { | 
|  | 47 | c = NULL; | 
|  | 48 | break; | 
|  | 49 | } | 
|  | 50 | #else | 
|  | 51 | # error "Define either _STACK_GROWS_DOWN or _STACK_GROWS_UP" | 
|  | 52 | #endif | 
|  | 53 | c->__routine(c->__arg); | 
|  | 54 | } | 
|  | 55 | THREAD_SETMEM(self, p_cleanup, c); | 
|  | 56 | if (THREAD_GETMEM(self, p_in_sighandler) | 
|  | 57 | && _JMPBUF_UNWINDS(target, THREAD_GETMEM(self, p_in_sighandler))) | 
|  | 58 | THREAD_SETMEM(self, p_in_sighandler, NULL); | 
|  | 59 | } | 
|  | 60 |  | 
|  | 61 | void attribute_noreturn siglongjmp(sigjmp_buf env, int val) | 
|  | 62 | { | 
|  | 63 | pthread_cleanup_upto(env->__jmpbuf); | 
|  | 64 | __libc_siglongjmp(env, val); | 
|  | 65 | } | 
|  | 66 |  | 
|  | 67 | void attribute_noreturn longjmp(jmp_buf env, int val) | 
|  | 68 | { | 
|  | 69 | pthread_cleanup_upto(env->__jmpbuf); | 
|  | 70 | __libc_longjmp(env, val); | 
|  | 71 | } |