diff --git a/ChangeLog b/ChangeLog index 5ad9eaaf05..479a5c529b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1657,10 +1657,5 @@ (usually called current_regs) should be marked volatile; Added general capability to support nested interrupts (not fully realized for all architectures). - - - - - - + * sched/task_create.c: Add support for starting kernel-mode thread. diff --git a/Documentation/NuttxPortingGuide.html b/Documentation/NuttxPortingGuide.html index 5efc76e6c3..b55dc6fd95 100644 --- a/Documentation/NuttxPortingGuide.html +++ b/Documentation/NuttxPortingGuide.html @@ -12,7 +12,7 @@

NuttX RTOS Porting Guide

-

Last Updated: April 6, 2011

+

Last Updated: April 7, 2011

@@ -1217,14 +1217,23 @@ The system can be re-made subsequently by just typing make.

Prototype: void up_initial_state(FAR _TCB *tcb);

Description. - A new thread is being started and a new TCB - has been created. This function is called to initialize - the processor specific portions of the new TCB. + A new thread is being started and a new TCB has been created. + This function is called to initialize the processor specific portions of the new TCB.

- This function must setup the initial architecture registers - and/or stack so that execution will begin at tcb->start - on the next context switch. + This function must setup the initial architecture registers and/or stack so that execution + will begin at tcb->start on the next context switch. +

+

+ This function may also need to set up processor registers so that the new thread executes + with the correct privileges. + If CONFIG_NUTTX_KERNEL has been selected in the NuttX configuration, + then special initialization may need to be performed depending on the task type specified + in the TCB's flags field: + Kernel threads will require kernel-mode privileges; + User tasks and pthreads should have only user-mode privileges. + If CONFIG_NUTTX_KERNEL has not been selected, + then all threads should have kernel-mode privileges.

4.1.4 up_create_stack()

