diff --git a/ChangeLog b/ChangeLog index 1e90ee2de06..1ec62c208a8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4124,4 +4124,10 @@ * includes/nuttx/sched.h and Lots of files: Change name of _TCB to struct tcb_s so that (1) it is consitent with other NuttX naming and so that (2) the naming can handle some upcoming changes. + * includes/nuttx/sched.h and sched/: There are three TCB structures: + struct tcb_s is a generic common version, struct task_tcb_s is a + version for tasks and kernel threads and pthread_tcb_s is a version + for pthreads. By dividing the TCB structure into these variants, + pthreads do not have to be burdened by task-specific data structures + (and vice versa). diff --git a/binfmt/binfmt_execmodule.c b/binfmt/binfmt_execmodule.c index 7d7f00b3319..bb91d78c5fc 100644 --- a/binfmt/binfmt_execmodule.c +++ b/binfmt/binfmt_execmodule.c @@ -134,7 +134,7 @@ static void exec_ctors(FAR void *arg) int exec_module(FAR const struct binary_s *binp) { - FAR struct tcb_s *tcb; + FAR struct task_tcb_s *tcb; #ifndef CONFIG_CUSTOM_STACK FAR uint32_t *stack; #endif @@ -156,7 +156,7 @@ int exec_module(FAR const struct binary_s *binp) /* Allocate a TCB for the new task. */ - tcb = (FAR struct tcb_s*)kzalloc(sizeof(struct tcb_s)); + tcb = (FAR struct task_tcb_s*)kzalloc(sizeof(struct task_tcb_s)); if (!tcb) { err = ENOMEM; @@ -198,17 +198,17 @@ int exec_module(FAR const struct binary_s *binp) */ #ifdef CONFIG_PIC - tcb->dspace = binp->alloc[0]; + tcb->cmn.dspace = binp->alloc[0]; /* Re-initialize the task's initial state to account for the new PIC base */ - up_initial_state(tcb); + up_initial_state(&tcb->cmn); #endif /* Assign the address environment to the task */ #ifdef CONFIG_ADDRENV - ret = up_addrenv_assign(binp->addrenv, tcb); + ret = up_addrenv_assign(binp->addrenv, &tcb->cmn); if (ret < 0) { err = -ret; @@ -228,7 +228,7 @@ int exec_module(FAR const struct binary_s *binp) /* Get the assigned pid before we start the task */ - pid = tcb->pid; + pid = tcb->cmn.pid; /* Then activate the task at the provided priority */ @@ -244,11 +244,11 @@ int exec_module(FAR const struct binary_s *binp) errout_with_stack: #ifndef CONFIG_CUSTOM_STACK - tcb->stack_alloc_ptr = NULL; - sched_releasetcb(tcb); + tcb->cmn.stack_alloc_ptr = NULL; + sched_releasetcb(&tcb->cmn); kfree(stack); #else - sched_releasetcb(tcb); + sched_releasetcb(&tcb->cmn); #endif goto errout; diff --git a/include/nuttx/sched.h b/include/nuttx/sched.h index 68afb3bf581..02d44d8299a 100644 --- a/include/nuttx/sched.h +++ b/include/nuttx/sched.h @@ -387,8 +387,9 @@ struct task_group_s #endif /* struct tcb_s ******************************************************************/ -/* This is the common part of the task control block (TCB). Each task or thread - * is represented by a TCB. The TCB is the heart of the NuttX task-control logic. +/* This is the common part of the task control block (TCB). The TCB is the heart + * of the NuttX task-control logic. Each task or thread is represented by a TCB + * that includes these common definitions. */ struct tcb_s @@ -419,12 +420,6 @@ struct tcb_s start_t start; /* Thread start function */ entry_t entry; /* Entry Point into the thread */ - -#ifdef CONFIG_SCHED_STARTHOOK - starthook_t starthook; /* Task startup function */ - FAR void *starthookarg; /* The argument passed to the function */ -#endif - uint8_t sched_priority; /* Current priority of the thread */ #ifdef CONFIG_PRIORITY_INHERITANCE @@ -439,19 +434,10 @@ struct tcb_s uint16_t flags; /* Misc. general status flags */ int16_t lockcount; /* 0=preemptable (not-locked) */ -#ifndef CONFIG_DISABLE_PTHREAD - FAR void *joininfo; /* Detach-able info to support join */ -#endif - #if CONFIG_RR_INTERVAL > 0 int timeslice; /* RR timeslice interval remaining */ #endif - /* Values needed to restart a task ********************************************/ - - uint8_t init_priority; /* Initial priority of the task */ - char *argv[CONFIG_MAX_TASK_ARGS+1]; /* Name+start-up parameters */ - /* Stack-Related Fields *******************************************************/ #ifndef CONFIG_CUSTOM_STACK @@ -470,12 +456,6 @@ struct tcb_s FAR struct dspace_s *dspace; /* Allocated area for .bss and .data */ #endif - /* POSIX Thread Specific Data *************************************************/ - -#if !defined(CONFIG_DISABLE_PTHREAD) && CONFIG_NPTHREAD_KEYS > 0 - FAR void *pthread_data[CONFIG_NPTHREAD_KEYS]; -#endif - /* POSIX Semaphore Control Fields *********************************************/ sem_t *waitsem; /* Semaphore ID waiting on */ @@ -512,6 +492,65 @@ struct tcb_s #endif }; +/* struct task_tcb_s *************************************************************/ +/* This is the particular form of the task control block (TCB) structure used by + * tasks (and kernel threads). There are two TCB forms: one for pthreads and + * one for tasks. Both share the common TCB fields (which must appear at the + * top of the structure) plus additional fields unique to tasks and threads. + * Having separate structures for tasks and pthreads adds some complexity, but + * saves memory in that it prevents pthreads from being burdened with the + * overhead required for tasks (and vice versa). + */ + +struct task_tcb_s +{ + /* Common TCB fields **********************************************************/ + + struct tcb_s cmn; /* Common TCB fields */ + + /* Task Management Fields *****************************************************/ + +#ifdef CONFIG_SCHED_STARTHOOK + starthook_t starthook; /* Task startup function */ + FAR void *starthookarg; /* The argument passed to the function */ +#endif + + /* Values needed to restart a task ********************************************/ + + uint8_t init_priority; /* Initial priority of the task */ + char *argv[CONFIG_MAX_TASK_ARGS+1]; /* Name+start-up parameters */ +}; + +/* struct pthread_tcb_s **********************************************************/ +/* This is the particular form of the task control block (TCB) structure used by + * pthreads. There are two TCB forms: one for pthreads and one for tasks. Both + * share the common TCB fields (which must appear at the top of the structure) + * plus additional fields unique to tasks and threads. Having separate structures + * for tasks and pthreads adds some complexity, but saves memory in that it + * prevents pthreads from being burdened with the overhead required for tasks + * (and vice versa). + */ + +#ifndef CONFIG_DISABLE_PTHREAD +struct pthread_tcb_s +{ + /* Common TCB fields **********************************************************/ + + struct tcb_s cmn; /* Common TCB fields */ + + /* Task Management Fields *****************************************************/ + + pthread_addr_t arg; /* Startup argument */ + FAR void *joininfo; /* Detach-able info to support join */ + + /* POSIX Thread Specific Data *************************************************/ + +#if CONFIG_NPTHREAD_KEYS > 0 + FAR void *pthread_data[CONFIG_NPTHREAD_KEYS]; +#endif +}; +#endif /* !CONFIG_DISABLE_PTHREAD */ + /* This is the callback type used by sched_foreach() */ typedef void (*sched_foreach_t)(FAR struct tcb_s *tcb, FAR void *arg); @@ -556,7 +595,7 @@ FAR struct socketlist *sched_getsockets(void); /* Setup up a start hook */ #ifdef CONFIG_SCHED_STARTHOOK -void task_starthook(FAR struct tcb_s *tcb, starthook_t starthook, FAR void *arg); +void task_starthook(FAR struct task_tcb_s *tcb, starthook_t starthook, FAR void *arg); #endif /* Internal vfork support.The overall sequence is: diff --git a/sched/group_internal.h b/sched/group_internal.h index 8936b9bbf6c..e79f96e8c4a 100644 --- a/sched/group_internal.h +++ b/sched/group_internal.h @@ -122,10 +122,10 @@ void group_removechildren(FAR struct task_group_s *group); /* Group data resource configuration */ #if CONFIG_NFILE_DESCRIPTORS > 0 || CONFIG_NSOCKET_DESCRIPTORS > 0 -int group_setupidlefiles(FAR struct tcb_s *tcb); -int group_setuptaskfiles(FAR struct tcb_s *tcb); +int group_setupidlefiles(FAR struct task_tcb_s *tcb); +int group_setuptaskfiles(FAR struct task_tcb_s *tcb); #if CONFIG_NFILE_STREAMS > 0 -int group_setupstreams(FAR struct tcb_s *tcb); +int group_setupstreams(FAR struct task_tcb_s *tcb); #endif #endif diff --git a/sched/group_setupidlefiles.c b/sched/group_setupidlefiles.c index d3e00660cd6..25ed71c0464 100644 --- a/sched/group_setupidlefiles.c +++ b/sched/group_setupidlefiles.c @@ -78,10 +78,10 @@ * ****************************************************************************/ -int group_setupidlefiles(FAR struct tcb_s *tcb) +int group_setupidlefiles(FAR struct task_tcb_s *tcb) { #if CONFIG_NFILE_DESCRIPTORS > 0 || CONFIG_NFILE_DESCRIPTORS > 0 - FAR struct task_group_s *group = tcb->group; + FAR struct task_group_s *group = tcb->cmn.group; #endif #if CONFIG_NFILE_DESCRIPTORS > 0 && defined(CONFIG_DEV_CONSOLE) int fd; diff --git a/sched/group_setupstreams.c b/sched/group_setupstreams.c index 377ee9e97f1..217decd5735 100644 --- a/sched/group_setupstreams.c +++ b/sched/group_setupstreams.c @@ -72,13 +72,13 @@ * ****************************************************************************/ -int group_setupstreams(FAR struct tcb_s *tcb) +int group_setupstreams(FAR struct task_tcb_s *tcb) { - DEBUGASSERT(tcb && tcb->group); + DEBUGASSERT(tcb && tcb->cmn.group); /* Initialize file streams for the task group */ - lib_streaminit(&tcb->group->tg_streamlist); + lib_streaminit(&tcb->cmn.group->tg_streamlist); /* fdopen to get the stdin, stdout and stderr streams. The following logic * depends on the fact that the library layer will allocate FILEs in order. @@ -88,9 +88,9 @@ int group_setupstreams(FAR struct tcb_s *tcb) * fd = 2 is stderr (write-only, append) */ - (void)fs_fdopen(0, O_RDONLY, tcb); - (void)fs_fdopen(1, O_WROK|O_CREAT, tcb); - (void)fs_fdopen(2, O_WROK|O_CREAT, tcb); + (void)fs_fdopen(0, O_RDONLY, (FAR struct tcb_s *)tcb); + (void)fs_fdopen(1, O_WROK|O_CREAT, (FAR struct tcb_s *)tcb); + (void)fs_fdopen(2, O_WROK|O_CREAT, (FAR struct tcb_s *)tcb); return OK; } diff --git a/sched/group_setuptaskfiles.c b/sched/group_setuptaskfiles.c index 8d1895c949e..269485ea468 100644 --- a/sched/group_setuptaskfiles.c +++ b/sched/group_setuptaskfiles.c @@ -85,7 +85,7 @@ ****************************************************************************/ #if CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_FDCLONE_DISABLE) -static inline void sched_dupfiles(FAR struct tcb_s *tcb) +static inline void sched_dupfiles(FAR struct task_tcb_s *tcb) { /* The parent task is the one at the head of the ready-to-run list */ @@ -94,7 +94,7 @@ static inline void sched_dupfiles(FAR struct tcb_s *tcb) FAR struct file *child; int i; - DEBUGASSERT(tcb && tcb->group && rtcb->group); + DEBUGASSERT(tcb && tcb->cmn.group && rtcb->group); /* Duplicate the file descriptors. This will be either all of the * file descriptors or just the first three (stdin, stdout, and stderr) @@ -105,7 +105,7 @@ static inline void sched_dupfiles(FAR struct tcb_s *tcb) /* Get pointers to the parent and child task file lists */ parent = rtcb->group->tg_filelist.fl_files; - child = tcb->group->tg_filelist.fl_files; + child = tcb->cmn.group->tg_filelist.fl_files; /* Check each file in the parent file list */ @@ -143,7 +143,7 @@ static inline void sched_dupfiles(FAR struct tcb_s *tcb) ****************************************************************************/ #if CONFIG_NSOCKET_DESCRIPTORS > 0 && !defined(CONFIG_SDCLONE_DISABLE) -static inline void sched_dupsockets(FAR struct tcb_s *tcb) +static inline void sched_dupsockets(FAR struct task_tcb_s *tcb) { /* The parent task is the one at the head of the ready-to-run list */ @@ -156,12 +156,12 @@ static inline void sched_dupsockets(FAR struct tcb_s *tcb) * task. */ - DEBUGASSERT(tcb && tcb->group && rtcb->group); + DEBUGASSERT(tcb && tcb->cmn.group && rtcb->group); /* Get pointers to the parent and child task socket lists */ parent = rtcb->group->tg_socketlist.sl_sockets; - child = tcb->group->tg_socketlist.sl_sockets; + child = tcb->cmn.group->tg_socketlist.sl_sockets; /* Check each socket in the parent socket list */ @@ -206,13 +206,16 @@ static inline void sched_dupsockets(FAR struct tcb_s *tcb) * ****************************************************************************/ -int group_setuptaskfiles(FAR struct tcb_s *tcb) +int group_setuptaskfiles(FAR struct task_tcb_s *tcb) { #if CONFIG_NFILE_DESCRIPTORS > 0 || CONFIG_NSOCKET_DESCRIPTORS > 0 - FAR struct task_group_s *group = tcb->group; + FAR struct task_group_s *group = tcb->cmn.group; DEBUGASSERT(group); #endif +#ifndef CONFIG_DISABLE_PTHREAD + DEBUGASSERT((tcb->cmn.flags & TCB_FLAG_TTYPE_MASK) != TCB_FLAG_TTYPE_PTHREAD); +#endif #if CONFIG_NFILE_DESCRIPTORS > 0 /* Initialize file descriptors for the TCB */ diff --git a/sched/os_internal.h b/sched/os_internal.h index 22f69e53d9e..eef0d5e7054 100644 --- a/sched/os_internal.h +++ b/sched/os_internal.h @@ -257,9 +257,9 @@ int os_bringup(void); void weak_function task_initialize(void); #endif void task_start(void); -int task_schedsetup(FAR struct tcb_s *tcb, int priority, start_t start, +int task_schedsetup(FAR struct task_tcb_s *tcb, int priority, start_t start, main_t main, uint8_t ttype); -int task_argsetup(FAR struct tcb_s *tcb, FAR const char *name, FAR char * const argv[]); +int task_argsetup(FAR struct task_tcb_s *tcb, FAR const char *name, FAR char * const argv[]); void task_exithook(FAR struct tcb_s *tcb, int status); int task_deletecurrent(void); diff --git a/sched/os_start.c b/sched/os_start.c index fd13865db2d..ace475ba129 100644 --- a/sched/os_start.c +++ b/sched/os_start.c @@ -204,7 +204,7 @@ const tasklist_t g_tasklisttable[NUM_TASK_STATES] = * that user init task is responsible for bringing up the rest of the system */ -static FAR struct tcb_s g_idletcb; +static FAR struct task_tcb_s g_idletcb; /* This is the name of the idle task */ @@ -262,7 +262,7 @@ void os_start(void) /* Assign the process ID of ZERO to the idle task */ - g_pidhash[ PIDHASH(0)].tcb = &g_idletcb; + g_pidhash[ PIDHASH(0)].tcb = &g_idletcb.cmn; g_pidhash[ PIDHASH(0)].pid = 0; /* Initialize a TCB for this thread of execution. NOTE: The default @@ -272,13 +272,13 @@ void os_start(void) * that has pid == 0 and sched_priority == 0. */ - bzero((void*)&g_idletcb, sizeof(struct tcb_s)); - g_idletcb.task_state = TSTATE_TASK_RUNNING; - g_idletcb.entry.main = (main_t)os_start; + bzero((void*)&g_idletcb, sizeof(struct task_tcb_s)); + g_idletcb.cmn.task_state = TSTATE_TASK_RUNNING; + g_idletcb.cmn.entry.main = (main_t)os_start; #if CONFIG_TASK_NAME_SIZE > 0 - strncpy(g_idletcb.name, g_idlename, CONFIG_TASK_NAME_SIZE-1); - g_idletcb.argv[0] = g_idletcb.name; + strncpy(g_idletcb.cmn.name, g_idlename, CONFIG_TASK_NAME_SIZE-1); + g_idletcb.argv[0] = g_idletcb.cmn.name; #else g_idletcb.argv[0] = (char*)g_idlename; #endif /* CONFIG_TASK_NAME_SIZE */ @@ -289,7 +289,7 @@ void os_start(void) /* Initialize the processor-specific portion of the TCB */ - up_initial_state(&g_idletcb); + up_initial_state(&g_idletcb.cmn); /* Initialize the semaphore facility(if in link). This has to be done * very early because many subsystems depend upon fully functional @@ -330,7 +330,7 @@ void os_start(void) /* Allocate the IDLE group and suppress child status. */ #ifdef HAVE_TASK_GROUP - (void)group_allocate(&g_idletcb); + (void)group_allocate(&g_idletcb.cmn); #endif /* Initialize the interrupt handling subsystem (if included) */ @@ -456,8 +456,8 @@ void os_start(void) */ #ifdef HAVE_TASK_GROUP - (void)group_initialize(&g_idletcb); - g_idletcb.group->tg_flags = GROUP_FLAG_NOCLDWAIT; + (void)group_initialize(&g_idletcb.cmn); + g_idletcb.cmn.group->tg_flags = GROUP_FLAG_NOCLDWAIT; #endif /* Create initial tasks and bring-up the system */ diff --git a/sched/pthread_create.c b/sched/pthread_create.c index 956c0aed978..70b5ceb4935 100644 --- a/sched/pthread_create.c +++ b/sched/pthread_create.c @@ -99,48 +99,26 @@ static const char g_pthreadname[] = ""; * * Input Parameters: * tcb - Address of the new task's TCB - * name - Name of the new task (not used) - * 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. + * arg - The argument to provide to the pthread on startup. * * Return Value: * None * ****************************************************************************/ -static void pthread_argsetup(FAR struct tcb_s *tcb, pthread_addr_t arg) +static inline void pthread_argsetup(FAR struct pthread_tcb_s *tcb, pthread_addr_t arg) { - int i; - #if CONFIG_TASK_NAME_SIZE > 0 /* Copy the pthread name into the TCB */ - strncpy(tcb->name, g_pthreadname, CONFIG_TASK_NAME_SIZE); - - /* Save the name as the first argument in the TCB */ - - tcb->argv[0] = tcb->name; -#else - /* Save the name as the first argument in the TCB */ - - tcb->argv[0] = (char *)g_pthreadname; + strncpy(tcb->cmn.name, g_pthreadname, CONFIG_TASK_NAME_SIZE); #endif /* CONFIG_TASK_NAME_SIZE */ /* For pthreads, args are strictly pass-by-value; that actual * type wrapped by pthread_addr_t is unknown. */ - tcb->argv[1] = (char*)arg; - - /* Nullify the remaining, unused argument storage */ - - for (i = 2; i < CONFIG_MAX_TASK_ARGS+1; i++) - { - tcb->argv[i] = NULL; - } + tcb->arg = arg; } /**************************************************************************** @@ -189,8 +167,8 @@ static inline void pthread_addjoininfo(FAR struct task_group_s *group, static void pthread_start(void) { - FAR struct tcb_s *ptcb = (FAR struct tcb_s*)g_readytorun.head; - FAR struct task_group_s *group = ptcb->group; + FAR struct pthread_tcb_s *ptcb = (FAR struct pthread_tcb_s*)g_readytorun.head; + FAR struct task_group_s *group = ptcb->cmn.group; FAR struct join_s *pjoin = (FAR struct join_s*)ptcb->joininfo; pthread_addr_t exit_status; @@ -214,7 +192,7 @@ static void pthread_start(void) * available to the pthread. */ - exit_status = (*ptcb->entry.pthread)((pthread_addr_t)ptcb->argv[1]); + exit_status = (*ptcb->cmn.entry.pthread)(ptcb->arg); /* The thread has returned */ @@ -247,7 +225,7 @@ static void pthread_start(void) int pthread_create(FAR pthread_t *thread, FAR pthread_attr_t *attr, pthread_startroutine_t start_routine, pthread_addr_t arg) { - FAR struct tcb_s *ptcb; + FAR struct pthread_tcb_s *ptcb; FAR struct join_s *pjoin; int priority; #if CONFIG_RR_INTERVAL > 0 @@ -266,7 +244,7 @@ int pthread_create(FAR pthread_t *thread, FAR pthread_attr_t *attr, /* Allocate a TCB for the new task. */ - ptcb = (FAR struct tcb_s*)kzalloc(sizeof(struct tcb_s)); + ptcb = (FAR struct pthread_tcb_s *)kzalloc(sizeof(struct pthread_tcb_s)); if (!ptcb) { return ENOMEM; @@ -277,7 +255,7 @@ int pthread_create(FAR pthread_t *thread, FAR pthread_attr_t *attr, */ #ifdef HAVE_TASK_GROUP - ret = group_bind(ptcb); + ret = group_bind((FAR struct tcb_s *)ptcb); if (ret < 0) { errcode = ENOMEM; @@ -291,7 +269,8 @@ int pthread_create(FAR pthread_t *thread, FAR pthread_attr_t *attr, */ #ifdef CONFIG_ADDRENV - ret = up_addrenv_share((FAR const struct tcb_s *)g_readytorun.head, ptcb); + ret = up_addrenv_share((FAR const struct tcb_s *)g_readytorun.head, + (FAR struct tcb_s *)ptcb); if (ret < 0) { errcode = -ret; @@ -310,7 +289,7 @@ int pthread_create(FAR pthread_t *thread, FAR pthread_attr_t *attr, /* Allocate the stack for the TCB */ - ret = up_create_stack(ptcb, attr->stacksize); + ret = up_create_stack((FAR struct tcb_s *)ptcb, attr->stacksize); if (ret != OK) { errcode = ENOMEM; @@ -359,8 +338,7 @@ int pthread_create(FAR pthread_t *thread, FAR pthread_attr_t *attr, /* Initialize the task control block */ - ret = task_schedsetup(ptcb, priority, pthread_start, (main_t)start_routine, - TCB_FLAG_TTYPE_PTHREAD); + ret = pthread_schedsetup(ptcb, priority, pthread_start, start_routine); if (ret != OK) { errcode = EBUSY; @@ -376,7 +354,7 @@ int pthread_create(FAR pthread_t *thread, FAR pthread_attr_t *attr, /* Join the parent's task group */ #ifdef HAVE_TASK_GROUP - ret = group_join(ptcb); + ret = group_join((FAR struct tcb_s *)ptcb); if (ret < 0) { errcode = ENOMEM; @@ -386,7 +364,7 @@ int pthread_create(FAR pthread_t *thread, FAR pthread_attr_t *attr, /* Attach the join info to the TCB. */ - ptcb->joininfo = (void*)pjoin; + ptcb->joininfo = (FAR void *)pjoin; /* If round robin scheduling is selected, set the appropriate flag * in the TCB. @@ -405,7 +383,7 @@ int pthread_create(FAR pthread_t *thread, FAR pthread_attr_t *attr, * as well. */ - pid = (int)ptcb->pid; + pid = (int)ptcb->cmn.pid; pjoin->thread = (pthread_t)pid; /* Initialize the semaphores in the join structure to zero. */ @@ -421,7 +399,7 @@ int pthread_create(FAR pthread_t *thread, FAR pthread_attr_t *attr, sched_lock(); if (ret == OK) { - ret = task_activate(ptcb); + ret = task_activate((FAR struct tcb_s *)ptcb); } if (ret == OK) @@ -465,6 +443,6 @@ errout_with_join: ptcb->joininfo = NULL; errout_with_tcb: - sched_releasetcb(ptcb); + sched_releasetcb((FAR struct tcb_s *)ptcb); return errcode; } diff --git a/sched/pthread_getspecific.c b/sched/pthread_getspecific.c index 065cb5a160b..1c87c29ebf4 100644 --- a/sched/pthread_getspecific.c +++ b/sched/pthread_getspecific.c @@ -104,11 +104,12 @@ FAR void *pthread_getspecific(pthread_key_t key) { #if CONFIG_NPTHREAD_KEYS > 0 - FAR struct tcb_s *rtcb = (FAR struct tcb_s*)g_readytorun.head; - FAR struct task_group_s *group = rtcb->group; + FAR struct pthread_tcb_s *rtcb = (FAR struct pthread_tcb_s*)g_readytorun.head; + FAR struct task_group_s *group = rtcb->cmn.group; FAR void *ret = NULL; - DEBUGASSERT(group); + DEBUGASSERT(group && + (rtcb->cmn.flags & TCB_FLAG_TTYPE_MASK) == TCB_FLAG_TTYPE_PTHREAD); /* Check if the key is valid. */ diff --git a/sched/pthread_internal.h b/sched/pthread_internal.h index 0b4adf758d2..aa0e8ba15de 100644 --- a/sched/pthread_internal.h +++ b/sched/pthread_internal.h @@ -46,6 +46,7 @@ #include #include #include +#include #include @@ -96,6 +97,8 @@ extern "C" struct task_group_s; /* Forward reference */ void weak_function pthread_initialize(void); +int pthread_schedsetup(FAR struct tcb_s *tcb, int priority, start_t start, + pthread_startroutine_t entry); int pthread_completejoin(pid_t pid, FAR void *exit_value); void pthread_destroyjoin(FAR struct task_group_s *group, FAR struct join_s *pjoin); diff --git a/sched/pthread_setspecific.c b/sched/pthread_setspecific.c index cc792b3ceb5..16401fbe67c 100644 --- a/sched/pthread_setspecific.c +++ b/sched/pthread_setspecific.c @@ -115,11 +115,12 @@ int pthread_setspecific(pthread_key_t key, FAR void *value) { #if CONFIG_NPTHREAD_KEYS > 0 - FAR struct tcb_s *rtcb = (FAR struct tcb_s*)g_readytorun.head; - FAR struct task_group_s *group = rtcb->group; + FAR struct pthread_tcb_s *rtcb = (FAR struct pthread_tcb_s*)g_readytorun.head; + FAR struct task_group_s *group = rtcb->cmn.group; int ret = EINVAL; - DEBUGASSERT(group); + DEBUGASSERT(group && + (rtcb->cmn.flags & TCB_FLAG_TTYPE_MASK) == TCB_FLAG_TTYPE_PTHREAD); /* Check if the key is valid. */ diff --git a/sched/sched_releasetcb.c b/sched/sched_releasetcb.c index 688c8bb9363..d4d59605dde 100644 --- a/sched/sched_releasetcb.c +++ b/sched/sched_releasetcb.c @@ -155,11 +155,14 @@ int sched_releasetcb(FAR struct tcb_s *tcb) * start/re-start. */ - if ((tcb->flags & TCB_FLAG_TTYPE_MASK) == TCB_FLAG_TTYPE_TASK) +#ifndef CONFIG_DISABLE_PTHREAD + if ((tcb->flags & TCB_FLAG_TTYPE_MASK) != TCB_FLAG_TTYPE_PTHREAD) +#endif { - for (i = 1; i < CONFIG_MAX_TASK_ARGS+1 && tcb->argv[i]; i++) + FAR struct task_tcb_s *ttcb = (FAR struct task_tcb_s *)tcb; + for (i = 1; i < CONFIG_MAX_TASK_ARGS+1 && ttcb->argv[i]; i++) { - sched_free((FAR void*)tcb->argv[i]); + sched_free((FAR void*)ttcb->argv[i]); } } diff --git a/sched/task_create.c b/sched/task_create.c index 976cca35be7..30fc1354ffa 100644 --- a/sched/task_create.c +++ b/sched/task_create.c @@ -106,14 +106,14 @@ static int thread_create(const char *name, uint8_t ttype, int priority, main_t entry, FAR char * const argv[]) #endif { - FAR struct tcb_s *tcb; + FAR struct task_tcb_s *tcb; pid_t pid; int errcode; int ret; /* Allocate a TCB for the new task. */ - tcb = (FAR struct tcb_s*)kzalloc(sizeof(struct tcb_s)); + tcb = (FAR struct task_tcb_s *)kzalloc(sizeof(struct task_tcb_s)); if (!tcb) { errcode = ENOMEM; @@ -123,7 +123,7 @@ static int thread_create(const char *name, uint8_t ttype, int priority, /* Allocate a new task group */ #ifdef HAVE_TASK_GROUP - ret = group_allocate(tcb); + ret = group_allocate((FAR struct tcb_s *)tcb); if (ret < 0) { errcode = -ret; @@ -145,7 +145,7 @@ static int thread_create(const char *name, uint8_t ttype, int priority, /* Allocate the stack for the TCB */ #ifndef CONFIG_CUSTOM_STACK - ret = up_create_stack(tcb, stack_size); + ret = up_create_stack((FAR struct tcb_s *)tcb, stack_size); if (ret != OK) { errcode = -ret; @@ -169,7 +169,7 @@ static int thread_create(const char *name, uint8_t ttype, int priority, /* Now we have enough in place that we can join the group */ #ifdef HAVE_TASK_GROUP - ret = group_initialize(tcb); + ret = group_initialize((FAR struct tcb_s *)tcb); if (ret < 0) { errcode = -ret; @@ -179,11 +179,11 @@ static int thread_create(const char *name, uint8_t ttype, int priority, /* Get the assigned pid before we start the task */ - pid = (int)tcb->pid; + pid = (int)tcb->cmn.pid; /* Activate the task */ - ret = task_activate(tcb); + ret = task_activate((FAR struct tcb_s *)tcb); if (ret != OK) { errcode = get_errno(); @@ -197,7 +197,7 @@ static int thread_create(const char *name, uint8_t ttype, int priority, return pid; errout_with_tcb: - sched_releasetcb(tcb); + sched_releasetcb((FAR struct tcb_s *)tcb); errout: set_errno(errcode); diff --git a/sched/task_exithook.c b/sched/task_exithook.c index 20d1bd16129..1c2137545d8 100644 --- a/sched/task_exithook.c +++ b/sched/task_exithook.c @@ -318,7 +318,9 @@ static inline void task_sigchild(gid_t pgid, FAR struct tcb_s *ctcb, int status) * interpretable exit Check if this is the main task that is exiting. */ - if ((ctcb->flags & TCB_FLAG_TTYPE_MASK) == TCB_FLAG_TTYPE_TASK) +#ifndef CONFIG_DISABLE_PTHREAD + if ((ctcb->flags & TCB_FLAG_TTYPE_MASK) != TCB_FLAG_TTYPE_PTHREAD) +#endif { task_exitstatus(pgrp, status); } @@ -363,7 +365,9 @@ static inline void task_sigchild(FAR struct tcb_s *ptcb, FAR struct tcb_s *ctcb, * that are still running. */ - if ((ctcb->flags & TCB_FLAG_TTYPE_MASK) == TCB_FLAG_TTYPE_TASK) +#ifndef CONFIG_DISABLE_PTHREAD + if ((ctcb->flags & TCB_FLAG_TTYPE_MASK) != TCB_FLAG_TTYPE_PTHREAD) +#endif { #ifdef CONFIG_SCHED_CHILD_STATUS /* Save the exit status now of the main thread */ @@ -480,11 +484,14 @@ static inline void task_exitwakeup(FAR struct tcb_s *tcb, int status) if (group) { - /* Only tasks return valid status. Record the exit status when the - * task exists. The group, however, may still be executing. + /* Only tasks (and kernel threads) return valid status. Record the + * exit status when the task exists. The group, however, may still + * be executing. */ - if ((tcb->flags & TCB_FLAG_TTYPE_MASK) == TCB_FLAG_TTYPE_TASK) +#ifndef CONFIG_DISABLE_PTHREAD + if ((tcb->flags & TCB_FLAG_TTYPE_MASK) != TCB_FLAG_TTYPE_PTHREAD) +#endif { /* Report the exit status. We do not nullify tg_statloc here * because we want to prent other tasks from registering for diff --git a/sched/task_init.c b/sched/task_init.c index 13f7ac8f795..802d0748d55 100644 --- a/sched/task_init.c +++ b/sched/task_init.c @@ -120,9 +120,17 @@ int task_init(FAR struct tcb_s *tcb, const char *name, int priority, main_t entry, FAR char * const argv[]) #endif { + FAR struct task_tcb_s *ttcb = (FAR struct task_tcb_s *)tcb; int errcode; int ret; + /* Only tasks and kernel threads can be initialized in this way */ + +#ifndef CONFIG_DISABLE_PTHREAD + DEBUGASSERT(tcb && + (tcb->flags & TCB_FLAG_TTYPE_MASK) != TCB_FLAG_TTYPE_PTHREAD); +#endif + /* Create a new task group */ #ifdef HAVE_TASK_GROUP @@ -137,7 +145,7 @@ int task_init(FAR struct tcb_s *tcb, const char *name, int priority, /* Associate file descriptors with the new task */ #if CONFIG_NFILE_DESCRIPTORS > 0 || CONFIG_NSOCKET_DESCRIPTORS > 0 - ret = group_setuptaskfiles(tcb); + ret = group_setuptaskfiles(ttcb); if (ret < 0) { errcode = -ret; @@ -153,7 +161,7 @@ int task_init(FAR struct tcb_s *tcb, const char *name, int priority, /* Initialize the task control block */ - ret = task_schedsetup(tcb, priority, task_start, entry, + ret = task_schedsetup(ttcb, priority, task_start, entry, TCB_FLAG_TTYPE_TASK); if (ret < OK) { @@ -163,7 +171,7 @@ int task_init(FAR struct tcb_s *tcb, const char *name, int priority, /* Setup to pass parameters to the new task */ - (void)task_argsetup(tcb, name, argv); + (void)task_argsetup(ttcb, name, argv); /* Now we have enough in place that we can join the group */ diff --git a/sched/task_restart.c b/sched/task_restart.c index 762cbec529b..578585c8e8d 100644 --- a/sched/task_restart.c +++ b/sched/task_restart.c @@ -1,7 +1,7 @@ /**************************************************************************** * sched/task_restart.c * - * Copyright (C) 2007, 2009, 2012 Gregory Nutt. All rights reserved. + * Copyright (C) 2007, 2009, 2012-2013 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -38,9 +38,13 @@ ****************************************************************************/ #include + #include #include +#include + #include + #include "os_internal.h" #include "sig_internal.h" @@ -97,7 +101,7 @@ int task_restart(pid_t pid) { FAR struct tcb_s *rtcb; - FAR struct tcb_s *tcb; + FAR struct task_tcb_s *tcb; irqstate_t state; int status; @@ -109,11 +113,12 @@ int task_restart(pid_t pid) /* Check if the task to restart is the calling task */ - rtcb = (FAR struct tcb_s*)g_readytorun.head; + rtcb = (FAR struct tcb_s *)g_readytorun.head; if ((pid == 0) || (pid == rtcb->pid)) { /* Not implemented */ + set_errno(ENOSYS); return ERROR; } @@ -123,11 +128,18 @@ int task_restart(pid_t pid) { /* Find for the TCB associated with matching pid */ - tcb = sched_gettcb(pid); + tcb = (FAR struct task_tcb_s *)sched_gettcb(pid); +#ifndef CONFIG_DISABLE_PTHREAD + if (!tcb || (tcb->cmn.flags & TCB_FLAG_TTYPE_MASK) == TCB_FLAG_TTYPE_PTHREAD) +#else if (!tcb) +#endif { - /* There is no TCB with this pid */ + /* There is no TCB with this pid or, if there is, it is not a + * task. + */ + set_errno(ESRCH); return ERROR; } @@ -136,24 +148,25 @@ int task_restart(pid_t pid) */ state = irqsave(); - dq_rem((FAR dq_entry_t*)tcb, (dq_queue_t*)g_tasklisttable[tcb->task_state].list); - tcb->task_state = TSTATE_TASK_INVALID; + dq_rem((FAR dq_entry_t*)tcb, + (dq_queue_t*)g_tasklisttable[tcb->cmn.task_state].list); + tcb->cmn.task_state = TSTATE_TASK_INVALID; irqrestore(state); /* Deallocate anything left in the TCB's queues */ - sig_cleanup(tcb); /* Deallocate Signal lists */ + sig_cleanup((FAR struct tcb_s *)tcb); /* Deallocate Signal lists */ /* Reset the current task priority */ - tcb->sched_priority = tcb->init_priority; + tcb->cmn.sched_priority = tcb->init_priority; /* Reset the base task priority and the number of pending reprioritizations */ #ifdef CONFIG_PRIORITY_INHERITANCE - tcb->base_priority = tcb->init_priority; + tcb->cmn.base_priority = tcb->init_priority; # if CONFIG_SEM_NNESTPRIO > 0 - tcb->npend_reprio = 0; + tcb->npend_reprio = 0; # endif #endif @@ -161,20 +174,20 @@ int task_restart(pid_t pid) * This will reset the entry point and the start-up parameters */ - up_initial_state(tcb); + up_initial_state((FAR struct tcb_s *)tcb); /* Add the task to the inactive task list */ dq_addfirst((FAR dq_entry_t*)tcb, (dq_queue_t*)&g_inactivetasks); - tcb->task_state = TSTATE_TASK_INACTIVE; + tcb->cmn.task_state = TSTATE_TASK_INACTIVE; /* Activate the task */ - status = task_activate(tcb); + status = task_activate((FAR struct tcb_s *)tcb); if (status != OK) { dq_rem((FAR dq_entry_t*)tcb, (dq_queue_t*)&g_inactivetasks); - sched_releasetcb(tcb); + sched_releasetcb((FAR struct tcb_s *)tcb); return ERROR; } } diff --git a/sched/task_setup.c b/sched/task_setup.c index 4c1b957f997..a7b634dd79a 100644 --- a/sched/task_setup.c +++ b/sched/task_setup.c @@ -49,6 +49,7 @@ #include #include "os_internal.h" +#include "pthread_internal.h" #include "group_internal.h" /**************************************************************************** @@ -183,7 +184,9 @@ static inline void task_saveparent(FAR struct tcb_s *tcb, uint8_t ttype) * the same task group. */ +#ifndef CONFIG_DISABLE_PTHREAD if ((tcb->flags & TCB_FLAG_TTYPE_MASK) != TCB_FLAG_TTYPE_PTHREAD) +#endif { /* This is a new task in a new task group, we have to copy the ID from * the parent's task group structure to child's task group. @@ -290,24 +293,20 @@ static inline void task_dupdspace(FAR struct tcb_s *tcb) #endif /**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: task_schedsetup + * Name: thread_schedsetup * * Description: - * This functions initializes a Task Control Block (TCB) in preparation - * for starting a new thread. + * This functions initializes the common portions of the Task Control Block + * (TCB) in preparation for starting a new thread. * - * task_schedsetup() is called from task_init(), task_start(), and - * pthread_create(); + * thread_schedsetup() is called from task_schedsetup() and + * pthread_schedsetup(). * * Input Parameters: * tcb - Address of the new task's TCB * priority - Priority of the new task - * entry - Entry point of a new task - * main - Application start point of the new task + * start - Thread startup rotuine + * entry - Thred user entry point * ttype - Type of the new thread: task, pthread, or kernel thread * * Return Value: @@ -318,8 +317,8 @@ static inline void task_dupdspace(FAR struct tcb_s *tcb) * ****************************************************************************/ -int task_schedsetup(FAR struct tcb_s *tcb, int priority, start_t start, main_t main, - uint8_t ttype) +static int thread_schedsetup(FAR struct tcb_s *tcb, int priority, + start_t start, FAR void *entry, uint8_t ttype) { int ret; @@ -330,13 +329,12 @@ int task_schedsetup(FAR struct tcb_s *tcb, int priority, start_t start, main_t m { /* Save task priority and entry point in the TCB */ - tcb->init_priority = (uint8_t)priority; tcb->sched_priority = (uint8_t)priority; #ifdef CONFIG_PRIORITY_INHERITANCE tcb->base_priority = (uint8_t)priority; #endif tcb->start = start; - tcb->entry.main = main; + tcb->entry.main = (main_t)entry; /* Save the thrad type. This setting will be needed in * up_initial_state() is called. @@ -388,6 +386,88 @@ int task_schedsetup(FAR struct tcb_s *tcb, int priority, start_t start, main_t m return ret; } +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: task_schedsetup + * + * Description: + * This functions initializes a Task Control Block (TCB) in preparation + * for starting a new task. + * + * task_schedsetup() is called from task_init() and task_start(). + * + * Input Parameters: + * tcb - Address of the new task's TCB + * priority - Priority of the new task + * start - Startup function (probably task_start()) + * main - Application start point of the new task + * ttype - Type of the new thread: task or kernel thread + * + * Return Value: + * OK on success; ERROR on failure. + * + * This function can only failure is it is unable to assign a new, unique + * task ID to the TCB (errno is not set). + * + ****************************************************************************/ + +int task_schedsetup(FAR struct task_tcb_s *tcb, int priority, start_t start, + main_t main, uint8_t ttype) +{ + int ret; + + /* Perform common thread setup */ + + ret = thread_schedsetup((FAR struct tcb_s *)tcb, priority, start, + (FAR void *)main, ttype); + if (ret == OK) + { + /* Save task restart priority */ + + tcb->init_priority = (uint8_t)priority; + } + + return ret; +} + +/**************************************************************************** + * Name: pthread_schedsetup + * + * Description: + * This functions initializes a Task Control Block (TCB) in preparation + * for starting a new pthread. + * + * pthread_schedsetup() is called from pthread_create(), + * + * Input Parameters: + * tcb - Address of the new task's TCB + * priority - Priority of the new task + * start - Startup function (probably pthread_start()) + * entry - Entry point of the new pthread + * ttype - Type of the new thread: task, pthread, or kernel thread + * + * Return Value: + * OK on success; ERROR on failure. + * + * This function can only failure is it is unable to assign a new, unique + * task ID to the TCB (errno is not set). + * + ****************************************************************************/ + +#ifndef CONFIG_DISABLE_PTHREAD +int pthread_schedsetup(FAR struct tcb_s *tcb, int priority, start_t start, + pthread_startroutine_t entry) +{ + /* Perform common thread setup */ + + return thread_schedsetup(tcb, priority, start, (FAR void *)entry, + TCB_FLAG_TTYPE_PTHREAD); +} +#endif + /**************************************************************************** * Name: task_argsetup * @@ -414,7 +494,8 @@ int task_schedsetup(FAR struct tcb_s *tcb, int priority, start_t start, main_t m * ****************************************************************************/ -int task_argsetup(FAR struct tcb_s *tcb, const char *name, FAR char * const argv[]) +int task_argsetup(FAR struct task_tcb_s *tcb, const char *name, + FAR char * const argv[]) { int i; @@ -423,16 +504,16 @@ int task_argsetup(FAR struct tcb_s *tcb, const char *name, FAR char * const argv if (!name) { - name = (char *)g_noname; + name = (FAR char *)g_noname; } /* Copy the name into the TCB */ - strncpy(tcb->name, name, CONFIG_TASK_NAME_SIZE); + strncpy(tcb->cmn.name, name, CONFIG_TASK_NAME_SIZE); /* Save the name as the first argument */ - tcb->argv[0] = tcb->name; + tcb->argv[0] = tcb->cmn.name; #else /* Save the name as the first argument */ diff --git a/sched/task_start.c b/sched/task_start.c index 5a66089c622..8e012b51540 100644 --- a/sched/task_start.c +++ b/sched/task_start.c @@ -1,7 +1,7 @@ /**************************************************************************** * sched/task_start.c * - * Copyright (C) 2007-2010 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2010, 2013 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -91,9 +91,11 @@ void task_start(void) { - FAR struct tcb_s *tcb = (FAR struct tcb_s*)g_readytorun.head; + FAR struct task_tcb_s *tcb = (FAR struct task_tcb_s*)g_readytorun.head; int argc; + DEBUGASSERT((tcb->cmn.flags & TCB_FLAG_TTYPE_MASK) != TCB_FLAG_TTYPE_PTHREAD); + /* Execute the start hook if one has been registered */ #ifdef CONFIG_SCHED_STARTHOOK @@ -119,5 +121,5 @@ void task_start(void) * the task returns. */ - exit(tcb->entry.main(argc, tcb->argv)); + exit(tcb->cmn.entry.main(argc, tcb->argv)); } diff --git a/sched/task_starthook.c b/sched/task_starthook.c index cf725a8549b..7fa0757aa1e 100644 --- a/sched/task_starthook.c +++ b/sched/task_starthook.c @@ -1,7 +1,7 @@ /**************************************************************************** - * sched/task_start.c + * sched/task_starthook.c * - * Copyright (C) 2007-2010 Gregory Nutt. All rights reserved. + * Copyright (C) 2013 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -90,9 +90,20 @@ * ****************************************************************************/ -void task_starthook(FAR struct tcb_s *tcb, starthook_t starthook, FAR void *arg) +void task_starthook(FAR struct task_tcb_s *tcb, starthook_t starthook, + FAR void *arg) { - DEBUGASSERT(tcb); + /* Only tasks can have starthooks. The starthook will be called when the + * task is started (or restarted). + */ + +#ifndef CONFIG_DISABLE_PTHREAD + DEBUGASSERT(tcb && + (tcb->cmn.flags & TCB_FLAG_TTYPE_MASK) != TCB_FLAG_TTYPE_PTHREAD); +#endif + + /* Set up the start hook */ + tcb->starthook = starthook; tcb->starthookarg = arg; } diff --git a/sched/task_vfork.c b/sched/task_vfork.c index f5d41bc8bc4..082854d602f 100644 --- a/sched/task_vfork.c +++ b/sched/task_vfork.c @@ -108,7 +108,7 @@ FAR struct tcb_s *task_vforksetup(start_t retaddr) { struct tcb_s *parent = (FAR struct tcb_s *)g_readytorun.head; - struct tcb_s *child; + struct task_tcb_s *child; int priority; int ret; @@ -116,7 +116,7 @@ FAR struct tcb_s *task_vforksetup(start_t retaddr) /* Allocate a TCB for the child task. */ - child = (FAR struct tcb_s*)kzalloc(sizeof(struct tcb_s)); + child = (FAR struct task_tcb_s *)kzalloc(sizeof(struct task_tcb_s)); if (!child) { set_errno(ENOMEM); @@ -152,10 +152,10 @@ FAR struct tcb_s *task_vforksetup(start_t retaddr) } svdbg("parent=%p, returning child=%p\n", parent, child); - return child; + return (FAR struct tcb_s *)child; errout_with_tcb: - sched_releasetcb(child); + sched_releasetcb((FAR struct tcb_s *)child); set_errno(-ret); return NULL; }