1*e2742650SMatthew Dillon /* 2*e2742650SMatthew Dillon * Copyright (c) 2007 Matthew T. Emmerton <matt@gsicomp.on.ca> 3*e2742650SMatthew Dillon * All rights reserved. 4*e2742650SMatthew Dillon * 5*e2742650SMatthew Dillon * Redistribution and use in source and binary forms, with or without 6*e2742650SMatthew Dillon * modification, are permitted provided that the following conditions 7*e2742650SMatthew Dillon * are met: 8*e2742650SMatthew Dillon * 1. Redistributions of source code must retain the above copyright 9*e2742650SMatthew Dillon * notice, this list of conditions and the following disclaimer. 10*e2742650SMatthew Dillon * 2. Neither the name of the author nor the names of its contributors 11*e2742650SMatthew Dillon * may be used to endorse or promote products derived from this software 12*e2742650SMatthew Dillon * without specific prior written permission. 13*e2742650SMatthew Dillon * 14*e2742650SMatthew Dillon * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15*e2742650SMatthew Dillon * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16*e2742650SMatthew Dillon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17*e2742650SMatthew Dillon * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18*e2742650SMatthew Dillon * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19*e2742650SMatthew Dillon * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20*e2742650SMatthew Dillon * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21*e2742650SMatthew Dillon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22*e2742650SMatthew Dillon * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23*e2742650SMatthew Dillon * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24*e2742650SMatthew Dillon * SUCH DAMAGE. 25*e2742650SMatthew Dillon * 26*e2742650SMatthew Dillon * $DragonFly: src/lib/libc/gen/ucontext.c,v 1.1 2007/01/16 07:16:23 dillon Exp $ 27*e2742650SMatthew Dillon */ 28*e2742650SMatthew Dillon 29*e2742650SMatthew Dillon #include <sys/cdefs.h> 30*e2742650SMatthew Dillon #include <sys/param.h> 31*e2742650SMatthew Dillon #include <sys/signal.h> 32*e2742650SMatthew Dillon #include <sys/ucontext.h> 33*e2742650SMatthew Dillon 34*e2742650SMatthew Dillon #include <errno.h> 35*e2742650SMatthew Dillon #include <stdarg.h> 36*e2742650SMatthew Dillon #include <stdlib.h> 37*e2742650SMatthew Dillon #include <unistd.h> 38*e2742650SMatthew Dillon #include <signal.h> 39*e2742650SMatthew Dillon 40*e2742650SMatthew Dillon /* Prototypes */ 41*e2742650SMatthew Dillon __weak_reference(_swapcontext, swapcontext); 42*e2742650SMatthew Dillon __weak_reference(_setcontext, setcontext); 43*e2742650SMatthew Dillon 44*e2742650SMatthew Dillon int get_mcontext(mcontext_t *); 45*e2742650SMatthew Dillon int set_mcontext(const mcontext_t *); 46*e2742650SMatthew Dillon 47*e2742650SMatthew Dillon /* 48*e2742650SMatthew Dillon * We need to block most signals during a context switch so we do not 49*e2742650SMatthew Dillon * dispatch a signal vector during a context switch. 50*e2742650SMatthew Dillon */ 51*e2742650SMatthew Dillon static sigset_t sigset_block_all; 52*e2742650SMatthew Dillon 53*e2742650SMatthew Dillon static void __sigset_block_all_setup(void) __attribute__ ((constructor)); 54*e2742650SMatthew Dillon 55*e2742650SMatthew Dillon static void 56*e2742650SMatthew Dillon __sigset_block_all_setup(void) 57*e2742650SMatthew Dillon { 58*e2742650SMatthew Dillon sigfillset(&sigset_block_all); 59*e2742650SMatthew Dillon sigdelset(&sigset_block_all, SIGSEGV); 60*e2742650SMatthew Dillon sigdelset(&sigset_block_all, SIGBUS); 61*e2742650SMatthew Dillon sigdelset(&sigset_block_all, SIGILL); 62*e2742650SMatthew Dillon } 63*e2742650SMatthew Dillon 64*e2742650SMatthew Dillon /* 65*e2742650SMatthew Dillon * Save the calling context in (oucp) then switch to (ucp). 66*e2742650SMatthew Dillon * 67*e2742650SMatthew Dillon * Block all signals while switching contexts. get_mcontext() returns zero 68*e2742650SMatthew Dillon * when retrieving a context. 69*e2742650SMatthew Dillon * 70*e2742650SMatthew Dillon * When some other thread calls set_mcontext() to resume our thread, 71*e2742650SMatthew Dillon * the resume point causes get_mcontext() to return non-zero to us. 72*e2742650SMatthew Dillon * Signals will be blocked and we must restore the signal mask before 73*e2742650SMatthew Dillon * returning. 74*e2742650SMatthew Dillon */ 75*e2742650SMatthew Dillon int 76*e2742650SMatthew Dillon _swapcontext(ucontext_t *oucp, const ucontext_t *ucp) 77*e2742650SMatthew Dillon { 78*e2742650SMatthew Dillon int ret; 79*e2742650SMatthew Dillon 80*e2742650SMatthew Dillon ret = _sigprocmask(SIG_BLOCK, &sigset_block_all, &oucp->uc_sigmask); 81*e2742650SMatthew Dillon if (ret == 0) { 82*e2742650SMatthew Dillon if (get_mcontext(&oucp->uc_mcontext) == 0) { 83*e2742650SMatthew Dillon ret = set_mcontext(&ucp->uc_mcontext); 84*e2742650SMatthew Dillon } else { 85*e2742650SMatthew Dillon ret = _sigprocmask(SIG_SETMASK, &oucp->uc_sigmask, NULL); 86*e2742650SMatthew Dillon } 87*e2742650SMatthew Dillon } 88*e2742650SMatthew Dillon return(ret); 89*e2742650SMatthew Dillon } 90*e2742650SMatthew Dillon 91*e2742650SMatthew Dillon /* 92*e2742650SMatthew Dillon * Switch to the target context. The current signal mask is saved in ucp 93*e2742650SMatthew Dillon * and all signals are blocked. The call to set_mcontext() causes the 94*e2742650SMatthew Dillon * specified context to be switched to (usually resuming as a return from 95*e2742650SMatthew Dillon * the get_mcontext() procedure). The current context is thrown away. 96*e2742650SMatthew Dillon * 97*e2742650SMatthew Dillon * The target context being resumed is responsible for restoring the 98*e2742650SMatthew Dillon * signal mask appropriate for the target context. 99*e2742650SMatthew Dillon */ 100*e2742650SMatthew Dillon int 101*e2742650SMatthew Dillon _setcontext(ucontext_t *ucp) 102*e2742650SMatthew Dillon { 103*e2742650SMatthew Dillon int ret; 104*e2742650SMatthew Dillon 105*e2742650SMatthew Dillon ret = _sigprocmask(SIG_BLOCK, &sigset_block_all, &ucp->uc_sigmask); 106*e2742650SMatthew Dillon if (ret == 0) 107*e2742650SMatthew Dillon ret = set_mcontext(&ucp->uc_mcontext); 108*e2742650SMatthew Dillon return(ret); 109*e2742650SMatthew Dillon } 110*e2742650SMatthew Dillon 111