From b2f817e0ba4f2db5e107d77e945aa0eeac2e88db Mon Sep 17 00:00:00 2001 From: Yunlk <3283559503@qq.com> Date: Wed, 21 Oct 2026 00:05:16 +0800 Subject: [PATCH 1/2] [kernel][scheduler] fix: keep FIFO order for same-priority threads rt_sched_insert_thread() inserted every thread without RT_THREAD_STAT_YIELD at the head of the ready list. A thread resumed from an IPC pending list never carries that flag, because the scheduler clears it when switching away from the thread (see scheduler_up.c). Waking several same-priority threads in pending order therefore reversed their execution order, and freshly started threads had the same problem. Only a thread that was preempted while it was still running keeps the head insertion now, which is the case the original code comment described. Every other case (time slice consumed, resumed from an IPC pending list, freshly started) is appended to the tail, so same-priority threads run in the order in which they became ready. The single core path and both multi-core insertion paths are updated consistently. Add utest core.scheduler_ready_order covering the semaphore wakeup path and the startup path. On SMP the worker threads are bound to the CPU running the test case so that the insertion order stays observable. Refs #8459 --- src/scheduler_mp.c | 41 +++--- src/scheduler_up.c | 25 ++-- src/utest/SConscript | 1 + src/utest/sched_ready_order_tc.c | 210 +++++++++++++++++++++++++++++++ 4 files changed, 255 insertions(+), 22 deletions(-) create mode 100644 src/utest/sched_ready_order_tc.c diff --git a/src/scheduler_mp.c b/src/scheduler_mp.c index 4bcbafad6dd6..b91590ea20a8 100644 --- a/src/scheduler_mp.c +++ b/src/scheduler_mp.c @@ -282,6 +282,8 @@ static void _sched_insert_thread_locked(struct rt_thread *thread) int cpu_id; int bind_cpu; rt_uint32_t cpu_mask; + rt_uint8_t stat_before; + rt_bool_t insert_at_head; if ((RT_SCHED_CTX(thread).stat & RT_THREAD_STAT_MASK) == RT_THREAD_READY) { @@ -299,7 +301,20 @@ static void _sched_insert_thread_locked(struct rt_thread *thread) } /* READY thread, insert to ready queue */ - RT_SCHED_CTX(thread).stat = RT_THREAD_READY | (RT_SCHED_CTX(thread).stat & ~RT_THREAD_STAT_MASK); + stat_before = RT_SCHED_CTX(thread).stat; + RT_SCHED_CTX(thread).stat = RT_THREAD_READY | (stat_before & ~RT_THREAD_STAT_MASK); + + /* A thread that was preempted while it still had time slices left keeps the + * head of the ready list, so that it is scheduled first next time. + * + * Every other case -- time slice consumed (@c RT_THREAD_STAT_YIELD set), + * resumed from an IPC pending list, or freshly started -- is appended to the + * tail. Inserting those at the head would reverse the order in which + * same-priority threads became ready, which breaks the FIFO fairness of the + * ready list (see RT-Thread issue #8459). + */ + insert_at_head = (((stat_before & RT_THREAD_STAT_MASK) == RT_THREAD_RUNNING) && + ((stat_before & RT_THREAD_STAT_YIELD_MASK) == 0)); cpu_id = rt_hw_cpu_id(); bind_cpu = RT_SCHED_CTX(thread).bind_cpu; @@ -312,17 +327,15 @@ static void _sched_insert_thread_locked(struct rt_thread *thread) #endif /* RT_THREAD_PRIORITY_MAX > 32 */ rt_thread_ready_priority_group |= RT_SCHED_PRIV(thread).number_mask; - /* there is no time slices left(YIELD), inserting thread before ready list*/ - if((RT_SCHED_CTX(thread).stat & RT_THREAD_STAT_YIELD_MASK) != 0) + if (insert_at_head) { - rt_list_insert_before(&(rt_thread_priority_table[RT_SCHED_PRIV(thread).current_priority]), - &RT_THREAD_LIST_NODE(thread)); + rt_list_insert_after(&(rt_thread_priority_table[RT_SCHED_PRIV(thread).current_priority]), + &RT_THREAD_LIST_NODE(thread)); } - /* there are some time slices left, inserting thread after ready list to schedule it firstly at next time*/ else { - rt_list_insert_after(&(rt_thread_priority_table[RT_SCHED_PRIV(thread).current_priority]), - &RT_THREAD_LIST_NODE(thread)); + rt_list_insert_before(&(rt_thread_priority_table[RT_SCHED_PRIV(thread).current_priority]), + &RT_THREAD_LIST_NODE(thread)); } cpu_mask = RT_CPU_MASK ^ (1 << cpu_id); @@ -337,17 +350,15 @@ static void _sched_insert_thread_locked(struct rt_thread *thread) #endif /* RT_THREAD_PRIORITY_MAX > 32 */ pcpu->priority_group |= RT_SCHED_PRIV(thread).number_mask; - /* there is no time slices left(YIELD), inserting thread before ready list*/ - if((RT_SCHED_CTX(thread).stat & RT_THREAD_STAT_YIELD_MASK) != 0) + if (insert_at_head) { - rt_list_insert_before(&(rt_cpu_index(bind_cpu)->priority_table[RT_SCHED_PRIV(thread).current_priority]), - &RT_THREAD_LIST_NODE(thread)); + rt_list_insert_after(&(rt_cpu_index(bind_cpu)->priority_table[RT_SCHED_PRIV(thread).current_priority]), + &RT_THREAD_LIST_NODE(thread)); } - /* there are some time slices left, inserting thread after ready list to schedule it firstly at next time*/ else { - rt_list_insert_after(&(rt_cpu_index(bind_cpu)->priority_table[RT_SCHED_PRIV(thread).current_priority]), - &RT_THREAD_LIST_NODE(thread)); + rt_list_insert_before(&(rt_cpu_index(bind_cpu)->priority_table[RT_SCHED_PRIV(thread).current_priority]), + &RT_THREAD_LIST_NODE(thread)); } if (cpu_id != bind_cpu) diff --git a/src/scheduler_up.c b/src/scheduler_up.c index 8560166fd17b..f42f05427b50 100644 --- a/src/scheduler_up.c +++ b/src/scheduler_up.c @@ -491,6 +491,7 @@ void rt_sched_thread_init_priv(struct rt_thread *thread, rt_uint32_t tick, rt_ui void rt_sched_insert_thread(struct rt_thread *thread) { rt_base_t level; + rt_uint8_t stat_before; RT_ASSERT(thread != RT_NULL); @@ -505,17 +506,27 @@ void rt_sched_insert_thread(struct rt_thread *thread) } /* READY thread, insert to ready queue */ - RT_SCHED_CTX(thread).stat = RT_THREAD_READY | (RT_SCHED_CTX(thread).stat & ~RT_THREAD_STAT_MASK); - /* there is no time slices left(YIELD), inserting thread before ready list*/ - if((RT_SCHED_CTX(thread).stat & RT_THREAD_STAT_YIELD_MASK) != 0) + stat_before = RT_SCHED_CTX(thread).stat; + RT_SCHED_CTX(thread).stat = RT_THREAD_READY | (stat_before & ~RT_THREAD_STAT_MASK); + + /* A thread that was preempted while it still had time slices left keeps the + * head of the ready list, so that it is scheduled first next time. + * + * Every other case -- time slice consumed (@c RT_THREAD_STAT_YIELD set), + * resumed from an IPC pending list, or freshly started -- is appended to the + * tail. Inserting those at the head would reverse the order in which + * same-priority threads became ready, which breaks the FIFO fairness of the + * ready list (see RT-Thread issue #8459). + */ + if (((stat_before & RT_THREAD_STAT_MASK) == RT_THREAD_RUNNING) && + ((stat_before & RT_THREAD_STAT_YIELD_MASK) == 0)) { - rt_list_insert_before(&(rt_thread_priority_table[RT_SCHED_PRIV(thread).current_priority]), - &RT_THREAD_LIST_NODE(thread)); + rt_list_insert_after(&(rt_thread_priority_table[RT_SCHED_PRIV(thread).current_priority]), + &RT_THREAD_LIST_NODE(thread)); } - /* there are some time slices left, inserting thread after ready list to schedule it firstly at next time*/ else { - rt_list_insert_after(&(rt_thread_priority_table[RT_SCHED_PRIV(thread).current_priority]), + rt_list_insert_before(&(rt_thread_priority_table[RT_SCHED_PRIV(thread).current_priority]), &RT_THREAD_LIST_NODE(thread)); } diff --git a/src/utest/SConscript b/src/utest/SConscript index 52aca3dcf698..2f4451dd293e 100644 --- a/src/utest/SConscript +++ b/src/utest/SConscript @@ -65,6 +65,7 @@ if GetDepend(['RT_UTEST_SCHEDULER']): src += ['sched_timed_mtx_tc.c'] src += ['sched_mtx_tc.c'] src += ['sched_sem_tc.c', 'sched_thread_tc.c'] + src += ['sched_ready_order_tc.c'] group = DefineGroup('utestcases', src, depend = ['RT_USING_UTESTCASES'], CPPPATH = CPPPATH) diff --git a/src/utest/sched_ready_order_tc.c b/src/utest/sched_ready_order_tc.c new file mode 100644 index 000000000000..71a29b783324 --- /dev/null +++ b/src/utest/sched_ready_order_tc.c @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2006-2026, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2026-10-20 Yunlk the first version + */ + +/** + * Test Case Name: Ready List Insertion Order Test (core.scheduler_ready_order) + * + * Test Objectives: + * - Verify that same-priority threads are inserted into the ready list in a + * first-in-first-out manner, so that the execution order matches the order in + * which they became ready. + * - Cover the two paths that currently bypass the FIFO order: + * - Threads resumed from an IPC (semaphore) pending list. + * - Threads started back-to-back via rt_thread_startup(). + * - List specific functions or APIs to be tested: + * - rt_sem_create / rt_sem_take / rt_sem_release + * - rt_thread_create / rt_thread_startup + * - rt_schedule_insert_thread (indirectly, through the two paths above) + * + * Test Scenarios: + * - **Semaphore Wakeup Order:** + * 1. Create a semaphore with RT_IPC_FLAG_PRIO and two same-priority worker threads. + * 2. Start the worker A first and let it block on the semaphore, then start B and + * let it block as well. The pending list is therefore deterministically A -> B. + * 3. Release the semaphore twice, which wakes A first and then B. + * 4. Let the workers run and record their execution order. + * + * - **Startup Order:** + * 1. Create two same-priority worker threads C and D. + * 2. Startup C and then D without yielding in between. + * 3. Let them run and record their execution order. + * + * Verification Metrics: + * - **Pass:** The semaphore case records "AB", i.e. the thread woken first runs first. + * - **Pass:** The startup case records "CD", i.e. the thread started first runs first. + * - On SMP the workers are bound to the CPU running this test case, so that the + * insertion order is observable without cross-core scheduling noise. + * + * Dependencies: + * - Hardware requirements + * - None. A single core is enough; more cores are also supported by binding. + * (This is met by the qemu-vexpress-a9 / qemu-virt64-riscv BSP). + * - Software configuration + * - `RT_USING_UTEST` must be enabled (`RT-Thread Utestcases`). + * - `Scheduler Test` must be enabled (`RT-Thread Utestcases` -> `Kernel Core` -> 'Scheduler Test'). + * - `RT_USING_SEMAPHORE` must be enabled. + * - Environmental assumptions + * - `RT_THREAD_PRIORITY_MAX` must leave at least one priority level between the + * utest thread and the idle thread. + * - Run the test case from the msh prompt: + * `utest_run core.scheduler_ready_order` + * + * Expected Results: + * - The console prints the observed execution order for both scenarios. + * - Final Output: `[ PASSED ] [ result ] testcase (core.scheduler_ready_order)` + */ + +#define __RT_IPC_SOURCE__ + +#include +#include "rthw.h" +#include "utest.h" + +/* worker threads must be lower priority than the utest thread, but above idle */ +#define TEST_THREAD_PRIORITY (UTEST_THR_PRIORITY + 2) + +#if TEST_THREAD_PRIORITY >= RT_THREAD_PRIORITY_MAX - 1 +#error "rtconfig: not enough priority levels between utest thread and idle thread" +#endif + +#define TEST_ORDER_MAX 8 + +static rt_sem_t _order_sem; +static char _run_order[TEST_ORDER_MAX]; +static rt_size_t _run_count; + +static void _order_reset(void) +{ + rt_size_t i; + + for (i = 0; i < TEST_ORDER_MAX; i++) + { + _run_order[i] = '\0'; + } + _run_count = 0; +} + +/* the workers run one at a time on the same core, but keep it interrupt-safe */ +static void _order_record(char c) +{ + rt_base_t level; + + level = rt_hw_interrupt_disable(); + if (_run_count < TEST_ORDER_MAX - 1) + { + _run_order[_run_count++] = c; + } + rt_hw_interrupt_enable(level); +} + +static void _start_worker(rt_thread_t thread) +{ +#ifdef RT_USING_SMP + /* keep the worker on this core, otherwise it may be picked up by an idle + * core immediately and the insertion order cannot be observed at all */ + rt_thread_control(thread, RT_THREAD_CTRL_BIND_CPU, + (void *)(rt_ubase_t)rt_hw_cpu_id()); +#endif /* RT_USING_SMP */ + + rt_thread_startup(thread); +} + +static void _worker_wait_sem(void *parameter) +{ + rt_sem_take(_order_sem, RT_WAITING_FOREVER); + _order_record((char)(rt_ubase_t)parameter); +} + +static void _worker_run(void *parameter) +{ + _order_record((char)(rt_ubase_t)parameter); +} + +/* ------------------------------------------------------------------ */ + +static void _sem_wakeup_order(void) +{ + rt_thread_t worker_a; + rt_thread_t worker_b; + + _order_reset(); + + _order_sem = rt_sem_create("order", 0, RT_IPC_FLAG_PRIO); + uassert_not_null(_order_sem); + + worker_a = rt_thread_create("owA", _worker_wait_sem, (void *)'A', + UTEST_THR_STACK_SIZE, TEST_THREAD_PRIORITY, 5); + worker_b = rt_thread_create("owB", _worker_wait_sem, (void *)'B', + UTEST_THR_STACK_SIZE, TEST_THREAD_PRIORITY, 5); + uassert_not_null(worker_a); + uassert_not_null(worker_b); + + /* start A and let it block first, then B: pending list is A -> B */ + _start_worker(worker_a); + rt_thread_mdelay(50); + _start_worker(worker_b); + rt_thread_mdelay(50); + + /* wake them in pending order, A first and B second */ + rt_sem_release(_order_sem); + rt_sem_release(_order_sem); + + /* let the ready threads run */ + rt_thread_mdelay(100); + + LOG_I("semaphore wakeup order: \"%s\", expect \"AB\"", _run_order); + uassert_str_equal(_run_order, "AB"); + + rt_sem_delete(_order_sem); + _order_sem = RT_NULL; +} + +static void _startup_order(void) +{ + rt_thread_t worker_c; + rt_thread_t worker_d; + + _order_reset(); + + worker_c = rt_thread_create("owC", _worker_run, (void *)'C', + UTEST_THR_STACK_SIZE, TEST_THREAD_PRIORITY, 5); + worker_d = rt_thread_create("owD", _worker_run, (void *)'D', + UTEST_THR_STACK_SIZE, TEST_THREAD_PRIORITY, 5); + uassert_not_null(worker_c); + uassert_not_null(worker_d); + + /* startup C then D without yielding in between */ + _start_worker(worker_c); + _start_worker(worker_d); + + rt_thread_mdelay(100); + + LOG_I("startup order: \"%s\", expect \"CD\"", _run_order); + uassert_str_equal(_run_order, "CD"); +} + +static rt_err_t utest_tc_init(void) +{ + _order_sem = RT_NULL; + _order_reset(); + return RT_EOK; +} + +static rt_err_t utest_tc_cleanup(void) +{ + return RT_EOK; +} + +static void testcase(void) +{ + UTEST_UNIT_RUN(_sem_wakeup_order); + UTEST_UNIT_RUN(_startup_order); +} +UTEST_TC_EXPORT(testcase, "core.scheduler_ready_order", utest_tc_init, utest_tc_cleanup, 10); From ed78f4af6be0102e8839a386c9559bcb2b0d7c85 Mon Sep 17 00:00:00 2001 From: Yunlk <103742015+Yunlk@users.noreply.github.com> Date: Wed, 21 Oct 2026 07:34:31 +0000 Subject: [PATCH 2/2] style: format code with clang-format --- src/scheduler_mp.c | 94 ++++++++++++++++++++++++---------------------- src/scheduler_up.c | 37 +++++++++--------- 2 files changed, 68 insertions(+), 63 deletions(-) diff --git a/src/scheduler_mp.c b/src/scheduler_mp.c index b91590ea20a8..55d3d4a93fff 100644 --- a/src/scheduler_mp.c +++ b/src/scheduler_mp.c @@ -39,8 +39,8 @@ #include #include -#define DBG_TAG "kernel.scheduler" -#define DBG_LVL DBG_INFO +#define DBG_TAG "kernel.scheduler" +#define DBG_LVL DBG_INFO #include rt_list_t rt_thread_priority_table[RT_THREAD_PRIORITY_MAX]; @@ -48,16 +48,18 @@ static struct rt_spinlock _mp_scheduler_lock; #define SCHEDULER_LOCK_FLAG(percpu) ((percpu)->sched_lock_flag) -#define SCHEDULER_ENTER_CRITICAL(curthr) \ - do \ - { \ - if (curthr) RT_SCHED_CTX(curthr).critical_lock_nest++; \ +#define SCHEDULER_ENTER_CRITICAL(curthr) \ + do \ + { \ + if (curthr) \ + RT_SCHED_CTX(curthr).critical_lock_nest++; \ } while (0) -#define SCHEDULER_EXIT_CRITICAL(curthr) \ - do \ - { \ - if (curthr) RT_SCHED_CTX(curthr).critical_lock_nest--; \ +#define SCHEDULER_EXIT_CRITICAL(curthr) \ + do \ + { \ + if (curthr) \ + RT_SCHED_CTX(curthr).critical_lock_nest--; \ } while (0) #define SCHEDULER_CONTEXT_LOCK(percpu) \ @@ -202,7 +204,7 @@ rt_inline rt_base_t _get_global_highest_ready_prio(void) return highest_ready_priority; } -rt_inline rt_base_t _get_local_highest_ready_prio(struct rt_cpu* pcpu) +rt_inline rt_base_t _get_local_highest_ready_prio(struct rt_cpu *pcpu) { rt_ubase_t number; rt_ubase_t local_highest_ready_priority; @@ -226,7 +228,7 @@ rt_inline rt_base_t _get_global_highest_ready_prio(void) return __rt_ffs(rt_thread_ready_priority_group) - 1; } -rt_inline rt_base_t _get_local_highest_ready_prio(struct rt_cpu* pcpu) +rt_inline rt_base_t _get_local_highest_ready_prio(struct rt_cpu *pcpu) { return __rt_ffs(pcpu->priority_group) - 1; } @@ -236,11 +238,11 @@ rt_inline rt_base_t _get_local_highest_ready_prio(struct rt_cpu* pcpu) /* * get the highest priority thread in ready queue */ -static struct rt_thread* _scheduler_get_highest_priority_thread(rt_ubase_t *highest_prio) +static struct rt_thread *_scheduler_get_highest_priority_thread(rt_ubase_t *highest_prio) { struct rt_thread *highest_priority_thread; rt_ubase_t highest_ready_priority, local_highest_ready_priority; - struct rt_cpu* pcpu = rt_cpu_self(); + struct rt_cpu *pcpu = rt_cpu_self(); highest_ready_priority = _get_global_highest_ready_prio(); local_highest_ready_priority = _get_local_highest_ready_prio(pcpu); @@ -288,7 +290,7 @@ static void _sched_insert_thread_locked(struct rt_thread *thread) if ((RT_SCHED_CTX(thread).stat & RT_THREAD_STAT_MASK) == RT_THREAD_READY) { /* already in ready queue */ - return ; + return; } else if (RT_SCHED_CTX(thread).oncpu != RT_CPU_DETACHED) { @@ -297,7 +299,7 @@ static void _sched_insert_thread_locked(struct rt_thread *thread) * this is a RUNNING thread. So here we reset it's status and let it go. */ RT_SCHED_CTX(thread).stat = RT_THREAD_RUNNING | (RT_SCHED_CTX(thread).stat & ~RT_THREAD_STAT_MASK); - return ; + return; } /* READY thread, insert to ready queue */ @@ -316,7 +318,7 @@ static void _sched_insert_thread_locked(struct rt_thread *thread) insert_at_head = (((stat_before & RT_THREAD_STAT_MASK) == RT_THREAD_RUNNING) && ((stat_before & RT_THREAD_STAT_YIELD_MASK) == 0)); - cpu_id = rt_hw_cpu_id(); + cpu_id = rt_hw_cpu_id(); bind_cpu = RT_SCHED_CTX(thread).bind_cpu; /* insert thread to ready list */ @@ -446,15 +448,15 @@ void rt_system_scheduler_init(void) rt_spin_lock_init(&_mp_scheduler_lock); - for (offset = 0; offset < RT_THREAD_PRIORITY_MAX; offset ++) + for (offset = 0; offset < RT_THREAD_PRIORITY_MAX; offset++) { rt_list_init(&rt_thread_priority_table[offset]); } for (cpu = 0; cpu < RT_CPUS_NR; cpu++) { - struct rt_cpu *pcpu = rt_cpu_index(cpu); - for (offset = 0; offset < RT_THREAD_PRIORITY_MAX; offset ++) + struct rt_cpu *pcpu = rt_cpu_index(cpu); + for (offset = 0; offset < RT_THREAD_PRIORITY_MAX; offset++) { rt_list_init(&pcpu->priority_table[offset]); } @@ -577,7 +579,9 @@ rt_err_t rt_sched_lock(rt_sched_lock_level_t *plvl) { rt_base_t level; if (!plvl) + { return -RT_EINVAL; + } SCHEDULER_LOCK(level); *plvl = level; @@ -653,8 +657,7 @@ static rt_thread_t _prepare_context_switch_locked(int cpu_id, if ((RT_SCHED_CTX(current_thread).stat & RT_THREAD_STAT_MASK) == RT_THREAD_RUNNING) { /* check if current thread can be running on current core again */ - if (RT_SCHED_CTX(current_thread).bind_cpu == RT_CPUS_NR - || RT_SCHED_CTX(current_thread).bind_cpu == cpu_id) + if (RT_SCHED_CTX(current_thread).bind_cpu == RT_CPUS_NR || RT_SCHED_CTX(current_thread).bind_cpu == cpu_id) { /* if current_thread is the highest runnable thread */ if (RT_SCHED_PRIV(current_thread).current_priority < highest_ready_priority) @@ -788,12 +791,12 @@ static void _sched_thread_process_signal(struct rt_thread *current_thread) /* lock is released above */ } -#define SCHED_THREAD_PREPROCESS_SIGNAL(pcpu, curthr) \ - do \ - { \ - SCHEDULER_CONTEXT_LOCK(pcpu); \ - _sched_thread_preprocess_signal(curthr); \ - SCHEDULER_CONTEXT_UNLOCK(pcpu); \ +#define SCHED_THREAD_PREPROCESS_SIGNAL(pcpu, curthr) \ + do \ + { \ + SCHEDULER_CONTEXT_LOCK(pcpu); \ + _sched_thread_preprocess_signal(curthr); \ + SCHEDULER_CONTEXT_UNLOCK(pcpu); \ } while (0) #define SCHED_THREAD_PREPROCESS_SIGNAL_LOCKED(curthr) \ _sched_thread_preprocess_signal(curthr) @@ -833,12 +836,12 @@ rt_err_t rt_sched_unlock_n_resched(rt_sched_lock_level_t level) { struct rt_thread *to_thread; struct rt_thread *current_thread; - struct rt_cpu *pcpu; - int cpu_id; - rt_err_t error = RT_EOK; + struct rt_cpu *pcpu; + int cpu_id; + rt_err_t error = RT_EOK; cpu_id = rt_hw_cpu_id(); - pcpu = rt_cpu_index(cpu_id); + pcpu = rt_cpu_index(cpu_id); current_thread = pcpu->current_thread; if (!current_thread) @@ -934,15 +937,15 @@ void rt_schedule(void) rt_base_t level; struct rt_thread *to_thread; struct rt_thread *current_thread; - struct rt_cpu *pcpu; - int cpu_id; + struct rt_cpu *pcpu; + int cpu_id; /* enter ciritical region of percpu scheduling context */ level = rt_hw_local_irq_disable(); /* get percpu scheduling context */ cpu_id = rt_hw_cpu_id(); - pcpu = rt_cpu_index(cpu_id); + pcpu = rt_cpu_index(cpu_id); current_thread = pcpu->current_thread; /* whether do switch in interrupt */ @@ -950,7 +953,7 @@ void rt_schedule(void) { pcpu->irq_switch_flag = 1; rt_hw_local_irq_enable(level); - return ; /* -RT_ESCHEDISR */ + return; /* -RT_ESCHEDISR */ } /* forbid any recursive entries of schedule() */ @@ -1026,16 +1029,16 @@ void rt_schedule(void) */ void rt_scheduler_do_irq_switch(void *context) { - int cpu_id; - rt_base_t level; - struct rt_cpu *pcpu; + int cpu_id; + rt_base_t level; + struct rt_cpu *pcpu; struct rt_thread *to_thread; struct rt_thread *current_thread; level = rt_hw_local_irq_disable(); cpu_id = rt_hw_cpu_id(); - pcpu = rt_cpu_index(cpu_id); + pcpu = rt_cpu_index(cpu_id); current_thread = pcpu->current_thread; /* forbid any recursive entries of schedule() */ @@ -1158,7 +1161,7 @@ void rt_sched_thread_init_priv(struct rt_thread *thread, rt_uint32_t tick, rt_ui /* priority init */ RT_ASSERT(priority < RT_THREAD_PRIORITY_MAX); - RT_SCHED_PRIV(thread).init_priority = priority; + RT_SCHED_PRIV(thread).init_priority = priority; RT_SCHED_PRIV(thread).current_priority = priority; /* don't add to scheduler queue as init thread */ @@ -1177,7 +1180,6 @@ void rt_sched_thread_init_priv(struct rt_thread *thread, rt_uint32_t tick, rt_ui /* lock init */ RT_SCHED_CTX(thread).critical_lock_nest = 0; #endif /* RT_USING_SMP */ - } /** @@ -1231,7 +1233,7 @@ void rt_sched_thread_startup(struct rt_thread *thread) */ void rt_sched_post_ctx_switch(struct rt_thread *thread) { - struct rt_cpu* pcpu = rt_cpu_self(); + struct rt_cpu *pcpu = rt_cpu_self(); rt_thread_t from_thread = pcpu->current_thread; RT_ASSERT(rt_hw_interrupt_is_disabled()); @@ -1280,13 +1282,13 @@ void rt_exit_critical_safe(rt_base_t critical_level) int dummy = 1; _critical_error_occurred = 1; - rt_kprintf("%s: un-compatible critical level\n" \ + rt_kprintf("%s: un-compatible critical level\n" "\tCurrent %d\n\tCaller %d\n", __func__, RT_SCHED_CTX(current_thread).critical_lock_nest, critical_level); rt_backtrace(); - while (dummy) ; + while (dummy); } } rt_exit_critical(); @@ -1438,7 +1440,9 @@ void rt_exit_critical(void) FREE_THREAD_SELF(level); if (need_resched) + { rt_schedule(); + } } else { diff --git a/src/scheduler_up.c b/src/scheduler_up.c index f42f05427b50..80084b6e1abb 100644 --- a/src/scheduler_up.c +++ b/src/scheduler_up.c @@ -39,8 +39,8 @@ #include #include -#define DBG_TAG "kernel.scheduler" -#define DBG_LVL DBG_INFO +#define DBG_TAG "kernel.scheduler" +#define DBG_LVL DBG_INFO #include rt_list_t rt_thread_priority_table[RT_THREAD_PRIORITY_MAX]; @@ -101,7 +101,7 @@ void rt_scheduler_switch_sethook(void (*hook)(struct rt_thread *tid)) * @{ */ -static struct rt_thread* _scheduler_get_highest_priority_thread(rt_ubase_t *highest_prio) +static struct rt_thread *_scheduler_get_highest_priority_thread(rt_ubase_t *highest_prio) { struct rt_thread *highest_priority_thread; rt_ubase_t highest_ready_priority; @@ -144,7 +144,9 @@ rt_err_t rt_sched_lock(rt_sched_lock_level_t *plvl) { rt_base_t level; if (!plvl) + { return -RT_EINVAL; + } level = rt_hw_interrupt_disable(); *plvl = level; @@ -215,7 +217,7 @@ void rt_system_scheduler_init(void) LOG_D("start scheduler: max priority 0x%02x", RT_THREAD_PRIORITY_MAX); - for (offset = 0; offset < RT_THREAD_PRIORITY_MAX; offset ++) + for (offset = 0; offset < RT_THREAD_PRIORITY_MAX; offset++) { rt_list_init(&rt_thread_priority_table[offset]); } @@ -310,8 +312,7 @@ void rt_schedule(void) { to_thread = curr_thread; } - else if (RT_SCHED_PRIV(curr_thread).current_priority == highest_ready_priority - && (RT_SCHED_CTX(curr_thread).stat & RT_THREAD_STAT_YIELD_MASK) == 0) + else if (RT_SCHED_PRIV(curr_thread).current_priority == highest_ready_priority && (RT_SCHED_CTX(curr_thread).stat & RT_THREAD_STAT_YIELD_MASK) == 0) { to_thread = curr_thread; } @@ -325,7 +326,7 @@ void rt_schedule(void) { /* if the destination thread is not the same as current thread */ rt_current_priority = (rt_uint8_t)highest_ready_priority; - from_thread = curr_thread; + from_thread = curr_thread; rt_cpu_self()->current_thread = to_thread; RT_OBJECT_HOOK_CALL(rt_scheduler_hook, (from_thread, to_thread)); @@ -346,11 +347,11 @@ void rt_schedule(void) /* switch to new thread */ interrupt_nest = rt_interrupt_get_nest(); LOG_D("[%d]switch to priority#%d " - "thread:%.*s(sp:0x%08x), " - "from thread:%.*s(sp: 0x%08x)", - interrupt_nest, highest_ready_priority, - RT_NAME_MAX, to_thread->parent.name, to_thread->sp, - RT_NAME_MAX, from_thread->parent.name, from_thread->sp); + "thread:%.*s(sp:0x%08x), " + "from thread:%.*s(sp: 0x%08x)", + interrupt_nest, highest_ready_priority, + RT_NAME_MAX, to_thread->parent.name, to_thread->sp, + RT_NAME_MAX, from_thread->parent.name, from_thread->sp); RT_SCHEDULER_STACK_CHECK(to_thread); @@ -361,7 +362,7 @@ void rt_schedule(void) RT_OBJECT_HOOK_CALL(rt_scheduler_switch_hook, (from_thread)); rt_hw_context_switch((rt_uintptr_t)&from_thread->sp, - (rt_uintptr_t)&to_thread->sp); + (rt_uintptr_t)&to_thread->sp); /* enable interrupt */ rt_hw_interrupt_enable(level); @@ -392,7 +393,7 @@ void rt_schedule(void) LOG_D("switch in interrupt"); rt_hw_context_switch_interrupt((rt_uintptr_t)&from_thread->sp, - (rt_uintptr_t)&to_thread->sp, from_thread, to_thread); + (rt_uintptr_t)&to_thread->sp, from_thread, to_thread); } } else @@ -465,7 +466,7 @@ void rt_sched_thread_init_priv(struct rt_thread *thread, rt_uint32_t tick, rt_ui /* priority init */ RT_ASSERT(priority < RT_THREAD_PRIORITY_MAX); - RT_SCHED_PRIV(thread).init_priority = priority; + RT_SCHED_PRIV(thread).init_priority = priority; RT_SCHED_PRIV(thread).current_priority = priority; /* don't add to scheduler queue as init thread */ @@ -616,13 +617,13 @@ void rt_exit_critical_safe(rt_base_t critical_level) int dummy = 1; _critical_error_occurred = 1; - rt_kprintf("%s: un-compatible critical level\n" \ + rt_kprintf("%s: un-compatible critical level\n" "\tCurrent %d\n\tCaller %d\n", __func__, rt_scheduler_lock_nest, critical_level); rt_backtrace(); - while (dummy) ; + while (dummy); } } rt_hw_interrupt_enable(level); @@ -697,7 +698,7 @@ void rt_exit_critical(void) /* disable interrupt */ level = rt_hw_interrupt_disable(); - rt_scheduler_lock_nest --; + rt_scheduler_lock_nest--; if (rt_scheduler_lock_nest <= 0) { rt_scheduler_lock_nest = 0;