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 2024 Oxide Computer Company
14 */
15
16 /*
17 * rwlock-specific tests and implementation
18 */
19
20 #include <err.h>
21 #include <stdlib.h>
22 #include <pthread.h>
23 #include <sys/debug.h>
24 #include <sys/sysmacros.h>
25 #include <stdbool.h>
26 #include <errno.h>
27 #include <string.h>
28
29 #include "clock_lock.h"
30
31 static void
clock_rwlock_create(const char * desc,void ** argp)32 clock_rwlock_create(const char *desc, void **argp)
33 {
34 int ret;
35 pthread_rwlock_t *rw;
36
37 rw = calloc(1, sizeof (pthread_rwlock_t));
38 if (rw == NULL) {
39 err(EXIT_FAILURE, "TEST FAILED: %s: failed to allocate memory "
40 "for a rwlock", desc);
41 }
42
43 if ((ret = pthread_rwlock_init(rw, NULL)) != 0) {
44 errc(EXIT_FAILURE, ret, "TEST FAILED: %s: failed to create "
45 "rwlock", desc);
46 }
47
48 *argp = rw;
49 }
50
51 static void
clock_rwlock_destroy(void * arg)52 clock_rwlock_destroy(void *arg)
53 {
54 VERIFY0(pthread_rwlock_destroy(arg));
55 free(arg);
56 }
57
58 static void
clock_rwlock_wrlock(void * arg)59 clock_rwlock_wrlock(void *arg)
60 {
61 VERIFY0(pthread_rwlock_trywrlock(arg));
62 }
63
64 static void
clock_rwlock_unlock(void * arg)65 clock_rwlock_unlock(void *arg)
66 {
67 VERIFY0(pthread_rwlock_unlock(arg));
68 }
69
70 /*
71 * While we have both read and write locks, we use a write lock for lo_lock()
72 * here as that'll ensure that any additional readers or writers will always
73 * block.
74 */
75 const lock_ops_t clock_lock_rwlock_ops = {
76 .lo_create = clock_rwlock_create,
77 .lo_destroy = clock_rwlock_destroy,
78 .lo_lock = clock_rwlock_wrlock,
79 .lo_unlock = clock_rwlock_unlock
80 };
81
82 static bool
clock_test_rwlock_invalid_source(const clock_test_t * test,void * prim)83 clock_test_rwlock_invalid_source(const clock_test_t *test, void *prim)
84 {
85 bool ret = true;
86 pthread_rwlock_t *rwl = prim;
87 const clockid_t clocks[] = { 0x7777, INT32_MAX, 0x23, CLOCK_VIRTUAL,
88 CLOCK_THREAD_CPUTIME_ID, CLOCK_PROCESS_CPUTIME_ID };
89 int p;
90
91 for (size_t i = 0; i < ARRAY_SIZE(clocks); i++) {
92 clockid_t c = clocks[i];
93
94 if ((p = pthread_rwlock_clockrdlock(rwl, c, &clock_to_100ms)) !=
95 EINVAL) {
96 warnx("TEST FAILED: %s: pthread_rwlock_clockrdlock "
97 "with clock 0x%x returned %s, not EINVAL",
98 test->ct_desc, c, strerrorname_np(p));
99 ret = false;
100 }
101
102 if ((p = pthread_rwlock_relclockrdlock_np(rwl, c,
103 &clock_to_100ms)) != EINVAL) {
104 warnx("TEST FAILED: %s: pthread_rwlock_relclockrdlock"
105 "_np with clock 0x%x returned %s, not EINVAL",
106 test->ct_desc, c, strerrorname_np(p));
107 ret = false;
108 }
109
110 if ((p = pthread_rwlock_clockwrlock(rwl, c, &clock_to_100ms)) !=
111 EINVAL) {
112 warnx("TEST FAILED: %s: pthread_rwlock_clockwrlock "
113 "with clock 0x%x returned %s, not EINVAL",
114 test->ct_desc, c, strerrorname_np(p));
115 ret = false;
116 }
117
118 if ((p = pthread_rwlock_relclockwrlock_np(rwl, c,
119 &clock_to_100ms)) != EINVAL) {
120 warnx("TEST FAILED: %s: pthread_rwlock_relclockwrlock"
121 "_np with clock 0x%x returned %s, not EINVAL",
122 test->ct_desc, c, strerrorname_np(p));
123 ret = false;
124 }
125
126 }
127
128 return (ret);
129 }
130
131 static bool
clock_test_rwlock_inv_to_ign_abs(const clock_test_t * test,void * prim)132 clock_test_rwlock_inv_to_ign_abs(const clock_test_t *test, void *prim)
133 {
134 bool ret = true;
135 pthread_rwlock_t *rwl = prim;
136 int p;
137
138 if ((p = pthread_rwlock_timedrdlock(rwl, &clock_to_invns)) != 0) {
139 warnx("TEST FAILED: %s: pthread_rwlock_timedrdlock failed with "
140 "an invalid timeout when the lock when lock was available: "
141 "expected success, found %s", test->ct_desc,
142 strerrorname_np(p));
143 ret = false;
144 } else {
145 test->ct_ops->lo_unlock(rwl);
146 }
147
148 if ((p = pthread_rwlock_clockrdlock(rwl, CLOCK_MONOTONIC,
149 &clock_to_invns)) != 0) {
150 warnx("TEST FAILED: %s: pthread_rwlock_clockrdlock failed with "
151 "an invalid timeout when the lock when lock was available: "
152 "expected success, found %s", test->ct_desc,
153 strerrorname_np(p));
154 ret = false;
155 } else {
156 test->ct_ops->lo_unlock(rwl);
157 }
158
159 if ((p = pthread_rwlock_timedwrlock(rwl, &clock_to_invns)) != 0) {
160 warnx("TEST FAILED: %s: pthread_rwlock_timedwrlock failed with "
161 "an invalid timeout when the lock when lock was available: "
162 "expected success, found %s", test->ct_desc,
163 strerrorname_np(p));
164 ret = false;
165 } else {
166 test->ct_ops->lo_unlock(rwl);
167 }
168
169 if ((p = pthread_rwlock_clockwrlock(rwl, CLOCK_MONOTONIC,
170 &clock_to_invns)) != 0) {
171 warnx("TEST FAILED: %s: pthread_rwlock_clockwrlock failed with "
172 "an invalid timeout when the lock when lock was available: "
173 "expected success, found %s", test->ct_desc,
174 strerrorname_np(p));
175 ret = false;
176 } else {
177 test->ct_ops->lo_unlock(rwl);
178 }
179
180 return (ret);
181 }
182
183 static bool
clock_test_rwlock_inv_to_abs(const clock_test_t * test,void * prim)184 clock_test_rwlock_inv_to_abs(const clock_test_t *test, void *prim)
185 {
186 bool ret = true;
187 pthread_rwlock_t *rwl = prim;
188 int p;
189
190 if ((p = pthread_rwlock_timedrdlock(rwl, &clock_to_invns)) != EINVAL) {
191 warnx("TEST FAILED: %s: pthread_rwlock_timedrdlock with "
192 "invalid timeout returned %s, not EINVAL", test->ct_desc,
193 strerrorname_np(p));
194 ret = false;
195 }
196
197 if ((p = pthread_rwlock_clockrdlock(rwl, CLOCK_MONOTONIC,
198 &clock_to_invns)) != EINVAL) {
199 warnx("TEST FAILED: %s: pthread_rwlock_clockrdlock with "
200 "invalid timeout returned %s, not EINVAL", test->ct_desc,
201 strerrorname_np(p));
202 ret = false;
203 }
204
205 if ((p = pthread_rwlock_timedwrlock(rwl, &clock_to_invns)) != EINVAL) {
206 warnx("TEST FAILED: %s: pthread_rwlock_timedwrlock with "
207 "invalid timeout returned %s, not EINVAL", test->ct_desc,
208 strerrorname_np(p));
209 ret = false;
210 }
211
212 if ((p = pthread_rwlock_clockwrlock(rwl, CLOCK_MONOTONIC,
213 &clock_to_invns)) != EINVAL) {
214 warnx("TEST FAILED: %s: pthread_rwlock_clockwrlock with "
215 "invalid timeout returned %s, not EINVAL", test->ct_desc,
216 strerrorname_np(p));
217 ret = false;
218 }
219
220 return (ret);
221 }
222
223 static bool
clock_test_rwlock_inv_to_ign_rel(const clock_test_t * test,void * prim)224 clock_test_rwlock_inv_to_ign_rel(const clock_test_t *test, void *prim)
225 {
226 bool ret = true;
227 pthread_rwlock_t *rwl = prim;
228 const struct timespec *specs[] = { &clock_to_invns, &clock_to_invnegs,
229 &clock_to_invnegns };
230 const char *descs[] = { "too many nanoseconds", "negative seconds",
231 "negative nanoseconds" };
232 int p;
233
234 for (size_t i = 0; i < ARRAY_SIZE(specs); i++) {
235 if ((p = pthread_rwlock_reltimedrdlock_np(rwl, specs[i])) !=
236 0) {
237 warnx("TEST FAILED: %s: pthread_rwlock_reltimedrdlock"
238 "_np failed with invalid timeout %s when the lock "
239 "when lock was available: expected success, found "
240 "%s", test->ct_desc, descs[i], strerrorname_np(p));
241 ret = false;
242 } else {
243 test->ct_ops->lo_unlock(rwl);
244 }
245
246 if ((p = pthread_rwlock_relclockrdlock_np(rwl, CLOCK_MONOTONIC,
247 specs[i])) != 0) {
248 warnx("TEST FAILED: %s: pthread_rwlock_relclockrdlock"
249 "_np failed with invalid timeout %s when the lock "
250 "when lock was available: expected success, found "
251 "%s", test->ct_desc, descs[i], strerrorname_np(p));
252 ret = false;
253 } else {
254 test->ct_ops->lo_unlock(rwl);
255 }
256
257 if ((p = pthread_rwlock_reltimedwrlock_np(rwl, specs[i])) !=
258 0) {
259 warnx("TEST FAILED: %s: pthread_rwlock_reltimedwrlock"
260 "_np failed with invalid timeout %s when the lock "
261 "when lock was available: expected success, found "
262 "%s", test->ct_desc, descs[i], strerrorname_np(p));
263 ret = false;
264 } else {
265 test->ct_ops->lo_unlock(rwl);
266 }
267
268 if ((p = pthread_rwlock_relclockwrlock_np(rwl, CLOCK_MONOTONIC,
269 specs[i])) != 0) {
270 warnx("TEST FAILED: %s: pthread_rwlock_relclockwrlock"
271 "_np failed with invalid timeout %s when the lock "
272 "when lock was available: expected success, found "
273 "%s", test->ct_desc, descs[i], strerrorname_np(p));
274 ret = false;
275 } else {
276 test->ct_ops->lo_unlock(rwl);
277 }
278 }
279
280 return (ret);
281 }
282
283 static bool
clock_test_rwlock_inv_to_rel(const clock_test_t * test,void * prim)284 clock_test_rwlock_inv_to_rel(const clock_test_t *test, void *prim)
285 {
286 bool ret = true;
287 pthread_rwlock_t *rwl = prim;
288 const struct timespec *specs[] = { &clock_to_invns, &clock_to_invnegs,
289 &clock_to_invnegns };
290 const char *descs[] = { "too many nanoseconds", "negative seconds",
291 "negative nanoseconds" };
292 int p;
293
294 for (size_t i = 0; i < ARRAY_SIZE(specs); i++) {
295 if ((p = pthread_rwlock_reltimedrdlock_np(rwl, specs[i])) !=
296 EINVAL) {
297 warnx("TEST FAILED: %s: pthread_rwlock_reltimedrdlock"
298 "_np with invalid timeout %s returned %s, not "
299 "EINVAL", test->ct_desc, descs[i],
300 strerrorname_np(p));
301 ret = false;
302 }
303
304 if ((p = pthread_rwlock_relclockrdlock_np(rwl, CLOCK_MONOTONIC,
305 specs[i])) != EINVAL) {
306 warnx("TEST FAILED: %s: pthread_rwlock_relclockrdlock"
307 "_np with invalid timeout %s returned %s, not "
308 "EINVAL", test->ct_desc, descs[i],
309 strerrorname_np(p));
310 ret = false;
311 }
312
313 if ((p = pthread_rwlock_reltimedwrlock_np(rwl, specs[i])) !=
314 EINVAL) {
315 warnx("TEST FAILED: %s: pthread_rwlock_reltimedwrlock"
316 "_np with invalid timeout %s returned %s, not "
317 "EINVAL", test->ct_desc, descs[i],
318 strerrorname_np(p));
319 ret = false;
320 }
321
322 if ((p = pthread_rwlock_relclockwrlock_np(rwl, CLOCK_MONOTONIC,
323 specs[i])) != EINVAL) {
324 warnx("TEST FAILED: %s: pthread_rwlock_relclockwrlock"
325 "_np with invalid timeout %s returned %s, not "
326 "EINVAL", test->ct_desc, descs[i],
327 strerrorname_np(p));
328 ret = false;
329 }
330 }
331
332 return (ret);
333 }
334
335 static bool
clock_test_rwlock_to_abs(const clock_test_t * test,void * prim)336 clock_test_rwlock_to_abs(const clock_test_t *test, void *prim)
337 {
338 pthread_rwlock_t *rwl = prim;
339 struct timespec to;
340 int p;
341 bool ret = true, elapse;
342
343 clock_rel_to_abs(CLOCK_REALTIME, &clock_to_100ms, &to);
344 p = pthread_rwlock_timedrdlock(rwl, &to);
345 elapse = clock_abs_after(CLOCK_REALTIME, &to);
346 if (p != ETIMEDOUT) {
347 warnx("TEST FAILED: %s pthread_rwlock_timedrdlock on locked "
348 "rwlock returned %s, not ETIMEDOUT", test->ct_desc,
349 strerrorname_np(p));
350 ret = false;
351 }
352 if (!elapse) {
353 warnx("TEST FAILED: %s: pthread_rwlock_timedrdlock on locked "
354 "rwlock did not block long enough!", test->ct_desc);
355 ret = false;
356 }
357
358 clock_rel_to_abs(CLOCK_REALTIME, &clock_to_100ms, &to);
359 p = pthread_rwlock_clockrdlock(rwl, CLOCK_REALTIME, &to);
360 elapse = clock_abs_after(CLOCK_REALTIME, &to);
361 if (p != ETIMEDOUT) {
362 warnx("TEST FAILED: %s: pthread_rwlock_clockrdlock on locked "
363 "rwlock with CLOCK_REALTIME returned %s, not ETIMEDOUT",
364 test->ct_desc, strerrorname_np(p));
365 ret = false;
366 }
367 if (!elapse) {
368 warnx("TEST FAILED: %s: pthread_rwlock_clockrdlock on locked "
369 "rwlock with CLOCK_REALTIME did not block long enough!",
370 test->ct_desc);
371 ret = false;
372 }
373
374 clock_rel_to_abs(CLOCK_HIGHRES, &clock_to_100ms, &to);
375 p = pthread_rwlock_clockrdlock(rwl, CLOCK_HIGHRES, &to);
376 elapse = clock_abs_after(CLOCK_HIGHRES, &to);
377 if (p != ETIMEDOUT) {
378 warnx("TEST FAILED: %s: pthread_rwlock_clockrdlock on locked "
379 "rwlock with CLOCK_HIGHRES returned %s, not ETIMEDOUT",
380 test->ct_desc, strerrorname_np(p));
381 ret = false;
382 }
383 if (!elapse) {
384 warnx("TEST FAILED: %s: pthread_rwlock_clockrdlock on locked "
385 "rwlock with CLOCK_HIGHRES did not block long enough!",
386 test->ct_desc);
387 ret = false;
388 }
389
390 clock_rel_to_abs(CLOCK_REALTIME, &clock_to_100ms, &to);
391 p = pthread_rwlock_timedwrlock(rwl, &to);
392 elapse = clock_abs_after(CLOCK_REALTIME, &to);
393 if (p != ETIMEDOUT) {
394 warnx("TEST FAILED: %s pthread_rwlock_timedwrlock on locked "
395 "rwlock returned %s, not ETIMEDOUT", test->ct_desc,
396 strerrorname_np(p));
397 ret = false;
398 }
399 if (!elapse) {
400 warnx("TEST FAILED: %s: pthread_rwlock_timedwrlock on locked "
401 "rwlock did not block long enough!", test->ct_desc);
402 ret = false;
403 }
404
405 clock_rel_to_abs(CLOCK_REALTIME, &clock_to_100ms, &to);
406 p = pthread_rwlock_clockwrlock(rwl, CLOCK_REALTIME, &to);
407 elapse = clock_abs_after(CLOCK_REALTIME, &to);
408 if (p != ETIMEDOUT) {
409 warnx("TEST FAILED: %s: pthread_rwlock_clockwrlock on locked "
410 "rwlock with CLOCK_REALTIME returned %s, not ETIMEDOUT",
411 test->ct_desc, strerrorname_np(p));
412 ret = false;
413 }
414 if (!elapse) {
415 warnx("TEST FAILED: %s: pthread_rwlock_clockwrlock on locked "
416 "rwlock with CLOCK_REALTIME did not block long enough!",
417 test->ct_desc);
418 ret = false;
419 }
420
421 clock_rel_to_abs(CLOCK_HIGHRES, &clock_to_100ms, &to);
422 p = pthread_rwlock_clockwrlock(rwl, CLOCK_HIGHRES, &to);
423 elapse = clock_abs_after(CLOCK_HIGHRES, &to);
424 if (p != ETIMEDOUT) {
425 warnx("TEST FAILED: %s: pthread_rwlock_clockwrlock on locked "
426 "rwlock with CLOCK_HIGHRES returned %s, not ETIMEDOUT",
427 test->ct_desc, strerrorname_np(p));
428 ret = false;
429 }
430 if (!elapse) {
431 warnx("TEST FAILED: %s: pthread_rwlock_clockwrlock on locked "
432 "rwlock with CLOCK_HIGHRES did not block long enough!",
433 test->ct_desc);
434 ret = false;
435 }
436
437
438 return (ret);
439 }
440
441 static bool
clock_test_rwlock_to_rel(const clock_test_t * test,void * prim)442 clock_test_rwlock_to_rel(const clock_test_t *test, void *prim)
443 {
444 pthread_rwlock_t *rwl = prim;
445 struct timespec start;
446 int p;
447 bool ret = true, elapse;
448
449 if (clock_gettime(CLOCK_REALTIME, &start) != 0) {
450 err(EXIT_FAILURE, "failed to read clock %d", CLOCK_REALTIME);
451 }
452 p = pthread_rwlock_reltimedrdlock_np(rwl, &clock_to_100ms);
453 elapse = clock_rel_after(CLOCK_REALTIME, &start, &clock_to_100ms);
454 if (p != ETIMEDOUT) {
455 warnx("TEST FAILED: %s: pthread_rwlock_reltimedrdlock_np on "
456 "locked rwlock returned %s, not ETIMEDOUT", test->ct_desc,
457 strerrorname_np(p));
458 ret = false;
459 }
460 if (!elapse) {
461 warnx("TEST FAILED: %s: pthread_rwlock_reltimedrdlock_np on "
462 "locked rwlock did not block long enough!", test->ct_desc);
463 ret = false;
464 }
465
466 if (clock_gettime(CLOCK_REALTIME, &start) != 0) {
467 err(EXIT_FAILURE, "failed to read clock %d", CLOCK_REALTIME);
468 }
469 p = pthread_rwlock_relclockrdlock_np(rwl, CLOCK_REALTIME,
470 &clock_to_100ms);
471 elapse = clock_rel_after(CLOCK_REALTIME, &start, &clock_to_100ms);
472 if (p != ETIMEDOUT) {
473 warnx("TEST FAILED: %s: pthread_rwlock_relclockrdlock_np on "
474 "locked rwlock with CLOCK_REALTIME returned %s, not "
475 "ETIMEDOUT", test->ct_desc, strerrorname_np(p));
476 ret = false;
477 }
478 if (!elapse) {
479 warnx("TEST FAILED: %s: pthread_rwlock_relclockrdlock_np on "
480 "locked " "rwlock with CLOCK_REALTIME did not block long "
481 "enough!", test->ct_desc);
482 ret = false;
483 }
484
485 if (clock_gettime(CLOCK_HIGHRES, &start) != 0) {
486 err(EXIT_FAILURE, "failed to read clock %d", CLOCK_HIGHRES);
487 }
488 p = pthread_rwlock_relclockrdlock_np(rwl, CLOCK_HIGHRES,
489 &clock_to_100ms);
490 elapse = clock_rel_after(CLOCK_HIGHRES, &start, &clock_to_100ms);
491 if (p != ETIMEDOUT) {
492 warnx("TEST FAILED: %s: pthread_rwlock_relclockrdlock_np on "
493 "locked rwlock with CLOCK_HIGHRES returned %s, not "
494 "ETIMEDOUT", test->ct_desc, strerrorname_np(p));
495 ret = false;
496 }
497 if (!elapse) {
498 warnx("TEST FAILED: %s: pthread_rwlock_relclockrdlock_np on "
499 "locked rwlock with CLOCK_HIGHRES did not block long "
500 "enough!", test->ct_desc);
501 ret = false;
502 }
503
504 if (clock_gettime(CLOCK_REALTIME, &start) != 0) {
505 err(EXIT_FAILURE, "failed to read clock %d", CLOCK_REALTIME);
506 }
507 p = pthread_rwlock_reltimedwrlock_np(rwl, &clock_to_100ms);
508 elapse = clock_rel_after(CLOCK_REALTIME, &start, &clock_to_100ms);
509 if (p != ETIMEDOUT) {
510 warnx("TEST FAILED: %s: pthread_rwlock_reltimedwrlock_np on "
511 "locked rwlock returned %s, not ETIMEDOUT", test->ct_desc,
512 strerrorname_np(p));
513 ret = false;
514 }
515 if (!elapse) {
516 warnx("TEST FAILED: %s: pthread_rwlock_reltimedwrlock_np on "
517 "locked " "rwlock did not block long enough!",
518 test->ct_desc);
519 ret = false;
520 }
521
522 if (clock_gettime(CLOCK_REALTIME, &start) != 0) {
523 err(EXIT_FAILURE, "failed to read clock %d", CLOCK_REALTIME);
524 }
525 p = pthread_rwlock_relclockwrlock_np(rwl, CLOCK_REALTIME,
526 &clock_to_100ms);
527 elapse = clock_rel_after(CLOCK_REALTIME, &start, &clock_to_100ms);
528 if (p != ETIMEDOUT) {
529 warnx("TEST FAILED: %s: pthread_rwlock_relclockwrlock_np on "
530 "locked rwlock with CLOCK_REALTIME returned %s, not "
531 "ETIMEDOUT", test->ct_desc, strerrorname_np(p));
532 ret = false;
533 }
534 if (!elapse) {
535 warnx("TEST FAILED: %s: pthread_rwlock_relclockwrlock_np on "
536 "locked " "rwlock with CLOCK_REALTIME did not block long "
537 "enough!", test->ct_desc);
538 ret = false;
539 }
540
541 if (clock_gettime(CLOCK_HIGHRES, &start) != 0) {
542 err(EXIT_FAILURE, "failed to read clock %d", CLOCK_HIGHRES);
543 }
544 p = pthread_rwlock_relclockwrlock_np(rwl, CLOCK_HIGHRES,
545 &clock_to_100ms);
546 elapse = clock_rel_after(CLOCK_HIGHRES, &start, &clock_to_100ms);
547 if (p != ETIMEDOUT) {
548 warnx("TEST FAILED: %s: pthread_rwlock_relclockwrlock_np on "
549 "locked rwlock with CLOCK_HIGHRES returned %s, not "
550 "ETIMEDOUT", test->ct_desc, strerrorname_np(p));
551 ret = false;
552 }
553 if (!elapse) {
554 warnx("TEST FAILED: %s: pthread_rwlock_relclockwrlock_np on "
555 "locked rwlock with CLOCK_HIGHRES did not block long "
556 "enough!", test->ct_desc);
557 ret = false;
558 }
559
560 return (ret);
561 }
562 const clock_test_t clock_rwlock_tests[] = { {
563 .ct_desc = "rwlock: invalid and unsupported clock sources",
564 .ct_ops = &clock_lock_rwlock_ops,
565 .ct_test = clock_test_rwlock_invalid_source
566 }, {
567 .ct_desc = "rwlock: invalid timeout works if lock available (absolute)",
568 .ct_ops = &clock_lock_rwlock_ops,
569 .ct_test = clock_test_rwlock_inv_to_ign_abs
570 }, {
571 .ct_desc = "rwlock: invalid timeout works if lock available (relative)",
572 .ct_ops = &clock_lock_rwlock_ops,
573 .ct_test = clock_test_rwlock_inv_to_ign_rel
574 }, {
575 .ct_desc = "rwlock: invalid timeout fails if lock taken (absolute)",
576 .ct_ops = &clock_lock_rwlock_ops,
577 .ct_test = clock_test_rwlock_inv_to_abs,
578 .ct_enter = true
579 }, {
580 .ct_desc = "rwlock: invalid timeout fails if lock taken (relative)",
581 .ct_ops = &clock_lock_rwlock_ops,
582 .ct_test = clock_test_rwlock_inv_to_rel,
583 .ct_enter = true
584 }, {
585 .ct_desc = "rwlock: timeout fires correctly (absolute)",
586 .ct_ops = &clock_lock_rwlock_ops,
587 .ct_test = clock_test_rwlock_to_abs,
588 .ct_enter = true
589 }, {
590 .ct_desc = "rwlock: timeout fires correctly (relative)",
591 .ct_ops = &clock_lock_rwlock_ops,
592 .ct_test = clock_test_rwlock_to_rel,
593 .ct_enter = true
594 } };
595
596 size_t clock_rwlock_ntests = ARRAY_SIZE(clock_rwlock_tests);
597