head 1.63; access; symbols PTH_2_0_7:1.62 PTH_2_0_6:1.61 PTH_2_0_5:1.61 PTH_2_0_4:1.61 PTH_2_0_3:1.60 PTH_2_0_2:1.59 PTH_2_0_1:1.59 PTH_2_0_0:1.58 PTH_2_0b2:1.57 PTH_2_0b1:1.57 PTH_2_0b0:1.57 PTH_1_4:1.56.0.2 PTH_1_4_1:1.56 PTH_1_4_0:1.55 PTH_1_3_7:1.50.2.1 PTH_1_4a3:1.54 PTH_1_3_6:1.50.2.1 PTH_1_4a2:1.54 PTH_1_3_5:1.50.2.1 PTH_1_4a1:1.53 PTH_1_3_4:1.50.2.1 PTH_1_3:1.50.0.2 PTH_1_3_3:1.50 PTH_1_3_2:1.50 PTH_1_3_1:1.50 PTH_1_3_0:1.50 PTH_1_3b3:1.50 PTH_1_2_3:1.42.2.2 PTH_1_3b2:1.50 PTH_1_3b1:1.50 PTH_1_3a5:1.50 PTH_1_3a4:1.50 PTH_1_3a3:1.49 PTH_1_2_2:1.42.2.2 PTH_1_3a2:1.47 PTH_1_2_1:1.42.2.1 PTH_1_3a1:1.43 PTH_1_2:1.42.0.2 PTH_1_2_0:1.42 PTH_1_2b8:1.41 PTH_1_2b7:1.41 PTH_1_1_6:1.36 PTH_1_2b6:1.41 PTH_1_2b5:1.40 PTH_1_2b4:1.40 PTH_1_2b3:1.40 PTH_1_2b2:1.38 PTH_1_2b1:1.37 PTH_1_1_5:1.36 PTH_1_0_6:1.29.2.1 PTH_1_0_5:1.29.2.1 PTH_1_0:1.29.0.2 PTH_1_1:1.36.0.2 PTH_1_1_4:1.36 PTH_1_1_3:1.35 PTH_1_1_2:1.35 PTH_1_1_1:1.35 PTH_1_1_0:1.35 PTH_1_1b7:1.34 PTH_1_1b6:1.33 PTH_1_1b5:1.32 PTH_1_1b4:1.31 PTH_1_1b3:1.31 PTH_1_1b2:1.31 PTH_1_1b1:1.31 PTH_1_0_4:1.29 PTH_1_0_3:1.29 PTH_1_0_2:1.29 PTH_1_0_1:1.28 PTH_1_0_0:1.28 PTH_1_0b8:1.26 PTH_1_0b7:1.26 PTH_1_0b6:1.26 PTH_1_0b5:1.26 PTH_1_0b4:1.26 PTH_1_0b3:1.23 PTH_1_0b2:1.23 PTH_1_0b1:1.22 PTH_0_9_21:1.22 PTH_0_9_20:1.22 PTH_0_9_19:1.21 PTH_0_9_18:1.21 PTH_0_9_17:1.21 PTH_0_9_16:1.20 PTH_0_9_15:1.19 PTH_0_9_14:1.16 PTH_0_9_13:1.15 PTH_0_9_12:1.7 PTH_0_9_11:1.7 PTH_0_9_10:1.7 PTH_0_9_9:1.6 PTH_0_9_8:1.6 PTH_0_9_7:1.5 PTH_0_9_6:1.4 PTH_0_9_5:1.2 PTH_0_9_4:1.2 PTH_0_9_3:1.2 PTH_0_9_2:1.2 PTH_0_9_1:1.1.1.1 PTH_0_9_0:1.1.1.1 RSE:1.1.1; locks; strict; comment @ * @; 1.63 date 2007.01.01.18.23.53; author rse; state Exp; branches; next 1.62; commitid 9DhdiirNzQPBIP0s; 1.62 date 2006.06.08.17.54.53; author rse; state Exp; branches; next 1.61; commitid x8N3mLVdQgkbdeAr; 1.61 date 2004.12.31.19.34.45; author rse; state Exp; branches; next 1.60; 1.60 date 2004.12.03.16.17.54; author rse; state Exp; branches; next 1.59; 1.59 date 2004.07.13.10.50.49; author rse; state Exp; branches; next 1.58; 1.58 date 2003.01.01.15.49.12; author rse; state Exp; branches; next 1.57; 1.57 date 2002.10.24.15.21.14; author rse; state Exp; branches; next 1.56; 1.56 date 2002.01.27.11.03.40; author rse; state Exp; branches; next 1.55; 1.55 date 2001.03.24.14.51.04; author rse; state Exp; branches; next 1.54; 1.54 date 2000.05.28.11.32.28; author rse; state Exp; branches; next 1.53; 1.53 date 2000.03.30.19.05.38; author rse; state Exp; branches; next 1.52; 1.52 date 2000.03.27.17.10.38; author rse; state Exp; branches; next 1.51; 1.51 date 2000.03.23.16.36.11; author rse; state Exp; branches; next 1.50; 1.50 date 2000.01.08.16.26.10; author rse; state Exp; branches 1.50.2.1; next 1.49; 1.49 date 2000.01.07.22.50.21; author rse; state Exp; branches; next 1.48; 1.48 date 2000.01.07.22.49.46; author rse; state Exp; branches; next 1.47; 1.47 date 99.12.30.21.59.00; author rse; state Exp; branches; next 1.46; 1.46 date 99.12.30.21.46.06; author rse; state Exp; branches; next 1.45; 1.45 date 99.12.14.17.32.18; author rse; state Exp; branches; next 1.44; 1.44 date 99.11.09.08.11.31; author rse; state Exp; branches; next 1.43; 1.43 date 99.11.01.10.27.19; author rse; state Exp; branches; next 1.42; 1.42 date 99.10.31.11.46.13; author rse; state Exp; branches 1.42.2.1; next 1.41; 1.41 date 99.09.25.13.06.25; author rse; state Exp; branches; next 1.40; 1.40 date 99.09.17.08.01.55; author rse; state Exp; branches; next 1.39; 1.39 date 99.09.17.06.50.45; author rse; state Exp; branches; next 1.38; 1.38 date 99.09.04.12.32.41; author rse; state Exp; branches; next 1.37; 1.37 date 99.09.01.08.51.24; author rse; state Exp; branches; next 1.36; 1.36 date 99.08.28.11.47.40; author rse; state Exp; branches; next 1.35; 1.35 date 99.08.19.15.08.52; author rse; state Exp; branches; next 1.34; 1.34 date 99.08.18.14.16.30; author rse; state Exp; branches; next 1.33; 1.33 date 99.08.18.11.10.46; author rse; state Exp; branches; next 1.32; 1.32 date 99.08.17.08.15.17; author rse; state Exp; branches; next 1.31; 1.31 date 99.08.07.13.47.50; author rse; state Exp; branches; next 1.30; 1.30 date 99.08.07.12.05.26; author rse; state Exp; branches; next 1.29; 1.29 date 99.07.24.08.22.33; author rse; state Exp; branches 1.29.2.1; next 1.28; 1.28 date 99.07.16.13.53.45; author rse; state Exp; branches; next 1.27; 1.27 date 99.07.16.13.45.20; author rse; state Exp; branches; next 1.26; 1.26 date 99.07.08.10.34.01; author rse; state Exp; branches; next 1.25; 1.25 date 99.07.08.10.30.00; author rse; state Exp; branches; next 1.24; 1.24 date 99.07.08.10.19.11; author rse; state Exp; branches; next 1.23; 1.23 date 99.07.04.12.05.35; author rse; state Exp; branches; next 1.22; 1.22 date 99.06.24.11.50.04; author rse; state Exp; branches; next 1.21; 1.21 date 99.06.12.16.57.30; author rse; state Exp; branches; next 1.20; 1.20 date 99.06.04.21.26.10; author rse; state Exp; branches; next 1.19; 1.19 date 99.06.04.10.47.42; author rse; state Exp; branches; next 1.18; 1.18 date 99.06.02.14.38.45; author rse; state Exp; branches; next 1.17; 1.17 date 99.06.02.14.12.02; author rse; state Exp; branches; next 1.16; 1.16 date 99.06.01.14.02.50; author rse; state Exp; branches; next 1.15; 1.15 date 99.06.01.11.33.39; author rse; state Exp; branches; next 1.14; 1.14 date 99.06.01.11.14.20; author rse; state Exp; branches; next 1.13; 1.13 date 99.06.01.09.55.26; author rse; state Exp; branches; next 1.12; 1.12 date 99.06.01.09.42.57; author rse; state Exp; branches; next 1.11; 1.11 date 99.06.01.09.37.06; author rse; state Exp; branches; next 1.10; 1.10 date 99.06.01.09.21.12; author rse; state Exp; branches; next 1.9; 1.9 date 99.06.01.09.18.19; author rse; state Exp; branches; next 1.8; 1.8 date 99.06.01.08.33.06; author rse; state Exp; branches; next 1.7; 1.7 date 99.05.28.09.05.11; author rse; state Exp; branches; next 1.6; 1.6 date 99.05.24.07.58.13; author rse; state Exp; branches; next 1.5; 1.5 date 99.05.22.15.08.51; author rse; state Exp; branches; next 1.4; 1.4 date 99.05.22.14.37.52; author rse; state Exp; branches; next 1.3; 1.3 date 99.05.22.11.43.45; author rse; state Exp; branches; next 1.2; 1.2 date 99.05.14.09.40.05; author rse; state Exp; branches; next 1.1; 1.1 date 99.05.13.12.18.16; author rse; state Exp; branches 1.1.1.1; next ; 1.50.2.1 date 2000.03.30.19.06.30; author rse; state Exp; branches; next ; 1.42.2.1 date 99.11.01.10.25.00; author rse; state Exp; branches; next 1.42.2.2; 1.42.2.2 date 99.11.24.07.30.09; author rse; state Exp; branches; next ; 1.29.2.1 date 99.08.31.08.30.29; author rse; state Exp; branches; next ; 1.1.1.1 date 99.05.13.12.18.16; author rse; state Exp; branches; next ; desc @@ 1.63 log @Adjusted all copyright messages for new year 2007. @ text @/* ** GNU Pth - The GNU Portable Threads ** Copyright (c) 1999-2007 Ralf S. Engelschall ** ** This file is part of GNU Pth, a non-preemptive thread scheduling ** library which can be found at http://www.gnu.org/software/pth/. ** ** This library is free software; you can redistribute it and/or ** modify it under the terms of the GNU Lesser General Public ** License as published by the Free Software Foundation; either ** version 2.1 of the License, or (at your option) any later version. ** ** This library is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ** Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser General Public ** License along with this library; if not, write to the Free Software ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 ** USA, or contact Ralf S. Engelschall . ** ** pth_mctx.c: Pth machine context handling */ /* ``If you can't do it in ANSI C, it isn't worth doing.'' -- Unknown */ #include "pth_p.h" #if cpp /* * machine context state structure * * In `jb' the CPU registers, the program counter, the stack * pointer and (usually) the signals mask is stored. When the * signal mask cannot be implicitly stored in `jb', it's * alternatively stored explicitly in `sigs'. The `error' stores * the value of `errno'. */ #if PTH_MCTX_MTH(mcsc) #include #endif typedef struct pth_mctx_st pth_mctx_t; struct pth_mctx_st { #if PTH_MCTX_MTH(mcsc) ucontext_t uc; int restored; #elif PTH_MCTX_MTH(sjlj) pth_sigjmpbuf jb; #else #error "unknown mctx method" #endif sigset_t sigs; #if PTH_MCTX_DSP(sjlje) sigset_t block; #endif int error; }; /* ** ____ MACHINE STATE SWITCHING ______________________________________ */ /* * save the current machine context */ #if PTH_MCTX_MTH(mcsc) #define pth_mctx_save(mctx) \ ( (mctx)->error = errno, \ (mctx)->restored = 0, \ getcontext(&(mctx)->uc), \ (mctx)->restored ) #elif PTH_MCTX_MTH(sjlj) && PTH_MCTX_DSP(sjlje) #define pth_mctx_save(mctx) \ ( (mctx)->error = errno, \ pth_sc(sigprocmask)(SIG_SETMASK, &((mctx)->block), NULL), \ pth_sigsetjmp((mctx)->jb) ) #elif PTH_MCTX_MTH(sjlj) #define pth_mctx_save(mctx) \ ( (mctx)->error = errno, \ pth_sigsetjmp((mctx)->jb) ) #else #error "unknown mctx method" #endif /* * restore the current machine context * (at the location of the old context) */ #if PTH_MCTX_MTH(mcsc) #define pth_mctx_restore(mctx) \ ( errno = (mctx)->error, \ (mctx)->restored = 1, \ (void)setcontext(&(mctx)->uc) ) #elif PTH_MCTX_MTH(sjlj) #define pth_mctx_restore(mctx) \ ( errno = (mctx)->error, \ (void)pth_siglongjmp((mctx)->jb, 1) ) #else #error "unknown mctx method" #endif /* * restore the current machine context * (at the location of the new context) */ #if PTH_MCTX_MTH(sjlj) && PTH_MCTX_DSP(sjlje) #define pth_mctx_restored(mctx) \ pth_sc(sigprocmask)(SIG_SETMASK, &((mctx)->sigs), NULL) #else #define pth_mctx_restored(mctx) \ /*nop*/ #endif /* * switch from one machine context to another */ #define SWITCH_DEBUG_LINE \ "==== THREAD CONTEXT SWITCH ===========================================" #ifdef PTH_DEBUG #define _pth_mctx_switch_debug pth_debug(NULL, 0, 1, SWITCH_DEBUG_LINE); #else #define _pth_mctx_switch_debug /*NOP*/ #endif #if PTH_MCTX_MTH(mcsc) #define pth_mctx_switch(old,new) \ _pth_mctx_switch_debug \ swapcontext(&((old)->uc), &((new)->uc)); #elif PTH_MCTX_MTH(sjlj) #define pth_mctx_switch(old,new) \ _pth_mctx_switch_debug \ if (pth_mctx_save(old) == 0) \ pth_mctx_restore(new); \ pth_mctx_restored(old); #else #error "unknown mctx method" #endif #endif /* cpp */ /* ** ____ MACHINE STATE INITIALIZATION ________________________________ */ #if PTH_MCTX_MTH(mcsc) /* * VARIANT 1: THE STANDARDIZED SVR4/SUSv2 APPROACH * * This is the preferred variant, because it uses the standardized * SVR4/SUSv2 makecontext(2) and friends which is a facility intended * for user-space context switching. The thread creation therefore is * straight-foreward. */ intern int pth_mctx_set( pth_mctx_t *mctx, void (*func)(void), char *sk_addr_lo, char *sk_addr_hi) { /* fetch current context */ if (getcontext(&(mctx->uc)) != 0) return FALSE; /* remove parent link */ mctx->uc.uc_link = NULL; /* configure new stack */ mctx->uc.uc_stack.ss_sp = pth_skaddr(makecontext, sk_addr_lo, sk_addr_hi-sk_addr_lo); mctx->uc.uc_stack.ss_size = pth_sksize(makecontext, sk_addr_lo, sk_addr_hi-sk_addr_lo); mctx->uc.uc_stack.ss_flags = 0; /* configure startup function (with no arguments) */ makecontext(&(mctx->uc), func, 0+1); return TRUE; } #elif PTH_MCTX_MTH(sjlj) &&\ !PTH_MCTX_DSP(sjljlx) &&\ !PTH_MCTX_DSP(sjljisc) &&\ !PTH_MCTX_DSP(sjljw32) /* * VARIANT 2: THE SIGNAL STACK TRICK * * This uses sigstack/sigaltstack() and friends and is really the * most tricky part of Pth. When you understand the following * stuff you're a good Unix hacker and then you've already * understood the gory ingredients of Pth. So, either welcome to * the club of hackers, or do yourself a favor and skip this ;) * * The ingenious fact is that this variant runs really on _all_ POSIX * compliant systems without special platform kludges. But be _VERY_ * carefully when you change something in the following code. The slightest * change or reordering can lead to horribly broken code. Really every * function call in the following case is intended to be how it is, doubt * me... * * For more details we strongly recommend you to read the companion * paper ``Portable Multithreading -- The Signal Stack Trick for * User-Space Thread Creation'' from Ralf S. Engelschall. A copy of the * draft of this paper you can find in the file rse-pmt.ps inside the * GNU Pth distribution. */ #if !defined(SA_ONSTACK) && defined(SV_ONSTACK) #define SA_ONSTACK SV_ONSTACK #endif #if !defined(SS_DISABLE) && defined(SA_DISABLE) #define SS_DISABLE SA_DISABLE #endif #if PTH_MCTX_STK(sas) && !defined(HAVE_SS_SP) && defined(HAVE_SS_BASE) #define ss_sp ss_base #endif static volatile jmp_buf mctx_trampoline; static volatile pth_mctx_t mctx_caller; static volatile sig_atomic_t mctx_called; static pth_mctx_t * volatile mctx_creating; static void (* volatile mctx_creating_func)(void); static volatile sigset_t mctx_creating_sigs; static void pth_mctx_set_trampoline(int); static void pth_mctx_set_bootstrap(void); /* initialize a machine state */ intern int pth_mctx_set( pth_mctx_t *mctx, void (*func)(void), char *sk_addr_lo, char *sk_addr_hi) { struct sigaction sa; struct sigaction osa; #if PTH_MCTX_STK(sas) && defined(HAVE_STACK_T) stack_t ss; stack_t oss; #elif PTH_MCTX_STK(sas) struct sigaltstack ss; struct sigaltstack oss; #elif PTH_MCTX_STK(ss) struct sigstack ss; struct sigstack oss; #else #error "unknown mctx stack setup" #endif sigset_t osigs; sigset_t sigs; pth_debug1("pth_mctx_set: enter"); /* * Preserve the SIGUSR1 signal state, block SIGUSR1, * and establish our signal handler. The signal will * later transfer control onto the signal stack. */ sigemptyset(&sigs); sigaddset(&sigs, SIGUSR1); pth_sc(sigprocmask)(SIG_BLOCK, &sigs, &osigs); sa.sa_handler = pth_mctx_set_trampoline; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_ONSTACK; if (sigaction(SIGUSR1, &sa, &osa) != 0) return FALSE; /* * Set the new stack. * * For sigaltstack we're lucky [from sigaltstack(2) on * FreeBSD 3.1]: ``Signal stacks are automatically adjusted * for the direction of stack growth and alignment * requirements'' * * For sigstack we have to decide ourself [from sigstack(2) * on Solaris 2.6]: ``The direction of stack growth is not * indicated in the historical definition of struct sigstack. * The only way to portably establish a stack pointer is for * the application to determine stack growth direction.'' */ #if PTH_MCTX_STK(sas) ss.ss_sp = pth_skaddr(sigaltstack, sk_addr_lo, sk_addr_hi-sk_addr_lo); ss.ss_size = pth_sksize(sigaltstack, sk_addr_lo, sk_addr_hi-sk_addr_lo); ss.ss_flags = 0; if (sigaltstack(&ss, &oss) < 0) return FALSE; #elif PTH_MCTX_STK(ss) ss.ss_sp = pth_skaddr(sigstack, sk_addr_lo, sk_addr_hi-sk_addr_lo); ss.ss_onstack = 0; if (sigstack(&ss, &oss) < 0) return FALSE; #else #error "unknown mctx stack setup" #endif /* * Now transfer control onto the signal stack and set it up. * It will return immediately via "return" after the setjmp() * was performed. Be careful here with race conditions. The * signal can be delivered the first time sigsuspend() is * called. */ mctx_called = FALSE; kill(getpid(), SIGUSR1); sigfillset(&sigs); sigdelset(&sigs, SIGUSR1); while (!mctx_called) sigsuspend(&sigs); /* * Inform the system that we are back off the signal stack by * removing the alternative signal stack. Be careful here: It * first has to be disabled, before it can be removed. */ #if PTH_MCTX_STK(sas) sigaltstack(NULL, &ss); ss.ss_flags = SS_DISABLE; if (sigaltstack(&ss, NULL) < 0) return FALSE; sigaltstack(NULL, &ss); if (!(ss.ss_flags & SS_DISABLE)) return pth_error(FALSE, EIO); if (!(oss.ss_flags & SS_DISABLE)) sigaltstack(&oss, NULL); #elif PTH_MCTX_STK(ss) if (sigstack(&oss, NULL)) return FALSE; #endif /* * Restore the old SIGUSR1 signal handler and mask */ sigaction(SIGUSR1, &osa, NULL); pth_sc(sigprocmask)(SIG_SETMASK, &osigs, NULL); /* * Initialize additional ingredients of the machine * context structure. */ #if PTH_MCTX_DSP(sjlje) sigemptyset(&mctx->block); #endif sigemptyset(&mctx->sigs); mctx->error = 0; /* * Tell the trampoline and bootstrap function where to dump * the new machine context, and what to do afterwards... */ mctx_creating = mctx; mctx_creating_func = func; memcpy((void *)&mctx_creating_sigs, &osigs, sizeof(sigset_t)); /* * Now enter the trampoline again, but this time not as a signal * handler. Instead we jump into it directly. The functionally * redundant ping-pong pointer arithmentic is neccessary to avoid * type-conversion warnings related to the `volatile' qualifier and * the fact that `jmp_buf' usually is an array type. */ if (pth_mctx_save((pth_mctx_t *)&mctx_caller) == 0) longjmp(*((jmp_buf *)&mctx_trampoline), 1); /* * Ok, we returned again, so now we're finished */ pth_debug1("pth_mctx_set: leave"); return TRUE; } /* trampoline signal handler */ static void pth_mctx_set_trampoline(int sig) { /* * Save current machine state and _immediately_ go back with * a standard "return" (to stop the signal handler situation) * to let him remove the stack again. Notice that we really * have do a normal "return" here, or the OS would consider * the thread to be running on a signal stack which isn't * good (for instance it wouldn't allow us to spawn a thread * from within a thread, etc.) * * The functionally redundant ping-pong pointer arithmentic is again * neccessary to avoid type-conversion warnings related to the * `volatile' qualifier and the fact that `jmp_buf' usually is an * array type. * * Additionally notice that we INTENTIONALLY DO NOT USE pth_mctx_save() * here. Instead we use a plain setjmp(3) call because we have to make * sure the alternate signal stack environment is _NOT_ saved into the * machine context (which can be the case for sigsetjmp(3) on some * platforms). */ if (setjmp(*((jmp_buf *)&mctx_trampoline)) == 0) { pth_debug1("pth_mctx_set_trampoline: return to caller"); mctx_called = TRUE; return; } pth_debug1("pth_mctx_set_trampoline: reentered from caller"); /* * Ok, the caller has longjmp'ed back to us, so now prepare * us for the real machine state switching. We have to jump * into another function here to get a new stack context for * the auto variables (which have to be auto-variables * because the start of the thread happens later). Else with * PIC (i.e. Position Independent Code which is used when PTH * is built as a shared library) most platforms would * horrible core dump as experience showed. */ pth_mctx_set_bootstrap(); } /* boot function */ static void pth_mctx_set_bootstrap(void) { pth_mctx_t * volatile mctx_starting; void (* volatile mctx_starting_func)(void); /* * Switch to the final signal mask (inherited from parent) */ pth_sc(sigprocmask)(SIG_SETMASK, (sigset_t *)&mctx_creating_sigs, NULL); /* * Move startup details from static storage to local auto * variables which is necessary because it has to survive in * a local context until the thread is scheduled for real. */ mctx_starting = mctx_creating; mctx_starting_func = mctx_creating_func; /* * Save current machine state (on new stack) and * go back to caller until we're scheduled for real... */ pth_debug1("pth_mctx_set_trampoline_jumpin: switch back to caller"); pth_mctx_switch((pth_mctx_t *)mctx_starting, (pth_mctx_t *)&mctx_caller); /* * The new thread is now running: GREAT! * Now we just invoke its init function.... */ pth_debug1("pth_mctx_set_trampoline_jumpin: reentered from scheduler"); mctx_starting_func(); abort(); } #elif PTH_MCTX_MTH(sjlj) && PTH_MCTX_DSP(sjljlx) /* * VARIANT 3: LINUX SPECIFIC JMP_BUF FIDDLING * * Oh hell, I really love it when Linux guys talk about their "POSIX * compliant system". It's far away from POSIX compliant, IMHO. Autoconf * finds sigstack/sigaltstack() on Linux, yes. But it doesn't work. Why? * Because on Linux below version 2.2 and glibc versions below 2.1 these * two functions are nothing more than silly stub functions which always * return just -1. Very useful, yeah... */ #include intern int pth_mctx_set( pth_mctx_t *mctx, void (*func)(void), char *sk_addr_lo, char *sk_addr_hi) { pth_mctx_save(mctx); #if defined(__GLIBC__) && defined(__GLIBC_MINOR__) \ && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 0 && defined(JB_PC) && defined(JB_SP) mctx->jb[0].__jmpbuf[JB_PC] = (int)func; mctx->jb[0].__jmpbuf[JB_SP] = (int)sk_addr_hi; #elif defined(__GLIBC__) && defined(__GLIBC_MINOR__) \ && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 0 && defined(__mc68000__) mctx->jb[0].__jmpbuf[0].__aregs[0] = (long int)func; mctx->jb[0].__jmpbuf[0].__sp = (int *)sk_addr_hi; #elif defined(__GNU_LIBRARY__) && defined(__i386__) mctx->jb[0].__jmpbuf[0].__pc = (char *)func; mctx->jb[0].__jmpbuf[0].__sp = sk_addr_hi; #else #error "Unsupported Linux (g)libc version and/or platform" #endif sigemptyset(&mctx->sigs); mctx->error = 0; return TRUE; } /* * VARIANT 4: INTERACTIVE SPECIFIC JMP_BUF FIDDLING * * No wonder, Interactive Unix (ISC) 4.x contains Microsoft code, so * it's clear that this beast lacks both sigstack and sigaltstack (about * makecontext we not even have to talk). So our only chance is to * fiddle with it's jmp_buf ingredients, of course. We support only i386 * boxes. */ #elif PTH_MCTX_MTH(sjlj) && PTH_MCTX_DSP(sjljisc) intern int pth_mctx_set(pth_mctx_t *mctx, void (*func)(void), char *sk_addr_lo, char *sk_addr_hi) { pth_mctx_save(mctx); #if i386 mctx->jb[4] = (int)sk_addr_hi - sizeof(mctx->jb); mctx->jb[5] = (int)func; #else #error "Unsupported ISC architecture" #endif sigemptyset(&mctx->sigs); mctx->error = 0; return TRUE; } /* * VARIANT 5: WIN32 SPECIFIC JMP_BUF FIDDLING * * Oh hell, Win32 has setjmp(3), but no sigstack(2) or sigaltstack(2). * So we have to fiddle around with the jmp_buf here too... */ #elif PTH_MCTX_MTH(sjlj) && PTH_MCTX_DSP(sjljw32) intern int pth_mctx_set(pth_mctx_t *mctx, void (*func)(void), char *sk_addr_lo, char *sk_addr_hi) { pth_mctx_save(mctx); #if i386 mctx->jb[7] = (int)sk_addr_hi; mctx->jb[8] = (int)func; #else #error "Unsupported Win32 architecture" #endif sigemptyset(&mctx->sigs); mctx->error = 0; return TRUE; } /* * VARIANT X: JMP_BUF FIDDLING FOR ONE MORE ESOTERIC OS * Add the jmp_buf fiddling for your esoteric OS here... * #elif PTH_MCTX_MTH(sjlj) && PTH_MCTX_DSP(sjljeso) intern int pth_mctx_set(pth_mctx_t *mctx, void (*func)(void), char *sk_addr_lo, char *sk_addr_hi) { pth_mctx_save(mctx); sigemptyset(&mctx->sigs); mctx->error = 0; ...start hacking here... mctx->.... = func; mctx->.... = sk_addr_hi; mctx->.... = sk_addr_lo; return TRUE; } */ #else #error "unknown mctx method" #endif @ 1.62 log @Adjusted all copyright messages for new year 2006 @ text @d3 1 a3 1 ** Copyright (c) 1999-2006 Ralf S. Engelschall @ 1.61 log @Adjusted all copyright messages for new year 2005. @ text @d3 1 a3 1 ** Copyright (c) 1999-2005 Ralf S. Engelschall @ 1.60 log @Enhance internal pth_mctx_save() if getcontext(3) is used for the machine context saving by better emulating the setjmp(3) style semantics. @ text @d3 1 a3 1 ** Copyright (c) 1999-2004 Ralf S. Engelschall @ 1.59 log @Adjusted all copyright messages for new year 2004. @ text @d50 1 d73 3 a75 1 getcontext(&(mctx)->uc) ) d96 1 @ 1.58 log @Adjusted all copyright messages for new year 2003. @ text @d3 1 a3 1 ** Copyright (c) 1999-2003 Ralf S. Engelschall @ 1.57 log @Internally switch from "errno_shield {...}" to "pth_shield {...}" and from "return_errno(..)" to "return pth_error(...)" in order to make the internal error handling a little bit more consistent. @ text @d3 1 a3 1 ** Copyright (c) 1999-2002 Ralf S. Engelschall @ 1.56 log @bump copyright year @ text @d318 1 a318 1 return_errno(FALSE, EIO); @ 1.55 log @*** empty log message *** @ text @d3 1 a3 1 ** Copyright (c) 1999-2001 Ralf S. Engelschall @ 1.54 log @*** empty log message *** @ text @d3 1 a3 1 ** Copyright (c) 1999-2000 Ralf S. Engelschall @ 1.53 log @*** empty log message *** @ text @d500 1 a500 1 mctx->jb[4] = (int)sk_addr_hi; @ 1.52 log @*** empty log message *** @ text @d219 2 a220 2 static volatile pth_mctx_t *mctx_creating; static volatile void (*mctx_creating_func)(void); d346 2 a347 2 mctx_creating = (volatile pth_mctx_t *)mctx; mctx_creating_func = (volatile void (*)(void))func; d413 2 a414 2 volatile pth_mctx_t *mctx_starting; volatile void (*mctx_starting_func)(void); @ 1.51 log @*** empty log message *** @ text @d120 1 a120 1 #define _pth_mctx_switch_debug pth_debug(NULL, 0, SWITCH_DEBUG_LINE); d171 1 a171 1 makecontext(&(mctx->uc), func, 1); @ 1.50 log @*** empty log message *** @ text @d453 3 a455 3 * Because on Linux (for glibc < 2.1) these two functions are nothing * more than silly stub functions which always return just -1. Very * useful, yeah... @ 1.50.2.1 log @*** empty log message *** @ text @d219 2 a220 2 static pth_mctx_t * volatile mctx_creating; static void (* volatile mctx_creating_func)(void); d346 2 a347 2 mctx_creating = mctx; mctx_creating_func = func; d413 2 a414 2 pth_mctx_t * volatile mctx_starting; void (* volatile mctx_starting_func)(void); @ 1.49 log @*** empty log message *** @ text @d119 5 d126 1 a126 1 pth_debug(NULL, 0, SWITCH_DEBUG_LINE); \ d130 1 a130 1 pth_debug(NULL, 0, SWITCH_DEBUG_LINE); \ @ 1.48 log @*** empty log message *** @ text @d117 2 a118 1 #define SWITCH_DEBUG_LINE "==== THREAD CONTEXT SWITCH ===========================================" @ 1.47 log @*** empty log message *** @ text @d117 1 d120 1 a120 1 pth_debug1("pth_mctx_switch"); \ d124 1 a124 1 pth_debug1("pth_mctx_switch"); \ @ 1.46 log @*** empty log message *** @ text @d3 1 a3 1 ** Copyright (c) 1999 Ralf S. Engelschall @ 1.45 log @*** empty log message *** @ text @d169 4 a172 1 #elif PTH_MCTX_MTH(sjlj) && !PTH_MCTX_DSP(sjljlx) && !PTH_MCTX_DSP(sjljisc) d497 24 @ 1.44 log @*** empty log message *** @ text @d200 1 a200 1 #if !defined(HAVE_SS_SP) && defined(HAVE_SS_BASE) @ 1.43 log @*** empty log message *** @ text @d32 1 a32 1 /* d66 1 a66 1 /* d86 1 a86 1 /* d102 2 a103 2 /* * restore the current machine context d114 2 a115 2 /* * switch from one machine context to another d147 1 a147 1 d239 2 a240 2 /* * Preserve the SIGUSR1 signal state, block SIGUSR1, d252 1 a252 1 d260 1 a260 1 * d268 1 a268 1 ss.ss_sp = pth_skaddr(sigaltstack, sk_addr_lo, sk_addr_hi-sk_addr_lo); d274 1 a274 1 ss.ss_sp = pth_skaddr(sigstack, sk_addr_lo, sk_addr_hi-sk_addr_lo); d282 1 a282 1 /* d296 1 a296 1 /* d307 1 a307 1 if (!(ss.ss_flags & SS_DISABLE)) d309 1 a309 1 if (!(oss.ss_flags & SS_DISABLE)) d316 1 a316 1 /* d332 2 a333 2 /* * Tell the trampoline and bootstrap function where to dump d340 1 a340 1 /* d360 1 a360 1 /* d406 1 a406 1 /* d419 2 a420 2 /* * Save current machine state (on new stack) and d426 1 a426 1 /* d504 3 a506 3 #elif PTH_MCTX_MTH(sjlj) && PTH_MCTX_DSP(sjljeso) intern int pth_mctx_set(pth_mctx_t *mctx, void (*func)(void), @ 1.42 log @*** empty log message *** @ text @d2 1 a2 2 ** pth_mctx.c -- Pth machine context handling ** d22 2 @ 1.42.2.1 log @*** empty log message *** @ text @d2 2 a3 1 ** GNU Pth - The GNU Portable Threads a22 2 ** ** pth_mctx.c: Pth machine context handling @ 1.42.2.2 log @*** empty log message *** @ text @d200 1 a200 1 #if PTH_MCTX_STK(sas) && !defined(HAVE_SS_SP) && defined(HAVE_SS_BASE) @ 1.41 log @*** empty log message *** @ text @d12 1 a12 1 ** version 2 of the License, or (at your option) any later version. @ 1.40 log @*** empty log message *** @ text @d337 1 a337 1 mctx_creating_sigs = (volatile sigset_t)osigs; @ 1.39 log @*** empty log message *** @ text @d10 1 a10 1 ** modify it under the terms of the GNU Library General Public d17 1 a17 1 ** Library General Public License for more details. d19 1 a19 1 ** You should have received a copy of the GNU Library General Public @ 1.38 log @*** empty log message *** @ text @d199 1 a199 1 #if defined(SA_DISABLE) @ 1.37 log @*** empty log message *** @ text @d168 1 a168 1 #elif PTH_MCTX_MTH(sjlj) && !PTH_MCTX_DSP(sjljlx) d465 28 a492 1 #error "Unknown Linux (g)libc version and/or platform" @ 1.36 log @*** empty log message *** @ text @a70 1 sigprocmask(SIG_SETMASK, NULL, &((mctx)->sigs)), \ d75 1 a75 1 sigprocmask(SIG_SETMASK, &((mctx)->block), &((mctx)->sigs)), \ a79 1 sigprocmask(SIG_SETMASK, NULL, &((mctx)->sigs)), \ d107 1 a107 1 sigprocmask(SIG_SETMASK, &((mctx)->sigs), NULL) d245 1 a245 2 sigprocmask(SIG_BLOCK, &sigs, &osigs); memset((void *)&sa, 0, sizeof(struct sigaction)); d247 1 a248 1 sigemptyset(&sa.sa_mask); d319 1 a319 1 sigprocmask(SIG_SETMASK, &osigs, NULL); d408 1 a408 1 sigprocmask(SIG_SETMASK, (sigset_t *)&mctx_creating_sigs, NULL); @ 1.35 log @*** empty log message *** @ text @d460 4 @ 1.34 log @*** empty log message *** @ text @d24 3 a26 1 @ 1.33 log @*** empty log message *** @ text @d203 2 a282 8 * Tell startup code on signal stack where to dump * the machine context, and what to do afterwards... */ mctx_creating = (volatile pth_mctx_t *)mctx; mctx_creating_func = (volatile void (*)(void))func; mctx_creating_sigs = (volatile sigset_t)osigs; /* d333 2 a334 3 * Now enter the trampoline again, but * this time not as a signal handler. * Instead we jump into it directly. d336 13 a348 1 pth_mctx_switch((pth_mctx_t *)&mctx_caller, mctx); d368 11 d380 1 a380 1 if (pth_mctx_save((pth_mctx_t *)mctx_creating) == 0) { @ 1.32 log @*** empty log message *** @ text @d310 1 a310 1 if (sigaltstack(&ss, NULL)) @ 1.31 log @*** empty log message *** @ text @d188 3 a190 1 * User-Space Thread Creation'' from Ralf S. Engelschall. @ 1.30 log @*** empty log message *** @ text @d139 6 a144 1 * THE POSIX MAKECONTEXT(2) BASED APPROACH d171 1 a171 1 * VARIANT 1: THE STANDARD d179 10 a188 7 * The ingenious fact is that this variant runs really on _all_ * POSIX compliant systems without special platform kludges. Not * even I've expect this, of course. But be _VERY_ carefully when * you change something in the following code. The slightest * change or reordering can lead to horribly broken code. Really * every function call in the following case is intended to be * how it is, doubt me... d201 1 a201 1 static pth_mctx_t mctx_caller; a202 26 static pth_mctx_t mctx_trampoline; static pth_mctx_t *mctx_creating = NULL; static void (*mctx_creating_func)(void) = NULL; /* trampoline jump-in function */ static void pth_mctx_set_trampoline_jumpin(void) { pth_mctx_t *mctx_starting; void (*mctx_starting_func)(void); /* * Move startup details from static storage to local auto * variables which is necessary because it has to survive in * a local context until the thread is scheduled for real. */ mctx_starting = mctx_creating; mctx_starting_func = mctx_creating_func; mctx_creating = NULL; mctx_creating_func = NULL; /* * Save current machine state (on new stack) and * go back to caller until we're scheduled for real... */ pth_debug1("pth_mctx_set_trampoline_jumpin: switch back to caller"); pth_mctx_switch(mctx_starting, &mctx_caller); d204 3 a206 8 /* * The new thread is now running: GREAT! * Now we just invoke its init function.... */ pth_debug1("pth_mctx_set_trampoline_jumpin: reentered from scheduler"); mctx_starting_func(); abort(); } d208 2 a209 42 /* trampoline signal handler */ static void pth_mctx_set_trampoline(int sig) { sigset_t sigs; /* * Unblock the SIGUSR1 signal that got us here because we've * to avoid that it's stored in blocked state in the machine * context. */ sigemptyset(&sigs); sigaddset(&sigs, SIGUSR1); sigprocmask(SIG_UNBLOCK, &sigs, NULL); /* * Save current machine state and _immediately_ go back with * a standard "return" (to stop the signal handler situation) * to let him remove the stack again. Notice that we really * have do a normal "return" here, or the OS would consider * the thread to be running on a signal stack which isn't * good (for instance it wouldn't allow us to spawn a thread * from within a thread, etc.) */ if (pth_mctx_save(&mctx_trampoline) == 0) { pth_debug1("pth_mctx_set_trampoline: return to caller"); mctx_called = TRUE; return; } pth_debug1("pth_mctx_set_trampoline: reentered from caller"); /* * Ok, the caller has longjmp'ed back to us, so now prepare * us for the real machine state switching. We have to jump * into another function here to get a new stack context for * the auto variables (which have to be auto-variables * because the start of the thread happens later). Else with * PIC (i.e. Position Independent Code which is used when PTH * is built as a shared library) most platforms would * horrible core dump as experience showed. */ pth_mctx_set_trampoline_jumpin(); } d219 1 d222 1 d225 1 d237 1 a237 1 * transfer control onto the signal stack. d267 1 a267 1 if (sigaltstack(&ss, NULL) < 0) d272 1 a272 1 if (sigstack(&ss, NULL) < 0) d282 3 a284 2 mctx_creating = mctx; mctx_creating_func = func; d313 2 d316 1 a316 1 if (sigstack(&ss, NULL)) d341 1 a341 1 pth_mctx_switch(&mctx_caller, &mctx_trampoline); d350 67 d420 1 a420 1 * VARIANT 2: LINUX SPECIFIC JMP_BUF FIDDLING d422 6 a427 6 * Oh hell, I really love it when Linux guys talk about their * "POSIX compliant system". It's far away from POSIX compliant, * IMHO. Autoconf finds sigstack/sigaltstack() on Linux, yes. * But it doesn't work. Why? Because on Linux (even with glibc * 2.1!) these two functions are nothing more than silly stub * functions which always return just -1. Very useful, yeah... a445 3 #if defined(PTH_EMULATE_SIGSETJMP) sigemptyset(&mctx->block); #endif a460 3 #if PTH_MCTX_DSP(sjlje) sigemptyset(&mctx->block); #endif @ 1.29 log @*** empty log message *** @ text @d38 5 d45 7 a51 1 pth_sigjmp_buf jb; d53 1 a53 1 #if defined(PTH_EMULATE_SIGSETJMP) d66 6 a71 1 #if defined(PTH_EMULATE_SIGSETJMP) d76 1 a76 1 #else d81 2 d89 5 d97 3 d105 1 a105 1 #if defined(PTH_EMULATE_SIGSETJMP) d116 5 d126 3 d136 28 a163 1 #if defined(PTH_MCTXSET_SIGSTACK) d280 1 a280 2 #if defined(HAVE_SIGALTSTACK) #if defined(HAVE_STACK_T) d282 1 a282 1 #else d284 1 a284 2 #endif #elif defined(HAVE_SIGSTACK) d286 2 d323 3 a325 3 #if defined(HAVE_SIGALTSTACK) ss.ss_sp = sk_addr_lo; ss.ss_size = sk_addr_hi - sk_addr_lo; d329 2 a330 2 #elif defined(HAVE_SIGSTACK) ss.ss_sp = (PTH_STACKSGROWDOWN ? sk_addr_hi : sk_addr_lo); d334 2 d364 1 a364 1 #if defined(HAVE_SIGALTSTACK) d372 1 a372 1 #elif defined(HAVE_SIGSTACK) d387 1 a387 1 #if defined(PTH_EMULATE_SIGSETJMP) d407 1 a407 1 #elif defined(PTH_MCTXSET_LINUX) d448 1 a448 1 #elif defined(PTH_MCTX_ESOTERIC) d454 1 a454 1 #if defined(PTH_EMULATE_SIGSETJMP) d467 2 @ 1.29.2.1 log @*** empty log message *** @ text @a221 1 stack_t oss; a223 1 struct sigaltstack oss; a226 1 struct sigstack oss; d266 1 a266 1 if (sigaltstack(&ss, &oss) < 0) d271 1 a271 1 if (sigstack(&ss, &oss) < 0) a308 1 sigaltstack(&oss, NULL); d310 1 a310 1 if (sigstack(&oss, NULL)) @ 1.28 log @*** empty log message *** @ text @d269 1 a269 1 ss.ss_sp = (PTH_STACKSGROWDOWN ? stack_hi_addr : stack_lo_addr); @ 1.27 log @*** empty log message *** @ text @d57 3 a59 3 ((mctx)->error = errno, \ sigprocmask(SIG_SETMASK, &((mctx)->block), &((mctx)->sigs)), \ pth_sigsetjmp((mctx)->jb)) d62 3 a64 3 ((mctx)->error = errno, \ sigprocmask(SIG_SETMASK, NULL, &((mctx)->sigs)), \ pth_sigsetjmp((mctx)->jb)) d72 2 a73 2 (errno = (mctx)->error, \ pth_siglongjmp((mctx)->jb, 1)) @ 1.26 log @*** empty log message *** @ text @d158 1 a158 1 pth_debug1("pth_mctx_set_trampoline: switch back to caller"); d165 1 a165 1 pth_debug1("pth_mctx_set_trampoline: reentered from scheduler"); @ 1.25 log @*** empty log message *** @ text @d2 1 a2 1 ** pth_mctx.c -- PTH machine context handling @ 1.24 log @*** empty log message *** @ text @d32 5 a36 5 * In "jb" the CPU registers, the program counter, the stack * pointer and (usually) the signals mask is stored. When the * signal mask cannot be implicitly stored in "jb", it's * alternatively stored explicitly in "sigs". The "error" stores * the value of "errno". d108 1 a108 1 * most tricky part of PTH. When you understand the following d110 1 a110 1 * understood the gory ingredients of PTH. So, either welcome to @ 1.23 log @*** empty log message *** @ text @d6 2 a7 2 ** This file is part of PTH, a non-preemptive thread scheduling library ** which can be found at http://www.gnu.org/software/pth/. @ 1.22 log @*** empty log message *** @ text @d7 1 a7 1 ** which can be found at http://www.engelschall.com/sw/pth/. @ 1.21 log @*** empty log message *** @ text @d214 1 a214 1 intern void pth_mctx_set( d245 2 a246 4 if (sigaction(SIGUSR1, &sa, &osa) != 0) { perror("sigaction"); abort(); } d266 2 a267 4 if (sigaltstack(&ss, NULL) < 0) { perror("sigaltstack"); abort(); } d271 2 a272 4 if (sigstack(&ss, NULL) < 0) { perror("sigstack"); abort(); } d304 2 a305 4 if (sigaltstack(&ss, NULL)) { perror("sigaltstack"); abort(); } d307 2 a308 4 if (!(ss.ss_flags & SS_DISABLE)) { fprintf(stderr, "SS_DISABLE not applied\n"); abort(); } d310 2 a311 4 if (sigstack(&ss, NULL)) { perror("sigstack"); abort(); } d341 1 a341 1 return; d350 1 a350 1 * "POSIX compliant system". It's fair away from POSIX compliant, d359 1 a359 1 intern void pth_mctx_set( d378 1 a378 1 return; d386 1 a386 1 intern void d400 1 a400 1 return; @ 1.20 log @*** empty log message *** @ text @d393 23 @ 1.19 log @*** empty log message *** @ text @d380 2 a381 2 mctx->jb->__pc = (char *)func; mctx->jb->__sp = sk_addr_hi; @ 1.18 log @*** empty log message *** @ text @d41 1 a43 1 sigset_t sigs; d63 1 d297 2 a298 1 sigemptyset(&sigs); d338 1 a339 1 #endif d387 1 a388 1 #endif @ 1.17 log @*** empty log message *** @ text @d58 1 a58 1 sigprocmask(0, &((mctx)->block), &((mctx)->sigs)), \ @ 1.16 log @*** empty log message *** @ text @d42 1 d58 1 a58 1 sigprocmask(0, NULL, &((mctx)->sigs)), \ d335 1 d384 1 @ 1.15 log @*** empty log message *** @ text @d29 9 a37 1 /* machine context states */ d47 7 a53 1 /* save the current machine context */ d65 4 a68 1 /* restore the current machine context (at old context) */ d73 4 a76 1 /* restore the current machine context (at new context) */ d85 3 a87 1 /* switch from one machine context to another */ d96 4 d104 14 a117 4 * This uses sigstack/sigaltstack and friends and is really the most tricky * part of PTH. When you understand the following stuff you're a good Unix * hacker and then you've already understood the gory ingredients of PTH. * So, either welcome to the club, or do yourself a favor and skip this ;) d356 7 a362 1 * This fiddles around in a jmp_buf for Linux d379 1 a379 1 #error "Unknown Linux libc version and/or platform" @ 1.14 log @*** empty log message *** @ text @d78 4 a81 1 * This uses sigstack or sigaltstack d101 1 a101 1 static void pth_mctx_set_trampoline_jump(void) d106 5 d117 1 a117 1 * Save current machine state (on new stack), d124 2 a125 1 * New thread is now running; invoke its init function d138 3 a140 3 * Unblock the SIGUSR1 signal that got us here * because we've to avoid that it's stored in blocked state * in the machine context. d147 7 a153 3 * Save current machine state and _immediately_ go back with a standard * "return" (to stop the signal handler situation) to let him remove the * stack again d164 7 a170 4 * us for the real machine state. We have to jump into * another function to get a new contect for the auto * variables. Else with Position Independent Code (PIC) most * platforms core would core dump. d172 1 a172 1 pth_mctx_set_trampoline_jump(); d194 1 a194 1 d196 3 a198 1 * Preserve the SIGUSR1 signal state and block it for now d203 9 a211 1 d213 12 a224 1 * Set the new stack a226 5 /* * For sigaltstack we're lucky [from sigaltstack(2) on FreeBSD 3.1]: * ``Signal stacks are automatically adjusted for the direction * of stack growth and alignment requirements'' */ a234 7 /* * For sigstack we have to decide ourself [from sigstack(2) on Solaris 2.6]: * ``The direction of stack growth is not indicated in the historical * definition of struct sigstack. The only way to portably establish a * stack pointer is for the application to determine stack growth * direction.'' */ a243 13 * Arrange for SIGUSR1 to transfer onto signal stack * (keep in mind that SIGUSR1 is still blocked) */ memset((void *)&sa, 0, sizeof(struct sigaction)); sa.sa_handler = pth_mctx_set_trampoline; sa.sa_flags = SA_ONSTACK; sigemptyset(&sa.sa_mask); if (sigaction(SIGUSR1, &sa, &osa) != 0) { perror("sigaction"); abort(); } /* d251 5 a255 2 * Transfer control onto signal stack and set it up. * It will return immediately. d264 3 a266 7 * Restore SIGUSR1 signal handler and mask */ sigaction(SIGUSR1, &osa, NULL); sigprocmask(SIG_SETMASK, &osigs, NULL); /* * Inform the system that we are back off the signal stack d288 1 a288 3 * Now enter the trampoline again, but * this time not as a signal handler. * Instead we jump into it directly. d290 2 a291 1 pth_mctx_switch(&mctx_caller, &mctx_trampoline); d294 2 a295 1 * Finally initialize more ingredients of the machine context d301 7 @ 1.13 log @*** empty log message *** @ text @d97 27 a123 1 /* signal handler */ d150 5 a154 2 * Ok, the caller has longjmp'ed back to us, so * now prepare us for the real machine state d156 1 a156 23 { pth_mctx_t *mctx_starting; void (*mctx_starting_func)(void); mctx_starting = mctx_creating; mctx_starting_func = mctx_creating_func; mctx_creating = NULL; mctx_creating_func = NULL; /* * Save current machine state (on new stack), * go back to caller until we're scheduled for real... */ pth_debug1("pth_mctx_set_trampoline: switch back to caller"); pth_mctx_switch(mctx_starting, &mctx_caller); /* * New thread is now running; invoke its init function */ pth_debug1("pth_mctx_set_trampoline: reentered from scheduler"); mctx_starting_func(); abort(); } @ 1.12 log @*** empty log message *** @ text @d20 1 a20 1 ** License along with this library; if not, write to the Free @ 1.11 log @*** empty log message *** @ text @d277 8 d314 4 @ 1.10 log @*** empty log message *** @ text @d104 2 d157 1 d167 2 d171 8 d213 1 d219 1 a219 1 if (sigaction(SIGUSR1, &sa, NULL) != 0) { d237 1 d239 7 a245 5 pth_time_usleep(1000); memset((void *)&sa, 0, sizeof(struct sigaction)); sa.sa_handler = SIG_IGN; sigemptyset(&sa.sa_mask); sigaction(SIGUSR1, &sa, NULL); @ 1.9 log @*** empty log message *** @ text @d59 1 a59 1 sigprocmask(SIG_SETMASK, &((mctx)->sigs), NULL), \ d91 5 a95 5 static pth_mctx_t mctx_caller; static int mctx_called; static pth_mctx_t mctx_trampoline; static pth_mctx_t *mctx_creating = NULL; static void (*mctx_creating_func)(void) = NULL; @ 1.8 log @*** empty log message *** @ text @d32 4 a35 1 jmp_buf jb; d40 1 a40 1 #if defined(HAVE__SETJMP) && defined(HAVE__LONGJMP) d42 3 a44 1 ((mctx)->error = errno, _setjmp((mctx)->jb)) d47 2 a48 1 ((mctx)->error = errno, setjmp((mctx)->jb)) d51 1 a51 2 /* restore the current machine context */ #if defined(HAVE__SETJMP) && defined(HAVE__LONGJMP) d53 7 a59 1 (errno = (mctx)->error, _longjmp((mctx)->jb, 1)) d61 2 a62 2 #define pth_mctx_restore(mctx) \ (errno = (mctx)->error, longjmp((mctx)->jb, 1)) d69 2 a70 1 pth_mctx_restore(new); @ 1.7 log @*** empty log message *** @ text @d88 2 a92 1 sigset_t sigs; @ 1.6 log @*** empty log message *** @ text @d27 35 d138 1 a138 1 void pth_mctx_set( d262 1 a262 1 void pth_mctx_set( @ 1.5 log @*** empty log message *** @ text @d6 1 a6 1 ** This file is part of PTH, a non-preemtive thread scheduling library @ 1.4 log @*** empty log message *** @ text @a24 11 /* * Machine Context Handling * (per-thread stack handling and context switching) * * This is the only really portability related stuff of PTH. * The exercise is write a pth_mctx_set() function which * initializes a jmp_buf with a given function and a stack, so * when one longjmp's to it the function starts executing on the * given stack. */ @ 1.3 log @*** empty log message *** @ text @a0 40 /* ==================================================================== * Copyright (c) 1999 Ralf S. Engelschall. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. All advertising materials mentioning features or use of this * software must display the following acknowledgment: * "This product includes software developed by * Ralf S. Engelschall ." * * 4. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by * Ralf S. Engelschall ." * * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RALF S. ENGELSCHALL OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== */ d2 21 a22 2 ** Non-Preemtive Scheduler Library (PTH) ** pth_mctx.c -- machine context code d29 5 a33 4 * This is the most complicated and unportable stuff of PTH. The exercise is * write a pth_mctx_set() function which initializes a jmp_buf with a given * function and a stack, so when one longjmp's to it the function starts * executing on the given stack. @ 1.2 log @*** empty log message *** @ text @d153 6 a158 1 ss.ss_sp = sk_addr_lo; d166 8 a173 1 ss.ss_sp = stack_hi_addr; @ 1.1 log @Initial revision @ text @d195 1 a195 1 pth_usleep(1000); @ 1.1.1.1 log @Import of PTH into CVS @ text @@