summaryrefslogtreecommitdiff
path: root/src/utest/smp/smp_affinity_pri1_tc.c
blob: 5f3c55804c12f4ed8543c470d300e16d5072c325 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
/*
 * 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!
 *
 * Test Case Name: [smp_affinity_pri1]
 *
 * Test Objectives:
 * - Verify that threads with low-priority bound cores do not preempt high-priority threads.
 *
 * Test Scenarios:
 * - RT_CPUS_NR threads (T0~T(RT_CPUS_NR-1)) are created, with each thread bound to its respective core. Among them, the
 * - thread on core 0 has the lowest priority (LOW_PRIORITY), while the other threads have the highest priority (THREAD_PRIORITY).
 * - All threads share a common entry function "thread_entry". In thread_entry, only the threads running on non-core-0 cores
 * - execute an infinite loop (i.e., they do not release core ownership). After running for a certain period of time, the
 * - thread on core 0 executes list_thread() and creates a medium-priority (THIGH_PRIORITY) thread Tn, whose entry function
 * - is thread_temp_entry. Tn is automatically destroyed after executing list_thread().
 *
 * Verification Metrics:
 * - Output message: [I/utest] [ PASSED ] [ result ] testcase (core.smp_affinity_pri1)
 *
 * Dependencies:
 * - Enable RT_USING_SMP, set RT_THREAD_PRIORITY_MAX = 256.
 *
 * Expected Results:
 * - You will see the information printed by list_thread() twice on the terminal. For the first time, you will see that T0 is
 * - running on core 0, and T1~T(RT_CPUS_NR-1) are running on their respective cores. For the second time, you will see that Tn
 * - is running on core 0, while T0 is in the ready state. Subsequently, the PASS message will be printed.
 */

/* Number of thread runs */
static int run_num = 10;
#define THREAD_STACK_SIZE UTEST_THR_STACK_SIZE
#define THREAD_PRIORITY   2
#define LOW_PRIORITY  30
#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 *)(rt_ubase_t)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, "core.smp_affinity_pri1", utest_tc_init, utest_tc_cleanup, 10);