summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--share/man/man9/Makefile5
-rw-r--r--share/man/man9/fork1.976
-rw-r--r--share/man/man9/thread_fork.9109
-rw-r--r--sys/arch/alpha/alpha/vm_machdep.c33
-rw-r--r--sys/arch/amd64/amd64/vm_machdep.c12
-rw-r--r--sys/arch/arm/arm/vm_machdep.c38
-rw-r--r--sys/arch/arm64/arm64/vm_machdep.c10
-rw-r--r--sys/arch/hppa/hppa/vm_machdep.c8
-rw-r--r--sys/arch/i386/i386/vm_machdep.c13
-rw-r--r--sys/arch/m88k/m88k/vm_machdep.c19
-rw-r--r--sys/arch/mips64/mips64/vm_machdep.c16
-rw-r--r--sys/arch/powerpc/powerpc/vm_machdep.c10
-rw-r--r--sys/arch/sh/sh/vm_machdep.c29
-rw-r--r--sys/arch/sparc64/sparc64/vm_machdep.c34
-rw-r--r--sys/kern/init_main.c5
-rw-r--r--sys/kern/kern_fork.c401
-rw-r--r--sys/kern/kern_kthread.c4
-rw-r--r--sys/kern/kern_sched.c4
-rw-r--r--sys/sys/proc.h12
-rw-r--r--sys/uvm/uvm_extern.h4
20 files changed, 479 insertions, 363 deletions
diff --git a/share/man/man9/Makefile b/share/man/man9/Makefile
index bf0a01351e4..8de8c6b5d87 100644
--- a/share/man/man9/Makefile
+++ b/share/man/man9/Makefile
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.285 2017/01/24 00:58:55 mpi Exp $
+# $OpenBSD: Makefile,v 1.286 2017/02/12 04:55:08 guenther Exp $
# $NetBSD: Makefile,v 1.4 1996/01/09 03:23:01 thorpej Exp $
# Makefile for section 9 (kernel function and variable) manual pages.
@@ -34,7 +34,8 @@ MAN= aml_evalnode.9 atomic_add_int.9 atomic_cas_uint.9 \
sensor_attach.9 \
spl.9 srp_enter.9 srpl_rc_init.9 startuphook_establish.9 \
socreate.9 sosplice.9 style.9 syscall.9 sysctl_int.9 \
- task_add.9 tc_init.9 tfind.9 time_second.9 timeout.9 tsleep.9 tvtohz.9 \
+ task_add.9 tc_init.9 tfind.9 thread_fork.9 \
+ time_second.9 timeout.9 tsleep.9 tvtohz.9 \
uiomove.9 uvm.9 usb_add_task.9 usbd_close_pipe.9 usbd_open_pipe.9 \
usbd_ref_wait.9 usbd_transfer.9 vfs.9 vfs_busy.9 \
vfs_cache.9 vaccess.9 vclean.9 vcount.9 vdevgone.9 vfinddev.9 vflush.9 \
diff --git a/share/man/man9/fork1.9 b/share/man/man9/fork1.9
index 82a8f8f46a7..c22c9800aa4 100644
--- a/share/man/man9/fork1.9
+++ b/share/man/man9/fork1.9
@@ -1,4 +1,4 @@
-.\" $OpenBSD: fork1.9,v 1.28 2017/01/24 07:59:58 jmc Exp $
+.\" $OpenBSD: fork1.9,v 1.29 2017/02/12 04:55:08 guenther Exp $
.\" $NetBSD: fork1.9,v 1.3 1999/03/16 00:40:47 garbled Exp $
.\"
.\" Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -29,7 +29,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd $Mdocdate: January 24 2017 $
+.Dd $Mdocdate: February 12 2017 $
.Dt FORK1 9
.Os
.Sh NAME
@@ -42,8 +42,6 @@
.Fo fork1
.Fa "struct proc *p1"
.Fa "int flags"
-.Fa "void *stack"
-.Fa "pid_t *tidptr"
.Fa "void (*func)(void *)"
.Fa "void *arg"
.Fa "register_t *retval"
@@ -53,10 +51,10 @@
.Fn fork1
creates a new process out of
.Ar p1 ,
-which should be the current process.
+which should be the current thread.
This function is used primarily to implement the
-.Xr fork 2 ,
-.Xr __tfork 3 ,
+.Xr fork 2
+and
.Xr vfork 2
system calls, as well as the
.Xr kthread_create 9
@@ -77,11 +75,6 @@ The call is done by the
.Xr vfork 2
system call.
Used only for statistics.
-.It Dv FORK_TFORK
-The call is done by the
-.Xr __tfork 3
-system call.
-Used only for statistics.
.It Dv FORK_PPWAIT
Suspend the parent process until the child is terminated (by calling
.Xr _exit 2
@@ -93,7 +86,7 @@ fdshare().
The default behavior is to copy the table through
fdcopy().
.It Dv FORK_IDLE
-The child will be left in the
+The new thread will be left in the
.Dv SIDL
state.
The default behavior is to make it runnable and add it to the run queue.
@@ -116,62 +109,37 @@ must also be set.
.It Dv FORK_PTRACE
The child will start with tracing enabled, as if
ptrace(PT_TRACE_ME, 0, 0, 0) had been invoked in the child.
-.It Dv FORK_THREAD
-The child will instead be a kernel-level thread in the same process
-as the parent.
-.Dv FORK_SHAREFILES ,
-.Dv FORK_SHAREVM ,
-and
-.Dv FORK_SIGHAND
-must also be set.
.El
.Pp
If
-.Fa stack
+.Fa func
is not
.Dv NULL ,
-it will be used as the initial value of the child's stack pointer,
-instead of using the child's copy of the parent's stack.
+the new thread will begin execution by calling this function.
+It defaults to child_return, which returns to userland.
.Pp
If
-.Fa tidptr
+.Fa arg
is not
.Dv NULL ,
-the PID of the child process will be written there in the parent
-on success.
-This is guaranteed to be done before
-the child process is started.
+it is the argument to the previous function.
+It defaults to a pointer to the new thread.
.Pp
If
.Fa retval
is not
.Dv NULL ,
-it will hold the following values after successful completion
-of the fork operation:
-.Bl -tag -width retval[0]
-.It Fa retval[0]
-This will contain the PID of the child process.
-.It Fa retval[1]
-In the parent process, this will contain the value 0.
-In the child process, this will contain 1.
-.El
+the PID of the child process will be stored in
+.Fa *retval
+on successful completion.
.Pp
If
-.Fa func
+.Fa rnewprocp
is not
.Dv NULL ,
-the new process will begin execution by calling this function.
-It defaults to child_return, which returns to userland.
-.Pp
-If
-.Fa arg
-is not
-.Dv NULL ,
-it is the argument to the previous function.
-It defaults to a pointer to the new process.
-.Pp
-The newly created process is returned through
-.Fa *rnewprocp .
+the newly created thread is stored in
+.Fa *rnewprocp
+on successful completion.
.Sh RETURN VALUES
Upon successful completion of the fork operation,
.Fn fork1
@@ -179,18 +147,20 @@ returns 0.
Otherwise, the following error values are returned:
.Bl -tag -width [EAGAIN]
.It Bq Er EAGAIN
-The limit on the total number of system processes would be exceeded.
+The system limits on the total number of threads or processes would
+be exceeded.
.It Bq Er EAGAIN
The limit
.Dv RLIMIT_NPROC
on the total number of processes under execution by this
user id would be exceeded.
+.It Bq Er ENOMEM
+There is insufficient swap space for the new thread.
.El
.Sh SEE ALSO
.Xr execve 2 ,
.Xr fork 2 ,
.Xr vfork 2 ,
-.Xr __tfork 3 ,
.Xr kthread_create 9 ,
.Xr psignal 9 ,
.Xr tfind 9
diff --git a/share/man/man9/thread_fork.9 b/share/man/man9/thread_fork.9
new file mode 100644
index 00000000000..7d0e2991799
--- /dev/null
+++ b/share/man/man9/thread_fork.9
@@ -0,0 +1,109 @@
+.\" $OpenBSD: thread_fork.9,v 1.1 2017/02/12 04:55:08 guenther Exp $
+.\" $NetBSD: fork1.9,v 1.3 1999/03/16 00:40:47 garbled Exp $
+.\"
+.\" Copyright (c) 1998 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+.\" NASA Ames Research Center.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd $Mdocdate: February 12 2017 $
+.Dt THREAD_FORK 9
+.Os
+.Sh NAME
+.Nm thread_fork
+.Nd create a new thread inside a process
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/proc.h
+.Ft int
+.Fo thread_fork
+.Fa "struct proc *p1"
+.Fa "void *stack"
+.Fa "void *tcb"
+.Fa "pid_t *tidptr"
+.Fa "register_t *retval"
+.Fc
+.Sh DESCRIPTION
+.Fn thread_fork
+creates a new thread out of
+.Ar p1 ,
+which should be the current thread.
+This function is used to implement the
+.Xr __tfork 3
+system call.
+.Pp
+.Fa stack ,
+which must not be
+.Dv NULL ,
+will be used as the initial value of the new thread's stack pointer.
+.Pp
+If
+.Fa tcb ,
+is not
+.Dv NULL ,
+it will be used as the initial address of the new thread's TCB
+(thread control block).
+.Pp
+If
+.Fa tidptr
+is not
+.Dv NULL ,
+the TID of the new thread will be copied out there on success.
+This is guaranteed to be done before the new thread is started.
+.Pp
+.Fa retval ,
+which must not be
+.Dv NULL ,
+the TID of the new thread will be stored in
+.Fa *retval
+on successful completion.
+.Sh RETURN VALUES
+Upon successful completion of the operation,
+.Fn thread_fork
+returns 0.
+Otherwise, the following error values are returned:
+.Bl -tag -width [EAGAIN]
+.It Bq Er EAGAIN
+The system limit on the total number of threads would be exceeded.
+.It Bq Er ENOMEM
+There is insufficient swap space for the new thread.
+.It Bq Er EINVAL
+The
+.Fa stack
+argument was
+.Dv NULL .
+.El
+.Sh SEE ALSO
+.Xr fork 2 ,
+.Xr __get_tcb 3 ,
+.Xr __tfork 3 ,
+.Xr tfind 9
+.Sh HISTORY
+The
+.Fn thread_fork
+function
+appeared in
+.Ox 6.1 .
diff --git a/sys/arch/alpha/alpha/vm_machdep.c b/sys/arch/alpha/alpha/vm_machdep.c
index 7ff834b9ec4..48f6ec11f2a 100644
--- a/sys/arch/alpha/alpha/vm_machdep.c
+++ b/sys/arch/alpha/alpha/vm_machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vm_machdep.c,v 1.45 2016/10/04 05:55:09 guenther Exp $ */
+/* $OpenBSD: vm_machdep.c,v 1.46 2017/02/12 04:55:08 guenther Exp $ */
/* $NetBSD: vm_machdep.c,v 1.55 2000/03/29 03:49:48 simonb Exp $ */
/*
@@ -71,24 +71,19 @@ cpu_exit(p)
* Copy and update the pcb and trap frame, making the child ready to run.
*
* Rig the child's kernel stack so that it will start out in
- * switch_trampoline() and call child_return() with p2 as an
- * argument. This causes the newly-created child process to go
- * directly to user level with an apparent return value of 0 from
- * fork(), while the parent process returns normally.
+ * proc_trampoline() and call 'func' with 'arg' as an argument.
+ * For normal processes this is child_return(), which causes the
+ * child to go directly to user level with an apparent return value
+ * of 0 from fork(), while the parent process returns normally.
+ * For kernel threads this will be a function that never return.
*
- * p1 is the process being forked;
- *
- * If an alternate user-level stack is requested (with non-NULL stack arg),
- * set up the user stack pointer
- * accordingly.
+ * An alternate user-level stack or TCB can be requested by passing
+ * a non-NULL value; these are poked into the PCB so they're in
+ * effect at the initial return to userspace.
*/
void
-cpu_fork(p1, p2, stack, stacksize, func, arg)
- struct proc *p1, *p2;
- void *stack;
- size_t stacksize;
- void (*func)(void *);
- void *arg;
+cpu_fork(struct proc *p1, struct proc *p2, void *stack, void *tcb,
+ void (*func)(void *), void *arg)
{
struct user *up = p2->p_addr;
@@ -115,15 +110,17 @@ cpu_fork(p1, p2, stack, stacksize, func, arg)
/*
* Copy pcb and stack from proc p1 to p2.
- * If specified, give the child a different stack.
+ * If specified, give the child a different stack and/or TCB.
* We do this as cheaply as possible, copying only the active
* part of the stack. The stack and pcb need to agree;
*/
up->u_pcb = p1->p_addr->u_pcb;
if (stack != NULL)
- up->u_pcb.pcb_hw.apcb_usp = (u_long)stack + stacksize;
+ up->u_pcb.pcb_hw.apcb_usp = (u_long)stack;
else
up->u_pcb.pcb_hw.apcb_usp = alpha_pal_rdusp();
+ if (tcb != NULL)
+ up->u_pcb.pcb_hw.apcb_unique = (unsigned long)tcb;
/*
* Arrange for a non-local goto when the new process
diff --git a/sys/arch/amd64/amd64/vm_machdep.c b/sys/arch/amd64/amd64/vm_machdep.c
index 2b402e5ec74..42dc47f92ea 100644
--- a/sys/arch/amd64/amd64/vm_machdep.c
+++ b/sys/arch/amd64/amd64/vm_machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vm_machdep.c,v 1.35 2016/04/03 19:49:35 guenther Exp $ */
+/* $OpenBSD: vm_machdep.c,v 1.36 2017/02/12 04:55:08 guenther Exp $ */
/* $NetBSD: vm_machdep.c,v 1.1 2003/04/26 18:39:33 fvdl Exp $ */
/*-
@@ -66,10 +66,10 @@ void setredzone(struct proc *);
* Finish a fork operation, with process p2 nearly set up.
* Copy and update the kernel stack and pcb, making the child
* ready to run, and marking it so that it can return differently
- * than the parent. Returns 1 in the child process, 0 in the parent.
+ * than the parent.
*/
void
-cpu_fork(struct proc *p1, struct proc *p2, void *stack, size_t stacksize,
+cpu_fork(struct proc *p1, struct proc *p2, void *stack, void *tcb,
void (*func)(void *), void *arg)
{
struct pcb *pcb = &p2->p_addr->u_pcb;
@@ -112,10 +112,12 @@ cpu_fork(struct proc *p1, struct proc *p2, void *stack, size_t stacksize,
setredzone(p2);
/*
- * If specified, give the child a different stack.
+ * If specified, give the child a different stack and/or TCB
*/
if (stack != NULL)
- tf->tf_rsp = (u_int64_t)stack + stacksize;
+ tf->tf_rsp = (u_int64_t)stack;
+ if (tcb != NULL)
+ pcb->pcb_fsbase = (u_int64_t)tcb;
sf = (struct switchframe *)tf - 1;
sf->sf_r12 = (u_int64_t)func;
diff --git a/sys/arch/arm/arm/vm_machdep.c b/sys/arch/arm/arm/vm_machdep.c
index 38dba6d7d77..9b2a00a92f5 100644
--- a/sys/arch/arm/arm/vm_machdep.c
+++ b/sys/arch/arm/arm/vm_machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vm_machdep.c,v 1.18 2016/07/31 09:18:01 jsg Exp $ */
+/* $OpenBSD: vm_machdep.c,v 1.19 2017/02/12 04:55:08 guenther Exp $ */
/* $NetBSD: vm_machdep.c,v 1.31 2004/01/04 11:33:29 jdolecek Exp $ */
/*
@@ -80,24 +80,21 @@ extern void proc_trampoline (void);
/*
* Finish a fork operation, with process p2 nearly set up.
* Copy and update the pcb and trap frame, making the child ready to run.
- *
- * Rig the child's kernel stack so that it will start out in
- * proc_trampoline() and call child_return() with p2 as an
- * argument. This causes the newly-created child process to go
- * directly to user level with an apparent return value of 0 from
- * fork(), while the parent process returns normally.
*
- * p1 is the process being forked; if p1 == &proc0, we are creating
- * a kernel thread, and the return path and argument are specified with
- * `func' and `arg'.
+ * Rig the child's kernel stack so that it will start out in
+ * proc_trampoline() and call 'func' with 'arg' as an argument.
+ * For normal processes this is child_return(), which causes the
+ * child to go directly to user level with an apparent return value
+ * of 0 from fork(), while the parent process returns normally.
+ * For kernel threads this will be a function that never return.
*
- * If an alternate user-level stack is requested (with non-zero values
- * in both the stack and stacksize args), set up the user stack pointer
- * accordingly.
+ * An alternate user-level stack or TCB can be requested by passing
+ * a non-NULL value; these are poked into the PCB so they're in
+ * effect at the initial return to userspace.
*/
void
-cpu_fork(struct proc *p1, struct proc *p2, void *stack,
- size_t stacksize, void (*func) (void *), void *arg)
+cpu_fork(struct proc *p1, struct proc *p2, void *stack, void *tcb,
+ void (*func)(void *), void *arg)
{
struct pcb *pcb = (struct pcb *)&p2->p_addr->u_pcb;
struct trapframe *tf;
@@ -130,16 +127,17 @@ cpu_fork(struct proc *p1, struct proc *p2, void *stack,
pmap_activate(p2);
- p2->p_addr->u_pcb.pcb_tf = tf =
- (struct trapframe *)pcb->pcb_un.un_32.pcb32_sp - 1;
+ pcb->pcb_tf = tf = (struct trapframe *)pcb->pcb_un.un_32.pcb32_sp - 1;
*tf = *p1->p_addr->u_pcb.pcb_tf;
/*
- * If specified, give the child a different stack (make sure
- * it's 8-byte aligned).
+ * If specified, give the child a different stack and/or TCB.
+ * Enforce 8-byte alignment on the stack.
*/
if (stack != NULL)
- tf->tf_usr_sp = ((vaddr_t)(stack) + stacksize) & -8;
+ tf->tf_usr_sp = (vaddr_t)stack & -8;
+ if (tcb != NULL)
+ p2->p_addr->u_pcb.pcb_tcb = tcb;
sf = (struct switchframe *)tf - 1;
sf->sf_r4 = (u_int)func;
diff --git a/sys/arch/arm64/arm64/vm_machdep.c b/sys/arch/arm64/arm64/vm_machdep.c
index c2e42e53234..3a879b9dc26 100644
--- a/sys/arch/arm64/arm64/vm_machdep.c
+++ b/sys/arch/arm64/arm64/vm_machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vm_machdep.c,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/* $OpenBSD: vm_machdep.c,v 1.2 2017/02/12 04:55:08 guenther Exp $ */
/* $NetBSD: vm_machdep.c,v 1.1 2003/04/26 18:39:33 fvdl Exp $ */
/*-
@@ -66,7 +66,7 @@
* than the parent. Returns 1 in the child process, 0 in the parent.
*/
void
-cpu_fork(struct proc *p1, struct proc *p2, void *stack, size_t stacksize,
+cpu_fork(struct proc *p1, struct proc *p2, void *stack, void *tcb,
void (*func)(void *), void *arg)
{
struct pcb *pcb = (struct pcb *)&p2->p_addr->u_pcb;
@@ -86,11 +86,13 @@ cpu_fork(struct proc *p1, struct proc *p2, void *stack, size_t stacksize,
- 0x10);
tf = (struct trapframe *)STACKALIGN(tf);
- p2->p_addr->u_pcb.pcb_tf = tf;
+ pcb->pcb_tf = tf;
*tf = *p1->p_addr->u_pcb.pcb_tf;
if (stack != NULL)
- tf->tf_sp = STACKALIGN((u_int)(stack) + stacksize);
+ tf->tf_sp = STACKALIGN((u_int)(stack));
+ if (tcb != NULL)
+ pcb->pcb_tcb = tcb;
sf = (struct switchframe *)tf - 1;
sf->sf_x19 = (uint64_t)func;
diff --git a/sys/arch/hppa/hppa/vm_machdep.c b/sys/arch/hppa/hppa/vm_machdep.c
index 11bceafc94c..eb517d2def7 100644
--- a/sys/arch/hppa/hppa/vm_machdep.c
+++ b/sys/arch/hppa/hppa/vm_machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vm_machdep.c,v 1.81 2015/05/05 02:13:46 guenther Exp $ */
+/* $OpenBSD: vm_machdep.c,v 1.82 2017/02/12 04:55:08 guenther Exp $ */
/*
* Copyright (c) 1999-2004 Michael Shalayeff
@@ -49,7 +49,7 @@
extern struct pool hppa_fppl;
void
-cpu_fork(struct proc *p1, struct proc *p2, void *stack, size_t stacksize,
+cpu_fork(struct proc *p1, struct proc *p2, void *stack, void *tcb,
void (*func)(void *), void *arg)
{
struct pcb *pcbp;
@@ -102,10 +102,12 @@ cpu_fork(struct proc *p1, struct proc *p2, void *stack, size_t stacksize,
(curcpu()->ci_psw & PSL_O);
/*
- * If specified, give the child a different stack.
+ * If specified, give the child a different stack and/or TCB
*/
if (stack != NULL)
setstack(tf, (u_long)stack, 0); /* XXX ignore error? */
+ if (tcb != NULL)
+ tf->tf_cr27 = (u_long)tcb;
/*
* Build stack frames for the cpu_switchto & co.
diff --git a/sys/arch/i386/i386/vm_machdep.c b/sys/arch/i386/i386/vm_machdep.c
index 49901d20f3e..182795c274f 100644
--- a/sys/arch/i386/i386/vm_machdep.c
+++ b/sys/arch/i386/i386/vm_machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vm_machdep.c,v 1.64 2016/04/03 17:45:30 guenther Exp $ */
+/* $OpenBSD: vm_machdep.c,v 1.65 2017/02/12 04:55:08 guenther Exp $ */
/* $NetBSD: vm_machdep.c,v 1.61 1996/05/03 19:42:35 christos Exp $ */
/*-
@@ -67,12 +67,9 @@
* Copy and update the kernel stack and pcb, making the child
* ready to run, and marking it so that it can return differently
* than the parent. Returns 1 in the child process, 0 in the parent.
- * We currently double-map the user area so that the stack is at the same
- * address in each process; in the future we will probably relocate
- * the frame pointers on the stack after copying.
*/
void
-cpu_fork(struct proc *p1, struct proc *p2, void *stack, size_t stacksize,
+cpu_fork(struct proc *p1, struct proc *p2, void *stack, void *tcb,
void (*func)(void *), void *arg)
{
struct pcb *pcb = &p2->p_addr->u_pcb;
@@ -104,10 +101,12 @@ cpu_fork(struct proc *p1, struct proc *p2, void *stack, size_t stacksize,
*tf = *p1->p_md.md_regs;
/*
- * If specified, give the child a different stack.
+ * If specified, give the child a different stack and/or TCB
*/
if (stack != NULL)
- tf->tf_esp = (u_int)stack + stacksize;
+ tf->tf_esp = (u_int)stack;
+ if (tcb != NULL)
+ i386_set_threadbase(p2, (uint32_t)tcb, TSEG_GS);
sf = (struct switchframe *)tf - 1;
sf->sf_esi = (int)func;
diff --git a/sys/arch/m88k/m88k/vm_machdep.c b/sys/arch/m88k/m88k/vm_machdep.c
index d4cb331f49b..c247482c54f 100644
--- a/sys/arch/m88k/m88k/vm_machdep.c
+++ b/sys/arch/m88k/m88k/vm_machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vm_machdep.c,v 1.24 2015/05/05 02:13:47 guenther Exp $ */
+/* $OpenBSD: vm_machdep.c,v 1.25 2017/02/12 04:55:08 guenther Exp $ */
/*
* Copyright (c) 1998 Steve Murphree, Jr.
@@ -67,18 +67,11 @@ extern void switch_exit(struct proc *);
* Copy and update the kernel stack and pcb, making the child
* ready to run, and marking it so that it can return differently
* than the parent. Returns 1 in the child process, 0 in the parent.
- * We currently double-map the user area so that the stack is at the same
- * address in each process; in the future we will probably relocate
- * the frame pointers on the stack after copying.
*/
void
-cpu_fork(p1, p2, stack, stacksize, func, arg)
- struct proc *p1, *p2;
- void *stack;
- size_t stacksize;
- void (*func)(void *);
- void *arg;
+cpu_fork(struct proc *p1, struct proc *p2, void *stack, void *tcb,
+ void (*func)(void *), void *arg)
{
struct ksigframe {
void (*func)(void *);
@@ -100,10 +93,12 @@ cpu_fork(p1, p2, stack, stacksize, func, arg)
p2->p_md.md_tf = (struct trapframe *)USER_REGS(p2);
/*
- * If specified, give the child a different stack.
+ * If specified, give the child a different stack and/or TCB.
*/
if (stack != NULL)
- USER_REGS(p2)->r[31] = (u_int)stack + stacksize;
+ USER_REGS(p2)->r[31] = (u_int)stack;
+ if (tcb != NULL)
+ USER_REGS(p2)->r[27] = (u_int)tcb;
ksfp = (struct ksigframe *)((char *)p2->p_addr + USPACE) - 1;
ksfp->func = func;
diff --git a/sys/arch/mips64/mips64/vm_machdep.c b/sys/arch/mips64/mips64/vm_machdep.c
index f49bed30773..366d7c6969a 100644
--- a/sys/arch/mips64/mips64/vm_machdep.c
+++ b/sys/arch/mips64/mips64/vm_machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vm_machdep.c,v 1.33 2016/03/06 19:42:27 mpi Exp $ */
+/* $OpenBSD: vm_machdep.c,v 1.34 2017/02/12 04:55:08 guenther Exp $ */
/*
* Copyright (c) 1988 University of Utah.
* Copyright (c) 1992, 1993
@@ -61,12 +61,8 @@ extern void proc_trampoline(void);
* Finish a fork operation, with process p2 nearly set up.
*/
void
-cpu_fork(p1, p2, stack, stacksize, func, arg)
- struct proc *p1, *p2;
- void *stack;
- size_t stacksize;
- void (*func)(void *);
- void *arg;
+cpu_fork(struct proc *p1, struct proc *p2, void *stack, void *tcb,
+ void (*func)(void *), void *arg)
{
struct cpu_info *ci = curcpu();
struct pcb *pcb;
@@ -117,10 +113,12 @@ cpu_fork(p1, p2, stack, stacksize, func, arg)
p2->p_md.md_regs = &p2->p_addr->u_pcb.pcb_regs;
/*
- * If specified, give the child a different stack.
+ * If specified, give the child a different stack and/or TCB.
*/
if (stack != NULL)
- p2->p_md.md_regs->sp = (u_int64_t)stack + stacksize;
+ p2->p_md.md_regs->sp = (u_int64_t)stack;
+ if (tcb != NULL)
+ TCB_SET(p2, tcb);
/*
* Copy the process control block to the new proc and
diff --git a/sys/arch/powerpc/powerpc/vm_machdep.c b/sys/arch/powerpc/powerpc/vm_machdep.c
index 43e18f7401e..fc64451a15c 100644
--- a/sys/arch/powerpc/powerpc/vm_machdep.c
+++ b/sys/arch/powerpc/powerpc/vm_machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vm_machdep.c,v 1.48 2015/05/05 02:13:47 guenther Exp $ */
+/* $OpenBSD: vm_machdep.c,v 1.49 2017/02/12 04:55:08 guenther Exp $ */
/* $NetBSD: vm_machdep.c,v 1.1 1996/09/30 16:34:57 ws Exp $ */
/*
@@ -49,7 +49,7 @@
* Finish a fork operation, with process p2 nearly set up.
*/
void
-cpu_fork(struct proc *p1, struct proc *p2, void *stack, size_t stacksize,
+cpu_fork(struct proc *p1, struct proc *p2, void *stack, void *tcb,
void (*func)(void *), void *arg)
{
struct trapframe *tf;
@@ -92,7 +92,11 @@ cpu_fork(struct proc *p1, struct proc *p2, void *stack, size_t stacksize,
*/
if (stack != NULL) {
tf = trapframe(p2);
- tf->fixreg[1] = (register_t)stack + stacksize;
+ tf->fixreg[1] = (register_t)stack;
+ }
+ if (tcb != NULL) {
+ tf = trapframe(p2);
+ tf->fixreg[2] = (register_t)tcb;
}
stktop2 = (caddr_t)((u_long)stktop2 & ~15); /* Align stack pointer */
diff --git a/sys/arch/sh/sh/vm_machdep.c b/sys/arch/sh/sh/vm_machdep.c
index 77b50487b5b..16645ebfd0d 100644
--- a/sys/arch/sh/sh/vm_machdep.c
+++ b/sys/arch/sh/sh/vm_machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vm_machdep.c,v 1.13 2015/05/05 02:13:47 guenther Exp $ */
+/* $OpenBSD: vm_machdep.c,v 1.14 2017/02/12 04:55:08 guenther Exp $ */
/* $NetBSD: vm_machdep.c,v 1.53 2006/08/31 16:49:21 matt Exp $ */
/*
@@ -120,23 +120,20 @@ extern void proc_trampoline(void);
/*
* Finish a fork operation, with process p2 nearly set up.
* Copy and update the pcb and trap frame, making the child ready to run.
- *
+ *
* Rig the child's kernel stack so that it will start out in
- * proc_trampoline() and call child_return() with p2 as an
- * argument. This causes the newly-created child process to go
- * directly to user level with an apparent return value of 0 from
- * fork(), while the parent process returns normally.
- *
- * p1 is the process being forked; if p1 == &proc0, we are creating
- * a kernel thread, and the return path and argument are specified with
- * `func' and `arg'.
+ * proc_trampoline() and call 'func' with 'arg' as an argument.
+ * For normal processes this is child_return(), which causes the
+ * child to go directly to user level with an apparent return value
+ * of 0 from fork(), while the parent process returns normally.
+ * For kernel threads this will be a function that never return.
*
- * If an alternate user-level stack is requested (with non-zero values
- * in both the stack and stacksize args), set up the user stack pointer
- * accordingly.
+ * An alternate user-level stack or TCB can be requested by passing
+ * a non-NULL value; these are poked into the PCB so they're in
+ * effect at the initial return to userspace.
*/
void
-cpu_fork(struct proc *p1, struct proc *p2, void *stack, size_t stacksize,
+cpu_fork(struct proc *p1, struct proc *p2, void *stack, void *tcb,
void (*func)(void *), void *arg)
{
struct pcb *pcb;
@@ -213,7 +210,9 @@ cpu_fork(struct proc *p1, struct proc *p2, void *stack, size_t stacksize,
* If specified, give the child a different stack.
*/
if (stack != NULL)
- tf->tf_r15 = (u_int)stack + stacksize;
+ tf->tf_r15 = (int)stack;
+ if (tcb != NULL)
+ tf->tf_gbr = (int)tcb;
/* Setup switch frame */
sf = &pcb->pcb_sf;
diff --git a/sys/arch/sparc64/sparc64/vm_machdep.c b/sys/arch/sparc64/sparc64/vm_machdep.c
index c30e79a42a7..18e012ed879 100644
--- a/sys/arch/sparc64/sparc64/vm_machdep.c
+++ b/sys/arch/sparc64/sparc64/vm_machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vm_machdep.c,v 1.35 2015/11/06 06:33:26 guenther Exp $ */
+/* $OpenBSD: vm_machdep.c,v 1.36 2017/02/12 04:55:08 guenther Exp $ */
/* $NetBSD: vm_machdep.c,v 1.38 2001/06/30 00:02:20 eeh Exp $ */
/*
@@ -153,26 +153,19 @@ char cpu_forkname[] = "cpu_fork()";
* Copy and update the pcb and trap frame, making the child ready to run.
*
* Rig the child's kernel stack so that it will start out in
- * proc_trampoline() and call child_return() with p2 as an
- * argument. This causes the newly-created child process to go
- * directly to user level with an apparent return value of 0 from
- * fork(), while the parent process returns normally.
+ * proc_trampoline() and call 'func' with 'arg' as an argument.
+ * For normal processes this is child_return(), which causes the
+ * child to go directly to user level with an apparent return value
+ * of 0 from fork(), while the parent process returns normally.
+ * For kernel threads this will be a function that never return.
*
- * p1 is the process being forked; if p1 == &proc0, we are creating
- * a kernel thread, and the return path and argument are specified with
- * `func' and `arg'.
- *
- * If an alternate user-level stack is requested (with non-zero values
- * in both the stack and stacksize args), set up the user stack pointer
- * accordingly.
+ * An alternate user-level stack or TCB can be requested by passing
+ * a non-NULL value; these are poked into the PCB so they're in
+ * effect at the initial return to userspace.
*/
void
-cpu_fork(p1, p2, stack, stacksize, func, arg)
- struct proc *p1, *p2;
- void *stack;
- size_t stacksize;
- void (*func)(void *);
- void *arg;
+cpu_fork(struct proc *p1, struct proc *p2, void *stack, void *tcb,
+ void (*func)(void *), void *arg)
{
struct pcb *opcb = &p1->p_addr->u_pcb;
struct pcb *npcb = &p2->p_addr->u_pcb;
@@ -240,10 +233,11 @@ cpu_fork(p1, p2, stack, stacksize, func, arg)
* with space reserved for the frame, and zero the frame pointer.
*/
if (stack != NULL) {
- tf2->tf_out[6] = (u_int64_t)(u_long)stack + stacksize
- - (BIAS + CC64FSZ);
+ tf2->tf_out[6] = (u_int64_t)(u_long)stack - (BIAS + CC64FSZ);
tf2->tf_in[6] = 0;
}
+ if (tcb != NULL)
+ tf2->tf_global[7] = (u_int64_t)tcb;
/* Construct kernel frame to return to in cpu_switch() */
rp = (struct rwindow *)((u_long)npcb + TOPFRAMEOFF);
diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c
index e21a8306854..faa74aa4244 100644
--- a/sys/kern/init_main.c
+++ b/sys/kern/init_main.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: init_main.c,v 1.265 2017/01/21 05:42:03 guenther Exp $ */
+/* $OpenBSD: init_main.c,v 1.266 2017/02/12 04:55:08 guenther Exp $ */
/* $NetBSD: init_main.c,v 1.84.4.1 1996/06/02 09:08:06 mrg Exp $ */
/*
@@ -437,8 +437,7 @@ main(void *framep)
{
struct proc *initproc;
- if (fork1(p, FORK_FORK, NULL, 0, start_init, NULL, NULL,
- &initproc))
+ if (fork1(p, FORK_FORK, start_init, NULL, NULL, &initproc))
panic("fork init");
initprocess = initproc->p_p;
}
diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c
index 867a12bdd92..38c1be4a981 100644
--- a/sys/kern/kern_fork.c
+++ b/sys/kern/kern_fork.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_fork.c,v 1.194 2017/02/08 20:58:30 guenther Exp $ */
+/* $OpenBSD: kern_fork.c,v 1.195 2017/02/12 04:55:08 guenther Exp $ */
/* $NetBSD: kern_fork.c,v 1.29 1996/02/09 18:59:34 christos Exp $ */
/*
@@ -75,12 +75,13 @@ int randompid; /* when set to 1, pid's go random */
struct forkstat forkstat;
void fork_return(void *);
-void tfork_child_return(void *);
pid_t alloctid(void);
pid_t allocpid(void);
int ispidtaken(pid_t);
-void process_new(struct proc *, struct process *, int);
+struct proc *thread_new(struct proc *_parent, vaddr_t _uaddr);
+struct process *process_new(struct proc *, struct process *, int);
+int fork_check_maxthread(uid_t _uid);
void
fork_return(void *arg)
@@ -101,14 +102,14 @@ sys_fork(struct proc *p, void *v, register_t *retval)
flags = FORK_FORK;
if (p->p_p->ps_ptmask & PTRACE_FORK)
flags |= FORK_PTRACE;
- return (fork1(p, flags, NULL, 0, fork_return, NULL, retval, NULL));
+ return fork1(p, flags, fork_return, NULL, retval, NULL);
}
int
sys_vfork(struct proc *p, void *v, register_t *retval)
{
- return (fork1(p, FORK_VFORK|FORK_PPWAIT, NULL, 0, NULL,
- NULL, retval, NULL));
+ return fork1(p, FORK_VFORK|FORK_PPWAIT, child_return, NULL,
+ retval, NULL);
}
int
@@ -120,32 +121,58 @@ sys___tfork(struct proc *p, void *v, register_t *retval)
} */ *uap = v;
size_t psize = SCARG(uap, psize);
struct __tfork param = { 0 };
- int flags;
int error;
if (psize == 0 || psize > sizeof(param))
- return (EINVAL);
+ return EINVAL;
if ((error = copyin(SCARG(uap, param), &param, psize)))
- return (error);
+ return error;
#ifdef KTRACE
if (KTRPOINT(p, KTR_STRUCT))
ktrstruct(p, "tfork", &param, sizeof(param));
#endif
- flags = FORK_TFORK | FORK_THREAD | FORK_SIGHAND | FORK_SHAREVM
- | FORK_SHAREFILES;
-
- return (fork1(p, flags, param.tf_stack, param.tf_tid,
- tfork_child_return, param.tf_tcb, retval, NULL));
+ return thread_fork(p, param.tf_stack, param.tf_tcb, param.tf_tid,
+ retval);
}
-void
-tfork_child_return(void *arg)
+/*
+ * Allocate and initialize a thread (proc) structure, given the parent thread.
+ */
+struct proc *
+thread_new(struct proc *parent, vaddr_t uaddr)
{
- struct proc *p = curproc;
+ struct proc *p;
- TCB_SET(p, arg);
- child_return(p);
+ p = pool_get(&proc_pool, PR_WAITOK);
+ p->p_stat = SIDL; /* protect against others */
+ p->p_flag = 0;
+
+ /*
+ * 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.
+ */
+ memset(&p->p_startzero, 0,
+ (caddr_t)&p->p_endzero - (caddr_t)&p->p_startzero);
+ memcpy(&p->p_startcopy, &parent->p_startcopy,
+ (caddr_t)&p->p_endcopy - (caddr_t)&p->p_startcopy);
+ crhold(p->p_ucred);
+ p->p_addr = (struct user *)uaddr;
+
+ /*
+ * Initialize the timeouts.
+ */
+ timeout_set(&p->p_sleep_to, endtsleep, p);
+
+ /*
+ * set priority of child to be that of parent
+ * XXX should move p_estcpu into the region of struct proc which gets
+ * copied.
+ */
+ scheduler_fork_hook(parent, p);
+
+ return p;
}
/*
@@ -175,7 +202,7 @@ process_initialize(struct process *pr, struct proc *p)
/*
* Allocate and initialize a new process.
*/
-void
+struct process *
process_new(struct proc *p, struct process *parent, int flags)
{
struct process *pr;
@@ -246,36 +273,16 @@ process_new(struct proc *p, struct process *parent, int flags)
/* it's sufficiently inited to be globally visible */
LIST_INSERT_HEAD(&allprocess, pr, ps_list);
+
+ return pr;
}
/* print the 'table full' message once per 10 seconds */
struct timeval fork_tfmrate = { 10, 0 };
int
-fork1(struct proc *curp, int flags, void *stack, pid_t *tidptr,
- void (*func)(void *), void *arg, register_t *retval,
- struct proc **rnewprocp)
+fork_check_maxthread(uid_t uid)
{
- struct process *curpr = curp->p_p;
- struct process *pr;
- struct proc *p;
- uid_t uid;
- struct vmspace *vm;
- int count;
- vaddr_t uaddr;
- int s;
- struct ptrace_state *newptstat = NULL;
-
- /* sanity check some flag combinations */
- if (flags & FORK_THREAD) {
- if ((flags & FORK_SHAREFILES) == 0 ||
- (flags & FORK_SIGHAND) == 0 ||
- (flags & FORK_SYSTEM) != 0)
- return (EINVAL);
- }
- if (flags & FORK_SIGHAND && (flags & FORK_SHAREVM) == 0)
- return (EINVAL);
-
/*
* Although process entries are dynamically created, we still keep
* a global limit on the maximum number we will create. We reserve
@@ -285,48 +292,80 @@ fork1(struct proc *curp, int flags, void *stack, pid_t *tidptr,
* the variable nthreads is the current number of procs, maxthread is
* the limit.
*/
- uid = curp->p_ucred->cr_ruid;
if ((nthreads >= maxthread - 5 && uid != 0) || nthreads >= maxthread) {
static struct timeval lasttfm;
if (ratecheck(&lasttfm, &fork_tfmrate))
tablefull("proc");
- return (EAGAIN);
+ return EAGAIN;
}
nthreads++;
- if ((flags & FORK_THREAD) == 0) {
- if ((nprocesses >= maxprocess - 5 && uid != 0) ||
- nprocesses >= maxprocess) {
- static struct timeval lasttfm;
+ return 0;
+}
- if (ratecheck(&lasttfm, &fork_tfmrate))
- tablefull("process");
- nthreads--;
- return (EAGAIN);
- }
- nprocesses++;
+static inline void
+fork_thread_start(struct proc *p, struct proc *parent, int flags)
+{
+ int s;
- /*
- * Increment the count of processes running with
- * this uid. Don't allow a nonprivileged user to
- * exceed their current limit.
- */
- count = chgproccnt(uid, 1);
- if (uid != 0 && count > curp->p_rlimit[RLIMIT_NPROC].rlim_cur) {
- (void)chgproccnt(uid, -1);
- nprocesses--;
- nthreads--;
- return (EAGAIN);
- }
+ SCHED_LOCK(s);
+ p->p_stat = SRUN;
+ p->p_cpu = sched_choosecpu_fork(parent, flags);
+ setrunqueue(p);
+ SCHED_UNLOCK(s);
+}
+
+int
+fork1(struct proc *curp, int flags, void (*func)(void *), void *arg,
+ register_t *retval, struct proc **rnewprocp)
+{
+ struct process *curpr = curp->p_p;
+ struct process *pr;
+ struct proc *p;
+ uid_t uid = curp->p_ucred->cr_ruid;
+ struct vmspace *vm;
+ int count;
+ vaddr_t uaddr;
+ int error;
+ struct ptrace_state *newptstat = NULL;
+
+ KASSERT((flags & ~(FORK_FORK | FORK_VFORK | FORK_PPWAIT | FORK_PTRACE
+ | FORK_IDLE | FORK_SHAREVM | FORK_SHAREFILES | FORK_NOZOMBIE
+ | FORK_SYSTEM | FORK_SIGHAND)) == 0);
+ KASSERT((flags & FORK_SIGHAND) == 0 || (flags & FORK_SHAREVM));
+ KASSERT(func != NULL);
+
+ if ((error = fork_check_maxthread(uid)))
+ return error;
+
+ if ((nprocesses >= maxprocess - 5 && uid != 0) ||
+ nprocesses >= maxprocess) {
+ static struct timeval lasttfm;
+
+ if (ratecheck(&lasttfm, &fork_tfmrate))
+ tablefull("process");
+ nthreads--;
+ return EAGAIN;
+ }
+ nprocesses++;
+
+ /*
+ * Increment the count of processes running with this uid.
+ * Don't allow a nonprivileged user to exceed their current limit.
+ */
+ count = chgproccnt(uid, 1);
+ if (uid != 0 && count > curp->p_rlimit[RLIMIT_NPROC].rlim_cur) {
+ (void)chgproccnt(uid, -1);
+ nprocesses--;
+ nthreads--;
+ return EAGAIN;
}
uaddr = uvm_uarea_alloc();
if (uaddr == 0) {
- if ((flags & FORK_THREAD) == 0) {
- (void)chgproccnt(uid, -1);
- nprocesses--;
- }
+ (void)chgproccnt(uid, -1);
+ nprocesses--;
nthreads--;
return (ENOMEM);
}
@@ -334,37 +373,9 @@ fork1(struct proc *curp, int flags, void *stack, pid_t *tidptr,
/*
* From now on, we're committed to the fork and cannot fail.
*/
+ p = thread_new(curp, uaddr);
+ pr = process_new(p, curpr, flags);
- /* Allocate new proc. */
- p = pool_get(&proc_pool, PR_WAITOK);
-
- p->p_stat = SIDL; /* protect against others */
- p->p_flag = 0;
-
- /*
- * 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.
- */
- memset(&p->p_startzero, 0,
- (caddr_t)&p->p_endzero - (caddr_t)&p->p_startzero);
- memcpy(&p->p_startcopy, &curp->p_startcopy,
- (caddr_t)&p->p_endcopy - (caddr_t)&p->p_startcopy);
- crhold(p->p_ucred);
-
- /*
- * Initialize the timeouts.
- */
- timeout_set(&p->p_sleep_to, endtsleep, p);
-
- if (flags & FORK_THREAD) {
- atomic_setbits_int(&p->p_flag, P_THREAD);
- p->p_p = pr = curpr;
- pr->ps_refcnt++;
- } else {
- process_new(p, curpr, flags);
- pr = p->p_p;
- }
p->p_fd = pr->ps_fd;
p->p_vmspace = pr->ps_vmspace;
if (pr->ps_flags & PS_SYSTEM)
@@ -380,24 +391,12 @@ fork1(struct proc *curp, int flags, void *stack, pid_t *tidptr,
* Copy traceflag and tracefile if enabled.
* If not inherited, these were zeroed above.
*/
- if ((flags & FORK_THREAD) == 0 && curpr->ps_traceflag & KTRFAC_INHERIT)
+ if (curpr->ps_traceflag & KTRFAC_INHERIT)
ktrsettrace(pr, curpr->ps_traceflag, curpr->ps_tracevp,
curpr->ps_tracecred);
#endif
/*
- * set priority of child to be that of parent
- * XXX should move p_estcpu into the region of struct proc which gets
- * copied.
- */
- scheduler_fork_hook(curp, p);
-
- if (flags & FORK_THREAD)
- sigstkinit(&p->p_sigstk);
-
- p->p_addr = (struct user *)uaddr;
-
- /*
* Finish creating the child thread. cpu_fork() will copy
* and update the pcb and make the child ready to run. If
* this is a normal user fork, the child will exit directly
@@ -405,7 +404,7 @@ fork1(struct proc *curp, int flags, void *stack, pid_t *tidptr,
* and will not return here. If this is a kernel thread,
* the specified entry point will be executed.
*/
- cpu_fork(curp, p, stack, 0, func ? func : child_return, arg ? arg : p);
+ cpu_fork(curp, p, NULL, NULL, func, arg ? arg : p);
vm = pr->ps_vmspace;
@@ -415,11 +414,8 @@ fork1(struct proc *curp, int flags, void *stack, pid_t *tidptr,
} else if (flags & FORK_VFORK) {
forkstat.cntvfork++;
forkstat.sizvfork += vm->vm_dsize + vm->vm_ssize;
- } else if (flags & FORK_TFORK) {
- forkstat.cnttfork++;
} else {
forkstat.cntkthread++;
- forkstat.sizkthread += vm->vm_dsize + vm->vm_ssize;
}
if (pr->ps_flags & PS_TRACED && flags & FORK_FORK)
@@ -429,76 +425,46 @@ fork1(struct proc *curp, int flags, void *stack, pid_t *tidptr,
LIST_INSERT_HEAD(&allproc, p, p_list);
LIST_INSERT_HEAD(TIDHASH(p->p_tid), p, p_hash);
- if ((flags & FORK_THREAD) == 0) {
- LIST_INSERT_HEAD(PIDHASH(pr->ps_pid), pr, ps_hash);
- LIST_INSERT_AFTER(curpr, pr, ps_pglist);
- LIST_INSERT_HEAD(&curpr->ps_children, pr, ps_sibling);
-
- if (pr->ps_flags & PS_TRACED) {
- pr->ps_oppid = curpr->ps_pid;
- if (pr->ps_pptr != curpr->ps_pptr)
- proc_reparent(pr, curpr->ps_pptr);
-
- /*
- * Set ptrace status.
- */
- if (flags & FORK_FORK) {
- pr->ps_ptstat = newptstat;
- newptstat = NULL;
- curpr->ps_ptstat->pe_report_event = PTRACE_FORK;
- pr->ps_ptstat->pe_report_event = PTRACE_FORK;
- curpr->ps_ptstat->pe_other_pid = pr->ps_pid;
- pr->ps_ptstat->pe_other_pid = curpr->ps_pid;
- }
- }
- } else {
- TAILQ_INSERT_TAIL(&pr->ps_threads, p, p_thr_link);
+ LIST_INSERT_HEAD(PIDHASH(pr->ps_pid), pr, ps_hash);
+ LIST_INSERT_AFTER(curpr, pr, ps_pglist);
+ LIST_INSERT_HEAD(&curpr->ps_children, pr, ps_sibling);
+
+ if (pr->ps_flags & PS_TRACED) {
+ pr->ps_oppid = curpr->ps_pid;
+ if (pr->ps_pptr != curpr->ps_pptr)
+ proc_reparent(pr, curpr->ps_pptr);
+
/*
- * if somebody else wants to take us to single threaded mode,
- * count ourselves in.
+ * Set ptrace status.
*/
- if (pr->ps_single) {
- curpr->ps_singlecount++;
- atomic_setbits_int(&p->p_flag, P_SUSPSINGLE);
+ if (newptstat != NULL) {
+ pr->ps_ptstat = newptstat;
+ newptstat = NULL;
+ curpr->ps_ptstat->pe_report_event = PTRACE_FORK;
+ pr->ps_ptstat->pe_report_event = PTRACE_FORK;
+ curpr->ps_ptstat->pe_other_pid = pr->ps_pid;
+ pr->ps_ptstat->pe_other_pid = curpr->ps_pid;
}
}
- if (tidptr != NULL) {
- pid_t tid = p->p_tid + THREAD_PID_OFFSET;
-
- if (copyout(&tid, tidptr, sizeof(tid)))
- psignal(curp, SIGSEGV);
- }
-
/*
* For new processes, set accounting bits and mark as complete.
*/
- if ((flags & FORK_THREAD) == 0) {
- getnanotime(&pr->ps_start);
- pr->ps_acflag = AFORK;
- atomic_clearbits_int(&pr->ps_flags, PS_EMBRYO);
- }
+ getnanotime(&pr->ps_start);
+ pr->ps_acflag = AFORK;
+ atomic_clearbits_int(&pr->ps_flags, PS_EMBRYO);
- /*
- * Make child runnable and add to run queue.
- */
- if ((flags & FORK_IDLE) == 0) {
- SCHED_LOCK(s);
- p->p_stat = SRUN;
- p->p_cpu = sched_choosecpu_fork(curp, flags);
- setrunqueue(p);
- SCHED_UNLOCK(s);
- } else
+ if ((flags & FORK_IDLE) == 0)
+ fork_thread_start(p, curp, flags);
+ else
p->p_cpu = arg;
- if (newptstat)
- free(newptstat, M_SUBPROC, sizeof(*newptstat));
+ free(newptstat, M_SUBPROC, sizeof(*newptstat));
/*
* Notify any interested parties about the new process.
*/
- if ((flags & FORK_THREAD) == 0)
- KNOTE(&curpr->ps_klist, NOTE_FORK | pr->ps_pid);
+ KNOTE(&curpr->ps_klist, NOTE_FORK | pr->ps_pid);
/*
* Update stats now that we know the fork was successful.
@@ -533,17 +499,98 @@ fork1(struct proc *curp, int flags, void *stack, pid_t *tidptr,
psignal(curp, SIGTRAP);
/*
- * Return child pid to parent process,
- * marking us as parent via retval[1].
+ * Return child pid to parent process
*/
if (retval != NULL) {
- retval[0] = (flags & FORK_THREAD) == 0 ? pr->ps_pid :
- (p->p_tid + THREAD_PID_OFFSET);
+ retval[0] = pr->ps_pid;
retval[1] = 0;
}
return (0);
}
+int
+thread_fork(struct proc *curp, void *stack, void *tcb, pid_t *tidptr,
+ register_t *retval)
+{
+ struct process *pr = curp->p_p;
+ struct proc *p;
+ pid_t tid;
+ vaddr_t uaddr;
+ int error;
+
+ if (stack == NULL)
+ return EINVAL;
+
+ if ((error = fork_check_maxthread(curp->p_ucred->cr_ruid)))
+ return error;
+
+ uaddr = uvm_uarea_alloc();
+ if (uaddr == 0) {
+ nthreads--;
+ return ENOMEM;
+ }
+
+ /*
+ * From now on, we're committed to the fork and cannot fail.
+ */
+ p = thread_new(curp, uaddr);
+ atomic_setbits_int(&p->p_flag, P_THREAD);
+ sigstkinit(&p->p_sigstk);
+
+ /* other links */
+ p->p_p = pr;
+ pr->ps_refcnt++;
+
+ /* local copies */
+ p->p_fd = pr->ps_fd;
+ p->p_vmspace = pr->ps_vmspace;
+
+ /*
+ * Finish creating the child thread. cpu_fork() will copy
+ * and update the pcb and make the child ready to run. The
+ * child will exit directly to user mode via child_return()
+ * on its first time slice and will not return here.
+ */
+ cpu_fork(curp, p, stack, tcb, child_return, p);
+
+ p->p_tid = alloctid();
+
+ LIST_INSERT_HEAD(&allproc, p, p_list);
+ LIST_INSERT_HEAD(TIDHASH(p->p_tid), p, p_hash);
+ TAILQ_INSERT_TAIL(&pr->ps_threads, p, p_thr_link);
+
+ /*
+ * if somebody else wants to take us to single threaded mode,
+ * count ourselves in.
+ */
+ if (pr->ps_single) {
+ pr->ps_singlecount++;
+ atomic_setbits_int(&p->p_flag, P_SUSPSINGLE);
+ }
+
+ /*
+ * Return tid to parent thread and copy it out to userspace
+ */
+ retval[0] = tid = p->p_tid + THREAD_PID_OFFSET;
+ retval[1] = 0;
+ if (tidptr != NULL) {
+ if (copyout(&tid, tidptr, sizeof(tid)))
+ psignal(curp, SIGSEGV);
+ }
+
+ fork_thread_start(p, curp, 0);
+
+ /*
+ * Update stats now that we know the fork was successful.
+ */
+ forkstat.cnttfork++;
+ uvmexp.forks++;
+ uvmexp.forks_sharevm++;
+
+ return 0;
+}
+
+
/* Find an unused tid */
pid_t
alloctid(void)
diff --git a/sys/kern/kern_kthread.c b/sys/kern/kern_kthread.c
index 80ee61dd77d..c2f95169367 100644
--- a/sys/kern/kern_kthread.c
+++ b/sys/kern/kern_kthread.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_kthread.c,v 1.40 2017/01/21 05:42:03 guenther Exp $ */
+/* $OpenBSD: kern_kthread.c,v 1.41 2017/02/12 04:55:08 guenther Exp $ */
/* $NetBSD: kern_kthread.c,v 1.3 1998/12/22 21:21:36 kleink Exp $ */
/*-
@@ -66,7 +66,7 @@ kthread_create(void (*func)(void *), void *arg,
* parent to wait for.
*/
error = fork1(&proc0, FORK_SHAREVM|FORK_SHAREFILES|FORK_NOZOMBIE|
- FORK_SYSTEM|FORK_SIGHAND, NULL, 0, func, arg, NULL, &p);
+ FORK_SYSTEM|FORK_SIGHAND, func, arg, NULL, &p);
if (error)
return (error);
diff --git a/sys/kern/kern_sched.c b/sys/kern/kern_sched.c
index dd3d4ef0dc5..50c86ec3b01 100644
--- a/sys/kern/kern_sched.c
+++ b/sys/kern/kern_sched.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_sched.c,v 1.44 2017/01/21 05:42:03 guenther Exp $ */
+/* $OpenBSD: kern_sched.c,v 1.45 2017/02/12 04:55:08 guenther Exp $ */
/*
* Copyright (c) 2007, 2008 Artur Grabowski <art@openbsd.org>
*
@@ -108,7 +108,7 @@ sched_kthreads_create(void *v)
static int num;
if (fork1(&proc0, FORK_SHAREVM|FORK_SHAREFILES|FORK_NOZOMBIE|
- FORK_SYSTEM|FORK_SIGHAND|FORK_IDLE, NULL, 0, sched_idle, ci, NULL,
+ FORK_SYSTEM|FORK_SIGHAND|FORK_IDLE, sched_idle, ci, NULL,
&spc->spc_idleproc))
panic("fork idle");
diff --git a/sys/sys/proc.h b/sys/sys/proc.h
index 6edbd641f6d..4f015f2eeb0 100644
--- a/sys/sys/proc.h
+++ b/sys/sys/proc.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: proc.h,v 1.233 2017/02/08 20:58:30 guenther Exp $ */
+/* $OpenBSD: proc.h,v 1.234 2017/02/12 04:55:08 guenther Exp $ */
/* $NetBSD: proc.h,v 1.44 1996/04/22 01:23:21 christos Exp $ */
/*-
@@ -447,10 +447,8 @@ struct uidinfo *uid_find(uid_t);
#define FORK_SYSTEM 0x00000020
#define FORK_NOZOMBIE 0x00000040
#define FORK_SHAREVM 0x00000080
-#define FORK_TFORK 0x00000100
#define FORK_SIGHAND 0x00000200
#define FORK_PTRACE 0x00000400
-#define FORK_THREAD 0x00000800
#define EXIT_NORMAL 0x00000001
#define EXIT_THREAD 0x00000002
@@ -517,10 +515,14 @@ void exit1(struct proc *, int, int);
void exit2(struct proc *);
int dowait4(struct proc *, pid_t, int *, int, struct rusage *,
register_t *);
+void cpu_fork(struct proc *_curp, struct proc *_child, void *_stack,
+ void *_tcb, void (*_func)(void *), void *_arg);
void cpu_exit(struct proc *);
void process_initialize(struct process *, struct proc *);
-int fork1(struct proc *, int, void *, pid_t *, void (*)(void *),
- void *, register_t *, struct proc **);
+int fork1(struct proc *_curp, int _flags, void (*_func)(void *),
+ void *_arg, register_t *_retval, struct proc **_newprocp);
+int thread_fork(struct proc *_curp, void *_stack, void *_tcb,
+ pid_t *_tidptr, register_t *_retval);
int groupmember(gid_t, struct ucred *);
void dorefreshcreds(struct process *, struct proc *);
void dosigsuspend(struct proc *, sigset_t);
diff --git a/sys/uvm/uvm_extern.h b/sys/uvm/uvm_extern.h
index 8ef427d06cb..0187782f1cb 100644
--- a/sys/uvm/uvm_extern.h
+++ b/sys/uvm/uvm_extern.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: uvm_extern.h,v 1.139 2016/06/05 08:35:57 stefan Exp $ */
+/* $OpenBSD: uvm_extern.h,v 1.140 2017/02/12 04:55:08 guenther Exp $ */
/* $NetBSD: uvm_extern.h,v 1.57 2001/03/09 01:02:12 chs Exp $ */
/*
@@ -272,8 +272,6 @@ extern vaddr_t vm_min_kernel_address;
void vmapbuf(struct buf *, vsize_t);
void vunmapbuf(struct buf *, vsize_t);
-void cpu_fork(struct proc *, struct proc *, void *,
- size_t, void (*)(void *), void *);
struct uvm_object *uao_create(vsize_t, int);
void uao_detach(struct uvm_object *);
void uao_detach_locked(struct uvm_object *);