]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - contrib/netbsd-tests/lib/libpthread/t_mutex.c
MFC r305358,r305449,r305451,r306367,r306397,r309474:
[FreeBSD/stable/10.git] / contrib / netbsd-tests / lib / libpthread / t_mutex.c
1 /* $NetBSD: t_mutex.c,v 1.10 2016/07/31 13:01:29 christos 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 #include <sys/cdefs.h>
30 __COPYRIGHT("@(#) Copyright (c) 2008\
31  The NetBSD Foundation, inc. All rights reserved.");
32 __RCSID("$NetBSD: t_mutex.c,v 1.10 2016/07/31 13:01:29 christos Exp $");
33
34 #include <pthread.h>
35 #include <stdio.h>
36 #include <string.h>
37 #include <errno.h>
38 #include <unistd.h>
39 #include <sys/sched.h>
40 #include <sys/param.h>
41
42 #include <atf-c.h>
43
44 #include "h_common.h"
45
46 static pthread_mutex_t mutex;
47 static pthread_mutex_t static_mutex = PTHREAD_MUTEX_INITIALIZER;
48 static int global_x;
49
50 static void *
51 mutex1_threadfunc(void *arg)
52 {
53         int *param;
54
55         printf("2: Second thread.\n");
56
57         param = arg;
58         printf("2: Locking mutex\n");
59         pthread_mutex_lock(&mutex);
60         printf("2: Got mutex. *param = %d\n", *param);
61         ATF_REQUIRE_EQ(*param, 20);
62         (*param)++;
63
64         pthread_mutex_unlock(&mutex);
65
66         return param;
67 }
68
69 ATF_TC(mutex1);
70 ATF_TC_HEAD(mutex1, tc)
71 {
72         atf_tc_set_md_var(tc, "descr", "Checks mutexes");
73 }
74 ATF_TC_BODY(mutex1, tc)
75 {
76         int x;
77         pthread_t new;
78         void *joinval;
79
80         printf("1: Mutex-test 1\n");
81
82         PTHREAD_REQUIRE(pthread_mutex_init(&mutex, NULL));
83         x = 1;
84         PTHREAD_REQUIRE(pthread_mutex_lock(&mutex));
85         PTHREAD_REQUIRE(pthread_create(&new, NULL, mutex1_threadfunc, &x));
86         printf("1: Before changing the value.\n");
87         sleep(2);
88         x = 20;
89         printf("1: Before releasing the mutex.\n");
90         sleep(2);
91         PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
92         printf("1: After releasing the mutex.\n");
93         PTHREAD_REQUIRE(pthread_join(new, &joinval));
94
95         PTHREAD_REQUIRE(pthread_mutex_lock(&mutex));
96         printf("1: Thread joined. X was %d. Return value (int) was %d\n",
97                 x, *(int *)joinval);
98         ATF_REQUIRE_EQ(x, 21);
99         ATF_REQUIRE_EQ(*(int *)joinval, 21);
100         PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
101 }
102
103 static void *
104 mutex2_threadfunc(void *arg)
105 {
106         long count = *(int *)arg;
107
108         printf("2: Second thread (%p). Count is %ld\n", pthread_self(), count);
109
110         while (count--) {
111                 PTHREAD_REQUIRE(pthread_mutex_lock(&mutex));
112                 global_x++;
113                 PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
114         }
115
116         return (void *)count;
117 }
118
119 ATF_TC(mutex2);
120 ATF_TC_HEAD(mutex2, tc)
121 {
122         atf_tc_set_md_var(tc, "descr", "Checks mutexes");
123 #ifdef __NetBSD__
124 #if defined(__powerpc__)
125         atf_tc_set_md_var(tc, "timeout", "40");
126 #endif
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 #ifdef __NetBSD__
138 #if defined(__powerpc__)
139         atf_tc_expect_timeout("PR port-powerpc/44387");
140 #endif
141 #endif
142
143         PTHREAD_REQUIRE(pthread_mutex_init(&mutex, NULL));
144         
145         global_x = 0;
146         count = count2 = 10000000;
147
148         PTHREAD_REQUIRE(pthread_mutex_lock(&mutex));
149         PTHREAD_REQUIRE(pthread_create(&new, NULL, mutex2_threadfunc, &count2));
150
151         printf("1: Thread %p\n", pthread_self());
152
153         PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
154
155         while (count--) {
156                 PTHREAD_REQUIRE(pthread_mutex_lock(&mutex));
157                 global_x++;
158                 PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
159         }
160
161         PTHREAD_REQUIRE(pthread_join(new, &joinval));
162
163         PTHREAD_REQUIRE(pthread_mutex_lock(&mutex));
164         printf("1: Thread joined. X was %d. Return value (long) was %ld\n",
165                 global_x, (long)joinval);
166         ATF_REQUIRE_EQ(global_x, 20000000);
167
168 #ifdef __NetBSD__
169 #if defined(__powerpc__)
170         /* XXX force a timeout in ppc case since an un-triggered race
171            otherwise looks like a "failure" */
172         /* We sleep for longer than the timeout to make ATF not
173            complain about unexpected success */
174         sleep(41);
175 #endif
176 #endif
177 }
178
179 static void *
180 mutex3_threadfunc(void *arg)
181 {
182         long count = *(int *)arg;
183
184         printf("2: Second thread (%p). Count is %ld\n", pthread_self(), count);
185
186         while (count--) {
187                 PTHREAD_REQUIRE(pthread_mutex_lock(&static_mutex));
188                 global_x++;
189                 PTHREAD_REQUIRE(pthread_mutex_unlock(&static_mutex));
190         }
191
192         return (void *)count;
193 }
194
195 ATF_TC(mutex3);
196 ATF_TC_HEAD(mutex3, tc)
197 {
198         atf_tc_set_md_var(tc, "descr", "Checks mutexes using a static "
199             "initializer");
200 #ifdef __NetBSD__
201 #if defined(__powerpc__)
202         atf_tc_set_md_var(tc, "timeout", "40");
203 #endif
204 #endif
205 }
206 ATF_TC_BODY(mutex3, tc)
207 {
208         int count, count2;
209         pthread_t new;
210         void *joinval;
211
212         printf("1: Mutex-test 3\n");
213
214 #ifdef __NetBSD__
215 #if defined(__powerpc__)
216         atf_tc_expect_timeout("PR port-powerpc/44387");
217 #endif
218 #endif
219
220         global_x = 0;
221         count = count2 = 10000000;
222
223         PTHREAD_REQUIRE(pthread_mutex_lock(&static_mutex));
224         PTHREAD_REQUIRE(pthread_create(&new, NULL, mutex3_threadfunc, &count2));
225
226         printf("1: Thread %p\n", pthread_self());
227
228         PTHREAD_REQUIRE(pthread_mutex_unlock(&static_mutex));
229
230         while (count--) {
231                 PTHREAD_REQUIRE(pthread_mutex_lock(&static_mutex));
232                 global_x++;
233                 PTHREAD_REQUIRE(pthread_mutex_unlock(&static_mutex));
234         }
235
236         PTHREAD_REQUIRE(pthread_join(new, &joinval));
237
238         PTHREAD_REQUIRE(pthread_mutex_lock(&static_mutex));
239         printf("1: Thread joined. X was %d. Return value (long) was %ld\n",
240                 global_x, (long)joinval);
241         ATF_REQUIRE_EQ(global_x, 20000000);
242
243 #ifdef __NetBSD__
244 #if defined(__powerpc__)
245         /* XXX force a timeout in ppc case since an un-triggered race
246            otherwise looks like a "failure" */
247         /* We sleep for longer than the timeout to make ATF not
248            complain about unexpected success */
249         sleep(41);
250 #endif
251 #endif
252 }
253
254 static void *
255 mutex4_threadfunc(void *arg)
256 {
257         int *param;
258
259         printf("2: Second thread.\n");
260
261         param = arg;
262         printf("2: Locking mutex\n");
263         PTHREAD_REQUIRE(pthread_mutex_lock(&mutex));
264         printf("2: Got mutex. *param = %d\n", *param);
265         (*param)++;
266
267         PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
268
269         return param;
270 }
271
272 ATF_TC(mutex4);
273 ATF_TC_HEAD(mutex4, tc)
274 {
275         atf_tc_set_md_var(tc, "descr", "Checks mutexes");
276 }
277 ATF_TC_BODY(mutex4, tc)
278 {
279         int x;
280         pthread_t new;
281         pthread_mutexattr_t mattr;
282         void *joinval;
283
284         printf("1: Mutex-test 4\n");
285
286         PTHREAD_REQUIRE(pthread_mutexattr_init(&mattr));
287         PTHREAD_REQUIRE(pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_RECURSIVE));
288
289         PTHREAD_REQUIRE(pthread_mutex_init(&mutex, &mattr));
290
291         PTHREAD_REQUIRE(pthread_mutexattr_destroy(&mattr));
292
293         x = 1;
294         PTHREAD_REQUIRE(pthread_mutex_lock(&mutex));
295         PTHREAD_REQUIRE(pthread_create(&new, NULL, mutex4_threadfunc, &x));
296
297         printf("1: Before recursively acquiring the mutex.\n");
298         PTHREAD_REQUIRE(pthread_mutex_lock(&mutex));
299
300         printf("1: Before releasing the mutex once.\n");
301         sleep(2);
302         PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
303         printf("1: After releasing the mutex once.\n");
304
305         x = 20;
306
307         printf("1: Before releasing the mutex twice.\n");
308         sleep(2);
309         PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
310         printf("1: After releasing the mutex twice.\n");
311
312         PTHREAD_REQUIRE(pthread_join(new, &joinval));
313
314         PTHREAD_REQUIRE(pthread_mutex_lock(&mutex));
315         printf("1: Thread joined. X was %d. Return value (int) was %d\n",
316                 x, *(int *)joinval);
317         ATF_REQUIRE_EQ(x, 21);
318         ATF_REQUIRE_EQ(*(int *)joinval, 21);
319         PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
320 }
321
322 #ifdef __NetBSD__
323 static pthread_mutexattr_t attr5;
324 static pthread_mutex_t mutex5;
325 static int min_fifo_prio, max_fifo_prio;
326
327 static void *
328 child_func(void* arg)
329 {
330         int res;
331
332         printf("child is waiting\n");
333         res = _sched_protect(-2);
334         ATF_REQUIRE_EQ_MSG(res, -1, "sched_protect returned %d", res);
335         ATF_REQUIRE_EQ(errno, ENOENT);
336         PTHREAD_REQUIRE(pthread_mutex_lock(&mutex5));
337         printf("child is owning resource\n");
338         res = _sched_protect(-2);
339         ATF_REQUIRE_EQ(res,  max_fifo_prio);
340         PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex5));
341         printf("child is done\n");
342         
343         return 0;
344 }
345
346 ATF_TC(mutex5);
347 ATF_TC_HEAD(mutex5, tc)
348 {
349         atf_tc_set_md_var(tc, "descr", "Checks mutexes for priority setting");
350         atf_tc_set_md_var(tc, "require.user", "root");
351 }
352
353 ATF_TC_BODY(mutex5, tc)
354 {
355         int res;
356         struct sched_param param;
357         pthread_t child;
358
359         min_fifo_prio = sched_get_priority_min(SCHED_FIFO);
360         max_fifo_prio = sched_get_priority_max(SCHED_FIFO);
361         printf("min prio for FIFO = %d\n", min_fifo_prio);
362         param.sched_priority = min_fifo_prio;
363
364         /* = 0 OTHER, 1 FIFO, 2 RR, -1 NONE */
365         res = sched_setscheduler(getpid(), SCHED_FIFO, &param);
366         printf("previous policy used = %d\n", res);
367
368         res = sched_getscheduler(getpid());
369         ATF_REQUIRE_EQ_MSG(res, SCHED_FIFO, "sched %d != FIFO %d", res, 
370             SCHED_FIFO);
371
372         PTHREAD_REQUIRE(pthread_mutexattr_init(&attr5));
373         PTHREAD_REQUIRE(pthread_mutexattr_setprotocol(&attr5,
374             PTHREAD_PRIO_PROTECT));
375         PTHREAD_REQUIRE(pthread_mutexattr_setprioceiling(&attr5,
376             max_fifo_prio));
377         
378         PTHREAD_REQUIRE(pthread_mutex_init(&mutex5, &attr5));
379         PTHREAD_REQUIRE(pthread_mutex_lock(&mutex5));
380         printf("enter critical section for main\n");
381         PTHREAD_REQUIRE(pthread_create(&child, NULL, child_func, NULL));
382         printf("main starts to sleep\n");
383         sleep(10);
384         printf("main completes\n");
385         PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex5));
386         PTHREAD_REQUIRE(pthread_join(child, NULL));
387 }
388
389 static pthread_mutex_t mutex6;
390 static int start = 0;
391 static uintmax_t high_cnt = 0, low_cnt = 0, MAX_LOOP = 100000000;
392
393 static void *
394 high_prio(void* arg)
395 {
396         struct sched_param param;
397         int policy;
398         param.sched_priority = min_fifo_prio + 10;
399         pthread_t childid = pthread_self();
400
401         PTHREAD_REQUIRE(pthread_setschedparam(childid, 1, &param));
402         PTHREAD_REQUIRE(pthread_getschedparam(childid, &policy, &param));
403         printf("high protect = %d, prio = %d\n",
404             _sched_protect(-2), param.sched_priority);
405         ATF_REQUIRE_EQ(policy, 1);
406         printf("high prio = %d\n", param.sched_priority);
407         sleep(1);
408         long tmp = 0;
409         for (int i = 0; i < 20; i++) {
410                 while (high_cnt < MAX_LOOP) {
411                         tmp += (123456789 % 1234) * (987654321 % 54321);
412                         high_cnt += 1;
413                 }
414                 high_cnt = 0;
415                 sleep(1);
416         }
417         PTHREAD_REQUIRE(pthread_mutex_lock(&mutex6));
418         if (start == 0) start = 2;
419         PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex6));
420
421         return 0;
422 }
423
424 static void *
425 low_prio(void* arg)
426 {
427         struct sched_param param;
428         int policy;
429         param.sched_priority = min_fifo_prio;
430         pthread_t childid = pthread_self();
431         int res = _sched_protect(max_fifo_prio);
432         ATF_REQUIRE_EQ(res, 0);
433         PTHREAD_REQUIRE(pthread_setschedparam(childid, 1, &param));
434         PTHREAD_REQUIRE(pthread_getschedparam(childid, &policy, &param));
435         printf("low protect = %d, prio = %d\n", _sched_protect(-2),
436             param.sched_priority);
437         ATF_REQUIRE_EQ(policy, 1);
438         printf("low prio = %d\n", param.sched_priority);
439         sleep(1);
440         long tmp = 0;
441         for (int i = 0; i < 20; i++) {
442                 while (low_cnt < MAX_LOOP) {
443                         tmp += (123456789 % 1234) * (987654321 % 54321);
444                         low_cnt += 1;
445                 }
446                 low_cnt = 0;
447                 sleep(1);
448         }
449         PTHREAD_REQUIRE(pthread_mutex_lock(&mutex6));
450         if (start == 0)
451                 start = 1;
452         PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex6));
453
454         return 0;
455 }
456
457 ATF_TC(mutex6);
458 ATF_TC_HEAD(mutex6, tc)
459 {
460         atf_tc_set_md_var(tc, "descr",
461             "Checks scheduling for priority ceiling");
462         atf_tc_set_md_var(tc, "require.user", "root");
463 }
464
465 /*
466  * 1. main thread sets itself to be a realtime task and launched two tasks,
467  *    one has higher priority and the other has lower priority.
468  * 2. each child thread(low and high priority thread) sets its scheduler and
469  *    priority.
470  * 3. each child thread did several rounds of computation, after each round it
471  *    sleep 1 second.
472  * 4. the child thread with low priority will call _sched_protect to increase
473  *    its protect priority.
474  * 5. We verify the thread with low priority runs first.
475  *
476  * Why does it work? From the main thread, we launched the high
477  * priority thread first. This gives this thread the benefit of
478  * starting first. The low priority thread did not call _sched_protect(2).
479  * The high priority thread should finish the task first. After each
480  * round of computation, we call sleep, to put the task into the
481  * sleep queue, and wake up again after the timer expires. This
482  * gives the scheduler the chance to decide which task to run. So,
483  * the thread with real high priority will always block the thread
484  * with real low priority.
485  * 
486  */
487 ATF_TC_BODY(mutex6, tc)
488 {
489         struct sched_param param;
490         int res;
491         pthread_t high, low;
492
493         min_fifo_prio = sched_get_priority_min(SCHED_FIFO);
494         max_fifo_prio = sched_get_priority_max(SCHED_FIFO);
495         PTHREAD_REQUIRE(pthread_mutex_init(&mutex, NULL));
496         printf("min_fifo_prio = %d, max_fifo_info = %d\n", min_fifo_prio,
497             max_fifo_prio);
498
499         param.sched_priority = min_fifo_prio;
500         res = sched_setscheduler(getpid(), SCHED_FIFO, &param);
501         printf("previous policy used = %d\n", res);
502
503         res = sched_getscheduler(getpid());
504         ATF_REQUIRE_EQ(res, 1);
505         PTHREAD_REQUIRE(pthread_create(&high, NULL, high_prio, NULL));
506         PTHREAD_REQUIRE(pthread_create(&low, NULL, low_prio, NULL));
507         sleep(5);
508         PTHREAD_REQUIRE(pthread_join(low, NULL));
509         PTHREAD_REQUIRE(pthread_join(high, NULL));
510         
511         ATF_REQUIRE_EQ(start, 1);
512 }
513 #endif
514
515 ATF_TC(mutexattr1);
516 ATF_TC_HEAD(mutexattr1, tc)
517 {
518         atf_tc_set_md_var(tc, "descr", "Checks mutexattr");
519 }
520
521 ATF_TC_BODY(mutexattr1, tc)
522 {
523         pthread_mutexattr_t mattr;
524         int protocol, target;
525         
526         PTHREAD_REQUIRE(pthread_mutexattr_init(&mattr));
527
528         target = PTHREAD_PRIO_NONE;
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         target = PTHREAD_PRIO_INHERIT;
535         PTHREAD_REQUIRE(pthread_mutexattr_setprotocol(&mattr, target));
536         PTHREAD_REQUIRE(pthread_mutexattr_getprotocol(&mattr, &protocol));
537         ATF_REQUIRE_EQ(protocol, target);
538         */
539
540         target = PTHREAD_PRIO_PROTECT;
541         PTHREAD_REQUIRE(pthread_mutexattr_setprotocol(&mattr, target));
542         PTHREAD_REQUIRE(pthread_mutexattr_getprotocol(&mattr, &protocol));
543         ATF_REQUIRE_EQ(protocol, target);
544 }
545
546 ATF_TC(mutexattr2);
547 ATF_TC_HEAD(mutexattr2, tc)
548 {
549         atf_tc_set_md_var(tc, "descr", "Checks mutexattr");
550 }
551
552 ATF_TC_BODY(mutexattr2, tc)
553 {
554         pthread_mutexattr_t mattr;
555
556 #ifdef __FreeBSD__
557         atf_tc_expect_fail("fails on i == 0 with: "
558             "pthread_mutexattr_setprioceiling(&mattr, i): Invalid argument "
559             "-- PR # 211802");
560 #endif
561
562         PTHREAD_REQUIRE(pthread_mutexattr_init(&mattr));
563         int max_prio = sched_get_priority_max(SCHED_FIFO);
564         int min_prio = sched_get_priority_min(SCHED_FIFO);
565         for (int i = min_prio; i <= max_prio; i++) {
566                 int prioceiling;
567 #ifdef __FreeBSD__
568                 int protocol;
569
570                 PTHREAD_REQUIRE(pthread_mutexattr_getprotocol(&mattr,
571                     &protocol));
572
573                 printf("priority: %d\nprotocol: %d\n", i, protocol);
574 #endif
575                 PTHREAD_REQUIRE(pthread_mutexattr_setprioceiling(&mattr, i));
576                 PTHREAD_REQUIRE(pthread_mutexattr_getprioceiling(&mattr,
577                     &prioceiling));
578 #ifdef __FreeBSD__
579                 printf("prioceiling: %d\n", prioceiling);
580 #endif
581                 ATF_REQUIRE_EQ(i, prioceiling);
582         }
583 }
584
585 ATF_TP_ADD_TCS(tp)
586 {
587         ATF_TP_ADD_TC(tp, mutex1);
588         ATF_TP_ADD_TC(tp, mutex2);
589         ATF_TP_ADD_TC(tp, mutex3);
590         ATF_TP_ADD_TC(tp, mutex4);
591 #ifdef __NetBSD__
592         ATF_TP_ADD_TC(tp, mutex5);
593         ATF_TP_ADD_TC(tp, mutex6);
594 #endif
595         ATF_TP_ADD_TC(tp, mutexattr1);
596         ATF_TP_ADD_TC(tp, mutexattr2);
597         
598         return atf_no_error();
599 }