arch/ and task/sched: vfork operation needs to allocate and copy the task argument too. Also correction of the address correction cannot depend on the stack pointer since it is not available in all architectures. Rather callculate the offset from the stack allocation pointer

This commit is contained in:
Xiang Xiao 2018-08-24 07:43:00 -06:00 committed by Gregory Nutt
parent 8b63d02309
commit 36b46a6a40
5 changed files with 76 additions and 12 deletions

View File

@ -117,6 +117,8 @@ pid_t up_vfork(const struct vfork_s *context)
uint32_t newsp;
uint32_t newfp;
uint32_t stackutil;
size_t argsize;
void *argv;
int ret;
sinfo("vfork context [%p]:\n", context);
@ -129,7 +131,7 @@ pid_t up_vfork(const struct vfork_s *context)
/* Allocate and initialize a TCB for the child task. */
child = task_vforksetup((start_t)(context->lr & ~1));
child = task_vforksetup((start_t)(context->lr & ~1), &argsize);
if (!child)
{
serr("ERROR: task_vforksetup failed\n");
@ -147,7 +149,7 @@ pid_t up_vfork(const struct vfork_s *context)
/* Allocate the stack for the TCB */
ret = up_create_stack((FAR struct tcb_s *)child, stacksize,
ret = up_create_stack((FAR struct tcb_s *)child, stacksize + argsize,
parent->flags & TCB_FLAG_TTYPE_MASK);
if (ret != OK)
{
@ -156,6 +158,11 @@ pid_t up_vfork(const struct vfork_s *context)
return (pid_t)ERROR;
}
/* Allocate the memory and copy argument from parent task */
argv = up_stack_frame((FAR struct tcb_s *)child, argsize);
memcpy(argv, parent->adj_stack_ptr, argsize);
/* How much of the parent's stack was utilized? The ARM uses
* a push-down stack so that the current stack pointer should
* be lower than the initial, adjusted stack pointer. The

View File

@ -121,6 +121,8 @@ pid_t up_vfork(const struct vfork_s *context)
uint32_t newfp;
#endif
uint32_t stackutil;
size_t argsize;
void *argv;
int ret;
sinfo("s0:%08x s1:%08x s2:%08x s3:%08x s4:%08x\n",
@ -149,7 +151,7 @@ pid_t up_vfork(const struct vfork_s *context)
/* Allocate and initialize a TCB for the child task. */
child = task_vforksetup((start_t)context->ra);
child = task_vforksetup((start_t)context->ra, &argsize);
if (!child)
{
sinfo("task_vforksetup failed\n");
@ -167,7 +169,7 @@ pid_t up_vfork(const struct vfork_s *context)
/* Allocate the stack for the TCB */
ret = up_create_stack((FAR struct tcb_s *)child, stacksize,
ret = up_create_stack((FAR struct tcb_s *)child, stacksize + argsize,
parent->flags & TCB_FLAG_TTYPE_MASK);
if (ret != OK)
{
@ -176,6 +178,11 @@ pid_t up_vfork(const struct vfork_s *context)
return (pid_t)ERROR;
}
/* Allocate the memory and copy argument from parent task */
argv = up_stack_frame((FAR struct tcb_s *)child, argsize);
memcpy(argv, parent->adj_stack_ptr, argsize);
/* 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

View File

@ -125,6 +125,8 @@ pid_t up_vfork(const struct vfork_s *context)
uint32_t newfp;
#endif
uint32_t stackutil;
size_t argsize;
void *argv;
int ret;
sinfo("s0:%08x s1:%08x s2:%08x s3:%08x s4:%08x\n",
@ -153,7 +155,7 @@ pid_t up_vfork(const struct vfork_s *context)
/* Allocate and initialize a TCB for the child task. */
child = task_vforksetup((start_t)context->ra);
child = task_vforksetup((start_t)context->ra, &argsize);
if (!child)
{
sinfo("task_vforksetup failed\n");
@ -171,7 +173,7 @@ pid_t up_vfork(const struct vfork_s *context)
/* Allocate the stack for the TCB */
ret = up_create_stack((FAR struct tcb_s *)child, stacksize,
ret = up_create_stack((FAR struct tcb_s *)child, stacksize + argsize,
parent->flags & TCB_FLAG_TTYPE_MASK);
if (ret != OK)
{
@ -180,6 +182,11 @@ pid_t up_vfork(const struct vfork_s *context)
return (pid_t)ERROR;
}
/* Allocate the memory and copy argument from parent task */
argv = up_stack_frame((FAR struct tcb_s *)child, argsize);
memcpy(argv, parent->adj_stack_ptr, argsize);
/* 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

View File

@ -872,7 +872,7 @@ void task_starthook(FAR struct task_tcb_s *tcb, starthook_t starthook,
*
********************************************************************************/
FAR struct task_tcb_s *task_vforksetup(start_t retaddr);
FAR struct task_tcb_s *task_vforksetup(start_t retaddr, size_t *argsize);
pid_t task_vforkstart(FAR struct task_tcb_s *child);
void task_vforkabort(FAR struct task_tcb_s *child, int errcode);

View File

@ -131,7 +131,7 @@ static inline int vfork_stackargsetup(FAR struct tcb_s *parent,
/* Get the address correction */
offset = child->cmn.xcp.regs[REG_SP] - parent->xcp.regs[REG_SP];
offset = child->cmn.adj_stack_ptr - parent->adj_stack_ptr;
/* Change the child argv[] to point into its stack (instead of its
* parent's stack).
@ -194,6 +194,45 @@ static inline int vfork_argsetup(FAR struct tcb_s *parent,
return vfork_stackargsetup(parent, child);
}
/****************************************************************************
* Name: vfork_argsize
*
* Description:
* Get the parent's argument size.
*
* Input Parameters:
* parent - Address of the parent task's TCB
*
* Return Value:
* The parent's argument size.
*
****************************************************************************/
static inline size_t vfork_argsize(FAR struct tcb_s *parent)
{
if ((parent->flags & TCB_FLAG_TTYPE_MASK) != TCB_FLAG_TTYPE_PTHREAD)
{
FAR struct task_tcb_s *ptcb = (FAR struct task_tcb_s *)parent;
size_t strtablen = 0;
int argc = 0;
while (ptcb->argv[argc])
{
/* Add the size of this argument (with NUL terminator) */
strtablen += strlen(ptcb->argv[argc++]) + 1;
}
/* Return the size to hold argv[] array and the strings. */
return (argc + 1) * sizeof(FAR char *) + strtablen;
}
else
{
return 0;
}
}
/****************************************************************************
* Public Functions
****************************************************************************/
@ -230,8 +269,8 @@ static inline int vfork_argsetup(FAR struct tcb_s *parent,
* 6) task_vforkstart() then executes the child thread.
*
* Input Parameters:
* parent - Address of the parent task's TCB
* child - Address of the child task's TCB
* retaddr - Return address
* argsize - Location to return the argument size
*
* Returned Value:
* Upon successful completion, task_vforksetup() returns a pointer to
@ -240,7 +279,7 @@ static inline int vfork_argsetup(FAR struct tcb_s *parent,
*
****************************************************************************/
FAR struct task_tcb_s *task_vforksetup(start_t retaddr)
FAR struct task_tcb_s *task_vforksetup(start_t retaddr, size_t *argsize)
{
struct tcb_s *parent = this_task();
struct task_tcb_s *child;
@ -248,7 +287,7 @@ FAR struct task_tcb_s *task_vforksetup(start_t retaddr)
int priority;
int ret;
DEBUGASSERT(retaddr);
DEBUGASSERT(retaddr != NULL && argsize != NULL);
/* Get the type of the fork'ed task (kernel or user) */
@ -312,6 +351,10 @@ FAR struct task_tcb_s *task_vforksetup(start_t retaddr)
goto errout_with_tcb;
}
/* Return the argument size */
*argsize = vfork_argsize(parent);
sinfo("parent=%p, returning child=%p\n", parent, child);
return child;