1 /*
2 * Copyright (c) 2021 intel, Inc.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 #include <zephyr.h>
7 #include <ztest.h>
8 #include <sys/mutex.h>
9
10 #define HIGH_T1 0xaaa
11 #define HIGH_T2 0xbbb
12 #define LOW_PRO 0xccc
13
14 #define STACKSIZE (512 + CONFIG_TEST_EXTRA_STACKSIZE)
15
16 static K_THREAD_STACK_DEFINE(thread_low_stack, STACKSIZE);
17 static struct k_thread thread_low_data;
18 static K_THREAD_STACK_DEFINE(thread_high_stack1, STACKSIZE);
19 static struct k_thread thread_high_data1;
20 static K_THREAD_STACK_DEFINE(thread_high_stack2, STACKSIZE);
21 static struct k_thread thread_high_data2;
22 SYS_MUTEX_DEFINE(mutex);
23 static uint32_t flag[3];
24
25 /* The order of threads getting mutex is judged by index
26 * self addition.
27 */
28 static uint32_t index;
29
low_prio_wait_for_mutex(void * p1,void * p2,void * p3)30 static void low_prio_wait_for_mutex(void *p1, void *p2, void *p3)
31 {
32 struct sys_mutex *pmutex = p1;
33
34 sys_mutex_lock(pmutex, K_FOREVER);
35
36 flag[index] = LOW_PRO;
37
38 index++;
39 /* Keep mutex for a while */
40 k_sleep(K_MSEC(10));
41
42 sys_mutex_unlock(pmutex);
43 }
44
high_prio_t1_wait_for_mutex(void * p1,void * p2,void * p3)45 static void high_prio_t1_wait_for_mutex(void *p1, void *p2, void *p3)
46 {
47 struct sys_mutex *pmutex = p1;
48
49 sys_mutex_lock(pmutex, K_FOREVER);
50
51 flag[index] = HIGH_T1;
52
53 index++;
54 /* Keep mutex for a while */
55 k_sleep(K_MSEC(10));
56
57 sys_mutex_unlock(pmutex);
58 }
59
high_prio_t2_wait_for_mutex(void * p1,void * p2,void * p3)60 static void high_prio_t2_wait_for_mutex(void *p1, void *p2, void *p3)
61 {
62 struct sys_mutex *pmutex = p1;
63
64 sys_mutex_lock(pmutex, K_FOREVER);
65
66 flag[index] = HIGH_T2;
67
68 index++;
69 /* Keep mutex for a while */
70 k_sleep(K_MSEC(10));
71
72 sys_mutex_unlock(pmutex);
73 }
74
75 /**
76 * @brief Test multi-threads to take mutex.
77 *
78 * @details Define three threads, and set a higher priority for two of them,
79 * and set a lower priority for the last one. Then Add a delay between
80 * creating the two high priority threads.
81 * Test point:
82 * 1. Any number of threads may wait on a mutex locked by others
83 * simultaneously.
84 * 2. When the mutex is released, it is took by the highest priority
85 * thread that has waited longest.
86 *
87 * @ingroup kernel_mutex_tests
88 */
test_mutex_multithread_competition(void)89 void test_mutex_multithread_competition(void)
90 {
91 int old_prio = k_thread_priority_get(k_current_get());
92 int prio = 10;
93
94 sys_mutex_lock(&mutex, K_NO_WAIT);
95
96 k_thread_priority_set(k_current_get(), prio);
97
98 k_thread_create(&thread_high_data1, thread_high_stack1, STACKSIZE,
99 high_prio_t1_wait_for_mutex,
100 &mutex, NULL, NULL,
101 prio + 2, 0, K_NO_WAIT);
102
103 /* Thread thread_high_data1 wait more time than thread_high_data2 */
104 k_sleep(K_MSEC(10));
105
106 k_thread_create(&thread_low_data, thread_low_stack, STACKSIZE,
107 low_prio_wait_for_mutex,
108 &mutex, NULL, NULL,
109 prio + 4, 0, K_NO_WAIT);
110
111 k_thread_create(&thread_high_data2, thread_high_stack2, STACKSIZE,
112 high_prio_t2_wait_for_mutex,
113 &mutex, NULL, NULL,
114 prio + 2, 0, K_NO_WAIT);
115
116 /* Release mutex by current thread */
117 sys_mutex_unlock(&mutex);
118
119 /* Wait for thread exiting */
120 k_thread_join(&thread_low_data, K_FOREVER);
121 k_thread_join(&thread_high_data1, K_FOREVER);
122 k_thread_join(&thread_high_data2, K_FOREVER);
123
124 /* The mutex should be keep by high prio t1 thread */
125 zassert_true(flag[0] == HIGH_T1,
126 "The highest priority thread failed to take the mutex.");
127
128 /* The mutex should be keep by high prio t2 thread */
129 zassert_true(flag[1] == HIGH_T2,
130 "The higher priority thread failed to take the mutex.");
131
132 /* The mutex should be keep by low prio thread */
133 zassert_true(flag[2] == LOW_PRO,
134 "The low priority thread failed to take the mutex.");
135
136 /* Revert priority of the main thread */
137 k_thread_priority_set(k_current_get(), old_prio);
138 }
139