#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include void sys__exit(int exitcode) { struct addrspace * as; struct proc * p = curproc; p->exitcode = exitcode; DEBUG(DB_SYSCALL,"Syscall: _exit(%d)\n",exitcode); KASSERT(curproc->p_addrspace != NULL); lock_acquire(proclock); int x = listpop(p->kids); while (x) { if(processes->pids[x]) { processes->pids[x]->parent = NULL; if (processes->pids[x]->exitcode >= 0) { lock_release(proclock); proc_destroy(processes->pids[x]); lock_acquire(proclock); } } x = listpop(p->kids); } lock_release(proclock); listelete(p->kids); // VFS fields if (p->p_cwd) { VOP_DECREF(p->p_cwd); p->p_cwd = NULL; } as_deactivate(); as = curproc_setas(NULL); as_destroy(as); /* detach this thread from its process */ /* note: curproc cannot be used after this call */ proc_remthread(curthread); threadarray_cleanup(&p->p_threads); spinlock_cleanup(&p->p_lock); lock_acquire(p->waitlock); cv_broadcast(p->waiting, p->waitlock); lock_release(p->waitlock); if (!(p->parent) || p->parent->exitcode >= 0 || p->parent == kproc) proc_destroy(p); thread_exit(); /* thread_exit() does not return, so we should never get here */ panic("return from thread_exit in sys_exit\n"); } // basically, return an error code, and put the actual result in retval int sys_getpid(pid_t * retval) { if (!(curproc)) return 1; *retval = curproc->pid; return(0); } int sys_waitpid(pid_t pid, userptr_t status, int options, pid_t * retval) { (void)status; if (options != 0) { return(EINVAL); } if (pid < PID_MIN || pid > PID_MAX) return ESRCH; struct proc * target = getChild(curproc, pid); if (!(target)) return ECHILD; if (target->exitcode >= 0) { *retval = target->exitcode; return 0; } lock_acquire(target->waitlock); cv_wait(target->waiting, target->waitlock); lock_release(target->waitlock); *retval = target->exitcode; proc_destroy(target); return 0; } int sys_fork(struct trapframe * tf, int * retval) { // create new process' memory space struct proc * child = proc_create_runprogram("childproc"); if ((!child)) return ENOMEM; struct trapframe * new_tf = kmalloc(sizeof(*tf)); struct addrspace * new_as; as_copy(curproc_getas(), &new_as); if (!(new_as) || !(new_tf)) { proc_destroy(child); kfree(new_as); kfree(new_tf); return ENOMEM; } // set PIDs, etc. copy data in to the new space child->p_addrspace = new_as; child->parent = curproc; add_child(curproc, child->pid); *new_tf = *tf; // start new thread thread_fork("childproc", child, enter_forked_process, new_tf, 0); // return correct values if (curproc->pid == child->pid) *retval = 0; else *retval = child->pid; return 0; } // args is an array of null terminated strings, with the last element being a null pointer so we don't overflow if iterating // since this is a userptr type, we need to use copyin and copyout to get data properly // hopefully the path in program is actually a full filepath int sys_execv(const char * program, userptr_t args) { userptr_t temp = args; int argcount = 0; char ** argv; int errcode; // why don't we have errno!!! my beautful one-liners!!! // see how long args is while (1) { char * temp2; errcode = copyin((const userptr_t)temp, temp2, sizeof(char *)); if (errcode) return errcode; if (!(temp2)) break; temp += sizeof(char *); ++argcount; } // allocate space for argv argv = kmalloc(argcount * sizeof(char *)); if (!argv) return ENOMEM; // get kernel copy of args in argv temp = args; for (int i = 0; i < argcount; ++i) { errcode = copyin(temp, argv[i], sizeof(char *)); if (errcode) { kfree(argv); return errcode; } temp += sizeof(char *); } // allocate space for filepath char * filepath = kmalloc(sizeof(program)); if (!(filepath)) { kfree(argv); return ENOMEM; } // get kernel copy of filepath size_t useless; errcode = copyinstr((const_userptr_t)program, filepath, strlen(program) + 1, &useless); if (errcode) { kfree(argv); kfree(filepath); return errcode; } // open program file struct vnode * v; errcode = vfs_open(filepath, O_RDONLY, 0, &v); if (errcode) { kfree(argv); kfree(filepath); return errcode; } // create new address space struct addrspace * as = as_create(); if (!(as)) { vfs_close(v); kfree(argv); kfree(filepath); return ENOMEM; } // Switch to the new as and activate. keep old in case we fail later struct addrspace * oldas = curproc_getas(); curproc_setas(as); as_activate(); vaddr_t entrypoint; // Load santa's favourite slave errcode = load_elf(v, &entrypoint); if (errcode) { vfs_close(v); kfree(argv); kfree(filepath); curproc_setas(oldas); as_destroy(as); return errcode; } // close the file now that we're done vfs_close(v); // create the new stack vaddr_t newstack; errcode = as_define_stack(as, &newstack); if (errcode) { kfree(argv); kfree(filepath); curproc_setas(oldas); as_destroy(as); return errcode; } userptr_t userArgv; // need to copy data over into the new address space, as rn it is all in kernel heap // delete old addrspace, enter new process as_destroy(oldas); enter_new_process(argcount, userArgv, newstack, entrypoint); panic("Enter new process returned!\n"); return EINVAL; }