From 19e43efe230a2b8720d98cba5a6ad156942e291f Mon Sep 17 00:00:00 2001 From: patacongo Date: Thu, 17 Jan 2013 18:32:13 +0000 Subject: NSH will now run files from the file system; Add logic to unload and clean-up after running a task from a file system; Extensions to builtin apps from Mike Smith git-svn-id: http://svn.code.sf.net/p/nuttx/code/trunk@5529 42af7a65-404d-4744-a932-0658087f49c3 --- nuttx/libc/spawn/lib_ps.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nuttx/libc') diff --git a/nuttx/libc/spawn/lib_ps.c b/nuttx/libc/spawn/lib_ps.c index 638b27f87..000f711a3 100644 --- a/nuttx/libc/spawn/lib_ps.c +++ b/nuttx/libc/spawn/lib_ps.c @@ -247,7 +247,7 @@ static int ps_exec(FAR pid_t *pidp, FAR const char *path, errout: sched_unlock(); - return OK; + return ret; } /**************************************************************************** -- cgit v1.2.3 From 2f653578c632ec95e94f67306af24c7d82700d28 Mon Sep 17 00:00:00 2001 From: patacongo Date: Thu, 17 Jan 2013 20:25:32 +0000 Subject: Misc bug fixes related to NSH file execution git-svn-id: http://svn.code.sf.net/p/nuttx/code/trunk@5530 42af7a65-404d-4744-a932-0658087f49c3 --- apps/builtin/exec_builtin.c | 16 +++++++++++++ apps/nshlib/nsh_builtin.c | 54 +++++++++++++++++++++++++++----------------- apps/nshlib/nsh_fileapps.c | 53 +++++++++++++++++++++++++++---------------- nuttx/configs/sim/README.txt | 33 ++++++++++++++++++++------- nuttx/libc/spawn/lib_ps.c | 16 +++++++++++++ 5 files changed, 123 insertions(+), 49 deletions(-) (limited to 'nuttx/libc') diff --git a/apps/builtin/exec_builtin.c b/apps/builtin/exec_builtin.c index d4431164c..803d1ef34 100644 --- a/apps/builtin/exec_builtin.c +++ b/apps/builtin/exec_builtin.c @@ -46,6 +46,7 @@ #include +#include #include #include #include @@ -92,7 +93,9 @@ struct builtin_parms_s ****************************************************************************/ static sem_t g_builtin_parmsem = SEM_INITIALIZER(1); +#ifndef CONFIG_SCHED_WAITPID static sem_t g_builtin_execsem = SEM_INITIALIZER(0); +#endif static struct builtin_parms_s g_builtin_parms; /**************************************************************************** @@ -274,7 +277,9 @@ static int builtin_proxy(int argc, char *argv[]) */ g_builtin_parms.result = ret; +#ifndef CONFIG_SCHED_WAITPID builtin_semgive(&g_builtin_execsem); +#endif return 0; } @@ -299,6 +304,9 @@ static inline int builtin_startproxy(int index, FAR const char **argv, struct sched_param param; pid_t proxy; int errcode; +#ifdef CONFIG_SCHED_WAITPID + int status; +#endif int ret; svdbg("index=%d argv=%p redirfile=%s oflags=%04x\n", @@ -353,7 +361,15 @@ static inline int builtin_startproxy(int index, FAR const char **argv, * for this. */ +#ifdef CONFIG_SCHED_WAITPID + ret = waitpid(proxy, &status, 0); + if (ret < 0) + { + sdbg("ERROR: waitpid() failed: %d\n", errno); + } +#else bultin_semtake(&g_builtin_execsem); +#endif /* Get the result and relinquish our access to the parameter structure */ diff --git a/apps/nshlib/nsh_builtin.c b/apps/nshlib/nsh_builtin.c index 2d23ca8d8..343a0824b 100644 --- a/apps/nshlib/nsh_builtin.c +++ b/apps/nshlib/nsh_builtin.c @@ -51,7 +51,6 @@ #endif #include -#include #include #include @@ -117,8 +116,8 @@ int nsh_builtin(FAR struct nsh_vtbl_s *vtbl, FAR const char *cmd, { int ret = OK; - /* Lock the scheduler to prevent the application from running until the - * waitpid() has been called. + /* Lock the scheduler in an attempt to prevent the application from + * running until waitpid() has been called. */ sched_lock(); @@ -146,18 +145,6 @@ int nsh_builtin(FAR struct nsh_vtbl_s *vtbl, FAR const char *cmd, #ifdef CONFIG_SCHED_WAITPID - /* Check if the application is still running */ - - if (kill(ret, 0) < 0) - { - /* It is not running. In this case, we have no idea if the - * application ran successfully or not. Let's assume that is - * did. - */ - - return 0; - } - /* CONFIG_SCHED_WAITPID is selected, so we may run the command in * foreground unless we were specifically requested to run the command * in background (and running commands in background is enabled). @@ -169,15 +156,40 @@ int nsh_builtin(FAR struct nsh_vtbl_s *vtbl, FAR const char *cmd, { int rc = 0; - /* Wait for the application to exit. Since we have locked the - * scheduler above, we know that the application has not yet - * started and there is no possibility that it has already exited. - * The scheduler will be unlocked while waitpid is waiting and the - * application will be able to run. + /* Wait for the application to exit. We did locked the scheduler + * above, but that does not guarantee that the application did not + * run in the case where I/O was redirected. The scheduler will + * be unlocked while waitpid is waiting and if the application has + * not yet run, it will be able to to do so. */ ret = waitpid(ret, &rc, 0); - if (ret >= 0) + if (ret < 0) + { + /* If the child thread does not exist, waitpid() will return + * the error ECHLD. Since we know that the task was successfully + * started, this must be one of the cases described above; we + * have to assume that the task already exit'ed. In this case, + * we have no idea if the application ran successfully or not + * (because NuttX does not retain exit status of child tasks). + * Let's assume that is did run successfully. + */ + + int errcode = errno; + if (errcode == ECHILD) + { + ret = OK; + } + else + { + nsh_output(vtbl, g_fmtcmdfailed, cmd, "waitpid", + NSH_ERRNO_OF(errcode)); + } + } + + /* Waitpid completed the wait successfully */ + + else { /* We can't return the exact status (nsh has nowhere to put it) * so just pass back zero/nonzero in a fashion that doesn't look diff --git a/apps/nshlib/nsh_fileapps.c b/apps/nshlib/nsh_fileapps.c index 7f9f58e53..92146a68d 100644 --- a/apps/nshlib/nsh_fileapps.c +++ b/apps/nshlib/nsh_fileapps.c @@ -44,7 +44,6 @@ #endif #include -#include #include #include #include @@ -154,8 +153,8 @@ int nsh_fileapp(FAR struct nsh_vtbl_s *vtbl, FAR const char *cmd, } } - /* Lock the scheduler to prevent the application from running until the - * waitpid() has been called. + /* Lock the scheduler in an attempt to prevent the application from + * running until waitpid() has been called. */ sched_lock(); @@ -182,17 +181,6 @@ int nsh_fileapp(FAR struct nsh_vtbl_s *vtbl, FAR const char *cmd, */ #ifdef CONFIG_SCHED_WAITPID - /* Check if the application is still running */ - - if (kill(ret, 0) < 0) - { - /* It is not running. In this case, we have no idea if the - * application ran successfully or not. Let's assume that is - * did. - */ - - return 0; - } /* CONFIG_SCHED_WAITPID is selected, so we may run the command in * foreground unless we were specifically requested to run the command @@ -205,15 +193,40 @@ int nsh_fileapp(FAR struct nsh_vtbl_s *vtbl, FAR const char *cmd, { int rc = 0; - /* Wait for the application to exit. Since we have locked the - * scheduler above, we know that the application has not yet - * started and there is no possibility that it has already exited. - * The scheduler will be unlocked while waitpid is waiting and the - * application will be able to run. + /* Wait for the application to exit. We did locked the scheduler + * above, but that does not guarantee that the application did not + * run in the case where I/O was redirected. The scheduler will + * be unlocked while waitpid is waiting and if the application has + * not yet run, it will be able to to do so. */ ret = waitpid(pid, &rc, 0); - if (ret >= 0) + if (ret < 0) + { + /* If the child thread does not exist, waitpid() will return + * the error ECHLD. Since we know that the task was successfully + * started, this must be one of the cases described above; we + * have to assume that the task already exit'ed. In this case, + * we have no idea if the application ran successfully or not + * (because NuttX does not retain exit status of child tasks). + * Let's assume that is did run successfully. + */ + + int errcode = errno; + if (errcode == ECHILD) + { + ret = OK; + } + else + { + nsh_output(vtbl, g_fmtcmdfailed, cmd, "waitpid", + NSH_ERRNO_OF(errcode)); + } + } + + /* Waitpid completed the wait successfully */ + + else { /* We can't return the exact status (nsh has nowhere to put it) * so just pass back zero/nonzero in a fashion that doesn't look diff --git a/nuttx/configs/sim/README.txt b/nuttx/configs/sim/README.txt index 67ff73019..963a46e08 100644 --- a/nuttx/configs/sim/README.txt +++ b/nuttx/configs/sim/README.txt @@ -291,14 +291,31 @@ nsh apps/examples/hello. 3. This configuration has BINFS enabled so that the builtin applications - can be made visible in the file system. For example: - - NuttShell (NSH) NuttX-6.24 - nsh> mount -t binfs /bin - nsh> ls /bin - /bin: - hello - nsh> + can be made visible in the file system. Because of that, the + build in applications do not work as other examples. + + For example trying to execute the hello builtin application will + fail: + + nsh> hello + nsh: hello: command not found + nsh> + + Unless you first mount the BINFS file system: + + nsh> mount -t binfs /bin + nsh> ls /bin + /bin: + hello + nsh> echo $PATH + /bin + nsh> hello + Hello, World!! + nsh> + + Notice that the executable 'hello' is found using the value in the PATH + variable (which was preset to "/bin"). If the PATH variable were not set + then you would have to use /bin/hello on the command line. nsh2 diff --git a/nuttx/libc/spawn/lib_ps.c b/nuttx/libc/spawn/lib_ps.c index 000f711a3..1bf7c2113 100644 --- a/nuttx/libc/spawn/lib_ps.c +++ b/nuttx/libc/spawn/lib_ps.c @@ -39,6 +39,7 @@ #include +#include #include #include #include @@ -75,7 +76,9 @@ struct spawn_parms_s ****************************************************************************/ static sem_t g_ps_parmsem = SEM_INITIALIZER(1); +#ifndef CONFIG_SCHED_WAITPID static sem_t g_ps_execsem = SEM_INITIALIZER(0); +#endif static struct spawn_parms_s g_ps_parms; /**************************************************************************** @@ -425,7 +428,9 @@ static int spawn_proxy(int argc, char *argv[]) */ g_ps_parms.result = ret; +#ifndef CONFIG_SCHED_WAITPID ps_semgive(&g_ps_execsem); +#endif return 0; } @@ -540,6 +545,9 @@ int posix_spawn(FAR pid_t *pid, FAR const char *path, { struct sched_param param; pid_t proxy; +#ifdef CONFIG_SCHED_WAITPID + int status; +#endif int ret; DEBUGASSERT(path); @@ -613,7 +621,15 @@ int posix_spawn(FAR pid_t *pid, FAR const char *path, /* Wait for the proxy to complete its job */ +#ifdef CONFIG_SCHED_WAITPID + ret = waitpid(proxy, &status, 0); + if (ret < 0) + { + sdbg("ERROR: waitpid() failed: %d\n", errno); + } +#else ps_semtake(&g_ps_execsem); +#endif /* Get the result and relinquish our access to the parameter structure */ -- cgit v1.2.3 From 76753ad9cb67133892000f19de10f93de78bb525 Mon Sep 17 00:00:00 2001 From: patacongo Date: Fri, 18 Jan 2013 01:52:42 +0000 Subject: Add internal API task_reparent(), used in posix_spawn(). Move libc/spawn/lib_ps.c to sched/task_posixspawn.c; Move libc/spawn/spawn.h to include/nuttx/spawn.h git-svn-id: http://svn.code.sf.net/p/nuttx/code/trunk@5531 42af7a65-404d-4744-a932-0658087f49c3 --- apps/builtin/exec_builtin.c | 44 ++- apps/nshlib/nsh_builtin.c | 26 +- apps/nshlib/nsh_fileapps.c | 21 +- nuttx/ChangeLog | 7 +- nuttx/binfmt/binfmt_exec.c | 1 - nuttx/include/nuttx/spawn.h | 121 ++++++ nuttx/include/signal.h | 9 +- nuttx/libc/spawn/Make.defs | 2 - nuttx/libc/spawn/lib_ps.c | 639 -------------------------------- nuttx/libc/spawn/lib_psfa_addaction.c | 2 +- nuttx/libc/spawn/lib_psfa_addclose.c | 2 +- nuttx/libc/spawn/lib_psfa_adddup2.c | 2 +- nuttx/libc/spawn/lib_psfa_addopen.c | 2 +- nuttx/libc/spawn/lib_psfa_destroy.c | 2 +- nuttx/libc/spawn/lib_psfa_dump.c | 2 +- nuttx/libc/spawn/spawn.h | 121 ------ nuttx/sched/Makefile | 6 +- nuttx/sched/os_internal.h | 3 + nuttx/sched/task_posixspawn.c | 673 ++++++++++++++++++++++++++++++++++ nuttx/sched/task_reparent.c | 145 ++++++++ nuttx/syscall/syscall.csv | 2 + 21 files changed, 1029 insertions(+), 803 deletions(-) create mode 100644 nuttx/include/nuttx/spawn.h delete mode 100644 nuttx/libc/spawn/lib_ps.c delete mode 100644 nuttx/libc/spawn/spawn.h create mode 100644 nuttx/sched/task_posixspawn.c create mode 100644 nuttx/sched/task_reparent.c (limited to 'nuttx/libc') diff --git a/apps/builtin/exec_builtin.c b/apps/builtin/exec_builtin.c index 803d1ef34..60e8b742d 100644 --- a/apps/builtin/exec_builtin.c +++ b/apps/builtin/exec_builtin.c @@ -124,7 +124,7 @@ static void bultin_semtake(FAR sem_t *sem) do { ret = sem_wait(sem); - ASSERT(ret == 0 || errno == EINTR); + ASSERT(ret == 0 || get_errno() == EINTR); } while (ret != 0); } @@ -152,7 +152,7 @@ static int builtin_taskcreate(int index, FAR const char **argv) if (b == NULL) { - errno = ENOENT; + set_errno(ENOENT); return ERROR; } @@ -228,7 +228,7 @@ static int builtin_proxy(int argc, char *argv[]) { /* Remember the errno value. ret is already set to ERROR */ - g_builtin_parms.errcode = errno; + g_builtin_parms.errcode = get_errno(); sdbg("ERROR: open of %s failed: %d\n", g_builtin_parms.redirfile, g_builtin_parms.errcode); } @@ -246,7 +246,7 @@ static int builtin_proxy(int argc, char *argv[]) ret = dup2(fd, 1); if (ret < 0) { - g_builtin_parms.errcode = errno; + g_builtin_parms.errcode = get_errno(); sdbg("ERROR: dup2 failed: %d\n", g_builtin_parms.errcode); } @@ -266,12 +266,18 @@ static int builtin_proxy(int argc, char *argv[]) ret = builtin_taskcreate(g_builtin_parms.index, g_builtin_parms.argv); if (ret < 0) { - g_builtin_parms.errcode = errno; + g_builtin_parms.errcode = get_errno(); sdbg("ERROR: builtin_taskcreate failed: %d\n", g_builtin_parms.errcode); } } + /* NOTE: There is a logical error here if CONFIG_SCHED_HAVE_PARENT is + * defined: The new task is the child of this proxy task, not the + * original caller. As a consequence, operations like waitpid() will + * fail on the caller's thread. + */ + /* Post the semaphore to inform the parent task that we have completed * what we need to do. */ @@ -340,11 +346,21 @@ static inline int builtin_startproxy(int index, FAR const char **argv, ret = sched_getparam(0, ¶m); if (ret < 0) { - errcode = errno; + errcode = get_errno(); sdbg("ERROR: sched_getparam failed: %d\n", errcode); - goto errout; + goto errout_with_sem; } + /* Disable pre-emption so that the proxy does not run until we waitpid + * is called. This is probably unnecessary since the builtin_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 = TASK_CREATE("builtin_proxy", param.sched_priority, @@ -352,9 +368,9 @@ static inline int builtin_startproxy(int index, FAR const char **argv, (FAR const char **)NULL); if (proxy < 0) { - errcode = errno; + errcode = get_errno(); sdbg("ERROR: Failed to start builtin_proxy: %d\n", errcode); - goto errout; + goto errout_with_lock; } /* Wait for the proxy to complete its job. We could use waitpid() @@ -365,7 +381,8 @@ static inline int builtin_startproxy(int index, FAR const char **argv, ret = waitpid(proxy, &status, 0); if (ret < 0) { - sdbg("ERROR: waitpid() failed: %d\n", errno); + sdbg("ERROR: waitpid() failed: %d\n", get_errno()); + goto errout_with_lock; } #else bultin_semtake(&g_builtin_execsem); @@ -377,7 +394,12 @@ static inline int builtin_startproxy(int index, FAR const char **argv, builtin_semgive(&g_builtin_parmsem); return g_builtin_parms.result; -errout: +errout_with_lock: +#ifdef CONFIG_SCHED_WAITPID + sched_unlock(); +#endif + +errout_with_sem: set_errno(errcode); builtin_semgive(&g_builtin_parmsem); return ERROR; diff --git a/apps/nshlib/nsh_builtin.c b/apps/nshlib/nsh_builtin.c index 343a0824b..0d5a0231c 100644 --- a/apps/nshlib/nsh_builtin.c +++ b/apps/nshlib/nsh_builtin.c @@ -131,12 +131,14 @@ int nsh_builtin(FAR struct nsh_vtbl_s *vtbl, FAR const char *cmd, { /* The application was successfully started with pre-emption disabled. * In the simplest cases, the application will not have run because the - * the scheduler is locked. but in the case were I/O redirected, a - * proxy task ran and, as result, so may have the application. + * the scheduler is locked. But in the case where I/O was redirected, a + * proxy task ran and broke our lock. As result, the application may + * have aso ran if its priority was higher than than the priority of + * this thread. * - * If the application did not run and if the application was not - * backgrounded, then we need to wait here for the application to - * exit. This only works works with the following options: + * If the application did not run to completion and if the application + * was not backgrounded, then we need to wait here for the application + * to exit. This only works works with the following options: * * - CONFIG_NSH_DISABLEBG - Do not run commands in background * - CONFIG_SCHED_WAITPID - Required to run external commands in @@ -156,11 +158,17 @@ int nsh_builtin(FAR struct nsh_vtbl_s *vtbl, FAR const char *cmd, { int rc = 0; - /* Wait for the application to exit. We did locked the scheduler + /* Wait for the application to exit. We did lock the scheduler * above, but that does not guarantee that the application did not - * run in the case where I/O was redirected. The scheduler will - * be unlocked while waitpid is waiting and if the application has - * not yet run, it will be able to to do so. + * already run to completion in the case where I/O was redirected. + * Here the scheduler will be unlocked while waitpid is waiting + * and if the application has not yet run, it will now be able to + * do so. + * + * Also, if CONFIG_SCHED_HAVE_PARENT is defined waitpid() might fail + * even if task is still active: If the I/O was re-directed by a + * proxy task, then the ask is a child of the proxy, and not this + * task. waitpid() fails with ECHILD in either case. */ ret = waitpid(ret, &rc, 0); diff --git a/apps/nshlib/nsh_fileapps.c b/apps/nshlib/nsh_fileapps.c index 92146a68d..9ff230f1a 100644 --- a/apps/nshlib/nsh_fileapps.c +++ b/apps/nshlib/nsh_fileapps.c @@ -168,12 +168,14 @@ int nsh_fileapp(FAR struct nsh_vtbl_s *vtbl, FAR const char *cmd, { /* The application was successfully started with pre-emption disabled. * In the simplest cases, the application will not have run because the - * the scheduler is locked. but in the case were I/O redirected, a - * proxy task ran and, as result, so may have the application. + * the scheduler is locked. But in the case where I/O was redirected, a + * proxy task ran and broke our lock. As result, the application may + * have aso ran if its priority was higher than than the priority of + * this thread. * - * If the application did not run and if the application was not - * backgrounded, then we need to wait here for the application to - * exit. This only works works with the following options: + * If the application did not run to completion and if the application + * was not backgrounded, then we need to wait here for the application + * to exit. This only works works with the following options: * * - CONFIG_NSH_DISABLEBG - Do not run commands in background * - CONFIG_SCHED_WAITPID - Required to run external commands in @@ -193,11 +195,12 @@ int nsh_fileapp(FAR struct nsh_vtbl_s *vtbl, FAR const char *cmd, { int rc = 0; - /* Wait for the application to exit. We did locked the scheduler + /* Wait for the application to exit. We did lock the scheduler * above, but that does not guarantee that the application did not - * run in the case where I/O was redirected. The scheduler will - * be unlocked while waitpid is waiting and if the application has - * not yet run, it will be able to to do so. + * already run to completion in the case where I/O was redirected. + * Here the scheduler will be unlocked while waitpid is waiting + * and if the application has not yet run, it will now be able to + * do so. */ ret = waitpid(pid, &rc, 0); diff --git a/nuttx/ChangeLog b/nuttx/ChangeLog index 1b0c5338b..2a1561abe 100644 --- a/nuttx/ChangeLog +++ b/nuttx/ChangeLog @@ -3971,4 +3971,9 @@ automatically unload and clean-up after running a task that was loaded into memory. * binfmt/libbuiltin: Extensions from Mike Smith - + * sched/task_reparent.c: Add internal interface to change the + parent task. + * sched/task_posixspawn(): Move libc/spawn/lib_ps.c to + sched/task_posixspawn() now it requires internal, reparenting + interfaces + * include/nuttx/spawn(): Move libc/spawn.h to include/nuttx/spawn.h diff --git a/nuttx/binfmt/binfmt_exec.c b/nuttx/binfmt/binfmt_exec.c index 7f45fb841..4226b6cfc 100644 --- a/nuttx/binfmt/binfmt_exec.c +++ b/nuttx/binfmt/binfmt_exec.c @@ -97,7 +97,6 @@ int exec(FAR const char *filename, FAR const char **argv, { #ifdef CONFIG_SCHED_ONEXIT FAR struct binary_s *bin; - int errorcode; int pid; int ret; diff --git a/nuttx/include/nuttx/spawn.h b/nuttx/include/nuttx/spawn.h new file mode 100644 index 000000000..f84ae8355 --- /dev/null +++ b/nuttx/include/nuttx/spawn.h @@ -0,0 +1,121 @@ +/**************************************************************************** + * include/nuttx/spawn.h + * + * Copyright (C) 2013 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __INCLUDE_NUTTX_SPAWN_H +#define __INCLUDE_NUTTX_SPAWN_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Type Definitions + ****************************************************************************/ +/* This enumerator identifies a file action */ + +enum spawn_file_actions_e +{ + SPAWN_FILE_ACTION_NONE = 0, + SPAWN_FILE_ACTION_CLOSE, + SPAWN_FILE_ACTION_DUP2, + SPAWN_FILE_ACTION_OPEN +}; + +/* posix_spawn_file_actions_addclose(), posix_spawn_file_actions_adddup2(), + * and posix_spawn_file_actions_addopen() will allocate memory and append + * a new file action to an instance of posix_spawn_file_actions_t. The + * internal representation of these structures are defined below: + */ + +struct spawn_general_file_action_s +{ + FAR struct spawn_general_file_action_s *flink; /* Supports a singly linked list */ + enum spawn_file_actions_e action; /* A member of enum spawn_file_actions_e */ +}; + +struct spawn_close_file_action_s +{ + FAR struct spawn_general_file_action_s *flink; /* Supports a singly linked list */ + enum spawn_file_actions_e action; /* SPAWN_FILE_ACTION_CLOSE */ + int fd; /* The file descriptor to close */ +}; + +struct spawn_dup2_file_action_s +{ + FAR struct spawn_general_file_action_s *flink; /* Supports a singly linked list */ + enum spawn_file_actions_e action; /* SPAWN_FILE_ACTION_DUP2 */ + int fd1; /* The first file descriptor for dup2() */ + int fd2; /* The second file descriptor for dup2() */ +}; + +struct spawn_open_file_action_s +{ + FAR struct spawn_general_file_action_s *flink; /* Supports a singly linked list */ + enum spawn_file_actions_e action; /* SPAWN_FILE_ACTION_OPEN */ + int fd; /* The file descriptor after opening */ + int oflags; /* Open flags */ + mode_t mode; /* File creation mode */ + char path[1]; /* Start of the path to be + * opened */ +}; + +#define SIZEOF_OPEN_FILE_ACTION_S(n) \ + (sizeof(struct spawn_open_file_action_s) + (n)) + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifdef __cplusplus +extern "C" +{ +#endif + +void add_file_action(FAR posix_spawn_file_actions_t *file_action, + FAR struct spawn_general_file_action_s *entry); + +#ifdef __cplusplus +} +#endif + +#endif /* __INCLUDE_NUTTX_SPAWN_H */ diff --git a/nuttx/include/signal.h b/nuttx/include/signal.h index 30726105b..7c6b4cd55 100644 --- a/nuttx/include/signal.h +++ b/nuttx/include/signal.h @@ -61,14 +61,17 @@ /* All signals are "real time" signals */ -#define SIGRTMIN 0 /* First real time signal */ -#define SIGRTMAX 31 /* Last real time signal */ +#define SIGRTMIN MIN_SIGNO /* First real time signal */ +#define SIGRTMAX MAX_SIGNO /* Last real time signal */ /* A few of the real time signals are used within the OS. They have * default values that can be overridden from the configuration file. The * rest are all user signals. * - * These are semi-standard signal definitions: + * The signal number zero is wasted for the most part. It is a valid + * signal number, but has special meaning at many interfaces (e.g., Kill()). + * + * These are the semi-standard signal definitions: */ #ifndef CONFIG_SIG_SIGUSR1 diff --git a/nuttx/libc/spawn/Make.defs b/nuttx/libc/spawn/Make.defs index 99ee781ce..8cb086fee 100644 --- a/nuttx/libc/spawn/Make.defs +++ b/nuttx/libc/spawn/Make.defs @@ -37,8 +37,6 @@ ifeq ($(CONFIG_LIBC_EXECFUNCS),y) -CSRCS += lib_ps.c - CSRCS += lib_psfa_addaction.c lib_psfa_addclose.c lib_psfa_adddup2.c CSRCS += lib_psfa_addopen.c lib_psfa_destroy.c lib_psfa_init.c diff --git a/nuttx/libc/spawn/lib_ps.c b/nuttx/libc/spawn/lib_ps.c deleted file mode 100644 index 1bf7c2113..000000000 --- a/nuttx/libc/spawn/lib_ps.c +++ /dev/null @@ -1,639 +0,0 @@ -/**************************************************************************** - * libc/string/lib_ps.c - * - * Copyright (C) 2013 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "spawn/spawn.h" - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -struct spawn_parms_s -{ - int result; - FAR pid_t *pid; - FAR const char *path; - FAR const posix_spawn_file_actions_t *file_actions; - FAR const posix_spawnattr_t *attr; - FAR char *const *argv; -}; - -/**************************************************************************** - * Public Data - ****************************************************************************/ - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -static sem_t g_ps_parmsem = SEM_INITIALIZER(1); -#ifndef CONFIG_SCHED_WAITPID -static sem_t g_ps_execsem = SEM_INITIALIZER(0); -#endif -static struct spawn_parms_s g_ps_parms; - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: ps_semtake and ps_semgive - * - * Description: - * Give and take semaphores - * - * Input Parameters: - * - * sem - The semaphore to act on. - * - * Returned Value: - * None - * - ****************************************************************************/ - -static void ps_semtake(FAR sem_t *sem) -{ - int ret; - - do - { - ret = sem_wait(sem); - ASSERT(ret == 0 || errno == EINTR); - } - while (ret != 0); -} - -#define ps_semgive(sem) sem_post(sem) - -/**************************************************************************** - * Name: ps_exec - * - * Description: - * Execute the task from the file system. - * - * Input Parameters: - * - * pidp - Upon successful completion, this will return the task ID of the - * child task in the variable pointed to by a non-NULL 'pid' argument.| - * - * path - The 'path' argument identifies the file to execute. If - * CONFIG_BINFMT_EXEPATH is defined, this may be either a relative or - * or an absolute path. Otherwise, it must be an absolute path. - * - * 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 - * following spawn flags are supported: - * - * - POSIX_SPAWN_SETSCHEDPARAM: Set new tasks priority to the sched_param - * value. - * - POSIX_SPAWN_SETSCHEDULER: Set the new tasks scheduler priority to - * the sched_policy value. - * - * NOTE: POSIX_SPAWN_SETSIGMASK is handled in ps_proxy(). - * - * argv - argv[] is the argument list for the new task. argv[] is an - * array of pointers to null-terminated strings. The list is terminated - * with a null pointer. - * - * Returned Value: - * This function will return zero on success. Otherwise, an error number - * will be returned as the function return value to indicate the error. - * This errno value may be that set by execv(), sched_setpolicy(), or - * sched_setparam(). - * - ****************************************************************************/ - -static int ps_exec(FAR pid_t *pidp, FAR const char *path, - FAR const posix_spawnattr_t *attr, - FAR char *const argv[]) -{ - struct sched_param param; - FAR const struct symtab_s *symtab; - int nsymbols; - int pid; - int ret = OK; - - DEBUGASSERT(path); - - /* Get the current symbol table selection */ - - exec_getsymtab(&symtab, &nsymbols); - - /* Disable pre-emption so that we can modify the task parameters after - * we start the new task; the new task will not actually begin execution - * until we re-enable pre-emption. - */ - - sched_lock(); - - /* Start the task */ - - pid = exec(path, (FAR const char **)argv, symtab, nsymbols); - if (pid < 0) - { - ret = errno; - sdbg("ERROR: exec failed: %d\n", ret); - goto errout; - } - - /* Return the task ID to the caller */ - - if (pid) - { - *pidp = pid; - } - - /* Now set the attributes. Note that we ignore all of the return values - * here because we have already successfully started the task. If we - * return an error value, then we would also have to stop the task. - */ - - if (attr) - { - /* If we are only setting the priority, then call sched_setparm() - * to set the priority of the of the new task. - */ - - if ((attr->flags & POSIX_SPAWN_SETSCHEDPARAM) != 0) - { - /* Get the priority from the attrributes */ - - param.sched_priority = attr->priority; - - /* If we are setting *both* the priority and the scheduler, - * then we will call sched_setscheduler() below. - */ - - if ((attr->flags & POSIX_SPAWN_SETSCHEDULER) == 0) - { - svdbg("Setting priority=%d for pid=%d\n", - param.sched_priority, pid); - - (void)sched_setparam(pid, ¶m); - } - } - - /* If we are only changing the scheduling policy, then reset - * the priority to the default value (the same as this thread) in - * preparation for the sched_setscheduler() call below. - */ - - else if ((attr->flags & POSIX_SPAWN_SETSCHEDULER) != 0) - { - (void)sched_getparam(0, ¶m); - } - - /* Are we setting the scheduling policy? If so, use the priority - * setting determined above. - */ - - if ((attr->flags & POSIX_SPAWN_SETSCHEDULER) != 0) - { - svdbg("Setting policy=%d priority=%d for pid=%d\n", - attr->policy, param.sched_priority, pid); - - (void)sched_setscheduler(pid, attr->policy, ¶m); - } - } - - /* Re-enable pre-emption and return */ - -errout: - sched_unlock(); - return ret; -} - -/**************************************************************************** - * Name: spawn_close, spawn_dup2, and spawn_open - * - * Description: - * Implement individual file actions - * - * Input Parameters: - * action - describes the action to be performed - * - * Returned Value: - * posix_spawn() and posix_spawnp() will return zero on success. - * Otherwise, an error number will be returned as the function return - * value to indicate the error. - * - ****************************************************************************/ - -static inline int spawn_close(FAR struct spawn_close_file_action_s *action) -{ - /* The return value from close() is ignored */ - - svdbg("Closing fd=%d\n", action->fd); - - (void)close(action->fd); - return OK; -} - -static inline int spawn_dup2(FAR struct spawn_dup2_file_action_s *action) -{ - int ret; - - /* Perform the dup */ - - svdbg("Dup'ing %d->%d\n", action->fd1, action->fd2); - - ret = dup2(action->fd1, action->fd2); - if (ret < 0) - { - int errcode = errno; - - sdbg("ERROR: dup2 failed: %d\n", errcode); - return errcode; - } - - return OK; -} - -static inline int spawn_open(FAR struct spawn_open_file_action_s *action) -{ - int fd; - int ret = OK; - - /* Open the file */ - - svdbg("Open'ing path=%s oflags=%04x mode=%04x\n", - action->path, action->oflags, action->mode); - - fd = open(action->path, action->oflags, action->mode); - if (fd < 0) - { - ret = errno; - sdbg("ERROR: open failed: %d\n", ret); - } - - /* Does the return file descriptor happen to match the required file - * desciptor number? - */ - - else if (fd != action->fd) - { - /* No.. dup2 to get the correct file number */ - - svdbg("Dup'ing %d->%d\n", fd, action->fd); - - ret = dup2(fd, action->fd); - if (ret < 0) - { - ret = errno; - sdbg("ERROR: dup2 failed: %d\n", ret); - } - - svdbg("Closing fd=%d\n", fd); - close(fd); - } - - return ret; -} - -/**************************************************************************** - * Name: spawn_proxy - * - * Description: - * Perform file_actions, then execute the task from the file system. - * - * Input Parameters: - * Standard task start-up parameters - * - * Returned Value: - * Standard task return value. - * - ****************************************************************************/ - -static int spawn_proxy(int argc, char *argv[]) -{ - FAR struct spawn_general_file_action_s *entry; - FAR const posix_spawnattr_t *attr = g_ps_parms.attr; - int ret = OK; - - /* 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. - */ - -#ifndef CONFIG_DISABLE_SIGNALS - DEBUGASSERT((g_ps_parms.file_actions && *g_ps_parms.file_actions) || - (attr && (attr->flags & POSIX_SPAWN_SETSIGMASK) != 0)); -#else - DEBUGASSERT(g_ps_parms.file_actions && *g_ps_parms.file_actions); -#endif - - /* Check if we need to change the signal mask */ - -#ifndef CONFIG_DISABLE_SIGNALS - if (attr && (attr->flags & POSIX_SPAWN_SETSIGMASK) != 0) - { - (void)sigprocmask(SIG_SETMASK, &attr->sigmask, NULL); - } - - /* Were we also requested to perform file actions? */ - - if (g_ps_parms.file_actions) -#endif - { - /* Execute each file action */ - - for (entry = (FAR struct spawn_general_file_action_s *)*g_ps_parms.file_actions; - entry && ret == OK; - entry = entry->flink) - { - switch (entry->action) - { - case SPAWN_FILE_ACTION_CLOSE: - ret = spawn_close((FAR struct spawn_close_file_action_s *)entry); - break; - - case SPAWN_FILE_ACTION_DUP2: - ret = spawn_dup2((FAR struct spawn_dup2_file_action_s *)entry); - break; - - case SPAWN_FILE_ACTION_OPEN: - ret = spawn_open((FAR struct spawn_open_file_action_s *)entry); - break; - - case SPAWN_FILE_ACTION_NONE: - default: - sdbg("ERROR: Unknown action: %d\n", entry->action); - ret = EINVAL; - break; - } - } - } - - /* Check for failures */ - - if (ret == OK) - { - /* Start the task */ - - ret = ps_exec(g_ps_parms.pid, g_ps_parms.path, attr, g_ps_parms.argv); - } - - /* Post the semaphore to inform the parent task that we have completed - * what we need to do. - */ - - g_ps_parms.result = ret; -#ifndef CONFIG_SCHED_WAITPID - ps_semgive(&g_ps_execsem); -#endif - return 0; -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: posix_spawn - * - * Description: - * The posix_spawn() and posix_spawnp() functions will create a new, - * child task, constructed from a regular executable file. - * - * Input Parameters: - * - * pid - Upon successful completion, posix_spawn() and posix_spawnp() will - * return the task ID of the child task to the parent task, in the - * variable pointed to by a non-NULL 'pid' argument. If the 'pid' - * argument is a null pointer, the process ID of the child is not - * returned to the caller. - * - * path - The 'path' argument to posix_spawn() is the absolute path that - * identifies the file to execute. The 'path' argument to posix_spawnp() - * may also be a relative path and will be used to construct a pathname - * that identifies the file to execute. In the case of a relative path, - * the path prefix for the file will be obtained by a search of the - * directories passed as the environment variable PATH. - * - * NOTE: NuttX provides only one implementation: If - * CONFIG_BINFMT_EXEPATH is defined, then only posix_spawnp() behavior - * is supported; otherwise, only posix_spawn behavior is supported. - * - * file_actions - If 'file_actions' is a null pointer, then file - * descriptors open in the calling process will remain open in the - * child process (unless CONFIG_FDCLONE_STDIO is defined). If - * 'file_actions' is not NULL, then the file descriptors open in the - * child process will be those open in the calling process as modified - * by the spawn file actions object pointed to by 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 - * posix_spawnattr_t spawn attributes object type is defined in spawn.h. - * It will contains these attributes, not all of which are supported by - * NuttX: - * - * - POSIX_SPAWN_SETPGROUP: Setting of the new task's process group is - * not supported. NuttX does not support process groups. - * - POSIX_SPAWN_SETSCHEDPARAM: Set new tasks priority to the sched_param - * value. - * - POSIX_SPAWN_SETSCHEDULER: Set the new task's scheduler policy to - * the sched_policy value. - * - POSIX_SPAWN_RESETIDS: Resetting of the effective user ID of the child - * process is not supported. NuttX does not support effective user - * IDs. - * - POSIX_SPAWN_SETSIGMASK: Set the new task's signal mask. - * - POSIX_SPAWN_SETSIGDEF: Resetting signal default actions is not - * supported. NuttX does not support default signal actions. - * - * argv - argv[] is the argument list for the new task. argv[] is an - * array of pointers to null-terminated strings. The list is terminated - * with a null pointer. - * - * envp - The envp[] argument is not used by NuttX and may be NULL. In - * standard implementations, envp[] is an array of character pointers to - * null-terminated strings that provide the environment for the new - * process image. The environment array is terminated by a null pointer. - * In NuttX, the envp[] argument is ignored and the new task will simply - * inherit the environment of the parent task. - * - * Returned Value: - * posix_spawn() and posix_spawnp() will return zero on success. - * Otherwise, an error number will be returned as the function return - * value to indicate the error: - * - * - EINVAL: The value specified by 'file_actions' or 'attr' is invalid. - * - Any errors that might have been return if vfork() and excec[l|v]() - * had been called. - * - * Assumptions/Limitations: - * - NuttX provides only posix_spawn() or posix_spawnp() behavior - * depending upon the setting of CONFIG_BINFMT_EXEPATH: If - * CONFIG_BINFMT_EXEPATH is defined, then only posix_spawnp() behavior - * is supported; otherwise, only posix_spawn behavior is supported. - * - The 'envp' argument is not used and the 'environ' variable is not - * altered (NuttX does not support the 'environ' variable). - * - Process groups are not supported (POSIX_SPAWN_SETPGROUP). - * - Effective user IDs are not supported (POSIX_SPAWN_RESETIDS). - * - Signal default actions cannot be modified in the newly task executed - * because NuttX does not support default signal actions - * (POSIX_SPAWN_SETSIGDEF). - * - * POSIX Compatibility - * - The value of the argv[0] received by the child task is assigned by - * NuttX. For the caller of posix_spawn(), the provided argv[0] will - * correspond to argv[1] received by the new task. - * - ****************************************************************************/ - -#ifdef CONFIG_BINFMT_EXEPATH -int posix_spawnp(FAR pid_t *pid, FAR const char *path, - FAR const posix_spawn_file_actions_t *file_actions, - FAR const posix_spawnattr_t *attr, - FAR char *const argv[], FAR char *const envp[]) -#else -int posix_spawn(FAR pid_t *pid, FAR const char *path, - FAR const posix_spawn_file_actions_t *file_actions, - FAR const posix_spawnattr_t *attr, - FAR char *const argv[], FAR char *const envp[]) -#endif -{ - struct sched_param param; - pid_t proxy; -#ifdef CONFIG_SCHED_WAITPID - int status; -#endif - int ret; - - DEBUGASSERT(path); - - svdbg("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. - */ - -#ifndef CONFIG_DISABLE_SIGNALS - if ((file_actions == NULL || *file_actions == NULL) && - (attr == NULL || (attr->flags & POSIX_SPAWN_SETSIGMASK) == 0)) -#else - if (file_actions == NULL || *file_actions == NULL) -#endif - { - return ps_exec(pid, path, attr, argv); - } - - /* 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 */ - - ps_semtake(&g_ps_parmsem); - - /* Populate the parameter structure */ - - g_ps_parms.result = ENOSYS; - g_ps_parms.pid = pid; - g_ps_parms.path = path; - g_ps_parms.file_actions = file_actions; - g_ps_parms.attr = attr; - g_ps_parms.argv = argv; - - /* Get the priority of this (parent) task */ - - ret = sched_getparam(0, ¶m); - if (ret < 0) - { - int errcode = errno; - - sdbg("ERROR: sched_getparam failed: %d\n", errcode); - ps_semgive(&g_ps_parmsem); - return errcode; - } - - /* Start the intermediary/proxy task at the same priority as the parent task. */ - - proxy = TASK_CREATE("spawn_proxy", param.sched_priority, - CONFIG_POSIX_SPAWN_STACKSIZE, (main_t)spawn_proxy, - (FAR const char **)NULL); - if (proxy < 0) - { - int errcode = errno; - - sdbg("ERROR: Failed to start spawn_proxy: %d\n", errcode); - ps_semgive(&g_ps_parmsem); - return errcode; - } - - /* Wait for the proxy to complete its job */ - -#ifdef CONFIG_SCHED_WAITPID - ret = waitpid(proxy, &status, 0); - if (ret < 0) - { - sdbg("ERROR: waitpid() failed: %d\n", errno); - } -#else - ps_semtake(&g_ps_execsem); -#endif - - /* Get the result and relinquish our access to the parameter structure */ - - ret = g_ps_parms.result; - ps_semgive(&g_ps_parmsem); - return ret; -} diff --git a/nuttx/libc/spawn/lib_psfa_addaction.c b/nuttx/libc/spawn/lib_psfa_addaction.c index 3f297d7cf..8700efc2a 100644 --- a/nuttx/libc/spawn/lib_psfa_addaction.c +++ b/nuttx/libc/spawn/lib_psfa_addaction.c @@ -41,7 +41,7 @@ #include -#include "spawn/spawn.h" +#include /**************************************************************************** * Global Functions diff --git a/nuttx/libc/spawn/lib_psfa_addclose.c b/nuttx/libc/spawn/lib_psfa_addclose.c index bf22a153a..1c72f0f82 100644 --- a/nuttx/libc/spawn/lib_psfa_addclose.c +++ b/nuttx/libc/spawn/lib_psfa_addclose.c @@ -44,7 +44,7 @@ #include #include -#include "spawn/spawn.h" +#include /**************************************************************************** * Global Functions diff --git a/nuttx/libc/spawn/lib_psfa_adddup2.c b/nuttx/libc/spawn/lib_psfa_adddup2.c index fc788a4e9..deb3cbdb3 100644 --- a/nuttx/libc/spawn/lib_psfa_adddup2.c +++ b/nuttx/libc/spawn/lib_psfa_adddup2.c @@ -44,7 +44,7 @@ #include #include -#include "spawn/spawn.h" +#include /**************************************************************************** * Global Functions diff --git a/nuttx/libc/spawn/lib_psfa_addopen.c b/nuttx/libc/spawn/lib_psfa_addopen.c index 385e1cfc3..66bbd813a 100644 --- a/nuttx/libc/spawn/lib_psfa_addopen.c +++ b/nuttx/libc/spawn/lib_psfa_addopen.c @@ -45,7 +45,7 @@ #include #include -#include "spawn/spawn.h" +#include /**************************************************************************** * Global Functions diff --git a/nuttx/libc/spawn/lib_psfa_destroy.c b/nuttx/libc/spawn/lib_psfa_destroy.c index 5d0a644d8..a21886645 100644 --- a/nuttx/libc/spawn/lib_psfa_destroy.c +++ b/nuttx/libc/spawn/lib_psfa_destroy.c @@ -43,7 +43,7 @@ #include #include -#include "spawn/spawn.h" +#include /**************************************************************************** * Global Functions diff --git a/nuttx/libc/spawn/lib_psfa_dump.c b/nuttx/libc/spawn/lib_psfa_dump.c index d7bf1576d..0dbaeb023 100644 --- a/nuttx/libc/spawn/lib_psfa_dump.c +++ b/nuttx/libc/spawn/lib_psfa_dump.c @@ -43,7 +43,7 @@ #include #include -#include "spawn/spawn.h" +#include #ifdef CONFIG_DEBUG diff --git a/nuttx/libc/spawn/spawn.h b/nuttx/libc/spawn/spawn.h deleted file mode 100644 index 3f4e195cc..000000000 --- a/nuttx/libc/spawn/spawn.h +++ /dev/null @@ -1,121 +0,0 @@ -/**************************************************************************** - * libc/spawn/spawn.h - * - * Copyright (C) 2013 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -#ifndef __LIBC_SPAWN_SPAWN_H -#define __LIBC_SPAWN_SPAWN_H - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/**************************************************************************** - * Type Definitions - ****************************************************************************/ -/* This enumerator identifies a file action */ - -enum spawn_file_actions_e -{ - SPAWN_FILE_ACTION_NONE = 0, - SPAWN_FILE_ACTION_CLOSE, - SPAWN_FILE_ACTION_DUP2, - SPAWN_FILE_ACTION_OPEN -}; - -/* posix_spawn_file_actions_addclose(), posix_spawn_file_actions_adddup2(), - * and posix_spawn_file_actions_addopen() will allocate memory and append - * a new file action to an instance of posix_spawn_file_actions_t. The - * internal representation of these structures are defined below: - */ - -struct spawn_general_file_action_s -{ - FAR struct spawn_general_file_action_s *flink; /* Supports a singly linked list */ - enum spawn_file_actions_e action; /* A member of enum spawn_file_actions_e */ -}; - -struct spawn_close_file_action_s -{ - FAR struct spawn_general_file_action_s *flink; /* Supports a singly linked list */ - enum spawn_file_actions_e action; /* SPAWN_FILE_ACTION_CLOSE */ - int fd; /* The file descriptor to close */ -}; - -struct spawn_dup2_file_action_s -{ - FAR struct spawn_general_file_action_s *flink; /* Supports a singly linked list */ - enum spawn_file_actions_e action; /* SPAWN_FILE_ACTION_DUP2 */ - int fd1; /* The first file descriptor for dup2() */ - int fd2; /* The second file descriptor for dup2() */ -}; - -struct spawn_open_file_action_s -{ - FAR struct spawn_general_file_action_s *flink; /* Supports a singly linked list */ - enum spawn_file_actions_e action; /* SPAWN_FILE_ACTION_OPEN */ - int fd; /* The file descriptor after opening */ - int oflags; /* Open flags */ - mode_t mode; /* File creation mode */ - char path[1]; /* Start of the path to be - * opened */ -}; - -#define SIZEOF_OPEN_FILE_ACTION_S(n) \ - (sizeof(struct spawn_open_file_action_s) + (n)) - -/**************************************************************************** - * Public Function Prototypes - ****************************************************************************/ - -#ifdef __cplusplus -extern "C" -{ -#endif - -void add_file_action(FAR posix_spawn_file_actions_t *file_action, - FAR struct spawn_general_file_action_s *entry); - -#ifdef __cplusplus -} -#endif - -#endif /* __LIBC_SPAWN_SPAWN_H */ diff --git a/nuttx/sched/Makefile b/nuttx/sched/Makefile index 3d6b58bac..73c67239e 100644 --- a/nuttx/sched/Makefile +++ b/nuttx/sched/Makefile @@ -48,7 +48,7 @@ TSK_SRCS = prctl.c task_create.c task_init.c task_setup.c task_activate.c \ task_restart.c task_vfork.c exit.c getpid.c sched_addreadytorun.c \ sched_removereadytorun.c sched_addprioritized.c sched_mergepending.c \ sched_addblocked.c sched_removeblocked.c sched_free.c sched_gettcb.c \ - sched_verifytcb.c sched_releasetcb.c + sched_verifytcb.c sched_releasetcb.c task_posixspawn.c SCHED_SRCS = sched_setparam.c sched_setpriority.c sched_getparam.c \ sched_setscheduler.c sched_getscheduler.c \ @@ -67,6 +67,10 @@ ifeq ($(CONFIG_PRIORITY_INHERITANCE),y) SCHED_SRCS += sched_reprioritize.c endif +ifeq ($(CONFIG_SCHED_HAVE_PARENT),y) +SCHED_SRCS += task_reparent.c +endif + ifeq ($(CONFIG_SCHED_WAITPID),y) SCHED_SRCS += sched_waitpid.c ifeq ($(CONFIG_SCHED_HAVE_PARENT),y) diff --git a/nuttx/sched/os_internal.h b/nuttx/sched/os_internal.h index 32d9fb4ac..f21d9654f 100644 --- a/nuttx/sched/os_internal.h +++ b/nuttx/sched/os_internal.h @@ -268,6 +268,9 @@ int task_schedsetup(FAR _TCB *tcb, int priority, start_t start, int task_argsetup(FAR _TCB *tcb, FAR const char *name, FAR const char *argv[]); void task_exithook(FAR _TCB *tcb, int status); int task_deletecurrent(void); +#ifdef CONFIG_SCHED_HAVE_PARENT +int task_reparent(pid_t oldpid, pid_t newpid, pid_t chpid); +#endif #ifndef CONFIG_CUSTOM_STACK int kernel_thread(FAR const char *name, int priority, int stack_size, main_t entry, FAR const char *argv[]); diff --git a/nuttx/sched/task_posixspawn.c b/nuttx/sched/task_posixspawn.c new file mode 100644 index 000000000..4201e759b --- /dev/null +++ b/nuttx/sched/task_posixspawn.c @@ -0,0 +1,673 @@ +/**************************************************************************** + * sched/task_posixspawn.c + * + * Copyright (C) 2013 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "os_internal.h" + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct spawn_parms_s +{ + int result; + FAR pid_t *pid; + FAR const char *path; + FAR const posix_spawn_file_actions_t *file_actions; + FAR const posix_spawnattr_t *attr; + FAR char *const *argv; +}; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static sem_t g_ps_parmsem = SEM_INITIALIZER(1); +#ifndef CONFIG_SCHED_WAITPID +static sem_t g_ps_execsem = SEM_INITIALIZER(0); +#endif +static struct spawn_parms_s g_ps_parms; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: spawn_semtake and spawn_semgive + * + * Description: + * Give and take semaphores + * + * Input Parameters: + * + * sem - The semaphore to act on. + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void spawn_semtake(FAR sem_t *sem) +{ + int ret; + + do + { + ret = sem_wait(sem); + ASSERT(ret == 0 || errno == EINTR); + } + while (ret != 0); +} + +#define spawn_semgive(sem) sem_post(sem) + +/**************************************************************************** + * Name: spawn_exec + * + * Description: + * Execute the task from the file system. + * + * Input Parameters: + * + * pidp - Upon successful completion, this will return the task ID of the + * child task in the variable pointed to by a non-NULL 'pid' argument.| + * + * path - The 'path' argument identifies the file to execute. If + * CONFIG_BINFMT_EXEPATH is defined, this may be either a relative or + * or an absolute path. Otherwise, it must be an absolute path. + * + * 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 + * following spawn flags are supported: + * + * - POSIX_SPAWN_SETSCHEDPARAM: Set new tasks priority to the sched_param + * value. + * - POSIX_SPAWN_SETSCHEDULER: Set the new tasks scheduler priority to + * the sched_policy value. + * + * NOTE: POSIX_SPAWN_SETSIGMASK is handled in ps_proxy(). + * + * argv - argv[] is the argument list for the new task. argv[] is an + * array of pointers to null-terminated strings. The list is terminated + * with a null pointer. + * + * Returned Value: + * This function will return zero on success. Otherwise, an error number + * will be returned as the function return value to indicate the error. + * This errno value may be that set by execv(), sched_setpolicy(), or + * sched_setparam(). + * + ****************************************************************************/ + +static int spawn_exec(FAR pid_t *pidp, FAR const char *path, + FAR const posix_spawnattr_t *attr, + FAR char *const argv[]) +{ + struct sched_param param; + FAR const struct symtab_s *symtab; + int nsymbols; + int pid; + int ret = OK; + + DEBUGASSERT(path); + + /* Get the current symbol table selection */ + + exec_getsymtab(&symtab, &nsymbols); + + /* Disable pre-emption so that we can modify the task parameters after + * we start the new task; the new task will not actually begin execution + * until we re-enable pre-emption. + */ + + sched_lock(); + + /* Start the task */ + + pid = exec(path, (FAR const char **)argv, symtab, nsymbols); + if (pid < 0) + { + ret = errno; + sdbg("ERROR: exec failed: %d\n", ret); + goto errout; + } + + /* Return the task ID to the caller */ + + if (pid) + { + *pidp = pid; + } + + /* Now set the attributes. Note that we ignore all of the return values + * here because we have already successfully started the task. If we + * return an error value, then we would also have to stop the task. + */ + + if (attr) + { + /* If we are only setting the priority, then call sched_setparm() + * to set the priority of the of the new task. + */ + + if ((attr->flags & POSIX_SPAWN_SETSCHEDPARAM) != 0) + { + /* Get the priority from the attrributes */ + + param.sched_priority = attr->priority; + + /* If we are setting *both* the priority and the scheduler, + * then we will call sched_setscheduler() below. + */ + + if ((attr->flags & POSIX_SPAWN_SETSCHEDULER) == 0) + { + svdbg("Setting priority=%d for pid=%d\n", + param.sched_priority, pid); + + (void)sched_setparam(pid, ¶m); + } + } + + /* If we are only changing the scheduling policy, then reset + * the priority to the default value (the same as this thread) in + * preparation for the sched_setscheduler() call below. + */ + + else if ((attr->flags & POSIX_SPAWN_SETSCHEDULER) != 0) + { + (void)sched_getparam(0, ¶m); + } + + /* Are we setting the scheduling policy? If so, use the priority + * setting determined above. + */ + + if ((attr->flags & POSIX_SPAWN_SETSCHEDULER) != 0) + { + svdbg("Setting policy=%d priority=%d for pid=%d\n", + attr->policy, param.sched_priority, pid); + + (void)sched_setscheduler(pid, attr->policy, ¶m); + } + } + + /* Re-enable pre-emption and return */ + +errout: + sched_unlock(); + return ret; +} + +/**************************************************************************** + * Name: spawn_close, spawn_dup2, and spawn_open + * + * Description: + * Implement individual file actions + * + * Input Parameters: + * action - describes the action to be performed + * + * Returned Value: + * posix_spawn() and posix_spawnp() will return zero on success. + * Otherwise, an error number will be returned as the function return + * value to indicate the error. + * + ****************************************************************************/ + +static inline int spawn_close(FAR struct spawn_close_file_action_s *action) +{ + /* The return value from close() is ignored */ + + svdbg("Closing fd=%d\n", action->fd); + + (void)close(action->fd); + return OK; +} + +static inline int spawn_dup2(FAR struct spawn_dup2_file_action_s *action) +{ + int ret; + + /* Perform the dup */ + + svdbg("Dup'ing %d->%d\n", action->fd1, action->fd2); + + ret = dup2(action->fd1, action->fd2); + if (ret < 0) + { + int errcode = errno; + + sdbg("ERROR: dup2 failed: %d\n", errcode); + return errcode; + } + + return OK; +} + +static inline int spawn_open(FAR struct spawn_open_file_action_s *action) +{ + int fd; + int ret = OK; + + /* Open the file */ + + svdbg("Open'ing path=%s oflags=%04x mode=%04x\n", + action->path, action->oflags, action->mode); + + fd = open(action->path, action->oflags, action->mode); + if (fd < 0) + { + ret = errno; + sdbg("ERROR: open failed: %d\n", ret); + } + + /* Does the return file descriptor happen to match the required file + * desciptor number? + */ + + else if (fd != action->fd) + { + /* No.. dup2 to get the correct file number */ + + svdbg("Dup'ing %d->%d\n", fd, action->fd); + + ret = dup2(fd, action->fd); + if (ret < 0) + { + ret = errno; + sdbg("ERROR: dup2 failed: %d\n", ret); + } + + svdbg("Closing fd=%d\n", fd); + close(fd); + } + + return ret; +} + +/**************************************************************************** + * Name: spawn_proxy + * + * Description: + * Perform file_actions, then execute the task from the file system. + * + * Input Parameters: + * Standard task start-up parameters + * + * Returned Value: + * Standard task return value. + * + ****************************************************************************/ + +static int spawn_proxy(int argc, char *argv[]) +{ + FAR struct spawn_general_file_action_s *entry; + FAR const posix_spawnattr_t *attr = g_ps_parms.attr; + int ret = OK; + + /* 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. + */ + +#ifndef CONFIG_DISABLE_SIGNALS + DEBUGASSERT((g_ps_parms.file_actions && *g_ps_parms.file_actions) || + (attr && (attr->flags & POSIX_SPAWN_SETSIGMASK) != 0)); +#else + DEBUGASSERT(g_ps_parms.file_actions && *g_ps_parms.file_actions); +#endif + + /* Check if we need to change the signal mask */ + +#ifndef CONFIG_DISABLE_SIGNALS + if (attr && (attr->flags & POSIX_SPAWN_SETSIGMASK) != 0) + { + (void)sigprocmask(SIG_SETMASK, &attr->sigmask, NULL); + } + + /* Were we also requested to perform file actions? */ + + if (g_ps_parms.file_actions) +#endif + { + /* Execute each file action */ + + for (entry = (FAR struct spawn_general_file_action_s *)*g_ps_parms.file_actions; + entry && ret == OK; + entry = entry->flink) + { + switch (entry->action) + { + case SPAWN_FILE_ACTION_CLOSE: + ret = spawn_close((FAR struct spawn_close_file_action_s *)entry); + break; + + case SPAWN_FILE_ACTION_DUP2: + ret = spawn_dup2((FAR struct spawn_dup2_file_action_s *)entry); + break; + + case SPAWN_FILE_ACTION_OPEN: + ret = spawn_open((FAR struct spawn_open_file_action_s *)entry); + break; + + case SPAWN_FILE_ACTION_NONE: + default: + sdbg("ERROR: Unknown action: %d\n", entry->action); + ret = EINVAL; + break; + } + } + } + + /* Check for failures */ + + if (ret == OK) + { + /* Start the task */ + + ret = spawn_exec(g_ps_parms.pid, g_ps_parms.path, attr, + g_ps_parms.argv); + +#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, 0, *g_ps_parms.pid); + if (tmp < 0) + { + sdbg("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_ps_parms.result = ret; +#ifndef CONFIG_SCHED_WAITPID + spawn_semgive(&g_ps_execsem); +#endif + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: posix_spawn + * + * Description: + * The posix_spawn() and posix_spawnp() functions will create a new, + * child task, constructed from a regular executable file. + * + * Input Parameters: + * + * pid - Upon successful completion, posix_spawn() and posix_spawnp() will + * return the task ID of the child task to the parent task, in the + * variable pointed to by a non-NULL 'pid' argument. If the 'pid' + * argument is a null pointer, the process ID of the child is not + * returned to the caller. + * + * path - The 'path' argument to posix_spawn() is the absolute path that + * identifies the file to execute. The 'path' argument to posix_spawnp() + * may also be a relative path and will be used to construct a pathname + * that identifies the file to execute. In the case of a relative path, + * the path prefix for the file will be obtained by a search of the + * directories passed as the environment variable PATH. + * + * NOTE: NuttX provides only one implementation: If + * CONFIG_BINFMT_EXEPATH is defined, then only posix_spawnp() behavior + * is supported; otherwise, only posix_spawn behavior is supported. + * + * file_actions - If 'file_actions' is a null pointer, then file + * descriptors open in the calling process will remain open in the + * child process (unless CONFIG_FDCLONE_STDIO is defined). If + * 'file_actions' is not NULL, then the file descriptors open in the + * child process will be those open in the calling process as modified + * by the spawn file actions object pointed to by 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 + * posix_spawnattr_t spawn attributes object type is defined in spawn.h. + * It will contains these attributes, not all of which are supported by + * NuttX: + * + * - POSIX_SPAWN_SETPGROUP: Setting of the new task's process group is + * not supported. NuttX does not support process groups. + * - POSIX_SPAWN_SETSCHEDPARAM: Set new tasks priority to the sched_param + * value. + * - POSIX_SPAWN_SETSCHEDULER: Set the new task's scheduler policy to + * the sched_policy value. + * - POSIX_SPAWN_RESETIDS: Resetting of the effective user ID of the child + * process is not supported. NuttX does not support effective user + * IDs. + * - POSIX_SPAWN_SETSIGMASK: Set the new task's signal mask. + * - POSIX_SPAWN_SETSIGDEF: Resetting signal default actions is not + * supported. NuttX does not support default signal actions. + * + * argv - argv[] is the argument list for the new task. argv[] is an + * array of pointers to null-terminated strings. The list is terminated + * with a null pointer. + * + * envp - The envp[] argument is not used by NuttX and may be NULL. In + * standard implementations, envp[] is an array of character pointers to + * null-terminated strings that provide the environment for the new + * process image. The environment array is terminated by a null pointer. + * In NuttX, the envp[] argument is ignored and the new task will simply + * inherit the environment of the parent task. + * + * Returned Value: + * posix_spawn() and posix_spawnp() will return zero on success. + * Otherwise, an error number will be returned as the function return + * value to indicate the error: + * + * - EINVAL: The value specified by 'file_actions' or 'attr' is invalid. + * - Any errors that might have been return if vfork() and excec[l|v]() + * had been called. + * + * Assumptions/Limitations: + * - NuttX provides only posix_spawn() or posix_spawnp() behavior + * depending upon the setting of CONFIG_BINFMT_EXEPATH: If + * CONFIG_BINFMT_EXEPATH is defined, then only posix_spawnp() behavior + * is supported; otherwise, only posix_spawn behavior is supported. + * - The 'envp' argument is not used and the 'environ' variable is not + * altered (NuttX does not support the 'environ' variable). + * - Process groups are not supported (POSIX_SPAWN_SETPGROUP). + * - Effective user IDs are not supported (POSIX_SPAWN_RESETIDS). + * - Signal default actions cannot be modified in the newly task executed + * because NuttX does not support default signal actions + * (POSIX_SPAWN_SETSIGDEF). + * + * POSIX Compatibility + * - The value of the argv[0] received by the child task is assigned by + * NuttX. For the caller of posix_spawn(), the provided argv[0] will + * correspond to argv[1] received by the new task. + * + ****************************************************************************/ + +#ifdef CONFIG_BINFMT_EXEPATH +int posix_spawnp(FAR pid_t *pid, FAR const char *path, + FAR const posix_spawn_file_actions_t *file_actions, + FAR const posix_spawnattr_t *attr, + FAR char *const argv[], FAR char *const envp[]) +#else +int posix_spawn(FAR pid_t *pid, FAR const char *path, + FAR const posix_spawn_file_actions_t *file_actions, + FAR const posix_spawnattr_t *attr, + FAR char *const argv[], FAR char *const envp[]) +#endif +{ + struct sched_param param; + pid_t proxy; +#ifdef CONFIG_SCHED_WAITPID + int status; +#endif + int ret; + + DEBUGASSERT(path); + + svdbg("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. + */ + +#ifndef CONFIG_DISABLE_SIGNALS + if ((file_actions == NULL || *file_actions == NULL) && + (attr == NULL || (attr->flags & POSIX_SPAWN_SETSIGMASK) == 0)) +#else + if (file_actions == NULL || *file_actions == NULL) +#endif + { + return spawn_exec(pid, path, attr, argv); + } + + /* 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 */ + + spawn_semtake(&g_ps_parmsem); + + /* Populate the parameter structure */ + + g_ps_parms.result = ENOSYS; + g_ps_parms.pid = pid; + g_ps_parms.path = path; + g_ps_parms.file_actions = file_actions; + g_ps_parms.attr = attr; + g_ps_parms.argv = argv; + + /* Get the priority of this (parent) task */ + + ret = sched_getparam(0, ¶m); + if (ret < 0) + { + int errcode = errno; + + sdbg("ERROR: sched_getparam failed: %d\n", errcode); + spawn_semgive(&g_ps_parmsem); + return errcode; + } + + /* Disable pre-emption so that the proxy does not run until we waitpid + * is called. This is probably unnecessary since the 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 = TASK_CREATE("spawn_proxy", param.sched_priority, + CONFIG_POSIX_SPAWN_STACKSIZE, (main_t)spawn_proxy, + (FAR const char **)NULL); + if (proxy < 0) + { + ret = get_errno(); + sdbg("ERROR: Failed to start spawn_proxy: %d\n", ret); + + goto errout_with_lock; + } + + /* Wait for the proxy to complete its job */ + +#ifdef CONFIG_SCHED_WAITPID + ret = waitpid(proxy, &status, 0); + if (ret < 0) + { + sdbg("ERROR: waitpid() failed: %d\n", errno); + goto errout_with_lock; + } +#else + spawn_semtake(&g_ps_execsem); +#endif + + /* Get the result and relinquish our access to the parameter structure */ + + ret = g_ps_parms.result; + +errout_with_lock: +#ifdef CONFIG_SCHED_WAITPID + sched_unlock(); +#endif + spawn_semgive(&g_ps_parmsem); + return ret; +} diff --git a/nuttx/sched/task_reparent.c b/nuttx/sched/task_reparent.c new file mode 100644 index 000000000..9daa0743b --- /dev/null +++ b/nuttx/sched/task_reparent.c @@ -0,0 +1,145 @@ +/***************************************************************************** + * sched/task_reparent.c + * + * Copyright (C) 2013 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ + +/***************************************************************************** + * Included Files + *****************************************************************************/ + +#include + +#include + +#include "os_internal.h" + +#ifdef CONFIG_SCHED_HAVE_PARENT + +/***************************************************************************** + * Private Functions + *****************************************************************************/ + +/***************************************************************************** + * Public Functions + *****************************************************************************/ + +/***************************************************************************** + * Name: task_reparent + * + * Description: + * Change the parent of a task. + * + * Parameters: + * oldpid - PID of the old parent task (0 if this task) + * newpid - PID ot the new parent task (0 for the parent of this task) + * chpid - PID of the child to be reparented. + * + * Return Value: + * 0 (OK) on success; A negated errno value on failure. + * + *****************************************************************************/ + +int task_reparent(pid_t oldpid, pid_t newpid, pid_t chpid) +{ + _TCB *oldtcb; + _TCB *newtcb; + _TCB *chtcb; + irqstate_t flags; + int ret; + + /* If oldpid is zero, then we are parent task. */ + + if (oldpid == 0) + { + oldpid = getpid(); + } + + /* Get the current parent task's TCB */ + + oldtcb = sched_gettcb(oldpid); + if (!oldtcb) + { + return -ESRCH; + } + + /* Disable interrupts so that nothing can change from this point */ + + flags = irqsave(); + + /* If newpid is zero, then new is the parent of oldpid. */ + + if (newpid == 0) + { + newpid = oldtcb->parent; + } + + /* Get the new parent task's TCB */ + + newtcb = sched_gettcb(newpid); + if (!newtcb) + { + ret = -ESRCH; + goto errout_with_ints; + } + + /* Get the child tasks TCB */ + + chtcb = sched_gettcb(chpid); + if (!chtcb) + { + ret = -ECHILD; + goto errout_with_ints; + } + + /* Verify that oldpid is the parent of chpid */ + + if (chtcb->parent != oldpid) + { + ret = -ECHILD; + goto errout_with_ints; + } + + /* Okay, reparent the child */ + + DEBUGASSERT(oldtcb->nchildren > 0); + chtcb->parent = newpid; + oldtcb->nchildren--; + newtcb->nchildren++; + ret = OK; + +errout_with_ints: + irqrestore(flags); + return ret; +} + +#endif /* CONFIG_SCHED_HAVE_PARENT */ diff --git a/nuttx/syscall/syscall.csv b/nuttx/syscall/syscall.csv index 4ccd53f9d..5bc52a71d 100644 --- a/nuttx/syscall/syscall.csv +++ b/nuttx/syscall/syscall.csv @@ -43,6 +43,8 @@ "prctl","sys/prctl.h", "CONFIG_TASK_NAME_SIZE > 0","int","int","..." "clock_systimer","nuttx/clock.h","!defined(CONFIG_DISABLE_CLOCK)","uint32_t" "poll","poll.h","!defined(CONFIG_DISABLE_POLL) && (CONFIG_NSOCKET_DESCRIPTORS > 0 || CONFIG_NFILE_DESCRIPTORS > 0)","int","FAR struct pollfd*","nfds_t","int" +"posix_spawnp", defined(CONFIG_BINFMT_EXEPATH), "int","FAR pid_t *","FAR const char *","FAR const posix_spawn_file_actions_t *","FAR const posix_spawnattr_t *","FAR char *const []","FAR char *const []" +"posix_spawn", !defined(CONFIG_BINFMT_EXEPATH), "int","FAR pid_t *","FAR const char *","FAR const posix_spawn_file_actions_t *","FAR const posix_spawnattr_t *","FAR char *const []","FAR char *const []" "pthread_barrier_destroy","pthread.h","!defined(CONFIG_DISABLE_PTHREAD)","int","FAR pthread_barrier_t*" "pthread_barrier_init","pthread.h","!defined(CONFIG_DISABLE_PTHREAD)","int","FAR pthread_barrier_t*","FAR const pthread_barrierattr_t*","unsigned int" "pthread_barrier_wait","pthread.h","!defined(CONFIG_DISABLE_PTHREAD)","int","FAR pthread_barrier_t*" -- cgit v1.2.3