Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests/futex: Refactor futex_requeue_pi with kselftest_harness.h

To reduce the boilerplate code, refactor futex_requeue_pi test to use
kselftest_harness header instead of futex's logging header.

Use kselftest fixture feature to make it easy to repeat the same test
with different parameters. With that, drop all repetitive test calls
from run.sh.

Signed-off-by: André Almeida <andrealmeid@igalia.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>

authored by

André Almeida and committed by
Thomas Gleixner
d060495a f2662ec2

+124 -168
+123 -143
tools/testing/selftests/futex/functional/futex_requeue_pi.c
··· 26 26 #include <stdlib.h> 27 27 #include <signal.h> 28 28 #include <string.h> 29 + 29 30 #include "atomic.h" 30 31 #include "futextest.h" 31 - #include "logging.h" 32 + #include "../../kselftest_harness.h" 32 33 33 - #define TEST_NAME "futex-requeue-pi" 34 34 #define MAX_WAKE_ITERS 1000 35 35 #define THREAD_MAX 10 36 36 #define SIGNAL_PERIOD_US 100 ··· 42 42 futex_t f2 = FUTEX_INITIALIZER; 43 43 futex_t wake_complete = FUTEX_INITIALIZER; 44 44 45 - /* Test option defaults */ 46 - static long timeout_ns; 47 - static int broadcast; 48 - static int owner; 49 - static int locked; 50 - 51 45 struct thread_arg { 52 46 long id; 53 47 struct timespec *timeout; ··· 50 56 }; 51 57 #define THREAD_ARG_INITIALIZER { 0, NULL, 0, 0 } 52 58 53 - void usage(char *prog) 59 + FIXTURE(args) 54 60 { 55 - printf("Usage: %s\n", prog); 56 - printf(" -b Broadcast wakeup (all waiters)\n"); 57 - printf(" -c Use color\n"); 58 - printf(" -h Display this help message\n"); 59 - printf(" -l Lock the pi futex across requeue\n"); 60 - printf(" -o Use a third party pi futex owner during requeue (cancels -l)\n"); 61 - printf(" -t N Timeout in nanoseconds (default: 0)\n"); 62 - printf(" -v L Verbosity level: %d=QUIET %d=CRITICAL %d=INFO\n", 63 - VQUIET, VCRITICAL, VINFO); 64 - } 61 + }; 62 + 63 + FIXTURE_SETUP(args) 64 + { 65 + }; 66 + 67 + FIXTURE_TEARDOWN(args) 68 + { 69 + }; 70 + 71 + FIXTURE_VARIANT(args) 72 + { 73 + long timeout_ns; 74 + bool broadcast; 75 + bool owner; 76 + bool locked; 77 + }; 78 + 79 + /* 80 + * For a given timeout value, this macro creates a test input with all the 81 + * possible combinations of valid arguments 82 + */ 83 + #define FIXTURE_VARIANT_ADD_TIMEOUT(timeout) \ 84 + \ 85 + FIXTURE_VARIANT_ADD(args, t_##timeout) \ 86 + { \ 87 + .timeout_ns = timeout, \ 88 + }; \ 89 + \ 90 + FIXTURE_VARIANT_ADD(args, t_##timeout##_broadcast) \ 91 + { \ 92 + .timeout_ns = timeout, \ 93 + .broadcast = true, \ 94 + }; \ 95 + \ 96 + FIXTURE_VARIANT_ADD(args, t_##timeout##_broadcast_locked) \ 97 + { \ 98 + .timeout_ns = timeout, \ 99 + .broadcast = true, \ 100 + .locked = true, \ 101 + }; \ 102 + \ 103 + FIXTURE_VARIANT_ADD(args, t_##timeout##_broadcast_owner) \ 104 + { \ 105 + .timeout_ns = timeout, \ 106 + .broadcast = true, \ 107 + .owner = true, \ 108 + }; \ 109 + \ 110 + FIXTURE_VARIANT_ADD(args, t_##timeout##_locked) \ 111 + { \ 112 + .timeout_ns = timeout, \ 113 + .locked = true, \ 114 + }; \ 115 + \ 116 + FIXTURE_VARIANT_ADD(args, t_##timeout##_owner) \ 117 + { \ 118 + .timeout_ns = timeout, \ 119 + .owner = true, \ 120 + }; \ 121 + 122 + FIXTURE_VARIANT_ADD_TIMEOUT(0); 123 + FIXTURE_VARIANT_ADD_TIMEOUT(5000); 124 + FIXTURE_VARIANT_ADD_TIMEOUT(500000); 125 + FIXTURE_VARIANT_ADD_TIMEOUT(2000000000); 65 126 66 127 int create_rt_thread(pthread_t *pth, void*(*func)(void *), void *arg, 67 128 int policy, int prio) ··· 130 81 131 82 ret = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); 132 83 if (ret) { 133 - error("pthread_attr_setinheritsched\n", ret); 84 + ksft_exit_fail_msg("pthread_attr_setinheritsched\n"); 134 85 return -1; 135 86 } 136 87 137 88 ret = pthread_attr_setschedpolicy(&attr, policy); 138 89 if (ret) { 139 - error("pthread_attr_setschedpolicy\n", ret); 90 + ksft_exit_fail_msg("pthread_attr_setschedpolicy\n"); 140 91 return -1; 141 92 } 142 93 143 94 schedp.sched_priority = prio; 144 95 ret = pthread_attr_setschedparam(&attr, &schedp); 145 96 if (ret) { 146 - error("pthread_attr_setschedparam\n", ret); 97 + ksft_exit_fail_msg("pthread_attr_setschedparam\n"); 147 98 return -1; 148 99 } 149 100 150 101 ret = pthread_create(pth, &attr, func, arg); 151 102 if (ret) { 152 - error("pthread_create\n", ret); 103 + ksft_exit_fail_msg("pthread_create\n"); 153 104 return -1; 154 105 } 155 106 return 0; ··· 161 112 struct thread_arg *args = (struct thread_arg *)arg; 162 113 futex_t old_val; 163 114 164 - info("Waiter %ld: running\n", args->id); 115 + ksft_print_dbg_msg("Waiter %ld: running\n", args->id); 165 116 /* Each thread sleeps for a different amount of time 166 117 * This is to avoid races, because we don't lock the 167 118 * external mutex here */ ··· 169 120 170 121 old_val = f1; 171 122 atomic_inc(&waiters_blocked); 172 - info("Calling futex_wait_requeue_pi: %p (%u) -> %p\n", 123 + ksft_print_dbg_msg("Calling futex_wait_requeue_pi: %p (%u) -> %p\n", 173 124 &f1, f1, &f2); 174 125 args->ret = futex_wait_requeue_pi(&f1, old_val, &f2, args->timeout, 175 126 FUTEX_PRIVATE_FLAG); 176 127 177 - info("waiter %ld woke with %d %s\n", args->id, args->ret, 128 + ksft_print_dbg_msg("waiter %ld woke with %d %s\n", args->id, args->ret, 178 129 args->ret < 0 ? strerror(errno) : ""); 179 130 atomic_inc(&waiters_woken); 180 131 if (args->ret < 0) { 181 132 if (args->timeout && errno == ETIMEDOUT) 182 133 args->ret = 0; 183 134 else { 184 - args->ret = RET_ERROR; 185 - error("futex_wait_requeue_pi\n", errno); 135 + ksft_exit_fail_msg("futex_wait_requeue_pi\n"); 186 136 } 187 137 futex_lock_pi(&f2, NULL, 0, FUTEX_PRIVATE_FLAG); 188 138 } 189 139 futex_unlock_pi(&f2, FUTEX_PRIVATE_FLAG); 190 140 191 - info("Waiter %ld: exiting with %d\n", args->id, args->ret); 141 + ksft_print_dbg_msg("Waiter %ld: exiting with %d\n", args->id, args->ret); 192 142 pthread_exit((void *)&args->ret); 193 143 } 194 144 ··· 200 152 int nr_wake = 1; 201 153 int i = 0; 202 154 203 - info("Waker: waiting for waiters to block\n"); 155 + ksft_print_dbg_msg("Waker: waiting for waiters to block\n"); 204 156 while (waiters_blocked.val < THREAD_MAX) 205 157 usleep(1000); 206 158 usleep(1000); 207 159 208 - info("Waker: Calling broadcast\n"); 160 + ksft_print_dbg_msg("Waker: Calling broadcast\n"); 209 161 if (args->lock) { 210 - info("Calling FUTEX_LOCK_PI on mutex=%x @ %p\n", f2, &f2); 162 + ksft_print_dbg_msg("Calling FUTEX_LOCK_PI on mutex=%x @ %p\n", f2, &f2); 211 163 futex_lock_pi(&f2, NULL, 0, FUTEX_PRIVATE_FLAG); 212 164 } 213 165 continue_requeue: ··· 215 167 args->ret = futex_cmp_requeue_pi(&f1, old_val, &f2, nr_wake, nr_requeue, 216 168 FUTEX_PRIVATE_FLAG); 217 169 if (args->ret < 0) { 218 - args->ret = RET_ERROR; 219 - error("FUTEX_CMP_REQUEUE_PI failed\n", errno); 170 + ksft_exit_fail_msg("FUTEX_CMP_REQUEUE_PI failed\n"); 220 171 } else if (++i < MAX_WAKE_ITERS) { 221 172 task_count += args->ret; 222 173 if (task_count < THREAD_MAX - waiters_woken.val) 223 174 goto continue_requeue; 224 175 } else { 225 - error("max broadcast iterations (%d) reached with %d/%d tasks woken or requeued\n", 226 - 0, MAX_WAKE_ITERS, task_count, THREAD_MAX); 227 - args->ret = RET_ERROR; 176 + ksft_exit_fail_msg("max broadcast iterations (%d) reached with %d/%d tasks woken or requeued\n", 177 + MAX_WAKE_ITERS, task_count, THREAD_MAX); 228 178 } 229 179 230 180 futex_wake(&wake_complete, 1, FUTEX_PRIVATE_FLAG); ··· 233 187 if (args->ret > 0) 234 188 args->ret = task_count; 235 189 236 - info("Waker: exiting with %d\n", args->ret); 190 + ksft_print_dbg_msg("Waker: exiting with %d\n", args->ret); 237 191 pthread_exit((void *)&args->ret); 238 192 } 239 193 ··· 246 200 int nr_wake = 1; 247 201 int i = 0; 248 202 249 - info("Waker: waiting for waiters to block\n"); 203 + ksft_print_dbg_msg("Waker: waiting for waiters to block\n"); 250 204 while (waiters_blocked.val < THREAD_MAX) 251 205 usleep(1000); 252 206 usleep(1000); 253 207 254 208 while (task_count < THREAD_MAX && waiters_woken.val < THREAD_MAX) { 255 - info("task_count: %d, waiters_woken: %d\n", 209 + ksft_print_dbg_msg("task_count: %d, waiters_woken: %d\n", 256 210 task_count, waiters_woken.val); 257 211 if (args->lock) { 258 - info("Calling FUTEX_LOCK_PI on mutex=%x @ %p\n", 259 - f2, &f2); 212 + ksft_print_dbg_msg("Calling FUTEX_LOCK_PI on mutex=%x @ %p\n", 213 + f2, &f2); 260 214 futex_lock_pi(&f2, NULL, 0, FUTEX_PRIVATE_FLAG); 261 215 } 262 - info("Waker: Calling signal\n"); 216 + ksft_print_dbg_msg("Waker: Calling signal\n"); 263 217 /* cond_signal */ 264 218 old_val = f1; 265 219 args->ret = futex_cmp_requeue_pi(&f1, old_val, &f2, ··· 267 221 FUTEX_PRIVATE_FLAG); 268 222 if (args->ret < 0) 269 223 args->ret = -errno; 270 - info("futex: %x\n", f2); 224 + ksft_print_dbg_msg("futex: %x\n", f2); 271 225 if (args->lock) { 272 - info("Calling FUTEX_UNLOCK_PI on mutex=%x @ %p\n", 273 - f2, &f2); 226 + ksft_print_dbg_msg("Calling FUTEX_UNLOCK_PI on mutex=%x @ %p\n", 227 + f2, &f2); 274 228 futex_unlock_pi(&f2, FUTEX_PRIVATE_FLAG); 275 229 } 276 - info("futex: %x\n", f2); 277 - if (args->ret < 0) { 278 - error("FUTEX_CMP_REQUEUE_PI failed\n", errno); 279 - args->ret = RET_ERROR; 280 - break; 281 - } 230 + ksft_print_dbg_msg("futex: %x\n", f2); 231 + if (args->ret < 0) 232 + ksft_exit_fail_msg("FUTEX_CMP_REQUEUE_PI failed\n"); 282 233 283 234 task_count += args->ret; 284 235 usleep(SIGNAL_PERIOD_US); 285 236 i++; 286 237 /* we have to loop at least THREAD_MAX times */ 287 238 if (i > MAX_WAKE_ITERS + THREAD_MAX) { 288 - error("max signaling iterations (%d) reached, giving up on pending waiters.\n", 289 - 0, MAX_WAKE_ITERS + THREAD_MAX); 290 - args->ret = RET_ERROR; 291 - break; 239 + ksft_exit_fail_msg("max signaling iterations (%d) reached, giving up on pending waiters.\n", 240 + MAX_WAKE_ITERS + THREAD_MAX); 292 241 } 293 242 } 294 243 ··· 292 251 if (args->ret >= 0) 293 252 args->ret = task_count; 294 253 295 - info("Waker: exiting with %d\n", args->ret); 296 - info("Waker: waiters_woken: %d\n", waiters_woken.val); 254 + ksft_print_dbg_msg("Waker: exiting with %d\n", args->ret); 255 + ksft_print_dbg_msg("Waker: waiters_woken: %d\n", waiters_woken.val); 297 256 pthread_exit((void *)&args->ret); 298 257 } 299 258 ··· 310 269 ret2 = futex_unlock_pi(&f2, FUTEX_PRIVATE_FLAG); 311 270 312 271 out: 313 - if (args->ret || ret2) { 314 - error("third_party_blocker() futex error", 0); 315 - args->ret = RET_ERROR; 316 - } 272 + if (args->ret || ret2) 273 + ksft_exit_fail_msg("third_party_blocker() futex error"); 317 274 318 275 pthread_exit((void *)&args->ret); 319 276 } 320 277 321 - int unit_test(int broadcast, long lock, int third_party_owner, long timeout_ns) 278 + TEST_F(args, futex_requeue_pi) 322 279 { 323 - void *(*wakerfn)(void *) = signal_wakerfn; 324 280 struct thread_arg blocker_arg = THREAD_ARG_INITIALIZER; 325 281 struct thread_arg waker_arg = THREAD_ARG_INITIALIZER; 326 282 pthread_t waiter[THREAD_MAX], waker, blocker; 327 - struct timespec ts, *tsp = NULL; 283 + void *(*wakerfn)(void *) = signal_wakerfn; 284 + bool third_party_owner = variant->owner; 285 + long timeout_ns = variant->timeout_ns; 286 + bool broadcast = variant->broadcast; 328 287 struct thread_arg args[THREAD_MAX]; 329 - int *waiter_ret; 330 - int i, ret = RET_PASS; 288 + struct timespec ts, *tsp = NULL; 289 + bool lock = variant->locked; 290 + int *waiter_ret, i, ret = 0; 291 + 292 + ksft_print_msg( 293 + "\tArguments: broadcast=%d locked=%d owner=%d timeout=%ldns\n", 294 + broadcast, lock, third_party_owner, timeout_ns); 331 295 332 296 if (timeout_ns) { 333 297 time_t secs; 334 298 335 - info("timeout_ns = %ld\n", timeout_ns); 299 + ksft_print_dbg_msg("timeout_ns = %ld\n", timeout_ns); 336 300 ret = clock_gettime(CLOCK_MONOTONIC, &ts); 337 301 secs = (ts.tv_nsec + timeout_ns) / 1000000000; 338 302 ts.tv_nsec = ((int64_t)ts.tv_nsec + timeout_ns) % 1000000000; 339 303 ts.tv_sec += secs; 340 - info("ts.tv_sec = %ld\n", ts.tv_sec); 341 - info("ts.tv_nsec = %ld\n", ts.tv_nsec); 304 + ksft_print_dbg_msg("ts.tv_sec = %ld\n", ts.tv_sec); 305 + ksft_print_dbg_msg("ts.tv_nsec = %ld\n", ts.tv_nsec); 342 306 tsp = &ts; 343 307 } 344 308 ··· 353 307 if (third_party_owner) { 354 308 if (create_rt_thread(&blocker, third_party_blocker, 355 309 (void *)&blocker_arg, SCHED_FIFO, 1)) { 356 - error("Creating third party blocker thread failed\n", 357 - errno); 358 - ret = RET_ERROR; 359 - goto out; 310 + ksft_exit_fail_msg("Creating third party blocker thread failed\n"); 360 311 } 361 312 } 362 313 ··· 361 318 for (i = 0; i < THREAD_MAX; i++) { 362 319 args[i].id = i; 363 320 args[i].timeout = tsp; 364 - info("Starting thread %d\n", i); 321 + ksft_print_dbg_msg("Starting thread %d\n", i); 365 322 if (create_rt_thread(&waiter[i], waiterfn, (void *)&args[i], 366 323 SCHED_FIFO, 1)) { 367 - error("Creating waiting thread failed\n", errno); 368 - ret = RET_ERROR; 369 - goto out; 324 + ksft_exit_fail_msg("Creating waiting thread failed\n"); 370 325 } 371 326 } 372 327 waker_arg.lock = lock; 373 328 if (create_rt_thread(&waker, wakerfn, (void *)&waker_arg, 374 329 SCHED_FIFO, 1)) { 375 - error("Creating waker thread failed\n", errno); 376 - ret = RET_ERROR; 377 - goto out; 330 + ksft_exit_fail_msg("Creating waker thread failed\n"); 378 331 } 379 332 380 333 /* Wait for threads to finish */ ··· 384 345 pthread_join(blocker, NULL); 385 346 pthread_join(waker, NULL); 386 347 387 - out: 388 348 if (!ret) { 389 349 if (*waiter_ret) 390 350 ret = *waiter_ret; ··· 393 355 ret = blocker_arg.ret; 394 356 } 395 357 396 - return ret; 358 + if (ret) 359 + ksft_test_result_fail("fail"); 397 360 } 398 361 399 - int main(int argc, char *argv[]) 400 - { 401 - char *test_name; 402 - int c, ret; 403 - 404 - while ((c = getopt(argc, argv, "bchlot:v:")) != -1) { 405 - switch (c) { 406 - case 'b': 407 - broadcast = 1; 408 - break; 409 - case 'c': 410 - log_color(1); 411 - break; 412 - case 'h': 413 - usage(basename(argv[0])); 414 - exit(0); 415 - case 'l': 416 - locked = 1; 417 - break; 418 - case 'o': 419 - owner = 1; 420 - locked = 0; 421 - break; 422 - case 't': 423 - timeout_ns = atoi(optarg); 424 - break; 425 - case 'v': 426 - log_verbosity(atoi(optarg)); 427 - break; 428 - default: 429 - usage(basename(argv[0])); 430 - exit(1); 431 - } 432 - } 433 - 434 - ksft_print_header(); 435 - ksft_set_plan(1); 436 - ksft_print_msg("%s: Test requeue functionality\n", basename(argv[0])); 437 - ksft_print_msg( 438 - "\tArguments: broadcast=%d locked=%d owner=%d timeout=%ldns\n", 439 - broadcast, locked, owner, timeout_ns); 440 - 441 - ret = asprintf(&test_name, 442 - "%s broadcast=%d locked=%d owner=%d timeout=%ldns", 443 - TEST_NAME, broadcast, locked, owner, timeout_ns); 444 - if (ret < 0) { 445 - ksft_print_msg("Failed to generate test name\n"); 446 - test_name = TEST_NAME; 447 - } 448 - 449 - /* 450 - * FIXME: unit_test is obsolete now that we parse options and the 451 - * various style of runs are done by run.sh - simplify the code and move 452 - * unit_test into main() 453 - */ 454 - ret = unit_test(broadcast, locked, owner, timeout_ns); 455 - 456 - print_result(test_name, ret); 457 - return ret; 458 - } 362 + TEST_HARNESS_MAIN
+1 -25
tools/testing/selftests/futex/functional/run.sh
··· 32 32 33 33 34 34 echo 35 - # requeue pi testing 36 - # without timeouts 37 - ./futex_requeue_pi $COLOR 38 - ./futex_requeue_pi $COLOR -b 39 - ./futex_requeue_pi $COLOR -b -l 40 - ./futex_requeue_pi $COLOR -b -o 41 - ./futex_requeue_pi $COLOR -l 42 - ./futex_requeue_pi $COLOR -o 43 - # with timeouts 44 - ./futex_requeue_pi $COLOR -b -l -t 5000 45 - ./futex_requeue_pi $COLOR -l -t 5000 46 - ./futex_requeue_pi $COLOR -b -l -t 500000 47 - ./futex_requeue_pi $COLOR -l -t 500000 48 - ./futex_requeue_pi $COLOR -b -t 5000 49 - ./futex_requeue_pi $COLOR -t 5000 50 - ./futex_requeue_pi $COLOR -b -t 500000 51 - ./futex_requeue_pi $COLOR -t 500000 52 - ./futex_requeue_pi $COLOR -b -o -t 5000 53 - ./futex_requeue_pi $COLOR -l -t 5000 54 - ./futex_requeue_pi $COLOR -b -o -t 500000 55 - ./futex_requeue_pi $COLOR -l -t 500000 56 - # with long timeout 57 - ./futex_requeue_pi $COLOR -b -l -t 2000000000 58 - ./futex_requeue_pi $COLOR -l -t 2000000000 59 - 35 + ./futex_requeue_pi 60 36 61 37 echo 62 38 ./futex_requeue_pi_mismatched_ops $COLOR