summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory Nutt <gnutt@nuttx.org>2014-09-29 12:21:34 -0600
committerGregory Nutt <gnutt@nuttx.org>2014-09-29 12:21:34 -0600
commit506e660018db40873b8f97bec663e29bbd2b030e (patch)
tree6bfee4461845b9e969f11afc8203ee24c1eec8e7
parent2e613d3c5fe48fb2eba322d5c2e257d6fe42a417 (diff)
downloadnuttx-506e660018db40873b8f97bec663e29bbd2b030e.tar.gz
nuttx-506e660018db40873b8f97bec663e29bbd2b030e.tar.bz2
nuttx-506e660018db40873b8f97bec663e29bbd2b030e.zip
Fix a perverse case where vfork() is called from a pthread. Still not recommended
-rw-r--r--nuttx/sched/task/task_vfork.c45
1 files changed, 29 insertions, 16 deletions
diff --git a/nuttx/sched/task/task_vfork.c b/nuttx/sched/task/task_vfork.c
index 864a29601..ea7ce295b 100644
--- a/nuttx/sched/task/task_vfork.c
+++ b/nuttx/sched/task/task_vfork.c
@@ -79,12 +79,12 @@
****************************************************************************/
#if CONFIG_TASK_NAME_SIZE > 0
-static inline void vfork_namesetup(FAR struct task_tcb_s *parent,
+static inline void vfork_namesetup(FAR struct tcb_s *parent,
FAR struct task_tcb_s *child)
{
/* Copy the name from the parent into the child TCB */
- strncpy(child->cmn.name, parent->cmn.name, CONFIG_TASK_NAME_SIZE);
+ strncpy(child->cmn.name, parent->name, CONFIG_TASK_NAME_SIZE);
}
#else
# define vfork_namesetup(p,c)
@@ -106,27 +106,40 @@ static inline void vfork_namesetup(FAR struct task_tcb_s *parent,
*
****************************************************************************/
-static inline void vfork_stackargsetup(FAR struct task_tcb_s *parent,
+static inline void vfork_stackargsetup(FAR struct tcb_s *parent,
FAR struct task_tcb_s *child)
{
- uintptr_t offset;
- int i;
+ /* Is the parent a task? or a pthread? */
- /* Get the address correction */
+ child->argv = NULL;
+ if ((parent->flags & TCB_FLAG_TTYPE_MASK) != TCB_FLAG_TTYPE_PTHREAD)
+ {
+ FAR struct task_tcb_s *ptcb = (FAR struct task_tcb_s *)parent;
+ uintptr_t offset;
+ int i;
- offset = child->cmn.xcp.regs[REG_SP] - parent->cmn.xcp.regs[REG_SP];
+ /* Get the address correction */
- /* Copy the adjusted address for each argument */
+ offset = child->cmn.xcp.regs[REG_SP] - parent->xcp.regs[REG_SP];
- for (i = 0; i < CONFIG_MAX_TASK_ARGS && parent->argv[i]; i++)
- {
- uintptr_t newaddr = (uintptr_t)parent->argv[i] + offset;
- child->argv[i] = (FAR char *)newaddr;
- }
+ /* Change the child argv[] to point into its stack (instead of its
+ * parent's stack).
+ */
+
+ child->argv = (FAR char **)((uintptr_t)ptcb->argv + offset);
- /* Put a terminator entry at the end of the child argv[] array. */
+ /* Copy the adjusted address for each argument */
- child->argv[i] = NULL;
+ for (i = 0; i < CONFIG_MAX_TASK_ARGS && ptcb->argv[i]; i++)
+ {
+ uintptr_t newaddr = (uintptr_t)ptcb->argv[i] + offset;
+ child->argv[i] = (FAR char *)newaddr;
+ }
+
+ /* Put a terminator entry at the end of the child argv[] array. */
+
+ child->argv[i] = NULL;
+ }
}
/****************************************************************************
@@ -144,7 +157,7 @@ static inline void vfork_stackargsetup(FAR struct task_tcb_s *parent,
*
****************************************************************************/
-static inline void vfork_argsetup(FAR struct task_tcb_s *parent,
+static inline void vfork_argsetup(FAR struct tcb_s *parent,
FAR struct task_tcb_s *child)
{
/* Clone the task name */