xiaoxiang781216 commented on code in PR #19562:
URL: https://github.com/apache/nuttx/pull/19562#discussion_r3699772513


##########
arch/arm/src/common/gnu/fork.S:
##########
@@ -86,6 +117,25 @@
 #endif
 
 up_fork:
+       movs            r2, #FORK_TYPE_FORK
+       b               arm_fork_common
+
+       .size   up_fork, .-up_fork
+#endif
+
+/* The shared snapshot.  r2 holds the FORK_TYPE_* selector on entry; it is
+ * call-clobbered and is not part of the snapshot, so it survives the
+ * sequence below untouched.  lr still holds the original caller's return
+ * address, because the entry points above branched here rather than calling.
+ */
+
+#ifdef __ghs__
+       .type   arm_fork_common, $function
+#else
+       .type   arm_fork_common, function
+#endif
+
+arm_fork_common:

Review Comment:
   why not keep the name as up_fork but add FORK_TYPE_XXX as it's argument?



##########
arch/arm/src/common/gnu/fork.S:
##########
@@ -104,22 +154,25 @@ up_fork:
        mov             r5, lr                  /* Copy lr to a low register */
        stmia           r1!, {r0,r5}            /* Save sp and lr in the 
structure */
 
-       /* Then, call arm_fork(), passing it a pointer to the stack structure */
+       /* Then, call arm_fork(), passing it a pointer to the stack structure
+        * and the selector that says which primitive was called.
+        */
 
        mov             r0, sp
+       mov             r1, r2

Review Comment:
   why not pass r0 as FORK_TYPE_xxx and r1 as sp



##########
libs/libc/unistd/lib_fork.c:
##########
@@ -217,22 +224,61 @@ pid_t vfork(void)
     }
 #endif
 
-  if (pid != 0)
-    {
-      /* we are in parent task, and we need to wait the child task
-       * until running finished or performing exec
-       */
+  return pid;
+}
+#endif /* CONFIG_ARCH_HAVE_VFORK */
 
-      ret = waitpid(pid, &status, WNOWAIT);
-      if (ret < 0)
-        {
-          serr("ERROR: waitpid failed: %d\n", get_errno());
-        }
+/****************************************************************************
+ * Name: fork
+ *
+ * Description:
+ *   POSIX fork().  The child receives its own copy of the parent's memory,
+ *   at the same virtual addresses.  It may modify anything, call anything,
+ *   return from the function that called fork(), and it runs concurrently
+ *   with the parent.  None of vfork()'s restrictions apply.
+ *
+ *   Provided only where CONFIG_ARCH_HAVE_FORK is selected; elsewhere fork()
+ *   is not declared at all, so calling it is a build error.
+ *   CONFIG_FORK_IS_TASK_FORK aliases it to task_fork() for legacy code.
+ *   Wrapper of the up_fork() syscall.
+ *
+ * Returned Value:
+ *   Upon successful completion, fork() returns 0 to the child process and
+ *   returns the process ID of the child process to the parent process.
+ *   Otherwise, -1 is returned to the parent, no child process is created,
+ *   and errno is set to indicate the error.
+ *
+ ****************************************************************************/
+
+#if defined(CONFIG_ARCH_HAVE_FORK)
+pid_t fork(void)
+{
+  pid_t pid;
+
+#ifdef CONFIG_PTHREAD_ATFORK
+  atfork_prepare();
+#endif
+  pid = up_fork();
+
+#ifdef CONFIG_PTHREAD_ATFORK
+  if (pid == 0)
+    {
+      atfork_child();
+    }
+  else
+    {
+      atfork_parent();
     }
+#endif
 
   return pid;
 }
+#elif defined(CONFIG_FORK_IS_TASK_FORK)

Review Comment:
   remove the fallback



##########
arch/Kconfig:
##########
@@ -482,9 +487,70 @@ config ARCH_HAVE_CPUID_MAPPING
        default n
        depends on ARCH_HAVE_MULTICPU
 
