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.
This commit is contained in:
John Dyson 1997-04-13 01:48:35 +00:00
parent 4ff323dd45
commit 5856e12e69
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=24848
13 changed files with 153 additions and 25 deletions

View File

@ -39,7 +39,7 @@
* SUCH DAMAGE.
*
* from: @(#)pmap.c 7.7 (Berkeley) 5/12/91
* $Id: pmap.c,v 1.138 1997/02/22 09:32:40 peter Exp $
* $Id: pmap.c,v 1.139 1997/04/07 07:15:52 peter Exp $
*/
/*
@ -94,6 +94,8 @@
#include <vm/vm_pageout.h>
#include <vm/vm_pager.h>
#include <sys/user.h>
#include <machine/pcb.h>
#include <machine/cputypes.h>
#include <machine/md_var.h>
@ -2966,6 +2968,13 @@ pmap_mincore(pmap, addr)
return val;
}
void
pmap_activate(struct proc *p)
{
load_cr3(p->p_addr->u_pcb.pcb_cr3 =
vtophys(p->p_vmspace->vm_pmap.pm_pdir));
}
#if defined(PMAP_DEBUG)
pmap_pid_dump(int pid) {
pmap_t pmap;

View File

@ -39,7 +39,7 @@
* SUCH DAMAGE.
*
* from: @(#)pmap.c 7.7 (Berkeley) 5/12/91
* $Id: pmap.c,v 1.138 1997/02/22 09:32:40 peter Exp $
* $Id: pmap.c,v 1.139 1997/04/07 07:15:52 peter Exp $
*/
/*
@ -94,6 +94,8 @@
#include <vm/vm_pageout.h>
#include <vm/vm_pager.h>
#include <sys/user.h>
#include <machine/pcb.h>
#include <machine/cputypes.h>
#include <machine/md_var.h>
@ -2966,6 +2968,13 @@ pmap_mincore(pmap, addr)
return val;
}
void
pmap_activate(struct proc *p)
{
load_cr3(p->p_addr->u_pcb.pcb_cr3 =
vtophys(p->p_vmspace->vm_pmap.pm_pdir));
}
#if defined(PMAP_DEBUG)
pmap_pid_dump(int pid) {
pmap_t pmap;

View File

@ -26,7 +26,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id: imgact_coff.c,v 1.22 1997/03/23 03:34:09 bde Exp $
* $Id: imgact_coff.c,v 1.23 1997/04/01 08:39:01 bde Exp $
*/
#include <sys/param.h>
@ -299,7 +299,7 @@ exec_coff_imgact(imgp)
const struct aouthdr *ahdr;
const struct scnhdr *scns;
int i;
struct vmspace *vmspace = imgp->proc->p_vmspace;
struct vmspace *vmspace;
int nscns;
int error;
unsigned long text_offset = 0, text_address = 0, text_size = 0;
@ -339,6 +339,7 @@ exec_coff_imgact(imgp)
}
exec_new_vmspace(imgp);
vmspace = imgp->proc->p_vmspace;
for (i = 0; i < nscns; i++) {

View File

@ -28,7 +28,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id: imgact_linux.c,v 1.20 1997/02/22 09:38:18 peter Exp $
* $Id: imgact_linux.c,v 1.21 1997/04/01 08:39:05 bde Exp $
*/
#ifndef LKM
@ -65,7 +65,7 @@ exec_linux_imgact(imgp)
struct image_params *imgp;
{
const struct exec *a_out = (const struct exec *) imgp->image_header;
struct vmspace *vmspace = imgp->proc->p_vmspace;
struct vmspace *vmspace;
vm_offset_t vmaddr;
unsigned long virtual_offset, file_offset;
vm_offset_t buffer;
@ -122,6 +122,7 @@ exec_linux_imgact(imgp)
* Destroy old process VM and create a new one (with a new stack)
*/
exec_new_vmspace(imgp);
vmspace = imgp->proc->p_vmspace;
/*
* Check if file_offset page aligned,.

View File

@ -23,7 +23,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id$
* $Id: imgact_aout.c,v 1.33 1997/02/22 09:38:55 peter Exp $
*/
#include "opt_rlimit.h"
@ -55,7 +55,7 @@ exec_aout_imgact(imgp)
struct image_params *imgp;
{
const struct exec *a_out = (const struct exec *) imgp->image_header;
struct vmspace *vmspace = imgp->proc->p_vmspace;
struct vmspace *vmspace;
vm_offset_t vmaddr;
unsigned long virtual_offset;
unsigned long file_offset;
@ -146,6 +146,11 @@ exec_aout_imgact(imgp)
*/
exec_new_vmspace(imgp);
/*
* The vm space can be changed by exec_new_vmspace
*/
vmspace = imgp->proc->p_vmspace;
/*
* Map text/data read/execute
*/

View File

@ -26,7 +26,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id: imgact_elf.c,v 1.17 1997/03/23 03:36:16 bde Exp $
* $Id: imgact_elf.c,v 1.18 1997/04/01 10:41:48 bde Exp $
*/
#include "opt_rlimit.h"
@ -470,7 +470,7 @@ exec_elf_imgact(struct image_params *imgp)
const Elf32_Ehdr *hdr = (const Elf32_Ehdr *) imgp->image_header;
const Elf32_Phdr *phdr, *mapped_phdr = NULL;
Elf32_Auxargs *elf_auxargs = NULL;
struct vmspace *vmspace = imgp->proc->p_vmspace;
struct vmspace *vmspace;
vm_prot_t prot = 0;
u_long text_size = 0, data_size = 0;
u_long text_addr = 0, data_addr = 0;
@ -527,6 +527,8 @@ exec_elf_imgact(struct image_params *imgp)
exec_new_vmspace(imgp);
vmspace = imgp->proc->p_vmspace;
for (i = 0; i < hdr->e_phnum; i++) {
switch(phdr[i].p_type) {

View File

@ -6,7 +6,7 @@
* this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
* ----------------------------------------------------------------------------
*
* $Id$
* $Id: imgact_gzip.c,v 1.28 1997/02/22 09:38:57 peter Exp $
*
* This module handles execution of a.out files which have been run through
* "gzip". This saves diskspace, but wastes cpu-cycles and VM.
@ -149,7 +149,7 @@ static int
do_aout_hdr(struct imgact_gzip * gz)
{
int error;
struct vmspace *vmspace = gz->ip->proc->p_vmspace;
struct vmspace *vmspace;
vm_offset_t vmaddr;
/*
@ -227,6 +227,8 @@ do_aout_hdr(struct imgact_gzip * gz)
*/
exec_new_vmspace(gz->ip);
vmspace = gz->ip->proc->p_vmspace;
vmaddr = gz->virtual_offset;
error = vm_mmap(&vmspace->vm_map,

View File

@ -23,7 +23,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: kern_exec.c,v 1.58 1997/04/11 23:37:23 dyson Exp $
* $Id: kern_exec.c,v 1.59 1997/04/12 04:07:50 dyson Exp $
*/
#include <sys/param.h>
@ -58,6 +58,8 @@
#include <vm/vm_kern.h>
#include <vm/vm_extern.h>
#include <sys/user.h>
#include <machine/reg.h>
static int *exec_copyout_strings __P((struct image_params *));

View File

@ -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,11 +129,51 @@ 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

View File

@ -61,7 +61,7 @@
* any improvements or extensions that they make and grant Carnegie the
* rights to redistribute these changes.
*
* $Id$
* $Id: pmap.h,v 1.19 1997/02/22 09:48:04 peter Exp $
*/
/*
@ -129,6 +129,7 @@ void pmap_new_proc __P((struct proc *p));
void pmap_dispose_proc __P((struct proc *p));
void pmap_swapout_proc __P((struct proc *p));
void pmap_swapin_proc __P((struct proc *p));
void pmap_activate __P((struct proc *p));
#endif /* KERNEL */

View File

@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* @(#)vm_extern.h 8.2 (Berkeley) 1/12/94
* $Id: vm_extern.h,v 1.32 1997/04/06 02:30:56 dyson Exp $
* $Id: vm_extern.h,v 1.33 1997/04/07 07:16:04 peter Exp $
*/
#ifndef _VM_EXTERN_H_
@ -88,6 +88,8 @@ void vm_set_page_size __P((void));
void vmmeter __P((void));
struct vmspace *vmspace_alloc __P((vm_offset_t, vm_offset_t, int));
struct vmspace *vmspace_fork __P((struct vmspace *));
void vmspace_exec __P((struct proc *));
void vmspace_unshare __P((struct proc *));
void vmspace_free __P((struct vmspace *));
void vnode_pager_setsize __P((struct vnode *, vm_ooffset_t));
void vnode_pager_umount __P((struct mount *));

View File

@ -59,7 +59,7 @@
* any improvements or extensions that they make and grant Carnegie the
* rights to redistribute these changes.
*
* $Id: vm_glue.c,v 1.61 1997/02/22 09:48:17 peter Exp $
* $Id: vm_glue.c,v 1.62 1997/04/07 07:16:04 peter Exp $
*/
#include "opt_rlimit.h"
@ -211,14 +211,16 @@ vm_fork(p1, p2, flags)
pmap_t pvp;
vm_object_t upobj;
if (flags & RFMEM) {
p2->p_vmspace = p1->p_vmspace;
p1->p_vmspace->vm_refcnt++;
}
while ((cnt.v_free_count + cnt.v_cache_count) < cnt.v_free_min) {
VM_WAIT;
}
if (flags & RFMEM) {
p2->p_vmspace = p1->p_vmspace;
p1->p_vmspace->vm_refcnt++;
} else {
if ((flags & RFMEM) == 0) {
p2->p_vmspace = vmspace_fork(p1->p_vmspace);
if (p1->p_vmspace->vm_shm)

View File

@ -61,7 +61,7 @@
* any improvements or extensions that they make and grant Carnegie the
* rights to redistribute these changes.
*
* $Id: vm_map.c,v 1.74 1997/04/06 03:04:31 dyson Exp $
* $Id: vm_map.c,v 1.75 1997/04/07 07:16:05 peter Exp $
*/
/*
@ -2230,6 +2230,58 @@ vmspace_fork(vm1)
return (vm2);
}
/*
* Unshare the specified VM space for exec. If other processes are
* mapped to it, then create a new one. The new vmspace is null.
*/
void
vmspace_exec(struct proc *p) {
struct vmspace *oldvmspace = p->p_vmspace;
struct vmspace *newvmspace;
vm_map_t map = &p->p_vmspace->vm_map;
newvmspace = vmspace_alloc(map->min_offset, map->max_offset,
map->entries_pageable);
bcopy(&oldvmspace->vm_startcopy, &newvmspace->vm_startcopy,
(caddr_t) (newvmspace + 1) - (caddr_t) &newvmspace->vm_startcopy);
/*
* This code is written like this for prototype purposes. The
* goal is to avoid running down the vmspace here, but let the
* other process's that are still using the vmspace to finally
* run it down. Even though there is little or no chance of blocking
* here, it is a good idea to keep this form for future mods.
*/
vm_map_reference(&oldvmspace->vm_map);
vmspace_free(oldvmspace);
p->p_vmspace = newvmspace;
if (p == curproc)
pmap_activate(p);
vm_map_deallocate(&oldvmspace->vm_map);
}
/*
* Unshare the specified VM space for forcing COW. This
* is called by rfork, for the (RFMEM|RFPROC) == 0 case.
*/
void
vmspace_unshare(struct proc *p) {
struct vmspace *oldvmspace = p->p_vmspace;
struct vmspace *newvmspace;
if (oldvmspace->vm_refcnt == 1)
return;
newvmspace = vmspace_fork(oldvmspace);
vm_map_reference(&oldvmspace->vm_map);
vmspace_free(oldvmspace);
p->p_vmspace = newvmspace;
if (p == curproc)
pmap_activate(p);
vm_map_deallocate(&oldvmspace->vm_map);
}
/*
* vm_map_lookup:
*