t_mutex.c revision 1.20
1/* $NetBSD: t_mutex.c,v 1.20 2022/05/07 05:13:17 rin 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.20 2022/05/07 05:13:17 rin Exp $");
33
34#include <sys/time.h> /* For timespecadd */
35#include <inttypes.h> /* For UINT16_MAX */
36#include <pthread.h>
37#include <stdio.h>
38#include <string.h>
39#include <errno.h>
40#include <time.h>
41#include <unistd.h>
42#include <sys/sched.h>
43#include <sys/param.h>
44
45#include <atf-c.h>
46
47#include "h_common.h"
48
49static pthread_mutex_t mutex;
50static pthread_mutex_t static_mutex = PTHREAD_MUTEX_INITIALIZER;
51static int global_x;
52
53#ifdef TIMEDMUTEX
54/* This code is used for verifying non-timed specific code */
55static struct timespec ts_lengthy = {
56	.tv_sec = UINT16_MAX,
57	.tv_nsec = 0
58};
59/* This code is used for verifying timed-only specific code */
60static struct timespec ts_shortlived = {
61	.tv_sec = 0,
62	.tv_nsec = 120
63};
64
65static int
66mutex_lock(pthread_mutex_t *m, const struct timespec *ts)
67{
68	struct timespec ts_wait;
69	ATF_REQUIRE(clock_gettime(CLOCK_REALTIME, &ts_wait) != -1);
70	timespecadd(&ts_wait, ts, &ts_wait);
71
72	return pthread_mutex_timedlock(m, &ts_wait);
73}
74#else
75#define mutex_lock(a, b) pthread_mutex_lock(a)
76#endif
77
78static void *
79mutex1_threadfunc(void *arg)
80{
81	int *param;
82
83	printf("2: Second thread.\n");
84
85	param = arg;
86	printf("2: Locking mutex\n");
87	mutex_lock(&mutex, &ts_lengthy);
88	printf("2: Got mutex. *param = %d\n", *param);
89	ATF_REQUIRE_EQ(*param, 20);
90	(*param)++;
91
92	pthread_mutex_unlock(&mutex);
93
94	return param;
95}
96
97ATF_TC(mutex1);
98ATF_TC_HEAD(mutex1, tc)
99{
100	atf_tc_set_md_var(tc, "descr", "Checks mutexes");
101}
102ATF_TC_BODY(mutex1, tc)
103{
104	int x;
105	pthread_t new;
106	void *joinval;
107
108	printf("1: Mutex-test 1\n");
109
110	PTHREAD_REQUIRE(pthread_mutex_init(&mutex, NULL));
111	x = 1;
112	PTHREAD_REQUIRE(mutex_lock(&mutex, &ts_lengthy));
113	PTHREAD_REQUIRE(pthread_create(&new, NULL, mutex1_threadfunc, &x));
114	printf("1: Before changing the value.\n");
115	sleep(2);
116	x = 20;
117	printf("1: Before releasing the mutex.\n");
118	sleep(2);
119	PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
120	printf("1: After releasing the mutex.\n");
121	PTHREAD_REQUIRE(pthread_join(new, &joinval));
122
123	PTHREAD_REQUIRE(mutex_lock(&mutex, &ts_lengthy));
124	printf("1: Thread joined. X was %d. Return value (int) was %d\n",
125		x, *(int *)joinval);
126	ATF_REQUIRE_EQ(x, 21);
127	ATF_REQUIRE_EQ(*(int *)joinval, 21);
128	PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
129}
130
131static void *
132mutex2_threadfunc(void *arg)
133{
134	long count = *(int *)arg;
135
136	printf("2: Second thread (%p). Count is %ld\n", pthread_self(), count);
137
138	while (count--) {
139		PTHREAD_REQUIRE(mutex_lock(&mutex, &ts_lengthy));
140		global_x++;
141		PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
142	}
143
144	return (void *)count;
145}
146
147ATF_TC(mutex2);
148ATF_TC_HEAD(mutex2, tc)
149{
150	atf_tc_set_md_var(tc, "descr", "Checks mutexes");
151	atf_tc_set_md_var(tc, "timeout", "600");
152}
153ATF_TC_BODY(mutex2, tc)
154{
155	int count, count2;
156	pthread_t new;
157	void *joinval;
158
159	printf("1: Mutex-test 2\n");
160
161	PTHREAD_REQUIRE(pthread_mutex_init(&mutex, NULL));
162
163	global_x = 0;
164	count = count2 = 10000000;
165
166	PTHREAD_REQUIRE(mutex_lock(&mutex, &ts_lengthy));
167	PTHREAD_REQUIRE(pthread_create(&new, NULL, mutex2_threadfunc, &count2));
168
169	printf("1: Thread %p\n", pthread_self());
170
171	PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
172
173	while (count--) {
174		PTHREAD_REQUIRE(mutex_lock(&mutex, &ts_lengthy));
175		global_x++;
176		PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
177	}
178
179	PTHREAD_REQUIRE(pthread_join(new, &joinval));
180
181	PTHREAD_REQUIRE(mutex_lock(&mutex, &ts_lengthy));
182	printf("1: Thread joined. X was %d. Return value (long) was %ld\n",
183		global_x, (long)joinval);
184	ATF_REQUIRE_EQ(global_x, 20000000);
185}
186
187static void *
188mutex3_threadfunc(void *arg)
189{
190	long count = *(int *)arg;
191
192	printf("2: Second thread (%p). Count is %ld\n", pthread_self(), count);
193
194	while (count--) {
195		PTHREAD_REQUIRE(mutex_lock(&static_mutex, &ts_lengthy));
196		global_x++;
197		PTHREAD_REQUIRE(pthread_mutex_unlock(&static_mutex));
198	}
199
200	return (void *)count;
201}
202
203ATF_TC(mutex3);
204ATF_TC_HEAD(mutex3, tc)
205{
206	atf_tc_set_md_var(tc, "descr", "Checks mutexes using a static "
207	    "initializer");
208	atf_tc_set_md_var(tc, "timeout", "600");
209}
210ATF_TC_BODY(mutex3, tc)
211{
212	int count, count2;
213	pthread_t new;
214	void *joinval;
215
216	printf("1: Mutex-test 3\n");
217
218	global_x = 0;
219	count = count2 = 10000000;
220
221	PTHREAD_REQUIRE(mutex_lock(&static_mutex, &ts_lengthy));
222	PTHREAD_REQUIRE(pthread_create(&new, NULL, mutex3_threadfunc, &count2));
223
224	printf("1: Thread %p\n", pthread_self());
225
226	PTHREAD_REQUIRE(pthread_mutex_unlock(&static_mutex));
227
228	while (count--) {
229		PTHREAD_REQUIRE(mutex_lock(&static_mutex, &ts_lengthy));
230		global_x++;
231		PTHREAD_REQUIRE(pthread_mutex_unlock(&static_mutex));
232	}
233
234	PTHREAD_REQUIRE(pthread_join(new, &joinval));
235
236	PTHREAD_REQUIRE(mutex_lock(&static_mutex, &ts_lengthy));
237	printf("1: Thread joined. X was %d. Return value (long) was %ld\n",
238		global_x, (long)joinval);
239	ATF_REQUIRE_EQ(global_x, 20000000);
240}
241
242static void *
243mutex4_threadfunc(void *arg)
244{
245	int *param;
246
247	printf("2: Second thread.\n");
248
249	param = arg;
250	printf("2: Locking mutex\n");
251	PTHREAD_REQUIRE(mutex_lock(&mutex, &ts_lengthy));
252	printf("2: Got mutex. *param = %d\n", *param);
253	(*param)++;
254
255	PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
256
257	return param;
258}
259
260ATF_TC(mutex4);
261ATF_TC_HEAD(mutex4, tc)
262{
263	atf_tc_set_md_var(tc, "descr", "Checks mutexes");
264}
265ATF_TC_BODY(mutex4, tc)
266{
267	int x;
268	pthread_t new;
269	pthread_mutexattr_t mattr;
270	void *joinval;
271
272	printf("1: Mutex-test 4\n");
273
274	PTHREAD_REQUIRE(pthread_mutexattr_init(&mattr));
275	PTHREAD_REQUIRE(pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_RECURSIVE));
276
277	PTHREAD_REQUIRE(pthread_mutex_init(&mutex, &mattr));
278
279	PTHREAD_REQUIRE(pthread_mutexattr_destroy(&mattr));
280
281	x = 1;
282	PTHREAD_REQUIRE(mutex_lock(&mutex, &ts_lengthy));
283	PTHREAD_REQUIRE(pthread_create(&new, NULL, mutex4_threadfunc, &x));
284
285	printf("1: Before recursively acquiring the mutex.\n");
286	PTHREAD_REQUIRE(mutex_lock(&mutex, &ts_lengthy));
287
288	printf("1: Before releasing the mutex once.\n");
289	sleep(2);
290	PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
291	printf("1: After releasing the mutex once.\n");
292
293	x = 20;
294
295	printf("1: Before releasing the mutex twice.\n");
296	sleep(2);
297	PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
298	printf("1: After releasing the mutex twice.\n");
299
300	PTHREAD_REQUIRE(pthread_join(new, &joinval));
301
302	PTHREAD_REQUIRE(mutex_lock(&mutex, &ts_lengthy));
303	printf("1: Thread joined. X was %d. Return value (int) was %d\n",
304		x, *(int *)joinval);
305	ATF_REQUIRE_EQ(x, 21);
306	ATF_REQUIRE_EQ(*(int *)joinval, 21);
307	PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
308}
309
310static pthread_mutexattr_t attr5;
311static pthread_mutex_t mutex5;
312static int min_fifo_prio, max_fifo_prio;
313
314static void *
315child_func(void* arg)
316{
317	int res;
318
319	printf("child is waiting\n");
320	res = _sched_protect(-2);
321	ATF_REQUIRE_EQ_MSG(res, -1, "sched_protect returned %d", res);
322	ATF_REQUIRE_EQ(errno, ENOENT);
323	PTHREAD_REQUIRE(mutex_lock(&mutex5, &ts_lengthy));
324	printf("child is owning resource\n");
325	res = _sched_protect(-2);
326	ATF_REQUIRE_EQ(res,  max_fifo_prio);
327	PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex5));
328	printf("child is done\n");
329
330	return 0;
331}
332
333ATF_TC(mutex5);
334ATF_TC_HEAD(mutex5, tc)
335{
336	atf_tc_set_md_var(tc, "descr", "Checks mutexes for priority setting");
337	atf_tc_set_md_var(tc, "require.user", "root");
338}
339
340ATF_TC_BODY(mutex5, tc)
341{
342	int res;
343	struct sched_param param;
344	pthread_t child;
345
346	min_fifo_prio = sched_get_priority_min(SCHED_FIFO);
347	max_fifo_prio = sched_get_priority_max(SCHED_FIFO);
348	printf("min prio for FIFO = %d\n", min_fifo_prio);
349	param.sched_priority = min_fifo_prio;
350
351	/* = 0 OTHER, 1 FIFO, 2 RR, -1 NONE */
352	res = sched_setscheduler(getpid(), SCHED_FIFO, &param);
353	printf("previous policy used = %d\n", res);
354
355	res = sched_getscheduler(getpid());
356	ATF_REQUIRE_EQ_MSG(res, SCHED_FIFO, "sched %d != FIFO %d", res,
357	    SCHED_FIFO);
358
359	PTHREAD_REQUIRE(pthread_mutexattr_init(&attr5));
360	PTHREAD_REQUIRE(pthread_mutexattr_setprotocol(&attr5,
361	    PTHREAD_PRIO_PROTECT));
362	PTHREAD_REQUIRE(pthread_mutexattr_setprioceiling(&attr5,
363	    max_fifo_prio));
364
365	PTHREAD_REQUIRE(pthread_mutex_init(&mutex5, &attr5));
366	PTHREAD_REQUIRE(mutex_lock(&mutex5, &ts_lengthy));
367	printf("enter critical section for main\n");
368	PTHREAD_REQUIRE(pthread_create(&child, NULL, child_func, NULL));
369	printf("main starts to sleep\n");
370	sleep(10);
371	printf("main completes\n");
372	PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex5));
373	PTHREAD_REQUIRE(pthread_join(child, NULL));
374}
375
376ATF_TC(mutexattr1);
377ATF_TC_HEAD(mutexattr1, tc)
378{
379	atf_tc_set_md_var(tc, "descr", "Checks mutexattr");
380}
381
382ATF_TC_BODY(mutexattr1, tc)
383{
384	pthread_mutexattr_t mattr;
385	int protocol, target;
386
387	PTHREAD_REQUIRE(pthread_mutexattr_init(&mattr));
388
389	target = PTHREAD_PRIO_NONE;
390	PTHREAD_REQUIRE(pthread_mutexattr_setprotocol(&mattr, target));
391	PTHREAD_REQUIRE(pthread_mutexattr_getprotocol(&mattr, &protocol));
392	ATF_REQUIRE_EQ(protocol, target);
393
394	/*
395	target = PTHREAD_PRIO_INHERIT;
396	PTHREAD_REQUIRE(pthread_mutexattr_setprotocol(&mattr, target));
397	PTHREAD_REQUIRE(pthread_mutexattr_getprotocol(&mattr, &protocol));
398	ATF_REQUIRE_EQ(protocol, target);
399	*/
400
401	target = PTHREAD_PRIO_PROTECT;
402	PTHREAD_REQUIRE(pthread_mutexattr_setprotocol(&mattr, target));
403	PTHREAD_REQUIRE(pthread_mutexattr_getprotocol(&mattr, &protocol));
404	ATF_REQUIRE_EQ(protocol, target);
405}
406
407ATF_TC(mutexattr2);
408ATF_TC_HEAD(mutexattr2, tc)
409{
410	atf_tc_set_md_var(tc, "descr", "Checks mutexattr");
411}
412
413ATF_TC_BODY(mutexattr2, tc)
414{
415	pthread_mutexattr_t mattr;
416
417	PTHREAD_REQUIRE(pthread_mutexattr_init(&mattr));
418	int max_prio = sched_get_priority_max(SCHED_FIFO);
419	int min_prio = sched_get_priority_min(SCHED_FIFO);
420	for (int i = min_prio; i <= max_prio; i++) {
421		int prioceiling;
422		int protocol;
423
424		PTHREAD_REQUIRE(pthread_mutexattr_getprotocol(&mattr,
425		    &protocol));
426
427		printf("priority: %d\nprotocol: %d\n", i, protocol);
428		PTHREAD_REQUIRE(pthread_mutexattr_setprioceiling(&mattr, i));
429		PTHREAD_REQUIRE(pthread_mutexattr_getprioceiling(&mattr,
430		    &prioceiling));
431		printf("prioceiling: %d\n", prioceiling);
432		ATF_REQUIRE_EQ(i, prioceiling);
433	}
434}
435
436#ifdef TIMEDMUTEX
437ATF_TC(timedmutex1);
438ATF_TC_HEAD(timedmutex1, tc)
439{
440	atf_tc_set_md_var(tc, "descr", "Checks timeout on selflock");
441}
442
443ATF_TC_BODY(timedmutex1, tc)
444{
445
446	printf("Timed mutex-test 1\n");
447
448	PTHREAD_REQUIRE(pthread_mutex_init(&mutex, NULL));
449
450	printf("Before acquiring mutex\n");
451	PTHREAD_REQUIRE(pthread_mutex_lock(&mutex));
452
453	printf("Before endeavor to reacquire timed-mutex (timeout expected)\n");
454	PTHREAD_REQUIRE_STATUS(mutex_lock(&mutex, &ts_shortlived),
455	    ETIMEDOUT);
456
457	printf("Unlocking mutex\n");
458	PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
459}
460
461ATF_TC(timedmutex2);
462ATF_TC_HEAD(timedmutex2, tc)
463{
464	atf_tc_set_md_var(tc, "descr",
465	    "Checks timeout on selflock with timedlock");
466}
467
468ATF_TC_BODY(timedmutex2, tc)
469{
470
471	printf("Timed mutex-test 2\n");
472
473	PTHREAD_REQUIRE(pthread_mutex_init(&mutex, NULL));
474
475	printf("Before acquiring mutex with timedlock\n");
476	PTHREAD_REQUIRE(mutex_lock(&mutex, &ts_lengthy));
477
478	printf("Before endeavor to reacquire timed-mutex (timeout expected)\n");
479	PTHREAD_REQUIRE_STATUS(mutex_lock(&mutex, &ts_shortlived),
480	    ETIMEDOUT);
481
482	printf("Unlocking mutex\n");
483	PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
484}
485
486ATF_TC(timedmutex3);
487ATF_TC_HEAD(timedmutex3, tc)
488{
489	atf_tc_set_md_var(tc, "descr",
490	    "Checks timeout on selflock in a new thread");
491}
492
493static void *
494timedmtx_thrdfunc(void *arg)
495{
496	printf("Before endeavor to reacquire timed-mutex (timeout expected)\n");
497	PTHREAD_REQUIRE_STATUS(mutex_lock(&mutex, &ts_shortlived),
498	    ETIMEDOUT);
499
500	return NULL;
501}
502
503ATF_TC_BODY(timedmutex3, tc)
504{
505	pthread_t new;
506
507	printf("Timed mutex-test 3\n");
508
509	PTHREAD_REQUIRE(pthread_mutex_init(&mutex, NULL));
510
511	printf("Before acquiring mutex with timedlock\n");
512	PTHREAD_REQUIRE(pthread_mutex_lock(&mutex));
513
514	printf("Before creating new thread\n");
515	PTHREAD_REQUIRE(pthread_create(&new, NULL, timedmtx_thrdfunc, NULL));
516
517	printf("Before joining the mutex\n");
518	PTHREAD_REQUIRE(pthread_join(new, NULL));
519
520	printf("Unlocking mutex\n");
521	PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
522}
523
524ATF_TC(timedmutex4);
525ATF_TC_HEAD(timedmutex4, tc)
526{
527	atf_tc_set_md_var(tc, "descr",
528	    "Checks timeout on selflock with timedlock in a new thread");
529}
530
531ATF_TC_BODY(timedmutex4, tc)
532{
533	pthread_t new;
534
535	printf("Timed mutex-test 4\n");
536
537	PTHREAD_REQUIRE(pthread_mutex_init(&mutex, NULL));
538
539	printf("Before acquiring mutex with timedlock\n");
540	PTHREAD_REQUIRE(mutex_lock(&mutex, &ts_lengthy));
541
542	printf("Before creating new thread\n");
543	PTHREAD_REQUIRE(pthread_create(&new, NULL, timedmtx_thrdfunc, NULL));
544
545	printf("Before joining the mutex\n");
546	PTHREAD_REQUIRE(pthread_join(new, NULL));
547
548	printf("Unlocking mutex\n");
549	PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
550}
551#endif
552
553ATF_TP_ADD_TCS(tp)
554{
555	ATF_TP_ADD_TC(tp, mutex1);
556	ATF_TP_ADD_TC(tp, mutex2);
557	ATF_TP_ADD_TC(tp, mutex3);
558	ATF_TP_ADD_TC(tp, mutex4);
559	ATF_TP_ADD_TC(tp, mutex5);
560	ATF_TP_ADD_TC(tp, mutexattr1);
561	ATF_TP_ADD_TC(tp, mutexattr2);
562
563#ifdef TIMEDMUTEX
564	ATF_TP_ADD_TC(tp, timedmutex1);
565	ATF_TP_ADD_TC(tp, timedmutex2);
566	ATF_TP_ADD_TC(tp, timedmutex3);
567	ATF_TP_ADD_TC(tp, timedmutex4);
568#endif
569
570	return atf_no_error();
571}
572