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