int sys_fork(struct trapframe *tf, pid_t *retval){ const char* name = "Anonymous student's process"; // create process struct for child struct proc *childp = proc_create_runprogram(name); if(childp == NULL){ return ENOMEM; //OUT OF MEMORY } // create and copy as to child struct addrspace* childas = kmalloc(sizeof(struct addrspace)); if(childas == NULL){ proc_destroy(childp); return ENOMEM; } if(as_copy(curproc->p_addrspace, &childas)){ kfree(childas); as_destroy(childas); proc_destroy(childp); return ENOMEM; } // attach new as to child proc childp->p_addrspace = childas; // create parent child relationship struct procinfo *pi = array_get(procinfotable, childp->pid - 1); if(pi == NULL){ kfree(childas); as_destroy(childas); proc_destroy(childp); return ECHILD; // NO SUCH CHILD IN THE INFO TABLE } pi->parent_pid = curproc->pid; // create thread for child and pass it tf struct trapframe *childtf = kmalloc(sizeof(struct trapframe)); memcpy(childtf,tf,sizeof(struct trapframe)); void ** data = kmalloc(2*sizeof(void*)); data[0] = (void*)childtf; data[1] = (void*)childas; int err = thread_fork(name, childp,(void *)enter_forked_process, data, 0); if(err){ kfree(childas); kfree(childtf); as_destroy(childas); proc_destroy(childp); kfree(childtf); return ENOMEM; } *retval = childp->pid; return 0; }
struct proc* proc_createchild(struct proc* parent, struct addrspace** as) { struct proc* child = proc_create(parent->p_name); if (child == NULL) { return NULL; } unsigned int i; // TODO Move this to a separate method for (i = 0; i < array_num(parent->p_filetable); i++) { struct filetable_entry* entry = array_get(parent->p_filetable, i); struct filetable_entry* newentry = (struct filetable_entry*) kmalloc(sizeof(struct filetable_entry)); if(entry == NULL) { proc_destroy(child); return NULL; } newentry->ft_fd = entry->ft_fd; newentry->ft_handle = entry->ft_handle; filehandle_incref(entry->ft_handle); int s = array_add(child->p_filetable, newentry, NULL); if (s == ENOMEM) { proc_destroy(child); return NULL; } } child->p_fdcounter = parent->p_fdcounter; /** process table */ if (addTo_processtable(child) != 0) { return NULL; } child->p_ppid = parent->p_pid; /** cwd */ /* * Lock the current process to copy its current directory. * (We don't need to lock the new process, though, as we have * the only reference to it.) */ spinlock_acquire(&(parent->p_lock)); if (parent->p_cwd != NULL) { VOP_INCREF(parent->p_cwd); child->p_cwd = parent->p_cwd; } spinlock_release(&(parent->p_lock)); /** address space */ (void) as; return child; }
/** * exit will perform the following tasks: * 1. close all open files (through file_close_all()) * 2. set the given exit code inside the proc structure. * 3. mark each child process as orphan. * 4. if orphan, will destroy the proc associated with the current thread. * 4.1 if not orphan, will signal the parent regarding our death. * 5. call thread_exit() so we become a zombie. */ void sys__exit( int code ) { struct proc *p = NULL; int err; KASSERT( curthread != NULL ); KASSERT( curthread->td_proc != NULL ); p = curthread->td_proc; //close all open files. err = file_close_all( p ); if( err ) panic( "problem closing a file." ); //lock so we can adjust the return value. PROC_LOCK( p ); p->p_retval = code; p->p_is_dead = true; //if we are orphans ourselves, no one is interested //in our return code, so we simply destroy ourselves. if( p->p_proc == NULL ) { PROC_UNLOCK( p ); proc_destroy( p ); } else { //signal that we are done. V( p->p_sem ); PROC_UNLOCK( p ); } //all that is left now is to kill our thread. thread_exit(); }
term_t cbif_spawn3(proc_t *proc, term_t *regs) { term_t m = regs[0]; term_t f = regs[1]; term_t args = regs[2]; if (!is_atom(m)) badarg(m); if (!is_atom(f)) badarg(f); if (!is_list(args)) badarg(args); if (list_len(args) < 0) badarg(args); // too odd proc_t *new_proc = proc_make(proc->group_leader); int x = proc_spawn_N(new_proc, m, f, args); if (x < 0) { proc_destroy(new_proc); // safe fail(err_to_term(x)); } return new_proc->pid; }
void sys__exit(int exitcode) { struct addrspace* as; struct proc* p = curproc; DEBUG(DB_EXEC, "sys_exit(): process %u exiting with code %d\n",p->p_pid,exitcode); KASSERT(p->p_addrspace != NULL); as_deactivate(); as = proc_setas(NULL); as_destroy(as); proc_remthread(curthread); p->p_exitstatus = _MKWAIT_EXIT(exitcode); p->p_exitable = true; lock_acquire(p->p_waitpid_lk); cv_broadcast(p->p_waitpid_cv, p->p_waitpid_lk); lock_release(p->p_waitpid_lk); proc_destroy(p); thread_exit(); panic("sys__exit(): unexpected return from thread_exit()\n"); }
void etimer_cancel_by_receiver(term_t dst) { etimer_t **ref = &active_timers; etimer_t *tm = active_timers; while (tm != 0) { if (tm->dst == dst) { if (tm->sender != 0) { assert(tm->sender->pending_timers > 0); tm->sender->pending_timers--; if (tm->sender->pending_timers == 0 && tm->sender->my_queue == MY_QUEUE_PENDING_TIMERS) proc_destroy(tm->sender); // destroy a zombie process } *ref = tm->next; etimer_t *free_me = tm; tm = tm->next; free_me->next = free_timers; free_timers = free_me; } else { ref = &tm->next; tm = tm->next; } } }
int etimer_cancel(uint64_t ref_id, int64_t *left_ns) { etimer_t **ref = &active_timers; etimer_t *tm = active_timers; while (tm != 0 && tm->ref_id != ref_id) { ref = &tm->next; tm = tm->next; } if (tm == 0) return -NOT_FOUND; *ref = tm->next; if (tm->sender != 0) { assert(tm->sender->pending_timers > 0); tm->sender->pending_timers--; if (tm->sender->pending_timers == 0 && tm->sender->my_queue == MY_QUEUE_PENDING_TIMERS) proc_destroy(tm->sender); // destroy a zombie process } *left_ns = tm->timeout - monotonic_clock(); //printk("*** etimer_cancel: ref_id %ld left_ms %ld\n", tm->ref_id, *left_ns /1000000); tm->next = free_timers; free_timers = tm; return 0; }
/* * Common code for cmd_prog and cmd_shell. * * Note that this does not wait for the subprogram to finish, but * returns immediately to the menu. This is usually not what you want, * so you should have it call your system-calls-assignment waitpid * code after forking. * * Also note that because the subprogram's thread uses the "args" * array and strings, until you do this a race condition exists * between that code and the menu input code. */ static int common_prog(int nargs, char **args) { struct proc *proc; int result; /* Create a process for the new program to run in. */ proc = proc_create_runprogram(args[0] /* name */); if (proc == NULL) { return ENOMEM; } result = thread_fork(args[0] /* thread name */, proc /* new process */, cmd_progthread /* thread function */, args /* thread arg */, nargs /* thread arg */); if (result) { kprintf("thread_fork failed: %s\n", strerror(result)); proc_destroy(proc); return result; } /* * The new process will be destroyed when the program exits... * once you write the code for handling that. */ return 0; }
term_t cbif_spawn1(proc_t *proc, term_t *regs) { term_t Fun = regs[0]; if (!is_boxed(Fun)) badarg(Fun); uint32_t *fdata = peel_boxed(Fun); if (boxed_tag(fdata) != SUBTAG_FUN) badarg(Fun); t_fun_t *f = (t_fun_t *)fdata; if (f->fe == 0) not_implemented("unloaded funs"); if (fun_arity(fdata) != fun_num_free(fdata)) badarg(); proc_t *new_proc = proc_make(proc->group_leader); int x = proc_spawn_fun0_N(new_proc, f); if (x < 0) { proc_destroy(new_proc); if (x == -TOO_DEEP) fail(A_SYSTEM_LIMIT); else fail(A_NOT_SPAWNED); } return new_proc->pid; }
void sys__exit(int exitcode) { struct addrspace *as; struct proc *p = curproc; /* for now, just include this to keep the compiler from complaining about an unused variable */ (void)exitcode; DEBUG(DB_SYSCALL,"Syscall: _exit(%d)\n",exitcode); KASSERT(curproc->p_addrspace != NULL); as_deactivate(); /* * clear p_addrspace before calling as_destroy. Otherwise if * as_destroy sleeps (which is quite possible) when we * come back we'll be calling as_activate on a * half-destroyed address space. This tends to be * messily fatal. */ as = curproc_setas(NULL); as_destroy(as); /* detach this thread from its process */ /* note: curproc cannot be used after this call */ proc_remthread(curthread); /* if this is the last user process in the system, proc_destroy() will wake up the kernel menu thread */ 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"); }
static void unhandled_trap(struct hw_trapframe *state, const char* name) { static spinlock_t screwup_lock = SPINLOCK_INITIALIZER; spin_lock(&screwup_lock); if(in_kernel(state)) { print_trapframe(state); panic("Unhandled trap in kernel!\nTrap type: %s", name); } else { char tf_buf[1024]; format_trapframe(state, tf_buf, sizeof(tf_buf)); warn("Unhandled trap in user!\nTrap type: %s\n%s", name, tf_buf); backtrace(); spin_unlock(&screwup_lock); assert(current); enable_irq(); proc_destroy(current); } }
term_t cbif_spawn_link1(proc_t *proc, term_t *regs) { term_t Fun = regs[0]; if (!is_boxed(Fun)) badarg(Fun); uint32_t *fdata = peel_boxed(Fun); if (boxed_tag(fdata) != SUBTAG_FUN) badarg(Fun); t_fun_t *f = (t_fun_t *)fdata; if (f->fe == 0) not_implemented("unloaded funs"); proc_t *new_proc = proc_make(proc->group_leader); int x = proc_spawn_fun0_N(new_proc, f); if (x == 0) x = inter_link_establish_N(&new_proc->links, proc->pid); if (x == 0) x = inter_link_establish_N(&proc->links, new_proc->pid); if (x < 0) { proc_destroy(new_proc); // no need to unlink, new_proc might have a link to proc but it was destroyed anyway if (x == -TOO_DEEP) fail(A_SYSTEM_LIMIT); else fail(A_NOT_SPAWNED); } return new_proc->pid; }
term_t cbif_spawn_monitor1(proc_t *proc, term_t *regs) { term_t Fun = regs[0]; if (!is_boxed(Fun)) badarg(Fun); uint32_t *fdata = peel_boxed(Fun); if (boxed_tag(fdata) != SUBTAG_FUN) badarg(Fun); t_fun_t *f = (t_fun_t *)fdata; if (f->fe == 0) not_implemented("unloaded funs"); term_t ref = heap_make_ref(&proc->hp); proc_t *new_proc = proc_make(proc->group_leader); int x = proc_spawn_fun0_N(new_proc, f); if (x == 0) { uint64_t ref_id = local_ref_id(ref); x = monitor(ref_id, proc->pid, new_proc->pid); } if (x < 0) { // no need to demonitor proc_destroy(new_proc); if (x == -TOO_DEEP) fail(A_SYSTEM_LIMIT); else fail(A_NOT_SPAWNED); } return heap_tuple2(&proc->hp, new_proc->pid, ref); }
term_t cbif_spawn_link3(proc_t *proc, term_t *regs) { term_t m = regs[0]; term_t f = regs[1]; term_t args = regs[2]; if (!is_atom(m)) badarg(m); if (!is_atom(f)) badarg(f); if (!is_list(args)) badarg(args); if (list_len(args) < 0) badarg(args); // too odd proc_t *new_proc = proc_make(proc->group_leader); int x = proc_spawn_N(new_proc, m, f, args); if (x == 0) x = inter_link_establish_N(&new_proc->links, proc->pid); if (x == 0) x = inter_link_establish_N(&proc->links, new_proc->pid); if (x < 0) { proc_destroy(new_proc); // no need to unlink, new_proc might have a link to proc but it is destroyed anyway fail(err_to_term(x)); } return new_proc->pid; }
int sys_fork(struct trapframe * tf, pid_t * retval){ struct trapframe * newtf = kmalloc(sizeof(struct trapframe)); if (newtf == NULL) { return ENOMEM; } *newtf = *tf; // disabling ALL interrupts so we can fork safely int spl = splhigh(); struct proc * child_proc = proc_fork(curproc); if (child_proc == NULL) { kfree(newtf); splx(spl); return ENOMEM; } int ret = thread_fork(curthread->t_name, child_proc, &forked_child_thread_entry, (void*)newtf, (unsigned long)curproc->p_addrspace); // can enable interrupts now splx(spl); if (ret) { proc_destroy(child_proc); kfree(newtf); return ret; } *retval = child_proc->pid; return(0); }
/* * Common code for cmd_prog and cmd_shell. * * Note that this does not wait for the subprogram to finish, but * returns immediately to the menu. This is usually not what you want, * so you should have it call your system-calls-assignment waitpid * code after forking. * * Also note that because the subprogram's thread uses the "args" * array and strings, until you do this a race condition exists * between that code and the menu input code. */ static int common_prog(int nargs, char **args) { struct proc *proc; int result; #if OPT_SYNCHPROBS kprintf("Warning: this probably won't work with a " "synchronization-problems kernel.\n"); #endif /* Create a process for the new program to run in. */ proc = proc_create_runprogram(args[0] /* name */); if (proc == NULL) { return ENOMEM; } result = thread_fork(args[0] /* thread name */, proc /* new process */, cmd_progthread /* thread function */, args /* thread arg */, nargs /* thread arg */); if (result) { kprintf("thread_fork failed: %s\n", strerror(result)); proc_destroy(proc); return result; } /* * The new process will be destroyed when the program exits... * once you write the code for handling that. */ return 0; }
/* * Common code for cmd_prog and cmd_shell. * * Note that this does not wait for the subprogram to finish, but * returns immediately to the menu. This is usually not what you want, * so you should have it call your system-calls-assignment waitpid * code after forking. * * Also note that because the subprogram's thread uses the "args" * array and strings, until you do this a race condition exists * between that code and the menu input code. */ static int common_prog(int nargs, char **args) { struct proc *proc; int result; #if OPT_SYNCHPROBS kprintf("Warning: this probably won't work with a " "synchronization-problems kernel.\n"); #endif /* Create a process for the new program to run in. */ proc = proc_create_runprogram(args[0] /* name */); if (proc == NULL) { return ENOMEM; } pid_t cpid = 0; int error = 0; error = proc_getAndCreateNewPid(&cpid); if (error) { proc_destroy(proc); return ENPROC; } proc->pid = cpid; proc_exitCodeNotNeeded(cpid); result = thread_fork(args[0] /* thread name */, proc /* new process */, cmd_progthread /* thread function */, args /* thread arg */, nargs /* thread arg */); if (result) { kprintf("thread_fork failed: %s\n", strerror(result)); proc_destroy(proc); return result; } #ifdef UW /* wait until the process we have just launched - and any others that it may fork - is finished before proceeding */ P(no_proc_sem); #endif // UW return 0; }
/* this needs to be fixed to get exit() and waitpid() working properly */ void sys__exit(int exitcode, int type) { struct addrspace *as; struct proc *p = curproc; DEBUG(DB_SYSCALL,"Syscall: _exit(%d)\n",exitcode); KASSERT(curproc->p_addrspace != NULL); as_deactivate(); /* * clear p_addrspace before calling as_destroy. Otherwise if * as_destroy sleeps (which is quite possible) when we * come back we'll be calling as_activate on a * half-destroyed address space. This tends to be * messily fatal. */ as = curproc_setas(NULL); as_destroy(as); lock_acquire(p->proc_exit_lock); if(!p->proc_parent_exited && p->pid > 1){ // Parent didnt exit yet, so we must only semi-destroy the proc proc_set_exit_status(p,exitcode, type); cv_broadcast(p->proc_exit_cv, p->proc_exit_lock); proc_exited_signal(p); /* detach this thread from its process */ /* note: curproc cannot be used after this call */ proc_remthread(curthread); // semi_destroy will release the proc_exit_lock for us. proc_semi_destroy(p); lock_release(p->proc_exit_lock); }else{ proc_exited_signal(p); lock_release(p->proc_exit_lock); /* detach this thread from its process */ /* note: curproc cannot be used after this call */ proc_remthread(curthread); /* if this is the last user process in the system, proc_destroy() will wake up the kernel menu thread */ 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"); }
void scheduler_exit_process(proc_t *proc, term_t reason) { assert(proc->my_queue == MY_QUEUE_NONE); // if (reason != A_NORMAL || proc->name == A_INIT) // { // if (proc->name == noval) // printk("*** Process %pt exits: %pt\n", // T(proc->pid), T(reason)); // else // printk("*** Process %pt (%pt) exits: %pt\n", // T(proc->pid), T(proc->name), T(reason)); // } // init calls halt() rather then exits normally assert(proc->name != A_INIT); // // Remove/unfix ETS table(s) // // NB: must precede monitor and link notifications // ets_process_exits(proc->pid); // Notify monitoring processes // int x = notify_monitors_N(proc->pid, reason); if (x < 0) printk("scheduler_exit_process: monitoring message(s)" " not delivered: pid %pt reason %pt\n", T(proc->pid), T(reason)); // Cancel timers that are known to have proc->pid as their destination // etimer_cancel_by_receiver(proc->pid); // // Notify linked processes/outlets // inter_links_notify(&proc->links, proc->pid, reason); if (proc->name != noval) scheduler_unregister(proc); hash_set_N(registry, &proc->pid, sizeof(proc->pid), 0); // never fails if (proc->pending_timers == 0) proc_destroy(proc); else { // The process is entering a 'zombie' state. There are pending timers // that have references to the process heap and thus the process heap // can not be released now. The process gets destroyed later, when the // last pending timer is fired or cancelled. proc->my_queue = MY_QUEUE_PENDING_TIMERS; } }
/* void free_root(struct procinfo* pi){ KASSERT(pi != NULL); if (pi->parent_pid == -1){ array_set(proc) } }*/ void sys__exit(int exitcode) { struct addrspace *as; struct proc *p = curproc; /* for now, just include this to keep the compiler from complaining about an unused variable */ #if OPT_A2 struct procinfo *pi = array_get(procinfotable, p->pid-1); if(pi == NULL){ goto parentexited; } lock_acquire(p->p_waitpid_lock); pi->exit_code = _MKWAIT_EXIT(exitcode); pi->active = 0; cv_broadcast(pi->waitpid_cv,p->p_waitpid_lock); lock_release(p->p_waitpid_lock); free_children(p->pid); parentexited: #else (void)exitcode; #endif DEBUG(DB_SYSCALL,"Syscall: _exit(%d)\n",exitcode); KASSERT(curproc->p_addrspace != NULL); as_deactivate(); /* * clear p_addrspace before calling as_destroy. Otherwise if * as_destroy sleeps (which is quite possible) when we * come back we'll be calling as_activate on a * half-destroyed address space. This tends to be * messily fatal. */ as = curproc_setas(NULL); as_destroy(as); /* detach this thread from its process */ /* note: curproc cannot be used after this call */ proc_remthread(curthread); /* if this is the last user process in the system, proc_destroy() will wake up the kernel menu thread */ 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"); }
static int erlang_fire(etimer_t *tm) { proc_t *to_proc = (is_atom(tm->dst)) ?scheduler_process_by_name(tm->dst) :scheduler_lookup(tm->dst); int rc = 0; if (to_proc != 0) { term_t marsh_msg = tm->msg; if (tm->sender != to_proc) // tm->sender may be zero { rc = heap_copy_terms_N(&to_proc->hp, &marsh_msg, 1); if (rc < 0) goto error; } term_t env_msg = marsh_msg; // {timeout,TRef,Msg} or Msg if (tm->enveloped) { term_t tref = heap_remake_local_ref_N(&to_proc->hp, tm->ref_id); if (tref == noval) { rc = -NO_MEMORY; goto error; } uint32_t *htop = heap_alloc_N(&to_proc->hp, 1 +3); if (htop == 0) { rc = -NO_MEMORY; goto error; } heap_set_top(&to_proc->hp, htop +1 +3); env_msg = tag_tuple(htop); htop[0] = 3; htop[1] = A_TIMEOUT; htop[2] = tref; htop[3] = marsh_msg; } rc = scheduler_new_local_mail_N(to_proc, env_msg); } error: if (tm->sender != 0) { assert(tm->sender->pending_timers > 0); tm->sender->pending_timers--; if (tm->sender->pending_timers == 0 && tm->sender->my_queue == MY_QUEUE_PENDING_TIMERS) proc_destroy(tm->sender); // destroy a zombie process } return rc; }
int sys_waitpid(pid_t pid, userptr_t returncode, int flags, pid_t *retval) { (void) pid; (void) returncode; (void) flags; (void) retval; int *test = kmalloc(sizeof(int)); int result; // TODO: a lot of sanity checks for this one. if (pid < 1 || pid > PID_MAX){ return ESRCH; } if (pid == curproc->pid) { return ECHILD; } if (flags != 0 && flags != WNOHANG) { return EINVAL; } if (returncode != NULL) { result = copyin(returncode, test, sizeof(int)); if (result) { return result; } } // TODO: what's the _MKWAIT_EXIT stuff? lock_acquire(proc_table_lock); struct proc *child = proc_table[pid]; if (child == NULL) { lock_release(proc_table_lock); return ESRCH; } if (child->parent_pid != curproc->pid) { lock_release(proc_table_lock); return ECHILD; } if (!child->exited) { // We always wait on the child's cv cv_wait(child->waitpid_cv, proc_table_lock); KASSERT(child->exited); } if (returncode != NULL) { // Give back returncode copyout(&child->exitcode, returncode, sizeof(int)); } *retval = pid; proc_destroy(child); lock_release(proc_table_lock); return 0; }
int sys_waitpid (pid_t pid, int *status, int options, int32_t *retval) { int result, p_status; struct proc *p_child; KASSERT (curproc != NULL); result = 0; *retval = -1; result = get_proc(pid, &p_child); if (result) return result; if (curproc != p_child->parent) return ECHILD; /* filter out supported options */ switch (options) { case 0: case WNOHANG: // case WUNTRACED: break; default: return EINVAL; } if ((options == WNOHANG) && !p_child->exited) { *retval = 0; return result; } if (status != NULL && (!as_is_addr_valid(curproc->p_addrspace, (vaddr_t) status))) return EFAULT; if (!p_child->exited) P(p_child->exit_sem); KASSERT (p_child->exited); p_status = p_child->exit_status; if (status) { result = copyout((const void *) &p_status, (userptr_t) status, sizeof(int)); if (result) return result; } proc_destroy(p_child); *retval = pid; return 0; }
term_t bif_destroy_process1(term_t Pid, process_t *ctx) { process_t *proc; if (!is_pid(Pid)) return A_BADARG; proc = proc_lookup(pid_serial(Pid)); if (proc) proc_destroy(proc); result(A_TRUE); return AI_OK; }
void proctable_remove_process(struct proc *proc_removed) { KASSERT(proc_removed != NULL); int pid = getPID(proc_removed); procarray_set(procTable, pid, NULL); procCount--; /* if this is the last user process in the system, proc_destroy() will wake up the kernel menu thread */ proc_destroy(proc_removed); }
void sys__exit(int exitcode) { (void) exitcode; lock_acquire(proc_table_lock); // orphan all children, should be done no matter what for (int i = 0; i < PID_MAX; i++) { // Found a children if (proc_table[i] != NULL && proc_table[i]->parent_pid == curproc->pid) { proc_table[i]->parent_pid = INVALID_PID; // weird case, parent doesn't wait, but exited later if (proc_table[i]->exited) { proc_destroy(proc_table[i]); } } } // set exitcode stuff is probably unnecessary for orphan if (curproc->parent_pid == INVALID_PID) { // Parent is dead, suicide proc_destroy(curproc); } else { // do fancy shit and don't destroy itself // it should be destroyed by parent in waitpid // TODO: This is probably not a good design curproc->exited = true; curproc->exitcode = _MKWAIT_EXIT(exitcode); // Wake up parent cv_signal(curproc->waitpid_cv, proc_table_lock); } lock_release(proc_table_lock); // kfree(curproc); thread_exit(); }
/* * Common code for cmd_prog and cmd_shell. * * Note that this does not wait for the subprogram to finish, but * returns immediately to the menu. This is usually not what you want, * so you should have it call your system-calls-assignment waitpid * code after forking. * * Also note that because the subprogram's thread uses the "args" * array and strings, until you do this a race condition exists * between that code and the menu input code. */ static int common_prog(int nargs, char **args) { struct proc *proc; int result; int status; int retval; unsigned tc; /* Create a process for the new program to run in. */ proc = proc_create_runprogram(args[0] /* name */); if (proc == NULL) { return ENOMEM; } tc = thread_count; result = thread_fork(args[0] /* thread name */, proc /* new process */, cmd_progthread /* thread function */, args /* thread arg */, nargs /* thread arg */); if (result) { kprintf("thread_fork failed: %s\n", strerror(result)); proc_destroy(proc); return result; } result = sys_waitpid(proc->pid, &status, 0 , &retval); if (result ) { kprintf_n("sys_waitpid done with result %d for pid %d \n",result,proc->pid ); //return 0; } /* * The new process will be destroyed when the program exits... * once you write the code for handling that. */ // Wait for all threads to finish cleanup, otherwise khu be a bit behind, // especially once swapping is enabled. thread_wait_for_count(tc); return 0; }
void sys__exit(int exitcode) { struct addrspace *as; struct proc *p = curproc; #if OPT_A2 int pid = (int)curproc->pid; struct proc_entry *entry = process_table[pid]; lock_acquire(entry->exit_mutex); process_table[pid]->exited = 1; process_table[pid]->exitcode = exitcode; //if(lock_do_i_hold(entry->exit_mutex)) cv_signal(entry->exit_wait, entry->exit_mutex); lock_release(entry->exit_mutex); #else /* for now, just include this to keep the compiler from complaining about an unused variable */ (void)exitcode; #endif kprintf("is exiting: %d\n", pid); DEBUG(DB_SYSCALL,"Syscall: _exit(%d)\n",exitcode); KASSERT(curproc->p_addrspace != NULL); as_deactivate(); /* * clear p_addrspace before calling as_destroy. Otherwise if * as_destroy sleeps (which is quite possible) when we * come back we'll be calling as_activate on a * half-destroyed address space. This tends to be * messily fatal. */ as = curproc_setas(NULL); as_destroy(as); /* detach this thread from its process */ /* note: curproc cannot be used after this call */ proc_remthread(curthread); /* if this is the last user process in the system, proc_destroy() will wake up the kernel menu thread */ 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"); }
/** Main test */ int main( int argc, char **argv ) { setlocale( LC_ALL, "" ); srand( time( 0 ) ); program_name=L"(ignore)"; say( L"Testing low-level functionality"); say( L"Lines beginning with '(ignore):' are not errors, they are warning messages\ngenerated by the fish parser library when given broken input, and can be\nignored. All actual errors begin with 'Error:'." ); proc_init(); halloc_util_init(); event_init(); parser_init(); function_init(); builtin_init(); reader_init(); env_init(); test_util(); test_escape(); test_convert(); test_tok(); test_parser(); test_expand(); test_path(); say( L"Encountered %d errors in low-level tests", err_count ); /* Skip performance tests for now, since they seem to hang when running from inside make (?) */ // say( L"Testing performance" ); // perf_complete(); env_destroy(); reader_destroy(); parser_destroy(); function_destroy(); builtin_destroy(); wutil_destroy(); event_destroy(); proc_destroy(); halloc_util_destroy(); }
int sys_waitpid(pid_t pid, userptr_t status, int options, int *retval) { (void) options; int result; /* Arguments Error Handling */ struct proc* waitproc = get_proc_pid(pid); if(waitproc == NULL) { return ESRCH; } // check if status pointer is aligned by 4 bytes if((uintptr_t)(const void *)(status) % 4 != 0) { return EFAULT; } // check for badflags if(options != 0) { return EINVAL; } if(pid == curthread->t_proc->pid || pid == curthread->t_proc->ppid) { return ECHILD; } if(curthread->t_proc->pid != waitproc->ppid) { return ECHILD; } if(waitproc->exited == false) P(waitproc->p_exitsem); if((int *) status != NULL) { result = copyout((const void *) &(waitproc->exitcode), status, sizeof(int)); if(result) //V(waitproc->p_exitsem); return EFAULT; } dealloc_pid(waitproc); // kprintf("********************** destroying process - %d \n", dealloc_pid(waitproc)); proc_destroy(waitproc); *retval = pid; return 0; }