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