1 /*
2  * Copyright (c) 2006-2024, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2024-08-10     RV           the first version
9  */
10 
11 #include <rtthread.h>
12 #include "utest.h"
13 
14 /**
15  * @brief   Threads are automatically balanced across cores.
16  *
17  * @note    Create RT_CPUS_NR threads, thread 0 is not bound to core 0, higher priority, the priority of the other
18  *          threads for the system's highest and the thread entry function does not let out the CPU control, run the
19  *          specified number of times after the creation of thread 0 in thread 0, a low-priority bound to the core 0,
20  *          the thread will not preempt the core 0 is running on threads
21  */
22 
23 /* Number of thread runs */
24 static int run_num = 10;
25 #define THREAD_STACK_SIZE UTEST_THR_STACK_SIZE
26 #define THREAD_PRIORITY   2
27 #define LOW_PRIORITY 50
28 #define THIGH_PRIORITY  10
29 static rt_thread_t        threads[RT_CPUS_NR];
30 static rt_thread_t        temp_thread;
31 static struct rt_spinlock lock;
32 static int                thread_inc = 0;
33 static int                run_flag = 0;
34 static int                num        = 0;
35 
thread_temp_entry(void * parameter)36 static void thread_temp_entry(void *parameter)
37 {
38     run_flag = 1;
39     rt_thread_delete(temp_thread);
40 }
41 
thread_entry(void * parameter)42 static void thread_entry(void *parameter)
43 {
44     int id   = 0;
45     int para = *(int *)parameter;
46     while (1)
47     {
48         thread_inc++;
49         id = rt_hw_cpu_id();
50         if (para == 0)
51         {
52             if (thread_inc == run_num)
53             {
54                 uassert_int_equal(id, 0);
55                 temp_thread = rt_thread_create("Tn", thread_temp_entry, RT_NULL, THREAD_STACK_SIZE, LOW_PRIORITY, 20);
56 
57                 if (temp_thread != RT_NULL)
58                 {
59                     rt_thread_control(temp_thread, RT_THREAD_CTRL_BIND_CPU, (void *)0);
60                     rt_thread_startup(temp_thread);
61                     uassert_int_not_equal(run_flag, 1);
62                 }
63             }
64             rt_thread_delay(5);
65         }
66         else
67         {
68             uassert_int_not_equal(id, 0);
69             while (1);
70         }
71     }
72 }
73 
smp_affinity_pri2_tc(void)74 static void smp_affinity_pri2_tc(void)
75 {
76     static int params[RT_CPUS_NR] = {0};
77     char thread_name[8];
78     int  i;
79 
80     for (i = 0; i < RT_CPUS_NR; i++)
81     {
82         params[i] = i;
83     }
84 
85     threads[0] = rt_thread_create("T0", thread_entry, (int *)&params[0], THREAD_STACK_SIZE, THIGH_PRIORITY, 20);
86 
87     if (threads[0] != RT_NULL)
88     {
89         uassert_true(1);
90         rt_thread_startup(threads[0]);
91     }
92 
93     /* Create high-priority unbound threads with thread functions that don't let out CPU control */
94     for (i = 1; i < RT_CPUS_NR; i++)
95     {
96         rt_snprintf(thread_name, sizeof(thread_name), "T%d", i);
97         threads[i] = rt_thread_create(thread_name, thread_entry, (int *)&params[i], THREAD_STACK_SIZE, THREAD_PRIORITY, 20);
98 
99         if (threads[i] != RT_NULL)
100         {
101             uassert_true(1);
102             rt_thread_control(threads[i], RT_THREAD_CTRL_BIND_CPU, (void *)i);
103             rt_thread_startup(threads[i]);
104         }
105     }
106     rt_thread_delay(50);
107 }
108 
utest_tc_init(void)109 static rt_err_t utest_tc_init(void)
110 {
111     rt_spin_lock_init(&lock);
112     return RT_EOK;
113 }
114 
utest_tc_cleanup(void)115 static rt_err_t utest_tc_cleanup(void)
116 {
117     for (num = 0; num < RT_CPUS_NR; num++)
118     {
119         rt_thread_delete(threads[num]);
120     }
121     return RT_EOK;
122 }
123 
testcase(void)124 static void testcase(void)
125 {
126     UTEST_UNIT_RUN(smp_affinity_pri2_tc);
127 }
128 UTEST_TC_EXPORT(testcase, "testcases.smp.affinity_pri2_tc", utest_tc_init, utest_tc_cleanup, 10);
129