diff --git a/include/sched.h b/include/sched.h index 72c860f0de..aa1103bde5 100644 --- a/include/sched.h +++ b/include/sched.h @@ -67,7 +67,7 @@ /* One processor family supported by NuttX has a single, fixed hardware stack. * That is the 8051 family. So for that family only, there is a variant form * of task_create() that does not take a stack size parameter. The following - * helper macro is provided to work around the ugliness of that exception. + * helper macros are provided to work around the ugliness of that exception. */ #ifndef CONFIG_CUSTOM_STACK diff --git a/sched/os_bringup.c b/sched/os_bringup.c index 84971ad6c3..9f05a3c70f 100644 --- a/sched/os_bringup.c +++ b/sched/os_bringup.c @@ -141,9 +141,9 @@ int os_bringup(void) #ifdef CONFIG_PAGING svdbg("Starting paging thread\n"); - g_pgworker = TASK_CREATE("pgfill", CONFIG_PAGING_DEFPRIO, - CONFIG_PAGING_STACKSIZE, - (main_t)pg_worker, (const char **)NULL); + g_pgworker = KERNEL_THREAD("pgfill", CONFIG_PAGING_DEFPRIO, + CONFIG_PAGING_STACKSIZE, + (main_t)pg_worker, (const char **)NULL); ASSERT(g_pgworker != ERROR); #endif @@ -152,9 +152,9 @@ int os_bringup(void) #ifdef CONFIG_SCHED_WORKQUEUE svdbg("Starting worker thread\n"); - g_worker = TASK_CREATE("work", CONFIG_SCHED_WORKPRIORITY, - CONFIG_SCHED_WORKSTACKSIZE, - (main_t)work_thread, (const char **)NULL); + g_worker = KERNEL_THREAD("work", CONFIG_SCHED_WORKPRIORITY, + CONFIG_SCHED_WORKSTACKSIZE, + (main_t)work_thread, (const char **)NULL); ASSERT(g_worker != ERROR); #endif diff --git a/sched/os_internal.h b/sched/os_internal.h index 8cd7257b4c..ceeb70df18 100644 --- a/sched/os_internal.h +++ b/sched/os_internal.h @@ -106,6 +106,18 @@ enum os_crash_codes_e # define sched_releasefiles(t) (OK) #endif +/* One processor family supported by NuttX has a single, fixed hardware stack. + * That is the 8051 family. So for that family only, there is a variant form + * of kernel_thread() that does not take a stack size parameter. The following + * helper macro is provided to work around the ugliness of that exception. + */ + +#ifndef CONFIG_CUSTOM_STACK +# define KERNEL_THREAD(n,p,s,e,a) task_create(n,p,s,e,a) +#else +# define KERNEL_THREAD(n,p,s,e,a) task_create(n,p,e,a) +#endif + /* A more efficient ways to access the errno */ #define SET_ERRNO(e) \ @@ -254,7 +266,13 @@ extern int task_schedsetup(FAR _TCB *tcb, int priority, start_t start, main_t main); extern int task_argsetup(FAR _TCB *tcb, const char *name, const char *argv[]); extern int task_deletecurrent(void); - +#ifndef CONFIG_CUSTOM_STACK +extern int kernel_thread(const char *name, int priority, + int stack_size, main_t entry, const char *argv[]); +#else +extern int kernel_thread(const char *name, int priority, + main_t entry, const char *argv[]); +#endif extern bool sched_addreadytorun(FAR _TCB *rtrtcb); extern bool sched_removereadytorun(FAR _TCB *rtrtcb); extern bool sched_addprioritized(FAR _TCB *newTcb, DSEG dq_queue_t *list); diff --git a/sched/os_start.c b/sched/os_start.c index da34ad8950..412c24ebc8 100644 --- a/sched/os_start.c +++ b/sched/os_start.c @@ -287,6 +287,7 @@ void os_start(void) /* Initialize the processor-specific portion of the TCB */ + g_idletcb.flags = TCB_FLAG_TTYPE_KERNEL; up_initial_state(&g_idletcb); /* Initialize the memory manager */ diff --git a/sched/pthread_create.c b/sched/pthread_create.c index e247ce372f..d51a5956bc 100644 --- a/sched/pthread_create.c +++ b/sched/pthread_create.c @@ -340,6 +340,12 @@ int pthread_create(FAR pthread_t *thread, FAR pthread_attr_t *attr, #endif } + /* Mark this task as a pthread (this setting will be needed in + * task_schedsetup() when up_initial_state() is called. + */ + + ptcb->flags |= TCB_FLAG_TTYPE_PTHREAD; + /* Initialize the task control block */ status = task_schedsetup(ptcb, priority, pthread_start, @@ -352,10 +358,6 @@ int pthread_create(FAR pthread_t *thread, FAR pthread_attr_t *attr, return EBUSY; } - /* Mark this task as a pthread */ - - ptcb->flags |= TCB_FLAG_TTYPE_PTHREAD; - /* Configure the TCB for a pthread receiving on parameter * passed by value */ diff --git a/sched/task_create.c b/sched/task_create.c index 3965e61efd..23478c8101 100644 --- a/sched/task_create.c +++ b/sched/task_create.c @@ -67,11 +67,126 @@ ****************************************************************************/ /**************************************************************************** - * Private Function Prototypes + * Private Functions ****************************************************************************/ /**************************************************************************** - * Private Functions + * Name: thread_create + * + * Description: + * This function creates and activates a new thread of the specified type + * with a specified priority and returns its system-assigned ID. It is the + * internal, commn implementation of task_create() and kernel_thread(). See + * comments with task_create() for further information. + * + * Input Parameters: + * name - Name of the new task + * type - Type of the new task + * priority - Priority of the new task + * stack_size - size (in bytes) of the stack needed + * entry - Entry point of a new task + * arg - 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: + * Returns the non-zero process ID of the new task or ERROR if memory is + * insufficient or the task cannot be created. The errno will be set to + * indicate the nature of the error (always ENOMEM). + * + ****************************************************************************/ + +#ifndef CONFIG_CUSTOM_STACK +static int thread_create(const char *name, uint8_t type, int priority, + int stack_size, main_t entry, const char **argv) +#else +static int thread_create(const char *name, uint8_t type, int priority, + main_t entry, const char **argv) +#endif +{ + FAR _TCB *tcb; + pid_t pid; + int ret; + + /* Allocate a TCB for the new task. */ + + tcb = (FAR _TCB*)kzalloc(sizeof(_TCB)); + if (!tcb) + { + goto errout; + } + + /* Associate file descriptors with the new task */ + +#if CONFIG_NFILE_DESCRIPTORS > 0 || CONFIG_NSOCKET_DESCRIPTORS > 0 + ret = sched_setuptaskfiles(tcb); + if (ret != OK) + { + goto errout_with_tcb; + } +#endif + + /* Clone the parent's task environment */ + + (void)env_dup(tcb); + + /* Allocate the stack for the TCB */ + +#ifndef CONFIG_CUSTOM_STACK + ret = up_create_stack(tcb, stack_size); + if (ret != OK) + { + goto errout_with_tcb; + } +#endif + + /* Mark the type of this thread (this setting will be needed in + * task_schedsetup() when up_initial_state() is called. + */ + + tcb->flags |= type; + + /* Initialize the task control block */ + + ret = task_schedsetup(tcb, priority, task_start, entry); + if (ret != OK) + { + goto errout_with_tcb; + } + + /* Setup to pass parameters to the new task */ + + (void)task_argsetup(tcb, name, argv); + + /* Get the assigned pid before we start the task */ + + pid = (int)tcb->pid; + + /* Activate the task */ + + ret = task_activate(tcb); + if (ret != OK) + { + dq_rem((FAR dq_entry_t*)tcb, (dq_queue_t*)&g_inactivetasks); + goto errout_with_tcb; + } + + return pid; + +errout_with_tcb: + sched_releasetcb(tcb); + +errout: + errno = ENOMEM; + return ERROR; +} + +/**************************************************************************** + * Public Functions ****************************************************************************/ /**************************************************************************** @@ -105,9 +220,9 @@ * NULL. * * Return Value: - * Returns the non-zero process ID of the new task or - * ERROR if memory is insufficient or the task cannot be - * created (errno is not set). + * Returns the non-zero process ID of the new task or ERROR if memory is + * insufficient or the task cannot be created. The errno will be set to + * indicate the nature of the error (always ENOMEM). * ****************************************************************************/ @@ -119,70 +234,41 @@ int task_create(const char *name, int priority, main_t entry, const char *argv[]) #endif { - FAR _TCB *tcb; - int status; - pid_t pid; - - /* Allocate a TCB for the new task. */ - - tcb = (FAR _TCB*)kzalloc(sizeof(_TCB)); - if (!tcb) - { - errno = ENOMEM; - return ERROR; - } - - /* Associate file descriptors with the new task */ - -#if CONFIG_NFILE_DESCRIPTORS > 0 || CONFIG_NSOCKET_DESCRIPTORS > 0 - if (sched_setuptaskfiles(tcb) != OK) - { - sched_releasetcb(tcb); - return ERROR; - } +#ifndef CONFIG_CUSTOM_STACK + return thread_create(name, TCB_FLAG_TTYPE_TASK, priority, stack_size, entry, argv); +#else + return thread_create(name, TCB_FLAG_TTYPE_TASK, priority, entry, argv); #endif +} - /* Clone the parent's task environment */ - - (void)env_dup(tcb); - - /* Allocate the stack for the TCB */ +/**************************************************************************** + * Name: kernel_thread + * + * Description: + * This function creates and activates a kernel thread task with kernel- + * mode privileges. It is identical to task_create() except that it + * configures the newly started thread to run in kernel model. + * + * Input Parameters: + * (same as task_create()) + * + * Return Value: + * (same as task_create()) + * + ****************************************************************************/ #ifndef CONFIG_CUSTOM_STACK - status = up_create_stack(tcb, stack_size); - if (status != OK) - { - sched_releasetcb(tcb); - return ERROR; - } +int kernel_thread(const char *name, int priority, + int stack_size, main_t entry, const char *argv[]) +#else +int kernel_thread(const char *name, int priority, + main_t entry, const char *argv[]) +#endif +{ +#ifndef CONFIG_CUSTOM_STACK + return thread_create(name, TCB_FLAG_TTYPE_KERNEL, priority, stack_size, entry, argv); +#else + return thread_create(name, TCB_FLAG_TTYPE_KERNEL, priority, entry, argv); #endif - - /* Initialize the task control block */ - - status = task_schedsetup(tcb, priority, task_start, entry); - if (status != OK) - { - sched_releasetcb(tcb); - return ERROR; - } - - /* Setup to pass parameters to the new task */ - - (void)task_argsetup(tcb, name, argv); - - /* Get the assigned pid before we start the task */ - - pid = (int)tcb->pid; - - /* Activate the task */ - - status = task_activate(tcb); - if (status != OK) - { - dq_rem((FAR dq_entry_t*)tcb, (dq_queue_t*)&g_inactivetasks); - sched_releasetcb(tcb); - return ERROR; - } - - return pid; } + diff --git a/sched/task_setup.c b/sched/task_setup.c index 217bdc892b..9fdbf3d253 100644 --- a/sched/task_setup.c +++ b/sched/task_setup.c @@ -1,7 +1,7 @@ /**************************************************************************** * sched/task_setup.c * - * Copyright (C) 2007-2010 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2011 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -202,6 +202,7 @@ static inline void task_dupdspace(FAR _TCB *tcb) * priority - Priority of the new task * entry - Entry point of a new task * main - Application start point of the new task + * type - Type of the new thread: task, pthread, or kernel thread * * Return Value: * OK on success; ERROR on failure.