In the kernel build, pass task paramters in the stack, not using the arrary in the TCB

git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@5770 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
patacongo 2013-03-21 21:51:15 +00:00
parent ee885b45d8
commit 5453d1f2e5
4 changed files with 274 additions and 48 deletions

View File

@ -543,7 +543,17 @@ struct task_tcb_s
/* Values needed to restart a task ********************************************/
uint8_t init_priority; /* Initial priority of the task */
#if !defined(CONFIG_CUSTOM_STACK) && defined(CONFIG_NUTTX_KERNEL)
/* In the kernel mode build, the arguments are saved on the task's stack */
FAR char **argv; /* Name+start-up parameters */
#else
/* Otherwise, the arguments are strdup'ed and the argv[] is statically */
/* defined here: */
char *argv[CONFIG_MAX_TASK_ARGS+1]; /* Name+start-up parameters */
#endif
};
/* struct pthread_tcb_s **********************************************************/

View File

@ -108,7 +108,7 @@ endif
$(Q) $(MKDEP) $(DEPPATH) "$(CC)" -- $(CFLAGS) -- $(SRCS) >Make.dep
$(Q) touch $@
depend: $(BINDIR)$(DELIM).depend
depend: .depend
# Clean most derived files, retaining the configuration

View File

@ -156,8 +156,13 @@ int sched_releasetcb(FAR struct tcb_s *tcb, uint8_t ttype)
}
#endif
#if !defined(CONFIG_CUSTOM_STACK) && defined(CONFIG_NUTTX_KERNEL)
/* Release command line arguments that were allocated for task
* start/re-start.
*
* NOTE: In the kernel mode build, the arguments were saved on
* the task's stack and will be cleaned up when the stack memory
* is released. Nothing need be done here in that case.
*/
#ifndef CONFIG_DISABLE_PTHREAD
@ -171,6 +176,8 @@ int sched_releasetcb(FAR struct tcb_s *tcb, uint8_t ttype)
}
}
#endif /* !CONFIG_CUSTOM_STACK && CONFIG_NUTTX_KERNEL */
/* Release this thread's reference to the address environment */
#ifdef CONFIG_ADDRENV

View File

@ -386,6 +386,232 @@ static int thread_schedsetup(FAR struct tcb_s *tcb, int priority,
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 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 kernal 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 (!tcb->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
****************************************************************************/
@ -472,12 +698,18 @@ int pthread_schedsetup(FAR struct pthread_tcb_s *tcb, int priority, start_t star
* Name: task_argsetup
*
* Description:
* This functions sets up parameters in the Task Control
* Block (TCB) in preparation for starting a new thread.
* 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. Argumens are
* cloned via strdup.
* 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 kernal 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
@ -494,56 +726,33 @@ int pthread_schedsetup(FAR struct pthread_tcb_s *tcb, int priority, start_t star
*
****************************************************************************/
int task_argsetup(FAR struct task_tcb_s *tcb, const char *name,
int task_argsetup(FAR struct task_tcb_s *tcb, FAR const char *name,
FAR char * const argv[])
{
int i;
int ret;
#if CONFIG_TASK_NAME_SIZE > 0
/* Give a name to the unnamed tasks */
/* Setup the task name */
if (!name)
{
name = (FAR char *)g_noname;
}
task_namesetup(tcb, name);
/* Copy the name into the TCB */
strncpy(tcb->cmn.name, name, CONFIG_TASK_NAME_SIZE);
/* Save the name as the first argument */
tcb->argv[0] = tcb->cmn.name;
#else
/* Save the name as the first argument */
tcb->argv[0] = (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 to dup the strings.
*
* The first NULL argument terminates the list of
* arguments. The argv pointer may be NULL if no
* parameters are passed.
#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 kernal 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.
*/
i = 1;
if (argv)
{
for (; i < CONFIG_MAX_TASK_ARGS+1 && argv[i-1]; i++)
{
tcb->argv[i] = strdup(argv[i-1]);
}
}
ret = task_stackargsetup(tcb, argv);
/* Nullify any unused argument storage */
#else
/* In the "normal" case, the argv[] array is a structure in the TCB, the
* arguments are cloned via strdup.
*/
for (; i < CONFIG_MAX_TASK_ARGS+1; i++)
{
tcb->argv[i] = NULL;
}
ret = task_tcbargsetup(tcb, argv);
return OK;
#endif /* !CONFIG_CUSTOM_STACK && CONFIG_NUTTX_KERNEL */
return ret;
}