+config ARCH_HAVE_TASK_FORK

Review Comment:
   remove? we don't need another nonstandard fork implementation.



##########
arch/arm64/src/common/arm64_fork_func.S:
##########
@@ -84,7 +84,7 @@
  *
  ****************************************************************************/
 
-#ifdef CONFIG_ARCH_HAVE_TASK_FORK
+#ifdef CONFIG_TASK_FORK

Review Comment:
   let's drop task_fork directly



##########
include/nuttx/sched.h:
##########
@@ -1136,34 +1159,54 @@ void nxtask_startup(main_t entrypt, int argc, FAR char 
*argv[]);
 #endif
 
 /****************************************************************************
- * Internal fork support.  The overall sequence is:
- *
- * 1) User code calls fork().  fork() is provided in architecture-specific
- *    code.
- * 2) fork()and calls nxtask_setup_fork().
+ * Internal support for the three cloning primitives -- task_fork(), vfork()
+ * and fork().  See include/nuttx/fork.h for what distinguishes them; the
+ * sequence below is common to all three, and `type' is one of the
+ * FORK_TYPE_* constants defined there.
+ *
+ * 1) User code calls task_fork(), vfork() or fork().  Each is a libc wrapper
+ *    around up_task_fork(), up_vfork() or up_fork() respectively, which are
+ *    provided in architecture-specific code.
+ * 2) The architecture-specific code snapshots the caller's registers and
+ *    calls nxtask_setup_fork().
  * 3) nxtask_setup_fork() allocates and configures the child task's TCB.
  *    This consists of:
  *    - Allocation of the child task's TCB.
  *    - Initialization of file descriptors and streams
  *    - Configuration of environment variables
- *    - Allocate and initialize the stack
+ *    - Establishing the child's address environment:  joined to the parent's
+ *      for task_fork() and vfork(), duplicated from it for fork()
+ *    - Allocating the stack, or inheriting the parent's for fork()
  *    - Setup the input parameters for the task.
  *    - Initialization of the TCB (including call to up_initial_state())
- * 4) fork() provides any additional operating context. fork must:
+ * 4) The architecture-specific code provides any additional operating
+ *    context:
  *    - Initialize special values in any CPU registers that were not
  *      already configured by up_initial_state()
- * 5) fork() then calls nxtask_start_fork()
+ *    - Relocate the copied stack, unless the child shares the parent's
+ * 5) It then calls nxtask_start_fork(), or nxtask_start_vfork() which
+ *    additionally suspends the caller.
  * 6) nxtask_start_fork() then executes the child thread.
  *
  * nxtask_abort_fork() may be called if an error occurs between
  * steps 3 and 6.
  *
+ * nxtask_vfork_resume() releases a suspended vfork() parent.  It is called
+ * from nxsched_release_tcb(), the last point in the child's life -- by which
+ * time the child is off the ready-to-run list and an exec()ing child has
+ * already handed its pid to the program it loaded.
+ *
  ****************************************************************************/
 
-FAR struct tcb_s *nxtask_setup_fork(start_t retaddr);
-pid_t nxtask_start_fork(FAR struct tcb_s *child);
+FAR struct tcb_s *nxtask_setup_fork(start_t retaddr, int type);
+pid_t nxtask_start_fork(FAR struct tcb_s *child, int type);
 void nxtask_abort_fork(FAR struct tcb_s *child, int errcode);
 
+#ifdef CONFIG_ARCH_HAVE_VFORK
+pid_t nxtask_start_vfork(FAR struct tcb_s *child);
+void nxtask_vfork_resume(FAR struct tcb_s *child);

Review Comment:
   nxtask_resume_vfork



##########
arch/arm/src/common/arm_fork.c:
##########
@@ -49,47 +49,58 @@
  * Name: arm_fork
  *
  * Description:
