Procházet zdrojové kódy

[utest] add smp testcases

Yaochenger před 11 měsíci
rodič
revize
f33312abe0

+ 4 - 0
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

+ 5 - 0
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')

+ 23 - 0
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

+ 27 - 0
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')

+ 135 - 0
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);

+ 128 - 0
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);

+ 91 - 0
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);

+ 114 - 0
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);

+ 120 - 0
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);

+ 93 - 0
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);

+ 86 - 0
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);