+ * proc_vfork_begin
+ *
+ * Description: start a vfork on a process
+ *
+ * Parameters: parent_proc process (re)entering vfork state
+ *
+ * Returns: (void)
+ *
+ * Notes: Although this function increments a count, a count in
+ * excess of 1 is not currently supported. According to the
+ * POSIX standard, calling anything other than execve() or
+ * _exit() following a vfork(), including calling vfork()
+ * itself again, will result in undefined behaviour
+ */
+void
+proc_vfork_begin(proc_t parent_proc)
+{
+ proc_lock(parent_proc);
+ parent_proc->p_lflag |= P_LVFORK;
+ parent_proc->p_vforkcnt++;
+ proc_unlock(parent_proc);
+}
+
+/*
+ * proc_vfork_end
+ *
+ * Description: stop a vfork on a process
+ *
+ * Parameters: parent_proc process leaving vfork state
+ *
+ * Returns: (void)
+ *
+ * Notes: Decrements the count; currently, reentrancy of vfork()
+ * is unsupported on the current process
+ */
+void
+proc_vfork_end(proc_t parent_proc)
+{
+ proc_lock(parent_proc);
+ parent_proc->p_vforkcnt--;
+ if (parent_proc->p_vforkcnt < 0)
+ panic("vfork cnt is -ve");
+ if (parent_proc->p_vforkcnt == 0)
+ parent_proc->p_lflag &= ~P_LVFORK;
+ proc_unlock(parent_proc);
+}
+
+
+/*
+ * vfork
+ *
+ * Description: vfork system call
+ *
+ * Parameters: void [no arguments]
+ *
+ * Retval: 0 (to child process)
+ * !0 pid of child (to parent process)
+ * -1 error (see "Returns:")
+ *
+ * Returns: EAGAIN Administrative limit reached
+ * EINVAL vfork() called during vfork()
+ * ENOMEM Failed to allocate new process
+ *
+ * Note: After a successful call to this function, the parent process
+ * has its task, thread, and uthread lent to the child process,
+ * and control is returned to the caller; if this function is
+ * invoked as a system call, the return is to user space, and
+ * is effectively running on the child process.
+ *
+ * Subsequent calls that operate on process state are permitted,
+ * though discouraged, and will operate on the child process; any
+ * operations on the task, thread, or uthread will result in
+ * changes in the parent state, and, if inheritable, the child
+ * state, when a task, thread, and uthread are realized for the
+ * child process at execve() time, will also be effected. Given
+ * this, it's recemmended that people use the posix_spawn() call
+ * instead.
+ *
+ * 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()
+ * | |
+ * `----------------'