- *   The fork() function has the same effect as posix fork(), except that the
- *   behavior is undefined if the process created by fork() either modifies
- *   any data other than a variable of type pid_t used to store the return
- *   value from fork(), or returns from the function in which fork() was
- *   called, or calls any other function before successfully calling _exit()
- *   or one of the exec family of functions.
+ *   The common ARM worker behind up_task_fork(), up_vfork() and up_fork().
+ *   All three snapshot the caller's registers identically; `type' -- one of
+ *   the FORK_TYPE_* constants from include/nuttx/fork.h -- says which
+ *   primitive was called, and is passed straight through to
+ *   nxtask_setup_fork(), which is where the memory semantics are decided.
+ *
+ *   What differs here is only the stack.  Normally the child has a stack of
+ *   its own, and this function fills it with a relocated copy of the
+ *   parent's, rebasing the stack and frame pointers to match.  When the
+ *   child shares the parent's stack addresses -- a fork() child, inside its
+ *   duplicated address environment -- there is nothing to relocate and the
+ *   pointers are carried over unchanged.
  *
  *   The overall sequence is:
  *
- *   1) User code calls fork().  fork() collects context information and
- *      transfers control up arm_fork().
- *   2) arm_fork() and calls nxtask_setup_fork().
+ *   1) User code calls task_fork(), vfork() or fork().  The libc wrapper
+ *      enters the matching architecture entry point, which collects context
+ *      information and transfers control to arm_fork().
+ *   2) arm_fork() calls nxtask_setup_fork().
  *   3) nxtask_setup_fork() allocates and configures the child task's TCB.
  *      This consists of:
  *      - Allocation of the child task's TCB.
  *      - Initialization of file descriptors and streams
  *      - Configuration of environment variables
- *      - Allocate and initialize the stack
+ *      - Establishing the child's address environment (for vfork() and
+ *        task_fork(); a fork() child's is duplicated later, once its stack
+ *        has been filled in -- see nxtask_start_fork())
+ *      - Allocating the stack, or inheriting the parent's for fork()
  *      - Setup the input parameters for the task.
  *      - Initialization of the TCB (including call to up_initial_state())
  *   4) arm_fork() provides any additional operating context. arm_fork must:
  *      - Initialize special values in any CPU registers that were not
  *        already configured by up_initial_state()
- *   5) arm_fork() then calls nxtask_start_fork()
- *   6) nxtask_start_fork() then executes the child thread.
+ *   5) arm_fork() then calls nxtask_start_fork(), or nxtask_start_vfork()
+ *      which additionally suspends the caller.
+ *   6) which executes the child thread.
  *
  * nxtask_abort_fork() may be called if an error occurs between steps 3 and
  * 6.
  *
  * Input Parameters:
- *   context - Caller context information saved by fork()
+ *   context - Caller context information saved by the entry point
+ *   type    - One of the FORK_TYPE_* constants
  *
  * Returned Value:
- *   Upon successful completion, fork() returns 0 to the child process and
- *   returns the process ID of the child process to the parent process.
- *   Otherwise, -1 is returned to the parent, no child process is created,
- *   and errno is set to indicate the error.
+ *   Upon successful completion, 0 is returned to the child and the process
+ *   ID of the child is returned to the parent.  Otherwise, -1 is returned to
+ *   the parent, no child is created, and errno is set to indicate the error.
  *
  ****************************************************************************/
 
-pid_t arm_fork(const struct fork_s *context)
+pid_t arm_fork(const struct fork_s *context, int type)

Review Comment:
   swap the argument order



##########
arch/arm64/src/common/arm64_fork.c:
##########
@@ -113,7 +113,7 @@ void arm64_fork_fpureg_save(struct fork_s *context)
  *
  ****************************************************************************/
 
-pid_t arm64_fork(const struct fork_s *context)
+pid_t arm64_fork(const struct fork_s *context, int type)

Review Comment:
   ditto



##########
libs/libbuiltin/libgcc/gcov.c:
##########
@@ -468,10 +468,16 @@ void __gcov_execle(void)
 {
 }
 
