/** Thread used to bring up userspace thread. * * @param arg Pointer to structure containing userspace entry and stack * addresses. */ void uinit(void *arg) { /* * So far, we don't have a use for joining userspace threads so we * immediately detach each uinit thread. If joining of userspace threads * is required, some userspace API based on the kernel mechanism will * have to be implemented. Moreover, garbage collecting of threads that * didn't detach themselves and nobody else joined them will have to be * deployed for the event of forceful task termination. */ thread_detach(THREAD); #ifdef CONFIG_UDEBUG udebug_stoppable_end(); #endif uspace_arg_t *uarg = (uspace_arg_t *) arg; uspace_arg_t local_uarg; local_uarg.uspace_entry = uarg->uspace_entry; local_uarg.uspace_stack = uarg->uspace_stack; local_uarg.uspace_stack_size = uarg->uspace_stack_size; local_uarg.uspace_uarg = uarg->uspace_uarg; local_uarg.uspace_thread_function = NULL; local_uarg.uspace_thread_arg = NULL; free(uarg); userspace(&local_uarg); }
void new_thread_handler(int sig) { int (*fn)(void *), n; void *arg; fn = current->thread.request.u.thread.proc; arg = current->thread.request.u.thread.arg; change_sig(SIGUSR1, 1); thread_wait(¤t->thread.mode.skas.switch_buf, current->thread.mode.skas.fork_buf); if(current->thread.prev_sched != NULL) schedule_tail(current->thread.prev_sched); current->thread.prev_sched = NULL; /* The return value is 1 if the kernel thread execs a process, * 0 if it just exits */ n = run_kernel_thread(fn, arg, ¤t->thread.exec_buf); if(n == 1){ /* Handle any immediate reschedules or signals */ interrupt_end(); userspace(¤t->thread.regs.regs); } else do_exit(0); }
/** * The hook called before 'do_execve' successfully return. * What we need to do here are: * 1. create a new host container if the process doesn't have one yet; * 2. create the stack for syscall stub; * 3. unmap umUcore kernel area in the child and erasing the info in the page table; * 4. copy arguments to the user stack of the child, and free the kernel's copy; * 5. call 'userspace'. * If everything is done, the current thread becomes a monitor thread forever. * @param argc the number of arguments * @param kargv the copy of the arguments in the kernel */ int do_execve_arch_hook(int argc, char **kargv) { if (current->arch.host == NULL) { current->arch.host = kmalloc(sizeof(struct host_container)); if (current->arch.host == NULL) return -1; } void *stub_stack = boot_alloc_page(); if (stub_stack == NULL) goto free_host; int ret = start_userspace(stub_stack); if (ret <= 0) goto free_stub_stack; current->arch.host->stub_stack = stub_stack; current->arch.host->host_pid = ret; current->arch.host->nr_threads = 1; /* unmap kernel area */ if (host_munmap(current, (void *)KERNBASE, KERNTOP - KERNBASE) < 0) panic("unmap kernel area failed\n"); /* erase kernel maps in the page table */ int valid_size = KERNBASE / PTSIZE * sizeof(pte_t); memset((void *)((int)(current->mm->pgdir) + valid_size), 0, PGSIZE - valid_size); /* Copy arguments */ current->arch.regs.is_user = 1; uintptr_t stacktop = USTACKTOP - argc * PGSIZE; char **uargv = (char **)(stacktop - argc * sizeof(char *)); int i, addr; for (i = 0; i < argc; i++) { addr = stacktop + i * PGSIZE; assert(copy_to_user (current->mm, uargv + i, &addr, sizeof(int))); assert(copy_to_user (current->mm, (void *)addr, kargv[i], strlen(kargv[i]) + 1)); } stacktop = (uintptr_t) uargv - sizeof(int); copy_to_user(current->mm, (void *)stacktop, &argc, sizeof(int)); /* The copy of the args in the kernel will never be used again and we will not return, * so free them here. */ while (argc > 0) { kfree(kargv[--argc]); } userspace(&(current->arch.regs)); /* should never comes here */ free_stub_stack: free_page(kva2page(stub_stack)); free_host: kfree(current->arch.host); current->arch.host = NULL; return -1; }
void fork_handler(int sig) { change_sig(SIGUSR1, 1); thread_wait(¤t->thread.mode.skas.switch_buf, current->thread.mode.skas.fork_buf); force_flush_all(); if(current->thread.prev_sched == NULL) panic("blech"); schedule_tail(current->thread.prev_sched); current->thread.prev_sched = NULL; userspace(¤t->thread.regs.regs); }
void fork_handler(int sig) { change_sig(SIGUSR1, 1); thread_wait(¤t->thread.mode.skas.switch_buf, current->thread.mode.skas.fork_buf); force_flush_all(); if(current->thread.prev_sched == NULL) panic("blech"); schedule_tail(current->thread.prev_sched); current->thread.prev_sched = NULL; /* Handle any immediate reschedules or signals */ interrupt_end(); userspace(¤t->thread.regs.regs); }
/* Called magically, see new_thread_handler above */ void fork_handler(void) { force_flush_all(); if(current->thread.prev_sched == NULL) panic("blech"); schedule_tail(current->thread.prev_sched); /* XXX: if interrupt_end() calls schedule, this call to * arch_switch_to_skas isn't needed. We could want to apply this to * improve performance. -bb */ arch_switch_to_skas(current->thread.prev_sched, current); current->thread.prev_sched = NULL; /* Handle any immediate reschedules or signals */ interrupt_end(); userspace(¤t->thread.regs.regs); }