sched/tcb: use shared group for kthreads
Kthreads can share the group data so that to reduce overheads. This implements shared kthread group via: - use `tcb_s` instead of `task_tcb_s` for kthreads - use `g_kthread_group` when creating kthreads - use stackargs to start tasks and kthreads see pull/12320 for test logs. Signed-off-by: Yanfeng Liu <yfliu2008@qq.com>
This commit is contained in:
parent
1d169fe325
commit
8a8c1f943e
7 changed files with 90 additions and 61 deletions
|
@ -72,7 +72,7 @@ int env_dup(FAR struct task_group_s *group, FAR char * const *envcp)
|
|||
|
||||
/* Is there an environment ? */
|
||||
|
||||
if (envcp != NULL)
|
||||
if (envcp != NULL && group->tg_envp == NULL)
|
||||
{
|
||||
/* Pre-emption must be disabled throughout the following because the
|
||||
* environment may be shared.
|
||||
|
|
|
@ -40,9 +40,11 @@
|
|||
#include "tls/tls.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
static struct task_group_s g_kthread_group; /* Shared among kthreads */
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
@ -119,9 +121,23 @@ int group_initialize(FAR struct task_tcb_s *tcb, uint8_t ttype)
|
|||
|
||||
DEBUGASSERT(tcb && !tcb->cmn.group);
|
||||
|
||||
/* Allocate the group structure and assign it to the TCB */
|
||||
ttype &= TCB_FLAG_TTYPE_MASK;
|
||||
|
||||
group = &tcb->group;
|
||||
/* Initialize group pointer and assign to TCB */
|
||||
|
||||
if (ttype == TCB_FLAG_TTYPE_KERNEL)
|
||||
{
|
||||
group = &g_kthread_group;
|
||||
tcb->cmn.group = group;
|
||||
if (group->tg_info)
|
||||
{
|
||||
return OK;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
group = &tcb->group;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_MM_KERNEL_HEAP)
|
||||
/* If this group is being created for a privileged thread, then all
|
||||
|
@ -222,5 +238,8 @@ void group_postinitialize(FAR struct task_tcb_s *tcb)
|
|||
* task has exited.
|
||||
*/
|
||||
|
||||
group->tg_pid = tcb->cmn.pid;
|
||||
if (group != &g_kthread_group)
|
||||
{
|
||||
group->tg_pid = tcb->cmn.pid;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -79,8 +79,12 @@ int group_setuptaskfiles(FAR struct task_tcb_s *tcb,
|
|||
|
||||
/* Duplicate the parent task's file descriptors */
|
||||
|
||||
ret = files_duplist(&rtcb->group->tg_filelist,
|
||||
&group->tg_filelist, actions, cloexec);
|
||||
if (group != rtcb->group)
|
||||
{
|
||||
files_duplist(&rtcb->group->tg_filelist,
|
||||
&group->tg_filelist, actions, cloexec);
|
||||
}
|
||||
|
||||
if (ret >= 0 && actions != NULL)
|
||||
{
|
||||
ret = spawn_file_actions(&tcb->cmn, actions);
|
||||
|
|
|
@ -206,7 +206,7 @@ uint8_t g_nx_initstate; /* See enum nx_initstate_e */
|
|||
* bringing up the rest of the system.
|
||||
*/
|
||||
|
||||
static struct task_tcb_s g_idletcb[CONFIG_SMP_NCPUS];
|
||||
static struct tcb_s g_idletcb[CONFIG_SMP_NCPUS];
|
||||
|
||||
/* This is the name of the idle task */
|
||||
|
||||
|
@ -351,10 +351,11 @@ static void tasklist_initialize(void)
|
|||
|
||||
static void idle_task_initialize(void)
|
||||
{
|
||||
FAR struct task_tcb_s *tcb;
|
||||
FAR struct tcb_s *tcb;
|
||||
FAR dq_queue_t *tasklist;
|
||||
int i;
|
||||
|
||||
memset(g_idletcb, 0, sizeof(g_idletcb));
|
||||
for (i = 0; i < CONFIG_SMP_NCPUS; i++)
|
||||
{
|
||||
tcb = &g_idletcb[i];
|
||||
|
@ -366,9 +367,8 @@ static void idle_task_initialize(void)
|
|||
* that has pid == 0 and sched_priority == 0.
|
||||
*/
|
||||
|
||||
memset(tcb, 0, sizeof(struct task_tcb_s));
|
||||
tcb->cmn.pid = i;
|
||||
tcb->cmn.task_state = TSTATE_TASK_RUNNING;
|
||||
tcb->pid = i;
|
||||
tcb->task_state = TSTATE_TASK_RUNNING;
|
||||
|
||||
/* Set the entry point. This is only for debug purposes. NOTE: that
|
||||
* the start_t entry point is not saved. That is acceptable, however,
|
||||
|
@ -379,14 +379,14 @@ static void idle_task_initialize(void)
|
|||
#ifdef CONFIG_SMP
|
||||
if (i > 0)
|
||||
{
|
||||
tcb->cmn.start = nx_idle_trampoline;
|
||||
tcb->cmn.entry.main = (main_t)nx_idle_trampoline;
|
||||
tcb->start = nx_idle_trampoline;
|
||||
tcb->entry.main = (main_t)nx_idle_trampoline;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
tcb->cmn.start = nx_start;
|
||||
tcb->cmn.entry.main = (main_t)nx_start;
|
||||
tcb->start = nx_start;
|
||||
tcb->entry.main = (main_t)nx_start;
|
||||
}
|
||||
|
||||
/* Set the task flags to indicate that this is a kernel thread and, if
|
||||
|
@ -394,8 +394,8 @@ static void idle_task_initialize(void)
|
|||
*/
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
tcb->cmn.flags = (TCB_FLAG_TTYPE_KERNEL | TCB_FLAG_CPU_LOCKED);
|
||||
tcb->cmn.cpu = i;
|
||||
tcb->flags = (TCB_FLAG_TTYPE_KERNEL | TCB_FLAG_CPU_LOCKED);
|
||||
tcb->cpu = i;
|
||||
|
||||
/* Set the affinity mask to allow the thread to run on all CPUs. No,
|
||||
* this IDLE thread can only run on its assigned CPU. That is
|
||||
|
@ -405,19 +405,19 @@ static void idle_task_initialize(void)
|
|||
* the IDLE task.
|
||||
*/
|
||||
|
||||
tcb->cmn.affinity =
|
||||
tcb->affinity =
|
||||
(cpu_set_t)(CONFIG_SMP_DEFAULT_CPUSET & SCHED_ALL_CPUS);
|
||||
#else
|
||||
tcb->cmn.flags = TCB_FLAG_TTYPE_KERNEL;
|
||||
tcb->flags = TCB_FLAG_TTYPE_KERNEL;
|
||||
#endif
|
||||
|
||||
#if CONFIG_TASK_NAME_SIZE > 0
|
||||
/* Set the IDLE task name */
|
||||
|
||||
# ifdef CONFIG_SMP
|
||||
snprintf(tcb->cmn.name, CONFIG_TASK_NAME_SIZE, "CPU%d IDLE", i);
|
||||
snprintf(tcb->name, CONFIG_TASK_NAME_SIZE, "CPU%d IDLE", i);
|
||||
# else
|
||||
strlcpy(tcb->cmn.name, g_idlename, CONFIG_TASK_NAME_SIZE);
|
||||
strlcpy(tcb->name, g_idlename, CONFIG_TASK_NAME_SIZE);
|
||||
# endif
|
||||
|
||||
/* Configure the task name in the argument list. The IDLE task does
|
||||
|
@ -428,7 +428,7 @@ static void idle_task_initialize(void)
|
|||
* stack and there is no support that yet.
|
||||
*/
|
||||
|
||||
g_idleargv[i][0] = tcb->cmn.name;
|
||||
g_idleargv[i][0] = tcb->name;
|
||||
#else
|
||||
g_idleargv[i][0] = (FAR char *)g_idlename;
|
||||
#endif /* CONFIG_TASK_NAME_SIZE */
|
||||
|
@ -438,15 +438,15 @@ static void idle_task_initialize(void)
|
|||
*/
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
tasklist = TLIST_HEAD(&tcb->cmn, i);
|
||||
tasklist = TLIST_HEAD(tcb, i);
|
||||
#else
|
||||
tasklist = TLIST_HEAD(&tcb->cmn);
|
||||
tasklist = TLIST_HEAD(tcb);
|
||||
#endif
|
||||
dq_addfirst((FAR dq_entry_t *)tcb, tasklist);
|
||||
|
||||
/* Mark the idle task as the running task */
|
||||
|
||||
g_running_tasks[i] = &tcb->cmn;
|
||||
g_running_tasks[i] = tcb;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -460,7 +460,7 @@ static void idle_task_initialize(void)
|
|||
|
||||
static void idle_group_initialize(void)
|
||||
{
|
||||
FAR struct task_tcb_s *tcb;
|
||||
FAR struct tcb_s *tcb;
|
||||
int hashndx;
|
||||
int i;
|
||||
|
||||
|
@ -471,16 +471,17 @@ static void idle_group_initialize(void)
|
|||
tcb = &g_idletcb[i];
|
||||
|
||||
hashndx = PIDHASH(i);
|
||||
g_pidhash[hashndx] = &tcb->cmn;
|
||||
g_pidhash[hashndx] = tcb;
|
||||
|
||||
/* Allocate the IDLE group */
|
||||
|
||||
DEBUGVERIFY(group_initialize(tcb, tcb->cmn.flags));
|
||||
tcb->cmn.group->tg_info->ta_argv = &g_idleargv[i][0];
|
||||
DEBUGVERIFY(
|
||||
group_initialize((FAR struct task_tcb_s *)tcb, tcb->flags));
|
||||
tcb->group->tg_info->ta_argv = &g_idleargv[i][0];
|
||||
|
||||
/* Initialize the task join */
|
||||
|
||||
nxtask_joininit(&tcb->cmn);
|
||||
nxtask_joininit(tcb);
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
/* Create a stack for all CPU IDLE threads (except CPU0 which already
|
||||
|
@ -489,26 +490,24 @@ static void idle_group_initialize(void)
|
|||
|
||||
if (i > 0)
|
||||
{
|
||||
DEBUGVERIFY(up_cpu_idlestack(i, &tcb->cmn,
|
||||
CONFIG_IDLETHREAD_STACKSIZE));
|
||||
DEBUGVERIFY(up_cpu_idlestack(i, tcb, CONFIG_IDLETHREAD_STACKSIZE));
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Initialize the processor-specific portion of the TCB */
|
||||
|
||||
up_initial_state(&tcb->cmn);
|
||||
up_initial_state(tcb);
|
||||
|
||||
/* Initialize the thread local storage */
|
||||
|
||||
tls_init_info(&tcb->cmn);
|
||||
tls_init_info(tcb);
|
||||
|
||||
/* Complete initialization of the IDLE group. Suppress retention
|
||||
* of child status in the IDLE group.
|
||||
*/
|
||||
|
||||
group_postinitialize(tcb);
|
||||
tcb->cmn.group->tg_flags = GROUP_FLAG_NOCLDWAIT |
|
||||
GROUP_FLAG_PRIVILEGED;
|
||||
group_postinitialize((FAR struct task_tcb_s *)tcb);
|
||||
tcb->group->tg_flags = GROUP_FLAG_NOCLDWAIT | GROUP_FLAG_PRIVILEGED;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -727,7 +726,7 @@ void nx_start(void)
|
|||
|
||||
/* Announce that the CPU0 IDLE task has started */
|
||||
|
||||
sched_note_start(&g_idletcb[0].cmn);
|
||||
sched_note_start(&g_idletcb[0]);
|
||||
|
||||
/* Initialize stdio for the IDLE task of each CPU */
|
||||
|
||||
|
@ -737,7 +736,8 @@ void nx_start(void)
|
|||
{
|
||||
/* Clone stdout, stderr, stdin from the CPU0 IDLE task. */
|
||||
|
||||
DEBUGVERIFY(group_setuptaskfiles(&g_idletcb[i], NULL, true));
|
||||
DEBUGVERIFY(group_setuptaskfiles(
|
||||
(FAR struct task_tcb_s *)&g_idletcb[i], NULL, true));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -76,13 +76,14 @@ int nxthread_create(FAR const char *name, uint8_t ttype, int priority,
|
|||
FAR void *stack_addr, int stack_size, main_t entry,
|
||||
FAR char * const argv[], FAR char * const envp[])
|
||||
{
|
||||
FAR struct task_tcb_s *tcb;
|
||||
FAR struct tcb_s *tcb;
|
||||
pid_t pid;
|
||||
int ret;
|
||||
|
||||
/* Allocate a TCB for the new task. */
|
||||
|
||||
tcb = kmm_zalloc(sizeof(struct task_tcb_s));
|
||||
tcb = kmm_zalloc(ttype == TCB_FLAG_TTYPE_KERNEL ?
|
||||
sizeof(struct tcb_s) : sizeof(struct task_tcb_s));
|
||||
if (!tcb)
|
||||
{
|
||||
serr("ERROR: Failed to allocate TCB\n");
|
||||
|
@ -91,12 +92,12 @@ int nxthread_create(FAR const char *name, uint8_t ttype, int priority,
|
|||
|
||||
/* Setup the task type */
|
||||
|
||||
tcb->cmn.flags = ttype | TCB_FLAG_FREE_TCB;
|
||||
tcb->flags = ttype | TCB_FLAG_FREE_TCB;
|
||||
|
||||
/* Initialize the task */
|
||||
|
||||
ret = nxtask_init(tcb, name, priority, stack_addr, stack_size,
|
||||
entry, argv, envp, NULL);
|
||||
ret = nxtask_init((FAR struct task_tcb_s *)tcb, name, priority,
|
||||
stack_addr, stack_size, entry, argv, envp, NULL);
|
||||
if (ret < OK)
|
||||
{
|
||||
kmm_free(tcb);
|
||||
|
@ -105,11 +106,11 @@ int nxthread_create(FAR const char *name, uint8_t ttype, int priority,
|
|||
|
||||
/* Get the assigned pid before we start the task */
|
||||
|
||||
pid = tcb->cmn.pid;
|
||||
pid = tcb->pid;
|
||||
|
||||
/* Activate the task */
|
||||
|
||||
nxtask_activate(&tcb->cmn);
|
||||
nxtask_activate(tcb);
|
||||
|
||||
return pid;
|
||||
}
|
||||
|
|
|
@ -514,6 +514,7 @@ static void nxtask_setup_name(FAR struct task_tcb_s *tcb,
|
|||
*
|
||||
* Input Parameters:
|
||||
* tcb - Address of the new task's TCB
|
||||
* name - Name of the new task
|
||||
* argv - A pointer to an array of input parameters. The array should be
|
||||
* terminated with a NULL argv[] value. If no parameters are
|
||||
* required, argv may be NULL.
|
||||
|
@ -527,6 +528,7 @@ static int nxtask_setup_stackargs(FAR struct task_tcb_s *tcb,
|
|||
FAR const char *name,
|
||||
FAR char * const argv[])
|
||||
{
|
||||
uint8_t ttype = tcb->cmn.flags & TCB_FLAG_TTYPE_MASK;
|
||||
FAR char **stackargv;
|
||||
FAR char *str;
|
||||
size_t strtablen;
|
||||
|
@ -630,8 +632,11 @@ static int nxtask_setup_stackargs(FAR struct task_tcb_s *tcb,
|
|||
|
||||
stackargv[argc + 1] = NULL;
|
||||
|
||||
tcb->cmn.group->tg_info->ta_argc = argc;
|
||||
tcb->cmn.group->tg_info->ta_argv = stackargv;
|
||||
if (ttype != TCB_FLAG_TTYPE_KERNEL)
|
||||
{
|
||||
tcb->cmn.group->tg_info->ta_argc = argc;
|
||||
tcb->cmn.group->tg_info->ta_argv = stackargv;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
|
|
@ -66,17 +66,18 @@
|
|||
void nxtask_start(void)
|
||||
{
|
||||
FAR struct tcb_s *tcb = this_task();
|
||||
uint8_t ttype = tcb->flags & TCB_FLAG_TTYPE_MASK;
|
||||
#ifdef CONFIG_SCHED_STARTHOOK
|
||||
FAR struct task_tcb_s *ttcb = (FAR struct task_tcb_s *)tcb;
|
||||
#endif
|
||||
int exitcode = EXIT_FAILURE;
|
||||
FAR char **argv;
|
||||
int argc;
|
||||
|
||||
DEBUGASSERT((tcb->flags & TCB_FLAG_TTYPE_MASK) != \
|
||||
TCB_FLAG_TTYPE_PTHREAD);
|
||||
DEBUGASSERT(ttype != TCB_FLAG_TTYPE_PTHREAD);
|
||||
|
||||
#ifdef CONFIG_SIG_DEFAULT
|
||||
if ((tcb->flags & TCB_FLAG_TTYPE_MASK) != TCB_FLAG_TTYPE_KERNEL)
|
||||
if (ttype != TCB_FLAG_TTYPE_KERNEL)
|
||||
{
|
||||
/* Set up default signal actions for NON-kernel thread */
|
||||
|
||||
|
@ -87,33 +88,32 @@ void nxtask_start(void)
|
|||
/* Execute the start hook if one has been registered */
|
||||
|
||||
#ifdef CONFIG_SCHED_STARTHOOK
|
||||
if (ttcb->starthook != NULL)
|
||||
if (ttype != TCB_FLAG_TTYPE_KERNEL && ttcb->starthook != NULL)
|
||||
{
|
||||
ttcb->starthook(ttcb->starthookarg);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Add program name */
|
||||
/* Take args from stack, as group is shared for kthreads */
|
||||
|
||||
argc = tcb->group->tg_info->ta_argc + 1;
|
||||
argv = nxsched_get_stackargs(tcb);
|
||||
for (argc = 0; argv && argv[argc]; argc++);
|
||||
|
||||
/* Call the 'main' entry point passing argc and argv. In the kernel build
|
||||
* this has to be handled differently if we are starting a user-space task;
|
||||
* we have to switch to user-mode before calling the task.
|
||||
*/
|
||||
|
||||
if ((tcb->flags & TCB_FLAG_TTYPE_MASK) == TCB_FLAG_TTYPE_KERNEL)
|
||||
if (ttype == TCB_FLAG_TTYPE_KERNEL)
|
||||
{
|
||||
exitcode = tcb->entry.main(argc, tcb->group->tg_info->ta_argv);
|
||||
exitcode = tcb->entry.main(argc, argv);
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef CONFIG_BUILD_FLAT
|
||||
nxtask_startup(tcb->entry.main, argc,
|
||||
tcb->group->tg_info->ta_argv);
|
||||
nxtask_startup(tcb->entry.main, argc, argv);
|
||||
#else
|
||||
up_task_start(tcb->entry.main, argc,
|
||||
tcb->group->tg_info->ta_argv);
|
||||
up_task_start(tcb->entry.main, argc, argv);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue