/* * pid_join - Store the exit status of the thread associated with * targetpid (in the status argument) as soon as it is available. * If the thread has not yet exited, curthread waits unless the flag * WNOHANG is sent. Return the pid of the joined thread on success or * a negative error code otherwise. */ int pid_join(pid_t targetpid, int *status, int flags) { int result = 0; /* Check if targetpid is valid. */ if (targetpid == INVALID_PID || targetpid == BOOTUP_PID) return -1 * EINVAL; /* Check if targetpid is caller. */ if (targetpid == curthread->t_pid) return -1 * EDEADLK; /* Obtain process information of target thread. */ struct pidinfo *pinfo; lock_acquire(pidlock); pinfo = pi_get(targetpid); /* No thread associated with targetpid could be found. */ if (pinfo == NULL) { result = -1 * ESRCH; goto out; } /* Check if target thread has been detached. */ if (pinfo->detached) { result = -1 * EINVAL; goto out; } if (!pinfo->pi_exited) { /* Target thread has not exited. */ if (flags == WNOHANG) goto out; else { /* Put thread to sleep. */ pinfo->waitingthreads++; DEBUG(DB_THREADS, "Parent waiting for %d\n", targetpid); cv_wait(pinfo->pi_cv, pidlock); pinfo->waitingthreads--; } } /* Store the exit status of the target thread in the caller */ if (status != NULL) *status = pinfo->pi_exitstatus; result = targetpid; /* Clean up pidinfo if there is no other thread waiting. */ if (pinfo->waitingthreads == 0) { pinfo->pi_ppid = INVALID_PID; pi_drop(targetpid); } out: lock_release(pidlock); return result; }
/* * pid_setexitstatus: Sets the exit status of this thread. Must only * be called if the thread actually had a pid assigned. Wakes up any * waiters and disposes of the piddata if nobody else is still using it. */ void pid_setexitstatus(int status) { struct pidinfo *us; int i; KASSERT(curthread->t_pid != INVALID_PID); lock_acquire(pidlock); /* First, disown all children */ for (i=0; i<PROCS_MAX; i++) { if (pidinfo[i]==NULL) { continue; } if (pidinfo[i]->pi_ppid == curthread->t_pid) { pidinfo[i]->pi_ppid = INVALID_PID; if (pidinfo[i]->pi_exited) { pi_drop(pidinfo[i]->pi_pid); } } } /* Now, wake up our parent */ us = pi_get(curthread->t_pid); KASSERT(us != NULL); us->pi_exitstatus = status; us->pi_exited = true; if (us->pi_ppid == INVALID_PID) { /* no parent */ pi_drop(curthread->t_pid); } else { cv_broadcast(us->pi_cv, pidlock); } lock_release(pidlock); }
/* * pid_detach - disavows interest in the child thread's exit status, so * it can be freed as soon as it exits. May only be called by the * parent thread. */ int pid_detach(pid_t childpid) { // Lock acquired lock_acquire(pidlock); // EINVAL: childpid is INVALID_PID or BOOTUP_PID. if(childpid == INVALID_PID || childpid == BOOTUP_PID || childpid < PID_MIN){ lock_release(pidlock); return -EINVAL; } // Get the pid info for the child pid struct pidinfo *child_pid; child_pid = pi_get(childpid); // ESRCH: No thread could be found corresponding to that specified by childpid. if(child_pid == NULL){ lock_release(pidlock); return -ESRCH; } // EINVAL: The thread childpid is already in the detached state. if(child_pid->pi_ppid == INVALID_PID){ lock_release(pidlock); return -EINVAL; } // EINVAL: The caller is not the parent of childpid. if(child_pid->pi_ppid != curthread->t_pid){ lock_release(pidlock); return -EINVAL; } // If child has exit when pid_detach has been called, then call drop function // to remove pidinfo and free its space. child_pid->pi_ppid = INVALID_PID; child_pid->detached = true; if(child_pid->pi_exited == true){ pi_drop(child_pid->pi_pid); } lock_release(pidlock); // On success return 0; }
/* * pid_detach - disavows interest in the child thread's exit status, so * it can be freed as soon as it exits. May only be called by the * parent thread. Returns 0 if the thread childpid is successfully placed * in the detached state. */ int pid_detach(pid_t childpid) { int err = 0; /* Check if childpid is valid. */ if (childpid == INVALID_PID || childpid == BOOTUP_PID) return EINVAL; /* Obtain process information of childs thread. */ struct pidinfo *pinfo; lock_acquire(pidlock); pinfo = pi_get(childpid); /* No thread associated with childpid could be found. */ if (pinfo == NULL) { err = ESRCH; goto out; } /* Check the childpid for the following: * (1) The caller is not the parent of childpid * (2) childpid has been joined at another thread * (3) childpid is already in the detached state */ if (pinfo->pi_ppid != curthread->t_pid || pinfo->waitingthreads > 0 || pinfo->detached) { err = EINVAL; goto out; } /* If thread already exited, drop associated pidinfo. * Otherwise, detach childpid by setting pi_ppid. */ if (pinfo->pi_exited) { pi_drop(childpid); } else { pinfo->detached = true; } out: lock_release(pidlock); return err; }
/* * pid_exit * - sets the exit status of this thread (i.e. curthread). * - disowns children. * - if dodetach is true, children are also detached. * - wakes any thread waiting for the curthread to exit. * - frees the PID and exit status if the curthread has been detached. * - must be called only if the thread has had a pid assigned. */ void pid_exit(int status, bool dodetach) { struct pidinfo *my_pi; // Implement me. Existing code simply sets the exit status. lock_acquire(pidlock); my_pi = pi_get(curthread->t_pid); KASSERT(my_pi != NULL); my_pi->pi_exitstatus = status; my_pi->pi_exited = true; /* Disown kids */ int i; struct pidinfo *current_kid; for(i = 0; i < my_pi->kids_tail; i++){ current_kid = pi_get(my_pi->kids[i]); if(current_kid != NULL){ current_kid->pi_ppid = INVALID_PID; if(dodetach){ lock_release(pidlock); pid_detach(current_kid->pi_pid); } } } //wake people up cv_broadcast(my_pi->pi_cv, pidlock); if(my_pi->detached){ my_pi->pi_ppid = INVALID_PID; pi_drop(my_pi->pi_pid); } if(lock_do_i_hold(pidlock)){ lock_release(pidlock); } }
/* * pid_exit * - sets the exit status of this thread (i.e. curthread). * - disowns children. * - if dodetach is true, children are also detached. * - wakes any thread waiting for the curthread to exit. * - frees the PID and exit status if the curthread has been detached. * - must be called only if the thread has had a pid assigned. */ void pid_exit(int status, bool dodetach) { // Lock aquired lock_acquire(pidlock); // Get the current thread pid struct pidinfo *my_pi; my_pi = pi_get(curthread->t_pid); KASSERT(my_pi != NULL); // Set the current pid exit to true and set the exitstatus my_pi->pi_exited = true; my_pi->pi_exitstatus = status; struct pidinfo *this_pid = NULL; // If dodetach is true, then we detach every child of this process if(dodetach){ for(int i =PID_MIN; i < PID_MAX; i++){ this_pid = pi_get((pid_t)i); if((this_pid != NULL) && (this_pid->pi_ppid == my_pi->pi_pid)){ lock_release(pidlock); pid_detach(this_pid->pi_pid); // Set Parent pid to invalid after detach lock_acquire(pidlock); this_pid->detached = true; } } } // tell the waiting thread about the exit status cv_broadcast(my_pi->pi_cv, pidlock); // if the pid we called is being detached, then we clear it in the // pid list if(my_pi->detached){ my_pi->pi_ppid = INVALID_PID; pi_drop(my_pi->pi_pid); } lock_release(pidlock); }
/* * pid_disown - disown any interest in waiting for a child's exit * status. */ void pid_disown(pid_t theirpid) { struct pidinfo *them; KASSERT(theirpid >= PID_MIN && theirpid <= PID_MAX); lock_acquire(pidlock); them = pi_get(theirpid); KASSERT(them != NULL); KASSERT(them->pi_ppid==curthread->t_pid); them->pi_ppid = INVALID_PID; if (them->pi_exited) { pi_drop(them->pi_pid); } lock_release(pidlock); }
/* * pid_exit * - sets the exit status of this thread (i.e. curthread). * - disowns children. * - if dodetach is true, children are also detached. * - wakes any thread waiting for the curthread to exit. * - frees the PID and exit status if the curthread has been detached. * - must be called only if the thread has had a pid assigned. */ void pid_exit(int status, bool dodetach) { struct pidinfo *my_pi; lock_acquire(pidlock); my_pi = pi_get(curthread->t_pid); KASSERT(my_pi != NULL); /* Thread has had a pid assigned */ KASSERT(my_pi->pi_pid == curthread->t_pid); my_pi->pi_exitstatus = status; my_pi->pi_exited = true; /* Disown children */ int i; for (i = 0; i < PROCS_MAX; i++){ if (pidinfo[i] != NULL && pidinfo[i]->pi_ppid == my_pi->pi_pid){ pidinfo[i]->pi_ppid = INVALID_PID; if (dodetach){ pid_detach(pidinfo[i]->pi_pid); } } } /* Wake up all threads waiting for curthread to exit */ if (my_pi->waitingThreads != 0){ cv_broadcast(my_pi->pi_cv, pidlock); } /* Free the PID and exit status if curthread is detached */ if (my_pi->detached){ my_pi->pi_ppid = INVALID_PID; pi_drop(my_pi->pi_pid); } lock_release(pidlock); }
/* * pid_detach - disavows interest in the child thread's exit status, so * it can be freed as soon as it exits. May only be called by the * parent thread. */ int pid_detach(pid_t childpid) { /* The childpid is invalid or bootup pid */ if (childpid == INVALID_PID || childpid == BOOTUP_PID){ return EINVAL; } struct pidinfo *pi; lock_acquire(pidlock); pi = pi_get(childpid); /* No thread could be found corresponding to that specified by childpid */ if (pi == NULL){ lock_release(pidlock); return ESRCH; } /* The thread childpid is already in detached state or the caller is not parent or the thread has joined another thread */ if (pi->detached || pi->pi_ppid != curthread->t_pid || pi->waitingThreads > 0){ lock_release(pidlock); return EINVAL; } /* If childpid already exited, drop it from process tabel else set it to detached state */ if (pi->pi_exited){ pi->pi_ppid = INVALID_PID; pi->pi_exited = true; pi_drop(pi->pi_pid); } else { pi->detached = true; } lock_release(pidlock); return 0; }
/* * pid_unalloc - unallocate a process id (allocated with pid_alloc) that * hasn't run yet. */ void pid_unalloc(pid_t theirpid) { struct pidinfo *them; KASSERT(theirpid >= PID_MIN && theirpid <= PID_MAX); lock_acquire(pidlock); them = pi_get(theirpid); KASSERT(them != NULL); KASSERT(them->pi_exited == false); KASSERT(them->pi_ppid == curthread->t_pid); /* keep pidinfo_destroy from complaining */ them->pi_exitstatus = 0xdead; them->pi_exited = true; them->pi_ppid = INVALID_PID; pi_drop(theirpid); lock_release(pidlock); }
/* * pid_exit * - sets the exit status of this thread (i.e. curthread). * - disowns children. * - if dodetach is true, children are also detached. * - wakes any thread waiting for the curthread to exit. * - frees the PID and exit status if the curthread has been detached. * - must be called only if the thread has had a pid assigned. */ void pid_exit(int status, bool dodetach) { struct pidinfo *my_pi; lock_acquire(pidlock); my_pi = pi_get(curthread->t_pid); KASSERT(my_pi != NULL && my_pi->pi_pid == curthread->t_pid); // Update the exit status of the current thread my_pi->pi_exited = true; my_pi->pi_exitstatus = status; // Disown children. pid_t pidindex = PID_MIN; while (pidindex <= PID_MAX) { struct pidinfo *pinfo = pi_get(pidindex); if (pinfo != NULL && pinfo->pi_ppid == my_pi->pi_pid) { pinfo->pi_ppid = INVALID_PID; if (dodetach) pinfo->detached = true; } pidindex++; } /* If current thread has been detached, discard the pid struct. */ if (my_pi->detached) { my_pi->pi_ppid = INVALID_PID; pi_drop(my_pi->pi_pid); } else { // Wakes any thread waiting for current thread. cv_broadcast(my_pi->pi_cv, pidlock); } lock_release(pidlock); }
/* * pid_join - returns the exit status of the thread associated with * targetpid (in the status argument) as soon as it is available. * If the thread has not yet exited, curthread waits unless the flag * WNOHANG is sent. * */ int pid_join(pid_t targetpid, int *status, int flags) { (void) flags; struct pidinfo *targetpi; pid_t temppid; //temporarly hold the pid so we can destroy targetpi int tempstatus; ///temporaly holds pid status lock_acquire(pidlock); //ERROR: if "targetpid" is INVALID_PID or BOOTUP_PID then return "EINVAL" if(targetpid == INVALID_PID || targetpid == BOOTUP_PID){ lock_release(pidlock); return EINVAL; } targetpi = pi_get(targetpid); //ERROR: if "targetpid" doesnt have a pid struct then return "ESRCH" if(targetpi == NULL){ lock_release(pidlock); return ESRCH; } //ERROR: if "targetpid" has been detached then return "EINVAL" else if(targetpi->detached){ lock_release(pidlock); return EINVAL; } //ERROR:if "targetpid" is pid of the thread that called PID_JOIN then return "EDEADLK". //MUST ADD ERROR else if(targetpi->pi_pid == curthread->t_pid){ lock_release(pidlock); return EDEADLK; } lock_release(pidlock); //check if pid has ALREADY exited if(targetpi->pi_exited){ //grab needed information if(!status){ temppid = targetpi->pi_pid; }else{ tempstatus = targetpi->pi_exitstatus; temppid = targetpi->pi_pid; } lock_acquire(pidlock); targetpi->pi_ppid = INVALID_PID; pi_drop(targetpi->pi_pid); lock_release(pidlock); }else{ //NOT EXITED if(flags == WNOHANG){ return 0; } //increase exit count lock_acquire(exitlock); targetpi->joined_pid += 1; lock_release(exitlock); lock_acquire(pidlock); //wait it exit cv_wait(targetpi->pi_cv, pidlock); lock_release(pidlock); //grab needed imformation if(!status){ temppid = targetpi->pi_pid; }else{ tempstatus = targetpi->pi_exitstatus; temppid = targetpi->pi_pid; } //decrease count lock_acquire(exitlock); targetpi->joined_pid -= 1; //if last person exiting, drop information if(targetpi->joined_pid==0){ lock_acquire(pidlock); targetpi->pi_exited = true; targetpi->pi_ppid = INVALID_PID; pi_drop(targetpi->pi_pid); lock_release(pidlock); } lock_release(exitlock); } *status = tempstatus; return temppid; }
/* * pid_detach - disavows interest in the child thread's exit status, so * it can be freed as soon as it exits. May only be called by the * parent thread. */ int pid_detach(pid_t childpid) { struct pidinfo *childpi; lock_acquire(pidlock); //ERROR: if "childpid" is INVALID_PID or BOOTUP_PID then return "EINVAL" if(childpid == INVALID_PID || childpid == BOOTUP_PID){ return EINVAL; } childpi = pi_get(childpid); /* 1) check to see "childpid" has exited */ //ERROR: if thread "childpid" could not be found return "ESRCH" if (childpi == NULL){ lock_release(pidlock); return ESRCH; } //ERROR: if thread "childpid" is already in deteached state then return "EINVAL" if(childpi->detached){ lock_release(pidlock); return EINVAL; } //ERROR: if the calling thread is not the parent of "childpid" then return "EINVAL" else if(childpi->pi_ppid != curthread->t_pid){ lock_release(pidlock); return EINVAL; } //ERROR: if "childpid" has already been joined by atleast one other thread return "EINVAL" else if(childpi->joined_pid == 1){ lock_release(pidlock); return EINVAL; } //check if pid has already exited, if so then frees it. if(childpi->pi_exited){ pi_drop(childpi->pi_pid); } //Put the childpid into the detached state else{ childpi->detached = true; } lock_release(pidlock); return 0; }
/* * Waits on a pid, returning the exit status when it's available. * status and ret are a kernel pointers, but pid/flags may come from * userland and may thus be maliciously invalid. * * status may be null, in which case the status is thrown away. ret * may only be null if WNOHANG is not set. */ int pid_wait(pid_t theirpid, int *status, int flags, pid_t *ret) { struct pidinfo *them; KASSERT(curthread->t_pid != INVALID_PID); /* Don't let a process wait for itself. */ if (theirpid == curthread->t_pid) { return EINVAL; } /* * We don't support the Unix meanings of negative pids or 0 * (0 is INVALID_PID) and other code may break on them, so * check now. */ if (theirpid == INVALID_PID || theirpid<0) { return EINVAL; } /* Only valid options */ if (flags != 0 && flags != WNOHANG) { return EINVAL; } lock_acquire(pidlock); them = pi_get(theirpid); if (them==NULL) { lock_release(pidlock); return ESRCH; } KASSERT(them->pi_pid==theirpid); /* Only allow waiting for own children. */ if (them->pi_ppid != curthread->t_pid) { lock_release(pidlock); return EPERM; } if (them->pi_exited == false) { if (flags == WNOHANG) { lock_release(pidlock); KASSERT(ret != NULL); *ret = 0; return 0; } /* don't need to loop on this */ cv_wait(them->pi_cv, pidlock); KASSERT(them->pi_exited == true); } if (status != NULL) { *status = them->pi_exitstatus; } if (ret != NULL) { /* * In Unix you can wait for any of several possible * processes by passing particular magic values of * pid. wait then returns the pid you actually * found. We don't support this, so always return the * pid we looked for. */ *ret = theirpid; } them->pi_ppid = 0; pi_drop(them->pi_pid); lock_release(pidlock); return 0; }