diff options
author | jasone <jasone@FreeBSD.org> | 2000-09-07 01:33:02 +0000 |
---|---|---|
committer | jasone <jasone@FreeBSD.org> | 2000-09-07 01:33:02 +0000 |
commit | 769e0f974d8929599ba599ac496510fffc90ff34 (patch) | |
tree | 9387522900085835de81e7830e570ef3f6b3ea80 /sys/kern/kern_fork.c | |
parent | acf1927de02afda4855ec278b1128fd9446405ea (diff) | |
download | FreeBSD-src-769e0f974d8929599ba599ac496510fffc90ff34.zip FreeBSD-src-769e0f974d8929599ba599ac496510fffc90ff34.tar.gz |
Major update to the way synchronization is done in the kernel. Highlights
include:
* Mutual exclusion is used instead of spl*(). See mutex(9). (Note: The
alpha port is still in transition and currently uses both.)
* Per-CPU idle processes.
* Interrupts are run in their own separate kernel threads and can be
preempted (i386 only).
Partially contributed by: BSDi (BSD/OS)
Submissions by (at least): cp, dfr, dillon, grog, jake, jhb, sheldonh
Diffstat (limited to 'sys/kern/kern_fork.c')
-rw-r--r-- | sys/kern/kern_fork.c | 80 |
1 files changed, 55 insertions, 25 deletions
diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c index f24c97e..0aa31ab 100644 --- a/sys/kern/kern_fork.c +++ b/sys/kern/kern_fork.c @@ -52,6 +52,7 @@ #include <sys/resourcevar.h> #include <sys/vnode.h> #include <sys/acct.h> +#include <sys/ktr.h> #include <sys/ktrace.h> #include <sys/unistd.h> #include <sys/jail.h> @@ -65,6 +66,8 @@ #include <sys/user.h> +#include <machine/mutex.h> + static MALLOC_DEFINE(M_ATFORK, "atfork", "atfork callback"); static int fast_vfork = 1; @@ -131,7 +134,8 @@ rfork(p, uap) int error; struct proc *p2; - error = fork1(p, uap->flags, &p2); + /* mask kernel only flags out of the user flags */ + error = fork1(p, uap->flags & ~RFKERNELONLY, &p2); if (error == 0) { p->p_retval[0] = p2 ? p2->p_pid : 0; p->p_retval[1] = 0; @@ -177,17 +181,19 @@ SYSCTL_PROC(_kern, OID_AUTO, randompid, CTLTYPE_INT|CTLFLAG_RW, int fork1(p1, flags, procp) - struct proc *p1; + struct proc *p1; /* parent proc */ int flags; - struct proc **procp; + struct proc **procp; /* child proc */ { struct proc *p2, *pptr; uid_t uid; struct proc *newproc; + int trypid; int ok; static int pidchecked = 0; struct forklist *ep; + /* Can't copy and clear */ if ((flags & (RFFDG|RFCFDG)) == (RFFDG|RFCFDG)) return (EINVAL); @@ -278,47 +284,56 @@ fork1(p1, flags, procp) /* * Find an unused process ID. We remember a range of unused IDs * ready to use (from nextpid+1 through pidchecked-1). + * + * If RFHIGHPID is set (used during system boot), do not allocate + * low-numbered pids. */ - nextpid++; + trypid = nextpid + 1; + if (flags & RFHIGHPID) { + if (trypid < 10) { + trypid = 10; + } + } else { if (randompid) - nextpid += arc4random() % 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 (nextpid >= PID_MAX) { - nextpid = nextpid % PID_MAX; - if (nextpid < 100) - nextpid += 100; + if (trypid >= PID_MAX) { + trypid = trypid % PID_MAX; + if (trypid < 100) + trypid += 100; pidchecked = 0; } - if (nextpid >= pidchecked) { + 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 nextpid, so we can avoid checking for a while. + * than trypid, so we can avoid checking for a while. */ p2 = LIST_FIRST(&allproc); again: for (; p2 != 0; p2 = LIST_NEXT(p2, p_list)) { - while (p2->p_pid == nextpid || - p2->p_pgrp->pg_id == nextpid || - p2->p_session->s_sid == nextpid) { - nextpid++; - if (nextpid >= pidchecked) + while (p2->p_pid == trypid || + p2->p_pgrp->pg_id == trypid || + p2->p_session->s_sid == trypid) { + trypid++; + if (trypid >= pidchecked) goto retry; } - if (p2->p_pid > nextpid && pidchecked > p2->p_pid) + if (p2->p_pid > trypid && pidchecked > p2->p_pid) pidchecked = p2->p_pid; - if (p2->p_pgrp->pg_id > nextpid && + if (p2->p_pgrp->pg_id > trypid && pidchecked > p2->p_pgrp->pg_id) pidchecked = p2->p_pgrp->pg_id; - if (p2->p_session->s_sid > nextpid && + if (p2->p_session->s_sid > trypid && pidchecked > p2->p_session->s_sid) pidchecked = p2->p_session->s_sid; } @@ -331,11 +346,19 @@ again: p2 = newproc; p2->p_stat = SIDL; /* protect against others */ - p2->p_pid = nextpid; + p2->p_pid = trypid; LIST_INSERT_HEAD(&allproc, p2, p_list); LIST_INSERT_HEAD(PIDHASH(p2->p_pid), p2, p_hash); /* + * RFHIGHPID does not mess with the nextpid counter during boot. + */ + if (flags & RFHIGHPID) + pidchecked = 0; + else + nextpid = trypid; + + /* * Make a proc table entry for the new process. * Start by zeroing the section of proc that is zero-initialized, * then copy the section that is copied directly from the parent. @@ -456,6 +479,8 @@ again: p2->p_pptr = pptr; LIST_INSERT_HEAD(&pptr->p_children, p2, p_sibling); LIST_INIT(&p2->p_children); + LIST_INIT(&p2->p_heldmtx); + LIST_INIT(&p2->p_contested); #ifdef KTRACE /* @@ -496,14 +521,19 @@ again: } /* - * Make child runnable and add to run queue. + * If RFSTOPPED not requested, make child runnable and add to + * run queue. */ microtime(&(p2->p_stats->p_start)); p2->p_acflag = AFORK; - (void) splhigh(); - p2->p_stat = SRUN; - setrunqueue(p2); - (void) spl0(); + if ((flags & RFSTOPPED) == 0) { + splhigh(); + mtx_enter(&sched_lock, MTX_SPIN); + p2->p_stat = SRUN; + setrunqueue(p2); + mtx_exit(&sched_lock, MTX_SPIN); + spl0(); + } /* * Now can be swapped. |