summaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorYaochenger <[email protected]>2024-08-27 17:13:17 +0800
committerRbb666 <[email protected]>2024-09-03 14:03:21 +0800
commitf33312abe0b058ae886abcf95ab6192b25dfca5e (patch)
treea414937623fa64ccd5f7191e5a76824eb1f8a772 /examples
parent0d87b028ed9c84f9ac9b83097d38b808cfe79f17 (diff)
[utest] add smp testcases
Diffstat (limited to 'examples')
-rw-r--r--examples/utest/testcases/kernel/Kconfig4
-rw-r--r--examples/utest/testcases/kernel/SConscript5
-rw-r--r--examples/utest/testcases/kernel/smp/Kconfig23
-rw-r--r--examples/utest/testcases/kernel/smp/SConscript27
-rw-r--r--examples/utest/testcases/kernel/smp/smp_affinity_pri1_tc.c135
-rw-r--r--examples/utest/testcases/kernel/smp/smp_affinity_pri2_tc.c128
-rw-r--r--examples/utest/testcases/kernel/smp/smp_assigned_idle_cores_tc.c91
-rw-r--r--examples/utest/testcases/kernel/smp/smp_bind_affinity_tc.c114
-rw-r--r--examples/utest/testcases/kernel/smp/smp_interrupt_pri_tc.c120
-rw-r--r--examples/utest/testcases/kernel/smp/smp_spinlock_tc.c93
-rw-r--r--examples/utest/testcases/kernel/smp/smp_thread_preemption_tc.c86
11 files changed, 826 insertions, 0 deletions
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 <rtthread.h>
+#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 *)&params[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 *)&params[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 <rtthread.h>
+#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 *)&params[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 *)&params[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 <rtthread.h>
+#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, &params[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 <rtthread.h>
+#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 *)&params[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 <rtthread.h>
+#include "utest.h"
+#include <interrupt.h>
+
+/**
+ * @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 <rtthread.h>
+#include "utest.h"
+#include <interrupt.h>
+
+/**
+ * @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 <rtthread.h>
+#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);