diff --git a/ChangeLog b/ChangeLog index 1b0c5338b9..2a1561abe4 100644 --- a/ChangeLog +++ b/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/binfmt/binfmt_exec.c b/binfmt/binfmt_exec.c index 7f45fb841b..4226b6cfc9 100644 --- a/binfmt/binfmt_exec.c +++ b/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/libc/spawn/spawn.h b/include/nuttx/spawn.h similarity index 97% rename from libc/spawn/spawn.h rename to include/nuttx/spawn.h index 3f4e195cc7..f84ae83556 100644 --- a/libc/spawn/spawn.h +++ b/include/nuttx/spawn.h @@ -1,5 +1,5 @@ /**************************************************************************** - * libc/spawn/spawn.h + * include/nuttx/spawn.h * * Copyright (C) 2013 Gregory Nutt. All rights reserved. * Author: Gregory Nutt @@ -33,8 +33,8 @@ * ****************************************************************************/ -#ifndef __LIBC_SPAWN_SPAWN_H -#define __LIBC_SPAWN_SPAWN_H +#ifndef __INCLUDE_NUTTX_SPAWN_H +#define __INCLUDE_NUTTX_SPAWN_H /**************************************************************************** * Included Files @@ -118,4 +118,4 @@ void add_file_action(FAR posix_spawn_file_actions_t *file_action, } #endif -#endif /* __LIBC_SPAWN_SPAWN_H */ +#endif /* __INCLUDE_NUTTX_SPAWN_H */ diff --git a/include/signal.h b/include/signal.h index 30726105bb..7c6b4cd553 100644 --- a/include/signal.h +++ b/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/libc/spawn/Make.defs b/libc/spawn/Make.defs index 99ee781ce2..8cb086feee 100644 --- a/libc/spawn/Make.defs +++ b/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/libc/spawn/lib_psfa_addaction.c b/libc/spawn/lib_psfa_addaction.c index 3f297d7cf8..8700efc2a5 100644 --- a/libc/spawn/lib_psfa_addaction.c +++ b/libc/spawn/lib_psfa_addaction.c @@ -41,7 +41,7 @@ #include -#include "spawn/spawn.h" +#include /**************************************************************************** * Global Functions diff --git a/libc/spawn/lib_psfa_addclose.c b/libc/spawn/lib_psfa_addclose.c index bf22a153a8..1c72f0f828 100644 --- a/libc/spawn/lib_psfa_addclose.c +++ b/libc/spawn/lib_psfa_addclose.c @@ -44,7 +44,7 @@ #include #include -#include "spawn/spawn.h" +#include /**************************************************************************** * Global Functions diff --git a/libc/spawn/lib_psfa_adddup2.c b/libc/spawn/lib_psfa_adddup2.c index fc788a4e9d..deb3cbdb33 100644 --- a/libc/spawn/lib_psfa_adddup2.c +++ b/libc/spawn/lib_psfa_adddup2.c @@ -44,7 +44,7 @@ #include #include -#include "spawn/spawn.h" +#include /**************************************************************************** * Global Functions diff --git a/libc/spawn/lib_psfa_addopen.c b/libc/spawn/lib_psfa_addopen.c index 385e1cfc33..66bbd813a6 100644 --- a/libc/spawn/lib_psfa_addopen.c +++ b/libc/spawn/lib_psfa_addopen.c @@ -45,7 +45,7 @@ #include #include -#include "spawn/spawn.h" +#include /**************************************************************************** * Global Functions diff --git a/libc/spawn/lib_psfa_destroy.c b/libc/spawn/lib_psfa_destroy.c index 5d0a644d8b..a21886645c 100644 --- a/libc/spawn/lib_psfa_destroy.c +++ b/libc/spawn/lib_psfa_destroy.c @@ -43,7 +43,7 @@ #include #include -#include "spawn/spawn.h" +#include /**************************************************************************** * Global Functions diff --git a/libc/spawn/lib_psfa_dump.c b/libc/spawn/lib_psfa_dump.c index d7bf1576de..0dbaeb0234 100644 --- a/libc/spawn/lib_psfa_dump.c +++ b/libc/spawn/lib_psfa_dump.c @@ -43,7 +43,7 @@ #include #include -#include "spawn/spawn.h" +#include #ifdef CONFIG_DEBUG diff --git a/sched/Makefile b/sched/Makefile index 3d6b58bacf..73c67239e5 100644 --- a/sched/Makefile +++ b/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/sched/os_internal.h b/sched/os_internal.h index 32d9fb4ac3..f21d9654f6 100644 --- a/sched/os_internal.h +++ b/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/libc/spawn/lib_ps.c b/sched/task_posixspawn.c similarity index 91% rename from libc/spawn/lib_ps.c rename to sched/task_posixspawn.c index 1bf7c21133..4201e759ba 100644 --- a/libc/spawn/lib_ps.c +++ b/sched/task_posixspawn.c @@ -1,5 +1,5 @@ /**************************************************************************** - * libc/string/lib_ps.c + * sched/task_posixspawn.c * * Copyright (C) 2013 Gregory Nutt. All rights reserved. * Author: Gregory Nutt @@ -50,8 +50,9 @@ #include #include +#include -#include "spawn/spawn.h" +#include "os_internal.h" /**************************************************************************** * Private Types @@ -86,7 +87,7 @@ static struct spawn_parms_s g_ps_parms; ****************************************************************************/ /**************************************************************************** - * Name: ps_semtake and ps_semgive + * Name: spawn_semtake and spawn_semgive * * Description: * Give and take semaphores @@ -100,7 +101,7 @@ static struct spawn_parms_s g_ps_parms; * ****************************************************************************/ -static void ps_semtake(FAR sem_t *sem) +static void spawn_semtake(FAR sem_t *sem) { int ret; @@ -112,10 +113,10 @@ static void ps_semtake(FAR sem_t *sem) while (ret != 0); } -#define ps_semgive(sem) sem_post(sem) +#define spawn_semgive(sem) sem_post(sem) /**************************************************************************** - * Name: ps_exec + * Name: spawn_exec * * Description: * Execute the task from the file system. @@ -153,9 +154,9 @@ static void ps_semtake(FAR sem_t *sem) * ****************************************************************************/ -static int ps_exec(FAR pid_t *pidp, FAR const char *path, - FAR const posix_spawnattr_t *attr, - FAR char *const argv[]) +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; @@ -420,7 +421,23 @@ static int spawn_proxy(int argc, char *argv[]) { /* Start the task */ - ret = ps_exec(g_ps_parms.pid, g_ps_parms.path, attr, g_ps_parms.argv); + 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 @@ -429,9 +446,9 @@ static int spawn_proxy(int argc, char *argv[]) g_ps_parms.result = ret; #ifndef CONFIG_SCHED_WAITPID - ps_semgive(&g_ps_execsem); + spawn_semgive(&g_ps_execsem); #endif - return 0; + return OK; } /**************************************************************************** @@ -566,7 +583,7 @@ int posix_spawn(FAR pid_t *pid, FAR const char *path, if (file_actions == NULL || *file_actions == NULL) #endif { - return ps_exec(pid, path, attr, argv); + return spawn_exec(pid, path, attr, argv); } /* Otherwise, we will have to go through an intermediary/proxy task in order @@ -582,7 +599,7 @@ int posix_spawn(FAR pid_t *pid, FAR const char *path, /* Get exclusive access to the global parameter structure */ - ps_semtake(&g_ps_parmsem); + spawn_semtake(&g_ps_parmsem); /* Populate the parameter structure */ @@ -601,22 +618,33 @@ int posix_spawn(FAR pid_t *pid, FAR const char *path, int errcode = errno; sdbg("ERROR: sched_getparam failed: %d\n", errcode); - ps_semgive(&g_ps_parmsem); + spawn_semgive(&g_ps_parmsem); return errcode; } - /* Start the intermediary/proxy task at the same priority as the parent task. */ + /* 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) { - int errcode = errno; + ret = get_errno(); + sdbg("ERROR: Failed to start spawn_proxy: %d\n", ret); - sdbg("ERROR: Failed to start spawn_proxy: %d\n", errcode); - ps_semgive(&g_ps_parmsem); - return errcode; + goto errout_with_lock; } /* Wait for the proxy to complete its job */ @@ -625,15 +653,21 @@ int posix_spawn(FAR pid_t *pid, FAR const char *path, ret = waitpid(proxy, &status, 0); if (ret < 0) { - sdbg("ERROR: waitpid() failed: %d\n", errno); + sdbg("ERROR: waitpid() failed: %d\n", errno); + goto errout_with_lock; } #else - ps_semtake(&g_ps_execsem); + spawn_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; + +errout_with_lock: +#ifdef CONFIG_SCHED_WAITPID + sched_unlock(); +#endif + spawn_semgive(&g_ps_parmsem); + return ret; } diff --git a/sched/task_reparent.c b/sched/task_reparent.c new file mode 100644 index 0000000000..9daa0743b0 --- /dev/null +++ b/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/syscall/syscall.csv b/syscall/syscall.csv index 4ccd53f9d6..5bc52a71d7 100644 --- a/syscall/syscall.csv +++ b/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*"