aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDarren Hart <dvhart@linux.intel.com>2015-05-13 00:07:52 -0400
committerShuah Khan <shuahkh@osg.samsung.com>2015-05-26 17:58:07 -0400
commit2aa8470f02a9b9e6a410d1264fe6c8fa6c402eff (patch)
tree378e6144e0c81175e26258630f1eae0bd663db85
parent61171d0407b537eff299aea2388773b6c760e6eb (diff)
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>
-rw-r--r--tools/testing/selftests/futex/Makefile11
-rw-r--r--tools/testing/selftests/futex/README62
-rw-r--r--tools/testing/selftests/futex/functional/Makefile24
-rw-r--r--tools/testing/selftests/futex/functional/futex_requeue_pi.c409
-rw-r--r--tools/testing/selftests/futex/functional/futex_requeue_pi_mismatched_ops.c135
-rw-r--r--tools/testing/selftests/futex/functional/futex_requeue_pi_signal_restart.c223
-rw-r--r--tools/testing/selftests/futex/functional/futex_wait_private_mapped_file.c125
-rw-r--r--tools/testing/selftests/futex/functional/futex_wait_timeout.c86
-rw-r--r--tools/testing/selftests/futex/functional/futex_wait_uninitialized_heap.c124
-rw-r--r--tools/testing/selftests/futex/functional/futex_wait_wouldblock.c79
-rwxr-xr-xtools/testing/selftests/futex/functional/run.sh79
-rw-r--r--tools/testing/selftests/futex/include/atomic.h83
-rw-r--r--tools/testing/selftests/futex/include/futextest.h266
-rw-r--r--tools/testing/selftests/futex/include/logging.h150
-rwxr-xr-xtools/testing/selftests/futex/run.sh33
15 files changed, 1889 insertions, 0 deletions
diff --git a/tools/testing/selftests/futex/Makefile b/tools/testing/selftests/futex/Makefile
new file mode 100644
index 000000000000..2c26d59aaaee
--- /dev/null
+++ b/tools/testing/selftests/futex/Makefile
@@ -0,0 +1,11 @@
1SUBDIRS := functional
2
3.PHONY: all clean
4all:
5 for DIR in $(SUBDIRS); do $(MAKE) -C $$DIR $@ ; done
6
7run_tests: all
8 ./run.sh
9
10clean:
11 for DIR in $(SUBDIRS); do $(MAKE) -C $$DIR $@ ; done
diff --git a/tools/testing/selftests/futex/README b/tools/testing/selftests/futex/README
new file mode 100644
index 000000000000..3224a049b196
--- /dev/null
+++ b/tools/testing/selftests/futex/README
@@ -0,0 +1,62 @@
1Futex Test
2==========
3Futex Test is intended to thoroughly test the Linux kernel futex system call
4API.
5
6Functional tests shall test the documented behavior of the futex operation
7code under test. This includes checking for proper behavior under normal use,
8odd corner cases, regression tests, and abject abuse and misuse.
9
10Futextest will also provide example implementation of mutual exclusion
11primitives. These can be used as is in user applications or can serve as
12examples for system libraries. These will likely be added to either a new lib/
13directory or purely as header files under include/, I'm leaning toward the
14latter.
15
16Quick Start
17-----------
18# make
19# ./run.sh
20
21Design and Implementation Goals
22-------------------------------
23o 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.
25o The build system shall remain as simple as possible, avoiding any archive or
26 shared object building and linking.
27o 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.
30o External dependendencies shall remain as minimal as possible. Currently gcc
31 and glibc are the only dependencies.
32o Tests return 0 for success and < 0 for failure.
33
34Output Formatting
35-----------------
36Test output shall be easily parsable by both human and machine. Title and
37results are printed to stdout, while intermediate ERROR or FAIL messages are
38sent to stderr. Tests shall support the -c option to print PASS, FAIL, and
39ERROR strings in color for easy visual parsing. Output shall conform to the
40following format:
41
42test_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
49Result: (PASS|FAIL|ERROR)
50
51Naming
52------
53o 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
59Coding Style
60------------
61o The Futex Test project adheres to the coding standards set forth by Linux
62 kernel as defined in the Linux source Documentation/CodingStyle.
diff --git a/tools/testing/selftests/futex/functional/Makefile b/tools/testing/selftests/futex/functional/Makefile
new file mode 100644
index 000000000000..720023e21781
--- /dev/null
+++ b/tools/testing/selftests/futex/functional/Makefile
@@ -0,0 +1,24 @@
1INCLUDES := -I../include
2CFLAGS := $(CFLAGS) -g -O2 -Wall -D_GNU_SOURCE -pthread $(INCLUDES)
3LDFLAGS := $(LDFLAGS) -pthread -lrt
4
5HEADERS := ../include/futextest.h
6TARGETS := \
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
16all: $(TARGETS)
17
18$(TARGETS): $(HEADERS)
19
20run_tests: all
21 ./run.sh
22
23clean:
24 rm -f $(TARGETS)
diff --git a/tools/testing/selftests/futex/functional/futex_requeue_pi.c b/tools/testing/selftests/futex/functional/futex_requeue_pi.c
new file mode 100644
index 000000000000..3da06ad23996
--- /dev/null
+++ b/tools/testing/selftests/futex/functional/futex_requeue_pi.c
@@ -0,0 +1,409 @@
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
39atomic_t waiters_blocked = ATOMIC_INITIALIZER;
40atomic_t waiters_woken = ATOMIC_INITIALIZER;
41
42futex_t f1 = FUTEX_INITIALIZER;
43futex_t f2 = FUTEX_INITIALIZER;
44futex_t wake_complete = FUTEX_INITIALIZER;
45
46/* Test option defaults */
47static long timeout_ns;
48static int broadcast;
49static int owner;
50static int locked;
51
52struct 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
60void 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
73int 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
111void *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
147void *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
195void *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
260void *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
281int 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
349out:
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
362int 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}
diff --git a/tools/testing/selftests/futex/functional/futex_requeue_pi_mismatched_ops.c b/tools/testing/selftests/futex/functional/futex_requeue_pi_mismatched_ops.c
new file mode 100644
index 000000000000..d5e4f2c4da2a
--- /dev/null
+++ b/tools/testing/selftests/futex/functional/futex_requeue_pi_mismatched_ops.c
@@ -0,0 +1,135 @@
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
33futex_t f1 = FUTEX_INITIALIZER;
34futex_t f2 = FUTEX_INITIALIZER;
35int child_ret = 0;
36
37void 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
46void *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
56int 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}
diff --git a/tools/testing/selftests/futex/functional/futex_requeue_pi_signal_restart.c b/tools/testing/selftests/futex/functional/futex_requeue_pi_signal_restart.c
new file mode 100644
index 000000000000..7f0c756993af
--- /dev/null
+++ b/tools/testing/selftests/futex/functional/futex_requeue_pi_signal_restart.c
@@ -0,0 +1,223 @@
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
37futex_t f1 = FUTEX_INITIALIZER;
38futex_t f2 = FUTEX_INITIALIZER;
39atomic_t requeued = ATOMIC_INITIALIZER;
40
41int waiter_ret = 0;
42
43void 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
52int 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
89void handle_signal(int signo)
90{
91 info("signal received %s requeue\n",
92 requeued.val ? "after" : "prior to");
93}
94
95void *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
121int 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}
diff --git a/tools/testing/selftests/futex/functional/futex_wait_private_mapped_file.c b/tools/testing/selftests/futex/functional/futex_wait_private_mapped_file.c
new file mode 100644
index 000000000000..5f687f247454
--- /dev/null
+++ b/tools/testing/selftests/futex/functional/futex_wait_private_mapped_file.c
@@ -0,0 +1,125 @@
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
39char pad[PAGE_SZ] = {1};
40futex_t val = 1;
41char pad2[PAGE_SZ] = {1};
42
43#define WAKE_WAIT_US 3000000
44struct timespec wait_timeout = { .tv_sec = 5, .tv_nsec = 0};
45
46void 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
55void *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
75int 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}
diff --git a/tools/testing/selftests/futex/functional/futex_wait_timeout.c b/tools/testing/selftests/futex/functional/futex_wait_timeout.c
new file mode 100644
index 000000000000..ab428ca894de
--- /dev/null
+++ b/tools/testing/selftests/futex/functional/futex_wait_timeout.c
@@ -0,0 +1,86 @@
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
30static long timeout_ns = 100000; /* 100us default timeout */
31
32void 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
42int 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}
diff --git a/tools/testing/selftests/futex/functional/futex_wait_uninitialized_heap.c b/tools/testing/selftests/futex/functional/futex_wait_uninitialized_heap.c
new file mode 100644
index 000000000000..fe7aee96844b
--- /dev/null
+++ b/tools/testing/selftests/futex/functional/futex_wait_uninitialized_heap.c
@@ -0,0 +1,124 @@
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
41static int child_blocked = 1;
42static int child_ret;
43void *buf;
44
45void 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
54void *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
69int 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}
diff --git a/tools/testing/selftests/futex/functional/futex_wait_wouldblock.c b/tools/testing/selftests/futex/functional/futex_wait_wouldblock.c
new file mode 100644
index 000000000000..b6b027448825
--- /dev/null
+++ b/tools/testing/selftests/futex/functional/futex_wait_wouldblock.c
@@ -0,0 +1,79 @@
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
33void 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
42int 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}
diff --git a/tools/testing/selftests/futex/functional/run.sh b/tools/testing/selftests/futex/functional/run.sh
new file mode 100755
index 000000000000..e87dbe2a0b0d
--- /dev/null
+++ b/tools/testing/selftests/futex/functional/run.sh
@@ -0,0 +1,79 @@
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
26if [ -z "$USE_COLOR" ]; then
27 tput setf 7
28 if [ $? -eq 0 ]; then
29 USE_COLOR=1
30 tput sgr0
31 fi
32fi
33if [ "$USE_COLOR" -eq 1 ]; then
34 COLOR="-c"
35fi
36
37
38echo
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
65echo
66./futex_requeue_pi_mismatched_ops $COLOR
67
68echo
69./futex_requeue_pi_signal_restart $COLOR
70
71echo
72./futex_wait_timeout $COLOR
73
74echo
75./futex_wait_wouldblock $COLOR
76
77echo
78./futex_wait_uninitialized_heap $COLOR
79./futex_wait_private_mapped_file $COLOR
diff --git a/tools/testing/selftests/futex/include/atomic.h b/tools/testing/selftests/futex/include/atomic.h
new file mode 100644
index 000000000000..f861da3e31ab
--- /dev/null
+++ b/tools/testing/selftests/futex/include/atomic.h
@@ -0,0 +1,83 @@
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
25typedef 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 */
39static inline int
40atomic_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 */
51static inline int
52atomic_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 */
63static inline int
64atomic_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 */
76static inline int
77atomic_set(atomic_t *addr, int newval)
78{
79 addr->val = newval;
80 return newval;
81}
82
83#endif
diff --git a/tools/testing/selftests/futex/include/futextest.h b/tools/testing/selftests/futex/include/futextest.h
new file mode 100644
index 000000000000..b98c3aba7102
--- /dev/null
+++ b/tools/testing/selftests/futex/include/futextest.h
@@ -0,0 +1,266 @@
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
29typedef 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 */
81static inline int
82futex_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 */
91static inline int
92futex_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 */
101static inline int
102futex_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 */
113static inline int
114futex_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 */
124static inline int
125futex_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 */
134static inline int
135futex_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 */
143static inline int
144futex_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 */
159static inline int
160futex_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 */
172static inline int
173futex_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 */
188static inline int
189futex_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 */
203static inline int
204futex_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 */
222static inline u_int32_t
223futex_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 */
234static inline u_int32_t
235futex_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 */
246static inline u_int32_t
247futex_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 */
259static inline u_int32_t
260futex_set(futex_t *uaddr, u_int32_t newval)
261{
262 *uaddr = newval;
263 return newval;
264}
265
266#endif
diff --git a/tools/testing/selftests/futex/include/logging.h b/tools/testing/selftests/futex/include/logging.h
new file mode 100644
index 000000000000..f6ed5c205ba7
--- /dev/null
+++ b/tools/testing/selftests/futex/include/logging.h
@@ -0,0 +1,150 @@
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'
42static const char PASS_COLOR[] = {BRIGHT_GREEN, ' ', 'P', 'A', 'S', 'S',
43 RESET_COLOR, 0};
44static const char ERROR_COLOR[] = {BRIGHT_YELLOW, 'E', 'R', 'R', 'O', 'R',
45 RESET_COLOR, 0};
46static const char FAIL_COLOR[] = {BRIGHT_RED, ' ', 'F', 'A', 'I', 'L',
47 RESET_COLOR, 0};
48static const char INFO_NORMAL[] = " INFO";
49static const char PASS_NORMAL[] = " PASS";
50static const char ERROR_NORMAL[] = "ERROR";
51static const char FAIL_NORMAL[] = " FAIL";
52const char *INFO = INFO_NORMAL;
53const char *PASS = PASS_NORMAL;
54const char *ERROR = ERROR_NORMAL;
55const 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
62int _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 */
73void 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 */
93void 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 */
108void 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...) \
128do { \
129 if (_verbose >= VINFO) \
130 fprintf(stderr, "\t%s: "message, INFO, ##vargs); \
131} while (0)
132
133#define error(message, err, args...) \
134do { \
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...) \
145do { \
146 if (_verbose >= VCRITICAL) \
147 fprintf(stderr, "\t%s: "message, FAIL, ##args); \
148} while (0)
149
150#endif
diff --git a/tools/testing/selftests/futex/run.sh b/tools/testing/selftests/futex/run.sh
new file mode 100755
index 000000000000..4126312ad64e
--- /dev/null
+++ b/tools/testing/selftests/futex/run.sh
@@ -0,0 +1,33 @@
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
25USE_COLOR=0
26tput setf 7
27if [ $? -eq 0 ]; then
28 USE_COLOR=1
29 tput sgr0
30fi
31export USE_COLOR
32
33(cd functional; ./run.sh)