diff --git a/ChangeLog b/ChangeLog index 41ac95db00..2d2cd82591 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3952,4 +3952,7 @@ scripts sub-directory * configs/ubw32/ostest: Configuration configured to use the kconfig-frontends tools. + * arch/mips/src/mips32/up_vfork.c, up_vfork.h, and vfork.S: + Implement vfork() for MIPS32 (no floating point support) + * configs/ubw32/ostest: Enable the vfork() test. diff --git a/Documentation/NuttX.html b/Documentation/NuttX.html index 22651de79e..c5f1ebc9c2 100644 --- a/Documentation/NuttX.html +++ b/Documentation/NuttX.html @@ -381,7 +381,7 @@

-

  • Well documented in the NuttX User Guide.
  • +
  • Well documented in the NuttX User Guide.
  • @@ -3833,7 +3833,7 @@ pascal-3.0 2011-05-15 Gregory Nutt <gnutt@nuttx.org> - User Guide + User Guide diff --git a/TODO b/TODO index 0d02e10e6c..58ca4cc8e4 100644 --- a/TODO +++ b/TODO @@ -6,7 +6,7 @@ standards, things that could be improved, and ideas for enhancements. nuttx/ - (10) Task/Scheduler (sched/) + (11) Task/Scheduler (sched/) (1) Memory Managment (mm/) (3) Signals (sched/, arch/) (2) pthreads (sched/) @@ -195,6 +195,25 @@ o Task/Scheduler (sched/) Status: Open Priority: Low + Title: IMPROVED TASK CONTROL BLOCK STRUCTURE + All task resources that are shared amongst threads have + their own "break-away", reference-counted structure. The + Task Control Block (TCB) of each thread holds a reference + to each breakaway structure (see include/nuttx/sched.h). + It would be more efficent to have one reference counted + structure that holds all of the shared resources. + + These are the current shared structures: + - Environment varaibles (struct environ_s) + - PIC data space and address environments (struct dspace_s) + - File descriptors (struct filelist) + - FILE streams (struct streamlist) + - Sockets (struct socketlist) + Status: Open + Priority: Low. This is an enhancement. It would slight reduce + memory usage but would also increase coupling. These + resources are nicely modular now. + o Memory Managment (mm/) ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/arch/arm/src/arm/vfork.S b/arch/arm/src/arm/vfork.S index 226d9f7de4..7c3c8b7274 100644 --- a/arch/arm/src/arm/vfork.S +++ b/arch/arm/src/arm/vfork.S @@ -105,6 +105,7 @@ vfork: mov r0, sp /* Save the value of the stack on entry */ sub sp, sp, #VFORK_SIZEOF /* Allocate the structure on the stack */ + /* CPU registers */ /* Save the volatile registers */ str r4, [sp, #VFORK_R4_OFFSET] @@ -121,6 +122,8 @@ vfork: str r0, [sp, #VFORK_SP_OFFSET] str lr, [sp, #VFORK_LR_OFFSET] + /* Floating point registers (not yet) */ + /* Then, call up_vfork(), passing it a pointer to the stack structure */ mov r0, sp diff --git a/arch/arm/src/armv7-m/vfork.S b/arch/arm/src/armv7-m/vfork.S index 386fca33c4..f36ff23aa7 100644 --- a/arch/arm/src/armv7-m/vfork.S +++ b/arch/arm/src/armv7-m/vfork.S @@ -108,6 +108,7 @@ vfork: mov r0, sp /* Save the value of the stack on entry */ sub sp, sp, #VFORK_SIZEOF /* Allocate the structure on the stack */ + /* CPU registers */ /* Save the volatile registers */ str r4, [sp, #VFORK_R4_OFFSET] @@ -124,6 +125,8 @@ vfork: str r0, [sp, #VFORK_SP_OFFSET] str lr, [sp, #VFORK_LR_OFFSET] + /* Floating point registers (not yet) */ + /* Then, call up_vfork(), passing it a pointer to the stack structure */ mov r0, sp diff --git a/arch/arm/src/common/up_vfork.c b/arch/arm/src/common/up_vfork.c index 5349378bc4..3b653e3170 100644 --- a/arch/arm/src/common/up_vfork.c +++ b/arch/arm/src/common/up_vfork.c @@ -208,7 +208,7 @@ pid_t up_vfork(const struct vfork_s *context) svdbg("New stack base:%08x SP:%08x FP:%08x\n", child->adj_stack_ptr, newsp, newfp); - /* Update the stack pointer, frame pointer, and voltile registers. When + /* Update the stack pointer, frame pointer, and volatile 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 diff --git a/arch/arm/src/common/up_vfork.h b/arch/arm/src/common/up_vfork.h index a4505474a3..97edf9aaa5 100644 --- a/arch/arm/src/common/up_vfork.h +++ b/arch/arm/src/common/up_vfork.h @@ -1,5 +1,5 @@ /**************************************************************************** - * arch/arm/src/common/arm-vfork.h + * arch/arm/src/common/up_vfork.h * * Copyright (C) 2013 Gregory Nutt. All rights reserved. * Author: Gregory Nutt @@ -53,6 +53,7 @@ #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*/ @@ -66,6 +67,8 @@ #ifndef __ASSEMBLY__ struct vfork_s { + /* CPU registers */ + uint32_t r4; /* Volatile register r4 */ uint32_t r5; /* Volatile register r5 */ uint32_t r6; /* Volatile register r6 */ @@ -73,9 +76,12 @@ struct vfork_s 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*/ + + /* Floating point registers (not yet) */ }; #endif diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 1b10e26aee..86482ef7ae 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -22,6 +22,7 @@ endchoice config ARCH_MIPS32 bool default n + select ARCH_HAVE_VFORK config ARCH_FAMILY string diff --git a/arch/mips/src/mips32/Kconfig b/arch/mips/src/mips32/Kconfig index b8b5d9b926..c7a4499c22 100644 --- a/arch/mips/src/mips32/Kconfig +++ b/arch/mips/src/mips32/Kconfig @@ -47,4 +47,12 @@ config MIPS32_TOOLCHAIN_PINGUINOL endchoice +config MIPS32_FRAMEPOINTER + bool "ABI Uses Frame Pointer" + default n + depends on ARCH_HAVE_VFORK + ---help--- + Register r30 may be a frame pointer in some ABIs. Or may just be + saved register s8. It makes a difference for vfork handling. + endif diff --git a/arch/mips/src/mips32/up_vfork.c b/arch/mips/src/mips32/up_vfork.c new file mode 100644 index 0000000000..6b7e27f318 --- /dev/null +++ b/arch/mips/src/mips32/up_vfork.c @@ -0,0 +1,254 @@ +/**************************************************************************** + * arch/mips/src/mips32/up_vfork.c + * + * Copyright (C) 2013 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "up_vfork.h" +#include "os_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef CONFIG_STACK_ALIGNMENT +# define CONFIG_STACK_ALIGNMENT 4 +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_vfork + * + * 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. + * + * 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: + * context - Caller context information saved by vfork() + * + * Return: + * 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 up_vfork(const struct vfork_s *context) +{ + _TCB *parent = (FAR _TCB *)g_readytorun.head; + _TCB *child; + size_t stacksize; + uint32_t newsp; +#if CONFIG_MIPS32_FRAMEPOINTER + uint32_t newfp; +#endif + uint32_t stackutil; + int ret; + + svdbg("s0:%08x s1:%08x s2:%08x s3:%08x s4:%08x\n", + context->s0, context->s1, context->s2, context->s3, context->s4); +#if CONFIG_MIPS32_FRAMEPOINTER + svdbg("s5:%08x s6:%08x s7:%08x\n", + context->s5, context->s6, context->s7); +#ifdef MIPS32_SAVE_GP + svdbg("fp:%08x sp:%08x ra:%08x gp:%08x\n", + context->fp, context->sp, context->ra, context->gp); +#else + svdbg("fp:%08x sp:%08x ra:%08x\n", + context->fp context->sp, context->ra); +#endif +#else + svdbg("s5:%08x s6:%08x s7:%08x s8:%08x\n", + context->s5, context->s6, context->s7, context->s8); +#ifdef MIPS32_SAVE_GP + svdbg("sp:%08x ra:%08x gp:%08x\n", + context->sp, context->ra, context->gp); +#else + svdbg("sp:%08x ra:%08x\n", + context->sp, context->ra); +#endif +#endif + + /* Allocate and initialize a TCB for the child task. */ + + child = task_vforksetup((start_t)context->ra); + if (!child) + { + sdbg("task_vforksetup failed\n"); + return (pid_t)ERROR; + } + + svdbg("Parent=%p Child=%p\n", parent, child); + + /* 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 + * requrested. + */ + + stacksize = parent->adj_stack_size + CONFIG_STACK_ALIGNMENT - 1; + + /* Allocate the stack for the TCB */ + + ret = up_create_stack(child, stacksize); + if (ret != OK) + { + sdbg("up_create_stack failed: %d\n", ret); + task_vforkabort(child, -ret); + return (pid_t)ERROR; + } + + /* How much of the parent's stack was utilized? The MIPS uses + * a push-down stack so that the current stack pointer should + * be lower than the initial, adjusted stack pointer. The + * stack usage should be the difference between those two. + */ + + DEBUGASSERT((uint32_t)parent->adj_stack_ptr > context->sp); + stackutil = (uint32_t)parent->adj_stack_ptr - context->sp; + + svdbg("stacksize:%d stackutil:%d\n", stacksize, stackutil); + + /* Make some feeble effort to perserve the stack contents. This is + * feeble because the stack surely contains invalid pointers 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); + + /* Was there a frame pointer in place before? */ + +#if CONFIG_MIPS32_FRAMEPOINTER + if (context->fp <= (uint32_t)parent->adj_stack_ptr && + context->fp >= (uint32_t)parent->adj_stack_ptr - stacksize) + { + uint32_t frameutil = (uint32_t)parent->adj_stack_ptr - context->fp; + newfp = (uint32_t)child->adj_stack_ptr - frameutil; + } + else + { + newfp = context->fp; + } + + svdbg("Old stack base:%08x SP:%08x FP:%08x\n", + parent->adj_stack_ptr, context->sp, context->fp); + svdbg("New stack base:%08x SP:%08x FP:%08x\n", + child->adj_stack_ptr, newsp, newfp); +#else + svdbg("Old stack base:%08x SP:%08x\n", + parent->adj_stack_ptr, context->sp); + svdbg("New stack base:%08x SP:%08x\n", + child->adj_stack_ptr, newsp); +#endif + + /* Update the stack pointer, frame pointer, global pointer and saved + * 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 v0 should be cleared to zero, providing the + * indication to the newly started child thread. + */ + + child->xcp.regs[REG_S0] = context->s0; /* Saved register s0 */ + child->xcp.regs[REG_S1] = context->s1; /* Saved register s1 */ + child->xcp.regs[REG_S2] = context->s2; /* Saved register s2 */ + child->xcp.regs[REG_S3] = context->s3; /* Volatile register s3 */ + child->xcp.regs[REG_S4] = context->s4; /* Volatile register s4 */ + child->xcp.regs[REG_S5] = context->s5; /* Volatile register s5 */ + child->xcp.regs[REG_S6] = context->s6; /* Volatile register s6 */ + child->xcp.regs[REG_S7] = context->s7; /* Volatile register s7 */ +#if CONFIG_MIPS32_FRAMEPOINTER + child->xcp.regs[REG_FP] = newfp; /* Frame pointer */ +#else + child->xcp.regs[REG_S8] = context->s8; /* Volatile register s8 */ +#endif + child->xcp.regs[REG_SP] = newsp; /* Stack pointer */ +#if MIPS32_SAVE_GP + child->xcp.regs[REG_GP] = newsp; /* Global pointer */ +#endif + + /* 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/arch/mips/src/mips32/up_vfork.h b/arch/mips/src/mips32/up_vfork.h new file mode 100644 index 0000000000..5566330727 --- /dev/null +++ b/arch/mips/src/mips32/up_vfork.h @@ -0,0 +1,132 @@ +/**************************************************************************** + * arch/mips/src/mips/up_vfork.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 __ARCH_MIPS_SRC_MIPS32_VFORK_H +#define __ARCH_MIPS_SRC_MIPS32_VFORK_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ +/* Register r30 may be a frame pointer in some ABIs. Or may just be saved + * register s8. It makes a difference for vfork handling. + */ + +#undef VFORK_HAVE_FP + +/* r0 zero Always has the value 0. + * r1 at Temporary generally used by assembler. + * r2-r3 v0-v1 Used for expression evaluations and to hold the integer and + * pointer type function return values. + * r4-r7 a0-a3 Used for passing arguments to functions; values are not + * preserved across function calls. + * r8-r15 t0-t7 Temporary registers used for expression evaluation; values + * are not preserved across function calls. + * r16-r23 s0-s7 Saved registers; values are preserved across function calls. + * r24-r25 t8-t9 Temporary registers used for expression evaluations; values + * are not preserved across function calls. When calling + * position independent functions r25 must contain the address + * of the called function. + * r26-r27 k0-k1 Used only by the operating system. + * r28 gp Global pointer and context pointer. + * r29 sp Stack pointer. + * r30 s8 Saved register (like s0-s7). If a frame pointer is used, + * then this is the frame pointer. + * r31 ra Return address. + */ + +#define VFORK_S0_OFFSET (0*4) /* Saved register s0 */ +#define VFORK_S1_OFFSET (1*4) /* Saved register s1 */ +#define VFORK_S2_OFFSET (2*4) /* Saved register s2 */ +#define VFORK_S3_OFFSET (3*4) /* Saved register s3 */ +#define VFORK_S4_OFFSET (4*4) /* Saved register s4 */ +#define VFORK_S5_OFFSET (5*4) /* Saved register s5 */ +#define VFORK_S6_OFFSET (6*4) /* Saved register s6 */ +#define VFORK_S7_OFFSET (7*4) /* Saved register s7 */ + +#ifdef CONFIG_MIPS32_FRAMEPOINTER +# define VFORK_FP_OFFSET (8*4) /* Frame pointer */ +#else +# define VFORK_S8_OFFSET (8*4) /* Saved register s8 */ +#endif + +#define VFORK_SP_OFFSET (9*4) /* Stack pointer*/ +#define VFORK_RA_OFFSET (10*4) /* Return address*/ +#ifdef MIPS32_SAVE_GP +# define VFORK_GP_OFFSET (11*4) /* Global pointer */ +# define VFORK_SIZEOF (12*4) +#else +# define VFORK_SIZEOF (11*4) +#endif + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +#ifndef __ASSEMBLY__ +struct vfork_s +{ + /* CPU registers */ + + uint32_t s0; /* Saved register s0 */ + uint32_t s1; /* Saved register s1 */ + uint32_t s2; /* Saved register s2 */ + uint32_t s3; /* Saved register s3 */ + uint32_t s4; /* Saved register s4 */ + uint32_t s5; /* Saved register s5 */ + uint32_t s6; /* Saved register s6 */ + uint32_t s7; /* Saved register s7 */ +#ifdef CONFIG_MIPS32_FRAMEPOINTER + uint32_t fp; /* Frame pointer */ +#else + uint32_t s8; /* Saved register s8 */ +#endif + uint32_t sp; /* Stack pointer*/ + uint32_t ra; /* Return address*/ +#ifdef MIPS32_SAVE_GP + uint32_t gp; /* Global pointer */ +#endif + + /* Floating point registers (not yet) */ +}; +#endif + +#endif /* __ARCH_MIPS_SRC_MIPS32_VFORK_H */ diff --git a/arch/mips/src/mips32/vfork.S b/arch/mips/src/mips32/vfork.S new file mode 100644 index 0000000000..2b7d180d35 --- /dev/null +++ b/arch/mips/src/mips32/vfork.S @@ -0,0 +1,154 @@ +/************************************************************************************ + * arch/mips/src/mips32/vfork.S + * + * 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 "up_vfork.h" + +/************************************************************************************ + * Pre-processor Definitions + ************************************************************************************/ + +/************************************************************************************ + * Global Symbols + ************************************************************************************/ + + .file "vfork.S" + .globl up_vfork + +/************************************************************************************ + * Public Functions + ************************************************************************************/ + +/************************************************************************************ + * Name: vfork + * + * 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 thin layer implements vfork by simply calling up_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 + * + * Return: + * 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. + * + ************************************************************************************/ + + .text + .align 2 + .globl vfork + .type vfork, function + .set nomips16 + .ent vfork + +vfork: + /* Create a stack frame */ + + move $t0, $sp /* Save the value of the stack on entry */ + addiu $sp, $sp, -VFORK_SIZEOF /* Allocate the structure on the stack */ + + /* CPU registers */ + /* Save the saved registers */ + + sw $s0, VFORK_S0_OFFSET($sp) + sw $s1, VFORK_S1_OFFSET($sp) + sw $s2, VFORK_S2_OFFSET($sp) + sw $s3, VFORK_S3_OFFSET($sp) + sw $s4, VFORK_S4_OFFSET($sp) + sw $s5, VFORK_S5_OFFSET($sp) + sw $s6, VFORK_S6_OFFSET($sp) + sw $s7, VFORK_S7_OFFSET($sp) + +#ifdef CONFIG_MIPS32_FRAMEPOINTER + sw $fp, VFORK_FP_OFFSET($sp) +#else + sw $s8, VFORK_S8_OFFSET($sp) +#endif + + /* Save the global pointer, stack pointer, and return address */ + + sw $t0, VFORK_SP_OFFSET($sp) + sw $ra, VFORK_RA_OFFSET($sp) +#ifdef MIPS32_SAVE_GP + sw $gp, VFORK_GP_OFFSET($sp) +#endif + + /* Floating point registers (not yet) */ + + /* Then, call up_vfork(), passing it a pointer to the stack structure */ + + move $a0, $sp + jal up_vfork + nop + + /* Release the stack data and return the value returned by up_vfork */ + + lw $ra, VFORK_RA_OFFSET($sp) + addiu $sp, $sp, VFORK_SIZEOF + j $ra + + .end vfork + .size vfork, .-vfork diff --git a/arch/mips/src/pic32mx/Make.defs b/arch/mips/src/pic32mx/Make.defs index 46fef84dce..861e1c3014 100644 --- a/arch/mips/src/pic32mx/Make.defs +++ b/arch/mips/src/pic32mx/Make.defs @@ -39,14 +39,14 @@ HEAD_ASRC = pic32mx-head.S # Common MIPS files -CMN_ASRCS = up_syscall0.S +CMN_ASRCS = up_syscall0.S vfork.S CMN_CSRCS = up_allocateheap.c up_assert.c up_blocktask.c up_copystate.c \ up_createstack.c up_doirq.c up_exit.c up_idle.c up_initialize.c \ up_initialstate.c up_interruptcontext.c up_irq.c up_lowputs.c \ up_mdelay.c up_modifyreg8.c up_modifyreg16.c up_modifyreg32.c \ up_puts.c up_releasepending.c up_releasestack.c up_reprioritizertr.c \ up_schedulesigaction.c up_sigdeliver.c up_swint0.c up_udelay.c \ - up_unblocktask.c up_usestack.c + up_unblocktask.c up_usestack.c up_vfork.c # Configuration dependent common files diff --git a/configs/ubw32/ostest/defconfig b/configs/ubw32/ostest/defconfig index 3a387ab997..a722e25e71 100644 --- a/configs/ubw32/ostest/defconfig +++ b/configs/ubw32/ostest/defconfig @@ -72,13 +72,10 @@ CONFIG_ARCH_MIPS32=y # MIPS32 Configuration Options # # CONFIG_MIPS32_TOOLCHAIN_GNU_ELF is not set -# CONFIG_MIPS32_TOOLCHAIN_MICROCHIPL is not set -# CONFIG_MIPS32_TOOLCHAIN_MICROCHIPL_LITE is not set # CONFIG_MIPS32_TOOLCHAIN_MICROCHIPW is not set CONFIG_MIPS32_TOOLCHAIN_MICROCHIPW_LITE=y -# CONFIG_MIPS32_TOOLCHAIN_MICROCHIPOPENL is not set # CONFIG_MIPS32_TOOLCHAIN_PINGUINOW is not set -# CONFIG_MIPS32_TOOLCHAIN_PINGUINOL is not set +# CONFIG_MIPS32_FRAMEPOINTER is not set # # PIC32MX Configuration Options @@ -245,7 +242,7 @@ CONFIG_ARCH_VECNOTIRQ=y CONFIG_ARCH_IRQPRIO=y # CONFIG_CUSTOM_STACK is not set # CONFIG_ADDRENV is not set -# CONFIG_ARCH_HAVE_VFORK is not set +CONFIG_ARCH_HAVE_VFORK=y CONFIG_ARCH_STACKDUMP=y # CONFIG_ENDIAN_BIG is not set CONFIG_ARCH_HAVE_RAMFUNCS=y @@ -308,7 +305,7 @@ CONFIG_DEV_CONSOLE=y # CONFIG_FDCLONE_STDIO is not set CONFIG_SDCLONE_DISABLE=y # CONFIG_SCHED_WORKQUEUE is not set -# CONFIG_SCHED_WAITPID is not set +CONFIG_SCHED_WAITPID=y # CONFIG_SCHED_ATEXIT is not set # CONFIG_SCHED_ONEXIT is not set CONFIG_USER_ENTRYPOINT="ostest_main" diff --git a/sched/task_vfork.c b/sched/task_vfork.c index 4b42c7b363..46b2d8e9f4 100644 --- a/sched/task_vfork.c +++ b/sched/task_vfork.c @@ -287,7 +287,11 @@ pid_t task_vforkstart(FAR _TCB *child) #endif #else - /* Again exploiting that execv() bug: Check if the child thread is + /* The following logic does not appear to work... It gets stuff in an + * infinite kill() loop and hogs the processor. Therefore, it looks + * as though CONFIG_SCHED_WAITPID may be a requirement to used vfork(). + * + * Again exploiting that execv() bug: Check if the child thread is * still running. */ @@ -331,4 +335,4 @@ void task_vforkabort(FAR _TCB *child, int errcode) sched_releasetcb(child); set_errno(errcode); -} \ No newline at end of file +}