📄 pth_mctx.c
字号:
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 <features.h>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 intpth_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 intpth_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 intpth_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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -