Initial public commit

Signed-off-by: Darren Hart <dvhltc@us.ibm.com>
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
diff --git a/README b/README
new file mode 100644
index 0000000..41ed174
--- /dev/null
+++ b/README
@@ -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
diff --git a/run.sh b/run.sh
new file mode 100755
index 0000000..0c54a74
--- /dev/null
+++ b/run.sh
@@ -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