diff options
author | dyson <dyson@FreeBSD.org> | 1997-04-13 01:48:35 +0000 |
---|---|---|
committer | dyson <dyson@FreeBSD.org> | 1997-04-13 01:48:35 +0000 |
commit | 61955ab83033e59cfabb8590ba5ccbf0669d9a47 (patch) | |
tree | 8d2081b02ed11701596e498b2013cf9f5a5625dd /sys/kern/kern_fork.c | |
parent | 438bdd8a9c9d390f13a4b05980c19b18e974d16c (diff) | |
download | FreeBSD-src-61955ab83033e59cfabb8590ba5ccbf0669d9a47.zip FreeBSD-src-61955ab83033e59cfabb8590ba5ccbf0669d9a47.tar.gz |
Fully implement vfork. Vfork is now much much faster than even our
fork. (On my machine, fork is about 240usecs, vfork is 78usecs.)
Implement rfork(!RFPROC !RFMEM), which allows a thread to divorce its memory
from the other threads of a group.
Implement rfork(!RFPROC RFCFDG), which closes all file descriptors, eliminating
possible existing shares with other threads/processes.
Implement rfork(!RFPROC RFFDG), which divorces the file descriptors for a
thread from the rest of the group.
Fix the case where a thread does an exec. It is almost nonsense for a thread
to modify the other threads address space by an exec, so we
now automatically divorce the address space before modifying it.
Diffstat (limited to 'sys/kern/kern_fork.c')
-rw-r--r-- | sys/kern/kern_fork.c | 48 |
1 files changed, 44 insertions, 4 deletions
diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c index 1c78b26..f6be206 100644 --- a/sys/kern/kern_fork.c +++ b/sys/kern/kern_fork.c @@ -36,7 +36,7 @@ * SUCH DAMAGE. * * @(#)kern_fork.c 8.6 (Berkeley) 4/8/94 - * $Id: kern_fork.c,v 1.33 1997/04/07 07:16:01 peter Exp $ + * $Id: kern_fork.c,v 1.34 1997/04/07 09:38:39 peter Exp $ */ #include "opt_ktrace.h" @@ -98,7 +98,7 @@ vfork(p, uap, retval) struct vfork_args *uap; int retval[]; { - return (fork1(p, (RFFDG|RFPROC|RFPPWAIT), retval)); + return (fork1(p, (RFFDG|RFPROC|RFPPWAIT|RFMEM), retval)); } /* ARGSUSED */ @@ -129,12 +129,52 @@ fork1(p1, flags, retval) fle_p ep ; ep = fork_list; - if ((flags & RFPROC) == 0) - return (EINVAL); + if ((flags & (RFFDG|RFCFDG)) == (RFFDG|RFCFDG)) return (EINVAL); /* + * Here we don't create a new process, but we divorce + * certain parts of a process from itself. + */ + if ((flags & RFPROC) == 0) { + + /* + * Divorce the memory, if it is shared, essentially + * this changes shared memory amongst threads, into + * COW locally. + */ + if ((flags & RFMEM) == 0) { + if (p1->p_vmspace->vm_refcnt > 1) { + vmspace_unshare(p1); + } + } + + /* + * Close all file descriptors. + */ + if (flags & RFCFDG) { + struct filedesc *fdtmp; + fdtmp = fdinit(p1); + fdfree(p1); + p1->p_fd = fdtmp; + } + + /* + * Unshare file descriptors (from parent.) + */ + if (flags & RFFDG) { + if (p1->p_fd->fd_refcnt > 1) { + struct filedesc *newfd; + newfd = fdcopy(p1); + fdfree(p1); + p1->p_fd = newfd; + } + } + return (0); + } + + /* * Although process entries are dynamically created, we still keep * a global limit on the maximum number we will create. Don't allow * a nonprivileged user to use the last process; don't let root |