Index: sys/kern/kern_fork.c =================================================================== RCS file: /home/ncvs/src/sys/kern/kern_fork.c,v retrieving revision 1.239 diff -u -r1.239 kern_fork.c --- sys/kern/kern_fork.c 13 Sep 2004 22:10:04 -0000 1.239 +++ sys/kern/kern_fork.c 17 Sep 2004 00:06:11 -0000 @@ -194,9 +194,8 @@ int pages; struct proc **procp; { - struct proc *p1, *p2, *pptr; + struct proc *p1, *p2, *p3, *pptr; uid_t uid; - struct proc *newproc; int ok, trypid; static int curfail, pidchecked = 0; static struct timeval lastfail; @@ -280,14 +279,11 @@ } /* Allocate new proc. */ - newproc = uma_zalloc(proc_zone, M_WAITOK); + p2 = uma_zalloc(proc_zone, M_WAITOK); #ifdef MAC - mac_init_proc(newproc); + mac_init_proc(p2); #endif - knlist_init(&newproc->p_klist, &newproc->p_mtx); - - /* We have to lock the process tree while we look for a pid. */ - sx_slock(&proctree_lock); + knlist_init(&p2->p_klist, &p2->p_mtx); /* * Although process entries are dynamically created, we still keep @@ -323,92 +319,6 @@ * are hard-limits as to the number of processes that can run. */ nprocs++; - - /* - * Find an unused process ID. We remember a range of unused IDs - * ready to use (from lastpid+1 through pidchecked-1). - * - * If RFHIGHPID is set (used during system boot), do not allocate - * low-numbered pids. - */ - trypid = lastpid + 1; - if (flags & RFHIGHPID) { - if (trypid < 10) - trypid = 10; - } else { - if (randompid) - trypid += arc4random() % randompid; - } -retry: - /* - * If the process ID prototype has wrapped around, - * restart somewhat above 0, as the low-numbered procs - * tend to include daemons that don't exit. - */ - if (trypid >= PID_MAX) { - trypid = trypid % PID_MAX; - if (trypid < 100) - trypid += 100; - pidchecked = 0; - } - if (trypid >= pidchecked) { - int doingzomb = 0; - - pidchecked = PID_MAX; - /* - * Scan the active and zombie procs to check whether this pid - * is in use. Remember the lowest pid that's greater - * than trypid, so we can avoid checking for a while. - */ - p2 = LIST_FIRST(&allproc); -again: - for (; p2 != NULL; p2 = LIST_NEXT(p2, p_list)) { - PROC_LOCK(p2); - while (p2->p_pid == trypid || - (p2->p_pgrp != NULL && - (p2->p_pgrp->pg_id == trypid || - (p2->p_session != NULL && - p2->p_session->s_sid == trypid)))) { - trypid++; - if (trypid >= pidchecked) { - PROC_UNLOCK(p2); - goto retry; - } - } - if (p2->p_pid > trypid && pidchecked > p2->p_pid) - pidchecked = p2->p_pid; - if (p2->p_pgrp != NULL) { - if (p2->p_pgrp->pg_id > trypid && - pidchecked > p2->p_pgrp->pg_id) - pidchecked = p2->p_pgrp->pg_id; - if (p2->p_session != NULL && - p2->p_session->s_sid > trypid && - pidchecked > p2->p_session->s_sid) - pidchecked = p2->p_session->s_sid; - } - PROC_UNLOCK(p2); - } - if (!doingzomb) { - doingzomb = 1; - p2 = LIST_FIRST(&zombproc); - goto again; - } - } - sx_sunlock(&proctree_lock); - - /* - * RFHIGHPID does not mess with the lastpid counter during boot. - */ - if (flags & RFHIGHPID) - pidchecked = 0; - else - lastpid = trypid; - - p2 = newproc; - p2->p_state = PRS_NEW; /* protect against others */ - p2->p_pid = trypid; - LIST_INSERT_HEAD(&allproc, p2, p_list); - LIST_INSERT_HEAD(PIDHASH(p2->p_pid), p2, p_hash); sx_xunlock(&allproc_lock); /* @@ -500,15 +410,7 @@ p2->p_flag = 0; if (p1->p_flag & P_PROFIL) startprofclock(p2); - mtx_lock_spin(&sched_lock); - p2->p_sflag = PS_INMEM; - /* - * Allow the scheduler to adjust the priority of the child and - * parent while we hold the sched_lock. - */ - sched_fork(td, td2); - mtx_unlock_spin(&sched_lock); p2->p_ucred = crhold(td->td_ucred); td2->td_ucred = crhold(p2->p_ucred); /* XXXKSE */ @@ -540,42 +442,109 @@ if (p2->p_textvp) vref(p2->p_textvp); + sx_xlock(&proctree_lock); + /* We have to lock the allproc list while we look for a pid. */ + sx_xlock(&allproc_lock); + /* - * Set up linkage for kernel based threading. + * Find an unused process ID. We remember a range of unused IDs + * ready to use (from lastpid+1 through pidchecked-1). + * + * If RFHIGHPID is set (used during system boot), do not allocate + * low-numbered pids. */ - if ((flags & RFTHREAD) != 0) { - mtx_lock(&ppeers_lock); - p2->p_peers = p1->p_peers; - p1->p_peers = p2; - p2->p_leader = p1->p_leader; - mtx_unlock(&ppeers_lock); - PROC_LOCK(p1->p_leader); - if ((p1->p_leader->p_flag & P_WEXIT) != 0) { - PROC_UNLOCK(p1->p_leader); - /* - * The task leader is exiting, so process p1 is - * going to be killed shortly. Since p1 obviously - * isn't dead yet, we know that the leader is either - * sending SIGKILL's to all the processes in this - * task or is sleeping waiting for all the peers to - * exit. We let p1 complete the fork, but we need - * to go ahead and kill the new process p2 since - * the task leader may not get a chance to send - * SIGKILL to it. We leave it on the list so that - * the task leader will wait for this new process - * to commit suicide. - */ - PROC_LOCK(p2); - psignal(p2, SIGKILL); - PROC_UNLOCK(p2); - } else - PROC_UNLOCK(p1->p_leader); + trypid = lastpid + 1; + if (flags & RFHIGHPID) { + if (trypid < 10) + trypid = 10; } else { - p2->p_peers = NULL; - p2->p_leader = p2; + if (randompid) + trypid += arc4random() % randompid; + } +retry: + /* + * If the process ID prototype has wrapped around, + * restart somewhat above 0, as the low-numbered procs + * tend to include daemons that don't exit. + */ + if (trypid >= PID_MAX) { + trypid = trypid % PID_MAX; + if (trypid < 100) + trypid += 100; + pidchecked = 0; } + if (trypid >= pidchecked) { + int doingzomb = 0; + + pidchecked = PID_MAX; + /* + * Scan the active and zombie procs to check whether this pid + * is in use. Remember the lowest pid that's greater + * than trypid, so we can avoid checking for a while. + */ + p3 = LIST_FIRST(&allproc); +again: + for (; p3 != NULL; p3 = LIST_NEXT(p3, p_list)) { + PROC_LOCK(p3); + while (p3->p_pid == trypid || + (p3->p_pgrp != NULL && + (p3->p_pgrp->pg_id == trypid || + (p3->p_session != NULL && + p3->p_session->s_sid == trypid)))) { + trypid++; + if (trypid >= pidchecked) { + PROC_UNLOCK(p3); + goto retry; + } + } + if (p3->p_pid > trypid && pidchecked > p3->p_pid) + pidchecked = p3->p_pid; + if (p3->p_pgrp != NULL) { + if (p3->p_pgrp->pg_id > trypid && + pidchecked > p3->p_pgrp->pg_id) + pidchecked = p3->p_pgrp->pg_id; + if (p3->p_session != NULL && + p3->p_session->s_sid > trypid && + pidchecked > p3->p_session->s_sid) + pidchecked = p3->p_session->s_sid; + } + PROC_UNLOCK(p3); + } + if (!doingzomb) { + doingzomb = 1; + p3 = LIST_FIRST(&zombproc); + goto again; + } + } + + /* + * RFHIGHPID does not mess with the lastpid counter during boot. + */ + if (flags & RFHIGHPID) + pidchecked = 0; + else + lastpid = trypid; + + p2->p_state = PRS_NEW; /* protect against others */ + p2->p_pid = trypid; + LIST_INSERT_HEAD(&allproc, p2, p_list); + LIST_INSERT_HEAD(PIDHASH(p2->p_pid), p2, p_hash); + sx_xunlock(&allproc_lock); + + /* + * Attach the new process to its parent. + * + * If RFNOWAIT is set, the newly created process becomes a child + * of init. This effectively disassociates the child from the + * parent. + */ + if (flags & RFNOWAIT) + pptr = initproc; + else + pptr = p1; + p2->p_pptr = pptr; + LIST_INSERT_HEAD(&pptr->p_children, p2, p_sibling); - sx_xlock(&proctree_lock); PGRP_LOCK(p1->p_pgrp); PROC_LOCK(p2); PROC_LOCK(p1); @@ -634,20 +603,42 @@ _PHOLD(p1); PROC_UNLOCK(p1); + sx_xunlock(&proctree_lock); + /* - * Attach the new process to its parent. - * - * If RFNOWAIT is set, the newly created process becomes a child - * of init. This effectively disassociates the child from the - * parent. + * Set up linkage for kernel based threading. */ - if (flags & RFNOWAIT) - pptr = initproc; - else - pptr = p1; - p2->p_pptr = pptr; - LIST_INSERT_HEAD(&pptr->p_children, p2, p_sibling); - sx_xunlock(&proctree_lock); + if ((flags & RFTHREAD) != 0) { + mtx_lock(&ppeers_lock); + p2->p_peers = p1->p_peers; + p1->p_peers = p2; + p2->p_leader = p1->p_leader; + mtx_unlock(&ppeers_lock); + PROC_LOCK(p1->p_leader); + if ((p1->p_leader->p_flag & P_WEXIT) != 0) { + PROC_UNLOCK(p1->p_leader); + /* + * The task leader is exiting, so process p1 is + * going to be killed shortly. Since p1 obviously + * isn't dead yet, we know that the leader is either + * sending SIGKILL's to all the processes in this + * task or is sleeping waiting for all the peers to + * exit. We let p1 complete the fork, but we need + * to go ahead and kill the new process p2 since + * the task leader may not get a chance to send + * SIGKILL to it. We leave it on the list so that + * the task leader will wait for this new process + * to commit suicide. + */ + PROC_LOCK(p2); + psignal(p2, SIGKILL); + PROC_UNLOCK(p2); + } else + PROC_UNLOCK(p1->p_leader); + } else { + p2->p_peers = NULL; + p2->p_leader = p2; + } /* Inform accounting that we have forked. */ p2->p_acflag = AFORK; @@ -687,10 +678,18 @@ /* * Set the child start time and mark the process as being complete. */ + PROC_LOCK(p2); + PROC_LOCK(p1); microuptime(&p2->p_stats->p_start); mtx_lock_spin(&sched_lock); + p2->p_sflag = PS_INMEM; p2->p_state = PRS_NORMAL; - + /* + * Allow the scheduler to adjust the priority of the child and + * parent while we hold the sched_lock. + */ + sched_fork(td, td2); + PROC_UNLOCK(p2); /* * If RFSTOPPED not requested, make child runnable and add to * run queue. @@ -704,7 +703,6 @@ /* * Now can be swapped. */ - PROC_LOCK(p1); _PRELE(p1); /* @@ -739,15 +737,14 @@ *procp = p2; return (0); fail: - sx_sunlock(&proctree_lock); if (ppsratecheck(&lastfail, &curfail, 1)) printf("maxproc limit exceeded by uid %i, please see tuning(7) and login.conf(5).\n", uid); sx_xunlock(&allproc_lock); #ifdef MAC - mac_destroy_proc(newproc); + mac_destroy_proc(p2); #endif - uma_zfree(proc_zone, newproc); + uma_zfree(proc_zone, p2); if (p1->p_flag & P_HADTHREADS) { PROC_LOCK(p1); thread_single_end();