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:
parent
4ff323dd45
commit
5856e12e69
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=24848
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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++) {
|
||||
|
||||
|
@ -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,.
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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) {
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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 *));
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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 *));
|
||||
|
@ -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)
|
||||
|
@ -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:
|
||||
*
|
||||
|
Loading…
Reference in New Issue
Block a user