diff options
Diffstat (limited to 'sys/kern/kern_spawn.c')
-rw-r--r-- | sys/kern/kern_spawn.c | 151 |
1 files changed, 115 insertions, 36 deletions
diff --git a/sys/kern/kern_spawn.c b/sys/kern/kern_spawn.c index cb898dc..7962ced 100644 --- a/sys/kern/kern_spawn.c +++ b/sys/kern/kern_spawn.c @@ -27,6 +27,8 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#include <sys/spawn.h> +#include <sys/wait.h> #include <sys/proc.h> #include <sys/exec.h> #include <sys/mman.h> @@ -34,7 +36,6 @@ #include <sys/errno.h> #include <sys/syslog.h> #include <sys/syscall.h> -#include <sys/atomic.h> #include <sys/signal.h> #include <sys/limits.h> #include <sys/sched.h> @@ -44,10 +45,17 @@ #define pr_trace(fmt, ...) kprintf("spawn: " fmt, ##__VA_ARGS__) #define pr_error(...) pr_trace(__VA_ARGS__) -static volatile size_t nthreads = 0; +#define ARGVP_MAX (ARG_MAX / sizeof(void *)) +static size_t next_pid = 1; + +/* + * TODO: envp + */ struct spawn_args { char path[PATH_MAX]; + char argv_blk[ARG_MAX]; + char *argv[ARGVP_MAX]; }; static inline void @@ -66,29 +74,55 @@ spawn_thunk(void) struct proc *cur; struct execve_args execve_args; struct spawn_args *args; - char *argv[] = { NULL, NULL }; char *envp[] = { NULL }; cur = this_td(); - args = cur->spawn_data; + args = cur->data; path = args->path; + memset(pathbuf, 0, sizeof(pathbuf)); memcpy(pathbuf, path, strlen(path)); - argv[0] = (char *)pathbuf; - execve_args.pathname = argv[0]; - execve_args.argv = argv; + execve_args.pathname = pathbuf; + execve_args.argv = (char **)&args->argv[0]; execve_args.envp = envp; - path = NULL; - dynfree(args); if (execve(cur, &execve_args) != 0) { pr_error("execve failed, aborting\n"); - exit1(this_td()); + exit1(this_td(), 0); } __builtin_unreachable(); } +pid_t +waitpid(pid_t pid, int *wstatus, int options) +{ + struct proc *child, *td; + pid_t ret; + + td = this_td(); + child = get_child(td, pid); + + if (child == NULL) { + return -1; + } + + /* Wait for it to be done */ + while (!ISSET(child->flags, PROC_ZOMB)) { + sched_yield(); + } + + + /* Give back the status */ + if (wstatus != NULL) { + copyout(&child->exit_status, wstatus, sizeof(*wstatus)); + } + + ret = child->pid; + proc_reap(child); + return ret; +} + /* * Spawn a new process * @@ -108,8 +142,8 @@ pid_t spawn(struct proc *cur, void(*func)(void), void *p, int flags, struct proc **newprocp) { struct proc *newproc; - struct mmap_lgdr *mlgdr; int error; + pid_t pid; newproc = dynalloc(sizeof(*newproc)); if (newproc == NULL) { @@ -118,19 +152,10 @@ spawn(struct proc *cur, void(*func)(void), void *p, int flags, struct proc **new return -ENOMEM; } - mlgdr = dynalloc(sizeof(*mlgdr)); - if (mlgdr == NULL) { - dynfree(newproc); - try_free_data(p); - pr_error("could not alloc proc mlgdr (-ENOMEM)\n"); - return -ENOMEM; - } - memset(newproc, 0, sizeof(*newproc)); error = md_spawn(newproc, cur, (uintptr_t)func); if (error < 0) { dynfree(newproc); - dynfree(mlgdr); try_free_data(p); pr_error("error initializing proc\n"); return error; @@ -146,21 +171,19 @@ spawn(struct proc *cur, void(*func)(void), void *p, int flags, struct proc **new cur->flags |= PROC_LEAFQ; } - /* Add to parent leafq */ - TAILQ_INSERT_TAIL(&cur->leafq, newproc, leaf_link); - atomic_inc_int(&cur->nleaves); - newproc->parent = cur; - newproc->spawn_data = p; - - /* Initialize the mmap ledger */ - mlgdr->nbytes = 0; - RBT_INIT(lgdr_entries, &mlgdr->hd); - newproc->mlgdr = mlgdr; + error = proc_init(newproc, cur); + if (error < 0) { + dynfree(newproc); + try_free_data(p); + pr_error("error initializing proc\n"); + return error; + } - newproc->pid = ++nthreads; - signals_init(newproc); + newproc->data = p; + newproc->pid = next_pid++; sched_enqueue_td(newproc); - return newproc->pid; + pid = newproc->pid; + return pid; } /* @@ -177,6 +200,9 @@ get_child(struct proc *cur, pid_t pid) struct proc *procp; TAILQ_FOREACH(procp, &cur->leafq, leaf_link) { + if (procp == NULL) { + continue; + } if (procp->pid == pid) { return procp; } @@ -186,20 +212,48 @@ get_child(struct proc *cur, pid_t pid) } /* + * arg0: PID + * arg1: wstatus + * arg2: options + * + * Returns PID of terminated child, returns + * -1 on failure. + */ +scret_t +sys_waitpid(struct syscall_args *scargs) +{ + pid_t pid; + int *u_wstatus; + int options; + + pid = scargs->arg0; + u_wstatus = (void *)scargs->arg1; + options = scargs->arg2; + return waitpid(pid, u_wstatus, options); +} + +/* * arg0: The file /path/to/executable - * arg1: Optional flags (`flags') + * arg1: Argv + * arg2: Envp (TODO) + * arg3: Optional flags (`flags') */ scret_t sys_spawn(struct syscall_args *scargs) { struct spawn_args *args; - const char *u_path; + char *path; + const char *u_path, **u_argv; + const char *u_p = NULL; struct proc *td; int flags, error; + size_t len, bytes_copied = 0; + size_t argv_i = 0; td = this_td(); - flags = scargs->arg1; u_path = (const char *)scargs->arg0; + u_argv = (const char **)scargs->arg1; + flags = scargs->arg3; args = dynalloc(sizeof(*args)); if (args == NULL) { @@ -212,5 +266,30 @@ sys_spawn(struct syscall_args *scargs) return error; } + memset(args->argv, 0, ARG_MAX); + for (size_t i = 0; i < ARG_MAX - 1; ++i) { + error = copyin(&u_argv[argv_i], &u_p, sizeof(u_p)); + if (error < 0) { + dynfree(args); + return error; + } + if (u_p == NULL) { + args->argv[argv_i++] = NULL; + break; + } + + path = &args->argv_blk[i]; + error = copyinstr(u_p, path, ARG_MAX - bytes_copied); + if (error < 0) { + dynfree(args); + return error; + } + + args->argv[argv_i++] = &args->argv_blk[i]; + len = strlen(path); + bytes_copied += (len + 1); + i += len; + } + return spawn(td, spawn_thunk, args, flags, NULL); } |