diff --git a/arch b/arch index 958e4d09fc..0ddf09674e 160000 --- a/arch +++ b/arch @@ -1 +1 @@ -Subproject commit 958e4d09fc413d88893881eee612d901b779e057 +Subproject commit 0ddf09674eb2115ecfedaa82e21a2c43fc09d127 diff --git a/configs b/configs index 05856eb712..81a10b64ed 160000 --- a/configs +++ b/configs @@ -1 +1 @@ -Subproject commit 05856eb712badecadbdbd7803c868ebd0b2de451 +Subproject commit 81a10b64ed544684bb975e218e09ab5bc8aaf445 diff --git a/include/nuttx/arch.h b/include/nuttx/arch.h index a28e7767ba..bbca284eab 100644 --- a/include/nuttx/arch.h +++ b/include/nuttx/arch.h @@ -1,7 +1,7 @@ /**************************************************************************** * include/nuttx/arch.h * - * Copyright (C) 2007-2015 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2016 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -1636,6 +1636,52 @@ int up_timer_cancel(FAR struct timespec *ts); int up_timer_start(FAR const struct timespec *ts); #endif +/**************************************************************************** + * Multiple CPU support + ****************************************************************************/ + +/**************************************************************************** + * Name: up_testset + * + * Description: + * Perform and atomic test and set operation on the provided spinlock. + * + * Input Parameters: + * lock - The address of spinlock object. + * + * Returned Value: + * The spinlock is always locked upon return. The value of previous value + * of the spinlock variable is returned, either SP_LOCKED if the spinlock + * as previously locked (meaning that the test-and-set operation failed to + * obtain the lock) or SP_UNLOCKED if the spinlock was previously unlocked + * (meaning that we successfully obtained the lock) + * + ****************************************************************************/ + +/* See prototype in include/nuttx/spinlock.h */ + +/**************************************************************************** + * Name: up_cpundx + * + * Description: + * Return an index in the range of 0 through (CONFIG_SMP_NCPUS-1) that + * corresponds to the currently executing CPU. + * + * Input Parameters: + * None + * + * Returned Value: + * An integer index in the range of 0 through (CONFIG_SMP_NCPUS-1) that + * corresponds to the currently executing CPU. + * + ****************************************************************************/ + +#ifdef CONFIG_SMP +int up_cpundx(void); +#else +# define up_cpundx() (0) +#endif + /**************************************************************************** * Name: up_romgetc * diff --git a/sched/init/os_start.c b/sched/init/os_start.c index c97b53b034..f64a33bae9 100644 --- a/sched/init/os_start.c +++ b/sched/init/os_start.c @@ -81,17 +81,53 @@ * and by a series of task lists. All of these tasks lists are declared * below. Although it is not always necessary, most of these lists are * prioritized so that common list handling logic can be used (only the - * g_readytorun, the g_pendingtasks, and the g_waitingforsemaphore lists need - * to be prioritized). + * g_readytorun, the g_pendingtasks, and the g_waitingforsemaphore lists + * need to be prioritized). */ -/* This is the list of all tasks that are ready to run. The head of this - * list is the currently active task; the tail of this list is always the - * IDLE task. +/* This is the list of all tasks that are ready to run. This is a + * prioritized list with head of the list holding the highest priority + * (unassigned) task. In the non-SMP cae, the head of this list is the + * currently active task and the tail of this list, the lowest priority + * task, is always the IDLE task. */ volatile dq_queue_t g_readytorun; +#ifdef CONFIG_SMP +/* In order to support SMP, the function of the g_readytorun list changes, + * The g_readytorun is still used but in the SMP cae it will contain only: + * + * - Only tasks/threads that are eligible to run, but not currently running, + * and + * - Tasks/threads that have not been assigned to a CPU. + * + * Otherwise, the TCB will be reatined in an assigned task list, + * g_assignedtasks. As its name suggests, on 'g_assignedtasks queue for CPU + * 'n' would contain only tasks/threads that are assigned to CPU 'n'. Tasks/ + * threads would be assigned a particular CPU by one of two mechanisms: + * + * - (Semi-)permanently through an RTOS interfaces such as + * pthread_attr_setaffinity(), or + * - Temporarily through scheduling logic when a previously unassigned task + * is made to run. + * + * Tasks/threads that are assigned to a CPU via an interface like + * pthread_attr_setaffinity() would never go into the g_readytorun list, but + * would only go into the g_assignedtasks[n] list for the CPU 'n' to which + * the thread has been assigned. Hence, the g_readytorun list would hold + * only unassigned tasks/threads. + * + * Like the g_readytorun list in in non-SMP case, each g_assignedtask[] list + * is prioritized: The head of the list is the currently active task on this + * CPU. Tasks after the active task are ready-to-run and assigned to this + * CPU. The tail of this assigned task list, the lowest priority task, is + * always the CPU's IDLE task. + */ + +volatile dq_queue_t g_assignedtasks[CONFIG_SMP_NCPUS]; +#endif + /* This is the list of all tasks that are ready-to-run, but cannot be placed * in the g_readytorun list because: (1) They are higher priority than the * currently active task at the head of the g_readytorun list, and (2) the diff --git a/sched/sched/sched.h b/sched/sched/sched.h index 772711cc42..e97e66f265 100644 --- a/sched/sched/sched.h +++ b/sched/sched/sched.h @@ -1,7 +1,7 @@ /**************************************************************************** * sched/sched/sched.h * - * Copyright (C) 2007-2014 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2014, 2016 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -47,6 +47,7 @@ #include #include +#include #include /**************************************************************************** @@ -68,9 +69,14 @@ * These macros are intended to support a future SMP implementation. */ -#define current_task(cpu) ((FAR struct tcb_s *)g_readytorun.head) -#define this_cpu() (0) -#define this_task() (current_task(this_cpu)) +#ifdef CONFIG_SMP +# define current_task(cpu) ((FAR struct tcb_s *)g_assignedtasks[cpu].head) +# define this_cpu() up_cpundx() +#else +# define current_task(cpu) ((FAR struct tcb_s *)g_readytorun.head) +# define this_cpu() (0) +#endif +#define this_task() (current_task(this_cpu())) /**************************************************************************** * Public Type Definitions @@ -117,17 +123,53 @@ struct tasklist_s * and by a series of task lists. All of these tasks lists are declared * below. Although it is not always necessary, most of these lists are * prioritized so that common list handling logic can be used (only the - * g_readytorun, the g_pendingtasks, and the g_waitingforsemaphore lists need - * to be prioritized). + * g_readytorun, the g_pendingtasks, and the g_waitingforsemaphore lists + * need to be prioritized). */ -/* This is the list of all tasks that are ready to run. The head of this - * list is the currently active task; the tail of this list is always the - * IDLE task. +/* This is the list of all tasks that are ready to run. This is a + * prioritized list with head of the list holding the highest priority + * (unassigned) task. In the non-SMP cae, the head of this list is the + * currently active task and the tail of this list, the lowest priority + * task, is always the IDLE task. */ extern volatile dq_queue_t g_readytorun; +#ifdef CONFIG_SMP +/* In order to support SMP, the function of the g_readytorun list changes, + * The g_readytorun is still used but in the SMP cae it will contain only: + * + * - Only tasks/threads that are eligible to run, but not currently running, + * and + * - Tasks/threads that have not been assigned to a CPU. + * + * Otherwise, the TCB will be reatined in an assigned task list, + * g_assignedtasks. As its name suggests, on 'g_assignedtasks queue for CPU + * 'n' would contain only tasks/threads that are assigned to CPU 'n'. Tasks/ + * threads would be assigned a particular CPU by one of two mechanisms: + * + * - (Semi-)permanently through an RTOS interfaces such as + * pthread_attr_setaffinity(), or + * - Temporarily through scheduling logic when a previously unassigned task + * is made to run. + * + * Tasks/threads that are assigned to a CPU via an interface like + * pthread_attr_setaffinity() would never go into the g_readytorun list, but + * would only go into the g_assignedtasks[n] list for the CPU 'n' to which + * the thread has been assigned. Hence, the g_readytorun list would hold + * only unassigned tasks/threads. + * + * Like the g_readytorun list in in non-SMP case, each g_assignedtask[] list + * is prioritized: The head of the list is the currently active task on this + * CPU. Tasks after the active task are ready-to-run and assigned to this + * CPU. The tail of this assigned task list, the lowest priority task, is + * always the CPU's IDLE task. + */ + +extern volatile dq_queue_t g_assignedtasks[CONFIG_SMP_NCPUS]; +#endif + /* This is the list of all tasks that are ready-to-run, but cannot be placed * in the g_readytorun list because: (1) They are higher priority than the * currently active task at the head of the g_readytorun list, and (2) the