1 | //------------------------------------------------------------------------------ |
2 | // Copyright (c) 2016 by Lukasz Janyst <lukasz@jany.st> |
3 | //------------------------------------------------------------------------------ |
4 | // This file is part of thread-bites. |
5 | // |
6 | // thread-bites is free software: you can redistribute it and/or modify |
7 | // it under the terms of the GNU General Public License as published by |
8 | // the Free Software Foundation, either version 3 of the License, or |
9 | // (at your option) any later version. |
10 | // |
11 | // thread-bites is distributed in the hope that it will be useful, |
12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | // GNU General Public License for more details. |
15 | // |
16 | // You should have received a copy of the GNU General Public License |
17 | // along with thread-bites. If not, see <http://www.gnu.org/licenses/>. |
18 | //------------------------------------------------------------------------------ |
19 | |
20 | #include <tb.h> |
21 | #include <string.h> |
22 | |
23 | #define THREADS 5 |
24 | |
25 | //------------------------------------------------------------------------------ |
26 | // Policy to string |
27 | //------------------------------------------------------------------------------ |
28 | const char *strpolicy(int policy) |
29 | { |
30 | switch(policy) |
31 | { |
32 | case SCHED_NORMAL: return "SCHED_NORMAL" ; |
33 | case SCHED_FIFO: return "SCHED_FIFO" ; |
34 | case SCHED_RR: return "SCHED_RR" ; |
35 | default: return "UNKNOWN" ; |
36 | } |
37 | } |
38 | |
39 | //------------------------------------------------------------------------------ |
40 | // Print policy |
41 | //------------------------------------------------------------------------------ |
42 | void print_sched() |
43 | { |
44 | tbthread_t self = tbthread_self(); |
45 | int policy, priority; |
46 | tbthread_getschedparam(self, &policy, &priority); |
47 | tbprint("[thread 0x%llx] Policy: %s, priority: %d\n" , self, strpolicy(policy), |
48 | priority); |
49 | } |
50 | |
51 | void print_sched_n(int n) |
52 | { |
53 | for(int i = 0; i < n; ++i) { |
54 | print_sched(); |
55 | tbsleep(1); |
56 | } |
57 | } |
58 | |
59 | //------------------------------------------------------------------------------ |
60 | // Thread function - PRIO PROTECT |
61 | //------------------------------------------------------------------------------ |
62 | struct tharg { |
63 | int num; |
64 | int before; |
65 | int inside; |
66 | int after; |
67 | tbthread_mutex_t *m[3]; |
68 | }; |
69 | void *thread_func_protect(void *arg) |
70 | { |
71 | tbthread_t self = tbthread_self(); |
72 | struct tharg *a = arg; |
73 | int priority; |
74 | tbprint("[thread 0x%llx] Starting\n" , self); |
75 | print_sched(); |
76 | for(int i = 0; i < 3; ++i) { |
77 | tbthread_mutex_lock(a->m[i]); |
78 | tbthread_mutex_getprioceiling(a->m[i], &priority); |
79 | tbprint("[thread 0x%llx] Mutex #%d (priority %d) locked\n" , self, i, |
80 | priority); |
81 | print_sched(); |
82 | } |
83 | tbsleep(1); |
84 | for(int i = 2; i >= 0; --i) { |
85 | tbthread_mutex_unlock(a->m[i]); |
86 | tbprint("[thread 0x%llx] Mutex #%d unlocked\n" , self, i); |
87 | print_sched(); |
88 | } |
89 | |
90 | tbprint("[thread 0x%llx] Done\n" , self); |
91 | print_sched(); |
92 | return 0; |
93 | } |
94 | |
95 | //------------------------------------------------------------------------------ |
96 | // Thread function - PRIO INHERIT |
97 | //------------------------------------------------------------------------------ |
98 | void *thread_func_inherit(void *arg) |
99 | { |
100 | tbthread_t self = tbthread_self(); |
101 | struct tharg *a = arg; |
102 | tbprint("[thread 0x%llx] Starting #%d\n" , self, a->num); |
103 | print_sched_n(a->before); |
104 | tbthread_mutex_lock(a->m[0]); |
105 | tbprint("[thread 0x%llx] Mutex locked\n" , self); |
106 | print_sched_n(a->inside); |
107 | tbthread_mutex_unlock(a->m[0]); |
108 | tbprint("[thread 0x%llx] Mutex unlocked\n" , self); |
109 | print_sched_n(a->after); |
110 | tbprint("[thread 0x%llx] Done\n" , self); |
111 | return 0; |
112 | } |
113 | |
114 | void *thread_func_inherit_0(void *arg) |
115 | { |
116 | tbthread_t self = tbthread_self(); |
117 | struct tharg *a = arg; |
118 | tbprint("[thread 0x%llx] Starting #0\n" , self); |
119 | print_sched_n(1); |
120 | |
121 | tbthread_mutex_lock(a->m[0]); |
122 | tbprint("[thread 0x%llx] Mutex 0 locked\n" , self); |
123 | print_sched_n(1); |
124 | |
125 | tbthread_mutex_lock(a->m[1]); |
126 | tbprint("[thread 0x%llx] Mutex 1 locked\n" , self); |
127 | print_sched_n(4); |
128 | |
129 | tbthread_mutex_lock(a->m[2]); |
130 | tbprint("[thread 0x%llx] Mutex 2 locked\n" , self); |
131 | print_sched_n(1); |
132 | |
133 | tbthread_mutex_unlock(a->m[2]); |
134 | tbprint("[thread 0x%llx] Mutex 2 unlocked\n" , self); |
135 | print_sched_n(1); |
136 | |
137 | tbthread_mutex_unlock(a->m[1]); |
138 | tbprint("[thread 0x%llx] Mutex 1 unlocked\n" , self); |
139 | print_sched_n(1); |
140 | |
141 | tbthread_mutex_unlock(a->m[0]); |
142 | tbprint("[thread 0x%llx] Mutex 0 unlocked\n" , self); |
143 | print_sched_n(1); |
144 | |
145 | tbprint("[thread 0x%llx] Done\n" , self); |
146 | return 0; |
147 | } |
148 | |
149 | //------------------------------------------------------------------------------ |
150 | // Run the threads |
151 | //------------------------------------------------------------------------------ |
152 | int run(tbthread_attr_t attr[THREADS], struct tharg arg[THREADS], |
153 | void *(*func[THREADS])(void *)) |
154 | { |
155 | tbthread_t thread[THREADS]; |
156 | int st = 0; |
157 | for(int i = 0; i < THREADS; ++i) { |
158 | st = tbthread_create(&thread[i], &attr[i], func[i], &arg[i]); |
159 | if(st != 0) { |
160 | tbprint("Failed to spawn thread %d: %s\n" , i, tbstrerror(-st)); |
161 | return st; |
162 | } |
163 | } |
164 | |
165 | tbprint("[thread main] Threads spawned successfully\n" ); |
166 | |
167 | for(int i = 0; i < THREADS; ++i) { |
168 | st = tbthread_join(thread[i], 0); |
169 | if(st != 0) { |
170 | tbprint("Failed to join thread %d: %s\n" , i, tbstrerror(-st)); |
171 | return st; |
172 | } |
173 | } |
174 | |
175 | tbprint("[thread main] Threads joined\n" ); |
176 | return 0; |
177 | } |
178 | //------------------------------------------------------------------------------ |
179 | // Start the show |
180 | //------------------------------------------------------------------------------ |
181 | int main(int argc, char **argv) |
182 | { |
183 | tbthread_init(); |
184 | tbthread_attr_t attr[THREADS]; |
185 | struct tharg arg[THREADS]; |
186 | int st = 0; |
187 | |
188 | //---------------------------------------------------------------------------- |
189 | // Warn about not being root |
190 | //---------------------------------------------------------------------------- |
191 | if(SYSCALL0(__NR_getuid) != 0) |
192 | tbprint("[!!!] You should run this test as root\n" ); |
193 | |
194 | //---------------------------------------------------------------------------- |
195 | // PRIO PROTECT |
196 | //---------------------------------------------------------------------------- |
197 | for(int i = 0; i < THREADS; ++i) |
198 | tbthread_attr_init(&attr[i]); |
199 | memset(arg, 0, THREADS*sizeof(struct tharg)); |
200 | |
201 | tbthread_mutex_t m_prot[THREADS+2]; |
202 | tbthread_mutexattr_t m_prot_attr[THREADS+2]; |
203 | uint32_t seed = tbtime(); |
204 | for(int i = 0; i < THREADS+2; ++i) { |
205 | tbthread_mutexattr_init(&m_prot_attr[i]); |
206 | tbthread_mutexattr_setprotocol(&m_prot_attr[i], TBTHREAD_PRIO_PROTECT); |
207 | tbthread_mutexattr_setprioceiling(&m_prot_attr[i], 1+(tbrandom(&seed)%99)); |
208 | tbthread_mutex_init(&m_prot[i], &m_prot_attr[i]); |
209 | } |
210 | |
211 | for(int i = 0; i < THREADS; ++i) |
212 | for(int j = i; j < i+3; ++j) |
213 | arg[i].m[j-i] = &m_prot[j]; |
214 | |
215 | void *(*m_prot_func[THREADS])(void *); |
216 | for(int i = 0; i < THREADS; ++i) |
217 | m_prot_func[i] = thread_func_protect; |
218 | |
219 | tbprint("Testing PRIO_PROTECT mutexes\n" ); |
220 | if((st = run(attr, arg, m_prot_func))) |
221 | goto exit; |
222 | tbprint("---\n" ); |
223 | |
224 | //---------------------------------------------------------------------------- |
225 | // PRIO INHERIT |
226 | //---------------------------------------------------------------------------- |
227 | memset(arg, 0, THREADS*sizeof(struct tharg)); |
228 | for(int i = 0; i < THREADS; ++i) { |
229 | tbthread_attr_init(&attr[i]); |
230 | tbthread_attr_setinheritsched(&attr[i], TBTHREAD_EXPLICIT_SCHED); |
231 | arg[i].num = i; |
232 | } |
233 | tbthread_attr_setschedpolicy(&attr[2], SCHED_FIFO); |
234 | tbthread_attr_setschedpolicy(&attr[3], SCHED_RR); |
235 | tbthread_attr_setschedpolicy(&attr[4], SCHED_RR); |
236 | tbthread_attr_setschedpriority(&attr[2], 5); |
237 | tbthread_attr_setschedpriority(&attr[3], 6); |
238 | tbthread_attr_setschedpriority(&attr[4], 7); |
239 | |
240 | tbthread_mutex_t m_inh[3]; |
241 | tbthread_mutexattr_t m_inh_attr[3]; |
242 | for(int i = 0; i < 3; ++i) { |
243 | tbthread_mutexattr_init(&m_inh_attr[i]); |
244 | tbthread_mutexattr_setprotocol(&m_inh_attr[i], TBTHREAD_PRIO_INHERIT); |
245 | tbthread_mutex_init(&m_inh[i], &m_inh_attr[i]); |
246 | } |
247 | |
248 | void *(*m_inh_func[THREADS])(void *); |
249 | m_inh_func[0] = thread_func_inherit_0; |
250 | for(int i = 1; i < THREADS; ++i) |
251 | m_inh_func[i] = thread_func_inherit; |
252 | |
253 | arg[0].m[0] = &m_inh[0]; |
254 | arg[0].m[1] = &m_inh[1]; |
255 | arg[0].m[2] = &m_inh[2]; |
256 | |
257 | arg[1].m[0] = &m_inh[2]; arg[1].before = 1; arg[1].inside = 10; arg[1].after = 1; |
258 | arg[2].m[0] = &m_inh[0]; arg[2].before = 4; arg[2].inside = 2; arg[2].after = 1; |
259 | arg[3].m[0] = &m_inh[1]; arg[3].before = 4; arg[3].inside = 2; arg[3].after = 1; |
260 | arg[4].m[0] = &m_inh[1]; arg[4].before = 4; arg[4].inside = 2; arg[4].after = 1; |
261 | |
262 | tbprint("Testing PRIO_INHERIT mutexes\n" ); |
263 | if((st = run(attr, arg, m_inh_func))) |
264 | goto exit; |
265 | tbprint("---\n" ); |
266 | |
267 | |
268 | exit: |
269 | tbthread_finit(); |
270 | return st; |
271 | }; |
272 | |