summaryrefslogtreecommitdiffstats
path: root/sys/kern/kern_fork.c
diff options
context:
space:
mode:
authorjasone <jasone@FreeBSD.org>2000-09-07 01:33:02 +0000
committerjasone <jasone@FreeBSD.org>2000-09-07 01:33:02 +0000
commit769e0f974d8929599ba599ac496510fffc90ff34 (patch)
tree9387522900085835de81e7830e570ef3f6b3ea80 /sys/kern/kern_fork.c
parentacf1927de02afda4855ec278b1128fd9446405ea (diff)
downloadFreeBSD-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.c80
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.
OpenPOWER on IntegriCloud