pid_t sys_waitpid(pid_t pid, int *status, int options, pid_t *retval) { int result; if (options != 0 && options != WNOHANG) { return -EINVAL; } result = pid_is_parent(curthread->t_pid, pid); if (result < 0) { return result; } result = pid_join(pid, status, options); *retval = result; if (result < 0) { return result; } return 0; }
static int common_prog(int nargs, char **args) { int result; char **args_copy; #if OPT_SYNCHPROBS kprintf("Warning: this probably won't work with a " "synchronization-problems kernel.\n"); #endif /* * Implementation of & option for menu when running programs. * By default, menu will wait for user program to end before running. * If on menu command line has a '&' at the end, * it will not wait for the user program to end * before continuing to run. */ bool toDetach; toDetach = false; pid_t childpid; if (*args[nargs - 1] == '&'){ nargs--; // So we don't pass on & toDetach = true; } /* demke: Make a copy of arguments to pass to new thread, * so that we aren't depending on parent's stack! */ args_copy = copy_args(nargs, args); if (!args_copy) { return ENOMEM; } /* demke: and now call thread_fork with the copy */ result = thread_fork(args_copy[0] /* thread name */, cmd_progthread /* thread function */, args_copy /* thread arg */, nargs /* thread arg */, &childpid); if (result) { kprintf("thread_fork failed: %s\n", strerror(result)); /* demke: need to free copy of args if fork fails */ free_args(nargs, args_copy); return result; } // If toDetach, then wont wait for program to end before continuing menu. if (toDetach) { pid_detach(childpid); } // Wait for program to end before continuing // (unless it's detached, in which case join will do nothing.) pid_join(childpid, NULL, (int)NULL); return 0; }
int thread_join(pid_t pid, int *status) { /* We need to check a bunch of things that are internal to * the pid system, like parent/child relationship and * exit status. So, just hand off to a pid system * function */ return pid_join(pid, status); }
static int common_prog(int nargs, char **args) { int result; int join_result; int *status; char **args_copy; pid_t *ret; #if OPT_SYNCHPROBS kprintf("Warning: this probably won't work with a " "synchronization-problems kernel.\n"); #endif /* demke: Make a copy of arguments to pass to new thread, * so that we aren't depending on parent's stack! */ args_copy = copy_args(nargs, args); if (!args_copy) { return ENOMEM; } if(strcmp(args[nargs-2], "&") == 0) { ret = NULL; //This will cause thread_fork to detach the child } /* demke: and now call thread_fork with the copy */ result = thread_fork(args_copy[0] /* thread name */, cmd_progthread /* thread function */, args_copy /* thread arg */, nargs /* thread arg */, ret); if (result) { kprintf("thread_fork failed: %s\n", strerror(result)); /* demke: need to free copy of args if fork fails */ free_args(nargs, args_copy); return result; } else if (result != 0 && ret != NULL) { join_result = pid_join(result, status, 0); if (status != 0 || join_result < 0) { return join_result; } } return 0; }
static int common_prog(int nargs, char **args) { int result; char **args_copy; pid_t childthread; int status; #if OPT_SYNCHPROBS kprintf("Warning: this probably won't work with a " "synchronization-problems kernel.\n"); #endif /* demke: Make a copy of arguments to pass to new thread, * so that we aren't depending on parent's stack! */ args_copy = copy_args(nargs, args); if (!args_copy) { return ENOMEM; } if(*args_copy[nargs-1]=='&'){ result = thread_fork(args_copy[0] /* thread name */, cmd_progthread /* thread function */, args_copy /* thread arg */, nargs /* thread arg */, NULL); } else{ result = thread_fork(args_copy[0] /* thread name */, cmd_progthread /* thread function */, args_copy /* thread arg */, nargs /* thread arg */, &childthread); pid_join(childthread,&status,0); } /* demke: and now call thread_fork with the copy */ if (result) { kprintf("thread_fork failed: %s\n", strerror(result)); /* demke: need to free copy of args if fork fails */ free_args(nargs, args_copy); return result; } return 0; }
/* * Handle system call waitpid - the current process waits for the target * process targetpid to exit, and stores the exit status in the pointer status. * Store a return value of 0 to retval if no error occurs and -1 otherwise. * Return the error code if an error occurs and 0 otherwise. */ int sys_waitpid(pid_t targetpid, int *status, int options, int *retval){ int err; /* Check if flag is valid. */ if (options != 0 && options != WNOHANG) { err = -1 * EINVAL; goto out; } /* Check if the current thread is waiting on one of its * own children. */ int ischild = check_ppid(targetpid); if (ischild == -1) { /* targetpid process does not exist. */ err = -1 * ESRCH; goto out; } else if (ischild == 0) { /* Current thread is not the parent of target thread. */ err = -1 * ECHILD; goto out; } err = pid_join(targetpid, status, options); out: if (err < 0) { /* An error occurred. */ err = -err; *retval = -1; } else { *retval = err; err = 0; } return err; }
int waittest(int nargs, char **args) { int i, spl, status, err; pid_t kid; pid_t kids2[NTHREADS]; int kids2_head = 0, kids2_tail = 0; (void)nargs; (void)args; init_sem(); kprintf("Starting wait test...\n"); /* * This first set should (hopefully) still be running when * wait is called (helped by the splhigh). */ kprintf("\n"); kprintf("Set 1 (wait should generally succeed)\n"); kprintf("-------------------------------------\n"); spl = splhigh(); for (i = 0; i < NTHREADS; i++) { err = thread_fork("wait test thread", waitfirstthread, NULL, i, &kid); if (err) { panic("waittest: thread_fork failed (%d)\n", err); } kprintf("Spawned pid %d\n", kid); kids2[kids2_tail] = kid; kids2_tail = (kids2_tail+1) % NTHREADS; } splx(spl); for (i = 0; i < NTHREADS; i++) { kid = kids2[kids2_head]; kids2_head = (kids2_head+1) % NTHREADS; kprintf("Waiting on pid %d...\n", kid); err = pid_join(kid, &status, 0); if (err) { kprintf("Pid %d waitpid error %d!\n", kid, err); } else { kprintf("Pid %d exit status: %d\n", kid, status); } } /* * This second set has to V their semaphore before the exit, * so when wait is called, they will have already exited, but * their parent is still alive. */ kprintf("\n"); kprintf("Set 2 (wait should always succeed)\n"); kprintf("----------------------------------\n"); for (i = 0; i < NTHREADS; i++) { err = thread_fork("wait test thread", exitfirstthread, NULL, i, &kid); if (err) { panic("waittest: thread_fork failed (%d)\n", err); } kprintf("Spawned pid %d\n", kid); kids2[kids2_tail] = kid; kids2_tail = (kids2_tail+1) % NTHREADS; if (err) { panic("waittest: q_addtail failed (%d)\n", err); } } for (i = 0; i < NTHREADS; i++) { kid = kids2[kids2_head]; kids2_head = (kids2_head+1) % NTHREADS; kprintf("Waiting for pid %d to V()...\n", kid); P(exitsems[i]); kprintf("Appears that pid %d P()'d\n", kid); kprintf("Waiting on pid %d...\n", kid); err = pid_join(kid, &status, 0); if (err) { kprintf("Pid %d waitpid error %d!\n", kid, err); } else { kprintf("Pid %d exit status: %d\n", kid, status); } } /* * This third set has to V their semaphore before the exit, so * when wait is called, they will have already exited, and * since we've gone through and disowned them all, their exit * statuses should have been disposed of already and our waits * should all fail. */ kprintf("\n"); kprintf("Set 3 (wait should never succeed)\n"); kprintf("---------------------------------\n"); for (i = 0; i < NTHREADS; i++) { err = thread_fork("wait test thread", exitfirstthread, NULL, i, &kid); if (err) { panic("waittest: thread_fork failed (%d)\n", err); } kprintf("Spawned pid %d\n", kid); pid_detach(kid); kids2[kids2_tail] = kid; kids2_tail = (kids2_tail+1) % NTHREADS; } for (i = 0; i < NTHREADS; i++) { kid = kids2[kids2_head]; kids2_head = (kids2_head+1) % NTHREADS; kprintf("Waiting for pid %d to V()...\n", kid); P(exitsems[i]); kprintf("Appears that pid %d P()'d\n", kid); kprintf("Waiting on pid %d...\n", kid); err = pid_join(kid, &status, 0); if (err) { kprintf("Pid %d waitpid error %d!\n", kid, err); } else { kprintf("Pid %d exit status: %d\n", kid, status); } } kprintf("\nWait test done.\n"); return 0; }