t_mutex.c revision 1.11 1 /* $NetBSD: t_mutex.c,v 1.11 2016/10/30 16:17:16 kamil Exp $ */
2
3 /*
4 * Copyright (c) 2008 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 /* Please sync code from this test with t_timedmutex.c */
30
31 #include <sys/cdefs.h>
32 __COPYRIGHT("@(#) Copyright (c) 2008\
33 The NetBSD Foundation, inc. All rights reserved.");
34 __RCSID("$NetBSD: t_mutex.c,v 1.11 2016/10/30 16:17:16 kamil Exp $");
35
36 #include <pthread.h>
37 #include <stdio.h>
38 #include <string.h>
39 #include <errno.h>
40 #include <unistd.h>
41 #include <sys/sched.h>
42 #include <sys/param.h>
43
44 #include <atf-c.h>
45
46 #include "h_common.h"
47
48 static pthread_mutex_t mutex;
49 static pthread_mutex_t static_mutex = PTHREAD_MUTEX_INITIALIZER;
50 static int global_x;
51
52 static void *
53 mutex1_threadfunc(void *arg)
54 {
55 int *param;
56
57 printf("2: Second thread.\n");
58
59 param = arg;
60 printf("2: Locking mutex\n");
61 pthread_mutex_lock(&mutex);
62 printf("2: Got mutex. *param = %d\n", *param);
63 ATF_REQUIRE_EQ(*param, 20);
64 (*param)++;
65
66 pthread_mutex_unlock(&mutex);
67
68 return param;
69 }
70
71 ATF_TC(mutex1);
72 ATF_TC_HEAD(mutex1, tc)
73 {
74 atf_tc_set_md_var(tc, "descr", "Checks mutexes");
75 }
76 ATF_TC_BODY(mutex1, tc)
77 {
78 int x;
79 pthread_t new;
80 void *joinval;
81
82 printf("1: Mutex-test 1\n");
83
84 PTHREAD_REQUIRE(pthread_mutex_init(&mutex, NULL));
85 x = 1;
86 PTHREAD_REQUIRE(pthread_mutex_lock(&mutex));
87 PTHREAD_REQUIRE(pthread_create(&new, NULL, mutex1_threadfunc, &x));
88 printf("1: Before changing the value.\n");
89 sleep(2);
90 x = 20;
91 printf("1: Before releasing the mutex.\n");
92 sleep(2);
93 PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
94 printf("1: After releasing the mutex.\n");
95 PTHREAD_REQUIRE(pthread_join(new, &joinval));
96
97 PTHREAD_REQUIRE(pthread_mutex_lock(&mutex));
98 printf("1: Thread joined. X was %d. Return value (int) was %d\n",
99 x, *(int *)joinval);
100 ATF_REQUIRE_EQ(x, 21);
101 ATF_REQUIRE_EQ(*(int *)joinval, 21);
102 PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
103 }
104
105 static void *
106 mutex2_threadfunc(void *arg)
107 {
108 long count = *(int *)arg;
109
110 printf("2: Second thread (%p). Count is %ld\n", pthread_self(), count);
111
112 while (count--) {
113 PTHREAD_REQUIRE(pthread_mutex_lock(&mutex));
114 global_x++;
115 PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
116 }
117
118 return (void *)count;
119 }
120
121 ATF_TC(mutex2);
122 ATF_TC_HEAD(mutex2, tc)
123 {
124 atf_tc_set_md_var(tc, "descr", "Checks mutexes");
125 #if defined(__powerpc__)
126 atf_tc_set_md_var(tc, "timeout", "40");
127 #endif
128 }
129 ATF_TC_BODY(mutex2, tc)
130 {
131 int count, count2;
132 pthread_t new;
133 void *joinval;
134
135 printf("1: Mutex-test 2\n");
136
137 #if defined(__powerpc__)
138 atf_tc_expect_timeout("PR port-powerpc/44387");
139 #endif
140
141 PTHREAD_REQUIRE(pthread_mutex_init(&mutex, NULL));
142
143 global_x = 0;
144 count = count2 = 10000000;
145
146 PTHREAD_REQUIRE(pthread_mutex_lock(&mutex));
147 PTHREAD_REQUIRE(pthread_create(&new, NULL, mutex2_threadfunc, &count2));
148
149 printf("1: Thread %p\n", pthread_self());
150
151 PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
152
153 while (count--) {
154 PTHREAD_REQUIRE(pthread_mutex_lock(&mutex));
155 global_x++;
156 PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
157 }
158
159 PTHREAD_REQUIRE(pthread_join(new, &joinval));
160
161 PTHREAD_REQUIRE(pthread_mutex_lock(&mutex));
162 printf("1: Thread joined. X was %d. Return value (long) was %ld\n",
163 global_x, (long)joinval);
164 ATF_REQUIRE_EQ(global_x, 20000000);
165
166 #if defined(__powerpc__)
167 /* XXX force a timeout in ppc case since an un-triggered race
168 otherwise looks like a "failure" */
169 /* We sleep for longer than the timeout to make ATF not
170 complain about unexpected success */
171 sleep(41);
172 #endif
173 }
174
175 static void *
176 mutex3_threadfunc(void *arg)
177 {
178 long count = *(int *)arg;
179
180 printf("2: Second thread (%p). Count is %ld\n", pthread_self(), count);
181
182 while (count--) {
183 PTHREAD_REQUIRE(pthread_mutex_lock(&static_mutex));
184 global_x++;
185 PTHREAD_REQUIRE(pthread_mutex_unlock(&static_mutex));
186 }
187
188 return (void *)count;
189 }
190
191 ATF_TC(mutex3);
192 ATF_TC_HEAD(mutex3, tc)
193 {
194 atf_tc_set_md_var(tc, "descr", "Checks mutexes using a static "
195 "initializer");
196 #if defined(__powerpc__)
197 atf_tc_set_md_var(tc, "timeout", "40");
198 #endif
199 }
200 ATF_TC_BODY(mutex3, tc)
201 {
202 int count, count2;
203 pthread_t new;
204 void *joinval;
205
206 printf("1: Mutex-test 3\n");
207
208 #if defined(__powerpc__)
209 atf_tc_expect_timeout("PR port-powerpc/44387");
210 #endif
211
212 global_x = 0;
213 count = count2 = 10000000;
214
215 PTHREAD_REQUIRE(pthread_mutex_lock(&static_mutex));
216 PTHREAD_REQUIRE(pthread_create(&new, NULL, mutex3_threadfunc, &count2));
217
218 printf("1: Thread %p\n", pthread_self());
219
220 PTHREAD_REQUIRE(pthread_mutex_unlock(&static_mutex));
221
222 while (count--) {
223 PTHREAD_REQUIRE(pthread_mutex_lock(&static_mutex));
224 global_x++;
225 PTHREAD_REQUIRE(pthread_mutex_unlock(&static_mutex));
226 }
227
228 PTHREAD_REQUIRE(pthread_join(new, &joinval));
229
230 PTHREAD_REQUIRE(pthread_mutex_lock(&static_mutex));
231 printf("1: Thread joined. X was %d. Return value (long) was %ld\n",
232 global_x, (long)joinval);
233 ATF_REQUIRE_EQ(global_x, 20000000);
234
235 #if defined(__powerpc__)
236 /* XXX force a timeout in ppc case since an un-triggered race
237 otherwise looks like a "failure" */
238 /* We sleep for longer than the timeout to make ATF not
239 complain about unexpected success */
240 sleep(41);
241 #endif
242 }
243
244 static void *
245 mutex4_threadfunc(void *arg)
246 {
247 int *param;
248
249 printf("2: Second thread.\n");
250
251 param = arg;
252 printf("2: Locking mutex\n");
253 PTHREAD_REQUIRE(pthread_mutex_lock(&mutex));
254 printf("2: Got mutex. *param = %d\n", *param);
255 (*param)++;
256
257 PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
258
259 return param;
260 }
261
262 ATF_TC(mutex4);
263 ATF_TC_HEAD(mutex4, tc)
264 {
265 atf_tc_set_md_var(tc, "descr", "Checks mutexes");
266 }
267 ATF_TC_BODY(mutex4, tc)
268 {
269 int x;
270 pthread_t new;
271 pthread_mutexattr_t mattr;
272 void *joinval;
273
274 printf("1: Mutex-test 4\n");
275
276 PTHREAD_REQUIRE(pthread_mutexattr_init(&mattr));
277 PTHREAD_REQUIRE(pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_RECURSIVE));
278
279 PTHREAD_REQUIRE(pthread_mutex_init(&mutex, &mattr));
280
281 PTHREAD_REQUIRE(pthread_mutexattr_destroy(&mattr));
282
283 x = 1;
284 PTHREAD_REQUIRE(pthread_mutex_lock(&mutex));
285 PTHREAD_REQUIRE(pthread_create(&new, NULL, mutex4_threadfunc, &x));
286
287 printf("1: Before recursively acquiring the mutex.\n");
288 PTHREAD_REQUIRE(pthread_mutex_lock(&mutex));
289
290 printf("1: Before releasing the mutex once.\n");
291 sleep(2);
292 PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
293 printf("1: After releasing the mutex once.\n");
294
295 x = 20;
296
297 printf("1: Before releasing the mutex twice.\n");
298 sleep(2);
299 PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
300 printf("1: After releasing the mutex twice.\n");
301
302 PTHREAD_REQUIRE(pthread_join(new, &joinval));
303
304 PTHREAD_REQUIRE(pthread_mutex_lock(&mutex));
305 printf("1: Thread joined. X was %d. Return value (int) was %d\n",
306 x, *(int *)joinval);
307 ATF_REQUIRE_EQ(x, 21);
308 ATF_REQUIRE_EQ(*(int *)joinval, 21);
309 PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
310 }
311
312 static pthread_mutexattr_t attr5;
313 static pthread_mutex_t mutex5;
314 static int min_fifo_prio, max_fifo_prio;
315
316 static void *
317 child_func(void* arg)
318 {
319 int res;
320
321 printf("child is waiting\n");
322 res = _sched_protect(-2);
323 ATF_REQUIRE_EQ_MSG(res, -1, "sched_protect returned %d", res);
324 ATF_REQUIRE_EQ(errno, ENOENT);
325 PTHREAD_REQUIRE(pthread_mutex_lock(&mutex5));
326 printf("child is owning resource\n");
327 res = _sched_protect(-2);
328 ATF_REQUIRE_EQ(res, max_fifo_prio);
329 PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex5));
330 printf("child is done\n");
331
332 return 0;
333 }
334
335 ATF_TC(mutex5);
336 ATF_TC_HEAD(mutex5, tc)
337 {
338 atf_tc_set_md_var(tc, "descr", "Checks mutexes for priority setting");
339 atf_tc_set_md_var(tc, "require.user", "root");
340 }
341
342 ATF_TC_BODY(mutex5, tc)
343 {
344 int res;
345 struct sched_param param;
346 pthread_t child;
347
348 min_fifo_prio = sched_get_priority_min(SCHED_FIFO);
349 max_fifo_prio = sched_get_priority_max(SCHED_FIFO);
350 printf("min prio for FIFO = %d\n", min_fifo_prio);
351 param.sched_priority = min_fifo_prio;
352
353 /* = 0 OTHER, 1 FIFO, 2 RR, -1 NONE */
354 res = sched_setscheduler(getpid(), SCHED_FIFO, ¶m);
355 printf("previous policy used = %d\n", res);
356
357 res = sched_getscheduler(getpid());
358 ATF_REQUIRE_EQ_MSG(res, SCHED_FIFO, "sched %d != FIFO %d", res,
359 SCHED_FIFO);
360
361 PTHREAD_REQUIRE(pthread_mutexattr_init(&attr5));
362 PTHREAD_REQUIRE(pthread_mutexattr_setprotocol(&attr5,
363 PTHREAD_PRIO_PROTECT));
364 PTHREAD_REQUIRE(pthread_mutexattr_setprioceiling(&attr5,
365 max_fifo_prio));
366
367 PTHREAD_REQUIRE(pthread_mutex_init(&mutex5, &attr5));
368 PTHREAD_REQUIRE(pthread_mutex_lock(&mutex5));
369 printf("enter critical section for main\n");
370 PTHREAD_REQUIRE(pthread_create(&child, NULL, child_func, NULL));
371 printf("main starts to sleep\n");
372 sleep(10);
373 printf("main completes\n");
374 PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex5));
375 PTHREAD_REQUIRE(pthread_join(child, NULL));
376 }
377
378 static pthread_mutex_t mutex6;
379 static int start = 0;
380 static uintmax_t high_cnt = 0, low_cnt = 0, MAX_LOOP = 100000000;
381
382 static void *
383 high_prio(void* arg)
384 {
385 struct sched_param param;
386 int policy;
387 param.sched_priority = min_fifo_prio + 10;
388 pthread_t childid = pthread_self();
389
390 PTHREAD_REQUIRE(pthread_setschedparam(childid, 1, ¶m));
391 PTHREAD_REQUIRE(pthread_getschedparam(childid, &policy, ¶m));
392 printf("high protect = %d, prio = %d\n",
393 _sched_protect(-2), param.sched_priority);
394 ATF_REQUIRE_EQ(policy, 1);
395 printf("high prio = %d\n", param.sched_priority);
396 sleep(1);
397 long tmp = 0;
398 for (int i = 0; i < 20; i++) {
399 while (high_cnt < MAX_LOOP) {
400 tmp += (123456789 % 1234) * (987654321 % 54321);
401 high_cnt += 1;
402 }
403 high_cnt = 0;
404 sleep(1);
405 }
406 PTHREAD_REQUIRE(pthread_mutex_lock(&mutex6));
407 if (start == 0) start = 2;
408 PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex6));
409
410 return 0;
411 }
412
413 static void *
414 low_prio(void* arg)
415 {
416 struct sched_param param;
417 int policy;
418 param.sched_priority = min_fifo_prio;
419 pthread_t childid = pthread_self();
420 int res = _sched_protect(max_fifo_prio);
421 ATF_REQUIRE_EQ(res, 0);
422 PTHREAD_REQUIRE(pthread_setschedparam(childid, 1, ¶m));
423 PTHREAD_REQUIRE(pthread_getschedparam(childid, &policy, ¶m));
424 printf("low protect = %d, prio = %d\n", _sched_protect(-2),
425 param.sched_priority);
426 ATF_REQUIRE_EQ(policy, 1);
427 printf("low prio = %d\n", param.sched_priority);
428 sleep(1);
429 long tmp = 0;
430 for (int i = 0; i < 20; i++) {
431 while (low_cnt < MAX_LOOP) {
432 tmp += (123456789 % 1234) * (987654321 % 54321);
433 low_cnt += 1;
434 }
435 low_cnt = 0;
436 sleep(1);
437 }
438 PTHREAD_REQUIRE(pthread_mutex_lock(&mutex6));
439 if (start == 0)
440 start = 1;
441 PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex6));
442
443 return 0;
444 }
445
446 ATF_TC(mutex6);
447 ATF_TC_HEAD(mutex6, tc)
448 {
449 atf_tc_set_md_var(tc, "descr",
450 "Checks scheduling for priority ceiling");
451 atf_tc_set_md_var(tc, "require.user", "root");
452 }
453
454 /*
455 * 1. main thread sets itself to be a realtime task and launched two tasks,
456 * one has higher priority and the other has lower priority.
457 * 2. each child thread(low and high priority thread) sets its scheduler and
458 * priority.
459 * 3. each child thread did several rounds of computation, after each round it
460 * sleep 1 second.
461 * 4. the child thread with low priority will call _sched_protect to increase
462 * its protect priority.
463 * 5. We verify the thread with low priority runs first.
464 *
465 * Why does it work? From the main thread, we launched the high
466 * priority thread first. This gives this thread the benefit of
467 * starting first. The low priority thread did not call _sched_protect(2).
468 * The high priority thread should finish the task first. After each
469 * round of computation, we call sleep, to put the task into the
470 * sleep queue, and wake up again after the timer expires. This
471 * gives the scheduler the chance to decide which task to run. So,
472 * the thread with real high priority will always block the thread
473 * with real low priority.
474 *
475 */
476 ATF_TC_BODY(mutex6, tc)
477 {
478 struct sched_param param;
479 int res;
480 pthread_t high, low;
481
482 min_fifo_prio = sched_get_priority_min(SCHED_FIFO);
483 max_fifo_prio = sched_get_priority_max(SCHED_FIFO);
484 PTHREAD_REQUIRE(pthread_mutex_init(&mutex, NULL));
485 printf("min_fifo_prio = %d, max_fifo_info = %d\n", min_fifo_prio,
486 max_fifo_prio);
487
488 param.sched_priority = min_fifo_prio;
489 res = sched_setscheduler(getpid(), SCHED_FIFO, ¶m);
490 printf("previous policy used = %d\n", res);
491
492 res = sched_getscheduler(getpid());
493 ATF_REQUIRE_EQ(res, 1);
494 PTHREAD_REQUIRE(pthread_create(&high, NULL, high_prio, NULL));
495 PTHREAD_REQUIRE(pthread_create(&low, NULL, low_prio, NULL));
496 sleep(5);
497 PTHREAD_REQUIRE(pthread_join(low, NULL));
498 PTHREAD_REQUIRE(pthread_join(high, NULL));
499
500 ATF_REQUIRE_EQ(start, 1);
501 }
502
503 ATF_TC(mutexattr1);
504 ATF_TC_HEAD(mutexattr1, tc)
505 {
506 atf_tc_set_md_var(tc, "descr", "Checks mutexattr");
507 }
508
509 ATF_TC_BODY(mutexattr1, tc)
510 {
511 pthread_mutexattr_t mattr;
512 int protocol, target;
513
514 PTHREAD_REQUIRE(pthread_mutexattr_init(&mattr));
515
516 target = PTHREAD_PRIO_NONE;
517 PTHREAD_REQUIRE(pthread_mutexattr_setprotocol(&mattr, target));
518 PTHREAD_REQUIRE(pthread_mutexattr_getprotocol(&mattr, &protocol));
519 ATF_REQUIRE_EQ(protocol, target);
520
521 /*
522 target = PTHREAD_PRIO_INHERIT;
523 PTHREAD_REQUIRE(pthread_mutexattr_setprotocol(&mattr, target));
524 PTHREAD_REQUIRE(pthread_mutexattr_getprotocol(&mattr, &protocol));
525 ATF_REQUIRE_EQ(protocol, target);
526 */
527
528 target = PTHREAD_PRIO_PROTECT;
529 PTHREAD_REQUIRE(pthread_mutexattr_setprotocol(&mattr, target));
530 PTHREAD_REQUIRE(pthread_mutexattr_getprotocol(&mattr, &protocol));
531 ATF_REQUIRE_EQ(protocol, target);
532 }
533
534 ATF_TC(mutexattr2);
535 ATF_TC_HEAD(mutexattr2, tc)
536 {
537 atf_tc_set_md_var(tc, "descr", "Checks mutexattr");
538 }
539
540 ATF_TC_BODY(mutexattr2, tc)
541 {
542 pthread_mutexattr_t mattr;
543
544 PTHREAD_REQUIRE(pthread_mutexattr_init(&mattr));
545 int max_prio = sched_get_priority_max(SCHED_FIFO);
546 int min_prio = sched_get_priority_min(SCHED_FIFO);
547 for (int i = min_prio; i <= max_prio; i++) {
548 int prioceiling;
549 PTHREAD_REQUIRE(pthread_mutexattr_setprioceiling(&mattr, i));
550 PTHREAD_REQUIRE(pthread_mutexattr_getprioceiling(&mattr,
551 &prioceiling));
552 ATF_REQUIRE_EQ(i, prioceiling);
553 }
554 }
555
556 ATF_TP_ADD_TCS(tp)
557 {
558 ATF_TP_ADD_TC(tp, mutex1);
559 ATF_TP_ADD_TC(tp, mutex2);
560 ATF_TP_ADD_TC(tp, mutex3);
561 ATF_TP_ADD_TC(tp, mutex4);
562 ATF_TP_ADD_TC(tp, mutex5);
563 ATF_TP_ADD_TC(tp, mutex6);
564 ATF_TP_ADD_TC(tp, mutexattr1);
565 ATF_TP_ADD_TC(tp, mutexattr2);
566
567 return atf_no_error();
568 }
569