diff options
author | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2013-03-21 21:51:15 +0000 |
---|---|---|
committer | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2013-03-21 21:51:15 +0000 |
commit | 7fd81076443ca5685f38f02ecd926e8bda368c9b (patch) | |
tree | b605ce1065d9caa777d1946801e25a9524bec805 | |
parent | 09c1049fff6e991733448e7fb164f518fa003021 (diff) | |
download | nuttx-7fd81076443ca5685f38f02ecd926e8bda368c9b.tar.gz nuttx-7fd81076443ca5685f38f02ecd926e8bda368c9b.tar.bz2 nuttx-7fd81076443ca5685f38f02ecd926e8bda368c9b.zip |
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
-rw-r--r-- | nuttx/include/nuttx/sched.h | 10 | ||||
-rw-r--r-- | nuttx/libc/Makefile | 2 | ||||
-rw-r--r-- | nuttx/sched/sched_releasetcb.c | 7 | ||||
-rw-r--r-- | nuttx/sched/task_setup.c | 299 |
4 files changed, 272 insertions, 46 deletions
diff --git a/nuttx/include/nuttx/sched.h b/nuttx/include/nuttx/sched.h index 2641dd9d1..229f86f74 100644 --- a/nuttx/include/nuttx/sched.h +++ b/nuttx/include/nuttx/sched.h @@ -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 **********************************************************/ diff --git a/nuttx/libc/Makefile b/nuttx/libc/Makefile index 8526f1b0b..c79c5e7d7 100644 --- a/nuttx/libc/Makefile +++ b/nuttx/libc/Makefile @@ -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 diff --git a/nuttx/sched/sched_releasetcb.c b/nuttx/sched/sched_releasetcb.c index 185fd4dcd..cbb58002d 100644 --- a/nuttx/sched/sched_releasetcb.c +++ b/nuttx/sched/sched_releasetcb.c @@ -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 diff --git a/nuttx/sched/task_setup.c b/nuttx/sched/task_setup.c index cbc3582a5..85e828fd0 100644 --- a/nuttx/sched/task_setup.c +++ b/nuttx/sched/task_setup.c @@ -387,6 +387,232 @@ static int thread_schedsetup(FAR struct tcb_s *tcb, int priority, } /**************************************************************************** + * 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. In the "normal" case, the argv[] array is a + * structure in the TCB, the arguments are cloned via strdup. * - * task_argsetup() is called only from task_init() and - * task_start() to create a new task. Argumens 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; - -#if CONFIG_TASK_NAME_SIZE > 0 - /* Give a name to the unnamed tasks */ + int ret; - if (!name) - { - name = (FAR char *)g_noname; - } + /* Setup the task name */ - /* Copy the name into the TCB */ + task_namesetup(tcb, name); - strncpy(tcb->cmn.name, name, CONFIG_TASK_NAME_SIZE); +#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. + */ - /* Save the name as the first argument */ + ret = task_stackargsetup(tcb, argv); - 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. + /* In the "normal" case, the argv[] array is a structure in the TCB, the + * arguments are cloned via strdup. */ - i = 1; - if (argv) - { - for (; i < CONFIG_MAX_TASK_ARGS+1 && argv[i-1]; i++) - { - tcb->argv[i] = strdup(argv[i-1]); - } - } + ret = task_tcbargsetup(tcb, argv); - /* Nullify any unused argument storage */ - - for (; i < CONFIG_MAX_TASK_ARGS+1; i++) - { - tcb->argv[i] = NULL; - } +#endif /* !CONFIG_CUSTOM_STACK && CONFIG_NUTTX_KERNEL */ - return OK; + return ret; } |