1bb535300SJeff Roberson /* 2df2cf821SDavid Xu * Copyright (c) 2005, David Xu <davidxu@freebsd.org> 3bb535300SJeff Roberson * All rights reserved. 4bb535300SJeff Roberson * 5bb535300SJeff Roberson * Redistribution and use in source and binary forms, with or without 6bb535300SJeff Roberson * modification, are permitted provided that the following conditions 7bb535300SJeff Roberson * are met: 8bb535300SJeff Roberson * 1. Redistributions of source code must retain the above copyright 9df2cf821SDavid Xu * notice unmodified, this list of conditions, and the following 10df2cf821SDavid Xu * disclaimer. 11bb535300SJeff Roberson * 2. Redistributions in binary form must reproduce the above copyright 12bb535300SJeff Roberson * notice, this list of conditions and the following disclaimer in the 13bb535300SJeff Roberson * documentation and/or other materials provided with the distribution. 14bb535300SJeff Roberson * 15df2cf821SDavid Xu * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16df2cf821SDavid Xu * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17df2cf821SDavid Xu * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18df2cf821SDavid Xu * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19df2cf821SDavid Xu * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20df2cf821SDavid Xu * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21df2cf821SDavid Xu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22df2cf821SDavid Xu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23df2cf821SDavid Xu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24df2cf821SDavid Xu * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25bb535300SJeff Roberson * 26bb535300SJeff Roberson * $FreeBSD$ 27bb535300SJeff Roberson */ 28bb535300SJeff Roberson 2937a6356bSDavid Xu #include "namespace.h" 30bb535300SJeff Roberson #include <sys/param.h> 31bb535300SJeff Roberson #include <sys/types.h> 32bb535300SJeff Roberson #include <sys/signalvar.h> 33bb535300SJeff Roberson #include <signal.h> 34a091d823SDavid Xu #include <errno.h> 35bb535300SJeff Roberson #include <fcntl.h> 36bb535300SJeff Roberson #include <unistd.h> 37a091d823SDavid Xu #include <string.h> 38bb535300SJeff Roberson #include <pthread.h> 3937a6356bSDavid Xu #include "un-namespace.h" 4089552201SMike Makonnen 41bb535300SJeff Roberson #include "thr_private.h" 42bb535300SJeff Roberson 43bb535300SJeff Roberson /* #define DEBUG_SIGNAL */ 44bb535300SJeff Roberson #ifdef DEBUG_SIGNAL 45bb535300SJeff Roberson #define DBG_MSG stdout_debug 46bb535300SJeff Roberson #else 47bb535300SJeff Roberson #define DBG_MSG(x...) 48bb535300SJeff Roberson #endif 49bb535300SJeff Roberson 5005c3a5eaSDavid Xu extern int __pause(void); 5105c3a5eaSDavid Xu int ___pause(void); 5205c3a5eaSDavid Xu int _raise(int); 5337a6356bSDavid Xu int __sigtimedwait(const sigset_t *set, siginfo_t *info, 5437a6356bSDavid Xu const struct timespec * timeout); 55922d56f9SDavid Xu int _sigtimedwait(const sigset_t *set, siginfo_t *info, 56922d56f9SDavid Xu const struct timespec * timeout); 5737a6356bSDavid Xu int __sigwaitinfo(const sigset_t *set, siginfo_t *info); 58922d56f9SDavid Xu int _sigwaitinfo(const sigset_t *set, siginfo_t *info); 5937a6356bSDavid Xu int __sigwait(const sigset_t *set, int *sig); 60922d56f9SDavid Xu int _sigwait(const sigset_t *set, int *sig); 61922d56f9SDavid Xu int __sigsuspend(const sigset_t *sigmask); 62*5cf22195SDavid Xu int _setcontext(const ucontext_t *); 63*5cf22195SDavid Xu int _swapcontext(ucontext_t *, const ucontext_t *); 6437a6356bSDavid Xu 65*5cf22195SDavid Xu static void 66*5cf22195SDavid Xu remove_thr_signals(sigset_t *set) 67*5cf22195SDavid Xu { 68*5cf22195SDavid Xu if (SIGISMEMBER(*set, SIGCANCEL)) 69*5cf22195SDavid Xu SIGDELSET(*set, SIGCANCEL); 70*5cf22195SDavid Xu } 71*5cf22195SDavid Xu 72*5cf22195SDavid Xu static const sigset_t * 73*5cf22195SDavid Xu thr_remove_thr_signals(const sigset_t *set, sigset_t *newset) 74*5cf22195SDavid Xu { 75*5cf22195SDavid Xu const sigset_t *pset; 76*5cf22195SDavid Xu 77*5cf22195SDavid Xu if (SIGISMEMBER(*set, SIGCANCEL)) { 78*5cf22195SDavid Xu *newset = *set; 79*5cf22195SDavid Xu SIGDELSET(*newset, SIGCANCEL); 80*5cf22195SDavid Xu pset = newset; 81*5cf22195SDavid Xu } else 82*5cf22195SDavid Xu pset = set; 83*5cf22195SDavid Xu return (pset); 84*5cf22195SDavid Xu } 856fdfcacbSDavid Xu 86a091d823SDavid Xu static void 8737a6356bSDavid Xu sigcancel_handler(int sig __unused, 8837a6356bSDavid Xu siginfo_t *info __unused, ucontext_t *ucp __unused) 89a091d823SDavid Xu { 90a091d823SDavid Xu struct pthread *curthread = _get_curthread(); 91a091d823SDavid Xu 921cb51125SDavid Xu curthread->in_sigcancel_handler++; 93bc414752SDavid Xu _thr_ast(curthread); 941cb51125SDavid Xu curthread->in_sigcancel_handler--; 95bc414752SDavid Xu } 96bc414752SDavid Xu 97bc414752SDavid Xu void 98bc414752SDavid Xu _thr_ast(struct pthread *curthread) 99bc414752SDavid Xu { 100635f917aSDavid Xu 101635f917aSDavid Xu if (THR_IN_CRITICAL(curthread)) 102635f917aSDavid Xu return; 103635f917aSDavid Xu 104635f917aSDavid Xu if (curthread->cancel_pending && curthread->cancel_enable 105635f917aSDavid Xu && !curthread->cancelling) { 106635f917aSDavid Xu if (curthread->cancel_async) { 107635f917aSDavid Xu /* 108635f917aSDavid Xu * asynchronous cancellation mode, act upon 109635f917aSDavid Xu * immediately. 110635f917aSDavid Xu */ 111635f917aSDavid Xu _pthread_exit(PTHREAD_CANCELED); 112635f917aSDavid Xu } else { 113635f917aSDavid Xu /* 114635f917aSDavid Xu * Otherwise, we are in defer mode, and we are at 115635f917aSDavid Xu * cancel point, tell kernel to not block the current 116635f917aSDavid Xu * thread on next cancelable system call. 117635f917aSDavid Xu * 118635f917aSDavid Xu * There are two cases we should call thr_wake() to 119635f917aSDavid Xu * turn on TDP_WAKEUP in kernel: 120635f917aSDavid Xu * 1) we are going to call a cancelable system call, 121635f917aSDavid Xu * non-zero cancel_point means we are already in 122635f917aSDavid Xu * cancelable state, next system call is cancelable. 123635f917aSDavid Xu * 2) because _thr_ast() may be called by 124635f917aSDavid Xu * THR_CRITICAL_LEAVE() which is used by rtld rwlock 125635f917aSDavid Xu * and any libthr internal locks, when rtld rwlock 126635f917aSDavid Xu * is used, it is mostly caused my an unresolved PLT. 127635f917aSDavid Xu * those routines may clear the TDP_WAKEUP flag by 128635f917aSDavid Xu * invoking some system calls, in those cases, we 129635f917aSDavid Xu * also should reenable the flag. 130635f917aSDavid Xu */ 131635f917aSDavid Xu if (curthread->cancel_point) { 132635f917aSDavid Xu if (curthread->cancel_defer) 133635f917aSDavid Xu thr_wake(curthread->tid); 134635f917aSDavid Xu else 135635f917aSDavid Xu _pthread_exit(PTHREAD_CANCELED); 136635f917aSDavid Xu } 137635f917aSDavid Xu } 138635f917aSDavid Xu } 139635f917aSDavid Xu 140bc414752SDavid Xu if (__predict_false((curthread->flags & 141bc414752SDavid Xu (THR_FLAGS_NEED_SUSPEND | THR_FLAGS_SUSPENDED)) 142bc414752SDavid Xu == THR_FLAGS_NEED_SUSPEND)) 143a091d823SDavid Xu _thr_suspend_check(curthread); 144a091d823SDavid Xu } 145a091d823SDavid Xu 146a091d823SDavid Xu void 147a091d823SDavid Xu _thr_suspend_check(struct pthread *curthread) 148a091d823SDavid Xu { 1498d6a11a0SDavid Xu uint32_t cycle; 150d448272dSDavid Xu int err; 151a091d823SDavid Xu 1522ea1f90aSDavid Xu if (curthread->force_exit) 1532ea1f90aSDavid Xu return; 1542ea1f90aSDavid Xu 155d448272dSDavid Xu err = errno; 156bc414752SDavid Xu /* 157bc414752SDavid Xu * Blocks SIGCANCEL which other threads must send. 158bc414752SDavid Xu */ 159a091d823SDavid Xu _thr_signal_block(curthread); 160bc414752SDavid Xu 161bc414752SDavid Xu /* 162bc414752SDavid Xu * Increase critical_count, here we don't use THR_LOCK/UNLOCK 163bc414752SDavid Xu * because we are leaf code, we don't want to recursively call 164bc414752SDavid Xu * ourself. 165bc414752SDavid Xu */ 166bc414752SDavid Xu curthread->critical_count++; 167bddd24cdSDavid Xu THR_UMUTEX_LOCK(curthread, &(curthread)->lock); 168bc414752SDavid Xu while ((curthread->flags & (THR_FLAGS_NEED_SUSPEND | 169bc414752SDavid Xu THR_FLAGS_SUSPENDED)) == THR_FLAGS_NEED_SUSPEND) { 170bc414752SDavid Xu curthread->cycle++; 171a091d823SDavid Xu cycle = curthread->cycle; 172bc414752SDavid Xu 173bc414752SDavid Xu /* Wake the thread suspending us. */ 1748d6a11a0SDavid Xu _thr_umtx_wake(&curthread->cycle, INT_MAX, 0); 175bc414752SDavid Xu 176bc414752SDavid Xu /* 177bc414752SDavid Xu * if we are from pthread_exit, we don't want to 178bc414752SDavid Xu * suspend, just go and die. 179bc414752SDavid Xu */ 180bc414752SDavid Xu if (curthread->state == PS_DEAD) 181bc414752SDavid Xu break; 182bc414752SDavid Xu curthread->flags |= THR_FLAGS_SUSPENDED; 183bddd24cdSDavid Xu THR_UMUTEX_UNLOCK(curthread, &(curthread)->lock); 1848d6a11a0SDavid Xu _thr_umtx_wait_uint(&curthread->cycle, cycle, NULL, 0); 185bddd24cdSDavid Xu THR_UMUTEX_LOCK(curthread, &(curthread)->lock); 186a091d823SDavid Xu curthread->flags &= ~THR_FLAGS_SUSPENDED; 187a091d823SDavid Xu } 188bddd24cdSDavid Xu THR_UMUTEX_UNLOCK(curthread, &(curthread)->lock); 189bc414752SDavid Xu curthread->critical_count--; 190bc414752SDavid Xu 191bc414752SDavid Xu /* 192bc414752SDavid Xu * Unblocks SIGCANCEL, it is possible a new SIGCANCEL is ready and 193bc414752SDavid Xu * a new signal frame will nest us, this seems a problem because 194bc414752SDavid Xu * stack will grow and overflow, but because kernel will automatically 195bc414752SDavid Xu * mask the SIGCANCEL when delivering the signal, so we at most only 196bc414752SDavid Xu * have one nesting signal frame, this should be fine. 197bc414752SDavid Xu */ 198a091d823SDavid Xu _thr_signal_unblock(curthread); 199d448272dSDavid Xu errno = err; 200a091d823SDavid Xu } 201a091d823SDavid Xu 202a091d823SDavid Xu void 203a091d823SDavid Xu _thr_signal_init(void) 204a091d823SDavid Xu { 205a091d823SDavid Xu struct sigaction act; 206a091d823SDavid Xu 207a091d823SDavid Xu /* Install cancel handler. */ 208a091d823SDavid Xu SIGEMPTYSET(act.sa_mask); 209a091d823SDavid Xu act.sa_flags = SA_SIGINFO | SA_RESTART; 210a091d823SDavid Xu act.sa_sigaction = (__siginfohandler_t *)&sigcancel_handler; 211a091d823SDavid Xu __sys_sigaction(SIGCANCEL, &act, NULL); 212a091d823SDavid Xu } 213a091d823SDavid Xu 214a091d823SDavid Xu void 215a091d823SDavid Xu _thr_signal_deinit(void) 216a091d823SDavid Xu { 217a091d823SDavid Xu } 218a091d823SDavid Xu 21905c3a5eaSDavid Xu __weak_reference(___pause, pause); 22005c3a5eaSDavid Xu 22105c3a5eaSDavid Xu int 22205c3a5eaSDavid Xu ___pause(void) 22305c3a5eaSDavid Xu { 22405c3a5eaSDavid Xu struct pthread *curthread = _get_curthread(); 22505c3a5eaSDavid Xu int ret; 22605c3a5eaSDavid Xu 227f08e1bf6SDavid Xu _thr_cancel_enter(curthread); 22805c3a5eaSDavid Xu ret = __pause(); 229f08e1bf6SDavid Xu _thr_cancel_leave(curthread); 23005c3a5eaSDavid Xu 23105c3a5eaSDavid Xu return ret; 23205c3a5eaSDavid Xu } 23305c3a5eaSDavid Xu 23405c3a5eaSDavid Xu __weak_reference(_raise, raise); 23505c3a5eaSDavid Xu 23605c3a5eaSDavid Xu int 23705c3a5eaSDavid Xu _raise(int sig) 23805c3a5eaSDavid Xu { 23905c3a5eaSDavid Xu int ret; 24005c3a5eaSDavid Xu 24105c3a5eaSDavid Xu if (!_thr_isthreaded()) 24205c3a5eaSDavid Xu ret = kill(getpid(), sig); 24305c3a5eaSDavid Xu else 24405c3a5eaSDavid Xu ret = _thr_send_sig(_get_curthread(), sig); 24505c3a5eaSDavid Xu return (ret); 24605c3a5eaSDavid Xu } 24705c3a5eaSDavid Xu 248a091d823SDavid Xu __weak_reference(_sigaction, sigaction); 249a091d823SDavid Xu 250a091d823SDavid Xu int 251a091d823SDavid Xu _sigaction(int sig, const struct sigaction * act, struct sigaction * oact) 252a091d823SDavid Xu { 253a091d823SDavid Xu /* Check if the signal number is out of range: */ 254b144e48bSKonstantin Belousov if (!_SIG_VALID(sig) || sig == SIGCANCEL) { 255a091d823SDavid Xu /* Return an invalid argument: */ 256a091d823SDavid Xu errno = EINVAL; 257a091d823SDavid Xu return (-1); 258a091d823SDavid Xu } 259a091d823SDavid Xu 260a091d823SDavid Xu return __sys_sigaction(sig, act, oact); 261a091d823SDavid Xu } 262a091d823SDavid Xu 263a091d823SDavid Xu __weak_reference(_sigprocmask, sigprocmask); 264a091d823SDavid Xu 265a091d823SDavid Xu int 266a091d823SDavid Xu _sigprocmask(int how, const sigset_t *set, sigset_t *oset) 267a091d823SDavid Xu { 268a091d823SDavid Xu const sigset_t *p = set; 269a091d823SDavid Xu sigset_t newset; 270a091d823SDavid Xu 271a091d823SDavid Xu if (how != SIG_UNBLOCK) { 272a091d823SDavid Xu if (set != NULL) { 273a091d823SDavid Xu newset = *set; 274a091d823SDavid Xu SIGDELSET(newset, SIGCANCEL); 275a091d823SDavid Xu p = &newset; 276a091d823SDavid Xu } 277a091d823SDavid Xu } 278a091d823SDavid Xu return (__sys_sigprocmask(how, p, oset)); 279a091d823SDavid Xu } 280a091d823SDavid Xu 281bb535300SJeff Roberson __weak_reference(_pthread_sigmask, pthread_sigmask); 282bb535300SJeff Roberson 283bb535300SJeff Roberson int 284bb535300SJeff Roberson _pthread_sigmask(int how, const sigset_t *set, sigset_t *oset) 285bb535300SJeff Roberson { 286a091d823SDavid Xu if (_sigprocmask(how, set, oset)) 287a091d823SDavid Xu return (errno); 288a091d823SDavid Xu return (0); 289bb535300SJeff Roberson } 290bb535300SJeff Roberson 29105c3a5eaSDavid Xu __weak_reference(__sigsuspend, sigsuspend); 292bb535300SJeff Roberson 293bb535300SJeff Roberson int 294a091d823SDavid Xu _sigsuspend(const sigset_t * set) 295bb535300SJeff Roberson { 29605c3a5eaSDavid Xu sigset_t newset; 29705c3a5eaSDavid Xu 29882746ea5SDavid Xu return (__sys_sigsuspend(thr_remove_thr_signals(set, &newset))); 29905c3a5eaSDavid Xu } 30005c3a5eaSDavid Xu 30105c3a5eaSDavid Xu int 30205c3a5eaSDavid Xu __sigsuspend(const sigset_t * set) 30305c3a5eaSDavid Xu { 304a091d823SDavid Xu struct pthread *curthread = _get_curthread(); 305a091d823SDavid Xu sigset_t newset; 306a091d823SDavid Xu int ret; 307bb535300SJeff Roberson 308f08e1bf6SDavid Xu _thr_cancel_enter(curthread); 30982746ea5SDavid Xu ret = __sys_sigsuspend(thr_remove_thr_signals(set, &newset)); 310f08e1bf6SDavid Xu _thr_cancel_leave(curthread); 3110ad70ba9SMike Makonnen 312a091d823SDavid Xu return (ret); 313a091d823SDavid Xu } 314a091d823SDavid Xu 315a091d823SDavid Xu __weak_reference(__sigwait, sigwait); 316a091d823SDavid Xu __weak_reference(__sigtimedwait, sigtimedwait); 317a091d823SDavid Xu __weak_reference(__sigwaitinfo, sigwaitinfo); 318a091d823SDavid Xu 319a091d823SDavid Xu int 32005c3a5eaSDavid Xu _sigtimedwait(const sigset_t *set, siginfo_t *info, 32105c3a5eaSDavid Xu const struct timespec * timeout) 32205c3a5eaSDavid Xu { 32305c3a5eaSDavid Xu sigset_t newset; 32405c3a5eaSDavid Xu 32582746ea5SDavid Xu return (__sys_sigtimedwait(thr_remove_thr_signals(set, &newset), info, 32682746ea5SDavid Xu timeout)); 32705c3a5eaSDavid Xu } 32805c3a5eaSDavid Xu 329635f917aSDavid Xu /* 330635f917aSDavid Xu * Cancellation behavior: 331635f917aSDavid Xu * Thread may be canceled at start, if thread got signal, 332635f917aSDavid Xu * it is not canceled. 333635f917aSDavid Xu */ 33405c3a5eaSDavid Xu int 335a091d823SDavid Xu __sigtimedwait(const sigset_t *set, siginfo_t *info, 336a091d823SDavid Xu const struct timespec * timeout) 337a091d823SDavid Xu { 338a091d823SDavid Xu struct pthread *curthread = _get_curthread(); 339a091d823SDavid Xu sigset_t newset; 340a091d823SDavid Xu int ret; 341a091d823SDavid Xu 342635f917aSDavid Xu _thr_cancel_enter_defer(curthread, 1); 34382746ea5SDavid Xu ret = __sys_sigtimedwait(thr_remove_thr_signals(set, &newset), info, 34482746ea5SDavid Xu timeout); 345635f917aSDavid Xu _thr_cancel_leave_defer(curthread, (ret == -1)); 346a091d823SDavid Xu return (ret); 347a091d823SDavid Xu } 348a091d823SDavid Xu 349a091d823SDavid Xu int 35005c3a5eaSDavid Xu _sigwaitinfo(const sigset_t *set, siginfo_t *info) 35105c3a5eaSDavid Xu { 35205c3a5eaSDavid Xu sigset_t newset; 35305c3a5eaSDavid Xu 35482746ea5SDavid Xu return (__sys_sigwaitinfo(thr_remove_thr_signals(set, &newset), info)); 35505c3a5eaSDavid Xu } 35605c3a5eaSDavid Xu 357635f917aSDavid Xu /* 358635f917aSDavid Xu * Cancellation behavior: 359635f917aSDavid Xu * Thread may be canceled at start, if thread got signal, 360635f917aSDavid Xu * it is not canceled. 361635f917aSDavid Xu */ 36205c3a5eaSDavid Xu int 363a091d823SDavid Xu __sigwaitinfo(const sigset_t *set, siginfo_t *info) 364a091d823SDavid Xu { 365a091d823SDavid Xu struct pthread *curthread = _get_curthread(); 366a091d823SDavid Xu sigset_t newset; 367a091d823SDavid Xu int ret; 368a091d823SDavid Xu 369635f917aSDavid Xu _thr_cancel_enter_defer(curthread, 1); 37082746ea5SDavid Xu ret = __sys_sigwaitinfo(thr_remove_thr_signals(set, &newset), info); 371635f917aSDavid Xu _thr_cancel_leave_defer(curthread, ret == -1); 372a091d823SDavid Xu return (ret); 373a091d823SDavid Xu } 374a091d823SDavid Xu 375a091d823SDavid Xu int 37605c3a5eaSDavid Xu _sigwait(const sigset_t *set, int *sig) 37705c3a5eaSDavid Xu { 37805c3a5eaSDavid Xu sigset_t newset; 37905c3a5eaSDavid Xu 38082746ea5SDavid Xu return (__sys_sigwait(thr_remove_thr_signals(set, &newset), sig)); 38105c3a5eaSDavid Xu } 38205c3a5eaSDavid Xu 383635f917aSDavid Xu /* 384635f917aSDavid Xu * Cancellation behavior: 385635f917aSDavid Xu * Thread may be canceled at start, if thread got signal, 386635f917aSDavid Xu * it is not canceled. 387635f917aSDavid Xu */ 38805c3a5eaSDavid Xu int 389a091d823SDavid Xu __sigwait(const sigset_t *set, int *sig) 390a091d823SDavid Xu { 391a091d823SDavid Xu struct pthread *curthread = _get_curthread(); 392a091d823SDavid Xu sigset_t newset; 393a091d823SDavid Xu int ret; 394a091d823SDavid Xu 395635f917aSDavid Xu _thr_cancel_enter_defer(curthread, 1); 39682746ea5SDavid Xu ret = __sys_sigwait(thr_remove_thr_signals(set, &newset), sig); 397635f917aSDavid Xu _thr_cancel_leave_defer(curthread, (ret != 0)); 398a091d823SDavid Xu return (ret); 399bb535300SJeff Roberson } 400*5cf22195SDavid Xu 401*5cf22195SDavid Xu __weak_reference(_setcontext, setcontext); 402*5cf22195SDavid Xu int 403*5cf22195SDavid Xu _setcontext(const ucontext_t *ucp) 404*5cf22195SDavid Xu { 405*5cf22195SDavid Xu ucontext_t uc; 406*5cf22195SDavid Xu 407*5cf22195SDavid Xu (void) memcpy(&uc, ucp, sizeof (uc)); 408*5cf22195SDavid Xu remove_thr_signals(&uc.uc_sigmask); 409*5cf22195SDavid Xu 410*5cf22195SDavid Xu return __sys_setcontext(&uc); 411*5cf22195SDavid Xu } 412*5cf22195SDavid Xu 413*5cf22195SDavid Xu __weak_reference(_swapcontext, swapcontext); 414*5cf22195SDavid Xu int 415*5cf22195SDavid Xu _swapcontext(ucontext_t *oucp, const ucontext_t *ucp) 416*5cf22195SDavid Xu { 417*5cf22195SDavid Xu ucontext_t uc; 418*5cf22195SDavid Xu 419*5cf22195SDavid Xu (void) memcpy(&uc, ucp, sizeof (uc)); 420*5cf22195SDavid Xu remove_thr_signals(&uc.uc_sigmask); 421*5cf22195SDavid Xu return __sys_swapcontext(oucp, &uc); 422*5cf22195SDavid Xu } 423