Regression tests for futex(2).
authormpi <mpi@openbsd.org>
Sun, 30 Apr 2017 09:03:58 +0000 (09:03 +0000)
committermpi <mpi@openbsd.org>
Sun, 30 Apr 2017 09:03:58 +0000 (09:03 +0000)
regress/sys/kern/Makefile
regress/sys/kern/futex/Makefile [new file with mode: 0644]
regress/sys/kern/futex/futex.c [new file with mode: 0644]
regress/sys/kern/futex/futex.h [new file with mode: 0644]

index b9bac93..5951d6a 100644 (file)
@@ -1,9 +1,10 @@
-#      $OpenBSD: Makefile,v 1.68 2017/01/13 01:33:14 bluhm Exp $
+#      $OpenBSD: Makefile,v 1.69 2017/04/30 09:03:58 mpi Exp $
 
 SUBDIR+= __syscall access accept dup2 dup2_self exec_self execve exit extent
 SUBDIR+= fchdir
 SUBDIR+= fcntl_dup
 SUBDIR+= flock
+SUBDIR+= futex
 SUBDIR+= getpeereid getrusage gettimeofday itimer 
 SUBDIR+= kqueue mbuf minherit
 SUBDIR+= main-thread-exited
diff --git a/regress/sys/kern/futex/Makefile b/regress/sys/kern/futex/Makefile
new file mode 100644 (file)
index 0000000..4243fd5
--- /dev/null
@@ -0,0 +1,8 @@
+#      $OpenBSD: Makefile,v 1.1 2017/04/30 09:03:58 mpi Exp $
+
+PROG=  futex
+
+LDADD+=        -lpthread
+DPADD+=        ${LIBPTHREAD}
+
+.include <bsd.regress.mk>
diff --git a/regress/sys/kern/futex/futex.c b/regress/sys/kern/futex/futex.c
new file mode 100644 (file)
index 0000000..643aa05
--- /dev/null
@@ -0,0 +1,86 @@
+/*     $OpenBSD: futex.c,v 1.1 2017/04/30 09:03:58 mpi Exp $ */
+/*
+ * Copyright (c) 2017 Martin Pieuchot
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/time.h>
+#include <sys/futex.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "futex.h"
+
+uint32_t lock = 0;
+
+void handler(int);
+void *signaled(void *);
+void *awakener(void *);
+
+int
+main(int argc, char *argv[])
+{
+       struct sigaction sa;
+       struct timespec abs = { 0, 5000 };
+       pthread_t thread;
+
+       /* Incorrect pointer */
+       assert(futex_twait((void *)0xdeadbeef, 1, 0, NULL) == EFAULT);
+
+       /* If (lock != 1) return EAGAIN */
+       assert(futex_twait(&lock, 1, 0, NULL) == EAGAIN);
+
+       /* Deadlock for 5000ns */
+       assert(futex_twait(&lock, 0, CLOCK_REALTIME, &abs) == ETIMEDOUT);
+
+       /* Interrupt a thread waiting on a futex. */
+       memset(&sa, 0, sizeof(sa));
+       sa.sa_handler = handler;
+       assert(sigaction(SIGUSR1, &sa, NULL) == 0);
+       assert(pthread_create(&thread, NULL, signaled, NULL) == 0);
+       usleep(100);
+       assert(pthread_kill(thread, SIGUSR1) == 0);
+       assert(pthread_join(thread, NULL) == 0);
+
+       /* Wait until another thread awakes us. */
+       assert(pthread_create(&thread, NULL, awakener, NULL) == 0);
+       assert(futex_twait(&lock, 0, 0, NULL) == 0);
+       assert(pthread_join(thread, NULL) == 0);
+
+       return 0;
+}
+
+void
+handler(int sig)
+{
+}
+
+void *
+signaled(void *arg)
+{
+       /* Wait until receiving a signal. */
+       assert(futex_twait(&lock, 0, 0, NULL) == EINTR);
+}
+
+void *
+awakener(void *arg)
+{
+       usleep(100);
+       assert(futex_wake(&lock, -1) == 1);
+}
diff --git a/regress/sys/kern/futex/futex.h b/regress/sys/kern/futex/futex.h
new file mode 100644 (file)
index 0000000..c2b382f
--- /dev/null
@@ -0,0 +1,58 @@
+/*     $OpenBSD: futex.h,v 1.1 2017/04/30 09:03:58 mpi Exp $ */
+/*
+ * Copyright (c) 2017 Martin Pieuchot
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+static inline int
+futex_wake(volatile uint32_t *p, int n)
+{
+       return futex(p, FUTEX_WAKE, n, NULL, NULL);
+}
+
+static inline void
+futex_wait(volatile uint32_t *p, int val)
+{
+       while (*p != (uint32_t)val)
+               futex(p, FUTEX_WAIT, val, NULL, NULL);
+}
+
+static inline int
+futex_twait(volatile uint32_t *p, int val, clockid_t clockid,
+    const struct timespec *abs)
+{
+       struct timespec rel;
+
+       if (abs == NULL)
+               return futex(p, FUTEX_WAIT, val, NULL, NULL);
+
+       if (abs->tv_nsec >= 1000000000 || clock_gettime(clockid, &rel))
+               return (EINVAL);
+
+       rel.tv_sec = abs->tv_sec - rel.tv_sec;
+       if ((rel.tv_nsec = abs->tv_nsec - rel.tv_nsec) < 0) {
+               rel.tv_sec--;
+               rel.tv_nsec += 1000000000;
+       }
+       if (rel.tv_sec < 0)
+               return (ETIMEDOUT);
+
+       return futex(p, FUTEX_WAIT, val, &rel, NULL);
+}
+
+static inline int
+futex_requeue(volatile uint32_t *p, int n, int m, volatile uint32_t *q)
+{
+       return futex(p, FUTEX_REQUEUE, n, (void *)(long)m, q);
+}