mirror of
https://github.com/apache/nuttx.git
synced 2026-06-06 00:14:22 +08:00
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 <anchao@xiaomi.com>
This commit is contained in:
@@ -62,6 +62,7 @@
|
|||||||
* exported by the caller and made available for linking the
|
* exported by the caller and made available for linking the
|
||||||
* module into the system.
|
* module into the system.
|
||||||
* nexports - The number of symbols in the exports table.
|
* nexports - The number of symbols in the exports table.
|
||||||
|
* actions - The spawn file actions
|
||||||
* attr - The spawn attributes.
|
* attr - The spawn attributes.
|
||||||
*
|
*
|
||||||
* Returned Value:
|
* Returned Value:
|
||||||
@@ -72,7 +73,8 @@
|
|||||||
|
|
||||||
int exec_spawn(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,
|
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;
|
FAR struct binary_s *bin;
|
||||||
int pid;
|
int pid;
|
||||||
@@ -128,7 +130,7 @@ int exec_spawn(FAR const char *filename, FAR char * const *argv,
|
|||||||
|
|
||||||
/* Then start the module */
|
/* Then start the module */
|
||||||
|
|
||||||
pid = exec_module(bin, filename, argv, envp);
|
pid = exec_module(bin, filename, argv, envp, actions);
|
||||||
if (pid < 0)
|
if (pid < 0)
|
||||||
{
|
{
|
||||||
ret = pid;
|
ret = pid;
|
||||||
@@ -239,7 +241,7 @@ int exec(FAR const char *filename, FAR char * const *argv,
|
|||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = exec_spawn(filename, argv, envp, exports, nexports, NULL);
|
ret = exec_spawn(filename, argv, envp, exports, nexports, NULL, NULL);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
set_errno(-ret);
|
set_errno(-ret);
|
||||||
|
|||||||
@@ -35,6 +35,7 @@
|
|||||||
#include <nuttx/arch.h>
|
#include <nuttx/arch.h>
|
||||||
#include <nuttx/kmalloc.h>
|
#include <nuttx/kmalloc.h>
|
||||||
#include <nuttx/sched.h>
|
#include <nuttx/sched.h>
|
||||||
|
#include <nuttx/spawn.h>
|
||||||
#include <nuttx/binfmt/binfmt.h>
|
#include <nuttx/binfmt/binfmt.h>
|
||||||
|
|
||||||
#include "binfmt.h"
|
#include "binfmt.h"
|
||||||
@@ -113,7 +114,8 @@ static void exec_ctors(FAR void *arg)
|
|||||||
|
|
||||||
int exec_module(FAR struct binary_s *binp,
|
int exec_module(FAR struct binary_s *binp,
|
||||||
FAR const char *filename, FAR char * const *argv,
|
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;
|
FAR struct task_tcb_s *tcb;
|
||||||
#if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_BUILD_KERNEL)
|
#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_freeargv(argv);
|
||||||
binfmt_freeenv(envp);
|
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)
|
#if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_ARCH_KERNEL_STACK)
|
||||||
/* Allocate the kernel stack */
|
/* Allocate the kernel stack */
|
||||||
|
|
||||||
@@ -283,7 +296,6 @@ int exec_module(FAR struct binary_s *binp,
|
|||||||
|
|
||||||
return (int)pid;
|
return (int)pid;
|
||||||
|
|
||||||
#if defined(CONFIG_ARCH_ADDRENV) || defined(CONFIG_ARCH_VMA_MAPPING)
|
|
||||||
errout_with_tcbinit:
|
errout_with_tcbinit:
|
||||||
#ifndef CONFIG_BUILD_KERNEL
|
#ifndef CONFIG_BUILD_KERNEL
|
||||||
if (binp->stackaddr != NULL)
|
if (binp->stackaddr != NULL)
|
||||||
@@ -294,7 +306,6 @@ errout_with_tcbinit:
|
|||||||
|
|
||||||
nxtask_uninit(tcb);
|
nxtask_uninit(tcb);
|
||||||
return ret;
|
return ret;
|
||||||
#endif
|
|
||||||
|
|
||||||
errout_with_addrenv:
|
errout_with_addrenv:
|
||||||
#if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_BUILD_KERNEL)
|
#if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_BUILD_KERNEL)
|
||||||
|
|||||||
@@ -1750,7 +1750,8 @@ static void uart_launch_worker(void *arg)
|
|||||||
CONFIG_TTY_LAUNCH_ENTRYPOINT,
|
CONFIG_TTY_LAUNCH_ENTRYPOINT,
|
||||||
NULL, &attr, argv, NULL);
|
NULL, &attr, argv, NULL);
|
||||||
#else
|
#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
|
#endif
|
||||||
posix_spawnattr_destroy(&attr);
|
posix_spawnattr_destroy(&attr);
|
||||||
}
|
}
|
||||||
|
|||||||
+93
-26
@@ -185,7 +185,7 @@ void files_releaselist(FAR struct filelist *list)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: file_allocate
|
* Name: file_allocate_from_tcb
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* Allocate a struct files instance and associate it with an inode
|
* 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,
|
int file_allocate_from_tcb(FAR struct tcb_s *tcb, FAR struct inode *inode,
|
||||||
FAR void *priv, int minfd, bool addref)
|
int oflags, off_t pos, FAR void *priv, int minfd,
|
||||||
|
bool addref)
|
||||||
{
|
{
|
||||||
FAR struct filelist *list;
|
FAR struct filelist *list;
|
||||||
int ret;
|
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. */
|
/* 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);
|
DEBUGASSERT(list != NULL);
|
||||||
|
|
||||||
ret = nxmutex_lock(&list->fl_lock);
|
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;
|
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
|
* 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:
|
* Description:
|
||||||
* nx_dup2() is similar to the standard 'dup2' interface except that is
|
* nx_dup2_from_tcb() is similar to the standard 'dup2' interface
|
||||||
* not a cancellation point and it does not modify the errno variable.
|
* 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
|
* nx_dup2_from_tcb() is an internal NuttX interface and should not be
|
||||||
* applications.
|
* called from applications.
|
||||||
*
|
*
|
||||||
* Clone a file descriptor to a specific descriptor number.
|
* Clone a file descriptor to a specific descriptor number.
|
||||||
*
|
*
|
||||||
@@ -449,7 +471,7 @@ 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 filelist *list;
|
||||||
FAR struct file *filep;
|
FAR struct file *filep;
|
||||||
@@ -461,10 +483,9 @@ int nx_dup2(int fd1, int fd2)
|
|||||||
return fd1;
|
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();
|
/* Get the file descriptor list. It should not be NULL in this context. */
|
||||||
DEBUGASSERT(list != NULL);
|
|
||||||
|
|
||||||
if (fd1 < 0 || fd1 >= CONFIG_NFILE_DESCRIPTORS_PER_BLOCK * list->fl_rows ||
|
if (fd1 < 0 || fd1 >= CONFIG_NFILE_DESCRIPTORS_PER_BLOCK * list->fl_rows ||
|
||||||
fd2 < 0)
|
fd2 < 0)
|
||||||
@@ -506,6 +527,29 @@ int nx_dup2(int fd1, int fd2)
|
|||||||
return ret < 0 ? ret : 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
|
* Name: dup2
|
||||||
*
|
*
|
||||||
@@ -530,14 +574,15 @@ int dup2(int fd1, int fd2)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: nx_close
|
* Name: nx_close_from_tcb
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* nx_close() is similar to the standard 'close' interface except that is
|
* nx_close_from_tcb() is similar to the standard 'close' interface
|
||||||
* not a cancellation point and it does not modify the errno variable.
|
* 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
|
* nx_close_from_tcb() is an internal NuttX interface and should not
|
||||||
* applications.
|
* be called from applications.
|
||||||
*
|
*
|
||||||
* Close an inode (if open)
|
* 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 *filep;
|
||||||
FAR struct file file;
|
FAR struct file file;
|
||||||
|
FAR struct filelist *list;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* Get the thread-specific file list. It should never be NULL in this
|
list = nxsched_get_files_from_tcb(tcb);
|
||||||
* context.
|
|
||||||
*/
|
|
||||||
|
|
||||||
list = nxsched_get_files();
|
|
||||||
DEBUGASSERT(list != NULL);
|
|
||||||
|
|
||||||
/* Perform the protected close operation */
|
/* Perform the protected close operation */
|
||||||
|
|
||||||
@@ -592,6 +632,33 @@ int nx_close(int fd)
|
|||||||
return file_close(&file);
|
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
|
* Name: close
|
||||||
*
|
*
|
||||||
|
|||||||
+44
-4
@@ -224,6 +224,7 @@ errout_with_search:
|
|||||||
* applications.
|
* applications.
|
||||||
*
|
*
|
||||||
* Input Parameters:
|
* Input Parameters:
|
||||||
|
* tcb - Address of the task's TCB
|
||||||
* path - The full path to the file to be opened.
|
* path - The full path to the file to be opened.
|
||||||
* oflags - open flags.
|
* oflags - open flags.
|
||||||
* ap - Variable argument list, may include 'mode_t mode'
|
* 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;
|
struct file filep;
|
||||||
int ret;
|
int ret;
|
||||||
@@ -250,7 +252,7 @@ static int nx_vopen(FAR const char *path, int oflags, va_list ap)
|
|||||||
|
|
||||||
/* Allocate a new file descriptor for the inode */
|
/* Allocate a new file descriptor for the inode */
|
||||||
|
|
||||||
fd = file_allocate(filep.f_inode, filep.f_oflags,
|
fd = file_allocate_from_tcb(tcb, filep.f_inode, filep.f_oflags,
|
||||||
filep.f_pos, filep.f_priv, 0, false);
|
filep.f_pos, filep.f_priv, 0, false);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
{
|
{
|
||||||
@@ -341,6 +343,44 @@ int file_open(FAR struct file *filep, FAR const char *path, int oflags, ...)
|
|||||||
return ret;
|
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
|
* Name: nx_open
|
||||||
*
|
*
|
||||||
@@ -370,7 +410,7 @@ int nx_open(FAR const char *path, int oflags, ...)
|
|||||||
/* Let nx_vopen() do all of the work */
|
/* Let nx_vopen() do all of the work */
|
||||||
|
|
||||||
va_start(ap, oflags);
|
va_start(ap, oflags);
|
||||||
fd = nx_vopen(path, oflags, ap);
|
fd = nx_vopen(nxsched_self(), path, oflags, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
return fd;
|
return fd;
|
||||||
@@ -400,7 +440,7 @@ int open(FAR const char *path, int oflags, ...)
|
|||||||
/* Let nx_vopen() do most of the work */
|
/* Let nx_vopen() do most of the work */
|
||||||
|
|
||||||
va_start(ap, oflags);
|
va_start(ap, oflags);
|
||||||
fd = nx_vopen(path, oflags, ap);
|
fd = nx_vopen(nxsched_self(), path, oflags, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
/* Set the errno value if any errors were reported by nx_open() */
|
/* Set the errno value if any errors were reported by nx_open() */
|
||||||
|
|||||||
@@ -264,7 +264,8 @@ int unload_module(FAR struct binary_s *bin);
|
|||||||
|
|
||||||
int exec_module(FAR struct binary_s *binp,
|
int exec_module(FAR struct binary_s *binp,
|
||||||
FAR const char *filename, FAR char * const *argv,
|
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
|
* 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
|
* exported by the caller and made available for linking the
|
||||||
* module into the system.
|
* module into the system.
|
||||||
* nexports - The number of symbols in the exports table.
|
* nexports - The number of symbols in the exports table.
|
||||||
|
* actions - The spawn file actions
|
||||||
* attr - The spawn attributes.
|
* attr - The spawn attributes.
|
||||||
*
|
*
|
||||||
* Returned Value:
|
* 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,
|
int exec_spawn(FAR const char *filename, FAR char * const *argv,
|
||||||
FAR char * const *envp, FAR const struct symtab_s *exports,
|
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
|
* Name: binfmt_exit
|
||||||
|
|||||||
+90
-1
@@ -170,6 +170,7 @@ struct stat;
|
|||||||
struct statfs;
|
struct statfs;
|
||||||
struct pollfd;
|
struct pollfd;
|
||||||
struct mtd_dev_s;
|
struct mtd_dev_s;
|
||||||
|
struct tcb_s;
|
||||||
|
|
||||||
/* The internal representation of type DIR is just a container for an inode
|
/* The internal representation of type DIR is just a container for an inode
|
||||||
* reference, and the path of directory.
|
* 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);
|
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
|
* 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);
|
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
|
* 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, ...);
|
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
|
* Name: nx_open
|
||||||
*
|
*
|
||||||
@@ -931,6 +996,31 @@ int fs_getfilep(int fd, FAR struct file **filep);
|
|||||||
|
|
||||||
int file_close(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
|
* Name: nx_close
|
||||||
*
|
*
|
||||||
@@ -1043,7 +1133,6 @@ int close_mtddriver(FAR struct inode *pinode);
|
|||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#ifdef CONFIG_FILE_STREAM
|
#ifdef CONFIG_FILE_STREAM
|
||||||
struct tcb_s; /* Forward reference */
|
|
||||||
int fs_fdopen(int fd, int oflags, FAR struct tcb_s *tcb,
|
int fs_fdopen(int fd, int oflags, FAR struct tcb_s *tcb,
|
||||||
FAR struct file_struct **filep);
|
FAR struct file_struct **filep);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -847,6 +847,40 @@ int nxsched_release_tcb(FAR struct tcb_s *tcb, uint8_t ttype);
|
|||||||
* the currently executing task.
|
* 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);
|
FAR struct filelist *nxsched_get_files(void);
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
|
|||||||
@@ -100,6 +100,9 @@ extern "C"
|
|||||||
void add_file_action(FAR posix_spawn_file_actions_t *file_action,
|
void add_file_action(FAR posix_spawn_file_actions_t *file_action,
|
||||||
FAR struct spawn_general_file_action_s *entry);
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -295,7 +295,7 @@ static inline void nx_start_application(void)
|
|||||||
attr.stacksize = CONFIG_INIT_STACKSIZE;
|
attr.stacksize = CONFIG_INIT_STACKSIZE;
|
||||||
|
|
||||||
ret = exec_spawn(CONFIG_INIT_FILEPATH, argv, NULL,
|
ret = exec_spawn(CONFIG_INIT_FILEPATH, argv, NULL,
|
||||||
CONFIG_INIT_SYMTAB, CONFIG_INIT_NEXPORTS, &attr);
|
CONFIG_INIT_SYMTAB, CONFIG_INIT_NEXPORTS, NULL, &attr);
|
||||||
#endif
|
#endif
|
||||||
posix_spawnattr_destroy(&attr);
|
posix_spawnattr_destroy(&attr);
|
||||||
DEBUGASSERT(ret > 0);
|
DEBUGASSERT(ret > 0);
|
||||||
|
|||||||
@@ -30,6 +30,42 @@
|
|||||||
* Public Functions
|
* Public Functions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* 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)
|
||||||
|
{
|
||||||
|
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
|
||||||
|
* been allocated. I have only seen this case when memory management
|
||||||
|
* debug is enabled.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (group)
|
||||||
|
{
|
||||||
|
return &group->tg_filelist;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Higher level logic must handle the NULL gracefully */
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: nxsched_get_files
|
* Name: nxsched_get_files
|
||||||
*
|
*
|
||||||
@@ -48,21 +84,5 @@
|
|||||||
|
|
||||||
FAR struct filelist *nxsched_get_files(void)
|
FAR struct filelist *nxsched_get_files(void)
|
||||||
{
|
{
|
||||||
FAR struct tcb_s *rtcb = this_task();
|
return nxsched_get_files_from_tcb(this_task());
|
||||||
FAR struct task_group_s *group = rtcb->group;
|
|
||||||
|
|
||||||
/* The group may be NULL under certain conditions. For example, if
|
|
||||||
* debug output is attempted from the IDLE thead before the group has
|
|
||||||
* been allocated. I have only seen this case when memory management
|
|
||||||
* debug is enabled.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (group)
|
|
||||||
{
|
|
||||||
return &group->tg_filelist;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Higher level logic must handle the NULL gracefully */
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-56
@@ -29,55 +29,6 @@
|
|||||||
#include <nuttx/mutex.h>
|
#include <nuttx/mutex.h>
|
||||||
#include <spawn.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
|
* Public Function Prototypes
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
@@ -116,16 +67,10 @@ int spawn_execattrs(pid_t pid, FAR const posix_spawnattr_t *attr);
|
|||||||
*
|
*
|
||||||
* Input Parameters:
|
* Input Parameters:
|
||||||
*
|
*
|
||||||
* pid - The pid of the new task.
|
|
||||||
* attr - The attributes to use
|
* 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,
|
void spawn_proxyattrs(FAR const posix_spawnattr_t *attr);
|
||||||
FAR const posix_spawn_file_actions_t *file_actions);
|
|
||||||
|
|
||||||
#endif /* __SCHED_TASK_SPAWN_H */
|
#endif /* __SCHED_TASK_SPAWN_H */
|
||||||
|
|||||||
@@ -59,6 +59,8 @@
|
|||||||
* CONFIG_LIBC_ENVPATH is defined, this may be either a relative or
|
* CONFIG_LIBC_ENVPATH is defined, this may be either a relative or
|
||||||
* or an absolute path. Otherwise, it must be an absolute path.
|
* 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
|
* attr - If the value of the 'attr' parameter is NULL, the all default
|
||||||
* values for the POSIX spawn attributes will be used. Otherwise, the
|
* values for the POSIX spawn attributes will be used. Otherwise, the
|
||||||
* attributes will be set according to the spawn flags. 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,
|
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 const posix_spawnattr_t *attr,
|
||||||
FAR char * const argv[],
|
FAR char * const argv[],
|
||||||
FAR char * const envp[])
|
FAR char * const envp[])
|
||||||
@@ -108,7 +111,7 @@ static int nxposix_spawn_exec(FAR pid_t *pidp, FAR const char *path,
|
|||||||
|
|
||||||
/* Start the task */
|
/* 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)
|
if (pid < 0)
|
||||||
{
|
{
|
||||||
ret = -pid;
|
ret = -pid;
|
||||||
@@ -140,81 +143,6 @@ errout:
|
|||||||
return ret;
|
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
|
* Public Functions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
@@ -311,125 +239,15 @@ int posix_spawn(FAR pid_t *pid, FAR const char *path,
|
|||||||
FAR const posix_spawnattr_t *attr,
|
FAR const posix_spawnattr_t *attr,
|
||||||
FAR char * const argv[], FAR char * const envp[])
|
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",
|
sinfo("pid=%p path=%s file_actions=%p attr=%p argv=%p\n",
|
||||||
pid, path, file_actions, attr, argv);
|
pid, path, file_actions, attr, argv);
|
||||||
|
|
||||||
/* If there are no file actions to be performed and there is no change to
|
if (attr != NULL)
|
||||||
* 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))
|
|
||||||
{
|
{
|
||||||
return nxposix_spawn_exec(pid, path, attr, argv, envp);
|
spawn_proxyattrs(attr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Otherwise, we will have to go through an intermediary/proxy task in
|
return nxposix_spawn_exec(pid, path,
|
||||||
* order to perform the I/O redirection. This would be a natural place
|
file_actions != NULL ?
|
||||||
* to fork(). However, true fork() behavior requires an MMU and most
|
*file_actions : NULL, attr, argv, envp);
|
||||||
* 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, ¶m);
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|||||||
+101
-216
@@ -46,6 +46,92 @@
|
|||||||
* Private Functions
|
* 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
|
* Name: nxtask_spawn_exec
|
||||||
*
|
*
|
||||||
@@ -61,6 +147,8 @@
|
|||||||
*
|
*
|
||||||
* entry - The child task's entry point (an address in memory)
|
* 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
|
* attr - If the value of the 'attr' parameter is NULL, the all default
|
||||||
* values for the POSIX spawn attributes will be used. Otherwise, the
|
* values for the POSIX spawn attributes will be used. Otherwise, the
|
||||||
* attributes will be set according to the spawn flags. 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,
|
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 char * const *argv, FAR char * const envp[])
|
||||||
{
|
{
|
||||||
FAR void *stackaddr = NULL;
|
FAR void *stackaddr = NULL;
|
||||||
@@ -131,12 +221,13 @@ static int nxtask_spawn_exec(FAR pid_t *pidp, FAR const char *name,
|
|||||||
|
|
||||||
/* Start the task */
|
/* Start the task */
|
||||||
|
|
||||||
pid = nxtask_create(name, priority, stackaddr,
|
pid = nxtask_spawn_create(name, priority, stackaddr,
|
||||||
stacksize, entry, argv, envp);
|
stacksize, entry, argv,
|
||||||
|
envp ? envp : environ, actions);
|
||||||
if (pid < 0)
|
if (pid < 0)
|
||||||
{
|
{
|
||||||
ret = pid;
|
ret = pid;
|
||||||
serr("ERROR: nxtask_create failed: %d\n", ret);
|
serr("ERROR: nxtask_spawn_create failed: %d\n", ret);
|
||||||
goto errout;
|
goto errout;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,92 +255,6 @@ errout:
|
|||||||
return ret;
|
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
|
* Public Functions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
@@ -321,142 +326,22 @@ int task_spawn(FAR const char *name, main_t entry,
|
|||||||
FAR const posix_spawnattr_t *attr,
|
FAR const posix_spawnattr_t *attr,
|
||||||
FAR char * const argv[], FAR char * const envp[])
|
FAR char * const argv[], FAR char * const envp[])
|
||||||
{
|
{
|
||||||
struct sched_param param;
|
|
||||||
pid_t proxy;
|
|
||||||
pid_t pid = INVALID_PROCESS_ID;
|
pid_t pid = INVALID_PROCESS_ID;
|
||||||
#ifdef CONFIG_SCHED_WAITPID
|
|
||||||
int status;
|
|
||||||
#endif
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
sinfo("name=%s entry=%p file_actions=%p attr=%p argv=%p\n",
|
sinfo("name=%s entry=%p file_actions=%p attr=%p argv=%p\n",
|
||||||
name, entry, file_actions, attr, argv);
|
name, entry, file_actions, attr, argv);
|
||||||
|
|
||||||
/* If there are no file actions to be performed and there is no change to
|
if (attr != NULL)
|
||||||
* 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))
|
|
||||||
{
|
{
|
||||||
ret = nxtask_spawn_exec(&pid, name, entry, attr, argv, envp);
|
spawn_proxyattrs(attr);
|
||||||
if (ret < 0)
|
|
||||||
{
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return pid;
|
ret = nxtask_spawn_exec(&pid, name, entry,
|
||||||
}
|
file_actions != NULL ? *file_actions : NULL,
|
||||||
|
attr, argv, envp);
|
||||||
|
|
||||||
/* Otherwise, we will have to go through an intermediary/proxy task in
|
return ret >= 0 ? (int)pid : ret;
|
||||||
* 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.task.name = name;
|
|
||||||
g_spawn_parms.u.task.entry = entry;
|
|
||||||
|
|
||||||
/* Get the priority of this (parent) task */
|
|
||||||
|
|
||||||
ret = nxsched_get_param(0, ¶m);
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_BUILD_KERNEL */
|
#endif /* CONFIG_BUILD_KERNEL */
|
||||||
|
|||||||
@@ -38,16 +38,6 @@
|
|||||||
#include "task/spawn.h"
|
#include "task/spawn.h"
|
||||||
#include "task/task.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
|
* 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 */
|
/* The return value from nx_close() is ignored */
|
||||||
|
|
||||||
sinfo("Closing fd=%d\n", action->fd);
|
sinfo("Closing fd=%d\n", action->fd);
|
||||||
|
|
||||||
nx_close(action->fd);
|
return nx_close_from_tcb(tcb, action->fd);
|
||||||
return OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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 */
|
/* Perform the dup */
|
||||||
|
|
||||||
sinfo("Dup'ing %d->%d\n", action->fd1, action->fd2);
|
sinfo("Dup'ing %d->%d\n", action->fd1, action->fd2);
|
||||||
|
|
||||||
ret = nx_dup2(action->fd1, action->fd2);
|
return nx_dup2_from_tcb(tcb, action->fd1, action->fd2);
|
||||||
if (ret < 0)
|
|
||||||
{
|
|
||||||
serr("ERROR: dup2 failed: %d\n", ret);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return OK;
|
static inline int nxspawn_open(FAR struct tcb_s *tcb,
|
||||||
}
|
FAR struct spawn_open_file_action_s *action)
|
||||||
|
|
||||||
static inline int nxspawn_open(FAR struct spawn_open_file_action_s *action)
|
|
||||||
{
|
{
|
||||||
int fd;
|
|
||||||
int ret = OK;
|
int ret = OK;
|
||||||
|
int fd;
|
||||||
|
|
||||||
/* Open the file */
|
/* Open the file */
|
||||||
|
|
||||||
sinfo("Open'ing path=%s oflags=%04x mode=%04x\n",
|
sinfo("Open'ing path=%s oflags=%04x mode=%04x\n",
|
||||||
action->path, action->oflags, action->mode);
|
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)
|
if (fd < 0)
|
||||||
{
|
{
|
||||||
ret = fd;
|
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)
|
else if (fd != action->fd)
|
||||||
{
|
{
|
||||||
/* No.. dup2 to get the correct file number */
|
ret = nx_dup2_from_tcb(tcb, fd, action->fd);
|
||||||
|
if (ret >= 0)
|
||||||
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 = OK;
|
ret = OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
sinfo("Closing fd=%d\n", fd);
|
nx_close_from_tcb(tcb, fd);
|
||||||
nx_close(fd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@@ -266,63 +236,68 @@ int spawn_execattrs(pid_t pid, FAR const posix_spawnattr_t *attr)
|
|||||||
*
|
*
|
||||||
* Input Parameters:
|
* Input Parameters:
|
||||||
*
|
*
|
||||||
* pid - The pid of the new task.
|
|
||||||
* attr - The attributes to use
|
* 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,
|
void spawn_proxyattrs(FAR const posix_spawnattr_t *attr)
|
||||||
FAR const posix_spawn_file_actions_t *file_actions)
|
|
||||||
{
|
{
|
||||||
FAR struct spawn_general_file_action_s *entry;
|
|
||||||
int ret = OK;
|
|
||||||
|
|
||||||
/* Check if we need to change the signal mask */
|
/* Check if we need to change the signal mask */
|
||||||
|
|
||||||
if (attr != NULL && (attr->flags & POSIX_SPAWN_SETSIGMASK) != 0)
|
if (attr != NULL && (attr->flags & POSIX_SPAWN_SETSIGMASK) != 0)
|
||||||
{
|
{
|
||||||
nxsig_procmask(SIG_SETMASK, &attr->sigmask, NULL);
|
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)
|
int spawn_file_actions(FAR struct tcb_s *tcb,
|
||||||
|
FAR const posix_spawn_file_actions_t *actions)
|
||||||
{
|
{
|
||||||
/* Yes.. Execute each file action */
|
FAR struct spawn_general_file_action_s *entry;
|
||||||
|
int ret = OK;
|
||||||
|
|
||||||
for (entry = (FAR struct spawn_general_file_action_s *)file_actions;
|
/* Execute each file action */
|
||||||
|
|
||||||
|
for (entry = (FAR struct spawn_general_file_action_s *)actions;
|
||||||
entry && ret == OK;
|
entry && ret == OK;
|
||||||
entry = entry->flink)
|
entry = entry->flink)
|
||||||
{
|
{
|
||||||
switch (entry->action)
|
switch (entry->action)
|
||||||
{
|
{
|
||||||
case SPAWN_FILE_ACTION_CLOSE:
|
case SPAWN_FILE_ACTION_CLOSE:
|
||||||
ret = nxspawn_close((FAR struct spawn_close_file_action_s *)
|
ret = nxspawn_close(tcb, (FAR void *)entry);
|
||||||
entry);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SPAWN_FILE_ACTION_DUP2:
|
case SPAWN_FILE_ACTION_DUP2:
|
||||||
ret = nxspawn_dup2((FAR struct spawn_dup2_file_action_s *)
|
ret = nxspawn_dup2(tcb, (FAR void *)entry);
|
||||||
entry);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SPAWN_FILE_ACTION_OPEN:
|
case SPAWN_FILE_ACTION_OPEN:
|
||||||
ret = nxspawn_open((FAR struct spawn_open_file_action_s *)
|
ret = nxspawn_open(tcb, (FAR void *)entry);
|
||||||
entry);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SPAWN_FILE_ACTION_NONE:
|
case SPAWN_FILE_ACTION_NONE:
|
||||||
default:
|
default:
|
||||||
serr("ERROR: Unknown action: %d\n", entry->action);
|
serr("ERROR: Unknown action: %d\n", entry->action);
|
||||||
ret = EINVAL;
|
ret = -EINVAL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user