aboutsummaryrefslogtreecommitdiff
path: root/sys/kern/kern_fork.c
diff options
context:
space:
mode:
authorJohn Dyson <dyson@FreeBSD.org>1997-04-13 01:48:35 +0000
committerJohn Dyson <dyson@FreeBSD.org>1997-04-13 01:48:35 +0000
commit5856e12e6950cdbbf627ab23ddc0d10006d8dd75 (patch)
treebddd380f285bf7d3a8f4c326934ea585723eec61 /sys/kern/kern_fork.c
parent4ff323dd450fa95949901235c99189a25477521d (diff)
downloadsrc-5856e12e6950cdbbf627ab23ddc0d10006d8dd75.tar.gz
src-5856e12e6950cdbbf627ab23ddc0d10006d8dd75.zip
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.
Notes
Notes: svn path=/head/; revision=24848
Diffstat (limited to 'sys/kern/kern_fork.c')
-rw-r--r--sys/kern/kern_fork.c48
1 files changed, 44 insertions, 4 deletions
diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c
index 1c78b262fe8f..f6be2068a8a9 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