+/* GCC redirects fork() in instrumented code to __gcov_fork(), so this is
+ * reachable only where unistd.h declares fork() at all.
+ */
+
+#if defined(CONFIG_ARCH_HAVE_FORK) || defined(CONFIG_FORK_IS_TASK_FORK)

Review Comment:
   `#ifdef CONFIG_ARCH_HAVE_FORK`



##########
libs/libc/unistd/lib_fork.c:
##########
@@ -28,13 +28,15 @@
 #include <nuttx/arch.h>
 #include <nuttx/tls.h>
 
+#include <sched.h>
 #include <unistd.h>
 #include <stdio.h>
 #include <sys/wait.h>
 #include <errno.h>
 #include <nuttx/debug.h>
 
-#if defined(CONFIG_ARCH_HAVE_FORK)
+#if defined(CONFIG_ARCH_HAVE_TASK_FORK) || defined(CONFIG_ARCH_HAVE_VFORK) || \

Review Comment:
   remove the check



##########
include/sched.h:
##########
@@ -233,6 +233,16 @@ int    task_create_with_stack(FAR const char *name, int 
priority,
 int    task_delete(pid_t pid);
 int    task_restart(pid_t pid);
 
+/* Clone the calling task:  the child shares the parent's memory, runs on a
+ * private copy of the parent's stack, and runs concurrently.  Returns twice,
+ * like fork().  Not POSIX; new code should prefer pthread_create() or
+ * posix_spawn().
+ */
+
+#ifdef CONFIG_ARCH_HAVE_TASK_FORK
+pid_t  task_fork(void);

Review Comment:
   I still prefer to drop task_fork since it isn't a standard defined, and 
useless.



##########
libs/libc/libc.csv:
##########
@@ -70,7 +70,7 @@
 "flockfile","stdio.h","!defined(CONFIG_FILE_STREAM)","void","FAR FILE *"
 "fnmatch","fnmatch.h","","int","FAR const char *","FAR const char *","int"
 "fopen","stdio.h","defined(CONFIG_FILE_STREAM)","FAR FILE *","FAR const char 
*","FAR const char *"
-"fork","unistd.h","!defined(CONFIG_BUILD_KERNEL) && 
defined(CONFIG_ARCH_HAVE_FORK)","pid_t"
+"fork","unistd.h","!defined(CONFIG_BUILD_KERNEL) && 
(defined(CONFIG_ARCH_HAVE_FORK) || defined(CONFIG_FORK_IS_TASK_FORK))","pid_t"

Review Comment:
   remove CONFIG_FORK_IS_TASK_FORK



##########
sched/task/task_fork.c:
##########
@@ -34,17 +34,123 @@
 #include <errno.h>
 #include <nuttx/debug.h>
 
+#include <nuttx/fork.h>
+#include <nuttx/kmalloc.h>
 #include <nuttx/queue.h>
+#include <nuttx/semaphore.h>
 
 #include "sched/sched.h"
 #include "environ/environ.h"
 #include "group/group.h"
 #include "task/task.h"
 #include "tls/tls.h"
 
-/* fork() requires architecture-specific support as well as waipid(). */
+/* This file is the common core of task_fork(), vfork() and fork(); it is
+ * built if the architecture can provide any one of them.
+ */
 
-#ifdef CONFIG_ARCH_HAVE_FORK
+#if defined(CONFIG_ARCH_HAVE_TASK_FORK) || defined(CONFIG_ARCH_HAVE_VFORK) || \

Review Comment:
   remove the check



##########
arch/risc-v/src/common/riscv_fork.c:
##########
@@ -41,7 +41,8 @@
 
 #include "sched/sched.h"
 
-#ifdef CONFIG_ARCH_HAVE_FORK
+#if defined(CONFIG_ARCH_HAVE_TASK_FORK) || defined(CONFIG_ARCH_HAVE_VFORK) || \

Review Comment:
   remove, already done in makefile



##########
arch/Kconfig:
##########
@@ -482,9 +487,70 @@ config ARCH_HAVE_CPUID_MAPPING
        default n
        depends on ARCH_HAVE_MULTICPU
 
+config ARCH_HAVE_TASK_FORK
+       bool
+       default n
+       ---help---
+               The architecture can clone the calling task:  the child shares 
the
+               parent's .data/.bss/heap and runs on a private copy of the 
parent's
+               stack, concurrently with the parent.  This is the non-POSIX
+               task_fork() primitive; it is neither fork() nor vfork().
+
+config ARCH_HAVE_VFORK
+       bool
+       default n
+       ---help---
+               The architecture can implement POSIX vfork():  the child shares 
the
+               parent's memory and the parent is suspended until the child 
calls
+               _exit() or one of the exec family of functions.
+
+config ARCH_HAVE_ADDRENV_FORK
+       bool
+       default n
+       depends on ARCH_ADDRENV && !ARCH_STACK_DYNAMIC
+       ---help---
+               The architecture implements up_addrenv_fork(), which duplicates 
an
+               address environment:  the copy is backed by freshly allocated 
pages
+               holding a copy of the parent's contents, mapped at the same 
virtual
+               addresses.  This is what POSIX fork() is built on.
+
+               No architecture selects this yet.  Two things are needed.  
First,
+               up_addrenv_fork() itself.  Second, the architecture must build 
the
+               child's register context from the *user's* saved system call 
frame:
+               in a kernel build fork() is reached through a system call, so 
the
+               return address and stack pointer the architecture's fork entry 
point
+               can see for itself are the kernel's, not the caller's, and a 
child
+               built from those resumes at a kernel address.
+
 config ARCH_HAVE_FORK
        bool
+       default y if ARCH_ADDRENV && ARCH_HAVE_ADDRENV_FORK
+       ---help---
+               This configuration can provide POSIX fork() semantics:  the 
child
+               receives its own copy of the parent's memory at the same virtual
+               addresses, may modify anything, may return from the function 
that
+               called fork(), and runs concurrently with the parent.
+
+               Where this is not selected fork() is not provided at all, and 
code
+               that calls it fails to build -- see FORK_IS_TASK_FORK.
+
+config FORK_IS_TASK_FORK

Review Comment:
   let's remove this option



##########
arch/arm64/src/common/arm64_fork_func.S:
##########
@@ -41,51 +41,77 @@
  ****************************************************************************/
 
 /****************************************************************************
- * Name: fork
+ * Name: up_task_fork, up_vfork, up_fork
  *
  * Description:
- *   The up_fork() function is the base of fork() function that provided in
- *   libc, and fork() is implemented as a wrapper of up_fork() function.
- *   The fork() function has the same effect as posix fork(), except that the
- *   behavior is undefined if the process created by fork() either modifies
- *   any data other than a variable of type pid_t used to store the return
- *   value from fork(), or returns from the function in which fork() was
- *   called, or calls any other function before successfully calling _exit()
- *   or one of the exec family of functions.
+ *   These are the architecture-specific entry points of NuttX's three
+ *   cloning primitives.  All three need exactly the same thing from
+ *   assembly -- a snapshot of the caller's registers, stack pointer and
+ *   return address -- and differ only in what the C code then does with it,
+ *   so they share one snapshot sequence and are distinguished by a
+ *   FORK_TYPE_* constant passed to arm64_fork() in x1.
  *
- *   This thin layer implements fork by simply calling up_fork() with the
- *   fork() context as an argument.  The overall sequence is:
+ *   See include/nuttx/fork.h for what the three primitives mean.
  *
- *   1) User code calls fork().  fork() collects context information and
- *      transfers control up up_fork().
- *   2) arm64_fork() and calls nxtask_setup_fork().
- *   3) nxtask_setup_fork() allocates and configures the child task's TCB.
- *      This consists of:
+ *   The overall sequence is:
+ *
+ *   1) User code calls task_fork(), vfork() or fork().  Each is a libc
+ *      wrapper around the matching entry point here.
+ *   2) The entry point collects the context and calls arm64_fork().
+ *   3) arm64_fork() calls nxtask_setup_fork(), which allocates and
+ *      configures the child task's TCB.  This consists of:
  *      - Allocation of the child task's TCB.
  *      - Initialization of file descriptors and streams
  *      - Configuration of environment variables
- *      - Allocate and initialize the stack
+ *      - Establishing the child's address environment
+ *      - Allocating the stack, or inheriting the parent's for fork()
  *      - Setup the input parameters for the task.
  *      - Initialization of the TCB (including call to up_initial_state())
- *   4) arm64_fork() provides any additional operating context. arm64_fork 
must:
+ *   4) arm64_fork() provides any additional operating context:
  *      - Initialize special values in any CPU registers that were not
  *        already configured by up_initial_state()
- *   5) arm64_fork() then calls nxtask_start_fork()
- *   6) nxtask_start_fork() then executes the child thread.
+ *      - Relocate the copied stack, unless the child shares the parent's
+ *   5) arm64_fork() then calls nxtask_start_fork() or nxtask_start_vfork()
+ *   6) which executes the child thread.
  *
  * Input Parameters:
  *   None
  *
  * Returned Value:
- *   Upon successful completion, fork() returns 0 to the child process and
- *   returns the process ID of the child process to the parent process.
- *   Otherwise, -1 is returned to the parent, no child process is created,
- *   and errno is set to indicate the error.
+ *   Upon successful completion, 0 is returned to the child and the process
+ *   ID of the child is returned to the parent.  Otherwise, -1 is returned to
+ *   the parent, no child is created, and errno is set to indicate the error.
  *
  ****************************************************************************/
 
+#ifdef CONFIG_ARCH_HAVE_TASK_FORK
+GTEXT(up_task_fork)
+SECTION_FUNC(text, up_task_fork)

Review Comment:
   ditto



##########
include/nuttx/fork.h:
##########
@@ -20,34 +20,34 @@
  *
  ****************************************************************************/
 
+#ifndef __INCLUDE_NUTTX_FORK_H
+#define __INCLUDE_NUTTX_FORK_H
+
 /****************************************************************************
  * Included Files
  ****************************************************************************/
 
 #include <nuttx/config.h>
 
-#include <assert.h>
-
-#include "sched/sched.h"
-
 /****************************************************************************
- * Public Functions
+ * Pre-processor Definitions
  ****************************************************************************/
 
-/****************************************************************************
- * Name: issetugid
+/* Which primitive a clone of the calling task implements.  Passed to
+ * nxtask_setup_fork(), which is where the memory semantics are decided.
+ * Macros rather than an enumeration:  the architecture entry points are
+ * assembly and load them into a register.
  *
- * Description:
- *   Return non-zero if the process is executing a set-user-ID or
- *   set-group-ID program image.
- *
- ****************************************************************************/
-
-int issetugid(void)
-{
-  FAR struct tcb_s *rtcb          = this_task();
-  FAR struct task_group_s *rgroup = rtcb->group;
-
-  DEBUGASSERT(rgroup != NULL);
-  return (rgroup->tg_flags & GROUP_FLAG_SECURE_EXEC) != 0;
-}
+ *   FORK_TYPE_TASK   task_fork():  shares memory, private stack copy, both
+ *                    run.  Not POSIX.
+ *   FORK_TYPE_VFORK  vfork():  shares memory, parent suspended until the
+ *                    child _exit()s or exec()s.
+ *   FORK_TYPE_FORK   fork():  child gets its own copy of the parent's memory
+ *                    at the same virtual addresses, both run.
+ */
+
+#define FORK_TYPE_TASK   0

Review Comment:
   move to arch.h



##########
include/nuttx/fork.h:
##########
@@ -20,34 +20,34 @@
  *
  ****************************************************************************/
 
+#ifndef __INCLUDE_NUTTX_FORK_H
+#define __INCLUDE_NUTTX_FORK_H
+
 /****************************************************************************
  * Included Files
  ****************************************************************************/
 
 #include <nuttx/config.h>
 
-#include <assert.h>
-
-#include "sched/sched.h"
-
 /****************************************************************************
- * Public Functions
+ * Pre-processor Definitions
  ****************************************************************************/
 
-/****************************************************************************
- * Name: issetugid
+/* Which primitive a clone of the calling task implements.  Passed to
+ * nxtask_setup_fork(), which is where the memory semantics are decided.
+ * Macros rather than an enumeration:  the architecture entry points are
+ * assembly and load them into a register.
  *
- * Description:
- *   Return non-zero if the process is executing a set-user-ID or
- *   set-group-ID program image.
- *
- ****************************************************************************/
-
-int issetugid(void)
-{
-  FAR struct tcb_s *rtcb          = this_task();
-  FAR struct task_group_s *rgroup = rtcb->group;
-
-  DEBUGASSERT(rgroup != NULL);
-  return (rgroup->tg_flags & GROUP_FLAG_SECURE_EXEC) != 0;
-}
+ *   FORK_TYPE_TASK   task_fork():  shares memory, private stack copy, both
+ *                    run.  Not POSIX.
+ *   FORK_TYPE_VFORK  vfork():  shares memory, parent suspended until the
+ *                    child _exit()s or exec()s.
+ *   FORK_TYPE_FORK   fork():  child gets its own copy of the parent's memory
+ *                    at the same virtual addresses, both run.
+ */
+
+#define FORK_TYPE_TASK   0
+#define FORK_TYPE_VFORK  1

Review Comment:
   if FORK_TYPE_TASK   is removed, we can switch `bool vfork`



##########
include/nuttx/sched.h:
##########
@@ -1136,34 +1159,54 @@ void nxtask_startup(main_t entrypt, int argc, FAR char 
*argv[]);
 #endif
 
 /****************************************************************************
- * Internal fork support.  The overall sequence is:
- *
- * 1) User code calls fork().  fork() is provided in architecture-specific
- *    code.
- * 2) fork()and calls nxtask_setup_fork().
+ * Internal support for the three cloning primitives -- task_fork(), vfork()
+ * and fork().  See include/nuttx/fork.h for what distinguishes them; the
+ * sequence below is common to all three, and `type' is one of the
+ * FORK_TYPE_* constants defined there.
+ *
+ * 1) User code calls task_fork(), vfork() or fork().  Each is a libc wrapper
+ *    around up_task_fork(), up_vfork() or up_fork() respectively, which are
+ *    provided in architecture-specific code.
+ * 2) The architecture-specific code snapshots the caller's registers and
+ *    calls nxtask_setup_fork().
  * 3) nxtask_setup_fork() allocates and configures the child task's TCB.
  *    This consists of:
  *    - Allocation of the child task's TCB.
  *    - Initialization of file descriptors and streams
  *    - Configuration of environment variables
- *    - Allocate and initialize the stack
+ *    - Establishing the child's address environment:  joined to the parent's
+ *      for task_fork() and vfork(), duplicated from it for fork()
+ *    - Allocating the stack, or inheriting the parent's for fork()
  *    - Setup the input parameters for the task.
  *    - Initialization of the TCB (including call to up_initial_state())
- * 4) fork() provides any additional operating context. fork must:
+ * 4) The architecture-specific code provides any additional operating
+ *    context:
  *    - Initialize special values in any CPU registers that were not
  *      already configured by up_initial_state()
- * 5) fork() then calls nxtask_start_fork()
+ *    - Relocate the copied stack, unless the child shares the parent's
+ * 5) It then calls nxtask_start_fork(), or nxtask_start_vfork() which
+ *    additionally suspends the caller.
  * 6) nxtask_start_fork() then executes the child thread.
  *
  * nxtask_abort_fork() may be called if an error occurs between
  * steps 3 and 6.
  *
+ * nxtask_vfork_resume() releases a suspended vfork() parent.  It is called
+ * from nxsched_release_tcb(), the last point in the child's life -- by which
+ * time the child is off the ready-to-run list and an exec()ing child has
+ * already handed its pid to the program it loaded.
+ *
  ****************************************************************************/
 
-FAR struct tcb_s *nxtask_setup_fork(start_t retaddr);
-pid_t nxtask_start_fork(FAR struct tcb_s *child);
+FAR struct tcb_s *nxtask_setup_fork(start_t retaddr, int type);
+pid_t nxtask_start_fork(FAR struct tcb_s *child, int type);
 void nxtask_abort_fork(FAR struct tcb_s *child, int errcode);
 
+#ifdef CONFIG_ARCH_HAVE_VFORK
+pid_t nxtask_start_vfork(FAR struct tcb_s *child);

Review Comment:
   why not reuse nxtask_start_fork



##########
arch/Kconfig:
##########
@@ -482,9 +487,70 @@ config ARCH_HAVE_CPUID_MAPPING
        default n
        depends on ARCH_HAVE_MULTICPU
 
+config ARCH_HAVE_TASK_FORK
+       bool
+       default n
+       ---help---
+               The architecture can clone the calling task:  the child shares 
the
+               parent's .data/.bss/heap and runs on a private copy of the 
parent's
+               stack, concurrently with the parent.  This is the non-POSIX
+               task_fork() primitive; it is neither fork() nor vfork().
+
+config ARCH_HAVE_VFORK
+       bool
+       default n
+       ---help---
+               The architecture can implement POSIX vfork():  the child shares 
the
+               parent's memory and the parent is suspended until the child 
calls
+               _exit() or one of the exec family of functions.
+
+config ARCH_HAVE_ADDRENV_FORK
+       bool
+       default n
+       depends on ARCH_ADDRENV && !ARCH_STACK_DYNAMIC
+       ---help---
+               The architecture implements up_addrenv_fork(), which duplicates 
an
+               address environment:  the copy is backed by freshly allocated 
pages
+               holding a copy of the parent's contents, mapped at the same 
virtual
+               addresses.  This is what POSIX fork() is built on.
+
+               No architecture selects this yet.  Two things are needed.  
First,
+               up_addrenv_fork() itself.  Second, the architecture must build 
the
+               child's register context from the *user's* saved system call 
frame:
+               in a kernel build fork() is reached through a system call, so 
the
+               return address and stack pointer the architecture's fork entry 
point
+               can see for itself are the kernel's, not the caller's, and a 
child
+               built from those resumes at a kernel address.
+
 config ARCH_HAVE_FORK
        bool
+       default y if ARCH_ADDRENV && ARCH_HAVE_ADDRENV_FORK

Review Comment:
   `depends on ARCH_ADDRENV`
   remove ARCH_HAVE_ADDRENV_FORK, 



##########
arch/Kconfig:
##########
@@ -482,9 +487,70 @@ config ARCH_HAVE_CPUID_MAPPING
        default n
        depends on ARCH_HAVE_MULTICPU
 
+config ARCH_HAVE_TASK_FORK
+       bool
+       default n
+       ---help---
+               The architecture can clone the calling task:  the child shares 
the
+               parent's .data/.bss/heap and runs on a private copy of the 
parent's
+               stack, concurrently with the parent.  This is the non-POSIX
+               task_fork() primitive; it is neither fork() nor vfork().
+
+config ARCH_HAVE_VFORK
+       bool
+       default n
+       ---help---
+               The architecture can implement POSIX vfork():  the child shares 
the
+               parent's memory and the parent is suspended until the child 
calls
+               _exit() or one of the exec family of functions.
+
+config ARCH_HAVE_ADDRENV_FORK
+       bool
+       default n
+       depends on ARCH_ADDRENV && !ARCH_STACK_DYNAMIC

Review Comment:
   why can't implement with ARCH_STACK_DYNAMIC



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to