You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2023/04/27 09:36:05 UTC

[nuttx] 01/02: sched/spawn: remove spawn proxy thread to simplify task/posix_spawn()

This is an automated email from the ASF dual-hosted git repository.

xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit 507c8145a9ecb2a575700dc3f1580e2a1f7895f7
Author: chao an <an...@xiaomi.com>
AuthorDate: Wed Apr 26 11:44:08 2023 +0800

    sched/spawn: remove spawn proxy thread to simplify task/posix_spawn()
    
    The spawn proxy thread is a special existence in NuttX, usually some developers
    spend a lot of time on stack overflow of spawn proxy thread:
    
    https://github.com/apache/nuttx/issues/9046
    https://github.com/apache/nuttx/pull/9081
    
    In order to avoid similar issues, this PR will remove spawn proxy thread to simplify
    the process of task/posix_spawn().
    
    1. Postpone the related processing of spawn file actions until after task_init()
    2. Delete the temporary thread of spawn proxy and related global variables
    
    Signed-off-by: chao an <an...@xiaomi.com>
---
 binfmt/binfmt_exec.c          |   8 +-
 binfmt/binfmt_execmodule.c    |  17 ++-
 drivers/serial/serial.c       |   3 +-
 fs/inode/fs_files.c           | 123 ++++++++++++----
 fs/vfs/fs_open.c              |  50 ++++++-
 include/nuttx/binfmt/binfmt.h |   7 +-
 include/nuttx/fs/fs.h         |  91 +++++++++++-
 include/nuttx/sched.h         |  34 +++++
 include/nuttx/spawn.h         |   3 +
 sched/init/nx_bringup.c       |   2 +-
 sched/sched/sched_getfiles.c  |  32 ++++-
 sched/task/spawn.h            |  57 +-------
 sched/task/task_posixspawn.c  | 200 ++------------------------
 sched/task/task_spawn.c       | 317 ++++++++++++++----------------------------
 sched/task/task_spawnparms.c  | 145 ++++++++-----------
 15 files changed, 491 insertions(+), 598 deletions(-)

diff --git a/binfmt/binfmt_exec.c b/binfmt/binfmt_exec.c
index ab361d5887..2d281b6dce 100644
--- a/binfmt/binfmt_exec.c
+++ b/binfmt/binfmt_exec.c
@@ -62,6 +62,7 @@
  *              exported by the caller and made available for linking the
  *              module into the system.
  *   nexports - The number of symbols in the exports table.
+ *   actions  - The spawn file actions
  *   attr     - The spawn attributes.
  *
  * Returned Value:
