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