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:
parent
89ae45be18
commit
507c8145a9
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -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() */
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -30,6 +30,42 @@
|
||||
* 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
|
||||
*
|
||||
@ -48,21 +84,5 @@
|
||||
|
||||
FAR struct filelist *nxsched_get_files(void)
|
||||
{
|
||||
FAR struct tcb_s *rtcb = 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;
|
||||
return nxsched_get_files_from_tcb(this_task());
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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, ¶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;
|
||||
return nxposix_spawn_exec(pid, path,
|
||||
file_actions != NULL ?
|
||||
*file_actions : NULL, attr, argv, envp);
|
||||
}
|
||||
|
@ -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;
|
||||
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.
|
||||
*/
|
||||
ret = nxtask_spawn_exec(&pid, name, entry,
|
||||
file_actions != NULL ? *file_actions : NULL,
|
||||
attr, argv, envp);
|
||||
|
||||
/* 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;
|
||||
return ret >= 0 ? (int)pid : ret;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_BUILD_KERNEL */
|
||||
|
@ -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)
|
||||
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 *)actions;
|
||||
entry && ret == OK;
|
||||
entry = entry->flink)
|
||||
{
|
||||
/* Yes.. Execute each file action */
|
||||
|
||||
for (entry = (FAR struct spawn_general_file_action_s *)file_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_CLOSE:
|
||||
ret = nxspawn_close(tcb, (FAR void *)entry);
|
||||
break;
|
||||
|
||||
case SPAWN_FILE_ACTION_DUP2:
|
||||
ret = nxspawn_dup2((FAR struct spawn_dup2_file_action_s *)
|
||||
entry);
|
||||
break;
|
||||
case SPAWN_FILE_ACTION_DUP2:
|
||||
ret = nxspawn_dup2(tcb, (FAR void *)entry);
|
||||
break;
|
||||
|
||||
case SPAWN_FILE_ACTION_OPEN:
|
||||
ret = nxspawn_open((FAR struct spawn_open_file_action_s *)
|
||||
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;
|
||||
}
|
||||
case SPAWN_FILE_ACTION_NONE:
|
||||
default:
|
||||
serr("ERROR: Unknown action: %d\n", entry->action);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user