+ *
+ * BLOCK DIAGRAM OF VFORK
+ *
+ * Before:
+ *
+ * ,----------------. ,-------------.
+ * | | task | |
+ * | parent_thread | ------> | parent_task |
+ * | | <.list. | |
+ * `----------------' `-------------'
+ * uthread | ^ bsd_info | ^
+ * v | vc_thread v | task
+ * ,----------------. ,-------------.
+ * | | | |
+ * | parent_uthread | <.list. | parent_proc | <-- current_proc()
+ * | | | |
+ * `----------------' `-------------'
+ * uu_proc |
+ * v
+ * NULL
+ *
+ * After:
+ *
+ * ,----------------. ,-------------.
+ * | | task | |
+ * ,----> | parent_thread | ------> | parent_task |
+ * | | | <.list. | |
+ * | `----------------' `-------------'
+ * | uthread | ^ bsd_info | ^
+ * | v | vc_thread v | task
+ * | ,----------------. ,-------------.
+ * | | | | |
+ * | | parent_uthread | <.list. | parent_proc |
+ * | | | | |
+ * | `----------------' `-------------'
+ * | uu_proc | . list
+ * | v v
+ * | ,----------------.
+ * `----- | |
+ * p_vforkact | child_proc | <-- current_proc()
+ * | |
+ * `----------------'
+ */
+int
+vfork(proc_t parent_proc, __unused struct vfork_args *uap, int32_t *retval)
+{
+ thread_t child_thread;
+ int err;
+
+ if ((err = fork1(parent_proc, &child_thread, PROC_CREATE_VFORK)) != 0) {
+ retval[1] = 0;
+ } else {
+ uthread_t ut = get_bsdthread_info(current_thread());
+ proc_t child_proc = ut->uu_proc;
+
+ retval[0] = child_proc->p_pid;
+ retval[1] = 1; /* flag child return for user space */
+
+ /*
+ * Drop the signal lock on the child which was taken on our
+ * behalf by forkproc()/cloneproc() to prevent signals being
+ * received by the child in a partially constructed state.
+ */
+ proc_signalend(child_proc, 0);
+ proc_transend(child_proc, 0);
+
+ proc_knote(parent_proc, NOTE_FORK | child_proc->p_pid);
+ DTRACE_PROC1(create, proc_t, child_proc);
+ ut->uu_flag &= ~UT_VFORKING;
+ }
+
+ return (err);
+}
+
+
+/*
+ * fork1
+ *
+ * Description: common code used by all new process creation other than the
+ * bootstrap of the initial process on the system
+ *
+ * Parameters: parent_proc parent process of the process being
+ * child_threadp pointer to location to receive the
+ * Mach thread_t of the child process
+ * breated
+ * kind kind of creation being requested
+ *
+ * Notes: Permissable values for 'kind':
+ *
+ * PROC_CREATE_FORK Create a complete process which will
+ * return actively running in both the
+ * parent and the child; the child copies
+ * the parent address space.
+ * PROC_CREATE_SPAWN Create a complete process which will
+ * return actively running in the parent
+ * only after returning actively running
+ * in the child; the child address space
+ * is newly created by an image activator,
+ * after which the child is run.
+ * PROC_CREATE_VFORK Creates a partial process which will
+ * borrow the parent task, thread, and
+ * uthread to return running in the child;
+ * the child address space and other parts
+ * are lazily created at execve() time, or
+ * the child is terminated, and the parent
+ * does not actively run until that
+ * happens.
+ *
+ * At first it may seem strange that we return the child thread
+ * address rather than process structure, since the process is
+ * the only part guaranteed to be "new"; however, since we do
+ * not actualy adjust other references between Mach and BSD (see
+ * the block diagram above the implementation of vfork()), this
+ * is the only method which guarantees us the ability to get
+ * back to the other information.