From d699ae3cb3e27074dc6c70bb2cebc577ff5db8d4 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Fri, 8 Aug 2014 16:44:08 -0600 Subject: Move task control files from sched/ to sched/task --- nuttx/arch/8051/src/up_exit.c | 1 + nuttx/arch/arm/src/common/up_exit.c | 7 +- nuttx/arch/avr/src/common/up_exit.c | 7 +- nuttx/arch/hc/src/common/up_exit.c | 7 +- nuttx/arch/mips/src/common/up_exit.c | 7 +- nuttx/arch/rgmp/src/nuttx.c | 5 +- nuttx/arch/sh/src/common/up_exit.c | 7 +- nuttx/arch/sim/src/up_exit.c | 1 + nuttx/arch/x86/src/common/up_exit.c | 7 +- nuttx/arch/z16/src/common/up_exit.c | 9 +- nuttx/arch/z80/src/common/up_exit.c | 9 +- nuttx/sched/Makefile | 35 +- nuttx/sched/exit.c | 3 +- nuttx/sched/group/Make.defs | 2 +- nuttx/sched/group/group.h | 5 + nuttx/sched/init/init.h | 7 - nuttx/sched/os_internal.h | 12 - nuttx/sched/pthread/pthread_exit.c | 1 + nuttx/sched/spawn_internal.h | 162 -------- nuttx/sched/task/Make.defs | 60 +++ nuttx/sched/task/spawn.h | 162 ++++++++ nuttx/sched/task/task.h | 77 ++++ nuttx/sched/task/task_activate.c | 117 ++++++ nuttx/sched/task/task_create.c | 293 ++++++++++++++ nuttx/sched/task/task_delete.c | 133 ++++++ nuttx/sched/task/task_exit.c | 165 ++++++++ nuttx/sched/task/task_exithook.c | 691 +++++++++++++++++++++++++++++++ nuttx/sched/task/task_getgroup.c | 106 +++++ nuttx/sched/task/task_init.c | 198 +++++++++ nuttx/sched/task/task_posixspawn.c | 462 +++++++++++++++++++++ nuttx/sched/task/task_recover.c | 124 ++++++ nuttx/sched/task/task_reparent.c | 321 +++++++++++++++ nuttx/sched/task/task_restart.c | 209 ++++++++++ nuttx/sched/task/task_setup.c | 765 +++++++++++++++++++++++++++++++++++ nuttx/sched/task/task_spawn.c | 454 +++++++++++++++++++++ nuttx/sched/task/task_spawnparms.c | 341 ++++++++++++++++ nuttx/sched/task/task_start.c | 145 +++++++ nuttx/sched/task/task_starthook.c | 113 ++++++ nuttx/sched/task/task_terminate.c | 189 +++++++++ nuttx/sched/task/task_vfork.c | 345 ++++++++++++++++ nuttx/sched/task_activate.c | 117 ------ nuttx/sched/task_create.c | 292 ------------- nuttx/sched/task_delete.c | 132 ------ nuttx/sched/task_exit.c | 162 -------- nuttx/sched/task_exithook.c | 690 ------------------------------- nuttx/sched/task_getgroup.c | 105 ----- nuttx/sched/task_init.c | 197 --------- nuttx/sched/task_posixspawn.c | 461 --------------------- nuttx/sched/task_recover.c | 123 ------ nuttx/sched/task_reparent.c | 320 --------------- nuttx/sched/task_restart.c | 208 ---------- nuttx/sched/task_setup.c | 764 ---------------------------------- nuttx/sched/task_spawn.c | 453 --------------------- nuttx/sched/task_spawnparms.c | 340 ---------------- nuttx/sched/task_start.c | 144 ------- nuttx/sched/task_starthook.c | 111 ----- nuttx/sched/task_terminate.c | 188 --------- nuttx/sched/task_vfork.c | 344 ---------------- 58 files changed, 5527 insertions(+), 5388 deletions(-) delete mode 100644 nuttx/sched/spawn_internal.h create mode 100644 nuttx/sched/task/Make.defs create mode 100644 nuttx/sched/task/spawn.h create mode 100644 nuttx/sched/task/task.h create mode 100644 nuttx/sched/task/task_activate.c create mode 100644 nuttx/sched/task/task_create.c create mode 100644 nuttx/sched/task/task_delete.c create mode 100644 nuttx/sched/task/task_exit.c create mode 100644 nuttx/sched/task/task_exithook.c create mode 100644 nuttx/sched/task/task_getgroup.c create mode 100644 nuttx/sched/task/task_init.c create mode 100644 nuttx/sched/task/task_posixspawn.c create mode 100644 nuttx/sched/task/task_recover.c create mode 100644 nuttx/sched/task/task_reparent.c create mode 100644 nuttx/sched/task/task_restart.c create mode 100644 nuttx/sched/task/task_setup.c create mode 100644 nuttx/sched/task/task_spawn.c create mode 100644 nuttx/sched/task/task_spawnparms.c create mode 100644 nuttx/sched/task/task_start.c create mode 100644 nuttx/sched/task/task_starthook.c create mode 100644 nuttx/sched/task/task_terminate.c create mode 100644 nuttx/sched/task/task_vfork.c delete mode 100644 nuttx/sched/task_activate.c delete mode 100644 nuttx/sched/task_create.c delete mode 100644 nuttx/sched/task_delete.c delete mode 100644 nuttx/sched/task_exit.c delete mode 100644 nuttx/sched/task_exithook.c delete mode 100644 nuttx/sched/task_getgroup.c delete mode 100644 nuttx/sched/task_init.c delete mode 100644 nuttx/sched/task_posixspawn.c delete mode 100644 nuttx/sched/task_recover.c delete mode 100644 nuttx/sched/task_reparent.c delete mode 100644 nuttx/sched/task_restart.c delete mode 100644 nuttx/sched/task_setup.c delete mode 100644 nuttx/sched/task_spawn.c delete mode 100644 nuttx/sched/task_spawnparms.c delete mode 100644 nuttx/sched/task_start.c delete mode 100644 nuttx/sched/task_starthook.c delete mode 100644 nuttx/sched/task_terminate.c delete mode 100644 nuttx/sched/task_vfork.c diff --git a/nuttx/arch/8051/src/up_exit.c b/nuttx/arch/8051/src/up_exit.c index 235eb691f..9ef273294 100644 --- a/nuttx/arch/8051/src/up_exit.c +++ b/nuttx/arch/8051/src/up_exit.c @@ -45,6 +45,7 @@ #include <8052.h> #include +#include "task/task.h" #include "os_internal.h" #include "up_internal.h" diff --git a/nuttx/arch/arm/src/common/up_exit.c b/nuttx/arch/arm/src/common/up_exit.c index 37b603e50..70358184d 100644 --- a/nuttx/arch/arm/src/common/up_exit.c +++ b/nuttx/arch/arm/src/common/up_exit.c @@ -43,13 +43,14 @@ #include #include -#include "os_internal.h" -#include "up_internal.h" - #ifdef CONFIG_DUMP_ON_EXIT #include #endif +#include "task/task.h" +#include "os_internal.h" +#include "up_internal.h" + /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ diff --git a/nuttx/arch/avr/src/common/up_exit.c b/nuttx/arch/avr/src/common/up_exit.c index 355163359..db422b410 100644 --- a/nuttx/arch/avr/src/common/up_exit.c +++ b/nuttx/arch/avr/src/common/up_exit.c @@ -43,13 +43,14 @@ #include #include -#include "os_internal.h" -#include "up_internal.h" - #ifdef CONFIG_DUMP_ON_EXIT #include #endif +#include "task/task.h" +#include "os_internal.h" +#include "up_internal.h" + /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ diff --git a/nuttx/arch/hc/src/common/up_exit.c b/nuttx/arch/hc/src/common/up_exit.c index 7fa526ff7..1e8bdca2e 100644 --- a/nuttx/arch/hc/src/common/up_exit.c +++ b/nuttx/arch/hc/src/common/up_exit.c @@ -43,13 +43,14 @@ #include #include -#include "os_internal.h" -#include "up_internal.h" - #ifdef CONFIG_DUMP_ON_EXIT #include #endif +#include "task/task.h" +#include "os_internal.h" +#include "up_internal.h" + /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ diff --git a/nuttx/arch/mips/src/common/up_exit.c b/nuttx/arch/mips/src/common/up_exit.c index 415ca64ee..585a667a7 100644 --- a/nuttx/arch/mips/src/common/up_exit.c +++ b/nuttx/arch/mips/src/common/up_exit.c @@ -45,13 +45,14 @@ #include #include -#include "os_internal.h" -#include "up_internal.h" - #ifdef CONFIG_DUMP_ON_EXIT #include #endif +#include "task/task.h" +#include "os_internal.h" +#include "up_internal.h" + /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ diff --git a/nuttx/arch/rgmp/src/nuttx.c b/nuttx/arch/rgmp/src/nuttx.c index 0178ae58a..2b20cad64 100644 --- a/nuttx/arch/rgmp/src/nuttx.c +++ b/nuttx/arch/rgmp/src/nuttx.c @@ -52,10 +52,11 @@ #include #include #include -#include -struct tcb_s *current_task = NULL; +#include "task/task.h" +#include "os_internal.h" +struct tcb_s *current_task = NULL; /** * This function is called in non-interrupt context diff --git a/nuttx/arch/sh/src/common/up_exit.c b/nuttx/arch/sh/src/common/up_exit.c index d4669caf4..bdb1c520e 100644 --- a/nuttx/arch/sh/src/common/up_exit.c +++ b/nuttx/arch/sh/src/common/up_exit.c @@ -44,13 +44,14 @@ #include -#include "os_internal.h" -#include "up_internal.h" - #ifdef CONFIG_DUMP_ON_EXIT #include #endif +#include "task/task.h" +#include "os_internal.h" +#include "up_internal.h" + /**************************************************************************** * Private Definitions ****************************************************************************/ diff --git a/nuttx/arch/sim/src/up_exit.c b/nuttx/arch/sim/src/up_exit.c index f4c91e544..b70a91154 100644 --- a/nuttx/arch/sim/src/up_exit.c +++ b/nuttx/arch/sim/src/up_exit.c @@ -44,6 +44,7 @@ #include +#include "task/task.h" #include "os_internal.h" #include "up_internal.h" diff --git a/nuttx/arch/x86/src/common/up_exit.c b/nuttx/arch/x86/src/common/up_exit.c index ad1ec41c6..bf2548214 100644 --- a/nuttx/arch/x86/src/common/up_exit.c +++ b/nuttx/arch/x86/src/common/up_exit.c @@ -43,13 +43,14 @@ #include #include -#include "os_internal.h" -#include "up_internal.h" - #ifdef CONFIG_DUMP_ON_EXIT #include #endif +#include "task/task.h" +#include "os_internal.h" +#include "up_internal.h" + /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ diff --git a/nuttx/arch/z16/src/common/up_exit.c b/nuttx/arch/z16/src/common/up_exit.c index c578a3bfe..99d50bab8 100644 --- a/nuttx/arch/z16/src/common/up_exit.c +++ b/nuttx/arch/z16/src/common/up_exit.c @@ -44,14 +44,15 @@ #include -#include "chip/chip.h" -#include "os_internal.h" -#include "up_internal.h" - #ifdef CONFIG_DUMP_ON_EXIT #include #endif +#include "chip/chip.h" +#include "task/task.h" +#include "os_internal.h" +#include "up_internal.h" + /**************************************************************************** * Private Definitions ****************************************************************************/ diff --git a/nuttx/arch/z80/src/common/up_exit.c b/nuttx/arch/z80/src/common/up_exit.c index 50d675f96..124ee1035 100644 --- a/nuttx/arch/z80/src/common/up_exit.c +++ b/nuttx/arch/z80/src/common/up_exit.c @@ -45,14 +45,15 @@ #include -#include "chip/chip.h" -#include "os_internal.h" -#include "up_internal.h" - #ifdef CONFIG_DUMP_ON_EXIT #include #endif +#include "chip/chip.h" +#include "task/task.h" +#include "os_internal.h" +#include "up_internal.h" + /**************************************************************************** * Private Definitions ****************************************************************************/ diff --git a/nuttx/sched/Makefile b/nuttx/sched/Makefile index 563983aac..c1dade975 100644 --- a/nuttx/sched/Makefile +++ b/nuttx/sched/Makefile @@ -40,31 +40,10 @@ DEPPATH = --dep-path . ASRCS = -TSK_SRCS = prctl.c exit.c getpid.c -TSK_SRCS += task_create.c task_init.c task_setup.c task_activate.c task_start.c -TSK_SRCS += task_delete.c task_exit.c task_exithook.c task_recover.c -TSK_SRCS += task_restart.c task_spawn.c task_spawnparms.c task_terminate.c -TSK_SRCS += sched_addreadytorun.c sched_removereadytorun.c sched_addprioritized.c -TSK_SRCS += sched_mergepending.c sched_addblocked.c sched_removeblocked.c -TSK_SRCS += sched_free.c sched_gettcb.c sched_verifytcb.c sched_releasetcb.c - -ifeq ($(CONFIG_ARCH_HAVE_VFORK),y) -ifeq ($(CONFIG_SCHED_WAITPID),y) -TSK_SRCS += task_vfork.c -endif -endif - -ifneq ($(CONFIG_BINFMT_DISABLE),y) -ifeq ($(CONFIG_LIBC_EXECFUNCS),y) -TSK_SRCS += task_posixspawn.c -endif -endif - -ifeq ($(CONFIG_SCHED_STARTHOOK),y) -TSK_SRCS += task_starthook.c -endif - SCHED_SRCS = sched_garbage.c sched_getfiles.c +SCHED_SRCS += sched_addreadytorun.c sched_removereadytorun.c sched_addprioritized.c +SCHED_SRCS += sched_mergepending.c sched_addblocked.c sched_removeblocked.c +SCHED_SRCS += sched_free.c sched_gettcb.c sched_verifytcb.c sched_releasetcb.c SCHED_SRCS += sched_getsockets.c sched_getstreams.c SCHED_SRCS += sched_setparam.c sched_setpriority.c sched_getparam.c SCHED_SRCS += sched_setscheduler.c sched_getscheduler.c @@ -108,6 +87,7 @@ include init/Make.defs include irq/Make.defs include paging/Make.defs include group/Make.defs +include task/Make.defs include errno/Make.defs include wdog/Make.defs include semaphore/Make.defs @@ -118,8 +98,11 @@ include clock/Make.defs include timer/Make.defs include environ/Make.defs -CSRCS = $(INIT_SRCS) $(IRQ_SRCS) $(PG_SRCS) $(GRP_SRCS) $(TSK_SRCS) -CSRCS += $(SCHED_SRCS) $(ERRNO_SRCS) $(WDOG_SRCS) $(SEM_SRCS) +# REVISIT +TSK_SRCS += prctl.c exit.c getpid.c + +CSRCS = $(INIT_SRCS) $(IRQ_SRCS) $(PG_SRCS) $(GRP_SRCS) $(SCHED_SRCS) +CSRCS += $(TSK_SRCS) $(ERRNO_SRCS) $(WDOG_SRCS) $(SEM_SRCS) CSRCS += $(SIGNAL_SRCS) $(PTHREAD_SRCS) $(MQUEUE_SRCS) $(CLOCK_SRCS) CSRCS += $(TIMER_SRCS) $(ENV_SRCS) diff --git a/nuttx/sched/exit.c b/nuttx/sched/exit.c index b88c84ec3..db922d89f 100644 --- a/nuttx/sched/exit.c +++ b/nuttx/sched/exit.c @@ -46,10 +46,11 @@ #include +#include "task/task.h" #include "os_internal.h" /**************************************************************************** - * Definitions + * Pre-processor Definitions ****************************************************************************/ /**************************************************************************** diff --git a/nuttx/sched/group/Make.defs b/nuttx/sched/group/Make.defs index b389055cf..b88436547 100644 --- a/nuttx/sched/group/Make.defs +++ b/nuttx/sched/group/Make.defs @@ -35,7 +35,7 @@ GRP_SRCS = group_create.c group_join.c group_leave.c group_find.c GRP_SRCS += group_setupstreams.c group_setupidlefiles.c group_setuptaskfiles.c -GRP_SRCS += task_getgroup.c group_foreachchild.c group_killchildren.c +GRP_SRCS += group_foreachchild.c group_killchildren.c ifeq ($(CONFIG_SCHED_HAVE_PARENT),y) GRP_SRCS += task_reparent.c diff --git a/nuttx/sched/group/group.h b/nuttx/sched/group/group.h index 96ebe231d..a15919070 100644 --- a/nuttx/sched/group/group.h +++ b/nuttx/sched/group/group.h @@ -75,6 +75,11 @@ extern FAR struct task_group_s *g_grouphead; /**************************************************************************** * Public Function Prototypes ****************************************************************************/ + +#ifdef CONFIG_SCHED_CHILD_STATUS +void weak_function task_initialize(void); +#endif + /* Task group data structure management */ #ifdef HAVE_TASK_GROUP diff --git a/nuttx/sched/init/init.h b/nuttx/sched/init/init.h index b52920a5c..d3f3ae913 100644 --- a/nuttx/sched/init/init.h +++ b/nuttx/sched/init/init.h @@ -42,13 +42,6 @@ #include -#include -#include -#include -#include - -#include - /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ diff --git a/nuttx/sched/os_internal.h b/nuttx/sched/os_internal.h index 6ce7a9757..9307fb313 100644 --- a/nuttx/sched/os_internal.h +++ b/nuttx/sched/os_internal.h @@ -219,18 +219,6 @@ extern volatile uint32_t g_cpuload_total; * Public Function Prototypes ****************************************************************************/ -#ifdef CONFIG_SCHED_CHILD_STATUS -void weak_function task_initialize(void); -#endif -void task_start(void); -int task_schedsetup(FAR struct task_tcb_s *tcb, int priority, - start_t start, main_t main, uint8_t ttype); -int task_argsetup(FAR struct task_tcb_s *tcb, FAR const char *name, - FAR char * const argv[]); -int task_exit(void); -int task_terminate(pid_t pid, bool nonblocking); -void task_exithook(FAR struct tcb_s *tcb, int status, bool nonblocking); -void task_recover(FAR struct tcb_s *tcb); bool sched_addreadytorun(FAR struct tcb_s *rtrtcb); bool sched_removereadytorun(FAR struct tcb_s *rtrtcb); bool sched_addprioritized(FAR struct tcb_s *newTcb, DSEG dq_queue_t *list); diff --git a/nuttx/sched/pthread/pthread_exit.c b/nuttx/sched/pthread/pthread_exit.c index 3ca5362f7..ebc7fb262 100644 --- a/nuttx/sched/pthread/pthread_exit.c +++ b/nuttx/sched/pthread/pthread_exit.c @@ -50,6 +50,7 @@ #include #include "os_internal.h" +#include "task/task.h" #include "pthread/pthread.h" /************************************************************************ diff --git a/nuttx/sched/spawn_internal.h b/nuttx/sched/spawn_internal.h deleted file mode 100644 index 89021226a..000000000 --- a/nuttx/sched/spawn_internal.h +++ /dev/null @@ -1,162 +0,0 @@ -/**************************************************************************** - * sched/spawn_internal.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 __SCHED_SPAWN_INERNAL_H -#define __SCHED_SPAWN_INERNAL_H - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include -#include - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -#ifndef CONFIG_POSIX_SPAWN_PROXY_STACKSIZE -# define CONFIG_POSIX_SPAWN_PROXY_STACKSIZE 1024 -#endif - -/**************************************************************************** - * Public Type Definitions - ****************************************************************************/ - -struct spawn_parms_s -{ - /* Common parameters */ - - int result; - FAR pid_t *pid; - FAR const posix_spawn_file_actions_t *file_actions; - FAR const posix_spawnattr_t *attr; - FAR char * const *argv; - - /* Parameters that differ for posix_spawn[p] and task_spawn */ - - union - { - struct - { - FAR const char *path; - } posix; - struct - { - FAR const char *name; - main_t entry; - } task; - } u; -}; - -/**************************************************************************** - * Public Data - ****************************************************************************/ - -extern sem_t g_spawn_parmsem; -#ifndef CONFIG_SCHED_WAITPID -extern sem_t g_spawn_execsem; -#endif -extern struct spawn_parms_s g_spawn_parms; - -/**************************************************************************** - * Public Function Prototypes - ****************************************************************************/ - -/**************************************************************************** - * Name: spawn_semtake and spawn_semgive - * - * Description: - * Give and take semaphores - * - * Input Parameters: - * - * sem - The semaphore to act on. - * - * Returned Value: - * None - * - ****************************************************************************/ - -void spawn_semtake(FAR sem_t *sem); -#define spawn_semgive(sem) sem_post(sem) - -/**************************************************************************** - * Name: spawn_execattrs - * - * Description: - * Set attributes of the new child task after it has been spawned. - * - * Input Parameters: - * - * pid - The pid of the new task. - * attr - The attributes to use - * - * Returned Value: - * Errors are not reported by this function. This is because errors - * cannot occur, but ratther that the new task has already been started - * so there is no graceful way to handle errors detected in this context - * (unless we delete the new task and recover). - * - * Assumptions: - * That task has been started but has not yet executed because pre- - * emption is disabled. - * - ****************************************************************************/ - -int spawn_execattrs(pid_t pid, FAR const posix_spawnattr_t *attr); - -/**************************************************************************** - * Name: spawn_proxyattrs - * - * Description: - * Set attributes of the proxy task before it has started the new child - * task. - * - * Input Parameters: - * - * pid - The pid of the new task. - * attr - The attributes to use - * file_actions - The attributes to use - * - * Returned Value: - * 0 (OK) on successed; A negated errno value is returned on failure. - * - ****************************************************************************/ - -int spawn_proxyattrs(FAR const posix_spawnattr_t *attr, - FAR const posix_spawn_file_actions_t *file_actions); - -#endif /* __SCHED_SPAWN_INERNAL_H */ diff --git a/nuttx/sched/task/Make.defs b/nuttx/sched/task/Make.defs new file mode 100644 index 000000000..0d979e501 --- /dev/null +++ b/nuttx/sched/task/Make.defs @@ -0,0 +1,60 @@ +############################################################################ +# sched/task/Make.defs +# +# Copyright (C) 2014 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. +# +############################################################################ + +TSK_SRCS = task_create.c task_init.c task_setup.c task_activate.c +TSK_SRCS += task_start.c task_delete.c task_exit.c task_exithook.c +TSK_SRCS += task_recover.c task_restart.c task_spawn.c task_spawnparms.c +TSK_SRCS += task_terminate.c task_getgroup.c + +ifeq ($(CONFIG_ARCH_HAVE_VFORK),y) +ifeq ($(CONFIG_SCHED_WAITPID),y) +TSK_SRCS += task_vfork.c +endif +endif + +ifneq ($(CONFIG_BINFMT_DISABLE),y) +ifeq ($(CONFIG_LIBC_EXECFUNCS),y) +TSK_SRCS += task_posixspawn.c +endif +endif + +ifeq ($(CONFIG_SCHED_STARTHOOK),y) +TSK_SRCS += task_starthook.c +endif + +# Include task build support + +DEPPATH += --dep-path task +VPATH += :task diff --git a/nuttx/sched/task/spawn.h b/nuttx/sched/task/spawn.h new file mode 100644 index 000000000..1e44f035a --- /dev/null +++ b/nuttx/sched/task/spawn.h @@ -0,0 +1,162 @@ +/**************************************************************************** + * sched/task/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 __SCHED_TASK_SPAWN_H +#define __SCHED_TASK_SPAWN_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef CONFIG_POSIX_SPAWN_PROXY_STACKSIZE +# define CONFIG_POSIX_SPAWN_PROXY_STACKSIZE 1024 +#endif + +/**************************************************************************** + * Public Type Definitions + ****************************************************************************/ + +struct spawn_parms_s +{ + /* Common parameters */ + + int result; + FAR pid_t *pid; + FAR const posix_spawn_file_actions_t *file_actions; + FAR const posix_spawnattr_t *attr; + FAR char * const *argv; + + /* Parameters that differ for posix_spawn[p] and task_spawn */ + + union + { + struct + { + FAR const char *path; + } posix; + struct + { + FAR const char *name; + main_t entry; + } task; + } u; +}; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +extern sem_t g_spawn_parmsem; +#ifndef CONFIG_SCHED_WAITPID +extern sem_t g_spawn_execsem; +#endif +extern struct spawn_parms_s g_spawn_parms; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: spawn_semtake and spawn_semgive + * + * Description: + * Give and take semaphores + * + * Input Parameters: + * + * sem - The semaphore to act on. + * + * Returned Value: + * None + * + ****************************************************************************/ + +void spawn_semtake(FAR sem_t *sem); +#define spawn_semgive(sem) sem_post(sem) + +/**************************************************************************** + * Name: spawn_execattrs + * + * Description: + * Set attributes of the new child task after it has been spawned. + * + * Input Parameters: + * + * pid - The pid of the new task. + * attr - The attributes to use + * + * Returned Value: + * Errors are not reported by this function. This is because errors + * cannot occur, but ratther that the new task has already been started + * so there is no graceful way to handle errors detected in this context + * (unless we delete the new task and recover). + * + * Assumptions: + * That task has been started but has not yet executed because pre- + * emption is disabled. + * + ****************************************************************************/ + +int spawn_execattrs(pid_t pid, FAR const posix_spawnattr_t *attr); + +/**************************************************************************** + * Name: spawn_proxyattrs + * + * Description: + * Set attributes of the proxy task before it has started the new child + * task. + * + * Input Parameters: + * + * pid - The pid of the new task. + * attr - The attributes to use + * file_actions - The attributes to use + * + * Returned Value: + * 0 (OK) on successed; A negated errno value is returned on failure. + * + ****************************************************************************/ + +int spawn_proxyattrs(FAR const posix_spawnattr_t *attr, + FAR const posix_spawn_file_actions_t *file_actions); + +#endif /* __SCHED_TASK_SPAWN_H */ diff --git a/nuttx/sched/task/task.h b/nuttx/sched/task/task.h new file mode 100644 index 000000000..a748877f7 --- /dev/null +++ b/nuttx/sched/task/task.h @@ -0,0 +1,77 @@ +/**************************************************************************** + * sched/task/task.h + * + * Copyright (C) 2007-2014 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 __SCHED_TASK_TASK_H +#define __SCHED_TASK_TASK_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include +#include + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Type Definitions + ****************************************************************************/ + +/**************************************************************************** + * Global Variables + ****************************************************************************/ +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +void task_start(void); +int task_schedsetup(FAR struct task_tcb_s *tcb, int priority, + start_t start, main_t main, uint8_t ttype); +int task_argsetup(FAR struct task_tcb_s *tcb, FAR const char *name, + FAR char * const argv[]); +int task_exit(void); +int task_terminate(pid_t pid, bool nonblocking); +void task_exithook(FAR struct tcb_s *tcb, int status, bool nonblocking); +void task_recover(FAR struct tcb_s *tcb); +bool sched_addreadytorun(FAR struct tcb_s *rtrtcb); + +#endif /* __SCHED_TASK_TASK_H */ diff --git a/nuttx/sched/task/task_activate.c b/nuttx/sched/task/task_activate.c new file mode 100644 index 000000000..2b11e5426 --- /dev/null +++ b/nuttx/sched/task/task_activate.c @@ -0,0 +1,117 @@ +/**************************************************************************** + * sched/task/task_activate.c + * + * Copyright (C) 2007-2009 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 + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Type Declarations + ****************************************************************************/ + +/**************************************************************************** + * Global Variables + ****************************************************************************/ + +/**************************************************************************** + * Private Variables + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: task_activate + * + * Description: + * This function activates tasks initialized by task_schedsetup(). Without + * activation, a task is ineligible for execution by the scheduler. + * + * Input Parameters: + * tcb - The TCB for the task for the task (same as the task_init argument). + * + * Return Value: + * Always returns OK + * + ****************************************************************************/ + +int task_activate(FAR struct tcb_s *tcb) +{ + irqstate_t flags = irqsave(); + +#ifdef CONFIG_SCHED_INSTRUMENTATION + + /* Check if this is really a re-start */ + + if (tcb->task_state != TSTATE_TASK_INACTIVE) + { + /* Inform the instrumentation layer that the task + * has stopped + */ + + sched_note_stop(tcb); + } + + /* Inform the instrumentation layer that the task + * has started + */ + + sched_note_start(tcb); +#endif + + up_unblock_task(tcb); + irqrestore(flags); + return OK; +} diff --git a/nuttx/sched/task/task_create.c b/nuttx/sched/task/task_create.c new file mode 100644 index 000000000..d6663e45c --- /dev/null +++ b/nuttx/sched/task/task_create.c @@ -0,0 +1,293 @@ +/**************************************************************************** + * sched/task/task_create.c + * + * Copyright (C) 2007-2010, 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 "os_internal.h" +#include "group/group.h" +#include "task/task.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Type Declarations + ****************************************************************************/ + +/**************************************************************************** + * Global Variables + ****************************************************************************/ + +/**************************************************************************** + * Private Variables + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: thread_create + * + * Description: + * This function creates and activates a new thread of the specified type + * with a specified priority and returns its system-assigned ID. It is the + * internal, commn implementation of task_create() and kernel_thread(). + * See comments with task_create() for further information. + * + * Input Parameters: + * name - Name of the new task + * ttype - Type of the new task + * priority - Priority of the new task + * stack_size - size (in bytes) of the stack needed + * entry - Entry point of a new task + * arg - A pointer to an array of input parameters. Up to + * CONFIG_MAX_TASK_ARG parameters may be provided. If fewer + * than CONFIG_MAX_TASK_ARG parameters are passed, the list + * should be terminated with a NULL argv[] value. If no + * parameters are required, argv may be NULL. + * + * Return Value: + * Returns the non-zero process ID of the new task or ERROR if memory is + * insufficient or the task cannot be created. The errno will be set to + * indicate the nature of the error (always ENOMEM). + * + ****************************************************************************/ + +#ifndef CONFIG_CUSTOM_STACK +static int thread_create(FAR const char *name, uint8_t ttype, int priority, + int stack_size, main_t entry, FAR char * const argv[]) +#else +static int thread_create(FAR const char *name, uint8_t ttype, int priority, + main_t entry, FAR char * const argv[]) +#endif +{ + FAR struct task_tcb_s *tcb; + pid_t pid; + int errcode; + int ret; + + /* Allocate a TCB for the new task. */ + + tcb = (FAR struct task_tcb_s *)kzalloc(sizeof(struct task_tcb_s)); + if (!tcb) + { + sdbg("ERROR: Failed to allocate TCB\n"); + errcode = ENOMEM; + goto errout; + } + + /* Allocate a new task group */ + +#ifdef HAVE_TASK_GROUP + ret = group_allocate(tcb); + if (ret < 0) + { + errcode = -ret; + goto errout_with_tcb; + } +#endif + + /* Associate file descriptors with the new task */ + +#if CONFIG_NFILE_DESCRIPTORS > 0 || CONFIG_NSOCKET_DESCRIPTORS > 0 + ret = group_setuptaskfiles(tcb); + if (ret < OK) + { + errcode = -ret; + goto errout_with_tcb; + } +#endif + + /* Allocate the stack for the TCB */ + +#ifndef CONFIG_CUSTOM_STACK + ret = up_create_stack((FAR struct tcb_s *)tcb, stack_size, ttype); + if (ret < OK) + { + errcode = -ret; + goto errout_with_tcb; + } +#endif + + /* Initialize the task control block */ + + ret = task_schedsetup(tcb, priority, task_start, entry, ttype); + if (ret < OK) + { + errcode = -ret; + goto errout_with_tcb; + } + + /* Setup to pass parameters to the new task */ + + (void)task_argsetup(tcb, name, argv); + + /* Now we have enough in place that we can join the group */ + +#ifdef HAVE_TASK_GROUP + ret = group_initialize(tcb); + if (ret < 0) + { + errcode = -ret; + goto errout_with_tcb; + } +#endif + + /* Get the assigned pid before we start the task */ + + pid = (int)tcb->cmn.pid; + + /* Activate the task */ + + ret = task_activate((FAR struct tcb_s *)tcb); + if (ret < OK) + { + errcode = get_errno(); + + /* The TCB was added to the active task list by task_schedsetup() */ + + dq_rem((FAR dq_entry_t*)tcb, (dq_queue_t*)&g_inactivetasks); + goto errout_with_tcb; + } + + return pid; + +errout_with_tcb: + sched_releasetcb((FAR struct tcb_s *)tcb, ttype); + +errout: + set_errno(errcode); + return ERROR; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: task_create + * + * Description: + * This function creates and activates a new task with a specified + * priority and returns its system-assigned ID. + * + * The entry address entry is the address of the "main" function of the + * task. This function will be called once the C environment has been + * set up. The specified function will be called with four arguments. + * Should the specified routine return, a call to exit() will + * automatically be made. + * + * Note that four (and only four) arguments must be passed for the spawned + * functions. + * + * Input Parameters: + * name - Name of the new task + * priority - Priority of the new task + * stack_size - size (in bytes) of the stack needed + * entry - Entry point of a new task + * arg - A pointer to an array of input parameters. Up to + * CONFIG_MAX_TASK_ARG parameters may be provided. If fewer + * than CONFIG_MAX_TASK_ARG parameters are passed, the list + * should be terminated with a NULL argv[] value. If no + * parameters are required, argv may be NULL. + * + * Return Value: + * Returns the non-zero process ID of the new task or ERROR if memory is + * insufficient or the task cannot be created. The errno will be set to + * indicate the nature of the error (always ENOMEM). + * + ****************************************************************************/ + +#ifndef CONFIG_CUSTOM_STACK +int task_create(FAR const char *name, int priority, + int stack_size, main_t entry, FAR char * const argv[]) +#else +int task_create(FAR const char *name, int priority, + main_t entry, FAR char * const argv[]) +#endif +{ +#ifndef CONFIG_CUSTOM_STACK + return thread_create(name, TCB_FLAG_TTYPE_TASK, priority, stack_size, entry, argv); +#else + return thread_create(name, TCB_FLAG_TTYPE_TASK, priority, entry, argv); +#endif +} + +/**************************************************************************** + * Name: kernel_thread + * + * Description: + * This function creates and activates a kernel thread task with kernel- + * mode privileges. It is identical to task_create() except that it + * configures the newly started thread to run in kernel model. + * + * Input Parameters: + * (same as task_create()) + * + * Return Value: + * (same as task_create()) + * + ****************************************************************************/ + +#ifndef CONFIG_CUSTOM_STACK +int kernel_thread(FAR const char *name, int priority, + int stack_size, main_t entry, FAR char * const argv[]) +#else +int kernel_thread(FAR const char *name, int priority, + main_t entry, FAR char * const argv[]) +#endif +{ +#ifndef CONFIG_CUSTOM_STACK + return thread_create(name, TCB_FLAG_TTYPE_KERNEL, priority, stack_size, entry, argv); +#else + return thread_create(name, TCB_FLAG_TTYPE_KERNEL, priority, entry, argv); +#endif +} + diff --git a/nuttx/sched/task/task_delete.c b/nuttx/sched/task/task_delete.c new file mode 100644 index 000000000..bdae89208 --- /dev/null +++ b/nuttx/sched/task/task_delete.c @@ -0,0 +1,133 @@ +/**************************************************************************** + * sched/task/task_delete.c + * + * Copyright (C) 2007-2009, 2011-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 "os_internal.h" +#include "task/task.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Type Declarations + ****************************************************************************/ + +/**************************************************************************** + * Global Variables + ****************************************************************************/ + +/**************************************************************************** + * Private Variables + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: task_delete + * + * Description: + * This function causes a specified task to cease to exist. Its stack and + * TCB will be deallocated. This function is the companion to task_create(). + * This is the version of the function exposed to the user; it is simply + * a wrapper around the internal, task_terminate function. + * + * The logic in this function only deletes non-running tasks. If the 'pid' + * parameter refers to to the currently runing task, then processing is + * redirected to exit(). This can only happen if a task calls task_delete() + * in order to delete itself. + * + * In fact, this function (and task_terminate) are the final functions + * called all task termination sequences. task_delete may be called + * from: + * + * - task_restart(), + * - pthread_cancel(), + * - and directly from user code. + * + * Other exit paths (exit(), _eixt(), and pthread_exit()) will go through + * task_terminate() + * + * Inputs: + * pid - The task ID of the task to delete. A pid of zero + * signifies the calling task. + * + * Return Value: + * OK on success; or ERROR on failure + * + * This function can fail if the provided pid does not correspond to a + * task (errno is not set) + * + ****************************************************************************/ + +int task_delete(pid_t pid) +{ + FAR struct tcb_s *rtcb; + + /* Check if the task to delete is the calling task */ + + rtcb = (FAR struct tcb_s*)g_readytorun.head; + if (pid == 0 || pid == rtcb->pid) + { + /* If it is, then what we really wanted to do was exit. Note that we + * don't bother to unlock the TCB since it will be going away. + */ + + exit(EXIT_SUCCESS); + } + + /* Then let task_terminate do the heavy lifting */ + + return task_terminate(pid, false); +} diff --git a/nuttx/sched/task/task_exit.c b/nuttx/sched/task/task_exit.c new file mode 100644 index 000000000..838eac460 --- /dev/null +++ b/nuttx/sched/task/task_exit.c @@ -0,0 +1,165 @@ +/**************************************************************************** + * sched/task/task_exit.c + * + * Copyright (C) 2008-2009, 2012-2014 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" + +#ifndef CONFIG_DISABLE_SIGNALS +# include "signal/signal.h" +#endif +#include "task/task.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Type Declarations + ****************************************************************************/ + +/**************************************************************************** + * Global Variables + ****************************************************************************/ + +/**************************************************************************** + * Private Variables + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: task_exit + * + * Description: + * This is a part of the logic used to implement _exit(). The full + * implementation of _exit() is architecture-dependent. The _exit() + * function also implements the bottom half of exit() and pthread_exit(). + * + * This function causes the currently running task (i.e., the task at the + * head of the ready-to-run list) to cease to exist. This function should + * never be called from normal user code, but only from the architecture- + * specific implementation of exit. + * + * Threads/tasks could also be terminated via pthread_cancel, task_delete(), + * and task_restart(). In the last two cases, the task will be terminated + * as though exit() were called. + * + * Inputs: + * None + * + * Return Value: + * OK on success; or ERROR on failure + * + * Assumeptions: + * Interrupts are disabled. + * + ****************************************************************************/ + +int task_exit(void) +{ + FAR struct tcb_s *dtcb = (FAR struct tcb_s*)g_readytorun.head; + FAR struct tcb_s *rtcb; + int ret; + + /* Remove the TCB of the current task from the ready-to-run list. A context + * switch will definitely be necessary -- that must be done by the + * architecture-specific logic. + * + * sched_removereadytorun will mark the task at the head of the ready-to-run + * with state == TSTATE_TASK_RUNNING + */ + + (void)sched_removereadytorun(dtcb); + rtcb = (FAR struct tcb_s*)g_readytorun.head; + + /* We are now in a bad state -- the head of the ready to run task list + * does not correspond to the thread that is running. Disabling pre- + * emption on this TCB and marking the new ready-to-run task as not + * running (see, for example, get_errno_ptr()). + * + * We disable pre-emption here by directly incrementing the lockcount + * (vs. calling sched_lock()). + */ + + rtcb->lockcount++; + rtcb->task_state = TSTATE_TASK_READYTORUN; + + /* Move the TCB to the specified blocked task list and delete it. Calling + * task_terminate with non-blocking true will suppress atexit() and on-exit() + * calls and will cause buffered I/O to fail to be flushed. The former + * is required _exit() behavior; the latter is optional _exit() behavior. + */ + + sched_addblocked(dtcb, TSTATE_TASK_INACTIVE); + ret = task_terminate(dtcb->pid, true); + rtcb->task_state = TSTATE_TASK_RUNNING; + + /* If there are any pending tasks, then add them to the ready-to-run + * task list now + */ + + if (g_pendingtasks.head) + { + (void)sched_mergepending(); + } + + /* We can't use sched_unlock() to decrement the lock count because the + * sched_mergepending() call above might have changed the task at the + * head of the ready-to-run list. Furthermore, we should not need to + * perform the unlock action anyway because we know that the pending + * task list is empty. So all we really need to do is to decrement + * the lockcount on rctb. + */ + + rtcb->lockcount--; + return ret; +} diff --git a/nuttx/sched/task/task_exithook.c b/nuttx/sched/task/task_exithook.c new file mode 100644 index 000000000..7d086c52e --- /dev/null +++ b/nuttx/sched/task/task_exithook.c @@ -0,0 +1,691 @@ +/**************************************************************************** + * sched/task/task_exithook.c + * + * Copyright (C) 2011-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 "os_internal.h" +#include "group/group.h" +#include "signal/signal.h" +#include "task/task.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Type Declarations + ****************************************************************************/ + +/**************************************************************************** + * Global Variables + ****************************************************************************/ + +/**************************************************************************** + * Private Variables + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: task_atexit + * + * Description: + * Call any registered atexit function(s) + * + ****************************************************************************/ + +#if defined(CONFIG_SCHED_ATEXIT) && !defined(CONFIG_SCHED_ONEXIT) +static inline void task_atexit(FAR struct tcb_s *tcb) +{ + FAR struct task_group_s *group = tcb->group; + + /* Make sure that we have not already left the group. Only the final + * exiting thread in the task group should trigger the atexit() + * callbacks. + */ + + if (group && group->tg_nmembers == 1) + { +#if defined(CONFIG_SCHED_ATEXIT_MAX) && CONFIG_SCHED_ATEXIT_MAX > 1 + int index; + + /* Call each atexit function in reverse order of registration atexit() + * functions are registered from lower to higher array indices; they + * must be called in the reverse order of registration when the task + * group exits, i.e., from higher to lower indices. + */ + + for (index = CONFIG_SCHED_ATEXIT_MAX-1; index >= 0; index--) + { + if (group->tg_atexitfunc[index]) + { + /* Call the atexit function */ + + (*group->tg_atexitfunc[index])(); + + /* Nullify the atexit function to prevent its reuse. */ + + group->tg_atexitfunc[index] = NULL; + } + } +#else + if (group->tg_atexitfunc) + { + /* Call the atexit function */ + + (*group->tg_atexitfunc)(); + + /* Nullify the atexit function to prevent its reuse. */ + + group->tg_atexitfunc = NULL; + } +#endif + } +} +#else +# define task_atexit(tcb) +#endif + +/**************************************************************************** + * Name: task_onexit + * + * Description: + * Call any registered on_exit function(s) + * + ****************************************************************************/ + +#ifdef CONFIG_SCHED_ONEXIT +static inline void task_onexit(FAR struct tcb_s *tcb, int status) +{ + FAR struct task_group_s *group = tcb->group; + + /* Make sure that we have not already left the group. Only the final + * exiting thread in the task group should trigger the atexit() + * callbacks. + */ + + if (group && group->tg_nmembers == 1) + { +#if defined(CONFIG_SCHED_ONEXIT_MAX) && CONFIG_SCHED_ONEXIT_MAX > 1 + int index; + + /* Call each on_exit function in reverse order of registration. + * on_exit() functions are registered from lower to higher array + * indices; they must be called in the reverse order of registration + * when the task group exits, i.e., from higher to lower indices. + */ + + for (index = CONFIG_SCHED_ONEXIT_MAX-1; index >= 0; index--) + { + if (group->tg_onexitfunc[index]) + { + /* Call the on_exit function */ + + (*group->tg_onexitfunc[index])(status, group->tg_onexitarg[index]); + + /* Nullify the on_exit function to prevent its reuse. */ + + group->tg_onexitfunc[index] = NULL; + } + } +#else + if (group->tg_onexitfunc) + { + /* Call the on_exit function */ + + (*group->tg_onexitfunc)(status, group->tg_onexitarg); + + /* Nullify the on_exit function to prevent its reuse. */ + + group->tg_onexitfunc = NULL; + } +#endif + } +} +#else +# define task_onexit(tcb,status) +#endif + +/**************************************************************************** + * Name: task_exitstatus + * + * Description: + * Report exit status when main task of a task group exits + * + ****************************************************************************/ + +#ifdef CONFIG_SCHED_CHILD_STATUS +static inline void task_exitstatus(FAR struct task_group_s *group, int status) +{ + FAR struct child_status_s *child; + + /* Check if the parent task group has suppressed retention of + * child exit status information. + */ + + if ((group->tg_flags & GROUP_FLAG_NOCLDWAIT) == 0) + { + /* No.. Find the exit status entry for this task in the parent TCB */ + + child = group_findchild(group, getpid()); + DEBUGASSERT(child); + if (child) + { +#ifndef HAVE_GROUP_MEMBERS + /* No group members? Save the exit status */ + + child->ch_status = status; +#endif + /* Save the exit status.. For the case of HAVE_GROUP_MEMBERS, + * the child status will be as exited until the last member + * of the task group exits. + */ + + child->ch_status = status; + } + } +} +#else + +# define task_exitstatus(group,status) + +#endif /* CONFIG_SCHED_CHILD_STATUS */ + +/**************************************************************************** + * Name: task_groupexit + * + * Description: + * Mark that the final thread of a child task group as exited. + * + ****************************************************************************/ + +#ifdef CONFIG_SCHED_CHILD_STATUS +static inline void task_groupexit(FAR struct task_group_s *group) +{ + FAR struct child_status_s *child; + + /* Check if the parent task group has suppressed retention of child exit + * status information. + */ + + if ((group->tg_flags & GROUP_FLAG_NOCLDWAIT) == 0) + { + /* No.. Find the exit status entry for this task in the parent TCB */ + + child = group_findchild(group, getpid()); + DEBUGASSERT(child); + if (child) + { + /* Mark that all members of the child task group has exited */ + + child->ch_flags |= CHILD_FLAG_EXITED; + } + } +} + +#else + +# define task_groupexit(group) + +#endif /* CONFIG_SCHED_CHILD_STATUS */ + +/**************************************************************************** + * Name: task_sigchild + * + * Description: + * Send the SIGCHILD signal to the parent thread + * + ****************************************************************************/ + +#ifdef CONFIG_SCHED_HAVE_PARENT +#ifdef HAVE_GROUP_MEMBERS +static inline void task_sigchild(gid_t pgid, FAR struct tcb_s *ctcb, int status) +{ + FAR struct task_group_s *chgrp = ctcb->group; + FAR struct task_group_s *pgrp; + siginfo_t info; + + DEBUGASSERT(chgrp); + + /* Get the parent task group. It is possible that all of the members of + * the parent task group have exited. This would not be an error. In + * this case, the child task group has been orphaned. + */ + + pgrp = group_findbygid(pgid); + if (!pgrp) + { + /* Set the task group ID to an invalid group ID. The dead parent + * task group ID could get reused some time in the future. + */ + + chgrp->tg_pgid = INVALID_GROUP_ID; + return; + } + + /* Save the exit status now if this is the main thread of the task group + * that is exiting. Only the exiting main task of a task group carries + * interpretable exit Check if this is the main task that is exiting. + */ + +#ifndef CONFIG_DISABLE_PTHREAD + if ((ctcb->flags & TCB_FLAG_TTYPE_MASK) != TCB_FLAG_TTYPE_PTHREAD) +#endif + { + task_exitstatus(pgrp, status); + } + + /* But only the final exiting thread in a task group, whatever it is, + * should generate SIGCHLD. + */ + + if (chgrp->tg_nmembers == 1) + { + /* Mark that all of the threads in the task group have exited */ + + task_groupexit(pgrp); + + /* Create the siginfo structure. We don't actually know the cause. + * That is a bug. Let's just say that the child task just exited + * for now. + */ + + info.si_signo = SIGCHLD; + info.si_code = CLD_EXITED; + info.si_value.sival_ptr = NULL; +#ifndef CONFIG_DISABLE_PTHREAD + info.si_pid = chgrp->tg_task; +#else + info.si_pid = ctcb->pid; +#endif + info.si_status = status; + + /* Send the signal to one thread in the group */ + + (void)group_signal(pgrp, &info); + } +} + +#else /* HAVE_GROUP_MEMBERS */ + +static inline void task_sigchild(FAR struct tcb_s *ptcb, + FAR struct tcb_s *ctcb, int status) +{ + siginfo_t info; + + /* If task groups are not supported then we will report SIGCHLD when the + * task exits. Unfortunately, there could still be threads in the group + * that are still running. + */ + +#ifndef CONFIG_DISABLE_PTHREAD + if ((ctcb->flags & TCB_FLAG_TTYPE_MASK) != TCB_FLAG_TTYPE_PTHREAD) +#endif + { +#ifdef CONFIG_SCHED_CHILD_STATUS + /* Save the exit status now of the main thread */ + + task_exitstatus(ptcb->group, status); + +#else /* CONFIG_SCHED_CHILD_STATUS */ + + /* Decrement the number of children from this parent */ + + DEBUGASSERT(ptcb->nchildren > 0); + ptcb->nchildren--; + +#endif /* CONFIG_SCHED_CHILD_STATUS */ + + /* Create the siginfo structure. We don't actually know the cause. + * That is a bug. Let's just say that the child task just exited + * for now. + */ + + info.si_signo = SIGCHLD; + info.si_code = CLD_EXITED; + info.si_value.sival_ptr = NULL; +#ifndef CONFIG_DISABLE_PTHREAD + info.si_pid = ctcb->group->tg_task; +#else + info.si_pid = ctcb->pid; +#endif + info.si_status = status; + + /* Send the signal. We need to use this internal interface so that we + * can provide the correct si_code value with the signal. + */ + + (void)sig_tcbdispatch(ptcb, &info); + } +} + +#endif /* HAVE_GROUP_MEMBERS */ +#else /* CONFIG_SCHED_HAVE_PARENT */ + +# define task_sigchild(x,ctcb,status) + +#endif /* CONFIG_SCHED_HAVE_PARENT */ + +/**************************************************************************** + * Name: task_signalparent + * + * Description: + * Send the SIGCHILD signal to the parent task group + * + ****************************************************************************/ + +#ifdef CONFIG_SCHED_HAVE_PARENT +static inline void task_signalparent(FAR struct tcb_s *ctcb, int status) +{ +#ifdef HAVE_GROUP_MEMBERS + DEBUGASSERT(ctcb && ctcb->group); + + /* Keep things stationary throughout the following */ + + sched_lock(); + + /* Send SIGCHLD to all members of the parent's task group */ + + task_sigchild(ctcb->group->tg_pgid, ctcb, status); + sched_unlock(); +#else + FAR struct tcb_s *ptcb; + + /* Keep things stationary throughout the following */ + + sched_lock(); + + /* Get the TCB of the receiving, parent task. We do this early to + * handle multiple calls to task_signalparent. ctcb->ppid is set to an + * invalid value below and the following call will fail if we are + * called again. + */ + + ptcb = sched_gettcb(ctcb->ppid); + if (!ptcb) + { + /* The parent no longer exists... bail */ + + sched_unlock(); + return; + } + + /* Send SIGCHLD to all members of the parent's task group */ + + task_sigchild(ptcb, ctcb, status); + + /* Forget who our parent was */ + + ctcb->ppid = INVALID_PROCESS_ID; + sched_unlock(); +#endif +} +#else +# define task_signalparent(ctcb,status) +#endif + +/**************************************************************************** + * Name: task_exitwakeup + * + * Description: + * Wakeup any tasks waiting for this task to exit + * + ****************************************************************************/ + +#if defined(CONFIG_SCHED_WAITPID) && !defined(CONFIG_SCHED_HAVE_PARENT) +static inline void task_exitwakeup(FAR struct tcb_s *tcb, int status) +{ + FAR struct task_group_s *group = tcb->group; + + /* Have we already left the group? */ + + if (group) + { + /* Only tasks (and kernel threads) return valid status. Record the + * exit status when the task exists. The group, however, may still + * be executing. + */ + +#ifndef CONFIG_DISABLE_PTHREAD + if ((tcb->flags & TCB_FLAG_TTYPE_MASK) != TCB_FLAG_TTYPE_PTHREAD) +#endif + { + /* Report the exit status. We do not nullify tg_statloc here + * because we want to prevent other tasks from registering for + * the return status. There is only one task per task group, + * there for, this logic should execute exactly once in the + * lifetime of the task group. + * + * "If more than one thread is suspended in waitpid() awaiting + * termination of the same process, exactly one thread will + * return the process status at the time of the target process + * termination." + * + * Hmmm.. what do we return to the others? + */ + + if (group->tg_statloc) + { + *group->tg_statloc = status << 8; + } + } + + /* Is this the last thread in the group? */ + + if (group->tg_nmembers == 1) + { + /* Yes.. Wakeup any tasks waiting for this task to exit */ + + group->tg_statloc = NULL; + while (group->tg_exitsem.semcount < 0) + { + /* Wake up the thread */ + + sem_post(&group->tg_exitsem); + } + } + } +} +#else +# define task_exitwakeup(tcb, status) +#endif + +/**************************************************************************** + * Name: task_flushstreams + * + * Description: + * Flush all streams when the final thread of a group exits. + * + ****************************************************************************/ + +#if CONFIG_NFILE_STREAMS > 0 +static inline void task_flushstreams(FAR struct tcb_s *tcb) +{ + FAR struct task_group_s *group = tcb->group; + + /* Have we already left the group? Are we the last thread in the group? */ + + if (group && group->tg_nmembers == 1) + { +#if defined(CONFIG_NUTTX_KERNEL) && defined(CONFIG_MM_KERNEL_HEAP) + (void)lib_flushall(tcb->group->tg_streamlist); +#else + (void)lib_flushall(&tcb->group->tg_streamlist); +#endif + } +} +#else +# define task_flushstreams(tcb) +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: task_exithook + * + * Description: + * This function implements some of the internal logic of exit() and + * task_delete(). This function performs some clean-up and other actions + * required when a task exits: + * + * - All open streams are flushed and closed. + * - All functions registered with atexit() and on_exit() are called, in + * the reverse order of their registration. + * + * When called from exit(), the tcb still resides at the head of the ready- + * to-run list. The following logic is safe because we will not be + * returning from the exit() call. + * + * When called from task_terminate() we are operating on a different thread; + * on the thread that called task_delete(). In this case, task_delete + * will have already removed the tcb from the ready-to-run list to prevent + * any further action on this task. + * + * nonblocking will be set true only when we are called from task_terminate() + * via _exit(). In that case, we must be careful to do nothing that can + * cause the cause the thread to block. + * + ****************************************************************************/ + +void task_exithook(FAR struct tcb_s *tcb, int status, bool nonblocking) +{ + /* Under certain conditions, task_exithook() can be called multiple times. + * A bit in the TCB was set the first time this function was called. If + * that bit is set, then just exit doing nothing more.. + */ + + if ((tcb->flags & TCB_FLAG_EXIT_PROCESSING) != 0) + { + return; + } + + /* If exit function(s) were registered, call them now before we do any un- + * initialization. + * + * NOTES: + * + * 1. In the case of task_delete(), the exit function will *not* be called + * on the thread execution of the task being deleted! That is probably + * a bug. + * 2. We cannot call the exit functions if nonblocking is requested: These + * functions might block. + * 3. This function will only be called with with non-blocking == true + * only when called through _exit(). _exit() behaviors requires that + * the exit functions *not* be called. + */ + +#if defined(CONFIG_SCHED_ATEXIT) || defined(CONFIG_SCHED_ONEXIT) + if (!nonblocking) + { + task_atexit(tcb); + + /* Call any registered on_exit function(s) */ + + task_onexit(tcb, status); + } +#endif + + /* If the task was terminated by another task, it may be in an unknown + * state. Make some feeble effort to recover the state. + */ + + task_recover(tcb); + + /* Send the SIGCHILD signal to the parent task group */ + + task_signalparent(tcb, status); + + /* Wakeup any tasks waiting for this task to exit */ + + task_exitwakeup(tcb, status); + + /* If this is the last thread in the group, then flush all streams (File + * descriptors will be closed when the TCB is deallocated). + * + * NOTES: + * 1. We cannot flush the buffered I/O if nonblocking is requested. + * that might cause this logic to block. + * 2. This function will only be called with with non-blocking == true + * only when called through _exit(). _exit() behavior does not + * require that the streams be flushed + */ + + if (!nonblocking) + { + task_flushstreams(tcb); + } + + /* Leave the task group. Perhaps discarding any un-reaped child + * status (no zombies here!) + */ + +#ifdef HAVE_TASK_GROUP + group_leave(tcb); +#endif + + /* Deallocate anything left in the TCB's queues */ + +#ifndef CONFIG_DISABLE_SIGNALS + sig_cleanup(tcb); /* Deallocate Signal lists */ +#endif + + /* This function can be re-entered in certain cases. Set a flag + * bit in the TCB to not that we have already completed this exit + * processing. + */ + + tcb->flags |= TCB_FLAG_EXIT_PROCESSING; +} diff --git a/nuttx/sched/task/task_getgroup.c b/nuttx/sched/task/task_getgroup.c new file mode 100644 index 000000000..abb3e23c5 --- /dev/null +++ b/nuttx/sched/task/task_getgroup.c @@ -0,0 +1,106 @@ +/***************************************************************************** + * sched/task/task_getgroup.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" +#include "group/group.h" +#include "task/task.h" + +#ifdef HAVE_TASK_GROUP + +/***************************************************************************** + * Pre-processor Definitions + *****************************************************************************/ + +/***************************************************************************** + * Private Types + *****************************************************************************/ + +/***************************************************************************** + * Private Data + *****************************************************************************/ + +/***************************************************************************** + * Public Data + *****************************************************************************/ + +/***************************************************************************** + * Private Functions + *****************************************************************************/ + +/***************************************************************************** + * Public Functions + *****************************************************************************/ + +/***************************************************************************** + * Name: task_getgroup + * + * Description: + * Given a task ID, return the group structure of this task. + * + * Parameters: + * pid - The task ID to use in the lookup. + * + * Return Value: + * On success, a pointer to the group task structure is returned. This + * function can fail only if there is no group that corresponds to the + * groupd ID. + * + * Assumptions: + * Called during when signally tasks in a safe context. No special + * precautions should be required here. However, extra care is taken when + * accessing the global g_grouphead list. + * + *****************************************************************************/ + +FAR struct task_group_s *task_getgroup(pid_t pid) +{ + FAR struct tcb_s *tcb = sched_gettcb(pid); + if (tcb) + { + return tcb->group; + } + + return NULL; +} + +#endif /* HAVE_TASK_GROUP */ diff --git a/nuttx/sched/task/task_init.c b/nuttx/sched/task/task_init.c new file mode 100644 index 000000000..a0ff9e750 --- /dev/null +++ b/nuttx/sched/task/task_init.c @@ -0,0 +1,198 @@ +/**************************************************************************** + * sched/task/task_init.c + * + * Copyright (C) 2007, 2009, 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 "os_internal.h" +#include "group/group.h" +#include "task/task.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Type Declarations + ****************************************************************************/ + +/**************************************************************************** + * Global Variables + ****************************************************************************/ + +/**************************************************************************** + * Private Variables + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: task_init + * + * Description: + * This function initializes a Task Control Block (TCB) in preparation for + * starting a new thread. It performs a subset of the functionality of + * task_create() + * + * Unlike task_create(): + * 1. Allocate the TCB. The pre-allocated TCB is passed in the arguments. + * 2. Allocate the stack. The pre-allocated stack is passed in the arguments. + * 3. Activate the task. This must be done by calling task_activate(). + * + * Input Parameters: + * tcb - Address of the new task's TCB + * name - Name of the new task (not used) + * priority - Priority of the new task + * stack - Start of the pre-allocated stack + * stack_size - Size (in bytes) of the stack allocated + * entry - Application start point of the new task + * arg - A pointer to an array of input parameters. Up to + * CONFIG_MAX_TASK_ARG parameters may be provided. If fewer + * than CONFIG_MAX_TASK_ARG parameters are passed, the list + * should be terminated with a NULL argv[] value. If no + * parameters are required, argv may be NULL. + * + * Return Value: + * OK on success; ERROR on failure with errno set appropriately. (See + * task_schedsetup() for possible failure conditions). On failure, the + * caller is responsible for freeing the stack memory and for calling + * sched_releasetcb() to free the TCB (which could be in most any state). + * + ****************************************************************************/ + +#ifndef CONFIG_CUSTOM_STACK +int task_init(FAR struct tcb_s *tcb, const char *name, int priority, + FAR uint32_t *stack, uint32_t stack_size, + main_t entry, FAR char * const argv[]) +#else +int task_init(FAR struct tcb_s *tcb, const char *name, int priority, + main_t entry, FAR char * const argv[]) +#endif +{ + FAR struct task_tcb_s *ttcb = (FAR struct task_tcb_s *)tcb; + int errcode; + int ret; + + /* Only tasks and kernel threads can be initialized in this way */ + +#ifndef CONFIG_DISABLE_PTHREAD + DEBUGASSERT(tcb && + (tcb->flags & TCB_FLAG_TTYPE_MASK) != TCB_FLAG_TTYPE_PTHREAD); +#endif + + /* Create a new task group */ + +#ifdef HAVE_TASK_GROUP + ret = group_allocate(ttcb); + if (ret < 0) + { + errcode = -ret; + goto errout; + } +#endif + + /* Associate file descriptors with the new task */ + +#if CONFIG_NFILE_DESCRIPTORS > 0 || CONFIG_NSOCKET_DESCRIPTORS > 0 + ret = group_setuptaskfiles(ttcb); + if (ret < 0) + { + errcode = -ret; + goto errout_with_group; + } +#endif + + /* Configure the user provided stack region */ + +#ifndef CONFIG_CUSTOM_STACK + up_use_stack(tcb, stack, stack_size); +#endif + + /* Initialize the task control block */ + + ret = task_schedsetup(ttcb, priority, task_start, entry, + TCB_FLAG_TTYPE_TASK); + if (ret < OK) + { + errcode = -ret; + goto errout_with_group; + } + + /* Setup to pass parameters to the new task */ + + (void)task_argsetup(ttcb, name, argv); + + /* Now we have enough in place that we can join the group */ + +#ifdef HAVE_TASK_GROUP + ret = group_initialize(ttcb); + if (ret < 0) + { + errcode = -ret; + goto errout_with_group; + } +#endif + return OK; + +errout_with_group: +#ifdef HAVE_TASK_GROUP + group_leave(tcb); + +errout: +#endif + set_errno(errcode); + return ERROR; +} + diff --git a/nuttx/sched/task/task_posixspawn.c b/nuttx/sched/task/task_posixspawn.c new file mode 100644 index 000000000..9d4f8f9a3 --- /dev/null +++ b/nuttx/sched/task/task_posixspawn.c @@ -0,0 +1,462 @@ +/**************************************************************************** + * sched/task/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 "os_internal.h" +#include "group/group.h" +#include "task/spawn.h" +#include "task/task.h" + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: posix_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 posix_spawn_exec(FAR pid_t *pidp, FAR const char *path, + FAR const posix_spawnattr_t *attr, + FAR char * const argv[]) +{ + 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 char * const *)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) + { + (void)spawn_execattrs(pid, attr); + } + + /* Re-enable pre-emption and return */ + +errout: + sched_unlock(); + return ret; +} + +/**************************************************************************** + * Name: posix_spawn_proxy + * + * Description: + * Perform file_actions, then execute the task from the file system. + * + * Do we really need this proxy task? Isn't that wasteful? + * + * Q: Why not use a starthook so that there is callout from task_start() + * to perform these operations after the file is loaded from + * the file system? + * A: That existing task_starthook() implementation cannot be used in + * this context; any of task_starthook() will also conflict with + * binfmt's use of the start hook to call C++ static initializers. + * task_restart() would also be an issue. + * + * Input Parameters: + * Standard task start-up parameters + * + * Returned Value: + * Standard task return value. + * + ****************************************************************************/ + +static int posix_spawn_proxy(int argc, FAR char *argv[]) +{ + int ret; + + /* Perform file actions and/or set a custom signal mask. We get here only + * if the file_actions parameter to posix_spawn[p] was non-NULL and/or the + * option to change the signal mask was selected. + */ + +#ifndef CONFIG_DISABLE_SIGNALS + DEBUGASSERT(g_spawn_parms.file_actions || + (g_spawn_parms.attr && + (g_spawn_parms.attr->flags & POSIX_SPAWN_SETSIGMASK) != 0)); +#else + DEBUGASSERT(g_spawn_parms.file_actions); +#endif + + /* Set the attributes and perform the file actions as appropriate */ + + ret = spawn_proxyattrs(g_spawn_parms.attr, g_spawn_parms.file_actions); + if (ret == OK) + { + /* Start the task */ + + ret = posix_spawn_exec(g_spawn_parms.pid, g_spawn_parms.u.posix.path, + g_spawn_parms.attr, g_spawn_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, *g_spawn_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_spawn_parms.result = ret; +#ifndef CONFIG_SCHED_WAITPID + spawn_semgive(&g_spawn_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 posix_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_spawn_parmsem); + + /* Populate the parameter structure */ + + g_spawn_parms.result = ENOSYS; + g_spawn_parms.pid = pid; + g_spawn_parms.file_actions = file_actions ? *file_actions : NULL; + g_spawn_parms.attr = attr; + g_spawn_parms.argv = argv; + g_spawn_parms.u.posix.path = path; + + /* 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_spawn_parmsem); + return errcode; + } + + /* Disable pre-emption so that the proxy does not run until waitpid + * is called. This is probably unnecessary since the posix_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("posix_spawn_proxy", param.sched_priority, + CONFIG_POSIX_SPAWN_PROXY_STACKSIZE, + (main_t)posix_spawn_proxy, + (FAR char * const *)NULL); + if (proxy < 0) + { + ret = get_errno(); + sdbg("ERROR: Failed to start posix_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_spawn_execsem); +#endif + + /* Get the result and relinquish our access to the parameter structure */ + + ret = g_spawn_parms.result; + +errout_with_lock: +#ifdef CONFIG_SCHED_WAITPID + sched_unlock(); +#endif + spawn_semgive(&g_spawn_parmsem); + return ret; +} diff --git a/nuttx/sched/task/task_recover.c b/nuttx/sched/task/task_recover.c new file mode 100644 index 000000000..76ac236bd --- /dev/null +++ b/nuttx/sched/task/task_recover.c @@ -0,0 +1,124 @@ +/**************************************************************************** + * sched/task/task_recover.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 "os_internal.h" +#include "mqueue/mqueue.h" +#include "task/task.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Type Declarations + ****************************************************************************/ + +/**************************************************************************** + * Global Variables + ****************************************************************************/ + +/**************************************************************************** + * Private Variables + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: task_recover + * + * Description: + * This function is called when a task is deleted via task_deleted or + * via pthread_cancel. I checks if the task was waiting for a message + * queue event and adjusts counts appropriately. + * + * Inputs: + * tcb - The TCB of the terminated task or thread + * + * Return Value: + * None. + * + * Assumptions: + * This function is called from task deletion logic in a safe context. + * + ****************************************************************************/ + +void task_recover(FAR struct tcb_s *tcb) +{ + irqstate_t flags; + + /* The task is being deleted. If it is waiting for any timed event, then + * tcb->waitdog will be non-NULL. Cancel the watchdog now so that no + * events occur after the watchdog expires. Obviously there are lots of + * race conditions here so this will most certainly have to be revisited in + * the future. + */ + + flags = irqsave(); + if (tcb->waitdog) + { + (void)wd_cancel(tcb->waitdog); + (void)wd_delete(tcb->waitdog); + tcb->waitdog = NULL; + } + + irqrestore(flags); + + /* Handle cases where the thread was waiting for a message queue event */ + +#ifndef CONFIG_DISABLE_MQUEUE + mq_recover(tcb); +#endif +} diff --git a/nuttx/sched/task/task_reparent.c b/nuttx/sched/task/task_reparent.c new file mode 100644 index 000000000..81a449bad --- /dev/null +++ b/nuttx/sched/task/task_reparent.c @@ -0,0 +1,321 @@ +/***************************************************************************** + * sched/task/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" +#include "group/group.h" +#include "task/task.h" + +#ifdef CONFIG_SCHED_HAVE_PARENT + +/***************************************************************************** + * Private Functions + *****************************************************************************/ + +/***************************************************************************** + * Public Functions + *****************************************************************************/ + +/***************************************************************************** + * Name: task_reparent + * + * Description: + * Change the parent of a task. + * + * Parameters: + * ppid - PID of the new parent task (0 for grandparent, i.e. the parent + * of the current parent task) + * chpid - PID of the child to be reparented. + * + * Return Value: + * 0 (OK) on success; A negated errno value on failure. + * + *****************************************************************************/ + +#ifdef HAVE_GROUP_MEMBERS +int task_reparent(pid_t ppid, pid_t chpid) +{ +#ifdef CONFIG_SCHED_CHILD_STATUS + FAR struct child_status_s *child; +#endif + FAR struct task_group_s *chgrp; + FAR struct task_group_s *ogrp; + FAR struct task_group_s *pgrp; + struct tcb_s *tcb; + gid_t ogid; + gid_t pgid; + irqstate_t flags; + int ret; + + /* Disable interrupts so that nothing can change in the relationship of + * the three task: Child, current parent, and new parent. + */ + + flags = irqsave(); + + /* Get the child tasks task group */ + + tcb = sched_gettcb(chpid); + if (!tcb) + { + ret = -ECHILD; + goto errout_with_ints; + } + + DEBUGASSERT(tcb->group); + chgrp = tcb->group; + + /* Get the GID of the old parent task's task group (ogid) */ + + ogid = chgrp->tg_pgid; + + /* Get the old parent task's task group (ogrp) */ + + ogrp = group_findbygid(ogid); + if (!ogrp) + { + ret = -ESRCH; + goto errout_with_ints; + } + + /* If new parent task's PID (ppid) is zero, then new parent is the + * grandparent will be the new parent, i.e., the parent of the current + * parent task. + */ + + if (ppid == 0) + { + /* Get the grandparent task's task group (pgrp) */ + + pgid = ogrp->tg_pgid; + pgrp = group_findbygid(pgid); + } + else + { + /* Get the new parent task's task group (pgrp) */ + + tcb = sched_gettcb(ppid); + if (!tcb) + { + ret = -ESRCH; + goto errout_with_ints; + } + + pgrp = tcb->group; + pgid = pgrp->tg_gid; + } + + if (!pgrp) + { + ret = -ESRCH; + goto errout_with_ints; + } + + /* Then reparent the child. Notice that we don't actually change the + * parent of the task. Rather, we change the parent task group for + * all members of the child's task group. + */ + + chgrp->tg_pgid = pgid; + +#ifdef CONFIG_SCHED_CHILD_STATUS + /* Remove the child status entry from old parent task group */ + + child = group_removechild(ogrp, chpid); + if (child) + { + /* Has the new parent's task group supressed child exit status? */ + + if ((pgrp->tg_flags && GROUP_FLAG_NOCLDWAIT) == 0) + { + /* No.. Add the child status entry to the new parent's task group */ + + group_addchild(pgrp, child); + } + else + { + /* Yes.. Discard the child status entry */ + + group_freechild(child); + } + + /* Either case is a success */ + + ret = OK; + } + else + { + /* This would not be an error if the original parent's task group has + * suppressed child exit status. + */ + + ret = ((ogrp->tg_flags && GROUP_FLAG_NOCLDWAIT) == 0) ? -ENOENT : OK; + } + +#else /* CONFIG_SCHED_CHILD_STATUS */ + + DEBUGASSERT(otcb->nchildren > 0); + + otcb->nchildren--; /* The orignal parent now has one few children */ + ptcb->nchildren++; /* The new parent has one additional child */ + ret = OK; + +#endif /* CONFIG_SCHED_CHILD_STATUS */ + +errout_with_ints: + irqrestore(flags); + return ret; +} +#else +int task_reparent(pid_t ppid, pid_t chpid) +{ +#ifdef CONFIG_SCHED_CHILD_STATUS + FAR struct child_status_s *child; +#endif + struct tcb_s *ptcb; + struct tcb_s *chtcb; + struct tcb_s *otcb; + pid_t opid; + irqstate_t flags; + int ret; + + /* Disable interrupts so that nothing can change in the relationship of + * the three task: Child, current parent, and new parent. + */ + + flags = irqsave(); + + /* Get the child tasks TCB (chtcb) */ + + chtcb = sched_gettcb(chpid); + if (!chtcb) + { + ret = -ECHILD; + goto errout_with_ints; + } + + /* Get the PID of the child task's parent (opid) */ + + opid = chtcb->ppid; + + /* Get the TCB of the child task's parent (otcb) */ + + otcb = sched_gettcb(opid); + if (!otcb) + { + ret = -ESRCH; + goto errout_with_ints; + } + + /* If new parent task's PID (ppid) is zero, then new parent is the + * grandparent will be the new parent, i.e., the parent of the current + * parent task. + */ + + if (ppid == 0) + { + ppid = otcb->ppid; + } + + /* Get the new parent task's TCB (ptcb) */ + + ptcb = sched_gettcb(ppid); + if (!ptcb) + { + ret = -ESRCH; + goto errout_with_ints; + } + + /* Then reparent the child */ + + chtcb->ppid = ppid; /* The task specified by ppid is the new parent */ + +#ifdef CONFIG_SCHED_CHILD_STATUS + /* Remove the child status entry from old parent TCB */ + + child = group_removechild(otcb->group, chpid); + if (child) + { + /* Has the new parent's task group supressed child exit status? */ + + if ((ptcb->group->tg_flags && GROUP_FLAG_NOCLDWAIT) == 0) + { + /* No.. Add the child status entry to the new parent's task group */ + + group_addchild(ptcb->group, child); + } + else + { + /* Yes.. Discard the child status entry */ + + group_freechild(child); + } + + /* Either case is a success */ + + ret = OK; + } + else + { + /* This would not be an error if the original parent's task group has + * suppressed child exit status. + */ + + ret = ((otcb->group->tg_flags && GROUP_FLAG_NOCLDWAIT) == 0) ? -ENOENT : OK; + } + +#else /* CONFIG_SCHED_CHILD_STATUS */ + + DEBUGASSERT(otcb->nchildren > 0); + + otcb->nchildren--; /* The orignal parent now has one few children */ + ptcb->nchildren++; /* The new parent has one additional child */ + ret = OK; + +#endif /* CONFIG_SCHED_CHILD_STATUS */ + +errout_with_ints: + irqrestore(flags); + return ret; +} +#endif +#endif /* CONFIG_SCHED_HAVE_PARENT */ diff --git a/nuttx/sched/task/task_restart.c b/nuttx/sched/task/task_restart.c new file mode 100644 index 000000000..dd3a78547 --- /dev/null +++ b/nuttx/sched/task/task_restart.c @@ -0,0 +1,209 @@ +/**************************************************************************** + * sched/task/task_restart.c + * + * Copyright (C) 2007, 2009, 2012-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 "os_internal.h" +#include "group/group.h" +#include "signal/signal.h" +#include "task/task.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Type Declarations + ****************************************************************************/ + +/**************************************************************************** + * Global Variables + ****************************************************************************/ + +/**************************************************************************** + * Private Variables + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: task_restart + * + * Description: + * This function "restarts" a task. The task is first terminated and then + * reinitialized with same ID, priority, original entry point, stack size, + * and parameters it had when it was first started. + * + * Inputs: + * pid - The task ID of the task to delete. An ID of zero signifies the + * calling task. + * + * Return Value: + * OK on sucess; ERROR on failure. + * + * This function can fail if: + * (1) A pid of zero or the pid of the calling task is provided + * (functionality not implemented) + * (2) The pid is not associated with any task known to the system. + * + ****************************************************************************/ + +int task_restart(pid_t pid) +{ + FAR struct tcb_s *rtcb; + FAR struct task_tcb_s *tcb; + irqstate_t state; + int status; + + /* Make sure this task does not become ready-to-run while + * we are futzing with its TCB + */ + + sched_lock(); + + /* Check if the task to restart is the calling task */ + + rtcb = (FAR struct tcb_s *)g_readytorun.head; + if ((pid == 0) || (pid == rtcb->pid)) + { + /* Not implemented */ + + set_errno(ENOSYS); + return ERROR; + } + + /* We are restarting some other task than ourselves */ + + else + { + /* Find for the TCB associated with matching pid */ + + tcb = (FAR struct task_tcb_s *)sched_gettcb(pid); +#ifndef CONFIG_DISABLE_PTHREAD + if (!tcb || (tcb->cmn.flags & TCB_FLAG_TTYPE_MASK) == TCB_FLAG_TTYPE_PTHREAD) +#else + if (!tcb) +#endif + { + /* There is no TCB with this pid or, if there is, it is not a + * task. + */ + + set_errno(ESRCH); + return ERROR; + } + + /* Try to recover from any bad states */ + + task_recover((FAR struct tcb_s *)tcb); + + /* Kill any children of this thread */ + +#if HAVE_GROUP_MEMBERS + (void)group_killchildren(tcb); +#endif + + /* Remove the TCB from whatever list it is in. At this point, the + * TCB should no longer be accessible to the system + */ + + state = irqsave(); + dq_rem((FAR dq_entry_t*)tcb, + (dq_queue_t*)g_tasklisttable[tcb->cmn.task_state].list); + tcb->cmn.task_state = TSTATE_TASK_INVALID; + irqrestore(state); + + /* Deallocate anything left in the TCB's queues */ + + sig_cleanup((FAR struct tcb_s *)tcb); /* Deallocate Signal lists */ + + /* Reset the current task priority */ + + tcb->cmn.sched_priority = tcb->init_priority; + + /* Reset the base task priority and the number of pending reprioritizations */ + +#ifdef CONFIG_PRIORITY_INHERITANCE + tcb->cmn.base_priority = tcb->init_priority; +# if CONFIG_SEM_NNESTPRIO > 0 + tcb->cmn.npend_reprio = 0; +# endif +#endif + + /* Re-initialize the processor-specific portion of the TCB + * This will reset the entry point and the start-up parameters + */ + + up_initial_state((FAR struct tcb_s *)tcb); + + /* Add the task to the inactive task list */ + + dq_addfirst((FAR dq_entry_t*)tcb, (dq_queue_t*)&g_inactivetasks); + tcb->cmn.task_state = TSTATE_TASK_INACTIVE; + + /* Activate the task */ + + status = task_activate((FAR struct tcb_s *)tcb); + if (status != OK) + { + (void)task_delete(pid); + set_errno(-status); + return ERROR; + } + } + + sched_unlock(); + return OK; +} diff --git a/nuttx/sched/task/task_setup.c b/nuttx/sched/task/task_setup.c new file mode 100644 index 000000000..89b0ec1d2 --- /dev/null +++ b/nuttx/sched/task/task_setup.c @@ -0,0 +1,765 @@ +/**************************************************************************** + * sched/task/task_setup.c + * + * Copyright (C) 2007-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 "os_internal.h" +#include "pthread/pthread.h" +#include "group/group.h" +#include "task/task.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Type Declarations + ****************************************************************************/ + +/**************************************************************************** + * Global Variables + ****************************************************************************/ + +/**************************************************************************** + * Private Variables + ****************************************************************************/ + +/* This is the name for un-named tasks */ + +static const char g_noname[] = ""; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int task_assignpid(FAR struct tcb_s* tcb); + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: task_assignpid + * + * Description: + * This function assigns the next unique task ID to a task. + * + * Inputs: + * tcb - TCB of task + * + * Return: + * OK on success; ERROR on failure (errno is not set) + * + ****************************************************************************/ + +static int task_assignpid(FAR struct tcb_s *tcb) +{ + pid_t next_pid; + int hash_ndx; + int tries; + + /* Disable pre-emption. This should provide sufficient protection + * for the following operation. + */ + + (void)sched_lock(); + + /* We'll try every allowable pid */ + + for (tries = 0; tries < CONFIG_MAX_TASKS; tries++) + { + /* Get the next process ID candidate */ + + next_pid = ++g_lastpid; + + /* Verify that the next_pid is in the valid range */ + + if (next_pid <= 0) + { + g_lastpid = 1; + next_pid = 1; + } + + /* Get the hash_ndx associated with the next_pid */ + + hash_ndx = PIDHASH(next_pid); + + /* Check if there is a (potential) duplicate of this pid */ + + if (!g_pidhash[hash_ndx].tcb) + { + /* Assign this PID to the task */ + + g_pidhash[hash_ndx].tcb = tcb; + g_pidhash[hash_ndx].pid = next_pid; +#ifdef CONFIG_SCHED_CPULOAD + g_pidhash[hash_ndx].ticks = 0; +#endif + tcb->pid = next_pid; + + (void)sched_unlock(); + return OK; + } + } + + /* If we get here, then the g_pidhash[] table is completely full. + * We cannot allow another task to be started. + */ + + (void)sched_unlock(); + return ERROR; +} + +/**************************************************************************** + * Name: task_saveparent + * + * Description: + * Save the task ID of the parent task in the child task's TCB and allocate + * a child status structure to catch the child task's exit status. + * + * Parameters: + * tcb - The TCB of the new, child task. + * ttype - Type of the new thread: task, pthread, or kernel thread + * + * Returned Value: + * None + * + * Assumptions: + * The parent of the new task is the task at the head of the ready-to-run + * list. + * + ****************************************************************************/ + +#ifdef CONFIG_SCHED_HAVE_PARENT +static inline void task_saveparent(FAR struct tcb_s *tcb, uint8_t ttype) +{ + FAR struct tcb_s *rtcb = (FAR struct tcb_s*)g_readytorun.head; + +#if defined(HAVE_GROUP_MEMBERS) || defined(CONFIG_SCHED_CHILD_STATUS) + DEBUGASSERT(tcb && tcb->group && rtcb->group); +#else +#endif + +#ifdef HAVE_GROUP_MEMBERS + /* Save the ID of the parent tasks' task group in the child's task group. + * Do nothing for pthreads. The parent and the child are both members of + * the same task group. + */ + +#ifndef CONFIG_DISABLE_PTHREAD + if ((tcb->flags & TCB_FLAG_TTYPE_MASK) != TCB_FLAG_TTYPE_PTHREAD) +#endif + { + /* This is a new task in a new task group, we have to copy the ID from + * the parent's task group structure to child's task group. + */ + + tcb->group->tg_pgid = rtcb->group->tg_gid; + } + +#else + DEBUGASSERT(tcb); + + /* Save the parent task's ID in the child task's TCB. I am not sure if + * this makes sense for the case of pthreads or not, but I don't think it + * is harmful in any event. + */ + + tcb->ppid = rtcb->pid; +#endif + +#ifdef CONFIG_SCHED_CHILD_STATUS + /* Tasks can also suppress retention of their child status by applying + * the SA_NOCLDWAIT flag with sigaction(). + */ + + if ((rtcb->group->tg_flags && GROUP_FLAG_NOCLDWAIT) == 0) + { + FAR struct child_status_s *child; + + /* Make sure that there is not already a structure for this PID in the + * parent TCB. There should not be. + */ + + child = group_findchild(rtcb->group, tcb->pid); + DEBUGASSERT(!child); + if (!child) + { + /* Allocate a new status structure */ + + child = group_allocchild(); + } + + /* Did we successfully find/allocate the child status structure? */ + + DEBUGASSERT(child); + if (child) + { + /* Yes.. Initialize the structure */ + + child->ch_flags = ttype; + child->ch_pid = tcb->pid; + child->ch_status = 0; + + /* Add the entry into the TCB list of children */ + + group_addchild(rtcb->group, child); + } + } +#else + DEBUGASSERT(rtcb->nchildren < UINT16_MAX); + rtcb->nchildren++; +#endif +} +#else +# define task_saveparent(tcb,ttype) +#endif + +/**************************************************************************** + * Name: task_dupdspace + * + * Description: + * When a new task or thread is created from a PIC module, then that + * module (probably) intends the task or thread to execute in the same + * D-Space. This function will duplicate the D-Space for that purpose. + * + * Parameters: + * tcb - The TCB of the new task. + * + * Returned Value: + * None + * + * Assumptions: + * The parent of the new task is the task at the head of the ready-to-run + * list. + * + ****************************************************************************/ + +#ifdef CONFIG_PIC +static inline void task_dupdspace(FAR struct tcb_s *tcb) +{ + FAR struct tcb_s *rtcb = (FAR struct tcb_s*)g_readytorun.head; + if (rtcb->dspace != NULL) + { + /* Copy the D-Space structure reference and increment the reference + * count on the memory. The D-Space memory will persist until the + * last thread exits (see sched_releasetcb()). + */ + + tcb->dspace = rtcb->dspace; + tcb->dspace->crefs++; + } +} +#else +# define task_dupdspace(tcb) +#endif + +/**************************************************************************** + * Name: thread_schedsetup + * + * Description: + * This functions initializes the common portions of the Task Control Block + * (TCB) in preparation for starting a new thread. + * + * thread_schedsetup() is called from task_schedsetup() and + * pthread_schedsetup(). + * + * Input Parameters: + * tcb - Address of the new task's TCB + * priority - Priority of the new task + * start - Thread startup routine + * entry - Thread user entry point + * ttype - Type of the new thread: task, pthread, or kernel thread + * + * Return Value: + * OK on success; ERROR on failure. + * + * This function can only failure is it is unable to assign a new, unique + * task ID to the TCB (errno is not set). + * + ****************************************************************************/ + +static int thread_schedsetup(FAR struct tcb_s *tcb, int priority, + start_t start, CODE void *entry, uint8_t ttype) +{ + int ret; + + /* Assign a unique task ID to the task. */ + + ret = task_assignpid(tcb); + if (ret == OK) + { + /* Save task priority and entry point in the TCB */ + + tcb->sched_priority = (uint8_t)priority; +#ifdef CONFIG_PRIORITY_INHERITANCE + tcb->base_priority = (uint8_t)priority; +#endif + tcb->start = start; + tcb->entry.main = (main_t)entry; + + /* Save the thread type. This setting will be needed in + * up_initial_state() is called. + */ + + ttype &= TCB_FLAG_TTYPE_MASK; + tcb->flags &= ~TCB_FLAG_TTYPE_MASK; + tcb->flags |= ttype; + + /* Save the task ID of the parent task in the TCB and allocate + * a child status structure. + */ + + task_saveparent(tcb, ttype); + + /* exec(), pthread_create(), task_create(), and vfork() all + * inherit the signal mask of the parent thread. + */ + +#ifndef CONFIG_DISABLE_SIGNALS + (void)sigprocmask(SIG_SETMASK, NULL, &tcb->sigprocmask); +#endif + + /* Initialize the task state. It does not get a valid state + * until it is activated. + */ + + tcb->task_state = TSTATE_TASK_INVALID; + + /* Clone the parent tasks D-Space (if it was running PIC). This + * must be done before calling up_initial_state() so that the + * state setup will take the PIC address base into account. + */ + + task_dupdspace(tcb); + + /* Initialize the processor-specific portion of the TCB */ + + up_initial_state(tcb); + + /* Add the task to the inactive task list */ + + sched_lock(); + dq_addfirst((FAR dq_entry_t*)tcb, (dq_queue_t*)&g_inactivetasks); + tcb->task_state = TSTATE_TASK_INACTIVE; + sched_unlock(); + } + + return ret; +} + +/**************************************************************************** + * Name: task_namesetup + * + * Description: + * Assign the task name. + * + * Input Parameters: + * tcb - Address of the new task's TCB + * name - Name of the new task + * + * Return Value: + * None + * + ****************************************************************************/ + +#if CONFIG_TASK_NAME_SIZE > 0 +static void task_namesetup(FAR struct task_tcb_s *tcb, FAR const char *name) +{ + /* Give a name to the unnamed tasks */ + + if (!name) + { + name = (FAR char *)g_noname; + } + + /* Copy the name into the TCB */ + + strncpy(tcb->cmn.name, name, CONFIG_TASK_NAME_SIZE); +} +#else +# define task_namesetup(t,n) +#endif /* CONFIG_TASK_NAME_SIZE */ + +/**************************************************************************** + * Name: task_tcbargsetup + * + * Description: + * This functions is called only from task_argsetup() in the "normal" + * case, where the argv[] array is a structure in the TCB. This function + * will clone all of the arguments using strdup. + * + * Input Parameters: + * tcb - Address of the new task's TCB + * argv - A pointer to an array of input parameters. + * Up to CONFIG_MAX_TASK_ARG parameters may be + * provided. If fewer than CONFIG_MAX_TASK_ARG + * parameters are passed, the list should be + * terminated with a NULL argv[] value. + * If no parameters are required, argv may be NULL. + * + * Return Value: + * OK. This function always succeeds. + * + ****************************************************************************/ + +#if defined(CONFIG_CUSTOM_STACK) || !defined(CONFIG_NUTTX_KERNEL) +static int task_tcbargsetup(FAR struct task_tcb_s *tcb, + FAR char * const argv[]) +{ + int i; + + /* Save the name as the first argument */ + +#if CONFIG_TASK_NAME_SIZE > 0 + tcb->argv[0] = tcb->cmn.name; +#else + tcb->argv[0] = (FAR char *)g_noname; +#endif /* CONFIG_TASK_NAME_SIZE */ + + /* For tasks, the life of the argument must be as long as the life of the + * task and the arguments must be strings. So for tasks, we have to dup + * the strings. + * + * The first NULL argument terminates the list of arguments. The argv + * pointer may be NULL if no parameters are passed. + */ + + i = 1; + if (argv) + { + for (; i < CONFIG_MAX_TASK_ARGS+1 && argv[i-1]; i++) + { + tcb->argv[i] = strdup(argv[i-1]); + } + } + + /* Nullify any unused argument storage */ + + for (; i < CONFIG_MAX_TASK_ARGS+1; i++) + { + tcb->argv[i] = NULL; + } + + return OK; +} +#endif /* CONFIG_CUSTOM_STACK || !CONFIG_NUTTX_KERNEL */ + +/**************************************************************************** + * Name: task_stackargsetup + * + * Description: + * This functions is called only from task_argsetup() for the case of the + * kernel build where the argv[] array and all strings are copied to the + * task's stack. This is done because the TCB (and kernel allocated + * strings) are only accessible in kernel-mode. Data on the stack, on the + * other hand, is guaranteed to be accessible no matter what mode the + * task runs in. + * + * Input Parameters: + * tcb - Address of the new task's TCB + * argv - A pointer to an array of input parameters. + * Up to CONFIG_MAX_TASK_ARG parameters may be + * provided. If fewer than CONFIG_MAX_TASK_ARG + * parameters are passed, the list should be + * terminated with a NULL argv[] value. + * If no parameters are required, argv may be NULL. + * + * Return Value: + * zero on success; a negated errno on failure. + * + ****************************************************************************/ + +#if !defined(CONFIG_CUSTOM_STACK) && defined(CONFIG_NUTTX_KERNEL) +static int task_stackargsetup(FAR struct task_tcb_s *tcb, + FAR char * const argv[]) +{ + FAR char **stackargv; + FAR const char *name; + FAR char *str; + size_t strtablen; + size_t argvlen; + int nbytes; + int argc; + int i; + + /* Get the name string that we will use as the first argument */ + +#if CONFIG_TASK_NAME_SIZE > 0 + name = tcb->cmn.name; +#else + name = (FAR const char *)g_noname; +#endif /* CONFIG_TASK_NAME_SIZE */ + + /* Get the size of the task name (including the NUL terminator) */ + + strtablen = (strlen(name) + 1); + + /* Count the number of arguments and get the accumulated size of the + * argument strings (including the null terminators). The argument count + * does not include the task name in that will be in argv[0]. + */ + + argc = 0; + if (argv) + { + for (; argc <= CONFIG_MAX_TASK_ARGS; argc++) + { + /* A NULL argument terminates the list */ + + if (!argv[argc]) + { + break; + } + + /* Add the size of this argument (with NUL terminator) */ + + strtablen += (strlen(argv[argc]) + 1); + } + } + + /* Allocate a stack frame to hold argv[] array and the strings. NOTE + * that argc + 2 entries are needed: The number of arguments plus the + * task name plus a NULL argv[] entry to terminate the list. + */ + + argvlen = (argc + 2)*sizeof(FAR char*); + stackargv = (FAR char **)up_stack_frame(&tcb->cmn, argvlen + strtablen); + + DEBUGASSERT(stackargv != NULL); + if (stackargv == NULL) + { + return -ENOMEM; + } + + /* Get the address of the string table that will lie immediately after + * the argv[] array and mark it as a null string. + */ + + str = (FAR char *)stackargv + argvlen; + + /* Copy the task name. Increment str to skip over the task name and its + * NUL terminator in the string buffer. + */ + + stackargv[0] = str; + nbytes = strlen(name) + 1; + strcpy(str, name); + str += nbytes; + + /* Copy each argument */ + + for (i = 0; i < argc; i++) + { + /* Save the pointer to the location in the string buffer and copy + * the argument into the buffer. Increment str to skip over the + * argument and its NUL terminator in the string buffer. + */ + + stackargv[i+1] = str; + nbytes = strlen(argv[i]) + 1; + strcpy(str, argv[i]); + str += nbytes; + } + + /* Put a terminator entry at the end of the argv[] array. Then save the + * argv[] arry pointer in the TCB where it will be recovered later by + * task_start(). + */ + + stackargv[argc + 1] = NULL; + tcb->argv = stackargv; + + return OK; +} +#endif /* !CONFIG_CUSTOM_STACK && CONFIG_NUTTX_KERNEL */ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: task_schedsetup + * + * Description: + * This functions initializes a Task Control Block (TCB) in preparation + * for starting a new task. + * + * task_schedsetup() is called from task_init() and task_start(). + * + * Input Parameters: + * tcb - Address of the new task's TCB + * priority - Priority of the new task + * start - Start-up function (probably task_start()) + * main - Application start point of the new task + * ttype - Type of the new thread: task or kernel thread + * + * Return Value: + * OK on success; ERROR on failure. + * + * This function can only failure is it is unable to assign a new, unique + * task ID to the TCB (errno is not set). + * + ****************************************************************************/ + +int task_schedsetup(FAR struct task_tcb_s *tcb, int priority, start_t start, + main_t main, uint8_t ttype) +{ + int ret; + + /* Perform common thread setup */ + + ret = thread_schedsetup((FAR struct tcb_s *)tcb, priority, start, + (CODE void *)main, ttype); + if (ret == OK) + { + /* Save task restart priority */ + + tcb->init_priority = (uint8_t)priority; + } + + return ret; +} + +/**************************************************************************** + * Name: pthread_schedsetup + * + * Description: + * This functions initializes a Task Control Block (TCB) in preparation + * for starting a new pthread. + * + * pthread_schedsetup() is called from pthread_create(), + * + * Input Parameters: + * tcb - Address of the new task's TCB + * priority - Priority of the new task + * start - Start-up function (probably pthread_start()) + * entry - Entry point of the new pthread + * ttype - Type of the new thread: task, pthread, or kernel thread + * + * Return Value: + * OK on success; ERROR on failure. + * + * This function can only failure is it is unable to assign a new, unique + * task ID to the TCB (errno is not set). + * + ****************************************************************************/ + +#ifndef CONFIG_DISABLE_PTHREAD +int pthread_schedsetup(FAR struct pthread_tcb_s *tcb, int priority, start_t start, + pthread_startroutine_t entry) +{ + /* Perform common thread setup */ + + return thread_schedsetup((FAR struct tcb_s *)tcb, priority, start, + (CODE void *)entry, TCB_FLAG_TTYPE_PTHREAD); +} +#endif + +/**************************************************************************** + * Name: task_argsetup + * + * Description: + * This functions sets up parameters in the Task Control Block (TCB) in + * preparation for starting a new thread. + * + * task_argsetup() is called only from task_init() and task_start() to + * create a new task. In the "normal" case, the argv[] array is a + * structure in the TCB, the arguments are cloned via strdup. + * + * In the kernel build case, the argv[] array and all strings are copied + * to the task's stack. This is done because the TCB (and kernel allocated + * strings) are only accessible in kernel-mode. Data on the stack, on the + * other hand, is guaranteed to be accessible no matter what mode the + * task runs in. + * + * Input Parameters: + * tcb - Address of the new task's TCB + * name - Name of the new task (not used) + * argv - A pointer to an array of input parameters. + * Up to CONFIG_MAX_TASK_ARG parameters may be + * provided. If fewer than CONFIG_MAX_TASK_ARG + * parameters are passed, the list should be + * terminated with a NULL argv[] value. + * If no parameters are required, argv may be NULL. + * + * Return Value: + * OK + * + ****************************************************************************/ + +int task_argsetup(FAR struct task_tcb_s *tcb, FAR const char *name, + FAR char * const argv[]) +{ + int ret; + + /* Setup the task name */ + + task_namesetup(tcb, name); + +#if !defined(CONFIG_CUSTOM_STACK) && defined(CONFIG_NUTTX_KERNEL) + /* In the kernel build case, the argv[] array and all strings are copied + * to the task's stack. This is done because the TCB (and kernel allocated + * strings) are only accessible in kernel-mode. Data on the stack, on the + * other hand, is guaranteed to be accessible no matter what mode the + * task runs in. + */ + + ret = task_stackargsetup(tcb, argv); + +#else + /* In the "normal" case, the argv[] array is a structure in the TCB, the + * arguments are cloned via strdup. + */ + + ret = task_tcbargsetup(tcb, argv); + +#endif /* !CONFIG_CUSTOM_STACK && CONFIG_NUTTX_KERNEL */ + + return ret; +} diff --git a/nuttx/sched/task/task_spawn.c b/nuttx/sched/task/task_spawn.c new file mode 100644 index 000000000..7678455fa --- /dev/null +++ b/nuttx/sched/task/task_spawn.c @@ -0,0 +1,454 @@ +/**************************************************************************** + * sched/task/task_spawn.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 "os_internal.h" +#include "group/group.h" +#include "task/spawn.h" +#include "task/task.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: task_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 task_spawn_exec(FAR pid_t *pidp, FAR const char *name, + main_t entry, FAR const posix_spawnattr_t *attr, + FAR char * const *argv) +{ + size_t stacksize; + int priority; + int pid; + int ret = OK; + + /* 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(); + + /* Use the default task priority and stack size if no attributes are provided */ + + if (attr) + { + priority = attr->priority; + stacksize = attr->stacksize; + } + else + { + struct sched_param param; + + /* Set the default priority to the same priority as this task */ + + ret = sched_getparam(0, ¶m); + if (ret < 0) + { + goto errout; + } + + priority = param.sched_priority; + stacksize = CONFIG_TASK_SPAWN_DEFAULT_STACKSIZE; + } + + /* Start the task */ + + pid = TASK_CREATE(name, priority, stacksize, entry, argv); + if (pid < 0) + { + ret = errno; + sdbg("ERROR: TASK_CREATE 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) + { + (void)spawn_execattrs(pid, attr); + } + + /* Re-enable pre-emption and return */ + +errout: + sched_unlock(); + return ret; +} + +/**************************************************************************** + * Name: task_spawn_proxy + * + * Description: + * Perform file_actions, then execute the task from the file system. + * + * Do we really need a proxy task in this case? Isn't that wasteful? + * + * Q: Why can we do what we need to do here and the just call the + * new task's entry point. + * A: This would require setting up the name, priority, and stacksize from + * the task_spawn, but it do-able. The only issue I can think of is + * that NuttX supports task_restart(), and you would never be able to + * restart a task from this point. + * + * Q: Why not use a starthook so that there is callout from task_start() + * to perform these operations? + * A: Good idea, except that existing task_starthook() implementation + * cannot be used here unless we get rid of task_create and, instead, + * use task_init() and task_activate(). start_taskhook() could then + * be called between task_init() and task)activate(). task_restart() + * would still be an issue. + * + * Input Parameters: + * Standard task start-up parameters + * + * Returned Value: + * Standard task return value. + * + ****************************************************************************/ + +static int task_spawn_proxy(int argc, FAR char *argv[]) +{ + int ret; + + /* Perform file actions and/or set a custom signal mask. We get here only + * if the file_actions parameter to task_spawn[p] was non-NULL and/or the + * option to change the signal mask was selected. + */ + +#ifndef CONFIG_DISABLE_SIGNALS + DEBUGASSERT(g_spawn_parms.file_actions || + (g_spawn_parms.attr && + (g_spawn_parms.attr->flags & POSIX_SPAWN_SETSIGMASK) != 0)); +#else + DEBUGASSERT(g_spawn_parms.file_actions); +#endif + + /* Set the attributes and perform the file actions as appropriate */ + + ret = spawn_proxyattrs(g_spawn_parms.attr, g_spawn_parms.file_actions); + if (ret == OK) + { + /* Start the task */ + + ret = task_spawn_exec(g_spawn_parms.pid, g_spawn_parms.u.task.name, + g_spawn_parms.u.task.entry, g_spawn_parms.attr, + g_spawn_parms.argv); + +#ifdef CONFIG_SCHED_HAVE_PARENT + if (ret == OK) + { + /* Change of the parent of the task we just spawned to our parent. + * What should we do in the event of a failure? + */ + + int tmp = task_reparent(0, *g_spawn_parms.pid); + if (tmp < 0) + { + 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_spawn_parms.result = ret; +#ifndef CONFIG_SCHED_WAITPID + spawn_semgive(&g_spawn_execsem); +#endif + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: task_spawn + * + * Description: + * The task_spawn() function will create a new, child task, where the + * entry point to the task is an address in memory. + * + * Input Parameters: + * + * pid - Upon successful completion, task_spawn() 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. + * + * name - The name to assign to the child task. + * + * entry - The child task's entry point (an address in memory) + * + * 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 + * task_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. + * + * And the non-standard: + * + * - TASK_SPAWN_SETSTACKSIZE: Set the stack size for the new task. + * + * 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. + * + * Returned Value: + * task_spawn() 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. + * + ****************************************************************************/ + +int task_spawn(FAR pid_t *pid, FAR const char *name, main_t entry, + FAR const posix_spawn_file_actions_t *file_actions, + FAR const posix_spawnattr_t *attr, + FAR char *const argv[], FAR char *const envp[]) +{ + struct sched_param param; + pid_t proxy; +#ifdef CONFIG_SCHED_WAITPID + int status; +#endif + int ret; + + svdbg("pid=%p name=%s entry=%p file_actions=%p attr=%p argv=%p\n", + pid, name, entry, file_actions, attr, argv); + + /* If there are no file actions to be performed and there is no change to + * the signal mask, then start the new child task directly from the parent task. + */ + +#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 task_spawn_exec(pid, name, entry, 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_spawn_parmsem); + + /* Populate the parameter structure */ + + g_spawn_parms.result = ENOSYS; + g_spawn_parms.pid = pid; + g_spawn_parms.file_actions = file_actions ? *file_actions : NULL; + g_spawn_parms.attr = attr; + g_spawn_parms.argv = argv; + g_spawn_parms.u.task.name = name; + g_spawn_parms.u.task.entry = entry; + + /* 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_spawn_parmsem); + return errcode; + } + + /* Disable pre-emption so that the proxy does not run until waitpid + * is called. This is probably unnecessary since the task_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("task_spawn_proxy", param.sched_priority, + CONFIG_POSIX_SPAWN_PROXY_STACKSIZE, + (main_t)task_spawn_proxy, + (FAR char * const*)NULL); + if (proxy < 0) + { + ret = get_errno(); + sdbg("ERROR: Failed to start task_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_spawn_execsem); +#endif + + /* Get the result and relinquish our access to the parameter structure */ + + ret = g_spawn_parms.result; + +errout_with_lock: +#ifdef CONFIG_SCHED_WAITPID + sched_unlock(); +#endif + spawn_semgive(&g_spawn_parmsem); + return ret; +} diff --git a/nuttx/sched/task/task_spawnparms.c b/nuttx/sched/task/task_spawnparms.c new file mode 100644 index 000000000..7a8cad6c4 --- /dev/null +++ b/nuttx/sched/task/task_spawnparms.c @@ -0,0 +1,341 @@ +/**************************************************************************** + * sched/task/task_spawnparms.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 "task/spawn.h" +#include "task/task.h" + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +sem_t g_spawn_parmsem = SEM_INITIALIZER(1); +#ifndef CONFIG_SCHED_WAITPID +sem_t g_spawn_execsem = SEM_INITIALIZER(0); +#endif +struct spawn_parms_s g_spawn_parms; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * 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; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: spawn_semtake and spawn_semgive + * + * Description: + * Give and take semaphores + * + * Input Parameters: + * + * sem - The semaphore to act on. + * + * Returned Value: + * None + * + ****************************************************************************/ + +void spawn_semtake(FAR sem_t *sem) +{ + int ret; + + do + { + ret = sem_wait(sem); + ASSERT(ret == 0 || errno == EINTR); + } + while (ret != 0); +} + +/**************************************************************************** + * Name: spawn_execattrs + * + * Description: + * Set attributes of the new child task after it has been spawned. + * + * Input Parameters: + * + * pid - The pid of the new task. + * attr - The attributes to use + * + * Returned Value: + * Errors are not reported by this function. This is because errors + * cannot occur, but ratther that the new task has already been started + * so there is no graceful way to handle errors detected in this context + * (unless we delete the new task and recover). + * + * Assumptions: + * That task has been started but has not yet executed because pre- + * emption is disabled. + * + ****************************************************************************/ + +int spawn_execattrs(pid_t pid, FAR const posix_spawnattr_t *attr) +{ + struct sched_param param; + + DEBUGASSERT(attr); + + /* 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 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); + } + + return OK; +} + +/**************************************************************************** + * Name: spawn_proxyattrs + * + * Description: + * Set attributes of the proxy task before it has started the new child + * task. + * + * Input Parameters: + * + * pid - The pid of the new task. + * attr - The attributes to use + * file_actions - The attributes to use + * + * Returned Value: + * 0 (OK) on successed; A negated errno value is returned on failure. + * + ****************************************************************************/ + +int spawn_proxyattrs(FAR const posix_spawnattr_t *attr, + FAR const posix_spawn_file_actions_t *file_actions) +{ + FAR struct spawn_general_file_action_s *entry; + int ret = OK; + + /* 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 (file_actions) +#endif + { + /* Yes.. Execute each file action */ + + for (entry = (FAR struct spawn_general_file_action_s *)file_actions; + entry && ret == OK; + entry = entry->flink) + { + switch (entry->action) + { + 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; + } + } + } + + return ret; +} diff --git a/nuttx/sched/task/task_start.c b/nuttx/sched/task/task_start.c new file mode 100644 index 000000000..653e2794a --- /dev/null +++ b/nuttx/sched/task/task_start.c @@ -0,0 +1,145 @@ +/**************************************************************************** + * sched/task/task_start.c + * + * Copyright (C) 2007-2010, 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 "os_internal.h" +#include "task/task.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Type Declarations + ****************************************************************************/ + +/**************************************************************************** + * Global Variables + ****************************************************************************/ + +/**************************************************************************** + * Private Variables + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: task_start + * + * Description: + * This function is the low level entry point into the main thread of + * execution of a task. It receives initial control when the task is + * started and calls main entry point of the newly started task. + * + * Inputs: + * None + * + * Return: + * None + * + ****************************************************************************/ + +void task_start(void) +{ + FAR struct task_tcb_s *tcb = (FAR struct task_tcb_s*)g_readytorun.head; + int exitcode; + int argc; + + DEBUGASSERT((tcb->cmn.flags & TCB_FLAG_TTYPE_MASK) != TCB_FLAG_TTYPE_PTHREAD); + + /* Execute the start hook if one has been registered */ + +#ifdef CONFIG_SCHED_STARTHOOK + if (tcb->starthook) + { + tcb->starthook(tcb->starthookarg); + } +#endif + + /* Count how many non-null arguments we are passing */ + + for (argc = 1; argc <= CONFIG_MAX_TASK_ARGS; argc++) + { + /* The first non-null argument terminates the list */ + + if (!tcb->argv[argc]) + { + break; + } + } + + /* Call the 'main' entry point passing argc and argv. In the kernel build + * this has to be handled differently if we are starting a user-space task; + * we have to switch to user-mode before calling the task. + */ + +#ifdef CONFIG_NUTTX_KERNEL + if ((tcb->cmn.flags & TCB_FLAG_TTYPE_MASK) != TCB_FLAG_TTYPE_KERNEL) + { + up_task_start(tcb->cmn.entry.main, argc, tcb->argv); + exitcode = EXIT_FAILURE; /* Should not get here */ + } + else +#endif + { + exitcode = tcb->cmn.entry.main(argc, tcb->argv); + } + + /* Call exit() if/when the task returns */ + + exit(exitcode); +} diff --git a/nuttx/sched/task/task_starthook.c b/nuttx/sched/task/task_starthook.c new file mode 100644 index 000000000..dcfb4fca9 --- /dev/null +++ b/nuttx/sched/task/task_starthook.c @@ -0,0 +1,113 @@ +/**************************************************************************** + * sched/task/task_starthook.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 "task/task.h" + +#ifdef CONFIG_SCHED_STARTHOOK + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Type Declarations + ****************************************************************************/ + +/**************************************************************************** + * Global Variables + ****************************************************************************/ + +/**************************************************************************** + * Private Variables + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: task_starthook + * + * Description: + * Configure a start hook... a function that will be called on the thread + * of the new task before the new task's main entry point is called. + * The start hook is useful, for example, for setting up automatic + * configuration of C++ constructors. + * + * Inputs: + * tcb - The new, unstarted task task that needs the start hook + * starthook - The pointer to the start hook function + * arg - The argument to pass to the start hook function. + * + * Return: + * None + * + ****************************************************************************/ + +void task_starthook(FAR struct task_tcb_s *tcb, starthook_t starthook, + FAR void *arg) +{ + /* Only tasks can have starthooks. The starthook will be called when the + * task is started (or restarted). + */ + +#ifndef CONFIG_DISABLE_PTHREAD + DEBUGASSERT(tcb && + (tcb->cmn.flags & TCB_FLAG_TTYPE_MASK) != TCB_FLAG_TTYPE_PTHREAD); +#endif + + /* Set up the start hook */ + + tcb->starthook = starthook; + tcb->starthookarg = arg; +} + +#endif /* CONFIG_SCHED_STARTHOOK */ diff --git a/nuttx/sched/task/task_terminate.c b/nuttx/sched/task/task_terminate.c new file mode 100644 index 000000000..4c41e51e4 --- /dev/null +++ b/nuttx/sched/task/task_terminate.c @@ -0,0 +1,189 @@ +/**************************************************************************** + * sched/task/task_terminate.c + * + * Copyright (C) 2007-2009, 2011-2014 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 "os_internal.h" +#ifndef CONFIG_DISABLE_SIGNALS +# include "signal/signal.h" +#endif +#include "task/task.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Type Declarations + ****************************************************************************/ + +/**************************************************************************** + * Global Variables + ****************************************************************************/ + +/**************************************************************************** + * Private Variables + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: task_terminate + * + * Description: + * This function causes a specified task to cease to exist. Its stack and + * TCB will be deallocated. This function is the internal implementation + * of the task_delete() function. It includes and additional parameter + * to determine if blocking is permitted or not. + * + * This function is the final function called all task termination + * sequences. task_terminate() is called only from task_delete() (with + * nonblocking == false) and from task_exit() (with nonblocking == true). + * + * The path through task_exit() supports the final stops of the exit(), + * _exit(), and pthread_exit + * + * - pthread_exit(). Calls _exit() + * - exit(). Calls _exit() + * - _exit(). Calls task_exit() making the currently running task + * non-running. task_exit then calls task_terminate() (with nonblocking + * == true) to terminate the non-running task. + * + * NOTE: that the state of non-blocking is irrelevant when called through + * exit() and pthread_exit(). In those cases task_exithook() has already + * been called with nonblocking == false; + * + * Inputs: + * pid - The task ID of the task to delete. A pid of zero + * signifies the calling task. + * nonblocking - True: The task is an unhealthy, partially torn down + * state and is not permitted to block. + * + * Return Value: + * OK on success; or ERROR on failure + * + * This function can fail if the provided pid does not correspond to a + * task (errno is not set) + * + ****************************************************************************/ + +int task_terminate(pid_t pid, bool nonblocking) +{ + FAR struct tcb_s *dtcb; + irqstate_t saved_state; + + /* Make sure the task does not become ready-to-run while we are futzing with + * its TCB by locking ourselves as the executing task. + */ + + sched_lock(); + + /* Find for the TCB associated with matching PID */ + + dtcb = sched_gettcb(pid); + if (!dtcb) + { + /* This PID does not correspond to any known task */ + + sched_unlock(); + return -ESRCH; + } + + /* Verify our internal sanity */ + + if (dtcb->task_state == TSTATE_TASK_RUNNING || + dtcb->task_state >= NUM_TASK_STATES) + { + sched_unlock(); + PANIC(); + } + + /* Perform common task termination logic (flushing streams, calling + * functions registered by at_exit/on_exit, etc.). We need to do + * this as early as possible so that higher level clean-up logic + * can run in a healthy tasking environment. + * + * In the case where the task exits via exit(), task_exithook() + * may be called twice. + * + * I suppose EXIT_SUCCESS is an appropriate return value??? + */ + + task_exithook(dtcb, EXIT_SUCCESS, nonblocking); + + /* Remove the task from the OS's tasks lists. */ + + saved_state = irqsave(); + dq_rem((FAR dq_entry_t*)dtcb, (dq_queue_t*)g_tasklisttable[dtcb->task_state].list); + dtcb->task_state = TSTATE_TASK_INVALID; + irqrestore(saved_state); + + /* At this point, the TCB should no longer be accessible to the system */ + + sched_unlock(); + + /* Since all tasks pass through this function as the final step in their + * exit sequence, this is an appropriate place to inform any instrumentation + * layer that the task no longer exists. + */ + + sched_note_stop(dtcb); + + /* Deallocate its TCB */ + + return sched_releasetcb(dtcb, dtcb->flags & TCB_FLAG_TTYPE_MASK); +} diff --git a/nuttx/sched/task/task_vfork.c b/nuttx/sched/task/task_vfork.c new file mode 100644 index 000000000..963633964 --- /dev/null +++ b/nuttx/sched/task/task_vfork.c @@ -0,0 +1,345 @@ +/**************************************************************************** + * sched/task/task_vfork + * + * 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 "os_internal.h" +#include "group/group.h" +#include "task/task.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ +/* vfork() requires architecture-specific support as well as waipid(). */ + +#if defined(CONFIG_ARCH_HAVE_VFORK) && defined(CONFIG_SCHED_WAITPID) + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: task_vforksetup + * + * Description: + * The vfork() function has the same effect as fork(), except that the + * behavior is undefined if the process created by vfork() either modifies + * any data other than a variable of type pid_t used to store the return + * value from vfork(), or returns from the function in which vfork() was + * called, or calls any other function before successfully calling _exit() + * or one of the exec family of functions. + * + * This functin provides one step in the overall vfork() sequence: It + * Allocates and initializes the child task's TCB. The overall sequence is: + * + * 1) User code calls vfork(). vfork() is provided in architecture-specific + * code. + * 2) vfork()and calls task_vforksetup(). + * 3) task_vforksetup() allocates and configures the child task's TCB. This + * consists of: + * - Allocation of the child task's TCB. + * - Initialization of file descriptors and streams + * - Configuration of environment variables + * - Setup the intput parameters for the task. + * - Initialization of the TCB (including call to up_initial_state() + * 4) up_vfork() provides any additional operating context. up_vfork must: + * - Allocate and initialize the stack + * - Initialize special values in any CPU registers that were not + * already configured by up_initial_state() + * 5) up_vfork() then calls task_vforkstart() + * 6) task_vforkstart() then executes the child thread. + * + * Input Paremeters: + * retaddr - The return address from vfork() where the child task + * will be started. + * + * Returned Value: + * Upon successful completion, task_vforksetup() returns a pointer to + * newly allocated and initalized child task's TCB. NULL is returned + * on any failure and the errno is set appropriately. + * + ****************************************************************************/ + +FAR struct task_tcb_s *task_vforksetup(start_t retaddr) +{ + struct tcb_s *parent = (FAR struct tcb_s *)g_readytorun.head; + struct task_tcb_s *child; + uint8_t ttype; + int priority; + int ret; + + DEBUGASSERT(retaddr); + + /* Get the type of the fork'ed task (kernel or user) */ + + if ((parent->flags & TCB_FLAG_TTYPE_MASK) == TCB_FLAG_TTYPE_KERNEL) + { + /* Fork'ed from a kernel thread */ + + ttype = TCB_FLAG_TTYPE_KERNEL; + } + else + { + /* Fork'ed from a user task or pthread */ + + ttype = TCB_FLAG_TTYPE_TASK; + } + + /* Allocate a TCB for the child task. */ + + child = (FAR struct task_tcb_s *)kzalloc(sizeof(struct task_tcb_s)); + if (!child) + { + sdbg("ERROR: Failed to allocate TCB\n"); + set_errno(ENOMEM); + return NULL; + } + + /* Allocate a new task group */ + +#ifdef HAVE_TASK_GROUP + ret = group_allocate(child); + if (ret < 0) + { + goto errout_with_tcb; + } +#endif + + /* Associate file descriptors with the new task */ + +#if CONFIG_NFILE_DESCRIPTORS > 0 || CONFIG_NSOCKET_DESCRIPTORS > 0 + ret = group_setuptaskfiles(child); + if (ret < OK) + { + goto errout_with_tcb; + } +#endif + + /* Get the priority of the parent task */ + +#ifdef CONFIG_PRIORITY_INHERITANCE + priority = parent->base_priority; /* "Normal," unboosted priority */ +#else + priority = parent->sched_priority; /* Current priority */ +#endif + + /* Initialize the task control block. This calls up_initial_state() */ + + svdbg("Child priority=%d start=%p\n", priority, retaddr); + ret = task_schedsetup(child, priority, retaddr, parent->entry.main, ttype); + if (ret < OK) + { + goto errout_with_tcb; + } + + svdbg("parent=%p, returning child=%p\n", parent, child); + return child; + +errout_with_tcb: + sched_releasetcb((FAR struct tcb_s *)child, ttype); + set_errno(-ret); + return NULL; +} + +/**************************************************************************** + * Name: task_vforkstart + * + * Description: + * The vfork() function has the same effect as fork(), except that the + * behavior is undefined if the process created by vfork() either modifies + * any data other than a variable of type pid_t used to store the return + * value from vfork(), or returns from the function in which vfork() was + * called, or calls any other function before successfully calling _exit() + * or one of the exec family of functions. + * + * This functin provides one step in the overall vfork() sequence: It + * starts execution of the previously initialized TCB. The overall + * sequence is: + * + * 1) User code calls vfork() + * 2) Architecture-specific code provides vfork()and calls task_vforksetup(). + * 3) task_vforksetup() allocates and configures the child task's TCB. This + * consists of: + * - Allocation of the child task's TCB. + * - Initialization of file descriptors and streams + * - Configuration of environment variables + * - Setup the intput parameters for the task. + * - Initialization of the TCB (including call to up_initial_state() + * 4) vfork() provides any additional operating context. vfork must: + * - Allocate and initialize the stack + * - Initialize special values in any CPU registers that were not + * already configured by up_initial_state() + * 5) vfork() then calls task_vforkstart() + * 6) task_vforkstart() then executes the child thread. + * + * Input Paremeters: + * retaddr - The return address from vfork() where the child task + * will be started. + * + * Returned Value: + * Upon successful completion, vfork() returns 0 to the child process and + * returns the process ID of the child process to the parent process. + * Otherwise, -1 is returned to the parent, no child process is created, + * and errno is set to indicate the error. + * + ****************************************************************************/ + +pid_t task_vforkstart(FAR struct task_tcb_s *child) +{ +#if CONFIG_TASK_NAME_SIZE > 0 + struct tcb_s *parent = (FAR struct tcb_s *)g_readytorun.head; +#endif + FAR const char *name; + pid_t pid; + int rc; + int ret; + + svdbg("Starting Child TCB=%p, parent=%p\n", child, g_readytorun.head); + DEBUGASSERT(child); + + /* Setup to pass parameters to the new task */ + +#if CONFIG_TASK_NAME_SIZE > 0 + name = parent->name; +#else + name = NULL; +#endif + + (void)task_argsetup(child, name, (FAR char * const *)NULL); + + /* Now we have enough in place that we can join the group */ + +#ifdef HAVE_TASK_GROUP + ret = group_initialize(child); + if (ret < 0) + { + task_vforkabort(child, -ret); + return ERROR; + } +#endif + + /* Get the assigned pid before we start the task */ + + pid = (int)child->cmn.pid; + + /* Activate the task */ + + ret = task_activate((FAR struct tcb_s *)child); + if (ret < OK) + { + task_vforkabort(child, -ret); + return ERROR; + } + + /* Since the child task has the same priority as the parent task, it is + * now ready to run, but has not yet ran. It is a requirement that + * the parent enivornment be stable while vfork runs; the child thread + * is still dependent on things in the parent thread... like the pointers + * into parent thread's stack which will still appear in the child's + * registers and environment. + * + * We do not have SIG_CHILD, so we have to do some silly things here. + * The simplest way to make sure that the child thread runs to completion + * is simply to yield here. Since the child can only do exit() or + * execv/l(), that should be all that is needed. + * + * Hmmm.. this is probably not sufficient. What if we are running + * SCHED_RR? What if the child thread is suspeneded and rescheduled + * after the parent thread again? + */ + + /* We can also exploit a bug in the execv() implementation: The PID + * of the task exec'ed by the child will not be the same as the PID of + * the child task. Therefore, waitpid() on the child task's PID will + * accomplish what we need to do. + */ + + rc = 0; + +#ifdef CONFIG_DEBUG + ret = waitpid(pid, &rc, 0); + if (ret < 0) + { + sdbg("ERROR: waitpid failed: %d\n", errno); + } +#else + (void)waitpid(pid, &rc, 0); +#endif + + return pid; +} + +/**************************************************************************** + * Name: task_vforkabort + * + * Description: + * Recover from any errors after task_vforksetup() was called. + * + * Returned Value: + * None + * + ****************************************************************************/ + +void task_vforkabort(FAR struct task_tcb_s *child, int errcode) +{ + /* The TCB was added to the active task list by task_schedsetup() */ + + dq_rem((FAR dq_entry_t*)child, (dq_queue_t*)&g_inactivetasks); + + /* Release the TCB */ + + sched_releasetcb((FAR struct tcb_s *)child, + child->cmn.flags & TCB_FLAG_TTYPE_MASK); + set_errno(errcode); +} + +#endif /* CONFIG_ARCH_HAVE_VFORK && CONFIG_SCHED_WAITPID */ diff --git a/nuttx/sched/task_activate.c b/nuttx/sched/task_activate.c deleted file mode 100644 index c4449464c..000000000 --- a/nuttx/sched/task_activate.c +++ /dev/null @@ -1,117 +0,0 @@ -/**************************************************************************** - * sched/task_activate.c - * - * Copyright (C) 2007-2009 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 - -/**************************************************************************** - * Definitions - ****************************************************************************/ - -/**************************************************************************** - * Private Type Declarations - ****************************************************************************/ - -/**************************************************************************** - * Global Variables - ****************************************************************************/ - -/**************************************************************************** - * Private Variables - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: task_activate - * - * Description: - * This function activates tasks initialized by task_schedsetup(). Without - * activation, a task is ineligible for execution by the scheduler. - * - * Input Parameters: - * tcb - The TCB for the task for the task (same as the task_init argument). - * - * Return Value: - * Always returns OK - * - ****************************************************************************/ - -int task_activate(FAR struct tcb_s *tcb) -{ - irqstate_t flags = irqsave(); - -#ifdef CONFIG_SCHED_INSTRUMENTATION - - /* Check if this is really a re-start */ - - if (tcb->task_state != TSTATE_TASK_INACTIVE) - { - /* Inform the instrumentation layer that the task - * has stopped - */ - - sched_note_stop(tcb); - } - - /* Inform the instrumentation layer that the task - * has started - */ - - sched_note_start(tcb); -#endif - - up_unblock_task(tcb); - irqrestore(flags); - return OK; -} diff --git a/nuttx/sched/task_create.c b/nuttx/sched/task_create.c deleted file mode 100644 index 55fdf22a6..000000000 --- a/nuttx/sched/task_create.c +++ /dev/null @@ -1,292 +0,0 @@ -/**************************************************************************** - * sched/task_create.c - * - * Copyright (C) 2007-2010, 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 "os_internal.h" -#include "group/group.h" - -/**************************************************************************** - * Definitions - ****************************************************************************/ - -/**************************************************************************** - * Private Type Declarations - ****************************************************************************/ - -/**************************************************************************** - * Global Variables - ****************************************************************************/ - -/**************************************************************************** - * Private Variables - ****************************************************************************/ - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: thread_create - * - * Description: - * This function creates and activates a new thread of the specified type - * with a specified priority and returns its system-assigned ID. It is the - * internal, commn implementation of task_create() and kernel_thread(). - * See comments with task_create() for further information. - * - * Input Parameters: - * name - Name of the new task - * ttype - Type of the new task - * priority - Priority of the new task - * stack_size - size (in bytes) of the stack needed - * entry - Entry point of a new task - * arg - A pointer to an array of input parameters. Up to - * CONFIG_MAX_TASK_ARG parameters may be provided. If fewer - * than CONFIG_MAX_TASK_ARG parameters are passed, the list - * should be terminated with a NULL argv[] value. If no - * parameters are required, argv may be NULL. - * - * Return Value: - * Returns the non-zero process ID of the new task or ERROR if memory is - * insufficient or the task cannot be created. The errno will be set to - * indicate the nature of the error (always ENOMEM). - * - ****************************************************************************/ - -#ifndef CONFIG_CUSTOM_STACK -static int thread_create(FAR const char *name, uint8_t ttype, int priority, - int stack_size, main_t entry, FAR char * const argv[]) -#else -static int thread_create(FAR const char *name, uint8_t ttype, int priority, - main_t entry, FAR char * const argv[]) -#endif -{ - FAR struct task_tcb_s *tcb; - pid_t pid; - int errcode; - int ret; - - /* Allocate a TCB for the new task. */ - - tcb = (FAR struct task_tcb_s *)kzalloc(sizeof(struct task_tcb_s)); - if (!tcb) - { - sdbg("ERROR: Failed to allocate TCB\n"); - errcode = ENOMEM; - goto errout; - } - - /* Allocate a new task group */ - -#ifdef HAVE_TASK_GROUP - ret = group_allocate(tcb); - if (ret < 0) - { - errcode = -ret; - goto errout_with_tcb; - } -#endif - - /* Associate file descriptors with the new task */ - -#if CONFIG_NFILE_DESCRIPTORS > 0 || CONFIG_NSOCKET_DESCRIPTORS > 0 - ret = group_setuptaskfiles(tcb); - if (ret < OK) - { - errcode = -ret; - goto errout_with_tcb; - } -#endif - - /* Allocate the stack for the TCB */ - -#ifndef CONFIG_CUSTOM_STACK - ret = up_create_stack((FAR struct tcb_s *)tcb, stack_size, ttype); - if (ret < OK) - { - errcode = -ret; - goto errout_with_tcb; - } -#endif - - /* Initialize the task control block */ - - ret = task_schedsetup(tcb, priority, task_start, entry, ttype); - if (ret < OK) - { - errcode = -ret; - goto errout_with_tcb; - } - - /* Setup to pass parameters to the new task */ - - (void)task_argsetup(tcb, name, argv); - - /* Now we have enough in place that we can join the group */ - -#ifdef HAVE_TASK_GROUP - ret = group_initialize(tcb); - if (ret < 0) - { - errcode = -ret; - goto errout_with_tcb; - } -#endif - - /* Get the assigned pid before we start the task */ - - pid = (int)tcb->cmn.pid; - - /* Activate the task */ - - ret = task_activate((FAR struct tcb_s *)tcb); - if (ret < OK) - { - errcode = get_errno(); - - /* The TCB was added to the active task list by task_schedsetup() */ - - dq_rem((FAR dq_entry_t*)tcb, (dq_queue_t*)&g_inactivetasks); - goto errout_with_tcb; - } - - return pid; - -errout_with_tcb: - sched_releasetcb((FAR struct tcb_s *)tcb, ttype); - -errout: - set_errno(errcode); - return ERROR; -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: task_create - * - * Description: - * This function creates and activates a new task with a specified - * priority and returns its system-assigned ID. - * - * The entry address entry is the address of the "main" function of the - * task. This function will be called once the C environment has been - * set up. The specified function will be called with four arguments. - * Should the specified routine return, a call to exit() will - * automatically be made. - * - * Note that four (and only four) arguments must be passed for the spawned - * functions. - * - * Input Parameters: - * name - Name of the new task - * priority - Priority of the new task - * stack_size - size (in bytes) of the stack needed - * entry - Entry point of a new task - * arg - A pointer to an array of input parameters. Up to - * CONFIG_MAX_TASK_ARG parameters may be provided. If fewer - * than CONFIG_MAX_TASK_ARG parameters are passed, the list - * should be terminated with a NULL argv[] value. If no - * parameters are required, argv may be NULL. - * - * Return Value: - * Returns the non-zero process ID of the new task or ERROR if memory is - * insufficient or the task cannot be created. The errno will be set to - * indicate the nature of the error (always ENOMEM). - * - ****************************************************************************/ - -#ifndef CONFIG_CUSTOM_STACK -int task_create(FAR const char *name, int priority, - int stack_size, main_t entry, FAR char * const argv[]) -#else -int task_create(FAR const char *name, int priority, - main_t entry, FAR char * const argv[]) -#endif -{ -#ifndef CONFIG_CUSTOM_STACK - return thread_create(name, TCB_FLAG_TTYPE_TASK, priority, stack_size, entry, argv); -#else - return thread_create(name, TCB_FLAG_TTYPE_TASK, priority, entry, argv); -#endif -} - -/**************************************************************************** - * Name: kernel_thread - * - * Description: - * This function creates and activates a kernel thread task with kernel- - * mode privileges. It is identical to task_create() except that it - * configures the newly started thread to run in kernel model. - * - * Input Parameters: - * (same as task_create()) - * - * Return Value: - * (same as task_create()) - * - ****************************************************************************/ - -#ifndef CONFIG_CUSTOM_STACK -int kernel_thread(FAR const char *name, int priority, - int stack_size, main_t entry, FAR char * const argv[]) -#else -int kernel_thread(FAR const char *name, int priority, - main_t entry, FAR char * const argv[]) -#endif -{ -#ifndef CONFIG_CUSTOM_STACK - return thread_create(name, TCB_FLAG_TTYPE_KERNEL, priority, stack_size, entry, argv); -#else - return thread_create(name, TCB_FLAG_TTYPE_KERNEL, priority, entry, argv); -#endif -} - diff --git a/nuttx/sched/task_delete.c b/nuttx/sched/task_delete.c deleted file mode 100644 index ead1811c3..000000000 --- a/nuttx/sched/task_delete.c +++ /dev/null @@ -1,132 +0,0 @@ -/**************************************************************************** - * sched/task_delete.c - * - * Copyright (C) 2007-2009, 2011-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 "os_internal.h" - -/**************************************************************************** - * Definitions - ****************************************************************************/ - -/**************************************************************************** - * Private Type Declarations - ****************************************************************************/ - -/**************************************************************************** - * Global Variables - ****************************************************************************/ - -/**************************************************************************** - * Private Variables - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: task_delete - * - * Description: - * This function causes a specified task to cease to exist. Its stack and - * TCB will be deallocated. This function is the companion to task_create(). - * This is the version of the function exposed to the user; it is simply - * a wrapper around the internal, task_terminate function. - * - * The logic in this function only deletes non-running tasks. If the 'pid' - * parameter refers to to the currently runing task, then processing is - * redirected to exit(). This can only happen if a task calls task_delete() - * in order to delete itself. - * - * In fact, this function (and task_terminate) are the final functions - * called all task termination sequences. task_delete may be called - * from: - * - * - task_restart(), - * - pthread_cancel(), - * - and directly from user code. - * - * Other exit paths (exit(), _eixt(), and pthread_exit()) will go through - * task_terminate() - * - * Inputs: - * pid - The task ID of the task to delete. A pid of zero - * signifies the calling task. - * - * Return Value: - * OK on success; or ERROR on failure - * - * This function can fail if the provided pid does not correspond to a - * task (errno is not set) - * - ****************************************************************************/ - -int task_delete(pid_t pid) -{ - FAR struct tcb_s *rtcb; - - /* Check if the task to delete is the calling task */ - - rtcb = (FAR struct tcb_s*)g_readytorun.head; - if (pid == 0 || pid == rtcb->pid) - { - /* If it is, then what we really wanted to do was exit. Note that we - * don't bother to unlock the TCB since it will be going away. - */ - - exit(EXIT_SUCCESS); - } - - /* Then let task_terminate do the heavy lifting */ - - return task_terminate(pid, false); -} diff --git a/nuttx/sched/task_exit.c b/nuttx/sched/task_exit.c deleted file mode 100644 index 4bcdc189c..000000000 --- a/nuttx/sched/task_exit.c +++ /dev/null @@ -1,162 +0,0 @@ -/**************************************************************************** - * sched/task_exit.c - * - * Copyright (C) 2008-2009, 2012-2014 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" -#ifndef CONFIG_DISABLE_SIGNALS -# include "signal/signal.h" -#endif - -/**************************************************************************** - * Definitions - ****************************************************************************/ - -/**************************************************************************** - * Private Type Declarations - ****************************************************************************/ - -/**************************************************************************** - * Global Variables - ****************************************************************************/ - -/**************************************************************************** - * Private Variables - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: task_exit - * - * Description: - * This is a part of the logic used to implement _exit(). The full - * implementation of _exit() is architecture-dependent. The _exit() - * function also implements the bottom half of exit() and pthread_exit(). - * - * This function causes the currently running task (i.e., the task at the - * head of the ready-to-run list) to cease to exist. This function should - * never be called from normal user code, but only from the architecture- - * specific implementation of exit. - * - * Threads/tasks could also be terminated via pthread_cancel, task_delete(), - * and task_restart(). In the last two cases, the task will be terminated - * as though exit() were called. - * - * Inputs: - * None - * - * Return Value: - * OK on success; or ERROR on failure - * - * Assumeptions: - * Interrupts are disabled. - * - ****************************************************************************/ - -int task_exit(void) -{ - FAR struct tcb_s *dtcb = (FAR struct tcb_s*)g_readytorun.head; - FAR struct tcb_s *rtcb; - int ret; - - /* Remove the TCB of the current task from the ready-to-run list. A context - * switch will definitely be necessary -- that must be done by the - * architecture-specific logic. - * - * sched_removereadytorun will mark the task at the head of the ready-to-run - * with state == TSTATE_TASK_RUNNING - */ - - (void)sched_removereadytorun(dtcb); - rtcb = (FAR struct tcb_s*)g_readytorun.head; - - /* We are now in a bad state -- the head of the ready to run task list - * does not correspond to the thread that is running. Disabling pre- - * emption on this TCB and marking the new ready-to-run task as not - * running (see, for example, get_errno_ptr()). - * - * We disable pre-emption here by directly incrementing the lockcount - * (vs. calling sched_lock()). - */ - - rtcb->lockcount++; - rtcb->task_state = TSTATE_TASK_READYTORUN; - - /* Move the TCB to the specified blocked task list and delete it. Calling - * task_terminate with non-blocking true will suppress atexit() and on-exit() - * calls and will cause buffered I/O to fail to be flushed. The former - * is required _exit() behavior; the latter is optional _exit() behavior. - */ - - sched_addblocked(dtcb, TSTATE_TASK_INACTIVE); - ret = task_terminate(dtcb->pid, true); - rtcb->task_state = TSTATE_TASK_RUNNING; - - /* If there are any pending tasks, then add them to the ready-to-run - * task list now - */ - - if (g_pendingtasks.head) - { - (void)sched_mergepending(); - } - - /* We can't use sched_unlock() to decrement the lock count because the - * sched_mergepending() call above might have changed the task at the - * head of the ready-to-run list. Furthermore, we should not need to - * perform the unlock action anyway because we know that the pending - * task list is empty. So all we really need to do is to decrement - * the lockcount on rctb. - */ - - rtcb->lockcount--; - return ret; -} diff --git a/nuttx/sched/task_exithook.c b/nuttx/sched/task_exithook.c deleted file mode 100644 index 90056c264..000000000 --- a/nuttx/sched/task_exithook.c +++ /dev/null @@ -1,690 +0,0 @@ -/**************************************************************************** - * sched/task_exithook.c - * - * Copyright (C) 2011-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 "os_internal.h" -#include "group/group.h" -#include "signal/signal.h" - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/**************************************************************************** - * Private Type Declarations - ****************************************************************************/ - -/**************************************************************************** - * Global Variables - ****************************************************************************/ - -/**************************************************************************** - * Private Variables - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: task_atexit - * - * Description: - * Call any registered atexit function(s) - * - ****************************************************************************/ - -#if defined(CONFIG_SCHED_ATEXIT) && !defined(CONFIG_SCHED_ONEXIT) -static inline void task_atexit(FAR struct tcb_s *tcb) -{ - FAR struct task_group_s *group = tcb->group; - - /* Make sure that we have not already left the group. Only the final - * exiting thread in the task group should trigger the atexit() - * callbacks. - */ - - if (group && group->tg_nmembers == 1) - { -#if defined(CONFIG_SCHED_ATEXIT_MAX) && CONFIG_SCHED_ATEXIT_MAX > 1 - int index; - - /* Call each atexit function in reverse order of registration atexit() - * functions are registered from lower to higher array indices; they - * must be called in the reverse order of registration when the task - * group exits, i.e., from higher to lower indices. - */ - - for (index = CONFIG_SCHED_ATEXIT_MAX-1; index >= 0; index--) - { - if (group->tg_atexitfunc[index]) - { - /* Call the atexit function */ - - (*group->tg_atexitfunc[index])(); - - /* Nullify the atexit function to prevent its reuse. */ - - group->tg_atexitfunc[index] = NULL; - } - } -#else - if (group->tg_atexitfunc) - { - /* Call the atexit function */ - - (*group->tg_atexitfunc)(); - - /* Nullify the atexit function to prevent its reuse. */ - - group->tg_atexitfunc = NULL; - } -#endif - } -} -#else -# define task_atexit(tcb) -#endif - -/**************************************************************************** - * Name: task_onexit - * - * Description: - * Call any registered on_exit function(s) - * - ****************************************************************************/ - -#ifdef CONFIG_SCHED_ONEXIT -static inline void task_onexit(FAR struct tcb_s *tcb, int status) -{ - FAR struct task_group_s *group = tcb->group; - - /* Make sure that we have not already left the group. Only the final - * exiting thread in the task group should trigger the atexit() - * callbacks. - */ - - if (group && group->tg_nmembers == 1) - { -#if defined(CONFIG_SCHED_ONEXIT_MAX) && CONFIG_SCHED_ONEXIT_MAX > 1 - int index; - - /* Call each on_exit function in reverse order of registration. - * on_exit() functions are registered from lower to higher array - * indices; they must be called in the reverse order of registration - * when the task group exits, i.e., from higher to lower indices. - */ - - for (index = CONFIG_SCHED_ONEXIT_MAX-1; index >= 0; index--) - { - if (group->tg_onexitfunc[index]) - { - /* Call the on_exit function */ - - (*group->tg_onexitfunc[index])(status, group->tg_onexitarg[index]); - - /* Nullify the on_exit function to prevent its reuse. */ - - group->tg_onexitfunc[index] = NULL; - } - } -#else - if (group->tg_onexitfunc) - { - /* Call the on_exit function */ - - (*group->tg_onexitfunc)(status, group->tg_onexitarg); - - /* Nullify the on_exit function to prevent its reuse. */ - - group->tg_onexitfunc = NULL; - } -#endif - } -} -#else -# define task_onexit(tcb,status) -#endif - -/**************************************************************************** - * Name: task_exitstatus - * - * Description: - * Report exit status when main task of a task group exits - * - ****************************************************************************/ - -#ifdef CONFIG_SCHED_CHILD_STATUS -static inline void task_exitstatus(FAR struct task_group_s *group, int status) -{ - FAR struct child_status_s *child; - - /* Check if the parent task group has suppressed retention of - * child exit status information. - */ - - if ((group->tg_flags & GROUP_FLAG_NOCLDWAIT) == 0) - { - /* No.. Find the exit status entry for this task in the parent TCB */ - - child = group_findchild(group, getpid()); - DEBUGASSERT(child); - if (child) - { -#ifndef HAVE_GROUP_MEMBERS - /* No group members? Save the exit status */ - - child->ch_status = status; -#endif - /* Save the exit status.. For the case of HAVE_GROUP_MEMBERS, - * the child status will be as exited until the last member - * of the task group exits. - */ - - child->ch_status = status; - } - } -} -#else - -# define task_exitstatus(group,status) - -#endif /* CONFIG_SCHED_CHILD_STATUS */ - -/**************************************************************************** - * Name: task_groupexit - * - * Description: - * Mark that the final thread of a child task group as exited. - * - ****************************************************************************/ - -#ifdef CONFIG_SCHED_CHILD_STATUS -static inline void task_groupexit(FAR struct task_group_s *group) -{ - FAR struct child_status_s *child; - - /* Check if the parent task group has suppressed retention of child exit - * status information. - */ - - if ((group->tg_flags & GROUP_FLAG_NOCLDWAIT) == 0) - { - /* No.. Find the exit status entry for this task in the parent TCB */ - - child = group_findchild(group, getpid()); - DEBUGASSERT(child); - if (child) - { - /* Mark that all members of the child task group has exited */ - - child->ch_flags |= CHILD_FLAG_EXITED; - } - } -} - -#else - -# define task_groupexit(group) - -#endif /* CONFIG_SCHED_CHILD_STATUS */ - -/**************************************************************************** - * Name: task_sigchild - * - * Description: - * Send the SIGCHILD signal to the parent thread - * - ****************************************************************************/ - -#ifdef CONFIG_SCHED_HAVE_PARENT -#ifdef HAVE_GROUP_MEMBERS -static inline void task_sigchild(gid_t pgid, FAR struct tcb_s *ctcb, int status) -{ - FAR struct task_group_s *chgrp = ctcb->group; - FAR struct task_group_s *pgrp; - siginfo_t info; - - DEBUGASSERT(chgrp); - - /* Get the parent task group. It is possible that all of the members of - * the parent task group have exited. This would not be an error. In - * this case, the child task group has been orphaned. - */ - - pgrp = group_findbygid(pgid); - if (!pgrp) - { - /* Set the task group ID to an invalid group ID. The dead parent - * task group ID could get reused some time in the future. - */ - - chgrp->tg_pgid = INVALID_GROUP_ID; - return; - } - - /* Save the exit status now if this is the main thread of the task group - * that is exiting. Only the exiting main task of a task group carries - * interpretable exit Check if this is the main task that is exiting. - */ - -#ifndef CONFIG_DISABLE_PTHREAD - if ((ctcb->flags & TCB_FLAG_TTYPE_MASK) != TCB_FLAG_TTYPE_PTHREAD) -#endif - { - task_exitstatus(pgrp, status); - } - - /* But only the final exiting thread in a task group, whatever it is, - * should generate SIGCHLD. - */ - - if (chgrp->tg_nmembers == 1) - { - /* Mark that all of the threads in the task group have exited */ - - task_groupexit(pgrp); - - /* Create the siginfo structure. We don't actually know the cause. - * That is a bug. Let's just say that the child task just exited - * for now. - */ - - info.si_signo = SIGCHLD; - info.si_code = CLD_EXITED; - info.si_value.sival_ptr = NULL; -#ifndef CONFIG_DISABLE_PTHREAD - info.si_pid = chgrp->tg_task; -#else - info.si_pid = ctcb->pid; -#endif - info.si_status = status; - - /* Send the signal to one thread in the group */ - - (void)group_signal(pgrp, &info); - } -} - -#else /* HAVE_GROUP_MEMBERS */ - -static inline void task_sigchild(FAR struct tcb_s *ptcb, - FAR struct tcb_s *ctcb, int status) -{ - siginfo_t info; - - /* If task groups are not supported then we will report SIGCHLD when the - * task exits. Unfortunately, there could still be threads in the group - * that are still running. - */ - -#ifndef CONFIG_DISABLE_PTHREAD - if ((ctcb->flags & TCB_FLAG_TTYPE_MASK) != TCB_FLAG_TTYPE_PTHREAD) -#endif - { -#ifdef CONFIG_SCHED_CHILD_STATUS - /* Save the exit status now of the main thread */ - - task_exitstatus(ptcb->group, status); - -#else /* CONFIG_SCHED_CHILD_STATUS */ - - /* Decrement the number of children from this parent */ - - DEBUGASSERT(ptcb->nchildren > 0); - ptcb->nchildren--; - -#endif /* CONFIG_SCHED_CHILD_STATUS */ - - /* Create the siginfo structure. We don't actually know the cause. - * That is a bug. Let's just say that the child task just exited - * for now. - */ - - info.si_signo = SIGCHLD; - info.si_code = CLD_EXITED; - info.si_value.sival_ptr = NULL; -#ifndef CONFIG_DISABLE_PTHREAD - info.si_pid = ctcb->group->tg_task; -#else - info.si_pid = ctcb->pid; -#endif - info.si_status = status; - - /* Send the signal. We need to use this internal interface so that we - * can provide the correct si_code value with the signal. - */ - - (void)sig_tcbdispatch(ptcb, &info); - } -} - -#endif /* HAVE_GROUP_MEMBERS */ -#else /* CONFIG_SCHED_HAVE_PARENT */ - -# define task_sigchild(x,ctcb,status) - -#endif /* CONFIG_SCHED_HAVE_PARENT */ - -/**************************************************************************** - * Name: task_signalparent - * - * Description: - * Send the SIGCHILD signal to the parent task group - * - ****************************************************************************/ - -#ifdef CONFIG_SCHED_HAVE_PARENT -static inline void task_signalparent(FAR struct tcb_s *ctcb, int status) -{ -#ifdef HAVE_GROUP_MEMBERS - DEBUGASSERT(ctcb && ctcb->group); - - /* Keep things stationary throughout the following */ - - sched_lock(); - - /* Send SIGCHLD to all members of the parent's task group */ - - task_sigchild(ctcb->group->tg_pgid, ctcb, status); - sched_unlock(); -#else - FAR struct tcb_s *ptcb; - - /* Keep things stationary throughout the following */ - - sched_lock(); - - /* Get the TCB of the receiving, parent task. We do this early to - * handle multiple calls to task_signalparent. ctcb->ppid is set to an - * invalid value below and the following call will fail if we are - * called again. - */ - - ptcb = sched_gettcb(ctcb->ppid); - if (!ptcb) - { - /* The parent no longer exists... bail */ - - sched_unlock(); - return; - } - - /* Send SIGCHLD to all members of the parent's task group */ - - task_sigchild(ptcb, ctcb, status); - - /* Forget who our parent was */ - - ctcb->ppid = INVALID_PROCESS_ID; - sched_unlock(); -#endif -} -#else -# define task_signalparent(ctcb,status) -#endif - -/**************************************************************************** - * Name: task_exitwakeup - * - * Description: - * Wakeup any tasks waiting for this task to exit - * - ****************************************************************************/ - -#if defined(CONFIG_SCHED_WAITPID) && !defined(CONFIG_SCHED_HAVE_PARENT) -static inline void task_exitwakeup(FAR struct tcb_s *tcb, int status) -{ - FAR struct task_group_s *group = tcb->group; - - /* Have we already left the group? */ - - if (group) - { - /* Only tasks (and kernel threads) return valid status. Record the - * exit status when the task exists. The group, however, may still - * be executing. - */ - -#ifndef CONFIG_DISABLE_PTHREAD - if ((tcb->flags & TCB_FLAG_TTYPE_MASK) != TCB_FLAG_TTYPE_PTHREAD) -#endif - { - /* Report the exit status. We do not nullify tg_statloc here - * because we want to prevent other tasks from registering for - * the return status. There is only one task per task group, - * there for, this logic should execute exactly once in the - * lifetime of the task group. - * - * "If more than one thread is suspended in waitpid() awaiting - * termination of the same process, exactly one thread will - * return the process status at the time of the target process - * termination." - * - * Hmmm.. what do we return to the others? - */ - - if (group->tg_statloc) - { - *group->tg_statloc = status << 8; - } - } - - /* Is this the last thread in the group? */ - - if (group->tg_nmembers == 1) - { - /* Yes.. Wakeup any tasks waiting for this task to exit */ - - group->tg_statloc = NULL; - while (group->tg_exitsem.semcount < 0) - { - /* Wake up the thread */ - - sem_post(&group->tg_exitsem); - } - } - } -} -#else -# define task_exitwakeup(tcb, status) -#endif - -/**************************************************************************** - * Name: task_flushstreams - * - * Description: - * Flush all streams when the final thread of a group exits. - * - ****************************************************************************/ - -#if CONFIG_NFILE_STREAMS > 0 -static inline void task_flushstreams(FAR struct tcb_s *tcb) -{ - FAR struct task_group_s *group = tcb->group; - - /* Have we already left the group? Are we the last thread in the group? */ - - if (group && group->tg_nmembers == 1) - { -#if defined(CONFIG_NUTTX_KERNEL) && defined(CONFIG_MM_KERNEL_HEAP) - (void)lib_flushall(tcb->group->tg_streamlist); -#else - (void)lib_flushall(&tcb->group->tg_streamlist); -#endif - } -} -#else -# define task_flushstreams(tcb) -#endif - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: task_exithook - * - * Description: - * This function implements some of the internal logic of exit() and - * task_delete(). This function performs some clean-up and other actions - * required when a task exits: - * - * - All open streams are flushed and closed. - * - All functions registered with atexit() and on_exit() are called, in - * the reverse order of their registration. - * - * When called from exit(), the tcb still resides at the head of the ready- - * to-run list. The following logic is safe because we will not be - * returning from the exit() call. - * - * When called from task_terminate() we are operating on a different thread; - * on the thread that called task_delete(). In this case, task_delete - * will have already removed the tcb from the ready-to-run list to prevent - * any further action on this task. - * - * nonblocking will be set true only when we are called from task_terminate() - * via _exit(). In that case, we must be careful to do nothing that can - * cause the cause the thread to block. - * - ****************************************************************************/ - -void task_exithook(FAR struct tcb_s *tcb, int status, bool nonblocking) -{ - /* Under certain conditions, task_exithook() can be called multiple times. - * A bit in the TCB was set the first time this function was called. If - * that bit is set, then just exit doing nothing more.. - */ - - if ((tcb->flags & TCB_FLAG_EXIT_PROCESSING) != 0) - { - return; - } - - /* If exit function(s) were registered, call them now before we do any un- - * initialization. - * - * NOTES: - * - * 1. In the case of task_delete(), the exit function will *not* be called - * on the thread execution of the task being deleted! That is probably - * a bug. - * 2. We cannot call the exit functions if nonblocking is requested: These - * functions might block. - * 3. This function will only be called with with non-blocking == true - * only when called through _exit(). _exit() behaviors requires that - * the exit functions *not* be called. - */ - -#if defined(CONFIG_SCHED_ATEXIT) || defined(CONFIG_SCHED_ONEXIT) - if (!nonblocking) - { - task_atexit(tcb); - - /* Call any registered on_exit function(s) */ - - task_onexit(tcb, status); - } -#endif - - /* If the task was terminated by another task, it may be in an unknown - * state. Make some feeble effort to recover the state. - */ - - task_recover(tcb); - - /* Send the SIGCHILD signal to the parent task group */ - - task_signalparent(tcb, status); - - /* Wakeup any tasks waiting for this task to exit */ - - task_exitwakeup(tcb, status); - - /* If this is the last thread in the group, then flush all streams (File - * descriptors will be closed when the TCB is deallocated). - * - * NOTES: - * 1. We cannot flush the buffered I/O if nonblocking is requested. - * that might cause this logic to block. - * 2. This function will only be called with with non-blocking == true - * only when called through _exit(). _exit() behavior does not - * require that the streams be flushed - */ - - if (!nonblocking) - { - task_flushstreams(tcb); - } - - /* Leave the task group. Perhaps discarding any un-reaped child - * status (no zombies here!) - */ - -#ifdef HAVE_TASK_GROUP - group_leave(tcb); -#endif - - /* Deallocate anything left in the TCB's queues */ - -#ifndef CONFIG_DISABLE_SIGNALS - sig_cleanup(tcb); /* Deallocate Signal lists */ -#endif - - /* This function can be re-entered in certain cases. Set a flag - * bit in the TCB to not that we have already completed this exit - * processing. - */ - - tcb->flags |= TCB_FLAG_EXIT_PROCESSING; -} diff --git a/nuttx/sched/task_getgroup.c b/nuttx/sched/task_getgroup.c deleted file mode 100644 index 9c7b4b954..000000000 --- a/nuttx/sched/task_getgroup.c +++ /dev/null @@ -1,105 +0,0 @@ -/***************************************************************************** - * sched/task_getgroup.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" -#include "group/group.h" - -#ifdef HAVE_TASK_GROUP - -/***************************************************************************** - * Pre-processor Definitions - *****************************************************************************/ - -/***************************************************************************** - * Private Types - *****************************************************************************/ - -/***************************************************************************** - * Private Data - *****************************************************************************/ - -/***************************************************************************** - * Public Data - *****************************************************************************/ - -/***************************************************************************** - * Private Functions - *****************************************************************************/ - -/***************************************************************************** - * Public Functions - *****************************************************************************/ - -/***************************************************************************** - * Name: task_getgroup - * - * Description: - * Given a task ID, return the group structure of this task. - * - * Parameters: - * pid - The task ID to use in the lookup. - * - * Return Value: - * On success, a pointer to the group task structure is returned. This - * function can fail only if there is no group that corresponds to the - * groupd ID. - * - * Assumptions: - * Called during when signally tasks in a safe context. No special - * precautions should be required here. However, extra care is taken when - * accessing the global g_grouphead list. - * - *****************************************************************************/ - -FAR struct task_group_s *task_getgroup(pid_t pid) -{ - FAR struct tcb_s *tcb = sched_gettcb(pid); - if (tcb) - { - return tcb->group; - } - - return NULL; -} - -#endif /* HAVE_TASK_GROUP */ diff --git a/nuttx/sched/task_init.c b/nuttx/sched/task_init.c deleted file mode 100644 index 112ac6801..000000000 --- a/nuttx/sched/task_init.c +++ /dev/null @@ -1,197 +0,0 @@ -/**************************************************************************** - * sched/task_init.c - * - * Copyright (C) 2007, 2009, 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 "os_internal.h" -#include "group/group.h" - -/**************************************************************************** - * Definitions - ****************************************************************************/ - -/**************************************************************************** - * Private Type Declarations - ****************************************************************************/ - -/**************************************************************************** - * Global Variables - ****************************************************************************/ - -/**************************************************************************** - * Private Variables - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: task_init - * - * Description: - * This function initializes a Task Control Block (TCB) in preparation for - * starting a new thread. It performs a subset of the functionality of - * task_create() - * - * Unlike task_create(): - * 1. Allocate the TCB. The pre-allocated TCB is passed in the arguments. - * 2. Allocate the stack. The pre-allocated stack is passed in the arguments. - * 3. Activate the task. This must be done by calling task_activate(). - * - * Input Parameters: - * tcb - Address of the new task's TCB - * name - Name of the new task (not used) - * priority - Priority of the new task - * stack - Start of the pre-allocated stack - * stack_size - Size (in bytes) of the stack allocated - * entry - Application start point of the new task - * arg - A pointer to an array of input parameters. Up to - * CONFIG_MAX_TASK_ARG parameters may be provided. If fewer - * than CONFIG_MAX_TASK_ARG parameters are passed, the list - * should be terminated with a NULL argv[] value. If no - * parameters are required, argv may be NULL. - * - * Return Value: - * OK on success; ERROR on failure with errno set appropriately. (See - * task_schedsetup() for possible failure conditions). On failure, the - * caller is responsible for freeing the stack memory and for calling - * sched_releasetcb() to free the TCB (which could be in most any state). - * - ****************************************************************************/ - -#ifndef CONFIG_CUSTOM_STACK -int task_init(FAR struct tcb_s *tcb, const char *name, int priority, - FAR uint32_t *stack, uint32_t stack_size, - main_t entry, FAR char * const argv[]) -#else -int task_init(FAR struct tcb_s *tcb, const char *name, int priority, - main_t entry, FAR char * const argv[]) -#endif -{ - FAR struct task_tcb_s *ttcb = (FAR struct task_tcb_s *)tcb; - int errcode; - int ret; - - /* Only tasks and kernel threads can be initialized in this way */ - -#ifndef CONFIG_DISABLE_PTHREAD - DEBUGASSERT(tcb && - (tcb->flags & TCB_FLAG_TTYPE_MASK) != TCB_FLAG_TTYPE_PTHREAD); -#endif - - /* Create a new task group */ - -#ifdef HAVE_TASK_GROUP - ret = group_allocate(ttcb); - if (ret < 0) - { - errcode = -ret; - goto errout; - } -#endif - - /* Associate file descriptors with the new task */ - -#if CONFIG_NFILE_DESCRIPTORS > 0 || CONFIG_NSOCKET_DESCRIPTORS > 0 - ret = group_setuptaskfiles(ttcb); - if (ret < 0) - { - errcode = -ret; - goto errout_with_group; - } -#endif - - /* Configure the user provided stack region */ - -#ifndef CONFIG_CUSTOM_STACK - up_use_stack(tcb, stack, stack_size); -#endif - - /* Initialize the task control block */ - - ret = task_schedsetup(ttcb, priority, task_start, entry, - TCB_FLAG_TTYPE_TASK); - if (ret < OK) - { - errcode = -ret; - goto errout_with_group; - } - - /* Setup to pass parameters to the new task */ - - (void)task_argsetup(ttcb, name, argv); - - /* Now we have enough in place that we can join the group */ - -#ifdef HAVE_TASK_GROUP - ret = group_initialize(ttcb); - if (ret < 0) - { - errcode = -ret; - goto errout_with_group; - } -#endif - return OK; - -errout_with_group: -#ifdef HAVE_TASK_GROUP - group_leave(tcb); - -errout: -#endif - set_errno(errcode); - return ERROR; -} - diff --git a/nuttx/sched/task_posixspawn.c b/nuttx/sched/task_posixspawn.c deleted file mode 100644 index 122a83a28..000000000 --- a/nuttx/sched/task_posixspawn.c +++ /dev/null @@ -1,461 +0,0 @@ -/**************************************************************************** - * 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 "os_internal.h" -#include "group/group.h" -#include "spawn_internal.h" - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Public Data - ****************************************************************************/ - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: posix_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 posix_spawn_exec(FAR pid_t *pidp, FAR const char *path, - FAR const posix_spawnattr_t *attr, - FAR char * const argv[]) -{ - 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 char * const *)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) - { - (void)spawn_execattrs(pid, attr); - } - - /* Re-enable pre-emption and return */ - -errout: - sched_unlock(); - return ret; -} - -/**************************************************************************** - * Name: posix_spawn_proxy - * - * Description: - * Perform file_actions, then execute the task from the file system. - * - * Do we really need this proxy task? Isn't that wasteful? - * - * Q: Why not use a starthook so that there is callout from task_start() - * to perform these operations after the file is loaded from - * the file system? - * A: That existing task_starthook() implementation cannot be used in - * this context; any of task_starthook() will also conflict with - * binfmt's use of the start hook to call C++ static initializers. - * task_restart() would also be an issue. - * - * Input Parameters: - * Standard task start-up parameters - * - * Returned Value: - * Standard task return value. - * - ****************************************************************************/ - -static int posix_spawn_proxy(int argc, FAR char *argv[]) -{ - int ret; - - /* Perform file actions and/or set a custom signal mask. We get here only - * if the file_actions parameter to posix_spawn[p] was non-NULL and/or the - * option to change the signal mask was selected. - */ - -#ifndef CONFIG_DISABLE_SIGNALS - DEBUGASSERT(g_spawn_parms.file_actions || - (g_spawn_parms.attr && - (g_spawn_parms.attr->flags & POSIX_SPAWN_SETSIGMASK) != 0)); -#else - DEBUGASSERT(g_spawn_parms.file_actions); -#endif - - /* Set the attributes and perform the file actions as appropriate */ - - ret = spawn_proxyattrs(g_spawn_parms.attr, g_spawn_parms.file_actions); - if (ret == OK) - { - /* Start the task */ - - ret = posix_spawn_exec(g_spawn_parms.pid, g_spawn_parms.u.posix.path, - g_spawn_parms.attr, g_spawn_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, *g_spawn_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_spawn_parms.result = ret; -#ifndef CONFIG_SCHED_WAITPID - spawn_semgive(&g_spawn_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 posix_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_spawn_parmsem); - - /* Populate the parameter structure */ - - g_spawn_parms.result = ENOSYS; - g_spawn_parms.pid = pid; - g_spawn_parms.file_actions = file_actions ? *file_actions : NULL; - g_spawn_parms.attr = attr; - g_spawn_parms.argv = argv; - g_spawn_parms.u.posix.path = path; - - /* 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_spawn_parmsem); - return errcode; - } - - /* Disable pre-emption so that the proxy does not run until waitpid - * is called. This is probably unnecessary since the posix_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("posix_spawn_proxy", param.sched_priority, - CONFIG_POSIX_SPAWN_PROXY_STACKSIZE, - (main_t)posix_spawn_proxy, - (FAR char * const *)NULL); - if (proxy < 0) - { - ret = get_errno(); - sdbg("ERROR: Failed to start posix_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_spawn_execsem); -#endif - - /* Get the result and relinquish our access to the parameter structure */ - - ret = g_spawn_parms.result; - -errout_with_lock: -#ifdef CONFIG_SCHED_WAITPID - sched_unlock(); -#endif - spawn_semgive(&g_spawn_parmsem); - return ret; -} diff --git a/nuttx/sched/task_recover.c b/nuttx/sched/task_recover.c deleted file mode 100644 index 1907a9fe4..000000000 --- a/nuttx/sched/task_recover.c +++ /dev/null @@ -1,123 +0,0 @@ -/**************************************************************************** - * sched/task_recover.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 "os_internal.h" -#include "mqueue/mqueue.h" - -/**************************************************************************** - * Definitions - ****************************************************************************/ - -/**************************************************************************** - * Private Type Declarations - ****************************************************************************/ - -/**************************************************************************** - * Global Variables - ****************************************************************************/ - -/**************************************************************************** - * Private Variables - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: task_recover - * - * Description: - * This function is called when a task is deleted via task_deleted or - * via pthread_cancel. I checks if the task was waiting for a message - * queue event and adjusts counts appropriately. - * - * Inputs: - * tcb - The TCB of the terminated task or thread - * - * Return Value: - * None. - * - * Assumptions: - * This function is called from task deletion logic in a safe context. - * - ****************************************************************************/ - -void task_recover(FAR struct tcb_s *tcb) -{ - irqstate_t flags; - - /* The task is being deleted. If it is waiting for any timed event, then - * tcb->waitdog will be non-NULL. Cancel the watchdog now so that no - * events occur after the watchdog expires. Obviously there are lots of - * race conditions here so this will most certainly have to be revisited in - * the future. - */ - - flags = irqsave(); - if (tcb->waitdog) - { - (void)wd_cancel(tcb->waitdog); - (void)wd_delete(tcb->waitdog); - tcb->waitdog = NULL; - } - - irqrestore(flags); - - /* Handle cases where the thread was waiting for a message queue event */ - -#ifndef CONFIG_DISABLE_MQUEUE - mq_recover(tcb); -#endif -} diff --git a/nuttx/sched/task_reparent.c b/nuttx/sched/task_reparent.c deleted file mode 100644 index 7f8c8de41..000000000 --- a/nuttx/sched/task_reparent.c +++ /dev/null @@ -1,320 +0,0 @@ -/***************************************************************************** - * 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" -#include "group/group.h" - -#ifdef CONFIG_SCHED_HAVE_PARENT - -/***************************************************************************** - * Private Functions - *****************************************************************************/ - -/***************************************************************************** - * Public Functions - *****************************************************************************/ - -/***************************************************************************** - * Name: task_reparent - * - * Description: - * Change the parent of a task. - * - * Parameters: - * ppid - PID of the new parent task (0 for grandparent, i.e. the parent - * of the current parent task) - * chpid - PID of the child to be reparented. - * - * Return Value: - * 0 (OK) on success; A negated errno value on failure. - * - *****************************************************************************/ - -#ifdef HAVE_GROUP_MEMBERS -int task_reparent(pid_t ppid, pid_t chpid) -{ -#ifdef CONFIG_SCHED_CHILD_STATUS - FAR struct child_status_s *child; -#endif - FAR struct task_group_s *chgrp; - FAR struct task_group_s *ogrp; - FAR struct task_group_s *pgrp; - struct tcb_s *tcb; - gid_t ogid; - gid_t pgid; - irqstate_t flags; - int ret; - - /* Disable interrupts so that nothing can change in the relationship of - * the three task: Child, current parent, and new parent. - */ - - flags = irqsave(); - - /* Get the child tasks task group */ - - tcb = sched_gettcb(chpid); - if (!tcb) - { - ret = -ECHILD; - goto errout_with_ints; - } - - DEBUGASSERT(tcb->group); - chgrp = tcb->group; - - /* Get the GID of the old parent task's task group (ogid) */ - - ogid = chgrp->tg_pgid; - - /* Get the old parent task's task group (ogrp) */ - - ogrp = group_findbygid(ogid); - if (!ogrp) - { - ret = -ESRCH; - goto errout_with_ints; - } - - /* If new parent task's PID (ppid) is zero, then new parent is the - * grandparent will be the new parent, i.e., the parent of the current - * parent task. - */ - - if (ppid == 0) - { - /* Get the grandparent task's task group (pgrp) */ - - pgid = ogrp->tg_pgid; - pgrp = group_findbygid(pgid); - } - else - { - /* Get the new parent task's task group (pgrp) */ - - tcb = sched_gettcb(ppid); - if (!tcb) - { - ret = -ESRCH; - goto errout_with_ints; - } - - pgrp = tcb->group; - pgid = pgrp->tg_gid; - } - - if (!pgrp) - { - ret = -ESRCH; - goto errout_with_ints; - } - - /* Then reparent the child. Notice that we don't actually change the - * parent of the task. Rather, we change the parent task group for - * all members of the child's task group. - */ - - chgrp->tg_pgid = pgid; - -#ifdef CONFIG_SCHED_CHILD_STATUS - /* Remove the child status entry from old parent task group */ - - child = group_removechild(ogrp, chpid); - if (child) - { - /* Has the new parent's task group supressed child exit status? */ - - if ((pgrp->tg_flags && GROUP_FLAG_NOCLDWAIT) == 0) - { - /* No.. Add the child status entry to the new parent's task group */ - - group_addchild(pgrp, child); - } - else - { - /* Yes.. Discard the child status entry */ - - group_freechild(child); - } - - /* Either case is a success */ - - ret = OK; - } - else - { - /* This would not be an error if the original parent's task group has - * suppressed child exit status. - */ - - ret = ((ogrp->tg_flags && GROUP_FLAG_NOCLDWAIT) == 0) ? -ENOENT : OK; - } - -#else /* CONFIG_SCHED_CHILD_STATUS */ - - DEBUGASSERT(otcb->nchildren > 0); - - otcb->nchildren--; /* The orignal parent now has one few children */ - ptcb->nchildren++; /* The new parent has one additional child */ - ret = OK; - -#endif /* CONFIG_SCHED_CHILD_STATUS */ - -errout_with_ints: - irqrestore(flags); - return ret; -} -#else -int task_reparent(pid_t ppid, pid_t chpid) -{ -#ifdef CONFIG_SCHED_CHILD_STATUS - FAR struct child_status_s *child; -#endif - struct tcb_s *ptcb; - struct tcb_s *chtcb; - struct tcb_s *otcb; - pid_t opid; - irqstate_t flags; - int ret; - - /* Disable interrupts so that nothing can change in the relationship of - * the three task: Child, current parent, and new parent. - */ - - flags = irqsave(); - - /* Get the child tasks TCB (chtcb) */ - - chtcb = sched_gettcb(chpid); - if (!chtcb) - { - ret = -ECHILD; - goto errout_with_ints; - } - - /* Get the PID of the child task's parent (opid) */ - - opid = chtcb->ppid; - - /* Get the TCB of the child task's parent (otcb) */ - - otcb = sched_gettcb(opid); - if (!otcb) - { - ret = -ESRCH; - goto errout_with_ints; - } - - /* If new parent task's PID (ppid) is zero, then new parent is the - * grandparent will be the new parent, i.e., the parent of the current - * parent task. - */ - - if (ppid == 0) - { - ppid = otcb->ppid; - } - - /* Get the new parent task's TCB (ptcb) */ - - ptcb = sched_gettcb(ppid); - if (!ptcb) - { - ret = -ESRCH; - goto errout_with_ints; - } - - /* Then reparent the child */ - - chtcb->ppid = ppid; /* The task specified by ppid is the new parent */ - -#ifdef CONFIG_SCHED_CHILD_STATUS - /* Remove the child status entry from old parent TCB */ - - child = group_removechild(otcb->group, chpid); - if (child) - { - /* Has the new parent's task group supressed child exit status? */ - - if ((ptcb->group->tg_flags && GROUP_FLAG_NOCLDWAIT) == 0) - { - /* No.. Add the child status entry to the new parent's task group */ - - group_addchild(ptcb->group, child); - } - else - { - /* Yes.. Discard the child status entry */ - - group_freechild(child); - } - - /* Either case is a success */ - - ret = OK; - } - else - { - /* This would not be an error if the original parent's task group has - * suppressed child exit status. - */ - - ret = ((otcb->group->tg_flags && GROUP_FLAG_NOCLDWAIT) == 0) ? -ENOENT : OK; - } - -#else /* CONFIG_SCHED_CHILD_STATUS */ - - DEBUGASSERT(otcb->nchildren > 0); - - otcb->nchildren--; /* The orignal parent now has one few children */ - ptcb->nchildren++; /* The new parent has one additional child */ - ret = OK; - -#endif /* CONFIG_SCHED_CHILD_STATUS */ - -errout_with_ints: - irqrestore(flags); - return ret; -} -#endif -#endif /* CONFIG_SCHED_HAVE_PARENT */ diff --git a/nuttx/sched/task_restart.c b/nuttx/sched/task_restart.c deleted file mode 100644 index 1e552030a..000000000 --- a/nuttx/sched/task_restart.c +++ /dev/null @@ -1,208 +0,0 @@ -/**************************************************************************** - * sched/task_restart.c - * - * Copyright (C) 2007, 2009, 2012-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 "os_internal.h" -#include "group/group.h" -#include "signal/signal.h" - -/**************************************************************************** - * Definitions - ****************************************************************************/ - -/**************************************************************************** - * Private Type Declarations - ****************************************************************************/ - -/**************************************************************************** - * Global Variables - ****************************************************************************/ - -/**************************************************************************** - * Private Variables - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: task_restart - * - * Description: - * This function "restarts" a task. The task is first terminated and then - * reinitialized with same ID, priority, original entry point, stack size, - * and parameters it had when it was first started. - * - * Inputs: - * pid - The task ID of the task to delete. An ID of zero signifies the - * calling task. - * - * Return Value: - * OK on sucess; ERROR on failure. - * - * This function can fail if: - * (1) A pid of zero or the pid of the calling task is provided - * (functionality not implemented) - * (2) The pid is not associated with any task known to the system. - * - ****************************************************************************/ - -int task_restart(pid_t pid) -{ - FAR struct tcb_s *rtcb; - FAR struct task_tcb_s *tcb; - irqstate_t state; - int status; - - /* Make sure this task does not become ready-to-run while - * we are futzing with its TCB - */ - - sched_lock(); - - /* Check if the task to restart is the calling task */ - - rtcb = (FAR struct tcb_s *)g_readytorun.head; - if ((pid == 0) || (pid == rtcb->pid)) - { - /* Not implemented */ - - set_errno(ENOSYS); - return ERROR; - } - - /* We are restarting some other task than ourselves */ - - else - { - /* Find for the TCB associated with matching pid */ - - tcb = (FAR struct task_tcb_s *)sched_gettcb(pid); -#ifndef CONFIG_DISABLE_PTHREAD - if (!tcb || (tcb->cmn.flags & TCB_FLAG_TTYPE_MASK) == TCB_FLAG_TTYPE_PTHREAD) -#else - if (!tcb) -#endif - { - /* There is no TCB with this pid or, if there is, it is not a - * task. - */ - - set_errno(ESRCH); - return ERROR; - } - - /* Try to recover from any bad states */ - - task_recover((FAR struct tcb_s *)tcb); - - /* Kill any children of this thread */ - -#if HAVE_GROUP_MEMBERS - (void)group_killchildren(tcb); -#endif - - /* Remove the TCB from whatever list it is in. At this point, the - * TCB should no longer be accessible to the system - */ - - state = irqsave(); - dq_rem((FAR dq_entry_t*)tcb, - (dq_queue_t*)g_tasklisttable[tcb->cmn.task_state].list); - tcb->cmn.task_state = TSTATE_TASK_INVALID; - irqrestore(state); - - /* Deallocate anything left in the TCB's queues */ - - sig_cleanup((FAR struct tcb_s *)tcb); /* Deallocate Signal lists */ - - /* Reset the current task priority */ - - tcb->cmn.sched_priority = tcb->init_priority; - - /* Reset the base task priority and the number of pending reprioritizations */ - -#ifdef CONFIG_PRIORITY_INHERITANCE - tcb->cmn.base_priority = tcb->init_priority; -# if CONFIG_SEM_NNESTPRIO > 0 - tcb->cmn.npend_reprio = 0; -# endif -#endif - - /* Re-initialize the processor-specific portion of the TCB - * This will reset the entry point and the start-up parameters - */ - - up_initial_state((FAR struct tcb_s *)tcb); - - /* Add the task to the inactive task list */ - - dq_addfirst((FAR dq_entry_t*)tcb, (dq_queue_t*)&g_inactivetasks); - tcb->cmn.task_state = TSTATE_TASK_INACTIVE; - - /* Activate the task */ - - status = task_activate((FAR struct tcb_s *)tcb); - if (status != OK) - { - (void)task_delete(pid); - set_errno(-status); - return ERROR; - } - } - - sched_unlock(); - return OK; -} diff --git a/nuttx/sched/task_setup.c b/nuttx/sched/task_setup.c deleted file mode 100644 index ddf1537bf..000000000 --- a/nuttx/sched/task_setup.c +++ /dev/null @@ -1,764 +0,0 @@ -/**************************************************************************** - * sched/task_setup.c - * - * Copyright (C) 2007-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 "os_internal.h" -#include "pthread/pthread.h" -#include "group/group.h" - -/**************************************************************************** - * Definitions - ****************************************************************************/ - -/**************************************************************************** - * Private Type Declarations - ****************************************************************************/ - -/**************************************************************************** - * Global Variables - ****************************************************************************/ - -/**************************************************************************** - * Private Variables - ****************************************************************************/ - -/* This is the name for un-named tasks */ - -static const char g_noname[] = ""; - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -static int task_assignpid(FAR struct tcb_s* tcb); - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: task_assignpid - * - * Description: - * This function assigns the next unique task ID to a task. - * - * Inputs: - * tcb - TCB of task - * - * Return: - * OK on success; ERROR on failure (errno is not set) - * - ****************************************************************************/ - -static int task_assignpid(FAR struct tcb_s *tcb) -{ - pid_t next_pid; - int hash_ndx; - int tries; - - /* Disable pre-emption. This should provide sufficient protection - * for the following operation. - */ - - (void)sched_lock(); - - /* We'll try every allowable pid */ - - for (tries = 0; tries < CONFIG_MAX_TASKS; tries++) - { - /* Get the next process ID candidate */ - - next_pid = ++g_lastpid; - - /* Verify that the next_pid is in the valid range */ - - if (next_pid <= 0) - { - g_lastpid = 1; - next_pid = 1; - } - - /* Get the hash_ndx associated with the next_pid */ - - hash_ndx = PIDHASH(next_pid); - - /* Check if there is a (potential) duplicate of this pid */ - - if (!g_pidhash[hash_ndx].tcb) - { - /* Assign this PID to the task */ - - g_pidhash[hash_ndx].tcb = tcb; - g_pidhash[hash_ndx].pid = next_pid; -#ifdef CONFIG_SCHED_CPULOAD - g_pidhash[hash_ndx].ticks = 0; -#endif - tcb->pid = next_pid; - - (void)sched_unlock(); - return OK; - } - } - - /* If we get here, then the g_pidhash[] table is completely full. - * We cannot allow another task to be started. - */ - - (void)sched_unlock(); - return ERROR; -} - -/**************************************************************************** - * Name: task_saveparent - * - * Description: - * Save the task ID of the parent task in the child task's TCB and allocate - * a child status structure to catch the child task's exit status. - * - * Parameters: - * tcb - The TCB of the new, child task. - * ttype - Type of the new thread: task, pthread, or kernel thread - * - * Returned Value: - * None - * - * Assumptions: - * The parent of the new task is the task at the head of the ready-to-run - * list. - * - ****************************************************************************/ - -#ifdef CONFIG_SCHED_HAVE_PARENT -static inline void task_saveparent(FAR struct tcb_s *tcb, uint8_t ttype) -{ - FAR struct tcb_s *rtcb = (FAR struct tcb_s*)g_readytorun.head; - -#if defined(HAVE_GROUP_MEMBERS) || defined(CONFIG_SCHED_CHILD_STATUS) - DEBUGASSERT(tcb && tcb->group && rtcb->group); -#else -#endif - -#ifdef HAVE_GROUP_MEMBERS - /* Save the ID of the parent tasks' task group in the child's task group. - * Do nothing for pthreads. The parent and the child are both members of - * the same task group. - */ - -#ifndef CONFIG_DISABLE_PTHREAD - if ((tcb->flags & TCB_FLAG_TTYPE_MASK) != TCB_FLAG_TTYPE_PTHREAD) -#endif - { - /* This is a new task in a new task group, we have to copy the ID from - * the parent's task group structure to child's task group. - */ - - tcb->group->tg_pgid = rtcb->group->tg_gid; - } - -#else - DEBUGASSERT(tcb); - - /* Save the parent task's ID in the child task's TCB. I am not sure if - * this makes sense for the case of pthreads or not, but I don't think it - * is harmful in any event. - */ - - tcb->ppid = rtcb->pid; -#endif - -#ifdef CONFIG_SCHED_CHILD_STATUS - /* Tasks can also suppress retention of their child status by applying - * the SA_NOCLDWAIT flag with sigaction(). - */ - - if ((rtcb->group->tg_flags && GROUP_FLAG_NOCLDWAIT) == 0) - { - FAR struct child_status_s *child; - - /* Make sure that there is not already a structure for this PID in the - * parent TCB. There should not be. - */ - - child = group_findchild(rtcb->group, tcb->pid); - DEBUGASSERT(!child); - if (!child) - { - /* Allocate a new status structure */ - - child = group_allocchild(); - } - - /* Did we successfully find/allocate the child status structure? */ - - DEBUGASSERT(child); - if (child) - { - /* Yes.. Initialize the structure */ - - child->ch_flags = ttype; - child->ch_pid = tcb->pid; - child->ch_status = 0; - - /* Add the entry into the TCB list of children */ - - group_addchild(rtcb->group, child); - } - } -#else - DEBUGASSERT(rtcb->nchildren < UINT16_MAX); - rtcb->nchildren++; -#endif -} -#else -# define task_saveparent(tcb,ttype) -#endif - -/**************************************************************************** - * Name: task_dupdspace - * - * Description: - * When a new task or thread is created from a PIC module, then that - * module (probably) intends the task or thread to execute in the same - * D-Space. This function will duplicate the D-Space for that purpose. - * - * Parameters: - * tcb - The TCB of the new task. - * - * Returned Value: - * None - * - * Assumptions: - * The parent of the new task is the task at the head of the ready-to-run - * list. - * - ****************************************************************************/ - -#ifdef CONFIG_PIC -static inline void task_dupdspace(FAR struct tcb_s *tcb) -{ - FAR struct tcb_s *rtcb = (FAR struct tcb_s*)g_readytorun.head; - if (rtcb->dspace != NULL) - { - /* Copy the D-Space structure reference and increment the reference - * count on the memory. The D-Space memory will persist until the - * last thread exits (see sched_releasetcb()). - */ - - tcb->dspace = rtcb->dspace; - tcb->dspace->crefs++; - } -} -#else -# define task_dupdspace(tcb) -#endif - -/**************************************************************************** - * Name: thread_schedsetup - * - * Description: - * This functions initializes the common portions of the Task Control Block - * (TCB) in preparation for starting a new thread. - * - * thread_schedsetup() is called from task_schedsetup() and - * pthread_schedsetup(). - * - * Input Parameters: - * tcb - Address of the new task's TCB - * priority - Priority of the new task - * start - Thread startup routine - * entry - Thread user entry point - * ttype - Type of the new thread: task, pthread, or kernel thread - * - * Return Value: - * OK on success; ERROR on failure. - * - * This function can only failure is it is unable to assign a new, unique - * task ID to the TCB (errno is not set). - * - ****************************************************************************/ - -static int thread_schedsetup(FAR struct tcb_s *tcb, int priority, - start_t start, CODE void *entry, uint8_t ttype) -{ - int ret; - - /* Assign a unique task ID to the task. */ - - ret = task_assignpid(tcb); - if (ret == OK) - { - /* Save task priority and entry point in the TCB */ - - tcb->sched_priority = (uint8_t)priority; -#ifdef CONFIG_PRIORITY_INHERITANCE - tcb->base_priority = (uint8_t)priority; -#endif - tcb->start = start; - tcb->entry.main = (main_t)entry; - - /* Save the thread type. This setting will be needed in - * up_initial_state() is called. - */ - - ttype &= TCB_FLAG_TTYPE_MASK; - tcb->flags &= ~TCB_FLAG_TTYPE_MASK; - tcb->flags |= ttype; - - /* Save the task ID of the parent task in the TCB and allocate - * a child status structure. - */ - - task_saveparent(tcb, ttype); - - /* exec(), pthread_create(), task_create(), and vfork() all - * inherit the signal mask of the parent thread. - */ - -#ifndef CONFIG_DISABLE_SIGNALS - (void)sigprocmask(SIG_SETMASK, NULL, &tcb->sigprocmask); -#endif - - /* Initialize the task state. It does not get a valid state - * until it is activated. - */ - - tcb->task_state = TSTATE_TASK_INVALID; - - /* Clone the parent tasks D-Space (if it was running PIC). This - * must be done before calling up_initial_state() so that the - * state setup will take the PIC address base into account. - */ - - task_dupdspace(tcb); - - /* Initialize the processor-specific portion of the TCB */ - - up_initial_state(tcb); - - /* Add the task to the inactive task list */ - - sched_lock(); - dq_addfirst((FAR dq_entry_t*)tcb, (dq_queue_t*)&g_inactivetasks); - tcb->task_state = TSTATE_TASK_INACTIVE; - sched_unlock(); - } - - return ret; -} - -/**************************************************************************** - * Name: task_namesetup - * - * Description: - * Assign the task name. - * - * Input Parameters: - * tcb - Address of the new task's TCB - * name - Name of the new task - * - * Return Value: - * None - * - ****************************************************************************/ - -#if CONFIG_TASK_NAME_SIZE > 0 -static void task_namesetup(FAR struct task_tcb_s *tcb, FAR const char *name) -{ - /* Give a name to the unnamed tasks */ - - if (!name) - { - name = (FAR char *)g_noname; - } - - /* Copy the name into the TCB */ - - strncpy(tcb->cmn.name, name, CONFIG_TASK_NAME_SIZE); -} -#else -# define task_namesetup(t,n) -#endif /* CONFIG_TASK_NAME_SIZE */ - -/**************************************************************************** - * Name: task_tcbargsetup - * - * Description: - * This functions is called only from task_argsetup() in the "normal" - * case, where the argv[] array is a structure in the TCB. This function - * will clone all of the arguments using strdup. - * - * Input Parameters: - * tcb - Address of the new task's TCB - * argv - A pointer to an array of input parameters. - * Up to CONFIG_MAX_TASK_ARG parameters may be - * provided. If fewer than CONFIG_MAX_TASK_ARG - * parameters are passed, the list should be - * terminated with a NULL argv[] value. - * If no parameters are required, argv may be NULL. - * - * Return Value: - * OK. This function always succeeds. - * - ****************************************************************************/ - -#if defined(CONFIG_CUSTOM_STACK) || !defined(CONFIG_NUTTX_KERNEL) -static int task_tcbargsetup(FAR struct task_tcb_s *tcb, - FAR char * const argv[]) -{ - int i; - - /* Save the name as the first argument */ - -#if CONFIG_TASK_NAME_SIZE > 0 - tcb->argv[0] = tcb->cmn.name; -#else - tcb->argv[0] = (FAR char *)g_noname; -#endif /* CONFIG_TASK_NAME_SIZE */ - - /* For tasks, the life of the argument must be as long as the life of the - * task and the arguments must be strings. So for tasks, we have to dup - * the strings. - * - * The first NULL argument terminates the list of arguments. The argv - * pointer may be NULL if no parameters are passed. - */ - - i = 1; - if (argv) - { - for (; i < CONFIG_MAX_TASK_ARGS+1 && argv[i-1]; i++) - { - tcb->argv[i] = strdup(argv[i-1]); - } - } - - /* Nullify any unused argument storage */ - - for (; i < CONFIG_MAX_TASK_ARGS+1; i++) - { - tcb->argv[i] = NULL; - } - - return OK; -} -#endif /* CONFIG_CUSTOM_STACK || !CONFIG_NUTTX_KERNEL */ - -/**************************************************************************** - * Name: task_stackargsetup - * - * Description: - * This functions is called only from task_argsetup() for the case of the - * kernel build where the argv[] array and all strings are copied to the - * task's stack. This is done because the TCB (and kernel allocated - * strings) are only accessible in kernel-mode. Data on the stack, on the - * other hand, is guaranteed to be accessible no matter what mode the - * task runs in. - * - * Input Parameters: - * tcb - Address of the new task's TCB - * argv - A pointer to an array of input parameters. - * Up to CONFIG_MAX_TASK_ARG parameters may be - * provided. If fewer than CONFIG_MAX_TASK_ARG - * parameters are passed, the list should be - * terminated with a NULL argv[] value. - * If no parameters are required, argv may be NULL. - * - * Return Value: - * zero on success; a negated errno on failure. - * - ****************************************************************************/ - -#if !defined(CONFIG_CUSTOM_STACK) && defined(CONFIG_NUTTX_KERNEL) -static int task_stackargsetup(FAR struct task_tcb_s *tcb, - FAR char * const argv[]) -{ - FAR char **stackargv; - FAR const char *name; - FAR char *str; - size_t strtablen; - size_t argvlen; - int nbytes; - int argc; - int i; - - /* Get the name string that we will use as the first argument */ - -#if CONFIG_TASK_NAME_SIZE > 0 - name = tcb->cmn.name; -#else - name = (FAR const char *)g_noname; -#endif /* CONFIG_TASK_NAME_SIZE */ - - /* Get the size of the task name (including the NUL terminator) */ - - strtablen = (strlen(name) + 1); - - /* Count the number of arguments and get the accumulated size of the - * argument strings (including the null terminators). The argument count - * does not include the task name in that will be in argv[0]. - */ - - argc = 0; - if (argv) - { - for (; argc <= CONFIG_MAX_TASK_ARGS; argc++) - { - /* A NULL argument terminates the list */ - - if (!argv[argc]) - { - break; - } - - /* Add the size of this argument (with NUL terminator) */ - - strtablen += (strlen(argv[argc]) + 1); - } - } - - /* Allocate a stack frame to hold argv[] array and the strings. NOTE - * that argc + 2 entries are needed: The number of arguments plus the - * task name plus a NULL argv[] entry to terminate the list. - */ - - argvlen = (argc + 2)*sizeof(FAR char*); - stackargv = (FAR char **)up_stack_frame(&tcb->cmn, argvlen + strtablen); - - DEBUGASSERT(stackargv != NULL); - if (stackargv == NULL) - { - return -ENOMEM; - } - - /* Get the address of the string table that will lie immediately after - * the argv[] array and mark it as a null string. - */ - - str = (FAR char *)stackargv + argvlen; - - /* Copy the task name. Increment str to skip over the task name and its - * NUL terminator in the string buffer. - */ - - stackargv[0] = str; - nbytes = strlen(name) + 1; - strcpy(str, name); - str += nbytes; - - /* Copy each argument */ - - for (i = 0; i < argc; i++) - { - /* Save the pointer to the location in the string buffer and copy - * the argument into the buffer. Increment str to skip over the - * argument and its NUL terminator in the string buffer. - */ - - stackargv[i+1] = str; - nbytes = strlen(argv[i]) + 1; - strcpy(str, argv[i]); - str += nbytes; - } - - /* Put a terminator entry at the end of the argv[] array. Then save the - * argv[] arry pointer in the TCB where it will be recovered later by - * task_start(). - */ - - stackargv[argc + 1] = NULL; - tcb->argv = stackargv; - - return OK; -} -#endif /* !CONFIG_CUSTOM_STACK && CONFIG_NUTTX_KERNEL */ - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: task_schedsetup - * - * Description: - * This functions initializes a Task Control Block (TCB) in preparation - * for starting a new task. - * - * task_schedsetup() is called from task_init() and task_start(). - * - * Input Parameters: - * tcb - Address of the new task's TCB - * priority - Priority of the new task - * start - Start-up function (probably task_start()) - * main - Application start point of the new task - * ttype - Type of the new thread: task or kernel thread - * - * Return Value: - * OK on success; ERROR on failure. - * - * This function can only failure is it is unable to assign a new, unique - * task ID to the TCB (errno is not set). - * - ****************************************************************************/ - -int task_schedsetup(FAR struct task_tcb_s *tcb, int priority, start_t start, - main_t main, uint8_t ttype) -{ - int ret; - - /* Perform common thread setup */ - - ret = thread_schedsetup((FAR struct tcb_s *)tcb, priority, start, - (CODE void *)main, ttype); - if (ret == OK) - { - /* Save task restart priority */ - - tcb->init_priority = (uint8_t)priority; - } - - return ret; -} - -/**************************************************************************** - * Name: pthread_schedsetup - * - * Description: - * This functions initializes a Task Control Block (TCB) in preparation - * for starting a new pthread. - * - * pthread_schedsetup() is called from pthread_create(), - * - * Input Parameters: - * tcb - Address of the new task's TCB - * priority - Priority of the new task - * start - Start-up function (probably pthread_start()) - * entry - Entry point of the new pthread - * ttype - Type of the new thread: task, pthread, or kernel thread - * - * Return Value: - * OK on success; ERROR on failure. - * - * This function can only failure is it is unable to assign a new, unique - * task ID to the TCB (errno is not set). - * - ****************************************************************************/ - -#ifndef CONFIG_DISABLE_PTHREAD -int pthread_schedsetup(FAR struct pthread_tcb_s *tcb, int priority, start_t start, - pthread_startroutine_t entry) -{ - /* Perform common thread setup */ - - return thread_schedsetup((FAR struct tcb_s *)tcb, priority, start, - (CODE void *)entry, TCB_FLAG_TTYPE_PTHREAD); -} -#endif - -/**************************************************************************** - * Name: task_argsetup - * - * Description: - * This functions sets up parameters in the Task Control Block (TCB) in - * preparation for starting a new thread. - * - * task_argsetup() is called only from task_init() and task_start() to - * create a new task. In the "normal" case, the argv[] array is a - * structure in the TCB, the arguments are cloned via strdup. - * - * In the kernel build case, the argv[] array and all strings are copied - * to the task's stack. This is done because the TCB (and kernel allocated - * strings) are only accessible in kernel-mode. Data on the stack, on the - * other hand, is guaranteed to be accessible no matter what mode the - * task runs in. - * - * Input Parameters: - * tcb - Address of the new task's TCB - * name - Name of the new task (not used) - * argv - A pointer to an array of input parameters. - * Up to CONFIG_MAX_TASK_ARG parameters may be - * provided. If fewer than CONFIG_MAX_TASK_ARG - * parameters are passed, the list should be - * terminated with a NULL argv[] value. - * If no parameters are required, argv may be NULL. - * - * Return Value: - * OK - * - ****************************************************************************/ - -int task_argsetup(FAR struct task_tcb_s *tcb, FAR const char *name, - FAR char * const argv[]) -{ - int ret; - - /* Setup the task name */ - - task_namesetup(tcb, name); - -#if !defined(CONFIG_CUSTOM_STACK) && defined(CONFIG_NUTTX_KERNEL) - /* In the kernel build case, the argv[] array and all strings are copied - * to the task's stack. This is done because the TCB (and kernel allocated - * strings) are only accessible in kernel-mode. Data on the stack, on the - * other hand, is guaranteed to be accessible no matter what mode the - * task runs in. - */ - - ret = task_stackargsetup(tcb, argv); - -#else - /* In the "normal" case, the argv[] array is a structure in the TCB, the - * arguments are cloned via strdup. - */ - - ret = task_tcbargsetup(tcb, argv); - -#endif /* !CONFIG_CUSTOM_STACK && CONFIG_NUTTX_KERNEL */ - - return ret; -} diff --git a/nuttx/sched/task_spawn.c b/nuttx/sched/task_spawn.c deleted file mode 100644 index 541c62b11..000000000 --- a/nuttx/sched/task_spawn.c +++ /dev/null @@ -1,453 +0,0 @@ -/**************************************************************************** - * sched/task_spawn.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 "os_internal.h" -#include "group/group.h" -#include "spawn_internal.h" - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Public Data - ****************************************************************************/ - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: task_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 task_spawn_exec(FAR pid_t *pidp, FAR const char *name, - main_t entry, FAR const posix_spawnattr_t *attr, - FAR char * const *argv) -{ - size_t stacksize; - int priority; - int pid; - int ret = OK; - - /* 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(); - - /* Use the default task priority and stack size if no attributes are provided */ - - if (attr) - { - priority = attr->priority; - stacksize = attr->stacksize; - } - else - { - struct sched_param param; - - /* Set the default priority to the same priority as this task */ - - ret = sched_getparam(0, ¶m); - if (ret < 0) - { - goto errout; - } - - priority = param.sched_priority; - stacksize = CONFIG_TASK_SPAWN_DEFAULT_STACKSIZE; - } - - /* Start the task */ - - pid = TASK_CREATE(name, priority, stacksize, entry, argv); - if (pid < 0) - { - ret = errno; - sdbg("ERROR: TASK_CREATE 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) - { - (void)spawn_execattrs(pid, attr); - } - - /* Re-enable pre-emption and return */ - -errout: - sched_unlock(); - return ret; -} - -/**************************************************************************** - * Name: task_spawn_proxy - * - * Description: - * Perform file_actions, then execute the task from the file system. - * - * Do we really need a proxy task in this case? Isn't that wasteful? - * - * Q: Why can we do what we need to do here and the just call the - * new task's entry point. - * A: This would require setting up the name, priority, and stacksize from - * the task_spawn, but it do-able. The only issue I can think of is - * that NuttX supports task_restart(), and you would never be able to - * restart a task from this point. - * - * Q: Why not use a starthook so that there is callout from task_start() - * to perform these operations? - * A: Good idea, except that existing task_starthook() implementation - * cannot be used here unless we get rid of task_create and, instead, - * use task_init() and task_activate(). start_taskhook() could then - * be called between task_init() and task)activate(). task_restart() - * would still be an issue. - * - * Input Parameters: - * Standard task start-up parameters - * - * Returned Value: - * Standard task return value. - * - ****************************************************************************/ - -static int task_spawn_proxy(int argc, FAR char *argv[]) -{ - int ret; - - /* Perform file actions and/or set a custom signal mask. We get here only - * if the file_actions parameter to task_spawn[p] was non-NULL and/or the - * option to change the signal mask was selected. - */ - -#ifndef CONFIG_DISABLE_SIGNALS - DEBUGASSERT(g_spawn_parms.file_actions || - (g_spawn_parms.attr && - (g_spawn_parms.attr->flags & POSIX_SPAWN_SETSIGMASK) != 0)); -#else - DEBUGASSERT(g_spawn_parms.file_actions); -#endif - - /* Set the attributes and perform the file actions as appropriate */ - - ret = spawn_proxyattrs(g_spawn_parms.attr, g_spawn_parms.file_actions); - if (ret == OK) - { - /* Start the task */ - - ret = task_spawn_exec(g_spawn_parms.pid, g_spawn_parms.u.task.name, - g_spawn_parms.u.task.entry, g_spawn_parms.attr, - g_spawn_parms.argv); - -#ifdef CONFIG_SCHED_HAVE_PARENT - if (ret == OK) - { - /* Change of the parent of the task we just spawned to our parent. - * What should we do in the event of a failure? - */ - - int tmp = task_reparent(0, *g_spawn_parms.pid); - if (tmp < 0) - { - 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_spawn_parms.result = ret; -#ifndef CONFIG_SCHED_WAITPID - spawn_semgive(&g_spawn_execsem); -#endif - return OK; -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: task_spawn - * - * Description: - * The task_spawn() function will create a new, child task, where the - * entry point to the task is an address in memory. - * - * Input Parameters: - * - * pid - Upon successful completion, task_spawn() 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. - * - * name - The name to assign to the child task. - * - * entry - The child task's entry point (an address in memory) - * - * 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 - * task_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. - * - * And the non-standard: - * - * - TASK_SPAWN_SETSTACKSIZE: Set the stack size for the new task. - * - * 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. - * - * Returned Value: - * task_spawn() 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. - * - ****************************************************************************/ - -int task_spawn(FAR pid_t *pid, FAR const char *name, main_t entry, - FAR const posix_spawn_file_actions_t *file_actions, - FAR const posix_spawnattr_t *attr, - FAR char *const argv[], FAR char *const envp[]) -{ - struct sched_param param; - pid_t proxy; -#ifdef CONFIG_SCHED_WAITPID - int status; -#endif - int ret; - - svdbg("pid=%p name=%s entry=%p file_actions=%p attr=%p argv=%p\n", - pid, name, entry, file_actions, attr, argv); - - /* If there are no file actions to be performed and there is no change to - * the signal mask, then start the new child task directly from the parent task. - */ - -#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 task_spawn_exec(pid, name, entry, 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_spawn_parmsem); - - /* Populate the parameter structure */ - - g_spawn_parms.result = ENOSYS; - g_spawn_parms.pid = pid; - g_spawn_parms.file_actions = file_actions ? *file_actions : NULL; - g_spawn_parms.attr = attr; - g_spawn_parms.argv = argv; - g_spawn_parms.u.task.name = name; - g_spawn_parms.u.task.entry = entry; - - /* 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_spawn_parmsem); - return errcode; - } - - /* Disable pre-emption so that the proxy does not run until waitpid - * is called. This is probably unnecessary since the task_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("task_spawn_proxy", param.sched_priority, - CONFIG_POSIX_SPAWN_PROXY_STACKSIZE, - (main_t)task_spawn_proxy, - (FAR char * const*)NULL); - if (proxy < 0) - { - ret = get_errno(); - sdbg("ERROR: Failed to start task_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_spawn_execsem); -#endif - - /* Get the result and relinquish our access to the parameter structure */ - - ret = g_spawn_parms.result; - -errout_with_lock: -#ifdef CONFIG_SCHED_WAITPID - sched_unlock(); -#endif - spawn_semgive(&g_spawn_parmsem); - return ret; -} diff --git a/nuttx/sched/task_spawnparms.c b/nuttx/sched/task_spawnparms.c deleted file mode 100644 index 25cb86531..000000000 --- a/nuttx/sched/task_spawnparms.c +++ /dev/null @@ -1,340 +0,0 @@ -/**************************************************************************** - * sched/task_spawnparms.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 "spawn_internal.h" - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Public Data - ****************************************************************************/ - -sem_t g_spawn_parmsem = SEM_INITIALIZER(1); -#ifndef CONFIG_SCHED_WAITPID -sem_t g_spawn_execsem = SEM_INITIALIZER(0); -#endif -struct spawn_parms_s g_spawn_parms; - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * 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; -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: spawn_semtake and spawn_semgive - * - * Description: - * Give and take semaphores - * - * Input Parameters: - * - * sem - The semaphore to act on. - * - * Returned Value: - * None - * - ****************************************************************************/ - -void spawn_semtake(FAR sem_t *sem) -{ - int ret; - - do - { - ret = sem_wait(sem); - ASSERT(ret == 0 || errno == EINTR); - } - while (ret != 0); -} - -/**************************************************************************** - * Name: spawn_execattrs - * - * Description: - * Set attributes of the new child task after it has been spawned. - * - * Input Parameters: - * - * pid - The pid of the new task. - * attr - The attributes to use - * - * Returned Value: - * Errors are not reported by this function. This is because errors - * cannot occur, but ratther that the new task has already been started - * so there is no graceful way to handle errors detected in this context - * (unless we delete the new task and recover). - * - * Assumptions: - * That task has been started but has not yet executed because pre- - * emption is disabled. - * - ****************************************************************************/ - -int spawn_execattrs(pid_t pid, FAR const posix_spawnattr_t *attr) -{ - struct sched_param param; - - DEBUGASSERT(attr); - - /* 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 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); - } - - return OK; -} - -/**************************************************************************** - * Name: spawn_proxyattrs - * - * Description: - * Set attributes of the proxy task before it has started the new child - * task. - * - * Input Parameters: - * - * pid - The pid of the new task. - * attr - The attributes to use - * file_actions - The attributes to use - * - * Returned Value: - * 0 (OK) on successed; A negated errno value is returned on failure. - * - ****************************************************************************/ - -int spawn_proxyattrs(FAR const posix_spawnattr_t *attr, - FAR const posix_spawn_file_actions_t *file_actions) -{ - FAR struct spawn_general_file_action_s *entry; - int ret = OK; - - /* 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 (file_actions) -#endif - { - /* Yes.. Execute each file action */ - - for (entry = (FAR struct spawn_general_file_action_s *)file_actions; - entry && ret == OK; - entry = entry->flink) - { - switch (entry->action) - { - 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; - } - } - } - - return ret; -} diff --git a/nuttx/sched/task_start.c b/nuttx/sched/task_start.c deleted file mode 100644 index e9667d486..000000000 --- a/nuttx/sched/task_start.c +++ /dev/null @@ -1,144 +0,0 @@ -/**************************************************************************** - * sched/task_start.c - * - * Copyright (C) 2007-2010, 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 "os_internal.h" - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/**************************************************************************** - * Private Type Declarations - ****************************************************************************/ - -/**************************************************************************** - * Global Variables - ****************************************************************************/ - -/**************************************************************************** - * Private Variables - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: task_start - * - * Description: - * This function is the low level entry point into the main thread of - * execution of a task. It receives initial control when the task is - * started and calls main entry point of the newly started task. - * - * Inputs: - * None - * - * Return: - * None - * - ****************************************************************************/ - -void task_start(void) -{ - FAR struct task_tcb_s *tcb = (FAR struct task_tcb_s*)g_readytorun.head; - int exitcode; - int argc; - - DEBUGASSERT((tcb->cmn.flags & TCB_FLAG_TTYPE_MASK) != TCB_FLAG_TTYPE_PTHREAD); - - /* Execute the start hook if one has been registered */ - -#ifdef CONFIG_SCHED_STARTHOOK - if (tcb->starthook) - { - tcb->starthook(tcb->starthookarg); - } -#endif - - /* Count how many non-null arguments we are passing */ - - for (argc = 1; argc <= CONFIG_MAX_TASK_ARGS; argc++) - { - /* The first non-null argument terminates the list */ - - if (!tcb->argv[argc]) - { - break; - } - } - - /* Call the 'main' entry point passing argc and argv. In the kernel build - * this has to be handled differently if we are starting a user-space task; - * we have to switch to user-mode before calling the task. - */ - -#ifdef CONFIG_NUTTX_KERNEL - if ((tcb->cmn.flags & TCB_FLAG_TTYPE_MASK) != TCB_FLAG_TTYPE_KERNEL) - { - up_task_start(tcb->cmn.entry.main, argc, tcb->argv); - exitcode = EXIT_FAILURE; /* Should not get here */ - } - else -#endif - { - exitcode = tcb->cmn.entry.main(argc, tcb->argv); - } - - /* Call exit() if/when the task returns */ - - exit(exitcode); -} diff --git a/nuttx/sched/task_starthook.c b/nuttx/sched/task_starthook.c deleted file mode 100644 index 7fa0757aa..000000000 --- a/nuttx/sched/task_starthook.c +++ /dev/null @@ -1,111 +0,0 @@ -/**************************************************************************** - * sched/task_starthook.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 - -#ifdef CONFIG_SCHED_STARTHOOK - -/**************************************************************************** - * Definitions - ****************************************************************************/ - -/**************************************************************************** - * Private Type Declarations - ****************************************************************************/ - -/**************************************************************************** - * Global Variables - ****************************************************************************/ - -/**************************************************************************** - * Private Variables - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: task_starthook - * - * Description: - * Configure a start hook... a function that will be called on the thread - * of the new task before the new task's main entry point is called. - * The start hook is useful, for example, for setting up automatic - * configuration of C++ constructors. - * - * Inputs: - * tcb - The new, unstarted task task that needs the start hook - * starthook - The pointer to the start hook function - * arg - The argument to pass to the start hook function. - * - * Return: - * None - * - ****************************************************************************/ - -void task_starthook(FAR struct task_tcb_s *tcb, starthook_t starthook, - FAR void *arg) -{ - /* Only tasks can have starthooks. The starthook will be called when the - * task is started (or restarted). - */ - -#ifndef CONFIG_DISABLE_PTHREAD - DEBUGASSERT(tcb && - (tcb->cmn.flags & TCB_FLAG_TTYPE_MASK) != TCB_FLAG_TTYPE_PTHREAD); -#endif - - /* Set up the start hook */ - - tcb->starthook = starthook; - tcb->starthookarg = arg; -} - -#endif /* CONFIG_SCHED_STARTHOOK */ diff --git a/nuttx/sched/task_terminate.c b/nuttx/sched/task_terminate.c deleted file mode 100644 index 11438d22d..000000000 --- a/nuttx/sched/task_terminate.c +++ /dev/null @@ -1,188 +0,0 @@ -/**************************************************************************** - * sched/task_terminate.c - * - * Copyright (C) 2007-2009, 2011-2014 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 "os_internal.h" -#ifndef CONFIG_DISABLE_SIGNALS -# include "signal/signal.h" -#endif - -/**************************************************************************** - * Definitions - ****************************************************************************/ - -/**************************************************************************** - * Private Type Declarations - ****************************************************************************/ - -/**************************************************************************** - * Global Variables - ****************************************************************************/ - -/**************************************************************************** - * Private Variables - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: task_terminate - * - * Description: - * This function causes a specified task to cease to exist. Its stack and - * TCB will be deallocated. This function is the internal implementation - * of the task_delete() function. It includes and additional parameter - * to determine if blocking is permitted or not. - * - * This function is the final function called all task termination - * sequences. task_terminate() is called only from task_delete() (with - * nonblocking == false) and from task_exit() (with nonblocking == true). - * - * The path through task_exit() supports the final stops of the exit(), - * _exit(), and pthread_exit - * - * - pthread_exit(). Calls _exit() - * - exit(). Calls _exit() - * - _exit(). Calls task_exit() making the currently running task - * non-running. task_exit then calls task_terminate() (with nonblocking - * == true) to terminate the non-running task. - * - * NOTE: that the state of non-blocking is irrelevant when called through - * exit() and pthread_exit(). In those cases task_exithook() has already - * been called with nonblocking == false; - * - * Inputs: - * pid - The task ID of the task to delete. A pid of zero - * signifies the calling task. - * nonblocking - True: The task is an unhealthy, partially torn down - * state and is not permitted to block. - * - * Return Value: - * OK on success; or ERROR on failure - * - * This function can fail if the provided pid does not correspond to a - * task (errno is not set) - * - ****************************************************************************/ - -int task_terminate(pid_t pid, bool nonblocking) -{ - FAR struct tcb_s *dtcb; - irqstate_t saved_state; - - /* Make sure the task does not become ready-to-run while we are futzing with - * its TCB by locking ourselves as the executing task. - */ - - sched_lock(); - - /* Find for the TCB associated with matching PID */ - - dtcb = sched_gettcb(pid); - if (!dtcb) - { - /* This PID does not correspond to any known task */ - - sched_unlock(); - return -ESRCH; - } - - /* Verify our internal sanity */ - - if (dtcb->task_state == TSTATE_TASK_RUNNING || - dtcb->task_state >= NUM_TASK_STATES) - { - sched_unlock(); - PANIC(); - } - - /* Perform common task termination logic (flushing streams, calling - * functions registered by at_exit/on_exit, etc.). We need to do - * this as early as possible so that higher level clean-up logic - * can run in a healthy tasking environment. - * - * In the case where the task exits via exit(), task_exithook() - * may be called twice. - * - * I suppose EXIT_SUCCESS is an appropriate return value??? - */ - - task_exithook(dtcb, EXIT_SUCCESS, nonblocking); - - /* Remove the task from the OS's tasks lists. */ - - saved_state = irqsave(); - dq_rem((FAR dq_entry_t*)dtcb, (dq_queue_t*)g_tasklisttable[dtcb->task_state].list); - dtcb->task_state = TSTATE_TASK_INVALID; - irqrestore(saved_state); - - /* At this point, the TCB should no longer be accessible to the system */ - - sched_unlock(); - - /* Since all tasks pass through this function as the final step in their - * exit sequence, this is an appropriate place to inform any instrumentation - * layer that the task no longer exists. - */ - - sched_note_stop(dtcb); - - /* Deallocate its TCB */ - - return sched_releasetcb(dtcb, dtcb->flags & TCB_FLAG_TTYPE_MASK); -} diff --git a/nuttx/sched/task_vfork.c b/nuttx/sched/task_vfork.c deleted file mode 100644 index 706ef864d..000000000 --- a/nuttx/sched/task_vfork.c +++ /dev/null @@ -1,344 +0,0 @@ -/**************************************************************************** - * sched/task_vfork - * - * 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 "os_internal.h" -#include "group/group.h" - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ -/* vfork() requires architecture-specific support as well as waipid(). */ - -#if defined(CONFIG_ARCH_HAVE_VFORK) && defined(CONFIG_SCHED_WAITPID) - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: task_vforksetup - * - * Description: - * The vfork() function has the same effect as fork(), except that the - * behavior is undefined if the process created by vfork() either modifies - * any data other than a variable of type pid_t used to store the return - * value from vfork(), or returns from the function in which vfork() was - * called, or calls any other function before successfully calling _exit() - * or one of the exec family of functions. - * - * This functin provides one step in the overall vfork() sequence: It - * Allocates and initializes the child task's TCB. The overall sequence is: - * - * 1) User code calls vfork(). vfork() is provided in architecture-specific - * code. - * 2) vfork()and calls task_vforksetup(). - * 3) task_vforksetup() allocates and configures the child task's TCB. This - * consists of: - * - Allocation of the child task's TCB. - * - Initialization of file descriptors and streams - * - Configuration of environment variables - * - Setup the intput parameters for the task. - * - Initialization of the TCB (including call to up_initial_state() - * 4) up_vfork() provides any additional operating context. up_vfork must: - * - Allocate and initialize the stack - * - Initialize special values in any CPU registers that were not - * already configured by up_initial_state() - * 5) up_vfork() then calls task_vforkstart() - * 6) task_vforkstart() then executes the child thread. - * - * Input Paremeters: - * retaddr - The return address from vfork() where the child task - * will be started. - * - * Returned Value: - * Upon successful completion, task_vforksetup() returns a pointer to - * newly allocated and initalized child task's TCB. NULL is returned - * on any failure and the errno is set appropriately. - * - ****************************************************************************/ - -FAR struct task_tcb_s *task_vforksetup(start_t retaddr) -{ - struct tcb_s *parent = (FAR struct tcb_s *)g_readytorun.head; - struct task_tcb_s *child; - uint8_t ttype; - int priority; - int ret; - - DEBUGASSERT(retaddr); - - /* Get the type of the fork'ed task (kernel or user) */ - - if ((parent->flags & TCB_FLAG_TTYPE_MASK) == TCB_FLAG_TTYPE_KERNEL) - { - /* Fork'ed from a kernel thread */ - - ttype = TCB_FLAG_TTYPE_KERNEL; - } - else - { - /* Fork'ed from a user task or pthread */ - - ttype = TCB_FLAG_TTYPE_TASK; - } - - /* Allocate a TCB for the child task. */ - - child = (FAR struct task_tcb_s *)kzalloc(sizeof(struct task_tcb_s)); - if (!child) - { - sdbg("ERROR: Failed to allocate TCB\n"); - set_errno(ENOMEM); - return NULL; - } - - /* Allocate a new task group */ - -#ifdef HAVE_TASK_GROUP - ret = group_allocate(child); - if (ret < 0) - { - goto errout_with_tcb; - } -#endif - - /* Associate file descriptors with the new task */ - -#if CONFIG_NFILE_DESCRIPTORS > 0 || CONFIG_NSOCKET_DESCRIPTORS > 0 - ret = group_setuptaskfiles(child); - if (ret < OK) - { - goto errout_with_tcb; - } -#endif - - /* Get the priority of the parent task */ - -#ifdef CONFIG_PRIORITY_INHERITANCE - priority = parent->base_priority; /* "Normal," unboosted priority */ -#else - priority = parent->sched_priority; /* Current priority */ -#endif - - /* Initialize the task control block. This calls up_initial_state() */ - - svdbg("Child priority=%d start=%p\n", priority, retaddr); - ret = task_schedsetup(child, priority, retaddr, parent->entry.main, ttype); - if (ret < OK) - { - goto errout_with_tcb; - } - - svdbg("parent=%p, returning child=%p\n", parent, child); - return child; - -errout_with_tcb: - sched_releasetcb((FAR struct tcb_s *)child, ttype); - set_errno(-ret); - return NULL; -} - -/**************************************************************************** - * Name: task_vforkstart - * - * Description: - * The vfork() function has the same effect as fork(), except that the - * behavior is undefined if the process created by vfork() either modifies - * any data other than a variable of type pid_t used to store the return - * value from vfork(), or returns from the function in which vfork() was - * called, or calls any other function before successfully calling _exit() - * or one of the exec family of functions. - * - * This functin provides one step in the overall vfork() sequence: It - * starts execution of the previously initialized TCB. The overall - * sequence is: - * - * 1) User code calls vfork() - * 2) Architecture-specific code provides vfork()and calls task_vforksetup(). - * 3) task_vforksetup() allocates and configures the child task's TCB. This - * consists of: - * - Allocation of the child task's TCB. - * - Initialization of file descriptors and streams - * - Configuration of environment variables - * - Setup the intput parameters for the task. - * - Initialization of the TCB (including call to up_initial_state() - * 4) vfork() provides any additional operating context. vfork must: - * - Allocate and initialize the stack - * - Initialize special values in any CPU registers that were not - * already configured by up_initial_state() - * 5) vfork() then calls task_vforkstart() - * 6) task_vforkstart() then executes the child thread. - * - * Input Paremeters: - * retaddr - The return address from vfork() where the child task - * will be started. - * - * Returned Value: - * Upon successful completion, vfork() returns 0 to the child process and - * returns the process ID of the child process to the parent process. - * Otherwise, -1 is returned to the parent, no child process is created, - * and errno is set to indicate the error. - * - ****************************************************************************/ - -pid_t task_vforkstart(FAR struct task_tcb_s *child) -{ -#if CONFIG_TASK_NAME_SIZE > 0 - struct tcb_s *parent = (FAR struct tcb_s *)g_readytorun.head; -#endif - FAR const char *name; - pid_t pid; - int rc; - int ret; - - svdbg("Starting Child TCB=%p, parent=%p\n", child, g_readytorun.head); - DEBUGASSERT(child); - - /* Setup to pass parameters to the new task */ - -#if CONFIG_TASK_NAME_SIZE > 0 - name = parent->name; -#else - name = NULL; -#endif - - (void)task_argsetup(child, name, (FAR char * const *)NULL); - - /* Now we have enough in place that we can join the group */ - -#ifdef HAVE_TASK_GROUP - ret = group_initialize(child); - if (ret < 0) - { - task_vforkabort(child, -ret); - return ERROR; - } -#endif - - /* Get the assigned pid before we start the task */ - - pid = (int)child->cmn.pid; - - /* Activate the task */ - - ret = task_activate((FAR struct tcb_s *)child); - if (ret < OK) - { - task_vforkabort(child, -ret); - return ERROR; - } - - /* Since the child task has the same priority as the parent task, it is - * now ready to run, but has not yet ran. It is a requirement that - * the parent enivornment be stable while vfork runs; the child thread - * is still dependent on things in the parent thread... like the pointers - * into parent thread's stack which will still appear in the child's - * registers and environment. - * - * We do not have SIG_CHILD, so we have to do some silly things here. - * The simplest way to make sure that the child thread runs to completion - * is simply to yield here. Since the child can only do exit() or - * execv/l(), that should be all that is needed. - * - * Hmmm.. this is probably not sufficient. What if we are running - * SCHED_RR? What if the child thread is suspeneded and rescheduled - * after the parent thread again? - */ - - /* We can also exploit a bug in the execv() implementation: The PID - * of the task exec'ed by the child will not be the same as the PID of - * the child task. Therefore, waitpid() on the child task's PID will - * accomplish what we need to do. - */ - - rc = 0; - -#ifdef CONFIG_DEBUG - ret = waitpid(pid, &rc, 0); - if (ret < 0) - { - sdbg("ERROR: waitpid failed: %d\n", errno); - } -#else - (void)waitpid(pid, &rc, 0); -#endif - - return pid; -} - -/**************************************************************************** - * Name: task_vforkabort - * - * Description: - * Recover from any errors after task_vforksetup() was called. - * - * Returned Value: - * None - * - ****************************************************************************/ - -void task_vforkabort(FAR struct task_tcb_s *child, int errcode) -{ - /* The TCB was added to the active task list by task_schedsetup() */ - - dq_rem((FAR dq_entry_t*)child, (dq_queue_t*)&g_inactivetasks); - - /* Release the TCB */ - - sched_releasetcb((FAR struct tcb_s *)child, - child->cmn.flags & TCB_FLAG_TTYPE_MASK); - set_errno(errcode); -} - -#endif /* CONFIG_ARCH_HAVE_VFORK && CONFIG_SCHED_WAITPID */ -- cgit v1.2.3