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//------------------------------------------------------------------------------
28const 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//------------------------------------------------------------------------------
42void 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
51void 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//------------------------------------------------------------------------------
62struct tharg {
63 int num;
64 int before;
65 int inside;
66 int after;
67 tbthread_mutex_t *m[3];
68};
69void *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//------------------------------------------------------------------------------
98void *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
114void *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//------------------------------------------------------------------------------
152int 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//------------------------------------------------------------------------------
181int 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
268exit:
269 tbthread_finit();
270 return st;
271};
272