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

selftests: Add futex functional tests

The futextest testsuite [1] provides functional, stress, and
performance tests for the various futex op codes. Those tests will be of
more use to futex developers if they are included with the kernel
source.

Copy the core infrastructure and the functional tests into selftests,
but adapt them for inclusion in the kernel:

- Update the Makefile to include the run_tests target, remove reference
to the performance and stress tests from the contributed sources.
- Replace my dead IBM email address with my current Intel email address.
- Remove the warrantee and write-to paragraphs from the license blurbs.
- Remove the NAME section as the filename is easily determined. ;-)
- Make the whitespace usage consistent in a couple of places.
- Cleanup various CodingStyle violations.

A future effort will explore moving the performance and stress tests
into the kernel.

1. http://git.kernel.org/cgit/linux/kernel/git/dvhart/futextest.git

Cc: Shuah Khan <shuahkh@osg.samsung.com>
Cc: linux-api@vger.kernel.org
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Davidlohr Bueso <dave@stgolabs.net>
Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Signed-off-by: Darren Hart <dvhart@linux.intel.com>
Signed-off-by: Shuah Khan <shuahkh@osg.samsung.com>

authored by

Darren Hart and committed by
Shuah Khan
2aa8470f 61171d04

+1889
+11
tools/testing/selftests/futex/Makefile
··· 1 + SUBDIRS := functional 2 + 3 + .PHONY: all clean 4 + all: 5 + for DIR in $(SUBDIRS); do $(MAKE) -C $$DIR $@ ; done 6 + 7 + run_tests: all 8 + ./run.sh 9 + 10 + clean: 11 + for DIR in $(SUBDIRS); do $(MAKE) -C $$DIR $@ ; done
+62
tools/testing/selftests/futex/README
··· 1 + Futex Test 2 + ========== 3 + Futex Test is intended to thoroughly test the Linux kernel futex system call 4 + API. 5 + 6 + Functional tests shall test the documented behavior of the futex operation 7 + code under test. This includes checking for proper behavior under normal use, 8 + odd corner cases, regression tests, and abject abuse and misuse. 9 + 10 + Futextest will also provide example implementation of mutual exclusion 11 + primitives. These can be used as is in user applications or can serve as 12 + examples for system libraries. These will likely be added to either a new lib/ 13 + directory or purely as header files under include/, I'm leaning toward the 14 + latter. 15 + 16 + Quick Start 17 + ----------- 18 + # make 19 + # ./run.sh 20 + 21 + Design and Implementation Goals 22 + ------------------------------- 23 + o Tests should be as self contained as is practical so as to facilitate sharing 24 + the individual tests on mailing list discussions and bug reports. 25 + o The build system shall remain as simple as possible, avoiding any archive or 26 + shared object building and linking. 27 + o Where possible, any helper functions or other package-wide code shall be 28 + implemented in header files, avoiding the need to compile intermediate object 29 + files. 30 + o External dependendencies shall remain as minimal as possible. Currently gcc 31 + and glibc are the only dependencies. 32 + o Tests return 0 for success and < 0 for failure. 33 + 34 + Output Formatting 35 + ----------------- 36 + Test output shall be easily parsable by both human and machine. Title and 37 + results are printed to stdout, while intermediate ERROR or FAIL messages are 38 + sent to stderr. Tests shall support the -c option to print PASS, FAIL, and 39 + ERROR strings in color for easy visual parsing. Output shall conform to the 40 + following format: 41 + 42 + test_name: Description of the test 43 + Arguments: arg1=val1 #units specified for clarity where appropriate 44 + ERROR: Description of unexpected error 45 + FAIL: Reason for test failure 46 + # FIXME: Perhaps an " INFO: informational message" option would be 47 + # useful here. Using -v to toggle it them on and off, as with -c. 48 + # there may be multiple ERROR or FAIL messages 49 + Result: (PASS|FAIL|ERROR) 50 + 51 + Naming 52 + ------ 53 + o FIXME: decide on a sane test naming scheme. Currently the tests are named 54 + based on the primary futex operation they test. Eventually this will become a 55 + problem as we intend to write multiple tests which collide in this namespace. 56 + Perhaps something like "wait-wake-1" "wait-wake-2" is adequate, leaving the 57 + detailed description in the test source and the output. 58 + 59 + Coding Style 60 + ------------ 61 + o The Futex Test project adheres to the coding standards set forth by Linux 62 + kernel as defined in the Linux source Documentation/CodingStyle.
+24
tools/testing/selftests/futex/functional/Makefile
··· 1 + INCLUDES := -I../include 2 + CFLAGS := $(CFLAGS) -g -O2 -Wall -D_GNU_SOURCE -pthread $(INCLUDES) 3 + LDFLAGS := $(LDFLAGS) -pthread -lrt 4 + 5 + HEADERS := ../include/futextest.h 6 + TARGETS := \ 7 + futex_wait_timeout \ 8 + futex_wait_wouldblock \ 9 + futex_requeue_pi \ 10 + futex_requeue_pi_signal_restart \ 11 + futex_requeue_pi_mismatched_ops \ 12 + futex_wait_uninitialized_heap \ 13 + futex_wait_private_mapped_file 14 + 15 + .PHONY: all clean 16 + all: $(TARGETS) 17 + 18 + $(TARGETS): $(HEADERS) 19 + 20 + run_tests: all 21 + ./run.sh 22 + 23 + clean: 24 + rm -f $(TARGETS)
+409
tools/testing/selftests/futex/functional/futex_requeue_pi.c
··· 1 + /****************************************************************************** 2 + * 3 + * Copyright © International Business Machines Corp., 2006-2008 4 + * 5 + * This program is free software; you can redistribute it and/or modify 6 + * it under the terms of the GNU General Public License as published by 7 + * the Free Software Foundation; either version 2 of the License, or 8 + * (at your option) any later version. 9 + * 10 + * DESCRIPTION 11 + * This test excercises the futex syscall op codes needed for requeuing 12 + * priority inheritance aware POSIX condition variables and mutexes. 13 + * 14 + * AUTHORS 15 + * Sripathi Kodi <sripathik@in.ibm.com> 16 + * Darren Hart <dvhart@linux.intel.com> 17 + * 18 + * HISTORY 19 + * 2008-Jan-13: Initial version by Sripathi Kodi <sripathik@in.ibm.com> 20 + * 2009-Nov-6: futex test adaptation by Darren Hart <dvhart@linux.intel.com> 21 + * 22 + *****************************************************************************/ 23 + 24 + #include <errno.h> 25 + #include <limits.h> 26 + #include <pthread.h> 27 + #include <stdio.h> 28 + #include <stdlib.h> 29 + #include <signal.h> 30 + #include <string.h> 31 + #include "atomic.h" 32 + #include "futextest.h" 33 + #include "logging.h" 34 + 35 + #define MAX_WAKE_ITERS 1000 36 + #define THREAD_MAX 10 37 + #define SIGNAL_PERIOD_US 100 38 + 39 + atomic_t waiters_blocked = ATOMIC_INITIALIZER; 40 + atomic_t waiters_woken = ATOMIC_INITIALIZER; 41 + 42 + futex_t f1 = FUTEX_INITIALIZER; 43 + futex_t f2 = FUTEX_INITIALIZER; 44 + futex_t wake_complete = FUTEX_INITIALIZER; 45 + 46 + /* Test option defaults */ 47 + static long timeout_ns; 48 + static int broadcast; 49 + static int owner; 50 + static int locked; 51 + 52 + struct thread_arg { 53 + long id; 54 + struct timespec *timeout; 55 + int lock; 56 + int ret; 57 + }; 58 + #define THREAD_ARG_INITIALIZER { 0, NULL, 0, 0 } 59 + 60 + void usage(char *prog) 61 + { 62 + printf("Usage: %s\n", prog); 63 + printf(" -b Broadcast wakeup (all waiters)\n"); 64 + printf(" -c Use color\n"); 65 + printf(" -h Display this help message\n"); 66 + printf(" -l Lock the pi futex across requeue\n"); 67 + printf(" -o Use a third party pi futex owner during requeue (cancels -l)\n"); 68 + printf(" -t N Timeout in nanoseconds (default: 0)\n"); 69 + printf(" -v L Verbosity level: %d=QUIET %d=CRITICAL %d=INFO\n", 70 + VQUIET, VCRITICAL, VINFO); 71 + } 72 + 73 + int create_rt_thread(pthread_t *pth, void*(*func)(void *), void *arg, 74 + int policy, int prio) 75 + { 76 + int ret; 77 + struct sched_param schedp; 78 + pthread_attr_t attr; 79 + 80 + pthread_attr_init(&attr); 81 + memset(&schedp, 0, sizeof(schedp)); 82 + 83 + ret = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); 84 + if (ret) { 85 + error("pthread_attr_setinheritsched\n", ret); 86 + return -1; 87 + } 88 + 89 + ret = pthread_attr_setschedpolicy(&attr, policy); 90 + if (ret) { 91 + error("pthread_attr_setschedpolicy\n", ret); 92 + return -1; 93 + } 94 + 95 + schedp.sched_priority = prio; 96 + ret = pthread_attr_setschedparam(&attr, &schedp); 97 + if (ret) { 98 + error("pthread_attr_setschedparam\n", ret); 99 + return -1; 100 + } 101 + 102 + ret = pthread_create(pth, &attr, func, arg); 103 + if (ret) { 104 + error("pthread_create\n", ret); 105 + return -1; 106 + } 107 + return 0; 108 + } 109 + 110 + 111 + void *waiterfn(void *arg) 112 + { 113 + struct thread_arg *args = (struct thread_arg *)arg; 114 + futex_t old_val; 115 + 116 + info("Waiter %ld: running\n", args->id); 117 + /* Each thread sleeps for a different amount of time 118 + * This is to avoid races, because we don't lock the 119 + * external mutex here */ 120 + usleep(1000 * (long)args->id); 121 + 122 + old_val = f1; 123 + atomic_inc(&waiters_blocked); 124 + info("Calling futex_wait_requeue_pi: %p (%u) -> %p\n", 125 + &f1, f1, &f2); 126 + args->ret = futex_wait_requeue_pi(&f1, old_val, &f2, args->timeout, 127 + FUTEX_PRIVATE_FLAG); 128 + 129 + info("waiter %ld woke with %d %s\n", args->id, args->ret, 130 + args->ret < 0 ? strerror(errno) : ""); 131 + atomic_inc(&waiters_woken); 132 + if (args->ret < 0) { 133 + if (args->timeout && errno == ETIMEDOUT) 134 + args->ret = 0; 135 + else { 136 + args->ret = RET_ERROR; 137 + error("futex_wait_requeue_pi\n", errno); 138 + } 139 + futex_lock_pi(&f2, NULL, 0, FUTEX_PRIVATE_FLAG); 140 + } 141 + futex_unlock_pi(&f2, FUTEX_PRIVATE_FLAG); 142 + 143 + info("Waiter %ld: exiting with %d\n", args->id, args->ret); 144 + pthread_exit((void *)&args->ret); 145 + } 146 + 147 + void *broadcast_wakerfn(void *arg) 148 + { 149 + struct thread_arg *args = (struct thread_arg *)arg; 150 + int nr_requeue = INT_MAX; 151 + int task_count = 0; 152 + futex_t old_val; 153 + int nr_wake = 1; 154 + int i = 0; 155 + 156 + info("Waker: waiting for waiters to block\n"); 157 + while (waiters_blocked.val < THREAD_MAX) 158 + usleep(1000); 159 + usleep(1000); 160 + 161 + info("Waker: Calling broadcast\n"); 162 + if (args->lock) { 163 + info("Calling FUTEX_LOCK_PI on mutex=%x @ %p\n", f2, &f2); 164 + futex_lock_pi(&f2, NULL, 0, FUTEX_PRIVATE_FLAG); 165 + } 166 + continue_requeue: 167 + old_val = f1; 168 + args->ret = futex_cmp_requeue_pi(&f1, old_val, &f2, nr_wake, nr_requeue, 169 + FUTEX_PRIVATE_FLAG); 170 + if (args->ret < 0) { 171 + args->ret = RET_ERROR; 172 + error("FUTEX_CMP_REQUEUE_PI failed\n", errno); 173 + } else if (++i < MAX_WAKE_ITERS) { 174 + task_count += args->ret; 175 + if (task_count < THREAD_MAX - waiters_woken.val) 176 + goto continue_requeue; 177 + } else { 178 + error("max broadcast iterations (%d) reached with %d/%d tasks woken or requeued\n", 179 + 0, MAX_WAKE_ITERS, task_count, THREAD_MAX); 180 + args->ret = RET_ERROR; 181 + } 182 + 183 + futex_wake(&wake_complete, 1, FUTEX_PRIVATE_FLAG); 184 + 185 + if (args->lock) 186 + futex_unlock_pi(&f2, FUTEX_PRIVATE_FLAG); 187 + 188 + if (args->ret > 0) 189 + args->ret = task_count; 190 + 191 + info("Waker: exiting with %d\n", args->ret); 192 + pthread_exit((void *)&args->ret); 193 + } 194 + 195 + void *signal_wakerfn(void *arg) 196 + { 197 + struct thread_arg *args = (struct thread_arg *)arg; 198 + unsigned int old_val; 199 + int nr_requeue = 0; 200 + int task_count = 0; 201 + int nr_wake = 1; 202 + int i = 0; 203 + 204 + info("Waker: waiting for waiters to block\n"); 205 + while (waiters_blocked.val < THREAD_MAX) 206 + usleep(1000); 207 + usleep(1000); 208 + 209 + while (task_count < THREAD_MAX && waiters_woken.val < THREAD_MAX) { 210 + info("task_count: %d, waiters_woken: %d\n", 211 + task_count, waiters_woken.val); 212 + if (args->lock) { 213 + info("Calling FUTEX_LOCK_PI on mutex=%x @ %p\n", 214 + f2, &f2); 215 + futex_lock_pi(&f2, NULL, 0, FUTEX_PRIVATE_FLAG); 216 + } 217 + info("Waker: Calling signal\n"); 218 + /* cond_signal */ 219 + old_val = f1; 220 + args->ret = futex_cmp_requeue_pi(&f1, old_val, &f2, 221 + nr_wake, nr_requeue, 222 + FUTEX_PRIVATE_FLAG); 223 + if (args->ret < 0) 224 + args->ret = -errno; 225 + info("futex: %x\n", f2); 226 + if (args->lock) { 227 + info("Calling FUTEX_UNLOCK_PI on mutex=%x @ %p\n", 228 + f2, &f2); 229 + futex_unlock_pi(&f2, FUTEX_PRIVATE_FLAG); 230 + } 231 + info("futex: %x\n", f2); 232 + if (args->ret < 0) { 233 + error("FUTEX_CMP_REQUEUE_PI failed\n", errno); 234 + args->ret = RET_ERROR; 235 + break; 236 + } 237 + 238 + task_count += args->ret; 239 + usleep(SIGNAL_PERIOD_US); 240 + i++; 241 + /* we have to loop at least THREAD_MAX times */ 242 + if (i > MAX_WAKE_ITERS + THREAD_MAX) { 243 + error("max signaling iterations (%d) reached, giving up on pending waiters.\n", 244 + 0, MAX_WAKE_ITERS + THREAD_MAX); 245 + args->ret = RET_ERROR; 246 + break; 247 + } 248 + } 249 + 250 + futex_wake(&wake_complete, 1, FUTEX_PRIVATE_FLAG); 251 + 252 + if (args->ret >= 0) 253 + args->ret = task_count; 254 + 255 + info("Waker: exiting with %d\n", args->ret); 256 + info("Waker: waiters_woken: %d\n", waiters_woken.val); 257 + pthread_exit((void *)&args->ret); 258 + } 259 + 260 + void *third_party_blocker(void *arg) 261 + { 262 + struct thread_arg *args = (struct thread_arg *)arg; 263 + int ret2 = 0; 264 + 265 + args->ret = futex_lock_pi(&f2, NULL, 0, FUTEX_PRIVATE_FLAG); 266 + if (args->ret) 267 + goto out; 268 + args->ret = futex_wait(&wake_complete, wake_complete, NULL, 269 + FUTEX_PRIVATE_FLAG); 270 + ret2 = futex_unlock_pi(&f2, FUTEX_PRIVATE_FLAG); 271 + 272 + out: 273 + if (args->ret || ret2) { 274 + error("third_party_blocker() futex error", 0); 275 + args->ret = RET_ERROR; 276 + } 277 + 278 + pthread_exit((void *)&args->ret); 279 + } 280 + 281 + int unit_test(int broadcast, long lock, int third_party_owner, long timeout_ns) 282 + { 283 + void *(*wakerfn)(void *) = signal_wakerfn; 284 + struct thread_arg blocker_arg = THREAD_ARG_INITIALIZER; 285 + struct thread_arg waker_arg = THREAD_ARG_INITIALIZER; 286 + pthread_t waiter[THREAD_MAX], waker, blocker; 287 + struct timespec ts, *tsp = NULL; 288 + struct thread_arg args[THREAD_MAX]; 289 + int *waiter_ret; 290 + int i, ret = RET_PASS; 291 + 292 + if (timeout_ns) { 293 + time_t secs; 294 + 295 + info("timeout_ns = %ld\n", timeout_ns); 296 + ret = clock_gettime(CLOCK_MONOTONIC, &ts); 297 + secs = (ts.tv_nsec + timeout_ns) / 1000000000; 298 + ts.tv_nsec = ((int64_t)ts.tv_nsec + timeout_ns) % 1000000000; 299 + ts.tv_sec += secs; 300 + info("ts.tv_sec = %ld\n", ts.tv_sec); 301 + info("ts.tv_nsec = %ld\n", ts.tv_nsec); 302 + tsp = &ts; 303 + } 304 + 305 + if (broadcast) 306 + wakerfn = broadcast_wakerfn; 307 + 308 + if (third_party_owner) { 309 + if (create_rt_thread(&blocker, third_party_blocker, 310 + (void *)&blocker_arg, SCHED_FIFO, 1)) { 311 + error("Creating third party blocker thread failed\n", 312 + errno); 313 + ret = RET_ERROR; 314 + goto out; 315 + } 316 + } 317 + 318 + atomic_set(&waiters_woken, 0); 319 + for (i = 0; i < THREAD_MAX; i++) { 320 + args[i].id = i; 321 + args[i].timeout = tsp; 322 + info("Starting thread %d\n", i); 323 + if (create_rt_thread(&waiter[i], waiterfn, (void *)&args[i], 324 + SCHED_FIFO, 1)) { 325 + error("Creating waiting thread failed\n", errno); 326 + ret = RET_ERROR; 327 + goto out; 328 + } 329 + } 330 + waker_arg.lock = lock; 331 + if (create_rt_thread(&waker, wakerfn, (void *)&waker_arg, 332 + SCHED_FIFO, 1)) { 333 + error("Creating waker thread failed\n", errno); 334 + ret = RET_ERROR; 335 + goto out; 336 + } 337 + 338 + /* Wait for threads to finish */ 339 + /* Store the first error or failure encountered in waiter_ret */ 340 + waiter_ret = &args[0].ret; 341 + for (i = 0; i < THREAD_MAX; i++) 342 + pthread_join(waiter[i], 343 + *waiter_ret ? NULL : (void **)&waiter_ret); 344 + 345 + if (third_party_owner) 346 + pthread_join(blocker, NULL); 347 + pthread_join(waker, NULL); 348 + 349 + out: 350 + if (!ret) { 351 + if (*waiter_ret) 352 + ret = *waiter_ret; 353 + else if (waker_arg.ret < 0) 354 + ret = waker_arg.ret; 355 + else if (blocker_arg.ret) 356 + ret = blocker_arg.ret; 357 + } 358 + 359 + return ret; 360 + } 361 + 362 + int main(int argc, char *argv[]) 363 + { 364 + int c, ret; 365 + 366 + while ((c = getopt(argc, argv, "bchlot:v:")) != -1) { 367 + switch (c) { 368 + case 'b': 369 + broadcast = 1; 370 + break; 371 + case 'c': 372 + log_color(1); 373 + break; 374 + case 'h': 375 + usage(basename(argv[0])); 376 + exit(0); 377 + case 'l': 378 + locked = 1; 379 + break; 380 + case 'o': 381 + owner = 1; 382 + locked = 0; 383 + break; 384 + case 't': 385 + timeout_ns = atoi(optarg); 386 + break; 387 + case 'v': 388 + log_verbosity(atoi(optarg)); 389 + break; 390 + default: 391 + usage(basename(argv[0])); 392 + exit(1); 393 + } 394 + } 395 + 396 + printf("%s: Test requeue functionality\n", basename(argv[0])); 397 + printf("\tArguments: broadcast=%d locked=%d owner=%d timeout=%ldns\n", 398 + broadcast, locked, owner, timeout_ns); 399 + 400 + /* 401 + * FIXME: unit_test is obsolete now that we parse options and the 402 + * various style of runs are done by run.sh - simplify the code and move 403 + * unit_test into main() 404 + */ 405 + ret = unit_test(broadcast, locked, owner, timeout_ns); 406 + 407 + print_result(ret); 408 + return ret; 409 + }
+135
tools/testing/selftests/futex/functional/futex_requeue_pi_mismatched_ops.c
··· 1 + /****************************************************************************** 2 + * 3 + * Copyright © International Business Machines Corp., 2009 4 + * 5 + * This program is free software; you can redistribute it and/or modify 6 + * it under the terms of the GNU General Public License as published by 7 + * the Free Software Foundation; either version 2 of the License, or 8 + * (at your option) any later version. 9 + * 10 + * DESCRIPTION 11 + * 1. Block a thread using FUTEX_WAIT 12 + * 2. Attempt to use FUTEX_CMP_REQUEUE_PI on the futex from 1. 13 + * 3. The kernel must detect the mismatch and return -EINVAL. 14 + * 15 + * AUTHOR 16 + * Darren Hart <dvhart@linux.intel.com> 17 + * 18 + * HISTORY 19 + * 2009-Nov-9: Initial version by Darren Hart <dvhart@linux.intel.com> 20 + * 21 + *****************************************************************************/ 22 + 23 + #include <errno.h> 24 + #include <getopt.h> 25 + #include <pthread.h> 26 + #include <stdio.h> 27 + #include <stdlib.h> 28 + #include <string.h> 29 + #include <time.h> 30 + #include "futextest.h" 31 + #include "logging.h" 32 + 33 + futex_t f1 = FUTEX_INITIALIZER; 34 + futex_t f2 = FUTEX_INITIALIZER; 35 + int child_ret = 0; 36 + 37 + void usage(char *prog) 38 + { 39 + printf("Usage: %s\n", prog); 40 + printf(" -c Use color\n"); 41 + printf(" -h Display this help message\n"); 42 + printf(" -v L Verbosity level: %d=QUIET %d=CRITICAL %d=INFO\n", 43 + VQUIET, VCRITICAL, VINFO); 44 + } 45 + 46 + void *blocking_child(void *arg) 47 + { 48 + child_ret = futex_wait(&f1, f1, NULL, FUTEX_PRIVATE_FLAG); 49 + if (child_ret < 0) { 50 + child_ret = -errno; 51 + error("futex_wait\n", errno); 52 + } 53 + return (void *)&child_ret; 54 + } 55 + 56 + int main(int argc, char *argv[]) 57 + { 58 + int ret = RET_PASS; 59 + pthread_t child; 60 + int c; 61 + 62 + while ((c = getopt(argc, argv, "chv:")) != -1) { 63 + switch (c) { 64 + case 'c': 65 + log_color(1); 66 + break; 67 + case 'h': 68 + usage(basename(argv[0])); 69 + exit(0); 70 + case 'v': 71 + log_verbosity(atoi(optarg)); 72 + break; 73 + default: 74 + usage(basename(argv[0])); 75 + exit(1); 76 + } 77 + } 78 + 79 + printf("%s: Detect mismatched requeue_pi operations\n", 80 + basename(argv[0])); 81 + 82 + if (pthread_create(&child, NULL, blocking_child, NULL)) { 83 + error("pthread_create\n", errno); 84 + ret = RET_ERROR; 85 + goto out; 86 + } 87 + /* Allow the child to block in the kernel. */ 88 + sleep(1); 89 + 90 + /* 91 + * The kernel should detect the waiter did not setup the 92 + * q->requeue_pi_key and return -EINVAL. If it does not, 93 + * it likely gave the lock to the child, which is now hung 94 + * in the kernel. 95 + */ 96 + ret = futex_cmp_requeue_pi(&f1, f1, &f2, 1, 0, FUTEX_PRIVATE_FLAG); 97 + if (ret < 0) { 98 + if (errno == EINVAL) { 99 + /* 100 + * The kernel correctly detected the mismatched 101 + * requeue_pi target and aborted. Wake the child with 102 + * FUTEX_WAKE. 103 + */ 104 + ret = futex_wake(&f1, 1, FUTEX_PRIVATE_FLAG); 105 + if (ret == 1) { 106 + ret = RET_PASS; 107 + } else if (ret < 0) { 108 + error("futex_wake\n", errno); 109 + ret = RET_ERROR; 110 + } else { 111 + error("futex_wake did not wake the child\n", 0); 112 + ret = RET_ERROR; 113 + } 114 + } else { 115 + error("futex_cmp_requeue_pi\n", errno); 116 + ret = RET_ERROR; 117 + } 118 + } else if (ret > 0) { 119 + fail("futex_cmp_requeue_pi failed to detect the mismatch\n"); 120 + ret = RET_FAIL; 121 + } else { 122 + error("futex_cmp_requeue_pi found no waiters\n", 0); 123 + ret = RET_ERROR; 124 + } 125 + 126 + pthread_join(child, NULL); 127 + 128 + if (!ret) 129 + ret = child_ret; 130 + 131 + out: 132 + /* If the kernel crashes, we shouldn't return at all. */ 133 + print_result(ret); 134 + return ret; 135 + }
+223
tools/testing/selftests/futex/functional/futex_requeue_pi_signal_restart.c
··· 1 + /****************************************************************************** 2 + * 3 + * Copyright © International Business Machines Corp., 2006-2008 4 + * 5 + * This program is free software; you can redistribute it and/or modify 6 + * it under the terms of the GNU General Public License as published by 7 + * the Free Software Foundation; either version 2 of the License, or 8 + * (at your option) any later version. 9 + * 10 + * DESCRIPTION 11 + * This test exercises the futex_wait_requeue_pi() signal handling both 12 + * before and after the requeue. The first should be restarted by the 13 + * kernel. The latter should return EWOULDBLOCK to the waiter. 14 + * 15 + * AUTHORS 16 + * Darren Hart <dvhart@linux.intel.com> 17 + * 18 + * HISTORY 19 + * 2008-May-5: Initial version by Darren Hart <dvhart@linux.intel.com> 20 + * 21 + *****************************************************************************/ 22 + 23 + #include <errno.h> 24 + #include <getopt.h> 25 + #include <limits.h> 26 + #include <pthread.h> 27 + #include <signal.h> 28 + #include <stdio.h> 29 + #include <stdlib.h> 30 + #include <string.h> 31 + #include "atomic.h" 32 + #include "futextest.h" 33 + #include "logging.h" 34 + 35 + #define DELAY_US 100 36 + 37 + futex_t f1 = FUTEX_INITIALIZER; 38 + futex_t f2 = FUTEX_INITIALIZER; 39 + atomic_t requeued = ATOMIC_INITIALIZER; 40 + 41 + int waiter_ret = 0; 42 + 43 + void usage(char *prog) 44 + { 45 + printf("Usage: %s\n", prog); 46 + printf(" -c Use color\n"); 47 + printf(" -h Display this help message\n"); 48 + printf(" -v L Verbosity level: %d=QUIET %d=CRITICAL %d=INFO\n", 49 + VQUIET, VCRITICAL, VINFO); 50 + } 51 + 52 + int create_rt_thread(pthread_t *pth, void*(*func)(void *), void *arg, 53 + int policy, int prio) 54 + { 55 + struct sched_param schedp; 56 + pthread_attr_t attr; 57 + int ret; 58 + 59 + pthread_attr_init(&attr); 60 + memset(&schedp, 0, sizeof(schedp)); 61 + 62 + ret = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); 63 + if (ret) { 64 + error("pthread_attr_setinheritsched\n", ret); 65 + return -1; 66 + } 67 + 68 + ret = pthread_attr_setschedpolicy(&attr, policy); 69 + if (ret) { 70 + error("pthread_attr_setschedpolicy\n", ret); 71 + return -1; 72 + } 73 + 74 + schedp.sched_priority = prio; 75 + ret = pthread_attr_setschedparam(&attr, &schedp); 76 + if (ret) { 77 + error("pthread_attr_setschedparam\n", ret); 78 + return -1; 79 + } 80 + 81 + ret = pthread_create(pth, &attr, func, arg); 82 + if (ret) { 83 + error("pthread_create\n", ret); 84 + return -1; 85 + } 86 + return 0; 87 + } 88 + 89 + void handle_signal(int signo) 90 + { 91 + info("signal received %s requeue\n", 92 + requeued.val ? "after" : "prior to"); 93 + } 94 + 95 + void *waiterfn(void *arg) 96 + { 97 + unsigned int old_val; 98 + int res; 99 + 100 + waiter_ret = RET_PASS; 101 + 102 + info("Waiter running\n"); 103 + info("Calling FUTEX_LOCK_PI on f2=%x @ %p\n", f2, &f2); 104 + old_val = f1; 105 + res = futex_wait_requeue_pi(&f1, old_val, &(f2), NULL, 106 + FUTEX_PRIVATE_FLAG); 107 + if (!requeued.val || errno != EWOULDBLOCK) { 108 + fail("unexpected return from futex_wait_requeue_pi: %d (%s)\n", 109 + res, strerror(errno)); 110 + info("w2:futex: %x\n", f2); 111 + if (!res) 112 + futex_unlock_pi(&f2, FUTEX_PRIVATE_FLAG); 113 + waiter_ret = RET_FAIL; 114 + } 115 + 116 + info("Waiter exiting with %d\n", waiter_ret); 117 + pthread_exit(NULL); 118 + } 119 + 120 + 121 + int main(int argc, char *argv[]) 122 + { 123 + unsigned int old_val; 124 + struct sigaction sa; 125 + pthread_t waiter; 126 + int c, res, ret = RET_PASS; 127 + 128 + while ((c = getopt(argc, argv, "chv:")) != -1) { 129 + switch (c) { 130 + case 'c': 131 + log_color(1); 132 + break; 133 + case 'h': 134 + usage(basename(argv[0])); 135 + exit(0); 136 + case 'v': 137 + log_verbosity(atoi(optarg)); 138 + break; 139 + default: 140 + usage(basename(argv[0])); 141 + exit(1); 142 + } 143 + } 144 + 145 + printf("%s: Test signal handling during requeue_pi\n", 146 + basename(argv[0])); 147 + printf("\tArguments: <none>\n"); 148 + 149 + sa.sa_handler = handle_signal; 150 + sigemptyset(&sa.sa_mask); 151 + sa.sa_flags = 0; 152 + if (sigaction(SIGUSR1, &sa, NULL)) { 153 + error("sigaction\n", errno); 154 + exit(1); 155 + } 156 + 157 + info("m1:f2: %x\n", f2); 158 + info("Creating waiter\n"); 159 + res = create_rt_thread(&waiter, waiterfn, NULL, SCHED_FIFO, 1); 160 + if (res) { 161 + error("Creating waiting thread failed", res); 162 + ret = RET_ERROR; 163 + goto out; 164 + } 165 + 166 + info("Calling FUTEX_LOCK_PI on f2=%x @ %p\n", f2, &f2); 167 + info("m2:f2: %x\n", f2); 168 + futex_lock_pi(&f2, 0, 0, FUTEX_PRIVATE_FLAG); 169 + info("m3:f2: %x\n", f2); 170 + 171 + while (1) { 172 + /* 173 + * signal the waiter before requeue, waiter should automatically 174 + * restart futex_wait_requeue_pi() in the kernel. Wait for the 175 + * waiter to block on f1 again. 176 + */ 177 + info("Issuing SIGUSR1 to waiter\n"); 178 + pthread_kill(waiter, SIGUSR1); 179 + usleep(DELAY_US); 180 + 181 + info("Requeueing waiter via FUTEX_CMP_REQUEUE_PI\n"); 182 + old_val = f1; 183 + res = futex_cmp_requeue_pi(&f1, old_val, &(f2), 1, 0, 184 + FUTEX_PRIVATE_FLAG); 185 + /* 186 + * If res is non-zero, we either requeued the waiter or hit an 187 + * error, break out and handle it. If it is zero, then the 188 + * signal may have hit before the the waiter was blocked on f1. 189 + * Try again. 190 + */ 191 + if (res > 0) { 192 + atomic_set(&requeued, 1); 193 + break; 194 + } else if (res > 0) { 195 + error("FUTEX_CMP_REQUEUE_PI failed\n", errno); 196 + ret = RET_ERROR; 197 + break; 198 + } 199 + } 200 + info("m4:f2: %x\n", f2); 201 + 202 + /* 203 + * Signal the waiter after requeue, waiter should return from 204 + * futex_wait_requeue_pi() with EWOULDBLOCK. Join the thread here so the 205 + * futex_unlock_pi() can't happen before the signal wakeup is detected 206 + * in the kernel. 207 + */ 208 + info("Issuing SIGUSR1 to waiter\n"); 209 + pthread_kill(waiter, SIGUSR1); 210 + info("Waiting for waiter to return\n"); 211 + pthread_join(waiter, NULL); 212 + 213 + info("Calling FUTEX_UNLOCK_PI on mutex=%x @ %p\n", f2, &f2); 214 + futex_unlock_pi(&f2, FUTEX_PRIVATE_FLAG); 215 + info("m5:f2: %x\n", f2); 216 + 217 + out: 218 + if (ret == RET_PASS && waiter_ret) 219 + ret = waiter_ret; 220 + 221 + print_result(ret); 222 + return ret; 223 + }
+125
tools/testing/selftests/futex/functional/futex_wait_private_mapped_file.c
··· 1 + /****************************************************************************** 2 + * 3 + * Copyright FUJITSU LIMITED 2010 4 + * Copyright KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License as published by 8 + * the Free Software Foundation; either version 2 of the License, or 9 + * (at your option) any later version. 10 + * 11 + * DESCRIPTION 12 + * Internally, Futex has two handling mode, anon and file. The private file 13 + * mapping is special. At first it behave as file, but after write anything 14 + * it behave as anon. This test is intent to test such case. 15 + * 16 + * AUTHOR 17 + * KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> 18 + * 19 + * HISTORY 20 + * 2010-Jan-6: Initial version by KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> 21 + * 22 + *****************************************************************************/ 23 + 24 + #include <stdio.h> 25 + #include <stdlib.h> 26 + #include <syscall.h> 27 + #include <unistd.h> 28 + #include <errno.h> 29 + #include <linux/futex.h> 30 + #include <pthread.h> 31 + #include <libgen.h> 32 + #include <signal.h> 33 + 34 + #include "logging.h" 35 + #include "futextest.h" 36 + 37 + #define PAGE_SZ 4096 38 + 39 + char pad[PAGE_SZ] = {1}; 40 + futex_t val = 1; 41 + char pad2[PAGE_SZ] = {1}; 42 + 43 + #define WAKE_WAIT_US 3000000 44 + struct timespec wait_timeout = { .tv_sec = 5, .tv_nsec = 0}; 45 + 46 + void usage(char *prog) 47 + { 48 + printf("Usage: %s\n", prog); 49 + printf(" -c Use color\n"); 50 + printf(" -h Display this help message\n"); 51 + printf(" -v L Verbosity level: %d=QUIET %d=CRITICAL %d=INFO\n", 52 + VQUIET, VCRITICAL, VINFO); 53 + } 54 + 55 + void *thr_futex_wait(void *arg) 56 + { 57 + int ret; 58 + 59 + info("futex wait\n"); 60 + ret = futex_wait(&val, 1, &wait_timeout, 0); 61 + if (ret && errno != EWOULDBLOCK && errno != ETIMEDOUT) { 62 + error("futex error.\n", errno); 63 + print_result(RET_ERROR); 64 + exit(RET_ERROR); 65 + } 66 + 67 + if (ret && errno == ETIMEDOUT) 68 + fail("waiter timedout\n"); 69 + 70 + info("futex_wait: ret = %d, errno = %d\n", ret, errno); 71 + 72 + return NULL; 73 + } 74 + 75 + int main(int argc, char **argv) 76 + { 77 + pthread_t thr; 78 + int ret = RET_PASS; 79 + int res; 80 + int c; 81 + 82 + while ((c = getopt(argc, argv, "chv:")) != -1) { 83 + switch (c) { 84 + case 'c': 85 + log_color(1); 86 + break; 87 + case 'h': 88 + usage(basename(argv[0])); 89 + exit(0); 90 + case 'v': 91 + log_verbosity(atoi(optarg)); 92 + break; 93 + default: 94 + usage(basename(argv[0])); 95 + exit(1); 96 + } 97 + } 98 + 99 + printf("%s: Test the futex value of private file mappings in FUTEX_WAIT\n", 100 + basename(argv[0])); 101 + 102 + ret = pthread_create(&thr, NULL, thr_futex_wait, NULL); 103 + if (ret < 0) { 104 + fprintf(stderr, "pthread_create error\n"); 105 + ret = RET_ERROR; 106 + goto out; 107 + } 108 + 109 + info("wait a while\n"); 110 + usleep(WAKE_WAIT_US); 111 + val = 2; 112 + res = futex_wake(&val, 1, 0); 113 + info("futex_wake %d\n", res); 114 + if (res != 1) { 115 + fail("FUTEX_WAKE didn't find the waiting thread.\n"); 116 + ret = RET_FAIL; 117 + } 118 + 119 + info("join\n"); 120 + pthread_join(thr, NULL); 121 + 122 + out: 123 + print_result(ret); 124 + return ret; 125 + }
+86
tools/testing/selftests/futex/functional/futex_wait_timeout.c
··· 1 + /****************************************************************************** 2 + * 3 + * Copyright © International Business Machines Corp., 2009 4 + * 5 + * This program is free software; you can redistribute it and/or modify 6 + * it under the terms of the GNU General Public License as published by 7 + * the Free Software Foundation; either version 2 of the License, or 8 + * (at your option) any later version. 9 + * 10 + * DESCRIPTION 11 + * Block on a futex and wait for timeout. 12 + * 13 + * AUTHOR 14 + * Darren Hart <dvhart@linux.intel.com> 15 + * 16 + * HISTORY 17 + * 2009-Nov-6: Initial version by Darren Hart <dvhart@linux.intel.com> 18 + * 19 + *****************************************************************************/ 20 + 21 + #include <errno.h> 22 + #include <getopt.h> 23 + #include <stdio.h> 24 + #include <stdlib.h> 25 + #include <string.h> 26 + #include <time.h> 27 + #include "futextest.h" 28 + #include "logging.h" 29 + 30 + static long timeout_ns = 100000; /* 100us default timeout */ 31 + 32 + void usage(char *prog) 33 + { 34 + printf("Usage: %s\n", prog); 35 + printf(" -c Use color\n"); 36 + printf(" -h Display this help message\n"); 37 + printf(" -t N Timeout in nanoseconds (default: 100,000)\n"); 38 + printf(" -v L Verbosity level: %d=QUIET %d=CRITICAL %d=INFO\n", 39 + VQUIET, VCRITICAL, VINFO); 40 + } 41 + 42 + int main(int argc, char *argv[]) 43 + { 44 + futex_t f1 = FUTEX_INITIALIZER; 45 + struct timespec to; 46 + int res, ret = RET_PASS; 47 + int c; 48 + 49 + while ((c = getopt(argc, argv, "cht:v:")) != -1) { 50 + switch (c) { 51 + case 'c': 52 + log_color(1); 53 + break; 54 + case 'h': 55 + usage(basename(argv[0])); 56 + exit(0); 57 + case 't': 58 + timeout_ns = atoi(optarg); 59 + break; 60 + case 'v': 61 + log_verbosity(atoi(optarg)); 62 + break; 63 + default: 64 + usage(basename(argv[0])); 65 + exit(1); 66 + } 67 + } 68 + 69 + printf("%s: Block on a futex and wait for timeout\n", 70 + basename(argv[0])); 71 + printf("\tArguments: timeout=%ldns\n", timeout_ns); 72 + 73 + /* initialize timeout */ 74 + to.tv_sec = 0; 75 + to.tv_nsec = timeout_ns; 76 + 77 + info("Calling futex_wait on f1: %u @ %p\n", f1, &f1); 78 + res = futex_wait(&f1, f1, &to, FUTEX_PRIVATE_FLAG); 79 + if (!res || errno != ETIMEDOUT) { 80 + fail("futex_wait returned %d\n", ret < 0 ? errno : ret); 81 + ret = RET_FAIL; 82 + } 83 + 84 + print_result(ret); 85 + return ret; 86 + }
+124
tools/testing/selftests/futex/functional/futex_wait_uninitialized_heap.c
··· 1 + /****************************************************************************** 2 + * 3 + * Copyright FUJITSU LIMITED 2010 4 + * Copyright KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License as published by 8 + * the Free Software Foundation; either version 2 of the License, or 9 + * (at your option) any later version. 10 + * 11 + * DESCRIPTION 12 + * Wait on uninitialized heap. It shold be zero and FUTEX_WAIT should 13 + * return immediately. This test is intent to test zero page handling in 14 + * futex. 15 + * 16 + * AUTHOR 17 + * KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> 18 + * 19 + * HISTORY 20 + * 2010-Jan-6: Initial version by KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> 21 + * 22 + *****************************************************************************/ 23 + 24 + #include <pthread.h> 25 + #include <stdio.h> 26 + #include <stdlib.h> 27 + #include <sys/mman.h> 28 + #include <syscall.h> 29 + #include <sys/types.h> 30 + #include <sys/stat.h> 31 + #include <unistd.h> 32 + #include <errno.h> 33 + #include <linux/futex.h> 34 + #include <libgen.h> 35 + 36 + #include "logging.h" 37 + #include "futextest.h" 38 + 39 + #define WAIT_US 5000000 40 + 41 + static int child_blocked = 1; 42 + static int child_ret; 43 + void *buf; 44 + 45 + void usage(char *prog) 46 + { 47 + printf("Usage: %s\n", prog); 48 + printf(" -c Use color\n"); 49 + printf(" -h Display this help message\n"); 50 + printf(" -v L Verbosity level: %d=QUIET %d=CRITICAL %d=INFO\n", 51 + VQUIET, VCRITICAL, VINFO); 52 + } 53 + 54 + void *wait_thread(void *arg) 55 + { 56 + int res; 57 + 58 + child_ret = RET_PASS; 59 + res = futex_wait(buf, 1, NULL, 0); 60 + child_blocked = 0; 61 + 62 + if (res != 0 && errno != EWOULDBLOCK) { 63 + error("futex failure\n", errno); 64 + child_ret = RET_ERROR; 65 + } 66 + pthread_exit(NULL); 67 + } 68 + 69 + int main(int argc, char **argv) 70 + { 71 + int c, ret = RET_PASS; 72 + long page_size; 73 + pthread_t thr; 74 + 75 + while ((c = getopt(argc, argv, "chv:")) != -1) { 76 + switch (c) { 77 + case 'c': 78 + log_color(1); 79 + break; 80 + case 'h': 81 + usage(basename(argv[0])); 82 + exit(0); 83 + case 'v': 84 + log_verbosity(atoi(optarg)); 85 + break; 86 + default: 87 + usage(basename(argv[0])); 88 + exit(1); 89 + } 90 + } 91 + 92 + page_size = sysconf(_SC_PAGESIZE); 93 + 94 + buf = mmap(NULL, page_size, PROT_READ|PROT_WRITE, 95 + MAP_PRIVATE|MAP_ANONYMOUS, 0, 0); 96 + if (buf == (void *)-1) { 97 + error("mmap\n", errno); 98 + exit(1); 99 + } 100 + 101 + printf("%s: Test the uninitialized futex value in FUTEX_WAIT\n", 102 + basename(argv[0])); 103 + 104 + 105 + ret = pthread_create(&thr, NULL, wait_thread, NULL); 106 + if (ret) { 107 + error("pthread_create\n", errno); 108 + ret = RET_ERROR; 109 + goto out; 110 + } 111 + 112 + info("waiting %dus for child to return\n", WAIT_US); 113 + usleep(WAIT_US); 114 + 115 + ret = child_ret; 116 + if (child_blocked) { 117 + fail("child blocked in kernel\n"); 118 + ret = RET_FAIL; 119 + } 120 + 121 + out: 122 + print_result(ret); 123 + return ret; 124 + }
+79
tools/testing/selftests/futex/functional/futex_wait_wouldblock.c
··· 1 + /****************************************************************************** 2 + * 3 + * Copyright © International Business Machines Corp., 2009 4 + * 5 + * This program is free software; you can redistribute it and/or modify 6 + * it under the terms of the GNU General Public License as published by 7 + * the Free Software Foundation; either version 2 of the License, or 8 + * (at your option) any later version. 9 + * 10 + * DESCRIPTION 11 + * Test if FUTEX_WAIT op returns -EWOULDBLOCK if the futex value differs 12 + * from the expected one. 13 + * 14 + * AUTHOR 15 + * Gowrishankar <gowrishankar.m@in.ibm.com> 16 + * 17 + * HISTORY 18 + * 2009-Nov-14: Initial version by Gowrishankar <gowrishankar.m@in.ibm.com> 19 + * 20 + *****************************************************************************/ 21 + 22 + #include <errno.h> 23 + #include <getopt.h> 24 + #include <stdio.h> 25 + #include <stdlib.h> 26 + #include <string.h> 27 + #include <time.h> 28 + #include "futextest.h" 29 + #include "logging.h" 30 + 31 + #define timeout_ns 100000 32 + 33 + void usage(char *prog) 34 + { 35 + printf("Usage: %s\n", prog); 36 + printf(" -c Use color\n"); 37 + printf(" -h Display this help message\n"); 38 + printf(" -v L Verbosity level: %d=QUIET %d=CRITICAL %d=INFO\n", 39 + VQUIET, VCRITICAL, VINFO); 40 + } 41 + 42 + int main(int argc, char *argv[]) 43 + { 44 + struct timespec to = {.tv_sec = 0, .tv_nsec = timeout_ns}; 45 + futex_t f1 = FUTEX_INITIALIZER; 46 + int res, ret = RET_PASS; 47 + int c; 48 + 49 + while ((c = getopt(argc, argv, "cht:v:")) != -1) { 50 + switch (c) { 51 + case 'c': 52 + log_color(1); 53 + break; 54 + case 'h': 55 + usage(basename(argv[0])); 56 + exit(0); 57 + case 'v': 58 + log_verbosity(atoi(optarg)); 59 + break; 60 + default: 61 + usage(basename(argv[0])); 62 + exit(1); 63 + } 64 + } 65 + 66 + printf("%s: Test the unexpected futex value in FUTEX_WAIT\n", 67 + basename(argv[0])); 68 + 69 + info("Calling futex_wait on f1: %u @ %p with val=%u\n", f1, &f1, f1+1); 70 + res = futex_wait(&f1, f1+1, &to, FUTEX_PRIVATE_FLAG); 71 + if (!res || errno != EWOULDBLOCK) { 72 + fail("futex_wait returned: %d %s\n", 73 + res ? errno : res, res ? strerror(errno) : ""); 74 + ret = RET_FAIL; 75 + } 76 + 77 + print_result(ret); 78 + return ret; 79 + }
+79
tools/testing/selftests/futex/functional/run.sh
··· 1 + #!/bin/sh 2 + 3 + ############################################################################### 4 + # 5 + # Copyright © International Business Machines Corp., 2009 6 + # 7 + # This program is free software; you can redistribute it and/or modify 8 + # it under the terms of the GNU General Public License as published by 9 + # the Free Software Foundation; either version 2 of the License, or 10 + # (at your option) any later version. 11 + # 12 + # DESCRIPTION 13 + # Run tests in the current directory. 14 + # 15 + # AUTHOR 16 + # Darren Hart <dvhart@linux.intel.com> 17 + # 18 + # HISTORY 19 + # 2009-Nov-9: Initial version by Darren Hart <dvhart@linux.intel.com> 20 + # 2010-Jan-6: Add futex_wait_uninitialized_heap and futex_wait_private_mapped_file 21 + # by KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> 22 + # 23 + ############################################################################### 24 + 25 + # Test for a color capable console 26 + if [ -z "$USE_COLOR" ]; then 27 + tput setf 7 28 + if [ $? -eq 0 ]; then 29 + USE_COLOR=1 30 + tput sgr0 31 + fi 32 + fi 33 + if [ "$USE_COLOR" -eq 1 ]; then 34 + COLOR="-c" 35 + fi 36 + 37 + 38 + echo 39 + # requeue pi testing 40 + # without timeouts 41 + ./futex_requeue_pi $COLOR 42 + ./futex_requeue_pi $COLOR -b 43 + ./futex_requeue_pi $COLOR -b -l 44 + ./futex_requeue_pi $COLOR -b -o 45 + ./futex_requeue_pi $COLOR -l 46 + ./futex_requeue_pi $COLOR -o 47 + # with timeouts 48 + ./futex_requeue_pi $COLOR -b -l -t 5000 49 + ./futex_requeue_pi $COLOR -l -t 5000 50 + ./futex_requeue_pi $COLOR -b -l -t 500000 51 + ./futex_requeue_pi $COLOR -l -t 500000 52 + ./futex_requeue_pi $COLOR -b -t 5000 53 + ./futex_requeue_pi $COLOR -t 5000 54 + ./futex_requeue_pi $COLOR -b -t 500000 55 + ./futex_requeue_pi $COLOR -t 500000 56 + ./futex_requeue_pi $COLOR -b -o -t 5000 57 + ./futex_requeue_pi $COLOR -l -t 5000 58 + ./futex_requeue_pi $COLOR -b -o -t 500000 59 + ./futex_requeue_pi $COLOR -l -t 500000 60 + # with long timeout 61 + ./futex_requeue_pi $COLOR -b -l -t 2000000000 62 + ./futex_requeue_pi $COLOR -l -t 2000000000 63 + 64 + 65 + echo 66 + ./futex_requeue_pi_mismatched_ops $COLOR 67 + 68 + echo 69 + ./futex_requeue_pi_signal_restart $COLOR 70 + 71 + echo 72 + ./futex_wait_timeout $COLOR 73 + 74 + echo 75 + ./futex_wait_wouldblock $COLOR 76 + 77 + echo 78 + ./futex_wait_uninitialized_heap $COLOR 79 + ./futex_wait_private_mapped_file $COLOR
+83
tools/testing/selftests/futex/include/atomic.h
··· 1 + /****************************************************************************** 2 + * 3 + * Copyright © International Business Machines Corp., 2009 4 + * 5 + * This program is free software; you can redistribute it and/or modify 6 + * it under the terms of the GNU General Public License as published by 7 + * the Free Software Foundation; either version 2 of the License, or 8 + * (at your option) any later version. 9 + * 10 + * DESCRIPTION 11 + * GCC atomic builtin wrappers 12 + * http://gcc.gnu.org/onlinedocs/gcc-4.1.0/gcc/Atomic-Builtins.html 13 + * 14 + * AUTHOR 15 + * Darren Hart <dvhart@linux.intel.com> 16 + * 17 + * HISTORY 18 + * 2009-Nov-17: Initial version by Darren Hart <dvhart@linux.intel.com> 19 + * 20 + *****************************************************************************/ 21 + 22 + #ifndef _ATOMIC_H 23 + #define _ATOMIC_H 24 + 25 + typedef struct { 26 + volatile int val; 27 + } atomic_t; 28 + 29 + #define ATOMIC_INITIALIZER { 0 } 30 + 31 + /** 32 + * atomic_cmpxchg() - Atomic compare and exchange 33 + * @uaddr: The address of the futex to be modified 34 + * @oldval: The expected value of the futex 35 + * @newval: The new value to try and assign the futex 36 + * 37 + * Return the old value of addr->val. 38 + */ 39 + static inline int 40 + atomic_cmpxchg(atomic_t *addr, int oldval, int newval) 41 + { 42 + return __sync_val_compare_and_swap(&addr->val, oldval, newval); 43 + } 44 + 45 + /** 46 + * atomic_inc() - Atomic incrememnt 47 + * @addr: Address of the variable to increment 48 + * 49 + * Return the new value of addr->val. 50 + */ 51 + static inline int 52 + atomic_inc(atomic_t *addr) 53 + { 54 + return __sync_add_and_fetch(&addr->val, 1); 55 + } 56 + 57 + /** 58 + * atomic_dec() - Atomic decrement 59 + * @addr: Address of the variable to decrement 60 + * 61 + * Return the new value of addr-val. 62 + */ 63 + static inline int 64 + atomic_dec(atomic_t *addr) 65 + { 66 + return __sync_sub_and_fetch(&addr->val, 1); 67 + } 68 + 69 + /** 70 + * atomic_set() - Atomic set 71 + * @addr: Address of the variable to set 72 + * @newval: New value for the atomic_t 73 + * 74 + * Return the new value of addr->val. 75 + */ 76 + static inline int 77 + atomic_set(atomic_t *addr, int newval) 78 + { 79 + addr->val = newval; 80 + return newval; 81 + } 82 + 83 + #endif
+266
tools/testing/selftests/futex/include/futextest.h
··· 1 + /****************************************************************************** 2 + * 3 + * Copyright © International Business Machines Corp., 2009 4 + * 5 + * This program is free software; you can redistribute it and/or modify 6 + * it under the terms of the GNU General Public License as published by 7 + * the Free Software Foundation; either version 2 of the License, or 8 + * (at your option) any later version. 9 + * 10 + * DESCRIPTION 11 + * Glibc independent futex library for testing kernel functionality. 12 + * 13 + * AUTHOR 14 + * Darren Hart <dvhart@linux.intel.com> 15 + * 16 + * HISTORY 17 + * 2009-Nov-6: Initial version by Darren Hart <dvhart@linux.intel.com> 18 + * 19 + *****************************************************************************/ 20 + 21 + #ifndef _FUTEXTEST_H 22 + #define _FUTEXTEST_H 23 + 24 + #include <unistd.h> 25 + #include <sys/syscall.h> 26 + #include <sys/types.h> 27 + #include <linux/futex.h> 28 + 29 + typedef volatile u_int32_t futex_t; 30 + #define FUTEX_INITIALIZER 0 31 + 32 + /* Define the newer op codes if the system header file is not up to date. */ 33 + #ifndef FUTEX_WAIT_BITSET 34 + #define FUTEX_WAIT_BITSET 9 35 + #endif 36 + #ifndef FUTEX_WAKE_BITSET 37 + #define FUTEX_WAKE_BITSET 10 38 + #endif 39 + #ifndef FUTEX_WAIT_REQUEUE_PI 40 + #define FUTEX_WAIT_REQUEUE_PI 11 41 + #endif 42 + #ifndef FUTEX_CMP_REQUEUE_PI 43 + #define FUTEX_CMP_REQUEUE_PI 12 44 + #endif 45 + #ifndef FUTEX_WAIT_REQUEUE_PI_PRIVATE 46 + #define FUTEX_WAIT_REQUEUE_PI_PRIVATE (FUTEX_WAIT_REQUEUE_PI | \ 47 + FUTEX_PRIVATE_FLAG) 48 + #endif 49 + #ifndef FUTEX_REQUEUE_PI_PRIVATE 50 + #define FUTEX_CMP_REQUEUE_PI_PRIVATE (FUTEX_CMP_REQUEUE_PI | \ 51 + FUTEX_PRIVATE_FLAG) 52 + #endif 53 + 54 + /** 55 + * futex() - SYS_futex syscall wrapper 56 + * @uaddr: address of first futex 57 + * @op: futex op code 58 + * @val: typically expected value of uaddr, but varies by op 59 + * @timeout: typically an absolute struct timespec (except where noted 60 + * otherwise). Overloaded by some ops 61 + * @uaddr2: address of second futex for some ops\ 62 + * @val3: varies by op 63 + * @opflags: flags to be bitwise OR'd with op, such as FUTEX_PRIVATE_FLAG 64 + * 65 + * futex() is used by all the following futex op wrappers. It can also be 66 + * used for misuse and abuse testing. Generally, the specific op wrappers 67 + * should be used instead. It is a macro instead of an static inline function as 68 + * some of the types over overloaded (timeout is used for nr_requeue for 69 + * example). 70 + * 71 + * These argument descriptions are the defaults for all 72 + * like-named arguments in the following wrappers except where noted below. 73 + */ 74 + #define futex(uaddr, op, val, timeout, uaddr2, val3, opflags) \ 75 + syscall(SYS_futex, uaddr, op | opflags, val, timeout, uaddr2, val3) 76 + 77 + /** 78 + * futex_wait() - block on uaddr with optional timeout 79 + * @timeout: relative timeout 80 + */ 81 + static inline int 82 + futex_wait(futex_t *uaddr, futex_t val, struct timespec *timeout, int opflags) 83 + { 84 + return futex(uaddr, FUTEX_WAIT, val, timeout, NULL, 0, opflags); 85 + } 86 + 87 + /** 88 + * futex_wake() - wake one or more tasks blocked on uaddr 89 + * @nr_wake: wake up to this many tasks 90 + */ 91 + static inline int 92 + futex_wake(futex_t *uaddr, int nr_wake, int opflags) 93 + { 94 + return futex(uaddr, FUTEX_WAKE, nr_wake, NULL, NULL, 0, opflags); 95 + } 96 + 97 + /** 98 + * futex_wait_bitset() - block on uaddr with bitset 99 + * @bitset: bitset to be used with futex_wake_bitset 100 + */ 101 + static inline int 102 + futex_wait_bitset(futex_t *uaddr, futex_t val, struct timespec *timeout, 103 + u_int32_t bitset, int opflags) 104 + { 105 + return futex(uaddr, FUTEX_WAIT_BITSET, val, timeout, NULL, bitset, 106 + opflags); 107 + } 108 + 109 + /** 110 + * futex_wake_bitset() - wake one or more tasks blocked on uaddr with bitset 111 + * @bitset: bitset to compare with that used in futex_wait_bitset 112 + */ 113 + static inline int 114 + futex_wake_bitset(futex_t *uaddr, int nr_wake, u_int32_t bitset, int opflags) 115 + { 116 + return futex(uaddr, FUTEX_WAKE_BITSET, nr_wake, NULL, NULL, bitset, 117 + opflags); 118 + } 119 + 120 + /** 121 + * futex_lock_pi() - block on uaddr as a PI mutex 122 + * @detect: whether (1) or not (0) to perform deadlock detection 123 + */ 124 + static inline int 125 + futex_lock_pi(futex_t *uaddr, struct timespec *timeout, int detect, 126 + int opflags) 127 + { 128 + return futex(uaddr, FUTEX_LOCK_PI, detect, timeout, NULL, 0, opflags); 129 + } 130 + 131 + /** 132 + * futex_unlock_pi() - release uaddr as a PI mutex, waking the top waiter 133 + */ 134 + static inline int 135 + futex_unlock_pi(futex_t *uaddr, int opflags) 136 + { 137 + return futex(uaddr, FUTEX_UNLOCK_PI, 0, NULL, NULL, 0, opflags); 138 + } 139 + 140 + /** 141 + * futex_wake_op() - FIXME: COME UP WITH A GOOD ONE LINE DESCRIPTION 142 + */ 143 + static inline int 144 + futex_wake_op(futex_t *uaddr, futex_t *uaddr2, int nr_wake, int nr_wake2, 145 + int wake_op, int opflags) 146 + { 147 + return futex(uaddr, FUTEX_WAKE_OP, nr_wake, nr_wake2, uaddr2, wake_op, 148 + opflags); 149 + } 150 + 151 + /** 152 + * futex_requeue() - requeue without expected value comparison, deprecated 153 + * @nr_wake: wake up to this many tasks 154 + * @nr_requeue: requeue up to this many tasks 155 + * 156 + * Due to its inherently racy implementation, futex_requeue() is deprecated in 157 + * favor of futex_cmp_requeue(). 158 + */ 159 + static inline int 160 + futex_requeue(futex_t *uaddr, futex_t *uaddr2, int nr_wake, int nr_requeue, 161 + int opflags) 162 + { 163 + return futex(uaddr, FUTEX_REQUEUE, nr_wake, nr_requeue, uaddr2, 0, 164 + opflags); 165 + } 166 + 167 + /** 168 + * futex_cmp_requeue() - requeue tasks from uaddr to uaddr2 169 + * @nr_wake: wake up to this many tasks 170 + * @nr_requeue: requeue up to this many tasks 171 + */ 172 + static inline int 173 + futex_cmp_requeue(futex_t *uaddr, futex_t val, futex_t *uaddr2, int nr_wake, 174 + int nr_requeue, int opflags) 175 + { 176 + return futex(uaddr, FUTEX_CMP_REQUEUE, nr_wake, nr_requeue, uaddr2, 177 + val, opflags); 178 + } 179 + 180 + /** 181 + * futex_wait_requeue_pi() - block on uaddr and prepare to requeue to uaddr2 182 + * @uaddr: non-PI futex source 183 + * @uaddr2: PI futex target 184 + * 185 + * This is the first half of the requeue_pi mechanism. It shall always be 186 + * paired with futex_cmp_requeue_pi(). 187 + */ 188 + static inline int 189 + futex_wait_requeue_pi(futex_t *uaddr, futex_t val, futex_t *uaddr2, 190 + struct timespec *timeout, int opflags) 191 + { 192 + return futex(uaddr, FUTEX_WAIT_REQUEUE_PI, val, timeout, uaddr2, 0, 193 + opflags); 194 + } 195 + 196 + /** 197 + * futex_cmp_requeue_pi() - requeue tasks from uaddr to uaddr2 (PI aware) 198 + * @uaddr: non-PI futex source 199 + * @uaddr2: PI futex target 200 + * @nr_wake: wake up to this many tasks 201 + * @nr_requeue: requeue up to this many tasks 202 + */ 203 + static inline int 204 + futex_cmp_requeue_pi(futex_t *uaddr, futex_t val, futex_t *uaddr2, int nr_wake, 205 + int nr_requeue, int opflags) 206 + { 207 + return futex(uaddr, FUTEX_CMP_REQUEUE_PI, nr_wake, nr_requeue, uaddr2, 208 + val, opflags); 209 + } 210 + 211 + /** 212 + * futex_cmpxchg() - atomic compare and exchange 213 + * @uaddr: The address of the futex to be modified 214 + * @oldval: The expected value of the futex 215 + * @newval: The new value to try and assign the futex 216 + * 217 + * Implement cmpxchg using gcc atomic builtins. 218 + * http://gcc.gnu.org/onlinedocs/gcc-4.1.0/gcc/Atomic-Builtins.html 219 + * 220 + * Return the old futex value. 221 + */ 222 + static inline u_int32_t 223 + futex_cmpxchg(futex_t *uaddr, u_int32_t oldval, u_int32_t newval) 224 + { 225 + return __sync_val_compare_and_swap(uaddr, oldval, newval); 226 + } 227 + 228 + /** 229 + * futex_dec() - atomic decrement of the futex value 230 + * @uaddr: The address of the futex to be modified 231 + * 232 + * Return the new futex value. 233 + */ 234 + static inline u_int32_t 235 + futex_dec(futex_t *uaddr) 236 + { 237 + return __sync_sub_and_fetch(uaddr, 1); 238 + } 239 + 240 + /** 241 + * futex_inc() - atomic increment of the futex value 242 + * @uaddr: the address of the futex to be modified 243 + * 244 + * Return the new futex value. 245 + */ 246 + static inline u_int32_t 247 + futex_inc(futex_t *uaddr) 248 + { 249 + return __sync_add_and_fetch(uaddr, 1); 250 + } 251 + 252 + /** 253 + * futex_set() - atomic decrement of the futex value 254 + * @uaddr: the address of the futex to be modified 255 + * @newval: New value for the atomic_t 256 + * 257 + * Return the new futex value. 258 + */ 259 + static inline u_int32_t 260 + futex_set(futex_t *uaddr, u_int32_t newval) 261 + { 262 + *uaddr = newval; 263 + return newval; 264 + } 265 + 266 + #endif
+150
tools/testing/selftests/futex/include/logging.h
··· 1 + /****************************************************************************** 2 + * 3 + * Copyright © International Business Machines Corp., 2009 4 + * 5 + * This program is free software; you can redistribute it and/or modify 6 + * it under the terms of the GNU General Public License as published by 7 + * the Free Software Foundation; either version 2 of the License, or 8 + * (at your option) any later version. 9 + * 10 + * DESCRIPTION 11 + * Glibc independent futex library for testing kernel functionality. 12 + * 13 + * AUTHOR 14 + * Darren Hart <dvhart@linux.intel.com> 15 + * 16 + * HISTORY 17 + * 2009-Nov-6: Initial version by Darren Hart <dvhart@linux.intel.com> 18 + * 19 + *****************************************************************************/ 20 + 21 + #ifndef _LOGGING_H 22 + #define _LOGGING_H 23 + 24 + #include <string.h> 25 + #include <unistd.h> 26 + #include <linux/futex.h> 27 + 28 + /* 29 + * Define PASS, ERROR, and FAIL strings with and without color escape 30 + * sequences, default to no color. 31 + */ 32 + #define ESC 0x1B, '[' 33 + #define BRIGHT '1' 34 + #define GREEN '3', '2' 35 + #define YELLOW '3', '3' 36 + #define RED '3', '1' 37 + #define ESCEND 'm' 38 + #define BRIGHT_GREEN ESC, BRIGHT, ';', GREEN, ESCEND 39 + #define BRIGHT_YELLOW ESC, BRIGHT, ';', YELLOW, ESCEND 40 + #define BRIGHT_RED ESC, BRIGHT, ';', RED, ESCEND 41 + #define RESET_COLOR ESC, '0', 'm' 42 + static const char PASS_COLOR[] = {BRIGHT_GREEN, ' ', 'P', 'A', 'S', 'S', 43 + RESET_COLOR, 0}; 44 + static const char ERROR_COLOR[] = {BRIGHT_YELLOW, 'E', 'R', 'R', 'O', 'R', 45 + RESET_COLOR, 0}; 46 + static const char FAIL_COLOR[] = {BRIGHT_RED, ' ', 'F', 'A', 'I', 'L', 47 + RESET_COLOR, 0}; 48 + static const char INFO_NORMAL[] = " INFO"; 49 + static const char PASS_NORMAL[] = " PASS"; 50 + static const char ERROR_NORMAL[] = "ERROR"; 51 + static const char FAIL_NORMAL[] = " FAIL"; 52 + const char *INFO = INFO_NORMAL; 53 + const char *PASS = PASS_NORMAL; 54 + const char *ERROR = ERROR_NORMAL; 55 + const char *FAIL = FAIL_NORMAL; 56 + 57 + /* Verbosity setting for INFO messages */ 58 + #define VQUIET 0 59 + #define VCRITICAL 1 60 + #define VINFO 2 61 + #define VMAX VINFO 62 + int _verbose = VCRITICAL; 63 + 64 + /* Functional test return codes */ 65 + #define RET_PASS 0 66 + #define RET_ERROR -1 67 + #define RET_FAIL -2 68 + 69 + /** 70 + * log_color() - Use colored output for PASS, ERROR, and FAIL strings 71 + * @use_color: use color (1) or not (0) 72 + */ 73 + void log_color(int use_color) 74 + { 75 + if (use_color) { 76 + PASS = PASS_COLOR; 77 + ERROR = ERROR_COLOR; 78 + FAIL = FAIL_COLOR; 79 + } else { 80 + PASS = PASS_NORMAL; 81 + ERROR = ERROR_NORMAL; 82 + FAIL = FAIL_NORMAL; 83 + } 84 + } 85 + 86 + /** 87 + * log_verbosity() - Set verbosity of test output 88 + * @verbose: Enable (1) verbose output or not (0) 89 + * 90 + * Currently setting verbose=1 will enable INFO messages and 0 will disable 91 + * them. FAIL and ERROR messages are always displayed. 92 + */ 93 + void log_verbosity(int level) 94 + { 95 + if (level > VMAX) 96 + level = VMAX; 97 + else if (level < 0) 98 + level = 0; 99 + _verbose = level; 100 + } 101 + 102 + /** 103 + * print_result() - Print standard PASS | ERROR | FAIL results 104 + * @ret: the return value to be considered: 0 | RET_ERROR | RET_FAIL 105 + * 106 + * print_result() is primarily intended for functional tests. 107 + */ 108 + void print_result(int ret) 109 + { 110 + const char *result = "Unknown return code"; 111 + 112 + switch (ret) { 113 + case RET_PASS: 114 + result = PASS; 115 + break; 116 + case RET_ERROR: 117 + result = ERROR; 118 + break; 119 + case RET_FAIL: 120 + result = FAIL; 121 + break; 122 + } 123 + printf("Result: %s\n", result); 124 + } 125 + 126 + /* log level macros */ 127 + #define info(message, vargs...) \ 128 + do { \ 129 + if (_verbose >= VINFO) \ 130 + fprintf(stderr, "\t%s: "message, INFO, ##vargs); \ 131 + } while (0) 132 + 133 + #define error(message, err, args...) \ 134 + do { \ 135 + if (_verbose >= VCRITICAL) {\ 136 + if (err) \ 137 + fprintf(stderr, "\t%s: %s: "message, \ 138 + ERROR, strerror(err), ##args); \ 139 + else \ 140 + fprintf(stderr, "\t%s: "message, ERROR, ##args); \ 141 + } \ 142 + } while (0) 143 + 144 + #define fail(message, args...) \ 145 + do { \ 146 + if (_verbose >= VCRITICAL) \ 147 + fprintf(stderr, "\t%s: "message, FAIL, ##args); \ 148 + } while (0) 149 + 150 + #endif
+33
tools/testing/selftests/futex/run.sh
··· 1 + #!/bin/sh 2 + 3 + ############################################################################### 4 + # 5 + # Copyright © International Business Machines Corp., 2009 6 + # 7 + # This program is free software; you can redistribute it and/or modify 8 + # it under the terms of the GNU General Public License as published by 9 + # the Free Software Foundation; either version 2 of the License, or 10 + # (at your option) any later version. 11 + # 12 + # DESCRIPTION 13 + # Run all tests under the functional, performance, and stress directories. 14 + # Format and summarize the results. 15 + # 16 + # AUTHOR 17 + # Darren Hart <dvhart@linux.intel.com> 18 + # 19 + # HISTORY 20 + # 2009-Nov-9: Initial version by Darren Hart <dvhart@linux.intel.com> 21 + # 22 + ############################################################################### 23 + 24 + # Test for a color capable shell and pass the result to the subdir scripts 25 + USE_COLOR=0 26 + tput setf 7 27 + if [ $? -eq 0 ]; then 28 + USE_COLOR=1 29 + tput sgr0 30 + fi 31 + export USE_COLOR 32 + 33 + (cd functional; ./run.sh)