diff --git a/examples/utest/testcases/kernel/Kconfig b/examples/utest/testcases/kernel/Kconfig index cc03ca0a4d..163e22a1da 100644 --- a/examples/utest/testcases/kernel/Kconfig +++ b/examples/utest/testcases/kernel/Kconfig @@ -77,4 +77,8 @@ config UTEST_SCHEDULER_TC bool "scheduler test" default n +if RT_USING_SMP +rsource "smp/Kconfig" +endif + endmenu diff --git a/examples/utest/testcases/kernel/SConscript b/examples/utest/testcases/kernel/SConscript index 1ec8beedd2..f6270a5490 100644 --- a/examples/utest/testcases/kernel/SConscript +++ b/examples/utest/testcases/kernel/SConscript @@ -62,4 +62,9 @@ if GetDepend(['UTEST_SCHEDULER_TC']): group = DefineGroup('utestcases', src, depend = ['RT_USING_UTESTCASES'], CPPPATH = CPPPATH) +list = os.listdir(cwd) +for item in list: + if os.path.isfile(os.path.join(cwd, item, 'SConscript')): + group = group + SConscript(os.path.join(item, 'SConscript')) + Return('group') diff --git a/examples/utest/testcases/kernel/smp/Kconfig b/examples/utest/testcases/kernel/smp/Kconfig new file mode 100644 index 0000000000..e7450b477f --- /dev/null +++ b/examples/utest/testcases/kernel/smp/Kconfig @@ -0,0 +1,23 @@ +menu "Kernel SMP Testcase" + +config UTEST_SMP_AFFFINITY_TC + bool "smp affinity and thread priority test1" + default n + +config UTEST_SMP_ASSIGNED_IDLE_CORE_TC + bool "smp threads auto assign to idle cores for test" + default n + +config UTEST_SMP_INTERRUPT_PRI_TC + bool "smp interrupt priority test" + default n + +config UTEST_SMP_SPINLOCK_TC + bool "smp spinlock test" + default n + +config UTEST_SMP_THREAD_PREEMPTION_TC + bool "smp threads preemption test" + default n + +endmenu diff --git a/examples/utest/testcases/kernel/smp/SConscript b/examples/utest/testcases/kernel/smp/SConscript new file mode 100644 index 0000000000..a15753f7be --- /dev/null +++ b/examples/utest/testcases/kernel/smp/SConscript @@ -0,0 +1,27 @@ +Import('rtconfig') +from building import * + +cwd = GetCurrentDir() +src = [] +CPPPATH = [cwd] + +if GetDepend(['UTEST_SMP_SPINLOCK_TC']): + src += ['smp_spinlock_tc.c'] + +if GetDepend(['UTEST_SMP_ASSIGNED_IDLE_CORE_TC']): + src += ['smp_assigned_idle_cores_tc.c'] + +if GetDepend(['UTEST_SMP_INTERRUPT_PRI_TC']): + src += ['smp_interrupt_pri_tc.c'] + +if GetDepend(['UTEST_SMP_THREAD_PREEMPTION_TC']): + src += ['smp_thread_preemption_tc.c'] + +if GetDepend(['UTEST_SMP_AFFFINITY_TC']): + src += ['smp_bind_affinity_tc.c'] + src += ['smp_affinity_pri1_tc.c'] + src += ['smp_affinity_pri2_tc.c'] + +group = DefineGroup('utestcases', src, depend = ['RT_USING_UTESTCASES'], CPPPATH = CPPPATH) + +Return('group') diff --git a/examples/utest/testcases/kernel/smp/smp_affinity_pri1_tc.c b/examples/utest/testcases/kernel/smp/smp_affinity_pri1_tc.c new file mode 100644 index 0000000000..56a8355f93 --- /dev/null +++ b/examples/utest/testcases/kernel/smp/smp_affinity_pri1_tc.c @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-08-10 RV the first version + */ + +#include +#include "utest.h" + +/** + * @brief Test that threads with low-priority bound cores do not preempt high-priority threads. + * + * @note Create RT_CPUS_NR threads, thread 0 is bound to core 0, lower priority, the priority of the other threads + * for the system's highest and the thread entry function does not let out the CPU control, run the specified + * number of times in thread 0 to create a high-priority not bound to the core of the thread, the thread will + * be preempted by the core 0 is running on the thread! + */ + +/* Number of thread runs */ +static int run_num = 10; +#define THREAD_STACK_SIZE 1024 +#define THREAD_PRIORITY 2 +#define LOW_PRIORITY 50 +#define THIGH_PRIORITY 10 +static rt_thread_t threads[RT_CPUS_NR]; +static rt_thread_t temp_thread; +static struct rt_spinlock lock; +static int thread_inc = 0; +static int num = 0; + +static void thread_temp_entry(void *parameter) +{ + int id = 0; + while (1) + { + id = rt_hw_cpu_id(); + uassert_int_equal(id, 0); + extern long list_thread(void); + list_thread(); + rt_thread_delete(temp_thread); + } +} + +static void thread_entry(void *parameter) +{ + int id = 0; + int para = *(int *)parameter; + while (1) + { + thread_inc++; + id = rt_hw_cpu_id(); + if (para == 0) + { + if (thread_inc == run_num) + { + uassert_int_equal(id, 0); + extern long list_thread(void); + list_thread(); + /* Creating high-priority untied core threads */ + temp_thread = rt_thread_create("Tn", thread_temp_entry, RT_NULL, THREAD_STACK_SIZE, THIGH_PRIORITY, 20); + + if (temp_thread != RT_NULL) + { + rt_thread_startup(temp_thread); + } + } + rt_thread_delay(5); + } + else + { + uassert_int_not_equal(id, 0); + while (1); + } + } +} + +static void smp_affinity_pri1_tc(void) +{ + static int params[RT_CPUS_NR] = {0}; + char thread_name[8]; + int i; + + for (i = 0; i < RT_CPUS_NR; i++) + { + params[i] = i; + } + + /* Creating threads with low priority bindings to core 0 */ + threads[0] = rt_thread_create("T0", thread_entry, (int *)¶ms[0], THREAD_STACK_SIZE, LOW_PRIORITY, 20); + + if (threads[0] != RT_NULL) + { + rt_thread_control(threads[0], RT_THREAD_CTRL_BIND_CPU, (void *)0); + rt_thread_startup(threads[0]); + } + + /* Create high-priority unbound threads with thread functions that don't let out CPU control */ + for (i = 1; i < RT_CPUS_NR; i++) + { + rt_snprintf(thread_name, sizeof(thread_name), "T%d", i); + threads[i] = rt_thread_create(thread_name, thread_entry, (int *)¶ms[i], THREAD_STACK_SIZE, THREAD_PRIORITY, 20); + + if (threads[i] != RT_NULL) + { + rt_thread_control(threads[i], RT_THREAD_CTRL_BIND_CPU, (void *)i); + rt_thread_startup(threads[i]); + } + } + rt_thread_delay(100); +} + +static rt_err_t utest_tc_init(void) +{ + rt_spin_lock_init(&lock); + return RT_EOK; +} + +static rt_err_t utest_tc_cleanup(void) +{ + for (num = 0; num < RT_CPUS_NR; num++) + { + rt_thread_delete(threads[num]); + } + return RT_EOK; +} + +static void testcase(void) +{ + UTEST_UNIT_RUN(smp_affinity_pri1_tc); +} +UTEST_TC_EXPORT(testcase, "testcases.smp.affinity_pri1_tc", utest_tc_init, utest_tc_cleanup, 10); diff --git a/examples/utest/testcases/kernel/smp/smp_affinity_pri2_tc.c b/examples/utest/testcases/kernel/smp/smp_affinity_pri2_tc.c new file mode 100644 index 0000000000..6036f341d6 --- /dev/null +++ b/examples/utest/testcases/kernel/smp/smp_affinity_pri2_tc.c @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-08-10 RV the first version + */ + +#include +#include "utest.h" + +/** + * @brief Threads are automatically balanced across cores. + * + * @note Create RT_CPUS_NR threads, thread 0 is not bound to core 0, higher priority, the priority of the other + * threads for the system's highest and the thread entry function does not let out the CPU control, run the + * specified number of times after the creation of thread 0 in thread 0, a low-priority bound to the core 0, + * the thread will not preempt the core 0 is running on threads + */ + +/* Number of thread runs */ +static int run_num = 10; +#define THREAD_STACK_SIZE 1024 +#define THREAD_PRIORITY 2 +#define LOW_PRIORITY 50 +#define THIGH_PRIORITY 10 +static rt_thread_t threads[RT_CPUS_NR]; +static rt_thread_t temp_thread; +static struct rt_spinlock lock; +static int thread_inc = 0; +static int run_flag = 0; +static int num = 0; + +static void thread_temp_entry(void *parameter) +{ + run_flag = 1; + rt_thread_delete(temp_thread); +} + +static void thread_entry(void *parameter) +{ + int id = 0; + int para = *(int *)parameter; + while (1) + { + thread_inc++; + id = rt_hw_cpu_id(); + if (para == 0) + { + if (thread_inc == run_num) + { + uassert_int_equal(id, 0); + temp_thread = rt_thread_create("Tn", thread_temp_entry, RT_NULL, THREAD_STACK_SIZE, LOW_PRIORITY, 20); + + if (temp_thread != RT_NULL) + { + rt_thread_control(temp_thread, RT_THREAD_CTRL_BIND_CPU, (void *)0); + rt_thread_startup(temp_thread); + uassert_int_not_equal(run_flag, 1); + } + } + rt_thread_delay(5); + } + else + { + uassert_int_not_equal(id, 0); + while (1); + } + } +} + +static void smp_affinity_pri2_tc(void) +{ + static int params[RT_CPUS_NR] = {0}; + char thread_name[8]; + int i; + + for (i = 0; i < RT_CPUS_NR; i++) + { + params[i] = i; + } + + threads[0] = rt_thread_create("T0", thread_entry, (int *)¶ms[0], THREAD_STACK_SIZE, THIGH_PRIORITY, 20); + + if (threads[0] != RT_NULL) + { + uassert_true(1); + rt_thread_startup(threads[0]); + } + + /* Create high-priority unbound threads with thread functions that don't let out CPU control */ + for (i = 1; i < RT_CPUS_NR; i++) + { + rt_snprintf(thread_name, sizeof(thread_name), "T%d", i); + threads[i] = rt_thread_create(thread_name, thread_entry, (int *)¶ms[i], THREAD_STACK_SIZE, THREAD_PRIORITY, 20); + + if (threads[i] != RT_NULL) + { + uassert_true(1); + rt_thread_control(threads[i], RT_THREAD_CTRL_BIND_CPU, (void *)i); + rt_thread_startup(threads[i]); + } + } + rt_thread_delay(50); +} + +static rt_err_t utest_tc_init(void) +{ + rt_spin_lock_init(&lock); + return RT_EOK; +} + +static rt_err_t utest_tc_cleanup(void) +{ + for (num = 0; num < RT_CPUS_NR; num++) + { + rt_thread_delete(threads[num]); + } + return RT_EOK; +} + +static void testcase(void) +{ + UTEST_UNIT_RUN(smp_affinity_pri2_tc); +} +UTEST_TC_EXPORT(testcase, "testcases.smp.affinity_pri2_tc", utest_tc_init, utest_tc_cleanup, 10); diff --git a/examples/utest/testcases/kernel/smp/smp_assigned_idle_cores_tc.c b/examples/utest/testcases/kernel/smp/smp_assigned_idle_cores_tc.c new file mode 100644 index 0000000000..7c138d5da8 --- /dev/null +++ b/examples/utest/testcases/kernel/smp/smp_assigned_idle_cores_tc.c @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-08-10 RV the first version + */ + +#include +#include "utest.h" + +/** + * @brief Threads are automatically balanced across cores. + * + * @note Create multiple threads untied core threads, run them for a while on each core to see + * if the threads are automatically distributed evenly, run for a while to output the threads + * running on each core. + */ + +#define THREAD_STACK_SIZE 1024 +#define THREAD_PRIORITY 20 +static rt_thread_t threads[RT_CPUS_NR]; +static int tick = 0, finsh_flag = 0; +static int num = 0; +/* thread entry function */ +static void thread_entry(void *parameter) +{ + while (1) + { + tick++; + if (tick == 100) + { + /* Output the current core running threads */ + extern long list_thread(void); + list_thread(); + finsh_flag = 0xA55A; + uassert_true(1); + } + rt_thread_delay(5); + } +} + +static void thread_on_idle_core_tc(void) +{ + static int params[RT_CPUS_NR] = {0}; + char thread_name[8]; + int i; + + /* Initialise the thread entry parameters */ + for (i = 0; i < RT_CPUS_NR; i++) + { + params[i] = i; + } + + /* Create RT_CPUS_NR threads and pass the entry parameters for each thread */ + for (i = 0; i < RT_CPUS_NR; i++) + { + rt_snprintf(thread_name, sizeof(thread_name), "T%d", i); + threads[i] = rt_thread_create(thread_name, thread_entry, ¶ms[i], THREAD_STACK_SIZE, THREAD_PRIORITY, 20); + if (threads[i] != RT_NULL) + { + uassert_true(1); + rt_thread_startup(threads[i]); + } + } + /* Waiting for test cases to finish */ + while (finsh_flag != 0xA55A); +} + +static rt_err_t utest_tc_init(void) +{ + rt_kprintf("[Test case]: created threads are automatically assigned to run on idle cores\r\n"); + return RT_EOK; +} + +static rt_err_t utest_tc_cleanup(void) +{ + for (num = 0; num < RT_CPUS_NR; num++) + { + rt_thread_delete(threads[num]); + } + return RT_EOK; +} + +static void testcase(void) +{ + UTEST_UNIT_RUN(thread_on_idle_core_tc); +} +UTEST_TC_EXPORT(testcase, "testcases.smp.assigned_idle_cores_tc", utest_tc_init, utest_tc_cleanup, 10); diff --git a/examples/utest/testcases/kernel/smp/smp_bind_affinity_tc.c b/examples/utest/testcases/kernel/smp/smp_bind_affinity_tc.c new file mode 100644 index 0000000000..e44ebeb2a6 --- /dev/null +++ b/examples/utest/testcases/kernel/smp/smp_bind_affinity_tc.c @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-08-10 RV the first version + */ + +#include +#include "utest.h" + +/** + * @brief Binding core affinity testcase. + * + * @note Create RT_CPUS_NR threads, thread 0 is bound to core 0, other threads are not bound to specific cores, + * after running for a set number of times, count the number of times each core is run on the corresponding core, + * thread 0 should always be run on core 0, other threads will be run on different cores. + */ + +/* Number of thread runs */ +static int run_num = 100; +#define THREAD_STACK_SIZE 1024 +#define THREAD_PRIORITY 20 +static rt_thread_t threads[RT_CPUS_NR]; +static struct rt_spinlock lock; +static int thread_inc[RT_CPUS_NR] = {0}; +static int thread_tic[RT_CPUS_NR] = {0}; +static int finsh_flag = 0; +static int num = 0; + +static void thread_entry(void *parameter) +{ + int id = 0; + int para = *(int *)parameter; + while (1) + { + thread_tic[para]++; + id = rt_hw_cpu_id(); + if (para == id) + { + thread_inc[para]++; + } + + if (thread_tic[para] == run_num) + { + if (para == 0) + uassert_int_equal(thread_inc[para], thread_tic[para]); + else + uassert_int_not_equal(thread_inc[para], thread_tic[para]); + finsh_flag ++; + } + rt_thread_delay(5); + } +} + +static void thread_bind_affinity_tc(void) +{ + static int params[RT_CPUS_NR] = {0}; + char thread_name[8]; + int i, j; + + for (i = 0; i < RT_CPUS_NR; i++) + { + params[i] = i; + } + + /* Create RT_CPUS_NR threads Thread 0 is bound to core 0 Other threads are not bound */ + for (i = 0; i < RT_CPUS_NR; i++) + { + rt_snprintf(thread_name, sizeof(thread_name), "thread%d", i); + threads[i] = rt_thread_create(thread_name, thread_entry, (int *)¶ms[i], THREAD_STACK_SIZE, THREAD_PRIORITY, 20); + if (i == 0) + { + rt_thread_control(threads[0], RT_THREAD_CTRL_BIND_CPU, (void *)0); + } + if (threads[i] != RT_NULL) + { + rt_thread_startup(threads[i]); + } + } + + while (finsh_flag != RT_CPUS_NR); + + /* Displays the number of times a thread was executed on the relevant core */ + for (j = 0; j < RT_CPUS_NR; j++) + { + rt_spin_lock(&lock); + rt_kprintf("Total runs[%d], Number of times thread[%d] run on [core%d]: [%4d], always run at core%d ? %s \r\n", run_num, j, j, thread_inc[j], j, (thread_inc[j] == run_num) ? "yes" : "no"); + rt_spin_unlock(&lock); + } +} + +static rt_err_t utest_tc_init(void) +{ + rt_spin_lock_init(&lock); + return RT_EOK; +} + +static rt_err_t utest_tc_cleanup(void) +{ + for (num = 0; num < RT_CPUS_NR; num++) + { + rt_thread_delete(threads[num]); + } + return RT_EOK; +} + +static void testcase(void) +{ + UTEST_UNIT_RUN(thread_bind_affinity_tc); +} +UTEST_TC_EXPORT(testcase, "testcases.smp.bind_affinity_tc", utest_tc_init, utest_tc_cleanup, 10); diff --git a/examples/utest/testcases/kernel/smp/smp_interrupt_pri_tc.c b/examples/utest/testcases/kernel/smp/smp_interrupt_pri_tc.c new file mode 100644 index 0000000000..4afd0ef143 --- /dev/null +++ b/examples/utest/testcases/kernel/smp/smp_interrupt_pri_tc.c @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-08-10 RV the first version + */ + +#include +#include "utest.h" +#include + +/** + * @brief Setting the Interrupt Priority Test. + * + * @note Without turning off interrupts, interrupts respond in the order in which they are triggered. + * With interrupts turned off, low and high priority interrupts are triggered sequentially, + * and when interrupts are turned on, high priority interrupts respond first. + */ + +#define RES_VAL 0X0 +#define SET_VAL 0XA +#define RT_SPI_1 1 +#define RT_SPI_2 2 +#define RT_SPI_PRI_HIGH 120 +#define RT_SPI_PRI_LOW 140 + +static int mode = 0; +static int ipi_val[2] = {0, 0}; + +/* Software Interrupt 1 Service Functions */ +static void rt_scheduler_ipi1_handler(int vector, void *param) +{ + ipi_val[0] = SET_VAL; + if (mode == 0) + { + uassert_true(ipi_val[0] > ipi_val[1]); + } + else + { + ipi_val[0] = RES_VAL; + ipi_val[1] = RES_VAL; + } +} + +/* Software Interrupt 2 Service Functions */ +static void rt_scheduler_ipi2_handler(int vector, void *param) +{ + ipi_val[1] = SET_VAL; + if (mode == 0) + { + ipi_val[0] = RES_VAL; + ipi_val[1] = RES_VAL; + } + else + { + uassert_true(ipi_val[0] < ipi_val[1]); + } +} + +/* Interrupt priority testcases 1 */ +static void int_pri1_tc(void) +{ + mode = 0; + unsigned int pri1, pri2; + pri1 = rt_hw_interrupt_get_priority(RT_SPI_1); + pri2 = rt_hw_interrupt_get_priority(RT_SPI_2); + + if (pri1 < pri2) + uassert_true(pri1 < pri2); + + /* Trigger interrupt */ + rt_hw_ipi_send(RT_SPI_1, 0x1); + rt_hw_ipi_send(RT_SPI_2, 0x1); + rt_thread_delay(5); +} + +/* Interrupt priority testcases 2 */ +static void int_pri2_tc(void) +{ + mode = 1; + unsigned int pri1, pri2; + pri1 = rt_hw_interrupt_get_priority(RT_SPI_1); + pri2 = rt_hw_interrupt_get_priority(RT_SPI_2); + + if (pri1 < pri2) + uassert_true(pri1 < pri2); + + rt_base_t level = rt_hw_local_irq_disable(); + /* Trigger interrupt */ + rt_hw_ipi_send(RT_SPI_1, 0x1); + rt_hw_ipi_send(RT_SPI_2, 0x1); + rt_hw_local_irq_enable(level); + rt_thread_delay(5); +} + +static rt_err_t utest_tc_init(void) +{ + /* Setting the priority of software interrupts */ + rt_hw_interrupt_set_priority(RT_SPI_1, RT_SPI_PRI_LOW); + rt_hw_interrupt_set_priority(RT_SPI_2, RT_SPI_PRI_HIGH); + /* Register software interrupt service functions */ + rt_hw_ipi_handler_install(RT_SPI_1, rt_scheduler_ipi1_handler); + rt_hw_ipi_handler_install(RT_SPI_2, rt_scheduler_ipi2_handler); + return RT_EOK; +} + +static rt_err_t utest_tc_cleanup(void) +{ + return RT_EOK; +} + +static void testcase(void) +{ + UTEST_UNIT_RUN(int_pri1_tc); + UTEST_UNIT_RUN(int_pri2_tc); +} +UTEST_TC_EXPORT(testcase, "testcases.smp.interrupt_pri_tc", utest_tc_init, utest_tc_cleanup, 10); diff --git a/examples/utest/testcases/kernel/smp/smp_spinlock_tc.c b/examples/utest/testcases/kernel/smp/smp_spinlock_tc.c new file mode 100644 index 0000000000..a6d58b605b --- /dev/null +++ b/examples/utest/testcases/kernel/smp/smp_spinlock_tc.c @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-08-13 RV the first version + */ + +#include +#include "utest.h" +#include + +/** + * @brief Spinlock testcase. + * + * @note Create multiple threads and use spinlocks to protect shared memory + */ + +#define THREAD_PRIORITY 20 +#define THREAD_TIMESLICE 20 +#define THREAD_STACK_SIZE 1024 +static rt_thread_t thread1; +static rt_thread_t thread2; +static rt_uint8_t finsh_flag = 0; +static struct rt_spinlock lock; +static rt_uint8_t number1, number2 = 0; + +static void rt_thread_entry1(void *parameter) +{ + while (1) + { + rt_spin_lock(&lock); + number1++; + rt_thread_yield(); + number2++; + rt_spin_unlock(&lock); + rt_thread_delay(5); + } +} + +static void rt_thread_entry2(void *parameter) +{ + while (1) + { + rt_spin_lock(&lock); + uassert_int_equal(number1, number2); + number1++; + number2++; + rt_spin_unlock(&lock); + if (number1 >= 10) + { + finsh_flag = 1; + } + rt_thread_delay(5); + } +} + +static void smp_spinlock_tc(void) +{ + thread1 = rt_thread_create("T1", rt_thread_entry1, RT_NULL, THREAD_STACK_SIZE, THREAD_PRIORITY, 20); + if (thread1 != RT_NULL) + { + rt_thread_startup(thread1); + } + + thread2 = rt_thread_create("T2", rt_thread_entry2, RT_NULL, THREAD_STACK_SIZE, THREAD_PRIORITY - 1, 20); + if (thread2 != RT_NULL) + { + rt_thread_startup(thread2); + } + while (finsh_flag == 0); +} + +static rt_err_t utest_tc_init(void) +{ + rt_spin_lock_init(&lock); + return RT_EOK; +} + +static rt_err_t utest_tc_cleanup(void) +{ + rt_thread_delete(thread1); + rt_thread_delete(thread2); + return RT_EOK; +} + +static void testcase(void) +{ + UTEST_UNIT_RUN(smp_spinlock_tc); +} +UTEST_TC_EXPORT(testcase, "testcases.smp.spinlock_tc", utest_tc_init, utest_tc_cleanup, 10); diff --git a/examples/utest/testcases/kernel/smp/smp_thread_preemption_tc.c b/examples/utest/testcases/kernel/smp/smp_thread_preemption_tc.c new file mode 100644 index 0000000000..7ffb673888 --- /dev/null +++ b/examples/utest/testcases/kernel/smp/smp_thread_preemption_tc.c @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-08-10 RV the first version + */ + +#include +#include "utest.h" + +/** + * @brief Thread Preemption Test with Different Priorities. + * + * @note Create multiple threads, low-priority threads run first, + * high-priority threads preempt low-priority threads, and + * print the current status of each core in the thread's entry function. + */ + +#define THREAD_PRIORITY_HIGH 21 +#define THREAD_PRIORITY_LOW 30 + +static rt_thread_t threads[2]; +static struct rt_spinlock lock; + +/* High Priority Thread */ +static void thread_high_entry(void *parameter) +{ + uassert_true(1); + rt_spin_lock(&lock); + rt_kprintf("High priority thread is running\n"); + extern long list_thread(void); + list_thread(); + rt_spin_unlock(&lock); +} + +/* Low Priority Thread */ +static void thread_low_entry(void *parameter) +{ + uassert_true(1); + rt_spin_lock(&lock); + rt_kprintf("Low priority thread is running\n"); + extern long list_thread(void); + list_thread(); + rt_spin_unlock(&lock); +} + +static void thread_preemptions_tc(void) +{ + /* Creating low-priority thread */ + threads[0] = rt_thread_create("tlow", thread_low_entry, RT_NULL, 1024, THREAD_PRIORITY_LOW, 10); + if (threads[0] != RT_NULL) + { + uassert_true(1); + rt_thread_startup(threads[0] ); + } + + rt_thread_delay(5); + /* Creating high-priority thread */ + threads[1] = rt_thread_create("thigh", thread_high_entry, RT_NULL, 1024, THREAD_PRIORITY_HIGH, 10); + if (threads[1] != RT_NULL) + { + uassert_true(1); + rt_thread_startup(threads[1]); + } + rt_thread_delay(50); +} + +static rt_err_t utest_tc_init(void) +{ + rt_spin_lock_init(&lock); + return RT_EOK; +} + +static rt_err_t utest_tc_cleanup(void) +{ + return RT_EOK; +} + +static void testcase(void) +{ + UTEST_UNIT_RUN(thread_preemptions_tc); +} +UTEST_TC_EXPORT(testcase, "testcases.smp.thread_preemptions_tc", utest_tc_init, utest_tc_cleanup, 10);