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 2017 Joyent, Inc. 14 */ 15 16 /* 17 * Validate various C11 threads routines. Specifically we want to cover: 18 * 19 * o threads 20 * o mutexes 21 * o condition variables 22 */ 23 24 #include <threads.h> 25 #include <sys/debug.h> 26 #include <stdlib.h> 27 #include <unistd.h> 28 29 #define STRESS_NTHREADS 128 30 #define STRESS_COUNT 1000 31 32 static mtx_t stress_mtx; 33 static int stress_count; 34 35 #define BROADCAST_NTHREADS 128 36 37 static mtx_t broadcast_mtx; 38 static cnd_t broadcast_cnd; 39 static boolean_t broadcast_done; 40 41 #define SIGNAL_NTHREADS 128 42 43 static mtx_t signal_mtx; 44 static cnd_t signal_cnd; 45 static boolean_t signal_done; 46 47 /* 48 * This thread should only ever be used for detach. 49 */ 50 static int 51 cthr_test_sleep_thr(void *arg) 52 { 53 for (;;) { 54 sleep(1000); 55 } 56 57 abort(); 58 } 59 60 static void 61 cthr_test_mtx_init(void) 62 { 63 mtx_t mtx; 64 65 VERIFY3S(mtx_init(&mtx, mtx_plain), ==, thrd_success); 66 mtx_destroy(&mtx); 67 VERIFY3S(mtx_init(&mtx, mtx_timed), ==, thrd_success); 68 mtx_destroy(&mtx); 69 VERIFY3S(mtx_init(&mtx, mtx_plain | mtx_recursive), ==, thrd_success); 70 mtx_destroy(&mtx); 71 VERIFY3S(mtx_init(&mtx, mtx_timed | mtx_recursive), ==, thrd_success); 72 mtx_destroy(&mtx); 73 74 VERIFY3S(mtx_init(&mtx, UINT32_MAX), ==, thrd_error); 75 VERIFY3S(mtx_init(&mtx, 42), ==, thrd_error); 76 } 77 78 static void 79 cthr_test_mtx_lockrec(void) 80 { 81 mtx_t mtx; 82 83 VERIFY3S(mtx_init(&mtx, mtx_plain | mtx_recursive), ==, thrd_success); 84 VERIFY3S(mtx_lock(&mtx), ==, thrd_success); 85 VERIFY3S(mtx_lock(&mtx), ==, thrd_success); 86 VERIFY3S(mtx_trylock(&mtx), ==, thrd_success); 87 VERIFY3S(mtx_unlock(&mtx), ==, thrd_success); 88 VERIFY3S(mtx_unlock(&mtx), ==, thrd_success); 89 VERIFY3S(mtx_unlock(&mtx), ==, thrd_success); 90 mtx_destroy(&mtx); 91 } 92 93 static void 94 cthr_test_mtx_trylock(void) 95 { 96 mtx_t mtx; 97 98 VERIFY3S(mtx_init(&mtx, mtx_plain), ==, thrd_success); 99 VERIFY3S(mtx_trylock(&mtx), ==, thrd_success); 100 VERIFY3S(mtx_trylock(&mtx), ==, thrd_busy); 101 VERIFY3S(mtx_unlock(&mtx), ==, thrd_success); 102 mtx_destroy(&mtx); 103 } 104 105 static int 106 cthr_test_stress_thr(void *arg) 107 { 108 int i; 109 int *ip = arg; 110 111 for (i = 0; i < STRESS_COUNT; i++) { 112 VERIFY3S(mtx_lock(&stress_mtx), ==, thrd_success); 113 *ip = *ip + 1; 114 VERIFY3S(mtx_unlock(&stress_mtx), ==, thrd_success); 115 } 116 117 return (0); 118 } 119 120 static void 121 cthr_test_stress(void) 122 { 123 int i; 124 thrd_t threads[STRESS_NTHREADS]; 125 126 VERIFY3S(mtx_init(&stress_mtx, mtx_plain), ==, thrd_success); 127 for (i = 0; i < STRESS_NTHREADS; i++) { 128 VERIFY3S(thrd_create(&threads[i], cthr_test_stress_thr, 129 &stress_count), ==, thrd_success); 130 } 131 132 for (i = 0; i < STRESS_NTHREADS; i++) { 133 VERIFY3S(thrd_join(threads[i], NULL), ==, thrd_success); 134 } 135 mtx_destroy(&stress_mtx); 136 137 VERIFY3S(stress_count, ==, STRESS_NTHREADS * STRESS_COUNT); 138 } 139 140 static void 141 cthr_test_equal(void) 142 { 143 thrd_t self, other; 144 145 self = thrd_current(); 146 147 VERIFY3S(thrd_equal(self, self), !=, 0); 148 VERIFY3S(thrd_create(&other, cthr_test_sleep_thr, NULL), ==, 149 thrd_success); 150 VERIFY3S(thrd_equal(self, other), ==, 0); 151 VERIFY3S(thrd_equal(other, other), !=, 0); 152 VERIFY3S(thrd_detach(other), ==, thrd_success); 153 } 154 155 static void 156 cthr_test_detach_err(void) 157 { 158 thrd_t self, other; 159 160 self = thrd_current(); 161 162 VERIFY3S(thrd_equal(self, self), !=, 0); 163 VERIFY3S(thrd_create(&other, cthr_test_sleep_thr, NULL), ==, 164 thrd_success); 165 VERIFY3S(thrd_detach(other), ==, thrd_success); 166 167 VERIFY3S(thrd_join(self, NULL), ==, thrd_error); 168 VERIFY3S(thrd_join(other, NULL), ==, thrd_error); 169 } 170 171 static int 172 cthr_test_detach_thr0(void *arg) 173 { 174 thrd_exit(23); 175 abort(); 176 } 177 178 static int 179 cthr_test_detach_thr1(void *arg) 180 { 181 return (42); 182 } 183 184 static void 185 cthr_test_detach(void) 186 { 187 int status; 188 thrd_t thrd; 189 190 VERIFY3S(thrd_create(&thrd, cthr_test_detach_thr0, NULL), ==, 191 thrd_success); 192 VERIFY3S(thrd_join(thrd, &status), ==, thrd_success); 193 VERIFY3S(status, ==, 23); 194 195 VERIFY3S(thrd_create(&thrd, cthr_test_detach_thr1, NULL), ==, 196 thrd_success); 197 VERIFY3S(thrd_join(thrd, &status), ==, thrd_success); 198 VERIFY3S(status, ==, 42); 199 } 200 201 static void 202 cthr_test_sleep(void) 203 { 204 struct timespec ts; 205 hrtime_t start, end; 206 long stime = 10 * NANOSEC / MILLISEC; 207 208 ts.tv_sec = 1; 209 ts.tv_nsec = -1; 210 211 VERIFY3S(thrd_sleep(&ts, NULL), <, -1); 212 213 ts.tv_sec = 0; 214 ts.tv_nsec = stime; 215 start = gethrtime(); 216 VERIFY3S(thrd_sleep(&ts, NULL), ==, 0); 217 end = gethrtime(); 218 219 VERIFY3S(end - start, >, stime); 220 } 221 222 static int 223 cthr_test_broadcast_thr(void *arg) 224 { 225 VERIFY3S(mtx_lock(&broadcast_mtx), ==, thrd_success); 226 while (broadcast_done == B_FALSE) 227 VERIFY3S(cnd_wait(&broadcast_cnd, &broadcast_mtx), ==, 228 thrd_success); 229 VERIFY3S(mtx_unlock(&broadcast_mtx), ==, thrd_success); 230 231 return (0); 232 } 233 234 static void 235 cthr_test_broadcast(void) 236 { 237 int i; 238 thrd_t threads[BROADCAST_NTHREADS]; 239 240 VERIFY3S(mtx_init(&broadcast_mtx, mtx_plain), ==, thrd_success); 241 VERIFY3S(cnd_init(&broadcast_cnd), ==, thrd_success); 242 for (i = 0; i < BROADCAST_NTHREADS; i++) { 243 VERIFY3S(thrd_create(&threads[i], cthr_test_broadcast_thr, 244 NULL), ==, thrd_success); 245 } 246 247 VERIFY3S(mtx_lock(&broadcast_mtx), ==, thrd_success); 248 broadcast_done = B_TRUE; 249 VERIFY3S(mtx_unlock(&broadcast_mtx), ==, thrd_success); 250 VERIFY3S(cnd_broadcast(&broadcast_cnd), ==, thrd_success); 251 252 for (i = 0; i < STRESS_NTHREADS; i++) { 253 VERIFY3S(thrd_join(threads[i], NULL), ==, thrd_success); 254 } 255 256 mtx_destroy(&broadcast_mtx); 257 cnd_destroy(&broadcast_cnd); 258 } 259 260 261 static int 262 cthr_test_signal_thr(void *arg) 263 { 264 VERIFY3S(mtx_lock(&signal_mtx), ==, thrd_success); 265 while (signal_done == B_FALSE) 266 VERIFY3S(cnd_wait(&signal_cnd, &signal_mtx), ==, 267 thrd_success); 268 VERIFY3S(mtx_unlock(&signal_mtx), ==, thrd_success); 269 VERIFY3S(cnd_signal(&signal_cnd), ==, thrd_success); 270 271 return (0); 272 } 273 274 static void 275 cthr_test_signal(void) 276 { 277 int i; 278 thrd_t threads[SIGNAL_NTHREADS]; 279 280 VERIFY3S(mtx_init(&signal_mtx, mtx_plain), ==, thrd_success); 281 VERIFY3S(cnd_init(&signal_cnd), ==, thrd_success); 282 for (i = 0; i < SIGNAL_NTHREADS; i++) { 283 VERIFY3S(thrd_create(&threads[i], cthr_test_signal_thr, NULL), 284 ==, thrd_success); 285 } 286 287 VERIFY3S(mtx_lock(&signal_mtx), ==, thrd_success); 288 signal_done = B_TRUE; 289 VERIFY3S(mtx_unlock(&signal_mtx), ==, thrd_success); 290 VERIFY3S(cnd_signal(&signal_cnd), ==, thrd_success); 291 292 for (i = 0; i < STRESS_NTHREADS; i++) { 293 VERIFY3S(thrd_join(threads[i], NULL), ==, thrd_success); 294 } 295 296 mtx_destroy(&signal_mtx); 297 cnd_destroy(&signal_cnd); 298 } 299 300 static void 301 cthr_test_cndtime(void) 302 { 303 mtx_t mtx; 304 cnd_t cnd; 305 struct timespec ts; 306 307 ts.tv_sec = 0; 308 ts.tv_nsec = 1 * NANOSEC / MILLISEC; 309 VERIFY3S(mtx_init(&mtx, mtx_plain), ==, thrd_success); 310 VERIFY3S(cnd_init(&cnd), ==, thrd_success); 311 312 VERIFY3S(mtx_lock(&mtx), ==, thrd_success); 313 VERIFY3S(cnd_timedwait(&cnd, &mtx, &ts), ==, thrd_timedout); 314 VERIFY3S(mtx_unlock(&mtx), ==, thrd_success); 315 316 mtx_destroy(&mtx); 317 cnd_destroy(&cnd); 318 } 319 320 static void 321 cthr_test_mtx_selftime(void) 322 { 323 mtx_t mtx; 324 struct timespec ts; 325 326 ts.tv_sec = 0; 327 ts.tv_nsec = 1 * NANOSEC / MILLISEC; 328 VERIFY3S(mtx_init(&mtx, mtx_timed), ==, thrd_success); 329 VERIFY3S(mtx_lock(&mtx), ==, thrd_success); 330 VERIFY3S(mtx_timedlock(&mtx, &ts), ==, thrd_timedout); 331 VERIFY3S(mtx_unlock(&mtx), ==, thrd_success); 332 mtx_destroy(&mtx); 333 } 334 335 static int 336 cthr_test_mtx_busy_thr(void *arg) 337 { 338 mtx_t *mtx = arg; 339 struct timespec ts; 340 341 ts.tv_sec = 0; 342 ts.tv_nsec = 1 * NANOSEC / MILLISEC; 343 344 VERIFY3S(mtx_trylock(mtx), ==, thrd_busy); 345 VERIFY3S(mtx_timedlock(mtx, &ts), ==, thrd_timedout); 346 347 return (0); 348 } 349 350 static void 351 cthr_test_mtx_busy(void) 352 { 353 mtx_t mtx; 354 thrd_t thrd; 355 356 VERIFY3S(mtx_init(&mtx, mtx_timed), ==, thrd_success); 357 VERIFY3S(mtx_lock(&mtx), ==, thrd_success); 358 359 VERIFY3S(thrd_create(&thrd, cthr_test_mtx_busy_thr, &mtx), ==, 360 thrd_success); 361 VERIFY3S(thrd_join(thrd, NULL), ==, thrd_success); 362 363 VERIFY3S(mtx_unlock(&mtx), ==, thrd_success); 364 mtx_destroy(&mtx); 365 } 366 367 int 368 main(void) 369 { 370 cthr_test_mtx_init(); 371 cthr_test_mtx_lockrec(); 372 cthr_test_mtx_trylock(); 373 cthr_test_stress(); 374 cthr_test_equal(); 375 cthr_test_detach_err(); 376 cthr_test_detach(); 377 cthr_test_sleep(); 378 cthr_test_broadcast(); 379 cthr_test_signal(); 380 cthr_test_cndtime(); 381 cthr_test_mtx_selftime(); 382 cthr_test_mtx_busy(); 383 384 return (0); 385 } 386