diff options
author | Darren Hart <dvhltc@us.ibm.com> | 2009-11-11 00:26:48 -0800 |
---|---|---|
committer | Darren Hart <dvhltc@us.ibm.com> | 2009-11-11 00:26:48 -0800 |
commit | 2462c22b4e23574735ca98819f704c0d558112e4 (patch) | |
tree | 9a743b01a30991222adf2280c5668c4441c90802 | |
download | futextest-2462c22b4e23574735ca98819f704c0d558112e4.tar.gz |
Initial public commit
Signed-off-by: Darren Hart <dvhltc@us.ibm.com>
-rw-r--r-- | .gitignore | 5 | ||||
-rw-r--r-- | Makefile | 8 | ||||
-rw-r--r-- | README | 234 | ||||
-rw-r--r-- | functional/Makefile | 18 | ||||
-rw-r--r-- | functional/futex_requeue_pi.c | 429 | ||||
-rw-r--r-- | functional/futex_requeue_pi_mismatched_ops.c | 146 | ||||
-rw-r--r-- | functional/futex_requeue_pi_signal_restart.c | 209 | ||||
-rw-r--r-- | functional/futex_wait_timeout.c | 92 | ||||
-rwxr-xr-x | functional/run.sh | 69 | ||||
-rw-r--r-- | include/futextest.h | 220 | ||||
-rwxr-xr-x | performance/run.sh | 35 | ||||
-rwxr-xr-x | run.sh | 38 | ||||
-rwxr-xr-x | stress/run.sh | 35 |
13 files changed, 1538 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c9b062c --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +functional/futex_requeue_pi +functional/futex_requeue_pi_signal_restart +functional/futex_wait_timeout + +functional/futex_requeue_pi_mismatched_ops diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..b3c4111 --- /dev/null +++ b/Makefile @@ -0,0 +1,8 @@ +SUBDIRS = functional performance stress + +.PHONY: all clean +all: + for DIR in $(SUBDIRS); do (cd $$DIR; ${MAKE} all); done + +clean: + for DIR in $(SUBDIRS); do (cd $$DIR; ${MAKE} clean); done @@ -0,0 +1,234 @@ +Futex Test +========== +Futex Test is intended to thoroughly test the Linux kernel futex system call +API. To the extent possible, each test is implemented using raw system calls +as well as the glibc pthread library. + +Tests shall fall under one of three categories: +o Functional + Functional tests shall test the documented behavior of the futex operation + code under test. This includes checking for proper behavior under normal use, + odd corner cases, regression tests, and abject abuse and misuse. + +o Stress + Stress tests shall impose a heavy load on the futex infrastructure. Tests + should stress the bottlenecks of the futex implementation, such as the + hashbucket locks, the mmap_sem (for shared futexes), and scheduler wakeups. + +o Performance + Performance tests shall measure quantifiable attributes of futex usage, such + as timeout latency, operations per second, scheduler wake-ups, etc. + +Quick Start +----------- +# make +# ./run.sh + +Design and Implementation Goals +------------------------------- +o Tests should be as self contained as is practical so as to facilitate sharing + the individual tests on mailing list discussions and bug reports. +o The build system shall remain as simple as possible, avoiding any archive or + shared object building and linking. +o Where possible, any helper functions or other package-wide code shall be + implemented in header files, avoiding the need to compile intermediate object + files. +o External dependendencies shall remain as minimal as possible. Currently gcc + and glibc are the only dependencies. +o Tests return 0 for success and < 0 for failure. + +Output Formatting +----------------- +Test output shall be easily parsable by both human and machine. Title and +results are printed to stdout, while intermediate ERROR or FAIL messages are +sent to stderr. Tests shall support the -c option to print PASS, FAIL, and +ERROR strings in color for easy visual parsing. Output shall conform to the +following format: + +test_name: Description of the test + Arguments: arg1=val1 #units specified for clarity where appropriate + ERROR: Description of unexpected error + FAIL: Reason for test failure + # FIXME: Perhaps an " INFO: informational message" option would be + # useful here. Using -v to toggle it them on and off, as with -c. + # there may be multiple ERROR or FAIL messages +Result: (PASS|FAIL|ERROR) # functional tests +Result: (measurement (units)|ERROR) # performance tests +Result: (COMPLETED|ERROR) # stress tests + +Naming +------ +o FIXME: decide on a sane test naming scheme. Currently the tests are named + based on the primary futex operation they test. Eventually this will become a + problem as we intend to write multiple tests which collide in this namespace. + Perhaps something like "wait-wake-1" "wait-wake-2" is adequate, leaving the + detailed description in the test source and the output. Opinions welcome! + +Coding Style +------------ +o The Futex Test project adheres to the coding standards set forth by Linux + kernel as defined in the Linux source Documentation/CodingStyle. + + +-------------------------------------------------------------------------------- + + +Darren's Notes +============== +TODO +---- +o Incorporate robust futexes +o execve testing + - http://git.kernel.org/?p=linux/kernel/git/tip/linux-2.6-tip.git;a=commit;h=322a2c100a8998158445599ea437fb556aa95b11 + - http://git.kernel.org/?p=linux/kernel/git/tip/linux-2.6-tip.git;a=commit;h=fc6b177dee33365ccb29fe6d2092223cf8d679f9 +o http://git.kernel.org/?p=linux/kernel/git/tip/linux-2.6-tip.git;a=commit;h=eaaea8036d0261d87d7072c5bc88c7ea730c18ac + +Futex Op Codes +-------------- +FUTEX_WAIT +FUTEX_WAKE +FUTEX_FD +FUTEX_REQUEUE +FUTEX_CMP_REQUEUE +FUTEX_WAKE_OP +FUTEX_LOCK_PI +FUTEX_UNLOCK_PI +FUTEX_TRYLOCK_PI +FUTEX_WAIT_BITSET +FUTEX_WAKE_BITSET +FUTEX_WAIT_REQUEUE_PI +FUTEX_CMP_REQUEUE_PI + +Syscalls to Test +---------------- +futex_wake +futex_wake_op +futex_cmp_requeue +futex_wait +futex_lock_pi +futex_unlock_pi +futex_wait_requeue_pi +futex_cmp_requeue_pi + +Functional Tests +---------------- +requeue_pi/* + Exercise the FUTEX_WAIT_REQUEUE_PI and FUTEX_CMP_REQUEUE_PI op codes, + under every possible combination of the following scenarios: + + o shared and private futexes + o CLOCK_MONOTONIC and CLOCK_REALTIME timeouts (and none) + o Signal handling prior to and post requeue + - http://bugzilla.kernel.org/show_bug.cgi?id=14289 + o correct and incorrect settings for val + o target futex owned by waker, owned by third party, unowned + o OWNERDIED reclaim of mutex + o ensure priority ordered wakeup of waiters + + Error and Misuse Cases + ---------------------- + o mixed shared and private futexes (should fail) + o pi source futex + o non-pi target futex + o unmapped shared futex fault handling + o bogus uaddrs + o invalid nr_wake and nr_requeue values + o mismatched wait_requeue and futex_requeue target futexes + o incorrect pairing of futex_wait_requeue_pi with futex_wake + - and the futex_wait with futex_requeue_pi + -http://git.kernel.org/?p=linux/kernel/git/tip/linux-2.6-tip.git;a=commit;h=2bc872036e1c5948b5b02942810bbdd8dbdb9812 + o http://git.kernel.org/?p=linux/kernel/git/tip/linux-2.6-tip.git;a=commit;h=0729e196147692d84d4c099fcff056eba2ed61d8 + + Syscalls Exercised + ------------------ + futex_wait_requeue_pi + futex_requeue + futex_lock_pi + futex_unlock_pi + +pi_lock/* + Exercise the FUTEX_LOCK_PI and FUTEX_UNLOCK_PI op codes, under every + possible combination of the following scenarious: + + o shared and private futexes + o CLOCK_MONOTONIC and CLOCK_REALTIME timeouts (and none) + o Signal handling + o correct and incorrect settings for val + o bogus uaddrs + o contended and uncontended cases + o OWNERDIED reclaim of mutex + + Error and Misuse Cases + ---------------------- + o pi_unlock of a non-pi-locked futex + o pi_lock of an owned non-pi futex + o unmapped shared futex fault handling + o mismatched futex_lock_pi and futex_wake(_op)? calls + o mismatched futex_wait and futex_unlock_pi calls + + Syscalls Exercised + ------------------ + futex_lock_pi + futex_unlock_pi + futex_wait + futex_wake + futex_wake_op + +requeue/* + Exercise the FUTEX_WAIT and the FUTEX_CMP_REQUEUE op codes. Perform + basic testing for FUTEX_REQUEUE, purposefully avoiding its known + flaws. + + Error and Misuse Cases + ---------------------- + + Syscalls Exercised + ------------------ + futex_wait + futex_requeue + +wait/* + Exercise the FUTEX_WAIT and FUTEX_WAKE op codes. + + Error and Misuse Cases + ---------------------- + o spurious wakeup, see ERESTARTSYS lkml thread + - http://lkml.org/lkml/2009/10/10/36 + - http://git.kernel.org/?p=linux/kernel/git/tip/linux-2.6-tip.git;a=commit;h=d58e6576b0deec6f0b9ff8450fe282da18c50883 + + Syscalls Exercised + ------------------ + futex_wait + futex_wake + futex_wake_op + + + +Performance Tests +----------------- + o attempt to expose lock contention issues, such as those exposed by + calling futex_wait on an unowned futex + o rapid lock and unlock of an uncontended futex + o rapid lock and unlock of a heavily conteded futex + o attempt to expose bottlenecks imposed by the shared hash-bucket + implementation + o attempt to expose real-time scheduling overhead + +Stress Tests +------------ + o thousands of threads/processes contending on a single futex + o thousands of threads/processes on thousands of futexes + +Other Thoughts +-------------- +kernel-side futex fault injection + There are a lot of places in futex.c that have to handle faults. I + think some kind of a fault injection system is needed. This could be + enabled via a sysctl or perhaps just configured in to a debug kernel. + Running this test suite in a loop would allow us to achieve some + statistical confidence in these numerous fault paths. + +FUTEX_REQUEUE + This op code is deprecated in favor of FUTEX_CMP_REQUEUE. Do to the + unreliable nature of the op code, only very limited testing can be + performed. diff --git a/functional/Makefile b/functional/Makefile new file mode 100644 index 0000000..4aeac3c --- /dev/null +++ b/functional/Makefile @@ -0,0 +1,18 @@ +INCLUDES = -I../include +CFLAGS = -g -O2 -Wall -D_GNU_SOURCE $(INCLUDES) +LDFLAGS = -lpthread -lrt + +HEADERS = ../include/futextest.h +TARGETS = \ + futex_wait_timeout \ + futex_requeue_pi \ + futex_requeue_pi_signal_restart \ + futex_requeue_pi_mismatched_ops + +.PHONY: all clean +all: $(TARGETS) + +$(TARGETS): $(HEADERS) + +clean: + rm -f $(TARGETS) diff --git a/functional/futex_requeue_pi.c b/functional/futex_requeue_pi.c new file mode 100644 index 0000000..a20a56d --- /dev/null +++ b/functional/futex_requeue_pi.c @@ -0,0 +1,429 @@ +/****************************************************************************** + * + * Copyright © International Business Machines Corp., 2006-2008 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * NAME + * futex_requeue_pi.c + * + * DESCRIPTION + * This test excercises the futex syscall op codes needed for requeuing + * priority inheritance aware POSIX condition variables and mutexes. + * + * AUTHORS + * Sripathi Kodi <sripathik@in.ibm.com> + * Darren Hart <dvhltc@us.ibm.com> + * + * HISTORY + * 2008-Jan-13: Initial version by Sripathi Kodi <sripathik@in.ibm.com> + * 2009-Nov-6: futex test adaptation by Darren Hart <dvhltc@us.ibm.com> + * + *****************************************************************************/ + +#include <errno.h> +#include <limits.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <signal.h> +#include <string.h> +#include "futextest.h" + +#define PRIVATE 1 +#ifdef PRIVATE +#define FUTEX_PRIVATE_FLAG 128 +#define PSHARED PTHREAD_PROCESS_PRIVATE +#else +#define FUTEX_PRIVATE_FLAG 0 +#define PSHARED PTHREAD_PROCESS_SHARED +#endif + +#define THREAD_MAX 10 +#define SIGNAL_PERIOD_US 100 + +pthread_mutex_t mutex; +pthread_barrier_t wake_barrier; +pthread_barrier_t waiter_barrier; +int waiters_woken; +futex_t wait_q = FUTEX_INITIALIZER; + +/* Test option defaults */ +static long timeout_ns = 0; +static int broadcast = 0; +static int owner = 0; +static int locked = 0; + +typedef struct struct_waiter_arg { + long id; + struct timespec *timeout; +} waiter_arg_t; + +void usage(char *prog) +{ + printf("Usage: %s\n", prog); + printf(" -b Broadcast wakeup (all waiters)\n"); + printf(" -c Use color\n"); + printf(" -h Display this help message\n"); + printf(" -l Lock the pi futex across requeue\n"); + printf(" -o Use a third party pi futex owner during requeue\n"); + printf(" -t N Timeout in nanoseconds (default: 100,000)\n"); +} + +int create_pi_mutex(pthread_mutex_t *mutex) +{ + int ret; + pthread_mutexattr_t mutexattr; + + if ((ret = pthread_mutexattr_init(&mutexattr)) != 0) { + fprintf(stderr, "\t%s: pthread_mutexattr_init: %s\n", + ERROR, strerror(ret)); + return -1; + } + if ((ret = pthread_mutexattr_setprotocol(&mutexattr, PTHREAD_PRIO_INHERIT)) != 0) { + fprintf(stderr, "\t%s: pthread_mutexattr_setprotocol: %s\n", + ERROR, strerror(ret)); + pthread_mutexattr_destroy(&mutexattr); + return -1; + } + if ((ret = pthread_mutexattr_setpshared(&mutexattr, PSHARED)) != 0) { + fprintf(stderr, "\t%s: pthread_mutexattr_setpshared(%d): %s\n", + ERROR, PSHARED, strerror(ret)); + pthread_mutexattr_destroy(&mutexattr); + return -1; + } + + int pshared; + pthread_mutexattr_getpshared(&mutexattr, &pshared); + fprintf(stderr, "\tpshared set to %d\n", pshared); + + if ((ret = pthread_mutex_init(mutex, &mutexattr)) != 0) { + printf("pthread_mutex_init: %s\n", strerror(ret)); + pthread_mutexattr_destroy(&mutexattr); + return -1; + } + + fprintf(stderr, "\tmutex.__data.__kind: %x\n", mutex->__data.__kind); + + return 0; +} + +int create_rt_thread(pthread_t *pth, void*(*func)(void*), void *arg, int policy, int prio) +{ + int ret; + struct sched_param schedp; + pthread_attr_t attr; + + pthread_attr_init(&attr); + memset(&schedp, 0, sizeof(schedp)); + + if ((ret = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED)) != 0) { + fprintf(stderr, "\t%s: pthread_attr_setinheritsched: %s\n", + ERROR, strerror(ret)); + return -1; + } + + if ((ret = pthread_attr_setschedpolicy(&attr, policy)) != 0) { + fprintf(stderr, "\t%s: pthread_attr_setschedpolicy: %s\n", + ERROR, strerror(ret)); + return -1; + } + + schedp.sched_priority = prio; + if ((ret = pthread_attr_setschedparam(&attr, &schedp)) != 0) { + fprintf(stderr, "\t%s: pthread_attr_setschedparam: %s\n", + ERROR, strerror(ret)); + return -1; + } + + if ((ret = pthread_create(pth, &attr, func, arg)) != 0) { + fprintf(stderr, "\t%s: pthread_create: %s\n", + ERROR, strerror(ret)); + return -1; + } + return 0; +} + + +void *waiterfn(void *arg) +{ + waiter_arg_t *args = (waiter_arg_t *)arg; + unsigned int old_val; + int ret; + + fprintf(stderr, "\tWaiter %ld: running\n", args->id); fflush(stderr); + /* Each thread sleeps for a different amount of time + * This is to avoid races, because we don't lock the + * external mutex here */ + usleep(1000 * (long)args->id); + + /* FIXME: need to hold the mutex prior to waiting right?... sort of... */ + + /* cond_wait */ + old_val = wait_q; + pthread_barrier_wait(&waiter_barrier); + ret = futex_wait_requeue_pi(&wait_q, old_val, &(mutex.__data.__lock), + args->timeout, FUTEX_PRIVATE_FLAG); + fprintf(stderr, "\twaiter %ld woke\n", args->id); fflush(stderr); + if (ret < 0) { + ret = -errno; + fprintf(stderr, "\t%s: waiterfn: %s\n", ERROR, strerror(errno)); + pthread_mutex_lock(&mutex); + } + waiters_woken++; + pthread_mutex_unlock(&mutex); + + fprintf(stderr, "\tWaiter %ld: exiting with %d\n", args->id, ret); + return (void*)(long)ret; +} + +void *broadcast_wakerfn(void *arg) +{ + unsigned int old_val; + int nr_wake = 1; + int nr_requeue = INT_MAX; + long lock = (long)arg; + int ret = 0; + pthread_barrier_wait(&waiter_barrier); + usleep(100000); /*icky*/ + fprintf(stderr, "\tWaker: Calling broadcast\n"); + + if (lock) { + fprintf(stderr, "\tCalling FUTEX_LOCK_PI on mutex=%x @ %p\n", + mutex.__data.__lock, &mutex.__data.__lock); + pthread_mutex_lock(&mutex); + } + /* cond_broadcast */ + old_val = wait_q; + ret = futex_cmp_requeue_pi(&wait_q, old_val, &(mutex.__data.__lock), nr_wake, + nr_requeue, FUTEX_PRIVATE_FLAG); + if (ret < 0) { + ret = -errno; + fprintf(stderr, "\t%s: FUTEX_CMP_REQUEUE_PI failed: %s\n", + ERROR, strerror(errno)); + } + + if (pthread_barrier_wait(&wake_barrier) == -EINVAL) + fprintf(stderr, "\t%s: broadcast_wakerfn: %s\n", + ERROR, strerror(errno)); + + if (lock) + pthread_mutex_unlock(&mutex); + + fprintf(stderr, "\tWaker: exiting with %d\n", ret); + return (void *)(long)ret;; +} + +void *signal_wakerfn(void *arg) +{ + long lock = (long)arg; + unsigned int old_val; + int nr_requeue = 0; + int task_count = 0; + int nr_wake = 1; + int ret = 0; + int i = 0; + + pthread_barrier_wait(&waiter_barrier); + while (task_count < THREAD_MAX && waiters_woken < THREAD_MAX) { + fprintf(stderr, "\ttask_count: %d, waiters_woken: %d\n", + task_count, waiters_woken); + if (lock) { + fprintf(stderr, "\tCalling FUTEX_LOCK_PI on mutex=%x @ %p\n", + mutex.__data.__lock, &mutex.__data.__lock); + pthread_mutex_lock(&mutex); + } + fprintf(stderr, "\tWaker: Calling signal\n"); + /* cond_signal */ + old_val = wait_q; + ret = futex_cmp_requeue_pi(&wait_q, old_val, &(mutex.__data.__lock), + nr_wake, nr_requeue, FUTEX_PRIVATE_FLAG); + if (ret < 0) + ret = -errno; + fprintf(stderr, "\tfutex: %x\n", mutex.__data.__lock); + if (lock) { + fprintf(stderr, "\tCalling FUTEX_UNLOCK_PI on mutex=%x @ %p\n", + mutex.__data.__lock, &mutex.__data.__lock); + pthread_mutex_unlock(&mutex); + } + fprintf(stderr, "\tfutex: %x\n", mutex.__data.__lock); + if (ret < 0) { + fprintf(stderr, "\t%s: FUTEX_CMP_REQUEUE_PI failed: %s\n", + ERROR, strerror(errno)); + break; + } + + if (!i) { + fprintf(stderr, "\twaker waiting on wake_barrier\n"); + if (pthread_barrier_wait(&wake_barrier) == -EINVAL) + fprintf(stderr, "\t%s: signal_wakerfn: %s", + ERROR, strerror(errno)); + } + + task_count += ret; + usleep(SIGNAL_PERIOD_US); + i++; + if (i > 1000) { + fprintf(stderr, "\ti>1000, giving up on pending waiters...\n"); + break; + } + } + if (ret >= 0) + ret = task_count; + + fprintf(stderr, "\tWaker: exiting with %d\n", ret); + fprintf(stderr, "\tWaker: waiters_woken: %d\n", waiters_woken); + return (void *)(long)ret; +} + +void *third_party_blocker(void *arg) +{ + pthread_mutex_lock(&mutex); + if (pthread_barrier_wait(&wake_barrier) == -EINVAL) + fprintf(stderr, "\t%s: third_party_blocker: %s", + ERROR, strerror(errno)); + pthread_mutex_unlock(&mutex); + return NULL; +} + +int unit_test(int broadcast, long lock, int third_party_owner, long timeout_ns) +{ + void *(*wakerfn)(void *) = signal_wakerfn; + pthread_t waiter[THREAD_MAX], waker, blocker; + waiter_arg_t args[THREAD_MAX]; + struct timespec ts, *tsp = NULL; + int ret; + long i; + + if (timeout_ns) { + ret = clock_gettime(CLOCK_MONOTONIC, &ts); + time_t secs = (ts.tv_nsec + timeout_ns) / 1000000000; + ts.tv_nsec = (ts.tv_nsec + timeout_ns) % 1000000000; + ts.tv_sec += secs; + tsp = &ts; + } + + if ((ret = pthread_barrier_init(&wake_barrier, NULL, + 1+third_party_owner))) { + fprintf(stderr, "\t%s: pthread_barrier_init(wake_barrier) failed: %s\n", + ERROR, strerror(errno)); + return ret; + } + if ((ret = pthread_barrier_init(&waiter_barrier, NULL, + 1+THREAD_MAX))) { + fprintf(stderr, "\t%s: pthread_barrier_init(waiter_barrier) failed: %s\n", + ERROR, strerror(errno)); + return ret; + } + + if (broadcast) + wakerfn = broadcast_wakerfn; + + if (third_party_owner) { + if ((ret = create_rt_thread(&blocker, third_party_blocker, NULL, + SCHED_FIFO, 1))) { + fprintf(stderr, "\t%s: Creating third party blocker thread failed: %s\n", + ERROR, strerror(errno)); + goto out; + } + } + + waiters_woken = 0; + for (i = 0; i < THREAD_MAX; i++) { + args[i].id = i; + args[i].timeout = tsp; + fprintf(stderr, "\tStarting thread %ld\n", i); fflush(stderr); + if ((ret = create_rt_thread(&waiter[i], waiterfn, (void *)&args[i], + SCHED_FIFO, 1))) { + fprintf(stderr, "\t%s: Creating waiting thread failed: %s\n", + ERROR, strerror(errno)); + goto out; + } + } + if ((ret = create_rt_thread(&waker, wakerfn, (void *)lock, + SCHED_FIFO, 1))) { + fprintf(stderr, "\t%s: Creating waker thread failed: %s\n", + ERROR, strerror(errno)); + goto out; + } + + /* Wait for threads to finish */ + for (i=0; i<THREAD_MAX; i++) { + pthread_join(waiter[i], NULL); + } + if (third_party_owner) + pthread_join(blocker, NULL); + pthread_join(waker, NULL); + +out: + if ((ret = pthread_barrier_destroy(&wake_barrier))) + fprintf(stderr, "\t%s: pthread_barrier_destroy(wake_barrier) failed: %s\n", + ERROR, strerror(errno)); + if ((ret = pthread_barrier_destroy(&waiter_barrier))) + fprintf(stderr, "\t%s: pthread_barrier_destroy(waiter_barrier) failed: %s\n", + ERROR, strerror(errno)); + return ret; +} + +int main(int argc, char *argv[]) +{ + int c, ret; + + while ((c = getopt(argc, argv, "bchlot:")) != -1) { + switch(c) { + case 'b': + broadcast = 1; + break; + case 'c': + futextest_use_color(1); + break; + case 'h': + usage(basename(argv[0])); + exit(0); + case 'l': + locked = 1; + break; + case 'o': + owner = 1; + break; + case 't': + timeout_ns = atoi(optarg); + break; + default: + usage(basename(argv[0])); + exit(1); + } + } + + printf("%s: Test requeue functionality\n", basename(argv[0])); + printf("\tArguments: broadcast=%d locked=%d owner=%d timeout=%ldns\n", + broadcast, locked, owner, timeout_ns); + + if ((ret = create_pi_mutex(&mutex)) != 0) { + printf("Creating pi mutex failed\n"); + exit(1); + } + + /* + * FIXME: unit_test is obsolete now that we parse options and the + * various style of runs are done by run.sh - simplify the code and move + * unit_test into main() + */ + ret = unit_test(broadcast, locked, owner, timeout_ns); + + /* FIXME: need to distinguish between FAIL and ERROR */ + printf("Result: %s\n", ret ? ERROR : PASS); + return ret; +} diff --git a/functional/futex_requeue_pi_mismatched_ops.c b/functional/futex_requeue_pi_mismatched_ops.c new file mode 100644 index 0000000..14707f2 --- /dev/null +++ b/functional/futex_requeue_pi_mismatched_ops.c @@ -0,0 +1,146 @@ +/****************************************************************************** + * + * Copyright © International Business Machines Corp., 2009 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * NAME + * futex_requeue_pi_mismatched_ops.c + * + * DESCRIPTION + * 1. Block a thread using FUTEX_WAIT + * 2. Attempt to use FUTEX_CMP_REQUEUE_PI on the futex from 1. + * 3. The kernel must detect the mismatch and return -EINVAL. + * + * AUTHOR + * Darren Hart <dvhltc@us.ibm.com> + * + * HISTORY + * 2009-Nov-9: Initial version by Darren Hart <dvhltc@us.ibm.com> + * + *****************************************************************************/ + +#include <errno.h> +#include <getopt.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include "futextest.h" + +futex_t f1 = FUTEX_INITIALIZER; +futex_t f2 = FUTEX_INITIALIZER; +int child_ret = 0; + +void usage(char *prog) +{ + printf("Usage: %s\n", prog); + printf(" -c Use color\n"); + printf(" -h Display this help message\n"); +} + +void *blocking_child(void *arg) +{ + child_ret = futex_wait(&f1, f1, NULL, FUTEX_PRIVATE_FLAG); + if (child_ret < 0) { + child_ret = -errno; + fprintf(stderr, "\t%s: futex_wait: %s\n", ERROR, strerror(errno)); + } + return (void *)&child_ret; +} + +int main(int argc, char *argv[]) +{ + pthread_t child; + int ret = 0; + int c; + + while ((c = getopt(argc, argv, "ch")) != -1) { + switch(c) { + case 'c': + futextest_use_color(1); + break; + case 'h': + usage(basename(argv[0])); + exit(0); + default: + usage(basename(argv[0])); + exit(1); + } + } + + printf("%s: Detect mismatched requeue_pi operations\n", + basename(argv[0])); + + ret = pthread_create(&child, NULL, blocking_child, NULL); + if (ret) { + fprintf(stderr, "\t%s: pthread_create: %s\n", + ERROR, strerror(errno)); + goto out; + } + /* Allow the child to block in the kernel. */ + sleep(1); + + /* + * The kernel should detect the waiter did not setup the + * q->requeue_pi_key and return -EINVAL. If it does not, + * it likely gave the lock to the child, which is now hung + * in the kernel. + */ + ret = futex_cmp_requeue_pi(&f1, f1, &f2, 1, 0, FUTEX_PRIVATE_FLAG); + if (ret < 0) { + ret = -errno; + if (ret == -EINVAL) { + /* + * The kernel correctly detected the mismatched + * requeue_pi target and aborted. Wake the child with + * FUTEX_WAKE. + */ + ret = futex_wake(&f1, f1, 1, FUTEX_PRIVATE_FLAG); + if (ret == 1) + ret = 0; + else if (ret < 0) + fprintf(stderr, "\t%s: futex_wake: %s\n", + ERROR, strerror(errno)); + else { + fprintf(stderr, "\t%s: futex_wake did not wake" + "the child\n", ERROR); + ret = -1; + } + } else { + fprintf(stderr, "\t%s: futex_cmp_requeue_pi: %s\n", + ERROR, strerror(errno)); + } + } else if (ret > 0) { + fprintf(stderr, "\t%s: futex_cmp_requeue_pi failed to detect " + "the mismatch\n", FAIL); + } else { + fprintf(stderr, "\t%s: futex_cmp_requeue_pi found no waiters\n", + ERROR); + ret = -1; + } + + pthread_join(child, NULL); + + if (!ret) + ret = child_ret; + + + out: + /* If the kernel crashes, we shouldn't return at all. */ + printf("Result: %s\n", ret == 0 ? PASS : FAIL); + return ret; +} diff --git a/functional/futex_requeue_pi_signal_restart.c b/functional/futex_requeue_pi_signal_restart.c new file mode 100644 index 0000000..dbaf23e --- /dev/null +++ b/functional/futex_requeue_pi_signal_restart.c @@ -0,0 +1,209 @@ +/****************************************************************************** + * + * Copyright © International Business Machines Corp., 2006-2008 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * NAME + * requeue_pi_sig_restart.c + * + * DESCRIPTION + * This test exercises the futex_wait_requeue_pi signal restart after a + * deliberate wake-up. + * + * AUTHORS + * Darren Hart <dvhltc@us.ibm.com> + * + * HISTORY + * 2008-May-5: Initial version by Darren Hart <dvhltc@us.ibm.com> + * + *****************************************************************************/ + +#include <errno.h> +#include <getopt.h> +#include <limits.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "futextest.h" + +futex_t f1 = FUTEX_INITIALIZER; +futex_t f2 = FUTEX_INITIALIZER; + +typedef struct struct_waiter_arg { + long id; + struct timespec *timeout; +} waiter_arg_t; + +void usage(char *prog) +{ + printf("Usage: %s\n", prog); + printf(" -c Use color\n"); + printf(" -h Display this help message\n"); +} + +int create_rt_thread(pthread_t *pth, void*(*func)(void*), void *arg, int policy, int prio) +{ + int ret; + struct sched_param schedp; + pthread_attr_t attr; + + pthread_attr_init(&attr); + memset(&schedp, 0, sizeof(schedp)); + + if ((ret = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED)) != 0) { + fprintf(stderr, "\t%s: pthread_attr_setinheritsched: %s\n", + ERROR, strerror(ret)); + return -1; + } + + if ((ret = pthread_attr_setschedpolicy(&attr, policy)) != 0) { + fprintf(stderr, "\t%s: pthread_attr_setschedpolicy: %s\n", + ERROR, strerror(ret)); + return -1; + } + + schedp.sched_priority = prio; + if ((ret = pthread_attr_setschedparam(&attr, &schedp)) != 0) { + fprintf(stderr, "\t%s: pthread_attr_setschedparam: %s\n", + ERROR, strerror(ret)); + return -1; + } + + if ((ret = pthread_create(pth, &attr, func, arg)) != 0) { + fprintf(stderr, "\t%s: pthread_create: %s\n", + ERROR, strerror(ret)); + return -1; + } + return 0; +} + +void handle_signal(int signo) +{ + fprintf(stderr, "\thandled signal: %d\n", signo); +} + +void *waiterfn(void *arg) +{ + unsigned int old_val; + int ret; + + fprintf(stderr, "\tWaiter running\n"); + + fprintf(stderr, "\tCalling FUTEX_LOCK_PI on f2=%x @ %p\n", f2, &f2); + /* cond_wait */ + old_val = f1; + ret = futex_wait_requeue_pi(&f1, old_val, &(f2), NULL, FUTEX_PRIVATE_FLAG); + if (ret < 0) { + ret = -errno; + fprintf(stderr, "\t%s: waiterfn: %s\n", ERROR, strerror(errno)); + } + fprintf(stderr, "\tFUTEX_WAIT_REQUEUE_PI returned: %d\n", ret); fflush(stdout); + fprintf(stderr, "\tw1:futex: %x\n", f2); fflush(stdout); + if (ret) + futex_lock_pi(&f2, 0, 0, FUTEX_PRIVATE_FLAG); + futex_unlock_pi(&f2, FUTEX_PRIVATE_FLAG); + + fprintf(stderr, "\tWaiter exiting with %d\n", ret); fflush(stdout); + fprintf(stderr, "\tw2:futex: %x\n", f2); fflush(stdout); + return (void*)(long)ret; +} + + +int main(int argc, char *argv[]) +{ + unsigned int old_val; + struct sigaction sa; + pthread_t waiter; + int c, ret = 0; + + while ((c = getopt(argc, argv, "ch")) != -1) { + switch(c) { + case 'c': + futextest_use_color(1); + break; + case 'h': + usage(basename(argv[0])); + exit(0); + default: + usage(basename(argv[0])); + exit(1); + } + } + + printf("%s: Test signal handling during requeue_pi\n", basename(argv[0])); + printf("\tArguments: <none>\n"); + + sa.sa_handler = handle_signal; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + if (sigaction(SIGUSR1, &sa, NULL)) { + fprintf(stderr, "\t%s: sigaction: %s\n", ERROR, strerror(errno)); + exit(1); + } + + fprintf(stderr, "\tm1:futex: %x\n", f2); + fprintf(stderr, "\tCreating waiter\n"); + if ((ret = create_rt_thread(&waiter, waiterfn, NULL, SCHED_FIFO, 1))) { + perror("Creating waiting thread failed"); + exit(1); + } + fprintf(stderr, "\tm2:futex: %x\n", f2); + + fprintf(stderr, "\tCalling FUTEX_LOCK_PI on mutex=%x @ %p\n", f2, &f2); + + futex_lock_pi(&f2, 0, 0, FUTEX_PRIVATE_FLAG); + fprintf(stderr, "\tm3:futex: %x\n", f2); + + fprintf(stderr, "\tWaking waiter via FUTEX_CMP_REQUEUE_PI\n");fflush(stdout); + /* cond_signal */ + old_val = f1; + ret = futex_cmp_requeue_pi(&f1, old_val, &(f2), + 1, 0, FUTEX_PRIVATE_FLAG); + if (ret < 0) { + ret = -errno; + fprintf(stderr, "\t%s: FUTEX_CMP_REQUEUE_PI failed: %s\n", + ERROR, strerror(errno)); + /* FIXME - do something sane.... */ + } + fprintf(stderr, "\tm4:futex: %x\n", f2); + + /* give the waiter time to wake and block on the lock */ + sleep(2); + fprintf(stderr, "\tm5:futex: %x\n", f2); + + /* + * signal the waiter to force a syscall restart to + * futex_lock_pi_restart() + */ + fprintf(stderr, "\tIssuing SIGUSR1 to waiter\n"); + pthread_kill(waiter, SIGUSR1); + + /* give the signal time to get to the waiter */ + sleep(2); + fprintf(stderr, "\tm6:futex: %x\n", f2); + fprintf(stderr, "\tCalling FUTEX_UNLOCK_PI on mutex=%x @ %p\n", f2, &f2); + futex_unlock_pi(&f2, FUTEX_PRIVATE_FLAG); + + /* Wait for waiter to finish */ + fprintf(stderr, "\tWaiting for waiter to return\n"); + pthread_join(waiter, NULL); + fprintf(stderr, "\tm7:futex: %x\n", f2); + + printf("Result: %s\n", ret ? ERROR : PASS); + return ret; +} diff --git a/functional/futex_wait_timeout.c b/functional/futex_wait_timeout.c new file mode 100644 index 0000000..d419733 --- /dev/null +++ b/functional/futex_wait_timeout.c @@ -0,0 +1,92 @@ +/****************************************************************************** + * + * Copyright © International Business Machines Corp., 2009 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * NAME + * futex_wait.c + * + * DESCRIPTION + * Block on a futex and wait for timeout. + * + * AUTHOR + * Darren Hart <dvhltc@us.ibm.com> + * + * HISTORY + * 2009-Nov-6: Initial version by Darren Hart <dvhltc@us.ibm.com> + * + *****************************************************************************/ + +#include <errno.h> +#include <getopt.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include "futextest.h" + +static long timeout_ns = 100000; /* 100us default timeout */ + +void usage(char *prog) +{ + printf("Usage: %s\n", prog); + printf(" -c Use color\n"); + printf(" -h Display this help message\n"); + printf(" -t N Timeout in nanoseconds (default: 100,000)\n"); +} + +int main(int argc, char *argv[]) +{ + futex_t f1 = FUTEX_INITIALIZER; + struct timespec to; + int ret = 0; + int c; + + while ((c = getopt(argc, argv, "cht:")) != -1) { + switch(c) { + case 'c': + futextest_use_color(1); + break; + case 'h': + usage(basename(argv[0])); + exit(0); + case 't': + timeout_ns = atoi(optarg); + break; + default: + usage(basename(argv[0])); + exit(1); + } + } + + printf("%s: Block on a futex and wait for timeout\n", basename(argv[0])); + printf("\tArguments: timeout=%ldns\n", timeout_ns); + + /* 100us relative timeout */ + to.tv_sec = 0; + to.tv_nsec = timeout_ns; + ret = futex_wait(&f1, f1, &to, FUTEX_PRIVATE_FLAG); + if (ret < 0) { + ret = -errno; + if (ret == -ETIMEDOUT) + ret = 0; + else + perror("ERROR: futex_wait"); + } + + printf("Result: %s\n", ret ? ERROR : PASS); + return ret; +} diff --git a/functional/run.sh b/functional/run.sh new file mode 100755 index 0000000..d32d6fd --- /dev/null +++ b/functional/run.sh @@ -0,0 +1,69 @@ +#!/bin/sh + +############################################################################### +# +# Copyright © International Business Machines Corp., 2009 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See +# the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# NAME +# run.sh +# +# DESCRIPTION +# Run tests in the current directory. +# +# AUTHOR +# Darren Hart <dvhltc@us.ibm.com> +# +# HISTORY +# 2009-Nov-9: Initial version by Darren Hart <dvhltc@us.ibm.com> +# +############################################################################### + +echo +# requeue pi testing +# without timeouts +./futex_requeue_pi +./futex_requeue_pi -c -b +./futex_requeue_pi -c -b -l +./futex_requeue_pi -c -b -o +./futex_requeue_pi -c -l +./futex_requeue_pi -c -o +# with timeouts +./futex_requeue_pi -c -b -l -t 5000 +./futex_requeue_pi -c -l -t 5000 +./futex_requeue_pi -c -b -l -t 500000 +./futex_requeue_pi -c -l -t 500000 +./futex_requeue_pi -c -b -t 5000 +./futex_requeue_pi -c -t 5000 +./futex_requeue_pi -c -b -t 500000 +./futex_requeue_pi -c -t 500000 +./futex_requeue_pi -c -b -o -t 5000 +./futex_requeue_pi -c -l -t 5000 +./futex_requeue_pi -c -b -o -t 500000 +./futex_requeue_pi -c -l -t 500000 +# with long timeout +./futex_requeue_pi -c -b -l -t 2000000000 +./futex_requeue_pi -c -l -t 2000000000 + + +echo +./futex_requeue_pi_mismatched_ops -c + +echo +./futex_requeue_pi_signal_restart -c + +echo +./futex_wait_timeout -c diff --git a/include/futextest.h b/include/futextest.h new file mode 100644 index 0000000..9d1c90f --- /dev/null +++ b/include/futextest.h @@ -0,0 +1,220 @@ +/****************************************************************************** + * + * Copyright © International Business Machines Corp., 2009 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * NAME + * futex.h + * + * DESCRIPTION + * Glibc independent futex library for testing kernel functionality. + * + * AUTHOR + * Darren Hart <dvhltc@us.ibm.com> + * + * HISTORY + * 2009-Nov-6: Initial version by Darren Hart <dvhltc@us.ibm.com> + * + *****************************************************************************/ + +#include <unistd.h> +#include <sys/syscall.h> +#include <sys/types.h> +#include <linux/futex.h> + +/* + * Define PASS, ERROR, and FAIL strings with and without color escape + * sequences, default to no color. + */ +#define ESC 0x1B, '[' +#define BRIGHT '1' +#define GREEN '3', '2' +#define YELLOW '3', '3' +#define RED '3', '1' +#define ESCEND 'm' +#define BRIGHT_GREEN ESC, BRIGHT, ';', GREEN, ESCEND +#define BRIGHT_YELLOW ESC, BRIGHT, ';', YELLOW, ESCEND +#define BRIGHT_RED ESC, BRIGHT, ';', RED, ESCEND +#define RESET_COLOR ESC, '0', 'm' +char PASS_COLOR[] = {BRIGHT_GREEN, ' ', 'P', 'A', 'S', 'S', RESET_COLOR, 0}; +char ERROR_COLOR[] = {BRIGHT_YELLOW, 'E', 'R', 'R', 'O', 'R', RESET_COLOR, 0}; +char FAIL_COLOR[] = {BRIGHT_RED, ' ', 'F', 'A', 'I', 'L', RESET_COLOR, 0}; +char PASS_NORMAL[] = " PASS"; +char ERROR_NORMAL[] = "ERROR"; +char FAIL_NORMAL[] = " FAIL"; +char *PASS = PASS_NORMAL; +char *ERROR = ERROR_NORMAL; +char *FAIL = FAIL_NORMAL; + +typedef volatile __uint32_t futex_t; +#define FUTEX_INITIALIZER 0 + +/* Define the newer op codes if the system header file is not up to date. */ +#ifndef FUTEX_WAIT_REQUEUE_PI +#define FUTEX_WAIT_REQUEUE_PI 11 +#endif +#ifndef FUTEX_CMP_REQUEUE_PI +#define FUTEX_CMP_REQUEUE_PI 12 +#endif +#ifndef FUTEX_WAIT_REQUEUE_PI_PRIVATE +#define FUTEX_WAIT_REQUEUE_PI_PRIVATE (FUTEX_WAIT_REQUEUE_PI | \ + FUTEX_PRIVATE_FLAG) +#endif +#ifndef FUTEX_REQUEUE_PI_PRIVATE +#define FUTEX_CMP_REQUEUE_PI_PRIVATE (FUTEX_CMP_REQUEUE_PI | \ + FUTEX_PRIVATE_FLAG) +#endif + +/** + * futex() - SYS_futex syscall wrapper + * @uaddr: address of first futex + * @op: futex op code + * @val: typically expected value of uaddr, but varies by op + * @timeout: typically an absolute struct timespec (except where noted + * otherwise). Overloaded by some ops + * @uaddr2: address of second futex for some ops\ + * @val3: varies by op + * @opflags: flags to be bitwise OR'd with op, such as FUTEX_PRIVATE_FLAG + * + * futex() is used by all the following futex op wrappers. It can also be + * used for misuse and abuse testing. Generally, the specific op wrappers + * should be used instead. + * + * These argument descriptions are the defaults for all + * like-named arguments in the following wrappers except where noted below. + */ +#define futex(uaddr, op, val, timeout, uaddr2, val3, opflags) \ + syscall(SYS_futex, uaddr, op | opflags, val, timeout, uaddr2, val3); + +/** + * futex_wait() - block on uaddr with optional timeout + * @timeout: relative timeout + */ +#define futex_wait(uaddr, val, timeout, opflags) \ + futex(uaddr, FUTEX_WAIT, val, timeout, NULL, 0, opflags) + +/** + * futex_wake() - wake one or more tasks blocked on uaddr + * @nr_wake: wake up to this many tasks + */ +#define futex_wake(uaddr, val, nr_wake, opflags) \ + futex(uaddr, FUTEX_WAKE, val, NULL, NULL, nr_wake, opflags) + +/** + * futex_wait_bitset() - block on uaddr with bitset + * @bitset: bitset to be used with futex_wake_bitset + */ +#define futex_wait_bitset(uaddr, val, timeout, bitset, opflags) \ + futex(uaddr, FUTEX_WAIT_BITSET, val, timeout, NULL, bitset, opflags) + +/** + * futex_wake_bitset() - wake one or more tasks blocked on uaddr with bitset + * @bitset: bitset to compare with that used in futex_wait_bitset + */ +#define futex_wake_bitset(uaddr, val, nr_wake, bitset, opflags) \ + futex(uaddr, FUTEX_WAKE_BITSET, val, NULL, NULL, bitset, opflags) + +/** + * futex_lock_pi() - block on uaddr as a PI mutex + * @detect: whether (1) or not (0) to perform deadlock detection + */ +#define futex_lock_pi(uaddr, timeout, detect, opflags) \ + futex(uaddr, FUTEX_LOCK_PI, detect, timeout, NULL, 0, opflags) + +/** + * futex_unlock_pi() - release uaddr as a PI mutex, waking the top waiter + */ +#define futex_unlock_pi(uaddr, opflags) \ + futex(uaddr, FUTEX_UNLOCK_PI, 0, NULL, NULL, 0, opflags) + +/** + * futex_wake_op() - FIXME: COME UP WITH A GOOD ONE LINE DESCRIPTION + */ +#define futex_wake_op(uaddr, uaddr2, nr_wake, nr_wake2, wake_op, opflags) \ + futex(uaddr, FUTEX_WAKE_OP, nr_wake, nr_wake2, uaddr2, wake_op, opflags) + +/** + * futex_requeue() - requeue without expected value comparison, deprecated + * @nr_wake: wake up to this many tasks + * @nr_requeue: requeue up to this many tasks + * + * Due to its inherently racy implementation, futex_requeue() is deprecated in + * favor of futex_cmp_requeue(). + */ +#define futex_requeue(uaddr, uaddr2, nr_wake, nr_requeue, opflags) \ + futex(uaddr, FUTEX_REQUEUE, nr_wake, nr_requeue, uaddr2, 0, opflags) + +/** + * futex_cmp_requeue() - requeue tasks from uaddr to uaddr2 + * @nr_wake: wake up to this many tasks + * @nr_requeue: requeue up to this many tasks + */ +#define futex_cmp_requeue(uaddr, val, uaddr2, nr_wake, nr_requeue, opflags) \ + futex(uaddr, FUTEX_CMP_REQUEUE, nr_wake, nr_requeue, uaddr2, val, \ + opflags) + +/** + * futex_wait_requeue_pi() - block on uaddr and prepare to requeue to uaddr2 + * @uaddr: non-PI futex source + * @uaddr2: PI futex target + * + * This is the first half of the requeue_pi mechanism. It shall always be + * paired with futex_cmp_requeue_pi(). + */ +#define futex_wait_requeue_pi(uaddr, val, uaddr2, timeout, opflags) \ + futex(uaddr, FUTEX_WAIT_REQUEUE_PI, val, timeout, uaddr2, 0, opflags) + +/** + * futex_cmp_requeue_pi() - requeue tasks from uaddr to uaddr2 (PI aware) + * @uaddr: non-PI futex source + * @uaddr2: PI futex target + * @nr_wake: wake up to this many tasks + * @nr_requeue: requeue up to this many tasks + */ +#define futex_cmp_requeue_pi(uaddr, val, uaddr2, nr_wake, nr_requeue, opflags) \ + futex(uaddr, FUTEX_CMP_REQUEUE_PI, nr_wake, nr_requeue, uaddr2, val, \ + opflags) + +/** + * futex_cmpxchg() - Atomic compare and exchange + * @uaddr: The address of the futex to be modified + * @oldval: The expected value of the futex + * @newval: The new value to try and assign the futex + * + * Implement cmpxchg using gcc atomic builtins. + * http://gcc.gnu.org/onlinedocs/gcc-4.1.0/gcc/Atomic-Builtins.html + */ +int futex_cmpxchg(futex_t *uaddr, u_int32_t oldval, u_int32_t newval) +{ + return __sync_val_compare_and_swap(uaddr, oldval, newval); +} + +/** + * futextest_use_color() - Use colored output for PASS, ERROR, and FAIL strings + * @use_color: use color (1) or not (0) + */ +void futextest_use_color(int use_color) +{ + if (use_color) { + PASS = PASS_COLOR; + ERROR = ERROR_COLOR; + FAIL = FAIL_COLOR; + } else { + PASS = PASS_NORMAL; + ERROR = ERROR_NORMAL; + FAIL = FAIL_NORMAL; + } +} diff --git a/performance/run.sh b/performance/run.sh new file mode 100755 index 0000000..655fc39 --- /dev/null +++ b/performance/run.sh @@ -0,0 +1,35 @@ +#!/bin/sh + +############################################################################### +# +# Copyright © International Business Machines Corp., 2009 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See +# the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# NAME +# run.sh +# +# DESCRIPTION +# Run tests in the current directory. +# +# AUTHOR +# Darren Hart <dvhltc@us.ibm.com> +# +# HISTORY +# 2009-Nov-9: Initial version by Darren Hart <dvhltc@us.ibm.com> +# +############################################################################### + +exit 0 @@ -0,0 +1,38 @@ +#!/bin/sh + +############################################################################### +# +# Copyright © International Business Machines Corp., 2009 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See +# the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# NAME +# run.sh +# +# DESCRIPTION +# Run all tests under the functional, performance, and stress directories. +# Format and summarize the results. +# +# AUTHOR +# Darren Hart <dvhltc@us.ibm.com> +# +# HISTORY +# 2009-Nov-9: Initial version by Darren Hart <dvhltc@us.ibm.com> +# +############################################################################### + +(cd functional; ./run.sh) +(cd performance; ./run.sh) +(cd stress; ./run.sh) diff --git a/stress/run.sh b/stress/run.sh new file mode 100755 index 0000000..655fc39 --- /dev/null +++ b/stress/run.sh @@ -0,0 +1,35 @@ +#!/bin/sh + +############################################################################### +# +# Copyright © International Business Machines Corp., 2009 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See +# the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# NAME +# run.sh +# +# DESCRIPTION +# Run tests in the current directory. +# +# AUTHOR +# Darren Hart <dvhltc@us.ibm.com> +# +# HISTORY +# 2009-Nov-9: Initial version by Darren Hart <dvhltc@us.ibm.com> +# +############################################################################### + +exit 0 |