@@ -72,7 +73,8 @@
 
 int exec_spawn(FAR const char *filename, FAR char * const *argv,
                FAR char * const *envp, FAR const struct symtab_s *exports,
-               int nexports, FAR const posix_spawnattr_t *attr)
+               int nexports, FAR const posix_spawn_file_actions_t *actions,
+               FAR const posix_spawnattr_t *attr)
 {
   FAR struct binary_s *bin;
   int pid;
@@ -128,7 +130,7 @@ int exec_spawn(FAR const char *filename, FAR char * const *argv,
 
   /* Then start the module */
 
-  pid = exec_module(bin, filename, argv, envp);
+  pid = exec_module(bin, filename, argv, envp, actions);
   if (pid < 0)
     {
       ret = pid;
@@ -239,7 +241,7 @@ int exec(FAR const char *filename, FAR char * const *argv,
 {
   int ret;
 
-  ret = exec_spawn(filename, argv, envp, exports, nexports, NULL);
+  ret = exec_spawn(filename, argv, envp, exports, nexports, NULL, NULL);
   if (ret < 0)
     {
       set_errno(-ret);
diff --git a/binfmt/binfmt_execmodule.c b/binfmt/binfmt_execmodule.c
index 8beea49cdd..6e6b26649d 100644
--- a/binfmt/binfmt_execmodule.c
+++ b/binfmt/binfmt_execmodule.c
@@ -35,6 +35,7 @@
 #include <nuttx/arch.h>
 #include <nuttx/kmalloc.h>
 #include <nuttx/sched.h>
+#include <nuttx/spawn.h>
 #include <nuttx/binfmt/binfmt.h>
 
 #include "binfmt.h"
@@ -113,7 +114,8 @@ static void exec_ctors(FAR void *arg)
 
 int exec_module(FAR struct binary_s *binp,
                 FAR const char *filename, FAR char * const *argv,
-                FAR char * const *envp)
+                FAR char * const *envp,
+                FAR const posix_spawn_file_actions_t *actions)
 {
   FAR struct task_tcb_s *tcb;
 #if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_BUILD_KERNEL)
@@ -216,6 +218,17 @@ int exec_module(FAR struct binary_s *binp,
   binfmt_freeargv(argv);
   binfmt_freeenv(envp);
 
+  /* Perform file actions */
+
+  if (actions != NULL)
+    {
+      ret = spawn_file_actions(&tcb->cmn, actions);
+      if (ret < 0)
+        {
+          goto errout_with_tcbinit;
+        }
+    }
+
 #if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_ARCH_KERNEL_STACK)
   /* Allocate the kernel stack */
 
@@ -283,7 +296,6 @@ int exec_module(FAR struct binary_s *binp,
 
   return (int)pid;
 
-#if defined(CONFIG_ARCH_ADDRENV) || defined(CONFIG_ARCH_VMA_MAPPING)
 errout_with_tcbinit:
 #ifndef CONFIG_BUILD_KERNEL
   if (binp->stackaddr != NULL)
@@ -294,7 +306,6 @@ errout_with_tcbinit:
 
   nxtask_uninit(tcb);
   return ret;
-#endif
 
 errout_with_addrenv:
 #if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_BUILD_KERNEL)
diff --git a/drivers/serial/serial.c b/drivers/serial/serial.c
index dea33b0a79..f97ea696c9 100644
--- a/drivers/serial/serial.c
+++ b/drivers/serial/serial.c
@@ -1750,7 +1750,8 @@ static void uart_launch_worker(void *arg)
                  CONFIG_TTY_LAUNCH_ENTRYPOINT,
                  NULL, &attr, argv, NULL);
 #else
-      exec_spawn(CONFIG_TTY_LAUNCH_FILEPATH, argv, NULL, NULL, 0, &attr);
+      exec_spawn(CONFIG_TTY_LAUNCH_FILEPATH,
+                 argv, NULL, NULL, 0, NULL, &attr);
 #endif
       posix_spawnattr_destroy(&attr);
     }
diff --git a/fs/inode/fs_files.c b/fs/inode/fs_files.c
index e38662b777..1f91b5e51e 100644
--- a/fs/inode/fs_files.c
+++ b/fs/inode/fs_files.c
@@ -185,7 +185,7 @@ void files_releaselist(FAR struct filelist *list)
 }
 
 /****************************************************************************
- * Name: file_allocate
+ * Name: file_allocate_from_tcb
  *
  * Description:
  *   Allocate a struct files instance and associate it with an inode
@@ -197,8 +197,9 @@ void files_releaselist(FAR struct filelist *list)
  *
  ****************************************************************************/
 
-int file_allocate(FAR struct inode *inode, int oflags, off_t pos,
-                  FAR void *priv, int minfd, bool addref)
+int file_allocate_from_tcb(FAR struct tcb_s *tcb, FAR struct inode *inode,
+                           int oflags, off_t pos, FAR void *priv, int minfd,
+                           bool addref)
 {
   FAR struct filelist *list;
   int ret;
@@ -207,7 +208,7 @@ int file_allocate(FAR struct inode *inode, int oflags, off_t pos,
 
   /* Get the file descriptor list.  It should not be NULL in this context. */
 
-  list = nxsched_get_files();
+  list = nxsched_get_files_from_tcb(tcb);
   DEBUGASSERT(list != NULL);
 
   ret = nxmutex_lock(&list->fl_lock);
@@ -285,6 +286,26 @@ int file_allocate(FAR struct inode *inode, int oflags, off_t pos,
   return i * CONFIG_NFILE_DESCRIPTORS_PER_BLOCK;
 }
 
+/****************************************************************************
+ * Name: file_allocate
+ *
+ * Description:
+ *   Allocate a struct files instance and associate it with an inode
+ *   instance.
+ *
+ * Returned Value:
+ *     Returns the file descriptor == index into the files array on success;
+ *     a negated errno value is returned on any failure.
+ *
+ ****************************************************************************/
+
+int file_allocate(FAR struct inode *inode, int oflags, off_t pos,
+                  FAR void *priv, int minfd, bool addref)
+{
+  return file_allocate_from_tcb(nxsched_self(), inode, oflags,
+                                pos, priv, minfd, addref);
+}
+
 /****************************************************************************
  * Name: files_duplist
  *
@@ -432,14 +453,15 @@ int fs_getfilep(int fd, FAR struct file **filep)
 }
 
 /****************************************************************************
- * Name: nx_dup2
+ * Name: nx_dup2_from_tcb
  *
  * Description:
- *   nx_dup2() is similar to the standard 'dup2' interface except that is
- *   not a cancellation point and it does not modify the errno variable.
+ *   nx_dup2_from_tcb() is similar to the standard 'dup2' interface
+ *   except that is not a cancellation point and it does not modify the
+ *   errno variable.
  *
- *   nx_dup2() is an internal NuttX interface and should not be called from
- *   applications.
+ *   nx_dup2_from_tcb() is an internal NuttX interface and should not be
+ *   called from applications.
  *
  *   Clone a file descriptor to a specific descriptor number.
  *
@@ -449,11 +471,11 @@ int fs_getfilep(int fd, FAR struct file **filep)
  *
  ****************************************************************************/
 
-int nx_dup2(int fd1, int fd2)
+int nx_dup2_from_tcb(FAR struct tcb_s *tcb, int fd1, int fd2)
 {
   FAR struct filelist *list;
-  FAR struct file     *filep;
-  FAR struct file      file;
+  FAR struct file *filep;
+  FAR struct file  file;
   int ret;
 
   if (fd1 == fd2)
@@ -461,10 +483,9 @@ int nx_dup2(int fd1, int fd2)
       return fd1;
     }
 
-  /* Get the file descriptor list.  It should not be NULL in this context. */
+  list = nxsched_get_files_from_tcb(tcb);
 
-  list = nxsched_get_files();
-  DEBUGASSERT(list != NULL);
+  /* Get the file descriptor list.  It should not be NULL in this context. */
 
   if (fd1 < 0 || fd1 >= CONFIG_NFILE_DESCRIPTORS_PER_BLOCK * list->fl_rows ||
       fd2 < 0)
@@ -506,6 +527,29 @@ int nx_dup2(int fd1, int fd2)
   return ret < 0 ? ret : fd2;
 }
 
+/****************************************************************************
+ * Name: nx_dup2
+ *
+ * Description:
+ *   nx_dup2() is similar to the standard 'dup2' interface except that is
+ *   not a cancellation point and it does not modify the errno variable.
+ *
+ *   nx_dup2() is an internal NuttX interface and should not be called from
+ *   applications.
+ *
+ *   Clone a file descriptor to a specific descriptor number.
+ *
+ * Returned Value:
+ *   fd2 is returned on success; a negated errno value is return on
+ *   any failure.
+ *
+ ****************************************************************************/
+
+int nx_dup2(int fd1, int fd2)
+{
+  return nx_dup2_from_tcb(nxsched_self(), fd1, fd2);
+}
+
 /****************************************************************************
  * Name: dup2
  *
@@ -530,14 +574,15 @@ int dup2(int fd1, int fd2)
 }
 
 /****************************************************************************
- * Name: nx_close
+ * Name: nx_close_from_tcb
  *
  * Description:
- *   nx_close() is similar to the standard 'close' interface except that is
- *   not a cancellation point and it does not modify the errno variable.
+ *   nx_close_from_tcb() is similar to the standard 'close' interface
+ *   except that is not a cancellation point and it does not modify the
+ *   errno variable.
  *
- *   nx_close() is an internal NuttX interface and should not be called from
- *   applications.
+ *   nx_close_from_tcb() is an internal NuttX interface and should not
+ *   be called from applications.
  *
  *   Close an inode (if open)
  *
@@ -551,19 +596,14 @@ int dup2(int fd1, int fd2)
  *
  ****************************************************************************/
 
-int nx_close(int fd)
+int nx_close_from_tcb(FAR struct tcb_s *tcb, int fd)
 {
-  FAR struct filelist *list;
   FAR struct file     *filep;
   FAR struct file      file;
+  FAR struct filelist *list;
   int                  ret;
 
-  /* Get the thread-specific file list.  It should never be NULL in this
-   * context.
-   */
-
-  list = nxsched_get_files();
-  DEBUGASSERT(list != NULL);
+  list = nxsched_get_files_from_tcb(tcb);
 
   /* Perform the protected close operation */
 
@@ -592,6 +632,33 @@ int nx_close(int fd)
   return file_close(&file);
 }
 
+/****************************************************************************
+ * Name: nx_close
+ *
+ * Description:
+ *   nx_close() is similar to the standard 'close' interface except that is
+ *   not a cancellation point and it does not modify the errno variable.
+ *
+ *   nx_close() is an internal NuttX interface and should not be called from
+ *   applications.
+ *
+ *   Close an inode (if open)
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success; A negated errno value is returned on
+ *   on any failure.
+ *
+ * Assumptions:
+ *   Caller holds the list mutex because the file descriptor will be
+ *   freed.
+ *
+ ****************************************************************************/
+
+int nx_close(int fd)
+{
+  return nx_close_from_tcb(nxsched_self(), fd);
+}
+
 /****************************************************************************
  * Name: close
  *
diff --git a/fs/vfs/fs_open.c b/fs/vfs/fs_open.c
index 014eed9b75..44e344adf4 100644
--- a/fs/vfs/fs_open.c
+++ b/fs/vfs/fs_open.c
@@ -224,6 +224,7 @@ errout_with_search:
  *   applications.
  *
  * Input Parameters:
+ *   tcb    - Address of the task's TCB
  *   path   - The full path to the file to be opened.
  *   oflags - open flags.
  *   ap     - Variable argument list, may include 'mode_t mode'
@@ -234,7 +235,8 @@ errout_with_search:
  *
  ****************************************************************************/
 
-static int nx_vopen(FAR const char *path, int oflags, va_list ap)
+static int nx_vopen(FAR struct tcb_s *tcb,
+                    FAR const char *path, int oflags, va_list ap)
 {
   struct file filep;
   int ret;
@@ -250,8 +252,8 @@ static int nx_vopen(FAR const char *path, int oflags, va_list ap)
 
   /* Allocate a new file descriptor for the inode */
 
-  fd = file_allocate(filep.f_inode, filep.f_oflags,
-                     filep.f_pos, filep.f_priv, 0, false);
+  fd = file_allocate_from_tcb(tcb, filep.f_inode, filep.f_oflags,
+                              filep.f_pos, filep.f_priv, 0, false);
   if (fd < 0)
     {
       file_close(&filep);
@@ -341,6 +343,44 @@ int file_open(FAR struct file *filep, FAR const char *path, int oflags, ...)
   return ret;
 }
 
+/****************************************************************************
+ * Name: nx_open_from_tcb
+ *
+ * Description:
+ *   nx_open_from_tcb() is similar to the standard 'open' interface except
+ *   that it is not a cancellation point and it does not modify the errno
+ *   variable.
+ *
+ *   nx_open_from_tcb() is an internal NuttX interface and should not be
+ *   called from applications.
+ *
+ * Input Parameters:
+ *   tcb    - Address of the task's TCB
+ *   path   - The full path to the file to be opened.
+ *   oflags - open flags.
+ *   ...    - Variable number of arguments, may include 'mode_t mode'
+ *
+ * Returned Value:
+ *   The new file descriptor is returned on success; a negated errno value is
+ *   returned on any failure.
+ *
+ ****************************************************************************/
+
+int nx_open_from_tcb(FAR struct tcb_s *tcb,
+                     FAR const char *path, int oflags, ...)
+{
+  va_list ap;
+  int fd;
+
+  /* Let nx_vopen() do all of the work */
+
+  va_start(ap, oflags);
+  fd = nx_vopen(tcb, path, oflags, ap);
+  va_end(ap);
+
+  return fd;
+}
+
 /****************************************************************************
  * Name: nx_open
  *
@@ -370,7 +410,7 @@ int nx_open(FAR const char *path, int oflags, ...)
   /* Let nx_vopen() do all of the work */
 
   va_start(ap, oflags);
-  fd = nx_vopen(path, oflags, ap);
+  fd = nx_vopen(nxsched_self(), path, oflags, ap);
   va_end(ap);
 
   return fd;
@@ -400,7 +440,7 @@ int open(FAR const char *path, int oflags, ...)
   /* Let nx_vopen() do most of the work */
 
   va_start(ap, oflags);
-  fd = nx_vopen(path, oflags, ap);
+  fd = nx_vopen(nxsched_self(), path, oflags, ap);
   va_end(ap);
 
   /* Set the errno value if any errors were reported by nx_open() */
diff --git a/include/nuttx/binfmt/binfmt.h b/include/nuttx/binfmt/binfmt.h
index e1b8e18157..1da05b65c9 100644
--- a/include/nuttx/binfmt/binfmt.h
+++ b/include/nuttx/binfmt/binfmt.h
@@ -264,7 +264,8 @@ int unload_module(FAR struct binary_s *bin);
 
 int exec_module(FAR struct binary_s *binp,
                 FAR const char *filename, FAR char * const *argv,
-                FAR char * const *envp);
+                FAR char * const *envp,
+                FAR const posix_spawn_file_actions_t *actions);
 
 /****************************************************************************
  * Name: exec
@@ -355,6 +356,7 @@ int exec(FAR const char *filename, FAR char * const *argv,
  *              exported by the caller and made available for linking the
  *              module into the system.
  *   nexports - The number of symbols in the exports table.
+ *   actions  - The spawn file actions
  *   attr     - The spawn attributes.
  *
  * Returned Value:
@@ -366,7 +368,8 @@ int exec(FAR const char *filename, FAR char * const *argv,
 
 int exec_spawn(FAR const char *filename, FAR char * const *argv,
                FAR char * const *envp, FAR const struct symtab_s *exports,
-               int nexports, FAR const posix_spawnattr_t *attr);
+               int nexports, FAR const posix_spawn_file_actions_t *actions,
+               FAR const posix_spawnattr_t *attr);
 
 /****************************************************************************
  * Name: binfmt_exit
diff --git a/include/nuttx/fs/fs.h b/include/nuttx/fs/fs.h
index 5d36568066..d2db19e987 100644
--- a/include/nuttx/fs/fs.h
+++ b/include/nuttx/fs/fs.h
@@ -170,6 +170,7 @@ struct stat;
 struct statfs;
 struct pollfd;
 struct mtd_dev_s;
+struct tcb_s;
 
 /* The internal representation of type DIR is just a container for an inode
  * reference, and the path of directory.
@@ -785,6 +786,23 @@ void files_releaselist(FAR struct filelist *list);
 
 int files_duplist(FAR struct filelist *plist, FAR struct filelist *clist);
 
+/****************************************************************************
+ * Name: file_allocate_from_tcb
+ *
+ * Description:
+ *   Allocate a struct files instance and associate it with an inode
+ *   instance.
+ *
+ * Returned Value:
+ *     Returns the file descriptor == index into the files array on success;
+ *     a negated errno value is returned on any failure.
+ *
+ ****************************************************************************/
+
+int file_allocate_from_tcb(FAR struct tcb_s *tcb, FAR struct inode *inode,
+                           int oflags, off_t pos, FAR void *priv, int minfd,
+                           bool addref);
+
 /****************************************************************************
  * Name: file_allocate
  *
@@ -834,6 +852,27 @@ int file_dup(FAR struct file *filep, int minfd, bool cloexec);
 
 int file_dup2(FAR struct file *filep1, FAR struct file *filep2);
 
+/****************************************************************************
+ * Name: nx_dup2_from_tcb
+ *
+ * Description:
+ *   nx_dup2_from_tcb() is similar to the standard 'dup2' interface
+ *   except that is not a cancellation point and it does not modify the
+ *   errno variable.
+ *
+ *   nx_dup2_from_tcb() is an internal NuttX interface and should not be
+ *   called from applications.
+ *
+ *   Clone a file descriptor to a specific descriptor number.
+ *
+ * Returned Value:
+ *   fd2 is returned on success; a negated errno value is return on
+ *   any failure.
+ *
+ ****************************************************************************/
+
+int nx_dup2_from_tcb(FAR struct tcb_s *tcb, int fd1, int fd2);
+
 /****************************************************************************
  * Name: nx_dup2
  *
@@ -875,6 +914,32 @@ int nx_dup2(int fd1, int fd2);
 
 int file_open(FAR struct file *filep, FAR const char *path, int oflags, ...);
 
+/****************************************************************************
+ * Name: nx_open_from_tcb
+ *
+ * Description:
+ *   nx_open_from_tcb() is similar to the standard 'open' interface except
+ *   that it is not a cancellation point and it does not modify the errno
+ *   variable.
+ *
+ *   nx_open_from_tcb() is an internal NuttX interface and should not be
+ *   called from applications.
+ *
+ * Input Parameters:
+ *   tcb    - Address of the task's TCB
+ *   path   - The full path to the file to be opened.
+ *   oflags - open flags.
+ *   ...    - Variable number of arguments, may include 'mode_t mode'
+ *
+ * Returned Value:
+ *   The new file descriptor is returned on success; a negated errno value is
+ *   returned on any failure.
+ *
+ ****************************************************************************/
+
+int nx_open_from_tcb(FAR struct tcb_s *tcb,
+                     FAR const char *path, int oflags, ...);
+
 /****************************************************************************
  * Name: nx_open
  *
@@ -931,6 +996,31 @@ int fs_getfilep(int fd, FAR struct file **filep);
 
 int file_close(FAR struct file *filep);
 
+/****************************************************************************
+ * Name: nx_close_from_tcb
+ *
+ * Description:
+ *   nx_close_from_tcb() is similar to the standard 'close' interface
+ *   except that is not a cancellation point and it does not modify the
+ *   errno variable.
+ *
+ *   nx_close_from_tcb() is an internal NuttX interface and should not
+ *   be called from applications.
+ *
+ *   Close an inode (if open)
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success; A negated errno value is returned on
+ *   on any failure.
+ *
+ * Assumptions:
+ *   Caller holds the list mutex because the file descriptor will be
+ *   freed.
+ *
+ ****************************************************************************/
+
+int nx_close_from_tcb(FAR struct tcb_s *tcb, int fd);
+
 /****************************************************************************
  * Name: nx_close
  *
@@ -1043,7 +1133,6 @@ int close_mtddriver(FAR struct inode *pinode);
  ****************************************************************************/
 
 #ifdef CONFIG_FILE_STREAM
-struct tcb_s; /* Forward reference */
 int fs_fdopen(int fd, int oflags, FAR struct tcb_s *tcb,
               FAR struct file_struct **filep);
 #endif
diff --git a/include/nuttx/sched.h b/include/nuttx/sched.h
index 1a163f6ac5..82df2b831f 100644
--- a/include/nuttx/sched.h
+++ b/include/nuttx/sched.h
@@ -847,6 +847,40 @@ int nxsched_release_tcb(FAR struct tcb_s *tcb, uint8_t ttype);
  * the currently executing task.
  */
 
+/****************************************************************************
+ * Name: nxsched_get_files_from_tcb
+ *
+ * Description:
+ *   Return a pointer to the file list from task context
+ *
+ * Input Parameters:
+ *   tcb - Address of the new task's TCB
+ *
+ * Returned Value:
+ *   A pointer to the errno.
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+FAR struct filelist *nxsched_get_files_from_tcb(FAR struct tcb_s *tcb);
+
+/****************************************************************************
+ * Name: nxsched_get_files
+ *
+ * Description:
+ *   Return a pointer to the file list for this thread
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   A pointer to the errno.
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
 FAR struct filelist *nxsched_get_files(void);
 
 /****************************************************************************
diff --git a/include/nuttx/spawn.h b/include/nuttx/spawn.h
index 09535c0371..c552e15f9a 100644
--- a/include/nuttx/spawn.h
+++ b/include/nuttx/spawn.h
@@ -100,6 +100,9 @@ extern "C"
 void add_file_action(FAR posix_spawn_file_actions_t *file_action,
                      FAR struct spawn_general_file_action_s *entry);
 
+int spawn_file_actions(FAR struct tcb_s *tcb,
+                       FAR const posix_spawn_file_actions_t *actions);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/sched/init/nx_bringup.c b/sched/init/nx_bringup.c
index 14a88d7eec..24c3c5fbfe 100644
--- a/sched/init/nx_bringup.c
+++ b/sched/init/nx_bringup.c
@@ -295,7 +295,7 @@ static inline void nx_start_application(void)
   attr.stacksize = CONFIG_INIT_STACKSIZE;
 
   ret = exec_spawn(CONFIG_INIT_FILEPATH, argv, NULL,
-                   CONFIG_INIT_SYMTAB, CONFIG_INIT_NEXPORTS, &attr);
+                   CONFIG_INIT_SYMTAB, CONFIG_INIT_NEXPORTS, NULL, &attr);
 #endif
   posix_spawnattr_destroy(&attr);
   DEBUGASSERT(ret > 0);
diff --git a/sched/sched/sched_getfiles.c b/sched/sched/sched_getfiles.c
index cdbb49a5fb..baa21b2393 100644
--- a/sched/sched/sched_getfiles.c
+++ b/sched/sched/sched_getfiles.c
@@ -31,13 +31,13 @@
  ****************************************************************************/
 
 /****************************************************************************
- * Name: nxsched_get_files
+ * Name: nxsched_get_files_from_tcb
  *
  * Description:
- *   Return a pointer to the file list for this thread
+ *   Return a pointer to the file list from task context
  *
  * Input Parameters:
- *   None
+ *   tcb - Address of the new task's TCB
  *
  * Returned Value:
  *   A pointer to the errno.
@@ -46,10 +46,9 @@
  *
  ****************************************************************************/
 
-FAR struct filelist *nxsched_get_files(void)
+FAR struct filelist *nxsched_get_files_from_tcb(FAR struct tcb_s *tcb)
 {
-  FAR struct tcb_s *rtcb = this_task();
-  FAR struct task_group_s *group = rtcb->group;
+  FAR struct task_group_s *group = tcb->group;
 
   /* The group may be NULL under certain conditions.  For example, if
    * debug output is attempted from the IDLE thead before the group has
@@ -66,3 +65,24 @@ FAR struct filelist *nxsched_get_files(void)
 
   return NULL;
 }
+
+/****************************************************************************
+ * Name: nxsched_get_files
+ *
+ * Description:
+ *   Return a pointer to the file list for this thread
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   A pointer to the errno.
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+FAR struct filelist *nxsched_get_files(void)
+{
+  return nxsched_get_files_from_tcb(this_task());
+}
diff --git a/sched/task/spawn.h b/sched/task/spawn.h
index 9b75c5a8cc..e55d6d0b4e 100644
--- a/sched/task/spawn.h
+++ b/sched/task/spawn.h
@@ -29,55 +29,6 @@
 #include <nuttx/mutex.h>
 #include <spawn.h>
 
-/****************************************************************************
- * Pre-processor Definitions
- ****************************************************************************/
-
-#ifndef CONFIG_POSIX_SPAWN_PROXY_STACKSIZE
-#  define CONFIG_POSIX_SPAWN_PROXY_STACKSIZE 1024
-#endif
-
-/****************************************************************************
- * Public Type Definitions
- ****************************************************************************/
-
-struct spawn_parms_s
-{
-  /* Common parameters */
-
-  int result;
-  FAR pid_t *pid;
-  FAR const posix_spawn_file_actions_t *file_actions;
-  FAR const posix_spawnattr_t *attr;
-  FAR char * const *argv;
-  FAR char * const *envp;
-
-  /* Parameters that differ for posix_spawn[p] and task_spawn */
-
-  union
-  {
-    struct
-    {
-      FAR const char *path;
-    } posix;
-    struct
-    {
-      FAR const char *name;
-      main_t entry;
-    } task;
-  } u;
-};
-
-/****************************************************************************
- * Public Data
- ****************************************************************************/
-
-extern mutex_t g_spawn_parmlock;
-#ifndef CONFIG_SCHED_WAITPID
-extern sem_t g_spawn_execsem;
-#endif
-extern struct spawn_parms_s g_spawn_parms;
-
 /****************************************************************************
  * Public Function Prototypes
  ****************************************************************************/
@@ -116,16 +67,10 @@ int spawn_execattrs(pid_t pid, FAR const posix_spawnattr_t *attr);
  *
  * Input Parameters:
  *
- *   pid - The pid of the new task.
  *   attr - The attributes to use
- *   file_actions - The attributes to use
- *
- * Returned Value:
- *   0 (OK) on success; A negated errno value is returned on failure.
  *
  ****************************************************************************/
 
-int spawn_proxyattrs(FAR const posix_spawnattr_t *attr,
-                     FAR const posix_spawn_file_actions_t *file_actions);
+void spawn_proxyattrs(FAR const posix_spawnattr_t *attr);
 
 #endif /* __SCHED_TASK_SPAWN_H */
diff --git a/sched/task/task_posixspawn.c b/sched/task/task_posixspawn.c
index a4d9e4a780..0fb56c97b9 100644
--- a/sched/task/task_posixspawn.c
+++ b/sched/task/task_posixspawn.c
@@ -59,6 +59,8 @@
  *     CONFIG_LIBC_ENVPATH is defined, this may be either a relative or
  *     or an absolute path.  Otherwise, it must be an absolute path.
  *
+ *   actions - The spawn file actions
+ *
  *   attr - If the value of the 'attr' parameter is NULL, the all default
  *     values for the POSIX spawn attributes will be used.  Otherwise, the
  *     attributes will be set according to the spawn flags.  The
@@ -84,6 +86,7 @@
  ****************************************************************************/
 
 static int nxposix_spawn_exec(FAR pid_t *pidp, FAR const char *path,
+                              FAR const posix_spawn_file_actions_t *actions,
                               FAR const posix_spawnattr_t *attr,
                               FAR char * const argv[],
                               FAR char * const envp[])
@@ -108,7 +111,7 @@ static int nxposix_spawn_exec(FAR pid_t *pidp, FAR const char *path,
 
   /* Start the task */
 
-  pid = exec_spawn(path, argv, envp, symtab, nsymbols, attr);
+  pid = exec_spawn(path, argv, envp, symtab, nsymbols, actions, attr);
   if (pid < 0)
     {
       ret = -pid;
@@ -140,81 +143,6 @@ errout:
   return ret;
 }
 
-/****************************************************************************
- * Name: nxposix_spawn_proxy
- *
- * Description:
- *   Perform file_actions, then execute the task from the file system.
- *
- *   Do we really need this proxy task?  Isn't that wasteful?
- *
- *   Q: Why not use a starthook so that there is callout from nxtask_start()
- *      to perform these operations after the file is loaded from
- *      the file system?
- *   A: That existing nxtask_starthook() implementation cannot be used in
- *      this context; any of nxtask_starthook() will also conflict with
- *      binfmt's use of the start hook to call C++ static initializers.
- *      task_restart() would also be an issue.
- *
- * Input Parameters:
- *   Standard task start-up parameters
- *
- * Returned Value:
- *   Standard task return value.
- *
- ****************************************************************************/
-
-static int nxposix_spawn_proxy(int argc, FAR char *argv[])
-{
-  int ret;
-
-  /* Perform file actions and/or set a custom signal mask.  We get here only
-   * if the file_actions parameter to posix_spawn[p] was non-NULL and/or the
-   * option to change the signal mask was selected.
-   */
-
-  DEBUGASSERT(g_spawn_parms.file_actions ||
-              (g_spawn_parms.attr &&
-               (g_spawn_parms.attr->flags & POSIX_SPAWN_SETSIGMASK) != 0));
-
-  /* Set the attributes and perform the file actions as appropriate */
-
-  ret = spawn_proxyattrs(g_spawn_parms.attr, g_spawn_parms.file_actions);
-  if (ret == OK)
-    {
-      /* Start the task */
-
-      ret = nxposix_spawn_exec(g_spawn_parms.pid, g_spawn_parms.u.posix.path,
-                               g_spawn_parms.attr, g_spawn_parms.argv,
-                               g_spawn_parms.envp);
-
-#ifdef CONFIG_SCHED_HAVE_PARENT
-      if (ret == OK)
-        {
-          /* Change of the parent of the task we just spawned to our parent.
-           * What should we do in the event of a failure?
-           */
-
-          int tmp = task_reparent(0, *g_spawn_parms.pid);
-          if (tmp < 0)
-            {
-              serr("ERROR: task_reparent() failed: %d\n", tmp);
-            }
-        }
-#endif
-    }
-
-  /* Post the semaphore to inform the parent task that we have completed
-   * what we need to do.
-   */
-
-  g_spawn_parms.result = ret;
-#ifndef CONFIG_SCHED_WAITPID
-  nxsem_post(&g_spawn_execsem);
-#endif
-  return OK;
-}
-
 /****************************************************************************
  * Public Functions
  ****************************************************************************/
@@ -311,125 +239,15 @@ int posix_spawn(FAR pid_t *pid, FAR const char *path,
                 FAR const posix_spawnattr_t *attr,
                 FAR char * const argv[], FAR char * const envp[])
 {
-  struct sched_param param;
-  int proxy;
-#ifdef CONFIG_SCHED_WAITPID
-  int status;
-#endif
-  int ret;
-
-  DEBUGASSERT(path);
-
   sinfo("pid=%p path=%s file_actions=%p attr=%p argv=%p\n",
         pid, path, file_actions, attr, argv);
 
-  /* If there are no file actions to be performed and there is no change to
-   * the signal mask, then start the new child task directly from the parent
-   * task.
-   */
-
-  if ((file_actions == NULL || *file_actions == NULL) &&
-      (attr == NULL || (attr->flags & POSIX_SPAWN_SETSIGMASK) == 0))
+  if (attr != NULL)
     {
-      return nxposix_spawn_exec(pid, path, attr, argv, envp);
+      spawn_proxyattrs(attr);
     }
 
-  /* Otherwise, we will have to go through an intermediary/proxy task in
-   * order to perform the I/O redirection.  This would be a natural place
-   * to fork().  However, true fork() behavior requires an MMU and most
-   * implementations of vfork() are not capable of these operations.
-   *
-   * Even without fork(), we can still do the job, but parameter passing is
-   * messier.  Unfortunately, there is no (clean) way to pass binary values
-   * as a task parameter, so we will use a semaphore-protected global
-   * structure.
-   */
-
-  /* Get exclusive access to the global parameter structure */
-
-  ret = nxmutex_lock(&g_spawn_parmlock);
-  if (ret < 0)
-    {
-      serr("ERROR: nxmutex_lock failed: %d\n", ret);
-      return -ret;
-    }
-
-  /* Populate the parameter structure */
-
-  g_spawn_parms.result       = ENOSYS;
-  g_spawn_parms.pid          = pid;
-  g_spawn_parms.file_actions = file_actions ? *file_actions : NULL;
-  g_spawn_parms.attr         = attr;
-  g_spawn_parms.argv         = argv;
-  g_spawn_parms.envp         = envp;
-  g_spawn_parms.u.posix.path = path;
-
-  /* Get the priority of this (parent) task */
-
-  ret = nxsched_get_param(0, &param);
-  if (ret < 0)
-    {
-      serr("ERROR: nxsched_get_param failed: %d\n", ret);
-      nxmutex_unlock(&g_spawn_parmlock);
-      return -ret;
-    }
-
-  /* Disable pre-emption so that the proxy does not run until waitpid
-   * is called.  This is probably unnecessary since the nxposix_spawn_proxy
-   * has the same priority as this thread; it should be schedule behind
-   * this task in the ready-to-run list.
-   */
-
-#ifdef CONFIG_SCHED_WAITPID
-  sched_lock();
-#endif
-
-  /* Start the intermediary/proxy task at the same priority as the parent
-   * task.
-   */
-
-  proxy = nxthread_create("nxposix_spawn_proxy", TCB_FLAG_TTYPE_KERNEL,
-                          param.sched_priority, NULL,
-                          CONFIG_POSIX_SPAWN_PROXY_STACKSIZE,
-                          nxposix_spawn_proxy, NULL, environ);
-  if (proxy < 0)
-    {
-      ret = -proxy;
-      serr("ERROR: Failed to start nxposix_spawn_proxy: %d\n", ret);
-      goto errout_with_lock;
-    }
-
-  /* Wait for the proxy to complete its job */
-
-#ifdef CONFIG_SCHED_WAITPID
-  /* REVISIT: This should not call waitpid() directly.  waitpid is a
-   * cancellation point and modifies the errno value.  It is inappropriate
-   * for use within the OS.
-   */
-
-  ret = nxsched_waitpid((pid_t)proxy, &status, 0);
-  if (ret < 0)
-    {
-      serr("ERROR: waitpid() failed: %d\n", ret);
-      goto errout_with_lock;
-    }
-#else
-  ret = nxsem_wait_uninterruptible(&g_spawn_execsem);
-  if (ret < 0)
-    {
-      serr("ERROR: nxsem_wait_uninterruptible() failed: %d\n", ret);
-      goto errout_with_lock;
-    }
-#endif
-
-  /* Get the result and relinquish our access to the parameter structure */
-
-  ret = g_spawn_parms.result;
-
-errout_with_lock:
-#ifdef CONFIG_SCHED_WAITPID
-  sched_unlock();
-#endif
-  nxmutex_unlock(&g_spawn_parmlock);
-  return ret;
+  return nxposix_spawn_exec(pid, path,
+                            file_actions != NULL ?
+                            *file_actions : NULL, attr, argv, envp);
 }
diff --git a/sched/task/task_spawn.c b/sched/task/task_spawn.c
index b680508b04..bb011a3853 100644
--- a/sched/task/task_spawn.c
+++ b/sched/task/task_spawn.c
@@ -46,6 +46,92 @@
  * Private Functions
  ****************************************************************************/
 
+/****************************************************************************
+ * Name: nxtask_spawn_create
+ *
+ * Description:
+ *   This function creates and activates a new thread of the specified type
+ *   with a specified priority and returns its system-assigned ID.  It is the
+ *   internal, common implementation of task_create() and kthread_create().
+ *   See comments with task_create() for further information.
+ *
+ * Input Parameters:
+ *   name       - Name of the new task
+ *   ttype      - Type of the new task
+ *   priority   - Priority of the new task
+ *   stack_addr - Address of the stack needed
+ *   stack_size - Size (in bytes) of the stack needed
+ *   entry      - Entry point of a new task
+ *   arg        - A pointer to an array of input parameters.  The array
+ *                should be terminated with a NULL argv[] value. If no
+ *                parameters are required, argv may be NULL.
+ *   envp       - A pointer to an array of environment strings. Terminated
+ *                with a NULL entry.
+ *   actions    - The spawn file actions
+ *
+ * Returned Value:
+ *   Returns the positive, non-zero process ID of the new task or a negated
+ *   errno value to indicate the nature of any failure.  If memory is
+ *   insufficient or the task cannot be created -ENOMEM will be returned.
+ *
+ ****************************************************************************/
+
+static int nxtask_spawn_create(FAR const char *name, int priority,
+                              FAR void *stack_addr, int stack_size,
+                              main_t entry, FAR char * const argv[],
+                              FAR char * const envp[],
+                              FAR const posix_spawn_file_actions_t *actions)
+{
+  FAR struct task_tcb_s *tcb;
+  pid_t pid;
+  int ret;
+
+  /* Allocate a TCB for the new task. */
+
+  tcb = (FAR struct task_tcb_s *)kmm_zalloc(sizeof(struct task_tcb_s));
+  if (tcb == NULL)
+    {
+      serr("ERROR: Failed to allocate TCB\n");
+      return -ENOMEM;
+    }
+
+  /* Setup the task type */
+
+  tcb->cmn.flags = TCB_FLAG_TTYPE_TASK;
+
+  /* Initialize the task */
+
+  ret = nxtask_init(tcb, name, priority, stack_addr, stack_size,
+                    entry, argv, envp);
+  if (ret < OK)
+    {
+      kmm_free(tcb);
+      return ret;
+    }
+
+  /* Perform file actions */
+
+  if (actions != NULL)
+    {
+      ret = spawn_file_actions(&tcb->cmn, actions);
+      if (ret < 0)
+        {
+          nxtask_uninit(tcb);
+          return ret;
+        }
+    }
+
+  /* Get the assigned pid before we start the task */
+
+  pid = tcb->cmn.pid;
+
+  /* Activate the task */
+
+  nxtask_activate(&tcb->cmn);
+
+  return (int)pid;
+}
+
 /****************************************************************************
  * Name: nxtask_spawn_exec
  *
@@ -61,6 +147,8 @@
  *
  *   entry - The child task's entry point (an address in memory)
  *
+ *   actions - The spawn file actions
+ *
  *   attr - If the value of the 'attr' parameter is NULL, the all default
  *     values for the POSIX spawn attributes will be used.  Otherwise, the
  *     attributes will be set according to the spawn flags.  The
@@ -89,7 +177,9 @@
  ****************************************************************************/
 
 static int nxtask_spawn_exec(FAR pid_t *pidp, FAR const char *name,
-                             main_t entry, FAR const posix_spawnattr_t *attr,
+                             main_t entry,
+                             FAR const posix_spawn_file_actions_t *actions,
+                             FAR const posix_spawnattr_t *attr,
                              FAR char * const *argv, FAR char * const envp[])
 {
   FAR void *stackaddr = NULL;
@@ -131,12 +221,13 @@ static int nxtask_spawn_exec(FAR pid_t *pidp, FAR const char *name,
 
   /* Start the task */
 
-  pid = nxtask_create(name, priority, stackaddr,
-                      stacksize, entry, argv, envp);
+  pid = nxtask_spawn_create(name, priority, stackaddr,
+                            stacksize, entry, argv,
+                            envp ? envp : environ, actions);
   if (pid < 0)
     {
       ret = pid;
-      serr("ERROR: nxtask_create failed: %d\n", ret);
+      serr("ERROR: nxtask_spawn_create failed: %d\n", ret);
       goto errout;
     }
 
@@ -164,92 +255,6 @@ errout:
   return ret;
 }
 
-/****************************************************************************
- * Name: nxtask_spawn_proxy
- *
- * Description:
- *   Perform file_actions, then execute the task from the file system.
- *
- *   Do we really need a proxy task in this case?  Isn't that wasteful?
- *
- *   Q: Why can we do what we need to do here and the just call the
- *      new task's entry point.
- *   A: This would require setting up the name, priority, and stacksize from
- *      the task_spawn, but it do-able.  The only issue I can think of is
- *      that NuttX supports task_restart(), and you would never be able to
- *      restart a task from this point.
- *
- *   Q: Why not use a starthook so that there is callout from nxtask_start()
- *      to perform these operations?
- *   A: Good idea, except that existing nxtask_starthook() implementation
- *      cannot be used here unless we get rid of task_create and, instead,
- *      use nxtask_init() and nxtask_activate().  start_taskhook() could then
- *      be called between nxtask_init() and nxtask_activate().
- *      task_restart() would still be an issue.
- *
- * Input Parameters:
- *   argc, argv - Ignored. The task's start-up parameters are passed via the
- *     semaphore-protected global structure g_spawn_parms.
- *
- * Returned Value:
- *   Standard task return value.
- *
- ****************************************************************************/
-
-static int nxtask_spawn_proxy(int argc, FAR char *argv[])
-{
-  int ret;
-
-  /* Perform file actions and/or set a custom signal mask.  We get here only
-   * if the file_actions parameter to task_spawn[p] was non-NULL and/or the
-   * option to change the signal mask was selected.
-   */
-
-  UNUSED(argc);
-  UNUSED(argv);
-
-  DEBUGASSERT(g_spawn_parms.file_actions ||
-              (g_spawn_parms.attr &&
-               (g_spawn_parms.attr->flags & POSIX_SPAWN_SETSIGMASK) != 0));
-
-  /* Set the attributes and perform the file actions as appropriate */
-
-  ret = spawn_proxyattrs(g_spawn_parms.attr, g_spawn_parms.file_actions);
-  if (ret == OK)
-    {
-      /* Start the task */
-
-      ret = nxtask_spawn_exec(g_spawn_parms.pid, g_spawn_parms.u.task.name,
-                              g_spawn_parms.u.task.entry, g_spawn_parms.attr,
-                              g_spawn_parms.argv, g_spawn_parms.envp);
-
-#ifdef CONFIG_SCHED_HAVE_PARENT
-      if (ret == OK)
-        {
-          /* Change of the parent of the task we just spawned to our parent.
-           * What should we do in the event of a failure?
-           */
-
-          int tmp = task_reparent(0, *g_spawn_parms.pid);
-          if (tmp < 0)
-            {
-              serr("ERROR: task_reparent() failed: %d\n", tmp);
-            }
-        }
-#endif
-    }
-
-  /* Post the semaphore to inform the parent task that we have completed
-   * what we need to do.
-   */
-
-  g_spawn_parms.result = ret;
-#ifndef CONFIG_SCHED_WAITPID
-  nxsem_post(&g_spawn_execsem);
-#endif
-  return OK;
-}
-
 /****************************************************************************
  * Public Functions
  ****************************************************************************/
@@ -321,142 +326,22 @@ int task_spawn(FAR const char *name, main_t entry,
                FAR const posix_spawnattr_t *attr,
                FAR char * const argv[], FAR char * const envp[])
 {
-  struct sched_param param;
-  pid_t proxy;
   pid_t pid = INVALID_PROCESS_ID;
-#ifdef CONFIG_SCHED_WAITPID
-  int status;
-#endif
   int ret;
 
   sinfo("name=%s entry=%p file_actions=%p attr=%p argv=%p\n",
         name, entry, file_actions, attr, argv);
 
-  /* If there are no file actions to be performed and there is no change to
-   * the signal mask, then start the new child task directly from the parent
-   * task.
-   */
-
-  if ((file_actions == NULL || *file_actions == NULL) &&
-      (attr == NULL || (attr->flags & POSIX_SPAWN_SETSIGMASK) == 0))
+  if (attr != NULL)
     {
-      ret = nxtask_spawn_exec(&pid, name, entry, attr, argv, envp);
-      if (ret < 0)
-        {
-          return ret;
-        }
-
-      return pid;
-    }
-
-  /* Otherwise, we will have to go through an intermediary/proxy task in
-   * order to perform the I/O redirection.  This would be a natural place to
-   * fork(). However, true fork() behavior requires an MMU and most
-   * implementations of vfork() are not capable of these operations.
-   *
-   * Even without fork(), we can still do the job, but parameter passing is
-   * messier.  Unfortunately, there is no (clean) way to pass binary values
-   * as a task parameter, so we will use a semaphore-protected global
-   * structure.
-   */
-
-  /* Get exclusive access to the global parameter structure */
-
-  ret = nxmutex_lock(&g_spawn_parmlock);
-  if (ret < 0)
-    {
-      serr("ERROR: nxmutex_lock failed: %d\n", ret);
-      return ret;
+      spawn_proxyattrs(attr);
     }
 
-  /* Populate the parameter structure */
-
-  g_spawn_parms.result       = ENOSYS;
-  g_spawn_parms.pid          = &pid;
-  g_spawn_parms.file_actions = file_actions ? *file_actions : NULL;
-  g_spawn_parms.attr         = attr;
-  g_spawn_parms.argv         = argv;
-  g_spawn_parms.envp         = envp;
-  g_spawn_parms.u.task.name  = name;
-  g_spawn_parms.u.task.entry = entry;
-
-  /* Get the priority of this (parent) task */
+  ret = nxtask_spawn_exec(&pid, name, entry,
+                          file_actions != NULL ? *file_actions : NULL,
+                          attr, argv, envp);
 
-  ret = nxsched_get_param(0, &param);
-  if (ret < 0)
-    {
-      serr("ERROR: nxsched_get_param failed: %d\n", ret);
-      g_spawn_parms.pid = NULL;
-      nxmutex_unlock(&g_spawn_parmlock);
-      return ret;
-    }
-
-#ifdef CONFIG_SCHED_WAITPID
-  /* Disable pre-emption so that the proxy does not run until waitpid
-   * is called.  This is probably unnecessary since the nxtask_spawn_proxy
-   * has the same priority as this thread; it should be schedule behind
-   * this task in the ready-to-run list.
-   *
-   * REVISIT:  This will may not have the desired effect in SMP mode.
-   */
-
-  sched_lock();
-#endif
-
-  /* Start the intermediary/proxy task at the same priority as the parent
-   * task.
-   */
-
-  proxy = nxtask_create("nxtask_spawn_proxy", param.sched_priority,
-                        NULL, CONFIG_POSIX_SPAWN_PROXY_STACKSIZE,
-                        nxtask_spawn_proxy, NULL, NULL);
-  if (proxy < 0)
-    {
-      ret = proxy;
-      serr("ERROR: Failed to start nxtask_spawn_proxy: %d\n", ret);
-      goto errout_with_lock;
-    }
-
-  /* Wait for the proxy to complete its job */
-
-#ifdef CONFIG_SCHED_WAITPID
-  /* REVISIT: This should not call waitpid() directly.  waitpid is a
-   * cancellation point and modifies the errno value.  It is inappropriate
-   * for use within the OS.
-   */
-
-  ret = nxsched_waitpid(proxy, &status, 0);
-  if (ret < 0)
-    {
-      serr("ERROR: waitpid() failed: %d\n", ret);
-      goto errout_with_lock;
-    }
-#else
-  ret = nxsem_wait_uninterruptible(&g_spawn_execsem);
-  if (ret < 0)
-    {
-      serr("ERROR: g_spawn_execsem() failed: %d\n", ret);
-      goto errout_with_lock;
-    }
-#endif
-
-  /* Get the result and relinquish our access to the parameter structure */
-
-  ret = -g_spawn_parms.result;
-  if (ret < 0)
-    {
-      goto errout_with_lock;
-    }
-
-  ret = (int)pid;
-
-errout_with_lock:
-#ifdef CONFIG_SCHED_WAITPID
-  sched_unlock();
-#endif
-  g_spawn_parms.pid = NULL;
-  nxmutex_unlock(&g_spawn_parmlock);
-  return ret;
+  return ret >= 0 ? (int)pid : ret;
 }
 
 #endif /* CONFIG_BUILD_KERNEL */
diff --git a/sched/task/task_spawnparms.c b/sched/task/task_spawnparms.c
index 3a62f1006c..2813713534 100644
--- a/sched/task/task_spawnparms.c
+++ b/sched/task/task_spawnparms.c
@@ -38,16 +38,6 @@
 #include "task/spawn.h"
 #include "task/task.h"
 
-/****************************************************************************
- * Public Data
- ****************************************************************************/
-
-mutex_t g_spawn_parmlock = NXMUTEX_INITIALIZER;
-#ifndef CONFIG_SCHED_WAITPID
-sem_t g_spawn_execsem = SEM_INITIALIZER(0);
-#endif
-struct spawn_parms_s g_spawn_parms;
-
 /****************************************************************************
  * Private Functions
  ****************************************************************************/
@@ -68,73 +58,53 @@ struct spawn_parms_s g_spawn_parms;
  *
  ****************************************************************************/
 
-static inline int nxspawn_close(FAR struct spawn_close_file_action_s *action)
+static inline int nxspawn_close(FAR struct tcb_s *tcb,
+                                FAR struct spawn_close_file_action_s *action)
 {
   /* The return value from nx_close() is ignored */
 
   sinfo("Closing fd=%d\n", action->fd);
 
-  nx_close(action->fd);
-  return OK;
+  return nx_close_from_tcb(tcb, action->fd);
 }
 
-static inline int nxspawn_dup2(FAR struct spawn_dup2_file_action_s *action)
+static inline int nxspawn_dup2(FAR struct tcb_s *tcb,
+                               FAR struct spawn_dup2_file_action_s *action)
 {
-  int ret;
-
   /* Perform the dup */
 
   sinfo("Dup'ing %d->%d\n", action->fd1, action->fd2);
 
-  ret = nx_dup2(action->fd1, action->fd2);
-  if (ret < 0)
-    {
-      serr("ERROR: dup2 failed: %d\n", ret);
-      return ret;
-    }
-
-  return OK;
+  return nx_dup2_from_tcb(tcb, action->fd1, action->fd2);
 }
 
-static inline int nxspawn_open(FAR struct spawn_open_file_action_s *action)
+static inline int nxspawn_open(FAR struct tcb_s *tcb,
+                               FAR struct spawn_open_file_action_s *action)
 {
-  int fd;
   int ret = OK;
+  int fd;
 
   /* Open the file */
 
   sinfo("Open'ing path=%s oflags=%04x mode=%04x\n",
         action->path, action->oflags, action->mode);
 
-  fd = nx_open(action->path, action->oflags, action->mode);
+  nx_close_from_tcb(tcb, action->fd);
+
+  fd = nx_open_from_tcb(tcb, action->path, action->oflags, action->mode);
   if (fd < 0)
     {
       ret = fd;
-      serr("ERROR: open failed: %d\n", ret);
     }
-
-  /* Does the return file descriptor happen to match the required file
-   * descriptor number?
-   */
-
   else if (fd != action->fd)
     {
-      /* No.. dup2 to get the correct file number */
-
-      sinfo("Dup'ing %d->%d\n", fd, action->fd);
-
-      ret = nx_dup2(fd, action->fd);
-      if (ret < 0)
-        {
-          serr("ERROR: dup2 failed: %d\n", ret);
-        }
-      else
+      ret = nx_dup2_from_tcb(tcb, fd, action->fd);
+      if (ret >= 0)
         {
           ret = OK;
         }
 
-      sinfo("Closing fd=%d\n", fd);
-      nx_close(fd);
+      nx_close_from_tcb(tcb, fd);
     }
 
   return ret;
@@ -266,61 +236,66 @@ int spawn_execattrs(pid_t pid, FAR const posix_spawnattr_t *attr)
  *
  * Input Parameters:
  *
- *   pid - The pid of the new task.
  *   attr - The attributes to use
- *   file_actions - The attributes to use
- *
- * Returned Value:
- *   0 (OK) on success; A negated errno value is returned on failure.
  *
  ****************************************************************************/
 
-int spawn_proxyattrs(FAR const posix_spawnattr_t *attr,
-                     FAR const posix_spawn_file_actions_t *file_actions)
+void spawn_proxyattrs(FAR const posix_spawnattr_t *attr)
 {
-  FAR struct spawn_general_file_action_s *entry;
-  int ret = OK;
-
   /* Check if we need to change the signal mask */
 
   if (attr != NULL && (attr->flags & POSIX_SPAWN_SETSIGMASK) != 0)
     {
       nxsig_procmask(SIG_SETMASK, &attr->sigmask, NULL);
     }
+}
 
-  /* Were we also requested to perform file actions? */
+/****************************************************************************
+ * Name: spawn_file_actions
+ *
+ * Description:
+ *   Perform Spawn file object that specifies file-related actions
+ *
+ * Input Parameters:
+ *
+ *   attr - The spawn file actions
+ *
+ * Returned Value:
+ *   0 (OK) on success; A negated errno value is returned on failure.
+ *
+ ****************************************************************************/
 
-  if (file_actions != NULL)
-    {
-      /* Yes.. Execute each file action */
+int spawn_file_actions(FAR struct tcb_s *tcb,
+                       FAR const posix_spawn_file_actions_t *actions)
+{
+  FAR struct spawn_general_file_action_s *entry;
+  int ret = OK;
+
+  /* Execute each file action */
 
-      for (entry = (FAR struct spawn_general_file_action_s *)file_actions;
-           entry && ret == OK;
-           entry = entry->flink)
+  for (entry = (FAR struct spawn_general_file_action_s *)actions;
+       entry && ret == OK;
+       entry = entry->flink)
+    {
+      switch (entry->action)
         {
-          switch (entry->action)
-            {
-              case SPAWN_FILE_ACTION_CLOSE:
-                ret = nxspawn_close((FAR struct spawn_close_file_action_s *)
-                                    entry);
-                break;
-
-              case SPAWN_FILE_ACTION_DUP2:
-                ret = nxspawn_dup2((FAR struct spawn_dup2_file_action_s *)
-                                   entry);
-                break;
-
-              case SPAWN_FILE_ACTION_OPEN:
-                ret = nxspawn_open((FAR struct spawn_open_file_action_s *)
-                                   entry);
-                break;
-
-              case SPAWN_FILE_ACTION_NONE:
-              default:
-                serr("ERROR: Unknown action: %d\n", entry->action);
-                ret = EINVAL;
-                break;
-            }
+          case SPAWN_FILE_ACTION_CLOSE:
+            ret = nxspawn_close(tcb, (FAR void *)entry);
+            break;
+
+          case SPAWN_FILE_ACTION_DUP2:
+            ret = nxspawn_dup2(tcb, (FAR void *)entry);
+            break;
+
+          case SPAWN_FILE_ACTION_OPEN:
+            ret = nxspawn_open(tcb, (FAR void *)entry);
+            break;
+
+          case SPAWN_FILE_ACTION_NONE:
+          default:
+            serr("ERROR: Unknown action: %d\n", entry->action);
+            ret = -EINVAL;
+            break;
         }
     }