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