pid_t sys_waitpid(pid_t pid, int * status, int options, int *retval){ int result = valid_pid(pid); if(result){ return result; } //If there is an option attached, FAIL. NO OPTIONS FOR YOU else if(options != 0){ return EINVAL; } //If pointer is not aligned, throw an error. NO EXIT CODE FOR YOU else if((int)status%4 != 0){ return EFAULT; } acquire_lock(pid); //While the process has not exited yet, while(has_exit_code(pid) == false){ put_to_sleep(pid); } *status = _MKWAIT_EXIT(get_exit_code(pid)); release_lock(pid); release_pid(pid); *retval = pid; return 0; }
void sys__exit(int exitcode) { // array init exitcode = _MKWAIT_EXIT(exitcode); // add to exitcode array struct exitc *c = find_exitc(curproc->p_pid); if(c) { c->exitcode = exitcode; } // remove from procarray. unsigned num = procarray_num(procarr); for (unsigned i = 0 ; i < num ; i++) { if ((procarray_get(procarr, i)) == curproc) { procarray_remove(procarr,i); break; } } // pid_list[curproc->p_pid] = false; cv_broadcast(curproc->p_cv,curproc->p_lk); //proc_remthread(curthread); thread_exit(); // curthread->t_proc = NULL; //what is this??? you removed it at the bottom and then added it here? // code below is removed. Since the process is destroyed, there is no "curthread" now. // We cannot access to it. // curthread->t_proc = NULL; }
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 sys_exit(int exitcode, bool is_sig){ lock_acquire(curproc->exitlock); for (int fd = 0; fd < OPEN_MAX; fd++) { int err; sys_close(fd, &err); } curproc->exit_flag = true; if (is_sig) { curproc->exit_code = _MKWAIT_SIG(exitcode); } else { curproc->exit_code = _MKWAIT_EXIT(exitcode); } if (proc_ids[curproc->ppid]->exit_flag == false) { cv_broadcast(curproc->exitcv, curproc->exitlock); lock_release(curproc->exitlock); } else { /* Clean Up */ lock_release(curproc->exitlock); cv_destroy(curproc->exitcv); as_destroy(curproc->p_addrspace); kfree(proc_ids[curproc->pid]->p_name); curproc->p_addrspace = NULL; kfree(proc_ids[curproc->pid]); proc_ids[curproc->pid] = NULL; lock_destroy(curproc->exitlock); } thread_exit(); }
// Doesn't return void sys_exit(int exit_code){ lock_acquire(pid_lock); if(curthread->ppid == -1){ // no parent kprintf("NO PARENT"); thread_exit(); } process_array[curthread->mypid]->exited = 1; process_array[curthread->mypid]->exit_code = _MKWAIT_EXIT(exit_code); //TODO: ppid? // TODO: close filehandletable entries (memory leak) // for(int fd = 0; fd < MAX_FILE_DESCRIPTORS; fd++){ // sys_close(fd); // } if(process_array[curthread->ppid] != NULL){ if(process_array[curthread->ppid]->thread != NULL){ V(process_array[curthread->ppid]->thread->exit_sem); } } lock_release(pid_lock); thread_exit(); }
/* * Function called when user-level code hits a fatal fault. */ static void kill_curthread(vaddr_t epc, unsigned code, vaddr_t vaddr) { int sig = 0; KASSERT(code < NTRAPCODES); switch (code) { case EX_IRQ: case EX_IBE: case EX_DBE: case EX_SYS: /* should not be seen */ KASSERT(0); sig = SIGABRT; break; case EX_MOD: case EX_TLBL: case EX_TLBS: sig = SIGSEGV; break; case EX_ADEL: case EX_ADES: sig = SIGBUS; break; case EX_BP: sig = SIGTRAP; break; case EX_RI: sig = SIGILL; break; case EX_CPU: sig = SIGSEGV; break; case EX_OVF: sig = SIGFPE; break; } /* * You will probably want to change this. */ kprintf("Fatal user mode trap %u sig %d (%s, epc 0x%x, vaddr 0x%x)\n", code, sig, trapcodenames[code], epc, vaddr); if(curthread->pid == 1){ V(menu_semaphore); } else { proc_tbl[curthread->pid]->exit_code = _MKWAIT_EXIT(1); proc_tbl[curthread->pid]->exit = true; V(proc_tbl[curthread->pid]->sem); } thread_exit(); // panic("I don't know how to handle this\n"); }
int sys___exit(int exit_code) { //Check whether the process calling exit has no children? pid_t pid_process=curthread->t_pid; //Check whether to indicate exit by calling cv_broadcast as well // cv_broadcast(process_array[pid_process]->process_cv,process_array[pid_process]->process_lock); //Now using a semaphore and V when the thread exits if(process_array[pid_process]->waitstatus==true) { lock_acquire(process_array[pid_process]->process_lock); //Indicate Exit by calling changing the exit status in the process array process_array[pid_process]->exit_code= _MKWAIT_EXIT(exit_code); process_array[pid_process]->exit_status=true; cv_signal(process_array[pid_process]->process_cv,process_array[pid_process]->process_lock); lock_release(process_array[pid_process]->process_lock); } //V(process_array[pid_process]->process_sem); else { lock_acquire(process_array[pid_process]->process_lock); //Store the exit code passed in the argument process_array[pid_process]->exit_code= _MKWAIT_EXIT(exit_code); //Indicate Exit by calling changing the exit status in the process array process_array[pid_process]->exit_status=true; lock_release(process_array[pid_process]->process_lock); } thread_exit(); return 0; }
/* 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 void fail(unsigned long num, const char *msg) { kprintf("thread %lu: Mismatch on %s\n", num, msg); kprintf("Test failed\n"); lock_release(testlock); V(donesem); thread_exit(_MKWAIT_EXIT(1)); }
int sys_waitpid(pid_t pid, userptr_t retstatus, int flags, pid_t *retval) { int status; int result; result = pid_wait(pid, &status, flags, retval); if (result) { return result; } status = _MKWAIT_EXIT(status); return copyout(&status, retstatus, sizeof(int)); }
static void cvtestthread(void *junk, unsigned long num) { int i; volatile int j; time_t secs1, secs2; uint32_t nsecs1, nsecs2; (void)junk; for (i=0; i<NCVLOOPS; i++) { lock_acquire(testlock); while (testval1 != num) { gettime(&secs1, &nsecs1); cv_wait(testcv, testlock); gettime(&secs2, &nsecs2); if (nsecs2 < nsecs1) { secs2--; nsecs2 += 1000000000; } nsecs2 -= nsecs1; secs2 -= secs1; /* Require at least 2000 cpu cycles (we're 25mhz) */ if (secs2==0 && nsecs2 < 40*2000) { kprintf("cv_wait took only %u ns\n", nsecs2); kprintf("That's too fast... you must be " "busy-looping\n"); V(donesem); thread_exit(_MKWAIT_EXIT(1)); } } kprintf("Thread %lu\n", num); testval1 = (testval1 + NTHREADS - 1)%NTHREADS; /* * loop a little while to make sure we can measure the * time waiting on the cv. */ for (j=0; j<3000; j++); cv_broadcast(testcv, testlock); lock_release(testlock); } V(donesem); }
void _exit(int exitcode){ int t= splhigh(); splx(t); struct process_block *currentProcess = pid_array[getpid()]; if(currentProcess !=NULL){ currentProcess->exited = true; currentProcess->exitcode = _MKWAIT_EXIT(exitcode); thread_exit(); } else{ kprintf("current process %d is null. something wrong\n",(int)getpid()); } }
void proctable_exit_process(struct proc *proc_exited, int exitcode) { // DEBUG(DB_EXEC, "Exiting PID: %d from proctable\n", getPID(proc_exited)); KASSERT(proc_exited != NULL); KASSERT(proc_exited->p_pid > 0); // set the process state to exited setState(proc_exited, PROC_EXITED); // encode the exit code as per the docs. setExitcode(proc_exited, _MKWAIT_EXIT(exitcode)); // Next we need to evaluate some cases: // If proc_exited has living children, they should now have a NULL parent. // If proc_exited has dead children, they should now be destroyed. int exitedPID = getPID(proc_exited); // Find the children of proc_exited. for (int i = MIN_PID; i < pidLimit; i++) { struct proc* cur = procarray_get(procTable, i); if (cur != NULL && getPPID(cur) == exitedPID) { // Check state of child int state = getState(cur); // A running child has its parent set to NULL if (state == PROC_RUNNING) { setPPID(cur, PROC_NO_PID); } // An exited child can now be completely removed. else if (state == PROC_EXITED) { proctable_remove_process(cur); } } } // If proc_exited has no parent, it can be removed if (getPPID(proc_exited) == PROC_NO_PID) { proctable_remove_process(proc_exited); } // Otherwise if proc_exited has a parent // then proc_exited must wake its potentially waiting parent else { cv_signal(proc_exited->wait_cv, procTableLock); } }
static void waitfirstthread(void *junk, unsigned long num) { unsigned long i; (void)junk; kprintf("waitfirstthread %lu started...\n", num); for (i = 0; i < 100 * (num + 1); i++) thread_yield(); kprintf("waitfirstthread %lu exiting.\n", num); thread_exit(_MKWAIT_EXIT(num)); }
void sys_exit(int exit_code){ pid_t pid = curthread->pid ; lock_acquire(process_table[pid]->exit_lock) ; process_table[pid]->exited = true ; process_table[pid]->exitcode=_MKWAIT_EXIT(exit_code); int i=0; for(i=0;i<OPEN_MAX_LOCAL;i++){ if(curthread->fd[i] != NULL) { sys_close((userptr_t)i); } } cv_broadcast(process_table[pid]->exit_cv,process_table[pid]->exit_lock) ; lock_release(process_table[pid]->exit_lock) ; thread_exit(); }
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; #if OPT_A2 proctable_update(proctable, curproc,_MKWAIT_EXIT (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"); }
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(); }
/* * System call dispatcher. * * A pointer to the trapframe created during exception entry (in * exception.S) is passed in. * * The calling conventions for syscalls are as follows: Like ordinary * function calls, the first 4 32-bit arguments are passed in the 4 * argument registers a0-a3. 64-bit arguments are passed in *aligned* * pairs of registers, that is, either a0/a1 or a2/a3. This means that * if the first argument is 32-bit and the second is 64-bit, a1 is * unused. * * This much is the same as the calling conventions for ordinary * function calls. In addition, the system call number is passed in * the v0 register. * * On successful return, the return value is passed back in the v0 * register, or v0 and v1 if 64-bit. This is also like an ordinary * function call, and additionally the a3 register is also set to 0 to * indicate success. * * On an error return, the error code is passed back in the v0 * register, and the a3 register is set to 1 to indicate failure. * (Userlevel code takes care of storing the error code in errno and * returning the value -1 from the actual userlevel syscall function. * See src/user/lib/libc/arch/mips/syscalls-mips.S and related files.) * * Upon syscall return the program counter stored in the trapframe * must be incremented by one instruction; otherwise the exception * return code will restart the "syscall" instruction and the system * call will repeat forever. * * If you run out of registers (which happens quickly with 64-bit * values) further arguments must be fetched from the user-level * stack, starting at sp+16 to skip over the slots for the * registerized values, with copyin(). */ void syscall(struct trapframe *tf) { int callno; int32_t retval; int err; KASSERT(curthread != NULL); KASSERT(curthread->t_curspl == 0); KASSERT(curthread->t_iplhigh_count == 0); callno = tf->tf_v0; /* * Initialize retval to 0. Many of the system calls don't * really return a value, just 0 for success and -1 on * error. Since retval is the value returned on success, * initialize it to 0 by default; thus it's not necessary to * deal with it except for calls that return other values, * like write. */ retval = 0; switch (callno) { case SYS_reboot: err = sys_reboot(tf->tf_a0); break; case SYS___time: err = sys___time((userptr_t)tf->tf_a0, (userptr_t)tf->tf_a1); break; /* ASST2: These implementations of read and write only work for * console I/O (stdin, stdout and stderr file descriptors) */ case SYS_read: err = sys_read(tf->tf_a0, (userptr_t)tf->tf_a1, tf->tf_a2, &retval); break; case SYS_write: err = sys_write(tf->tf_a0, (userptr_t)tf->tf_a1, tf->tf_a2, &retval); break; /* process calls */ case SYS__exit: thread_exit(_MKWAIT_EXIT(tf->tf_a0)); panic("Returning from exit\n"); case SYS_fork: err = sys_fork(tf, &retval); break; /* ASST2 - You need to fill in the code for each of these cases */ case SYS_getpid: err = sys_getpid(&retval); break; case SYS_waitpid: if(sys_waitpid(tf->tf_a0, \ (userptr_t)tf->tf_a1, tf->tf_a2, &retval) == -1) { err=retval; } else{ err=0; } break; case SYS_kill: err = sys_kill(tf->tf_a0, tf->tf_a1); break; /* Even more system calls will go here */ default: kprintf("Unknown syscall %d\n", callno); err = ENOSYS; break; } if (err) { /* * Return the error code. This gets converted at * userlevel to a return value of -1 and the error * code in errno. */ tf->tf_v0 = err; tf->tf_a3 = 1; /* signal an error */ } else { /* Success. */ tf->tf_v0 = retval; tf->tf_a3 = 0; /* signal no error */ } /* * Now, advance the program counter, to avoid restarting * the syscall over and over again. */ tf->tf_epc += 4; /* Make sure the syscall code didn't forget to lower spl */ KASSERT(curthread->t_curspl == 0); /* ...or leak any spinlocks */ KASSERT(curthread->t_iplhigh_count == 0); }