diff options
author | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2013-01-07 19:35:47 +0000 |
---|---|---|
committer | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2013-01-07 19:35:47 +0000 |
commit | a5f001189e1a056be275e1d736e38893f96cd395 (patch) | |
tree | fca977319643c4fcdbaeecbd38ee572fb9c31ae1 /nuttx | |
parent | 876062fe3a2b6273855b77c0ed1c9d0cbcfc43c6 (diff) | |
download | px4-firmware-a5f001189e1a056be275e1d736e38893f96cd395.tar.gz px4-firmware-a5f001189e1a056be275e1d736e38893f96cd395.tar.bz2 px4-firmware-a5f001189e1a056be275e1d736e38893f96cd395.zip |
This initial vfork() check-in was a little pollyanna-ish
git-svn-id: http://svn.code.sf.net/p/nuttx/code/trunk@5487 42af7a65-404d-4744-a932-0658087f49c3
Diffstat (limited to 'nuttx')
24 files changed, 598 insertions, 75 deletions
diff --git a/nuttx/arch/arm/src/arm/up_vfork.S b/nuttx/arch/arm/src/arm/vfork.S index 23e975c30..f0fe17f73 100644 --- a/nuttx/arch/arm/src/arm/up_vfork.S +++ b/nuttx/arch/arm/src/arm/vfork.S @@ -1,5 +1,5 @@ /************************************************************************************ - * arch/arm/src/arm/up_vfork.S + * arch/arm/src/arm/vfork.S * * Copyright (C) 2013 Gregory Nutt. All rights reserved. * Author: Gregory Nutt <gnutt@nuttx.org> @@ -39,6 +39,8 @@ #include <nuttx/config.h> +#include "up_vfork.h" + /************************************************************************************ * Pre-processor Definitions ************************************************************************************/ @@ -47,8 +49,8 @@ * Global Symbols ************************************************************************************/ - .file "up_vfork.S" - .globl __vfork + .file "vfork.S" + .globl task_vfork /************************************************************************************ * Public Functions @@ -64,8 +66,25 @@ * 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 thin layer implements vfork by simply calling __vfork() with the vfork() - * return address as an argument. + * This thin layer implements vfork by simply calling task_vfork() with the vfork() + * context as an argument. The overall sequence is: + * + * 1) User code calls vfork(). vfork() collects context information and + * transfers control up up_vfork(). + * 2) up_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: * None @@ -81,12 +100,35 @@ .globl vfork .type vfork, function vfork: + /* Create a stack frame */ + + mov r0, sp /* Save the value of the stack frame on entry */ + sub sp, sp, #VFORK_SIZEOF /* Allocate the structure on the stack */ + + /* Save the volatile registers */ + + str r4, [sp, #VFORK_R4_OFFSET] + str r5, [sp, #VFORK_R5_OFFSET] + str r6, [sp, #VFORK_R6_OFFSET] + str r7, [sp, #VFORK_R7_OFFSET] + str r8, [sp, #VFORK_R8_OFFSET] + str r9, [sp, #VFORK_R9_OFFSET] + str r10, [sp, #VFORK_R10_OFFSET] + + /* Save the frame pointer, stack pointer, and return address */ + + str fp, [sp, #VFORK_FP_OFFSET] + str r0, [sp, #VFORK_SP_OFFSET] + str lr, [sp, #VFORK_LR_OFFSET] + + /* Then, call task_vfork(), passing it a pointer to the stack structure */ + + mov r0, sp + bl task_vfork - /* I know, I could have used the GCC's return address builtin and done this all - * in C. But this works even if there is no builtin. - */ + /* Release the stack data and return the value returned by task_vfork */ - mov r0, lr - b __vfork + add sp, sp, #VFORK_SIZEOF + mov pc, lr .size vfork, .-vfork .end diff --git a/nuttx/arch/arm/src/armv7-m/up_vfork.S b/nuttx/arch/arm/src/armv7-m/vfork.S index 65ccc4535..aceded400 100644 --- a/nuttx/arch/arm/src/armv7-m/up_vfork.S +++ b/nuttx/arch/arm/src/armv7-m/vfork.S @@ -1,5 +1,5 @@ /************************************************************************************ - * arch/arm/src/armv7-m/up_vfork.S + * arch/arm/src/armv7-m/vfork.S * * Copyright (C) 2013 Gregory Nutt. All rights reserved. * Author: Gregory Nutt <gnutt@nuttx.org> @@ -39,6 +39,8 @@ #include <nuttx/config.h> +#include "up_vfork.h" + /************************************************************************************ * Pre-processor Definitions ************************************************************************************/ @@ -49,8 +51,8 @@ .syntax unified .thumb - .file "up_vfork.S" - .globl __vfork + .file "vfork.S" + .globl task_vfork /************************************************************************************ * Public Functions @@ -66,8 +68,25 @@ * 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 thin layer implements vfork by simply calling __vfork() with the vfork() - * return address as an argument. + * This thin layer implements vfork by simply calling task_vfork() with the vfork() + * context as an argument. The overall sequence is: + * + * 1) User code calls vfork(). vfork() collects context information and + * transfers control up up_vfork(). + * 2) up_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: * None @@ -84,13 +103,36 @@ .globl vfork .type vfork, function vfork: + /* Create a stack frame */ + + mov r0, sp /* Save the value of the stack frame on entry */ + sub sp, sp, #VFORK_SIZEOF /* Allocate the structure on the stack */ + + /* Save the volatile registers */ + + str r4, [sp, #VFORK_R4_OFFSET] + str r5, [sp, #VFORK_R5_OFFSET] + str r6, [sp, #VFORK_R6_OFFSET] + str r7, [sp, #VFORK_R7_OFFSET] + str r8, [sp, #VFORK_R8_OFFSET] + str r9, [sp, #VFORK_R9_OFFSET] + str r10, [sp, #VFORK_R10_OFFSET] + + /* Save the frame pointer, stack pointer, and return address */ + + str fp, [sp, #VFORK_FP_OFFSET] + str r0, [sp, #VFORK_SP_OFFSET] + str lr, [sp, #VFORK_LR_OFFSET] + + /* Then, call task_vfork(), passing it a pointer to the stack structure */ + + mov r0, sp + bl task_vfork - /* I know, I could have used the GCC's return address builtin and done this all - * in C. But this works even if there is no builtin. - */ + /* Release the stack data and return the value returned by task_vfork */ - mov r0, lr - b __vfork + add sp, sp, #VFORK_SIZEOF + bx lr .size vfork, .-vfork .end diff --git a/nuttx/arch/arm/src/c5471/Make.defs b/nuttx/arch/arm/src/c5471/Make.defs index 89c3aaf0b..afa73cf6c 100644 --- a/nuttx/arch/arm/src/c5471/Make.defs +++ b/nuttx/arch/arm/src/c5471/Make.defs @@ -35,14 +35,14 @@ HEAD_ASRC = up_nommuhead.S -CMN_ASRCS = up_saveusercontext.S up_fullcontextrestore.S up_vfork.S +CMN_ASRCS = up_saveusercontext.S up_fullcontextrestore.S vfork.S CMN_CSRCS = up_allocateheap.c up_assert.c up_blocktask.c up_copystate.c \ up_createstack.c up_dataabort.c up_mdelay.c up_udelay.c up_doirq.c \ up_exit.c up_idle.c up_initialize.c up_initialstate.c \ up_interruptcontext.c up_prefetchabort.c up_releasepending.c \ up_releasestack.c up_reprioritizertr.c up_schedulesigaction.c \ up_sigdeliver.c up_syscall.c up_unblocktask.c \ - up_undefinedinsn.c up_usestack.c up__vfork.c + up_undefinedinsn.c up_usestack.c up_vfork.c ifeq ($(CONFIG_ELF),y) CMN_CSRCS += up_elf.c diff --git a/nuttx/arch/arm/src/calypso/Make.defs b/nuttx/arch/arm/src/calypso/Make.defs index 957d4e677..1a1d14869 100644 --- a/nuttx/arch/arm/src/calypso/Make.defs +++ b/nuttx/arch/arm/src/calypso/Make.defs @@ -39,14 +39,14 @@ HEAD_ASRC = calypso_head.S CMN_ASRCS = up_saveusercontext.S up_fullcontextrestore.S up_vectors.S \ - up_nommuhead.S up_vfork.S + up_nommuhead.S vfork.S CMN_CSRCS = up_allocateheap.c up_assert.c up_blocktask.c up_copystate.c \ up_createstack.c up_dataabort.c up_mdelay.c up_udelay.c up_doirq.c \ up_exit.c up_idle.c up_initialstate.c up_initialize.c \ up_interruptcontext.c up_prefetchabort.c up_releasepending.c \ up_releasestack.c up_reprioritizertr.c up_schedulesigaction.c \ up_sigdeliver.c up_syscall.c up_unblocktask.c \ - up_undefinedinsn.c up_usestack.c calypso_power.c up__vfork.c + up_undefinedinsn.c up_usestack.c calypso_power.c up_vfork.c ifeq ($(CONFIG_ELF),y) CMN_CSRCS += up_elf.c diff --git a/nuttx/arch/arm/src/common/up__vfork.c b/nuttx/arch/arm/src/common/up_vfork.c index a1081faa8..404abd1f8 100644 --- a/nuttx/arch/arm/src/common/up__vfork.c +++ b/nuttx/arch/arm/src/common/up_vfork.c @@ -1,5 +1,5 @@ /**************************************************************************** - * arch/arm/src/common/up__vfork + * arch/arm/src/common/up_vfork.c * * Copyright (C) 2013 Gregory Nutt. All rights reserved. * Author: Gregory Nutt <gnutt@nuttx.org> @@ -39,10 +39,16 @@ #include <nuttx/config.h> -#include <sched.h> +#include <stdint.h> +#include <string.h> +#include <assert.h> +#include <errno.h> #include <nuttx/sched.h> +#include <nuttx/arch.h> +#include <arch/irq.h> +#include "up_vfork.h" #include "os_internal.h" /**************************************************************************** @@ -75,7 +81,7 @@ ****************************************************************************/ /**************************************************************************** - * Name: __vfork + * Name: up_vfork * * Description: * The vfork() function has the same effect as fork(), except that the @@ -85,11 +91,29 @@ * called, or calls any other function before successfully calling _exit() * or one of the exec family of functions. * - * This thin layer starts the vfork child by simply spawning a new thread - * that begins at the return address of vfork(). + * The overall sequence is: + * + * 1) User code calls vfork(). vfork() collects context information and + * transfers control up up_vfork(). + * 2) up_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. + * + * task_vforkabort() may be called if an error occurs between steps 3 and 6. * * Input Paremeters: - * retaddr - The return address of vfork() + * context - Caller context information saved by vfork() * * Return: * Upon successful completion, vfork() returns 0 to the child process and @@ -99,11 +123,22 @@ * ****************************************************************************/ -pid_t __vfork(uint32_t retaddr) +pid_t up_vfork(struct vfork_s *context) { - FAR _TCB *parent = (FAR _TCB *)g_readytorun.head; + _TCB *parent = (FAR _TCB *)g_readytorun.head; + _TCB *child; size_t stacksize; - int priority; + uint32_t newsp; + uint32_t stackutil; + int ret; + + /* Allocate and initialize a TCB for the child task. */ + + child = task_vforksetup((start_t)context->lr); + if (!child) + { + return (pid_t)ERROR; + } /* Get the size of the parent task's stack. Due to alignment operations, * the adjusted stack size may be smaller than the stack size originally @@ -112,23 +147,50 @@ pid_t __vfork(uint32_t retaddr) stacksize = parent->adj_stack_size + CONFIG_STACK_ALIGNMENT - 1; - /* Get the current priority of the parent task */ + /* Allocate the stack for the TCB */ -#ifdef CONFIG_PRIORITY_INHERITANCE - priority = parent->base_priority; /* "Normal," unboosted priority */ -#else - priority = parent->sched_priority; /* Current priority */ -#endif + ret = up_create_stack(child, stacksize); + if (ret != OK) + { + task_vforkabort(child, -ret); + return (pid_t)ERROR; + } + + /* How much of the parent's stack was utilized? */ - /* Start the child thread at the vfork return address. TASK_CREATE will - * return the PID of the new thread. Otherwise a negative value will be - * returned and the errno will be set appropriately. - * - * When the registers are initialized, the return value in R0 should be - * cleared to zero, providing the indication to the newly started child - * thread. + DEBUGASSERT(parent->adj_stack_ptr > context->sp); + stackutil = (uint32_t)parent->adj_stack_ptr - context->sp; + + /* Make some feeble effort to perserve the stack contents. This is + * feeble because the stack surely contains invalid pointer and other + * content that will not work in the child context. However, if the + * user follows all of the caveats of vfor() usage, even this feeble + * effort is overkill. + */ + + newsp = (uint32_t)child->adj_stack_ptr - stackutil; + memcpy((void *)newsp, (const void *)context->sp, stackutil); + + /* Update the stack pointer, frame pointer, and voltile registers. When + * the child TCB was initialized, all of the values were set to zero. + * up_initial_state() altered a few values, but the return value in R0 + * should be cleared to zero, providing the indication to the newly started + * child thread. */ - return TASK_CREATE("init", priority, stacksize, (main_t)retaddr, - (const char **)NULL); + child->xcp.regs[REG_R4] = context->r4; /* Volatile register r4 */ + child->xcp.regs[REG_R5] = context->r5; /* Volatile register r5 */ + child->xcp.regs[REG_R6] = context->r6; /* Volatile register r6 */ + child->xcp.regs[REG_R7] = context->r7; /* Volatile register r7 */ + child->xcp.regs[REG_R8] = context->r8; /* Volatile register r8 */ + child->xcp.regs[REG_R9] = context->r9; /* Volatile register r9 */ + child->xcp.regs[REG_R10] = context->r10; /* Volatile register r10 */ + child->xcp.regs[REG_FP] = context->fp; /* Frame pointer */ + child->xcp.regs[REG_SP] = context->sp; /* Stack pointer */ + + /* And, finally, start the child task. On a failure, task_vforkstart() + * will discard the TCB by calling task_vforkabort(). + */ + + return task_vforkstart(child); } diff --git a/nuttx/arch/arm/src/common/up_vfork.h b/nuttx/arch/arm/src/common/up_vfork.h new file mode 100644 index 000000000..a4505474a --- /dev/null +++ b/nuttx/arch/arm/src/common/up_vfork.h @@ -0,0 +1,82 @@ +/**************************************************************************** + * arch/arm/src/common/arm-vfork.h + * + * Copyright (C) 2013 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * 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 __ARCH_ARM_SRC_ARM_VFORK_H +#define __ARCH_ARM_SRC_ARM_VFORK_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define VFORK_R4_OFFSET (0*4) /* Volatile register r4 */ +#define VFORK_R5_OFFSET (1*4) /* Volatile register r5 */ +#define VFORK_R6_OFFSET (2*4) /* Volatile register r6 */ +#define VFORK_R7_OFFSET (3*4) /* Volatile register r7 */ +#define VFORK_R8_OFFSET (4*4) /* Volatile register r8 */ +#define VFORK_R9_OFFSET (5*4) /* Volatile register r9 */ +#define VFORK_R10_OFFSET (6*4) /* Volatile register r10 */ +#define VFORK_FP_OFFSET (7*4) /* Frame pointer */ +#define VFORK_SP_OFFSET (8*4) /* Stack pointer*/ +#define VFORK_LR_OFFSET (9*4) /* Return address*/ + +#define VFORK_SIZEOF (10*4) + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +#ifndef __ASSEMBLY__ +struct vfork_s +{ + uint32_t r4; /* Volatile register r4 */ + uint32_t r5; /* Volatile register r5 */ + uint32_t r6; /* Volatile register r6 */ + uint32_t r7; /* Volatile register r7 */ + uint32_t r8; /* Volatile register r8 */ + uint32_t r9; /* Volatile register r9 */ + uint32_t r10; /* Volatile register r10 */ + uint32_t fp; /* Frame pointer */ + uint32_t sp; /* Stack pointer*/ + uint32_t lr; /* Return address*/ +}; +#endif + +#endif /* __ARCH_ARM_SRC_ARM_VFORK_H */ diff --git a/nuttx/arch/arm/src/dm320/Make.defs b/nuttx/arch/arm/src/dm320/Make.defs index 52e65c0e8..651d9fea9 100644 --- a/nuttx/arch/arm/src/dm320/Make.defs +++ b/nuttx/arch/arm/src/dm320/Make.defs @@ -36,14 +36,14 @@ HEAD_ASRC = up_head.S CMN_ASRCS = up_cache.S up_fullcontextrestore.S up_saveusercontext.S \ - up_vectors.S up_vectoraddrexcptn.S up_vectortab.S up_vfork.S + up_vectors.S up_vectoraddrexcptn.S up_vectortab.S vfork.S CMN_CSRCS = up_assert.c up_blocktask.c up_copystate.c up_createstack.c \ up_dataabort.c up_mdelay.c up_udelay.c up_exit.c up_idle.c \ up_initialize.c up_initialstate.c up_interruptcontext.c \ up_prefetchabort.c up_releasepending.c up_releasestack.c \ up_reprioritizertr.c up_schedulesigaction.c \ up_sigdeliver.c up_syscall.c up_unblocktask.c \ - up_undefinedinsn.c up_usestack.c up__vfork.c + up_undefinedinsn.c up_usestack.c up_vfork.c ifeq ($(CONFIG_ELF),y) CMN_CSRCS += up_elf.c diff --git a/nuttx/arch/arm/src/imx/Make.defs b/nuttx/arch/arm/src/imx/Make.defs index a7c0ceebd..3cea29b9b 100644 --- a/nuttx/arch/arm/src/imx/Make.defs +++ b/nuttx/arch/arm/src/imx/Make.defs @@ -36,14 +36,14 @@ HEAD_ASRC = up_head.S CMN_ASRCS = up_cache.S up_fullcontextrestore.S up_saveusercontext.S \ - up_vectors.S up_vectoraddrexcptn.S up_vectortab.S up_vfork.S + up_vectors.S up_vectoraddrexcptn.S up_vectortab.S vfork.S CMN_CSRCS = up_assert.c up_blocktask.c up_copystate.c up_createstack.c \ up_dataabort.c up_mdelay.c up_udelay.c up_exit.c up_idle.c \ up_initialize.c up_initialstate.c up_interruptcontext.c \ up_prefetchabort.c up_releasepending.c up_releasestack.c \ up_reprioritizertr.c up_schedulesigaction.c \ up_sigdeliver.c up_syscall.c up_unblocktask.c \ - up_undefinedinsn.c up_usestack.c up__vfork.c + up_undefinedinsn.c up_usestack.c up_vfork.c ifeq ($(CONFIG_ELF),y) CMN_CSRCS += up_elf.c diff --git a/nuttx/arch/arm/src/kinetis/Make.defs b/nuttx/arch/arm/src/kinetis/Make.defs index bad2946e2..e41746547 100644 --- a/nuttx/arch/arm/src/kinetis/Make.defs +++ b/nuttx/arch/arm/src/kinetis/Make.defs @@ -40,7 +40,7 @@ HEAD_ASRC = kinetis_vectors.S # Common ARM and Cortex-M3 files CMN_ASRCS = up_saveusercontext.S up_fullcontextrestore.S up_switchcontext.S \ - up_vfork.S + vfork.S CMN_CSRCS = up_allocateheap.c up_assert.c up_blocktask.c up_copystate.c \ up_createstack.c up_mdelay.c up_udelay.c up_exit.c up_initialize.c \ up_memfault.c up_initialstate.c up_interruptcontext.c \ @@ -48,7 +48,7 @@ CMN_CSRCS = up_allocateheap.c up_assert.c up_blocktask.c up_copystate.c \ up_releasestack.c up_reprioritizertr.c up_schedulesigaction.c \ up_releasepending.c up_sigdeliver.c up_unblocktask.c up_usestack.c \ up_doirq.c up_hardfault.c up_svcall.c up_checkstack.c \ - up__vfork.c + up_vfork.c ifeq ($(CONFIG_ARCH_MEMCPY),y) CMN_ASRCS += up_memcpy.S diff --git a/nuttx/arch/arm/src/lm3s/Make.defs b/nuttx/arch/arm/src/lm3s/Make.defs index c745e1953..66b8f5658 100644 --- a/nuttx/arch/arm/src/lm3s/Make.defs +++ b/nuttx/arch/arm/src/lm3s/Make.defs @@ -36,7 +36,7 @@ HEAD_ASRC = lm3s_vectors.S CMN_ASRCS = up_saveusercontext.S up_fullcontextrestore.S up_switchcontext.S \ - up_vfork.S + vfork.S CMN_CSRCS = up_allocateheap.c up_assert.c up_blocktask.c up_copystate.c \ up_createstack.c up_mdelay.c up_udelay.c up_exit.c \ up_idle.c up_initialize.c up_initialstate.c up_interruptcontext.c \ @@ -44,7 +44,7 @@ CMN_CSRCS = up_allocateheap.c up_assert.c up_blocktask.c up_copystate.c \ up_releasepending.c up_releasestack.c up_reprioritizertr.c \ up_schedulesigaction.c up_sigdeliver.c up_unblocktask.c \ up_usestack.c up_doirq.c up_hardfault.c up_svcall.c \ - up__vfork.c + up_vfork.c ifeq ($(CONFIG_ARCH_MEMCPY),y) CMN_ASRCS += up_memcpy.S diff --git a/nuttx/arch/arm/src/lpc17xx/Make.defs b/nuttx/arch/arm/src/lpc17xx/Make.defs index 1ea0183a1..ed05fff95 100644 --- a/nuttx/arch/arm/src/lpc17xx/Make.defs +++ b/nuttx/arch/arm/src/lpc17xx/Make.defs @@ -40,14 +40,14 @@ HEAD_ASRC = lpc17_vectors.S # Common ARM and Cortex-M3 files CMN_ASRCS = up_saveusercontext.S up_fullcontextrestore.S up_switchcontext.S \ - up_vfork.S + vfork.S CMN_CSRCS = up_assert.c up_blocktask.c up_copystate.c up_createstack.c \ up_mdelay.c up_udelay.c up_exit.c up_initialize.c up_memfault.c \ up_initialstate.c up_interruptcontext.c up_modifyreg8.c \ up_modifyreg16.c up_modifyreg32.c up_releasepending.c \ up_releasestack.c up_reprioritizertr.c up_schedulesigaction.c \ up_sigdeliver.c up_unblocktask.c up_usestack.c up_doirq.c \ - up_hardfault.c up_svcall.c up_checkstack.c up__vfork.c + up_hardfault.c up_svcall.c up_checkstack.c up_vfork.c ifeq ($(CONFIG_ARCH_MEMCPY),y) CMN_ASRCS += up_memcpy.S diff --git a/nuttx/arch/arm/src/lpc214x/Make.defs b/nuttx/arch/arm/src/lpc214x/Make.defs index 6821d512b..34713b008 100644 --- a/nuttx/arch/arm/src/lpc214x/Make.defs +++ b/nuttx/arch/arm/src/lpc214x/Make.defs @@ -36,13 +36,13 @@ HEAD_ASRC = lpc214x_head.S CMN_ASRCS = up_saveusercontext.S up_fullcontextrestore.S up_vectors.S \ - up_vfork.S + vfork.S CMN_CSRCS = up_allocateheap.c up_assert.c up_blocktask.c up_copystate.c \ up_createstack.c up_dataabort.c up_mdelay.c up_udelay.c \ up_exit.c up_idle.c up_initialize.c up_initialstate.c \ up_interruptcontext.c up_prefetchabort.c up_releasepending.c \ up_releasestack.c up_reprioritizertr.c up_syscall.c up_unblocktask.c \ - up_undefinedinsn.c up_usestack.c up_lowputs.c up__vfork.c + up_undefinedinsn.c up_usestack.c up_lowputs.c up_vfork.c ifneq ($(CONFIG_DISABLE_SIGNALS),y) CMN_CSRCS += up_schedulesigaction.c up_sigdeliver.c diff --git a/nuttx/arch/arm/src/lpc2378/Make.defs b/nuttx/arch/arm/src/lpc2378/Make.defs index 3d3c15926..cfd9dc79f 100644 --- a/nuttx/arch/arm/src/lpc2378/Make.defs +++ b/nuttx/arch/arm/src/lpc2378/Make.defs @@ -41,13 +41,13 @@ HEAD_ASRC = lpc23xx_head.S CMN_ASRCS = up_saveusercontext.S up_fullcontextrestore.S up_vectors.S \ - up_vfork.S + vfork.S CMN_CSRCS = up_allocateheap.c up_assert.c up_blocktask.c up_copystate.c \ up_createstack.c up_dataabort.c up_mdelay.c up_udelay.c \ up_exit.c up_idle.c up_initialize.c up_initialstate.c \ up_interruptcontext.c up_prefetchabort.c up_releasepending.c \ up_releasestack.c up_reprioritizertr.c up_syscall.c up_unblocktask.c \ - up_undefinedinsn.c up_usestack.c up_lowputs.c up__vfork.c + up_undefinedinsn.c up_usestack.c up_lowputs.c up_vfork.c ifneq ($(CONFIG_DISABLE_SIGNALS),y) CMN_CSRCS += up_schedulesigaction.c up_sigdeliver.c diff --git a/nuttx/arch/arm/src/lpc31xx/Make.defs b/nuttx/arch/arm/src/lpc31xx/Make.defs index b3a9746b4..4e6f69299 100644 --- a/nuttx/arch/arm/src/lpc31xx/Make.defs +++ b/nuttx/arch/arm/src/lpc31xx/Make.defs @@ -36,7 +36,7 @@ HEAD_ASRC = up_head.S CMN_ASRCS = up_cache.S up_fullcontextrestore.S up_saveusercontext.S \ - up_vectors.S up_vectoraddrexcptn.S up_vectortab.S up_vfork.S + up_vectors.S up_vectoraddrexcptn.S up_vectortab.S vfork.S CMN_CSRCS = up_assert.c up_blocktask.c up_copystate.c up_createstack.c \ up_dataabort.c up_mdelay.c up_udelay.c up_exit.c up_idle.c \ up_initialize.c up_initialstate.c up_interruptcontext.c \ @@ -44,7 +44,7 @@ CMN_CSRCS = up_assert.c up_blocktask.c up_copystate.c up_createstack.c \ up_prefetchabort.c up_releasepending.c up_releasestack.c \ up_reprioritizertr.c up_schedulesigaction.c \ up_sigdeliver.c up_syscall.c up_unblocktask.c \ - up_undefinedinsn.c up_usestack.c up__vfork.c + up_undefinedinsn.c up_usestack.c up_vfork.c ifeq ($(CONFIG_PAGING),y) CMN_CSRCS += up_pginitialize.c up_checkmapping.c up_allocpage.c up_va2pte.c diff --git a/nuttx/arch/arm/src/lpc43xx/Make.defs b/nuttx/arch/arm/src/lpc43xx/Make.defs index 211f9bee3..9674196c5 100644 --- a/nuttx/arch/arm/src/lpc43xx/Make.defs +++ b/nuttx/arch/arm/src/lpc43xx/Make.defs @@ -36,7 +36,7 @@ HEAD_ASRC = CMN_ASRCS = up_saveusercontext.S up_fullcontextrestore.S up_switchcontext.S -CMN_ASRCS += up_vfork.S +CMN_ASRCS += vfork.S CMN_CSRCS = up_assert.c up_blocktask.c up_copystate.c CMN_CSRCS += up_createstack.c up_mdelay.c up_udelay.c up_exit.c @@ -44,7 +44,7 @@ CMN_CSRCS += up_initialize.c up_initialstate.c up_interruptcontext.c CMN_CSRCS += up_memfault.c up_modifyreg8.c up_modifyreg16.c up_modifyreg32.c CMN_CSRCS += up_releasepending.c up_releasestack.c up_reprioritizertr.c CMN_CSRCS += up_schedulesigaction.c up_sigdeliver.c up_unblocktask.c -CMN_CSRCS += up_usestack.c up_doirq.c up_hardfault.c up_svcall.c up__vfork.c +CMN_CSRCS += up_usestack.c up_doirq.c up_hardfault.c up_svcall.c up_vfork.c ifeq ($(CONFIG_ARMV7M_CMNVECTOR),y) CMN_ASRCS += up_exception.S diff --git a/nuttx/arch/arm/src/sam3u/Make.defs b/nuttx/arch/arm/src/sam3u/Make.defs index 4682ea83d..58047af21 100644 --- a/nuttx/arch/arm/src/sam3u/Make.defs +++ b/nuttx/arch/arm/src/sam3u/Make.defs @@ -40,14 +40,14 @@ HEAD_ASRC = sam3u_vectors.S # Common ARM and Cortex-M3 files CMN_ASRCS = up_saveusercontext.S up_fullcontextrestore.S up_switchcontext.S \ - up_vfork.S + vfork.S CMN_CSRCS = up_assert.c up_blocktask.c up_copystate.c up_createstack.c \ up_mdelay.c up_udelay.c up_exit.c up_idle.c up_initialize.c \ up_initialstate.c up_interruptcontext.c up_memfault.c up_modifyreg8.c \ up_modifyreg16.c up_modifyreg32.c up_releasepending.c \ up_releasestack.c up_reprioritizertr.c up_schedulesigaction.c \ up_sigdeliver.c up_unblocktask.c up_usestack.c up_doirq.c \ - up_hardfault.c up_svcall.c up__vfork.c + up_hardfault.c up_svcall.c up_vfork.c # Configuration-dependent common files diff --git a/nuttx/arch/arm/src/stm32/Make.defs b/nuttx/arch/arm/src/stm32/Make.defs index 89c291791..fd19e3bf6 100644 --- a/nuttx/arch/arm/src/stm32/Make.defs +++ b/nuttx/arch/arm/src/stm32/Make.defs @@ -40,7 +40,7 @@ HEAD_ASRC = stm32_vectors.S endif CMN_ASRCS = up_saveusercontext.S up_fullcontextrestore.S up_switchcontext.S \ - up_vfork.S + vfork.S CMN_CSRCS = up_assert.c up_blocktask.c up_copystate.c \ up_createstack.c up_mdelay.c up_udelay.c up_exit.c \ up_initialize.c up_initialstate.c up_interruptcontext.c \ @@ -48,7 +48,7 @@ CMN_CSRCS = up_assert.c up_blocktask.c up_copystate.c \ up_releasepending.c up_releasestack.c up_reprioritizertr.c \ up_schedulesigaction.c up_sigdeliver.c up_systemreset.c \ up_unblocktask.c up_usestack.c up_doirq.c up_hardfault.c \ - up_svcall.c up__vfork.c + up_svcall.c up_vfork.c ifeq ($(CONFIG_ARMV7M_CMNVECTOR),y) CMN_ASRCS += up_exception.S diff --git a/nuttx/arch/arm/src/str71x/Make.defs b/nuttx/arch/arm/src/str71x/Make.defs index 3612950a6..bde5ca003 100644 --- a/nuttx/arch/arm/src/str71x/Make.defs +++ b/nuttx/arch/arm/src/str71x/Make.defs @@ -36,13 +36,13 @@ HEAD_ASRC = str71x_head.S CMN_ASRCS = up_saveusercontext.S up_fullcontextrestore.S up_vectors.S \ - up_vfork.S + vfork.S CMN_CSRCS = up_allocateheap.c up_assert.c up_blocktask.c up_copystate.c \ up_createstack.c up_dataabort.c up_mdelay.c up_udelay.c \ up_exit.c up_idle.c up_initialize.c up_initialstate.c \ up_interruptcontext.c up_prefetchabort.c up_releasepending.c \ up_releasestack.c up_reprioritizertr.c up_syscall.c up_unblocktask.c \ - up_undefinedinsn.c up_usestack.c up_lowputs.c up__vfork.c + up_undefinedinsn.c up_usestack.c up_lowputs.c up_vfork.c ifneq ($(CONFIG_DISABLE_SIGNALS),y) CMN_CSRCS += up_schedulesigaction.c up_sigdeliver.c diff --git a/nuttx/include/nuttx/arch.h b/nuttx/include/nuttx/arch.h index 8b4b10ade..958986472 100644 --- a/nuttx/include/nuttx/arch.h +++ b/nuttx/include/nuttx/arch.h @@ -1,7 +1,7 @@ /**************************************************************************** * include/nuttx/arch.h * - * Copyright (C) 2007-2012 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2013 Gregory Nutt. All rights reserved. * Author: Gregory Nutt <gnutt@nuttx.org> * * Redistribution and use in source and binary forms, with or without diff --git a/nuttx/include/nuttx/sched.h b/nuttx/include/nuttx/sched.h index 6eaba6e9c..940bf1f1b 100644 --- a/nuttx/include/nuttx/sched.h +++ b/nuttx/include/nuttx/sched.h @@ -382,6 +382,32 @@ EXTERN FAR struct streamlist *sched_getstreams(void); EXTERN FAR struct socketlist *sched_getsockets(void); #endif /* CONFIG_NSOCKET_DESCRIPTORS */ +/* Internal vfork support.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) 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. + * + * task_vforkabort() may be called if an error occurs between steps 3 and 6. + */ + +FAR _TCB *task_vforksetup(start_t retaddr); +pid_t task_vforkstart(FAR _TCB *child); +void task_vforkabort(FAR _TCB *child, int errcode); + /* sched_foreach will enumerate over each task and provide the * TCB of each task to a user callback functions. Interrupts * will be disabled throughout this enumeration! diff --git a/nuttx/sched/Makefile b/nuttx/sched/Makefile index 82f74fc3c..23d1e9938 100644 --- a/nuttx/sched/Makefile +++ b/nuttx/sched/Makefile @@ -45,7 +45,7 @@ MISC_SRCS = os_start.c os_bringup.c errno_getptr.c errno_get.c errno_set.c \ TSK_SRCS = prctl.c task_create.c task_init.c task_setup.c task_activate.c \ task_start.c task_delete.c task_deletecurrent.c task_exithook.c \ - task_restart.c exit.c getpid.c sched_addreadytorun.c \ + task_restart.c task_vfork.c exit.c getpid.c sched_addreadytorun.c \ sched_removereadytorun.c sched_addprioritized.c sched_mergepending.c \ sched_addblocked.c sched_removeblocked.c sched_free.c sched_gettcb.c \ sched_verifytcb.c sched_releasetcb.c diff --git a/nuttx/sched/sched_setuptaskfiles.c b/nuttx/sched/sched_setuptaskfiles.c index fe0b14143..d01b8d4cd 100644 --- a/nuttx/sched/sched_setuptaskfiles.c +++ b/nuttx/sched/sched_setuptaskfiles.c @@ -200,7 +200,8 @@ static inline void sched_dupsockets(FAR _TCB *tcb) * tcb - tcb of the new task. * * Return Value: - * None + * Zero (OK) is returned on success; A negated errno value is returned on + * failure. * * Assumptions: * diff --git a/nuttx/sched/task_create.c b/nuttx/sched/task_create.c index 4d92c9bb0..801706cbf 100644 --- a/nuttx/sched/task_create.c +++ b/nuttx/sched/task_create.c @@ -169,6 +169,8 @@ static int thread_create(const char *name, uint8_t type, int priority, ret = task_activate(tcb); if (ret != OK) { + /* 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; } diff --git a/nuttx/sched/task_vfork.c b/nuttx/sched/task_vfork.c new file mode 100644 index 000000000..93fcb46da --- /dev/null +++ b/nuttx/sched/task_vfork.c @@ -0,0 +1,266 @@ +/**************************************************************************** + * sched/task_vfork + * + * Copyright (C) 2013 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * 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 <nuttx/config.h> + +#include <stdint.h> +#include <assert.h> +#include <queue.h> +#include <errno.h> + +#include <nuttx/sched.h> + +#include "os_internal.h" +#include "env_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * 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 _TCB *task_vforksetup(start_t retaddr) +{ + _TCB *parent = (FAR _TCB *)g_readytorun.head; + _TCB *child; + int priority; + int ret; + + DEBUGASSERT(retaddr); + + /* Allocate a TCB for the child task. */ + + child = (FAR _TCB*)kzalloc(sizeof(_TCB)); + if (!child) + { + set_errno(ENOMEM); + return NULL; + } + + /* Associate file descriptors with the new task */ + +#if CONFIG_NFILE_DESCRIPTORS > 0 || CONFIG_NSOCKET_DESCRIPTORS > 0 + ret = sched_setuptaskfiles(child); + if (ret != OK) + { + goto errout_with_tcb; + } +#endif + + /* Clone the parent's task environment */ + + (void)env_dup(child); + + /* Mark the type of this thread (this setting will be needed in + * task_schedsetup() when up_initial_state() is called. + */ + + child->flags |= TCB_FLAG_TTYPE_TASK; + + /* 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() */ + + ret = task_schedsetup(child, priority, retaddr, parent->entry.main); + if (ret != OK) + { + goto errout_with_tcb; + } + + return child; + +errout_with_tcb: + sched_releasetcb(child); + 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 _TCB *child) +{ + FAR const char *name; + pid_t pid; + int ret; + + DEBUGASSERT(child); + + /* Setup to pass parameters to the new task */ + +#if CONFIG_TASK_NAME_SIZE > 0 + name = parent->name; +#else + name = "<noname>"; +#endif + + (void)task_argsetup(child, name, (const char **)NULL); + + /* Get the assigned pid before we start the task */ + + pid = (int)child->pid; + + /* Activate the task */ + + ret = task_activate(child); + if (ret != OK) + { + task_vforkabort(child, -ret); + return ERROR; + } + + return pid; +} + +/**************************************************************************** + * Name: task_vforkabort + * + * Description: + * Recover from any errors after task_vforksetup() was called. + * + * Returned Value: + * None + * + ****************************************************************************/ + +void task_vforkabort(FAR _TCB *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(child); + set_errno(errcode); +}
\ No newline at end of file |