diff options
Diffstat (limited to 'arch/um/os-Linux/skas/process.c')
-rw-r--r-- | arch/um/os-Linux/skas/process.c | 92 |
1 files changed, 35 insertions, 57 deletions
diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c index 7baf90fda58b..cb9ab54146cc 100644 --- a/arch/um/os-Linux/skas/process.c +++ b/arch/um/os-Linux/skas/process.c @@ -8,7 +8,6 @@ #include <unistd.h> #include <errno.h> #include <signal.h> -#include <setjmp.h> #include <sched.h> #include "ptrace_user.h" #include <sys/wait.h> @@ -156,11 +155,15 @@ extern int __syscall_stub_start; static int userspace_tramp(void *stack) { void *addr; + int err; ptrace(PTRACE_TRACEME, 0, 0, 0); init_new_thread_signals(); - enable_timer(); + err = set_interval(1); + if(err) + panic("userspace_tramp - setting timer failed, errno = %d\n", + err); if(!proc_mm){ /* This has a pte, but it can't be mapped in with the usual @@ -190,14 +193,25 @@ static int userspace_tramp(void *stack) } } if(!ptrace_faultinfo && (stack != NULL)){ + struct sigaction sa; + unsigned long v = UML_CONFIG_STUB_CODE + (unsigned long) stub_segv_handler - (unsigned long) &__syscall_stub_start; set_sigstack((void *) UML_CONFIG_STUB_DATA, page_size()); - set_handler(SIGSEGV, (void *) v, SA_ONSTACK, - SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, - SIGUSR1, -1); + sigemptyset(&sa.sa_mask); + sigaddset(&sa.sa_mask, SIGIO); + sigaddset(&sa.sa_mask, SIGWINCH); + sigaddset(&sa.sa_mask, SIGALRM); + sigaddset(&sa.sa_mask, SIGVTALRM); + sigaddset(&sa.sa_mask, SIGUSR1); + sa.sa_flags = SA_ONSTACK; + sa.sa_handler = (void *) v; + sa.sa_restorer = NULL; + if(sigaction(SIGSEGV, &sa, NULL) < 0) + panic("userspace_tramp - setting SIGSEGV handler " + "failed - errno = %d\n", errno); } os_stop_process(os_getpid()); @@ -430,56 +444,22 @@ void map_stub_pages(int fd, unsigned long code, } } -void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr, - void (*handler)(int)) +void new_thread(void *stack, jmp_buf *buf, void (*handler)(void)) { - unsigned long flags; - jmp_buf switch_buf, fork_buf; - - *switch_buf_ptr = &switch_buf; - *fork_buf_ptr = &fork_buf; - - /* Somewhat subtle - siglongjmp restores the signal mask before doing - * the longjmp. This means that when jumping from one stack to another - * when the target stack has interrupts enabled, an interrupt may occur - * on the source stack. This is bad when starting up a process because - * it's not supposed to get timer ticks until it has been scheduled. - * So, we disable interrupts around the sigsetjmp to ensure that - * they can't happen until we get back here where they are safe. - */ - flags = get_signals(); - block_signals(); - if(UML_SETJMP(&fork_buf) == 0) - new_thread_proc(stack, handler); - - remove_sigstack(); - - set_signals(flags); + (*buf)[0].JB_IP = (unsigned long) handler; + (*buf)[0].JB_SP = (unsigned long) stack + + (PAGE_SIZE << UML_CONFIG_KERNEL_STACK_ORDER) - sizeof(void *); } #define INIT_JMP_NEW_THREAD 0 -#define INIT_JMP_REMOVE_SIGSTACK 1 -#define INIT_JMP_CALLBACK 2 -#define INIT_JMP_HALT 3 -#define INIT_JMP_REBOOT 4 +#define INIT_JMP_CALLBACK 1 +#define INIT_JMP_HALT 2 +#define INIT_JMP_REBOOT 3 -void thread_wait(void *sw, void *fb) +void switch_threads(jmp_buf *me, jmp_buf *you) { - jmp_buf buf, **switch_buf = sw, *fork_buf; - - *switch_buf = &buf; - fork_buf = fb; - if(UML_SETJMP(&buf) == 0) - siglongjmp(*fork_buf, INIT_JMP_REMOVE_SIGSTACK); -} - -void switch_threads(void *me, void *next) -{ - jmp_buf my_buf, **me_ptr = me, *next_buf = next; - - *me_ptr = &my_buf; - if(UML_SETJMP(&my_buf) == 0) - UML_LONGJMP(next_buf, 1); + if(UML_SETJMP(me) == 0) + UML_LONGJMP(you, 1); } static jmp_buf initial_jmpbuf; @@ -489,23 +469,21 @@ static void (*cb_proc)(void *arg); static void *cb_arg; static jmp_buf *cb_back; -int start_idle_thread(void *stack, void *switch_buf_ptr, void **fork_buf_ptr) +int start_idle_thread(void *stack, jmp_buf *switch_buf) { - jmp_buf **switch_buf = switch_buf_ptr; int n; set_handler(SIGWINCH, (__sighandler_t) sig_handler, SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGALRM, SIGVTALRM, -1); - *fork_buf_ptr = &initial_jmpbuf; n = UML_SETJMP(&initial_jmpbuf); switch(n){ case INIT_JMP_NEW_THREAD: - new_thread_proc((void *) stack, new_thread_handler); - break; - case INIT_JMP_REMOVE_SIGSTACK: - remove_sigstack(); + (*switch_buf)[0].JB_IP = (unsigned long) new_thread_handler; + (*switch_buf)[0].JB_SP = (unsigned long) stack + + (PAGE_SIZE << UML_CONFIG_KERNEL_STACK_ORDER) - + sizeof(void *); break; case INIT_JMP_CALLBACK: (*cb_proc)(cb_arg); @@ -520,7 +498,7 @@ int start_idle_thread(void *stack, void *switch_buf_ptr, void **fork_buf_ptr) default: panic("Bad sigsetjmp return in start_idle_thread - %d\n", n); } - UML_LONGJMP(*switch_buf, 1); + UML_LONGJMP(switch_buf, 1); } void initial_thread_cb_skas(void (*proc)(void *), void *arg) |