xref: /illumos-gate/usr/src/test/libc-tests/tests/mutex_attr.c (revision 489f6310fe8952e87fc1dce8af87990fcfd90f18)
1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2025 Oxide Computer Company
14  */
15 
16 /*
17  * Verify we can set and obtain various mutex attributes in the structure. This
18  * is also a regression test for illumos#17334 where we did not get the type
19  * correctly. This does not validate that a mutex can be successfully created
20  * with these attributes.
21  */
22 
23 #include <stdlib.h>
24 #include <err.h>
25 #include <pthread.h>
26 #include <sys/sysmacros.h>
27 #include <stdbool.h>
28 #include <errno.h>
29 #include <string.h>
30 
31 typedef int (*attr_set_f)(pthread_mutexattr_t *, int);
32 typedef int (*attr_get_f)(const pthread_mutexattr_t *, int *);
33 
34 static const int check_types[] = { PTHREAD_MUTEX_NORMAL,
35     PTHREAD_MUTEX_ERRORCHECK, PTHREAD_MUTEX_RECURSIVE, PTHREAD_MUTEX_DEFAULT };
36 static const int check_shared[] = { PTHREAD_PROCESS_SHARED,
37     PTHREAD_PROCESS_PRIVATE };
38 static const int check_prioceil[] = { 0, 1, 2 };
39 static const int check_protocol[] = { PTHREAD_PRIO_NONE, PTHREAD_PRIO_INHERIT,
40     PTHREAD_PRIO_PROTECT };
41 static const int check_robust[] = { PTHREAD_MUTEX_STALLED, PTHREAD_MUTEX_ROBUST,
42     PTHREAD_MUTEX_STALL_NP, PTHREAD_MUTEX_ROBUST_NP };
43 
44 static bool
45 check_field(const char *desc, pthread_mutexattr_t *attr, attr_get_f get_f,
46     attr_set_f set_f, int def, const int *vals, size_t nvals, int err_code)
47 {
48 	bool ret = true;
49 	int r, v;
50 
51 	if ((r = get_f(attr, NULL)) != EINVAL) {
52 		warnx("TEST FAILED: expected getting %s attribute with invalid "
53 		    "attr structure to return EINVAL, found %s", desc,
54 		    strerrorname_np(r));
55 		ret = false;
56 	} else {
57 		(void) printf("TEST PASSED: getting attribute %s with invalid "
58 		    "attributes returned EINVAL\n");
59 	}
60 
61 	if ((r = get_f(attr, &v)) != 0) {
62 		warnc(r, "TEST FAILED: failed to get default value for mutex "
63 		    "%s", desc);
64 		ret = false;
65 	} else if (v != def) {
66 		warnx("TEST FAILED: mutex %s has wrong default value: expected "
67 		    "0x%x, found 0x%x", desc, def, v);
68 		ret = false;
69 	} else {
70 		(void) printf("TEST PASSED: mutex %s default value is the "
71 		    "expected value\n", desc);
72 	}
73 
74 	for (size_t i = 0; i < nvals; i++) {
75 		if ((r = set_f(attr, vals[i])) != 0) {
76 			warnc(r, "TEST FAILED: failed to set mutex %s "
77 			    "attribute to 0x%x", desc, vals[i]);
78 			ret = false;
79 			continue;
80 		}
81 
82 		if ((r = get_f(attr, &v)) != 0) {
83 			warnc(r, "TEST FAILED: failed to get value for mutex "
84 			    "%s", desc);
85 			ret = false;
86 		} else if (v != vals[i]) {
87 			warnx("TEST FAILED: mutex %s has wrong value: expected "
88 			    "0x%x, found 0x%x", desc, vals[i], v);
89 			ret = false;
90 		} else {
91 			(void) printf("TEST PASSED: mutex %s value matches "
92 			    "what we just set (0x%x)\n", desc, vals[i]);
93 		}
94 	}
95 
96 	if ((r = set_f(attr, INT32_MAX)) != err_code) {
97 		warnx("TEST FAILED: expected setting mutex %s to INT32_MAX to "
98 		    "fail with %s, got %s (0x%x)", desc,
99 		    strerrorname_np(err_code), strerrorname_np(r), r);
100 		ret = false;
101 	} else {
102 		(void) printf("TEST PASSED: Setting mutex %s to invalid value "
103 		    "(INT32_MAX) correctly failed with %s\n", desc,
104 		    strerrorname_np(err_code));
105 	}
106 
107 	if ((r = set_f(attr, INT32_MIN)) != err_code) {
108 		warnx("TEST FAILED: expected setting mutex %s to INT32_MIN to "
109 		    "fail with %s, got %s (0x%x)", desc,
110 		    strerrorname_np(err_code), strerrorname_np(r), r);
111 		ret = false;
112 	} else {
113 		(void) printf("TEST PASSED: Setting mutex %s to invalid value "
114 		    "(INT32_MIN) correctly failed with %s\n", desc,
115 		    strerrorname_np(err_code));
116 	}
117 
118 	return (ret);
119 }
120 
121 int
122 main(void)
123 {
124 	int ret = EXIT_SUCCESS, r;
125 	pthread_mutexattr_t attr;
126 
127 	if ((r = pthread_mutexattr_init(&attr)) != 0) {
128 		errc(EXIT_FAILURE, r, "TEST FAILED: failed to initialize "
129 		    "mutex attributes");
130 	}
131 
132 	if (!check_field("type", &attr, pthread_mutexattr_gettype,
133 	    pthread_mutexattr_settype, PTHREAD_MUTEX_DEFAULT, check_types,
134 	    ARRAY_SIZE(check_types), EINVAL)) {
135 		ret = EXIT_FAILURE;
136 	}
137 
138 	if (!check_field("shared", &attr, pthread_mutexattr_getpshared,
139 	    pthread_mutexattr_setpshared, PTHREAD_PROCESS_PRIVATE, check_shared,
140 	    ARRAY_SIZE(check_shared), EINVAL)) {
141 		ret = EXIT_FAILURE;
142 	}
143 
144 	if (!check_field("priority ceiling", &attr,
145 	    pthread_mutexattr_getprioceiling, pthread_mutexattr_setprioceiling,
146 	    0, check_prioceil, ARRAY_SIZE(check_prioceil), EINVAL)) {
147 		ret = EXIT_FAILURE;
148 	}
149 
150 	if (!check_field("protocol", &attr, pthread_mutexattr_getprotocol,
151 	    pthread_mutexattr_setprotocol, PTHREAD_PRIO_NONE, check_protocol,
152 	    ARRAY_SIZE(check_protocol), ENOTSUP)) {
153 		ret = EXIT_FAILURE;
154 	}
155 
156 	if (!check_field("robust", &attr, pthread_mutexattr_getrobust,
157 	    pthread_mutexattr_setrobust, PTHREAD_MUTEX_STALLED, check_robust,
158 	    ARRAY_SIZE(check_robust), EINVAL)) {
159 		ret = EXIT_FAILURE;
160 	}
161 
162 	if ((r = pthread_mutexattr_destroy(&attr)) != 0) {
163 		warnc(r, "TEST FAILED: failed to destroy mutex attributes");
164 		ret = EXIT_FAILURE;
165 	}
166 
167 	if (ret == EXIT_SUCCESS) {
168 		(void) printf("All tests passed successfully\n");
169 	}
170 
171 	return (ret);
172 }
173