Add test cases for private versus non-private futexes.
authorvisa <visa@openbsd.org>
Sun, 26 Aug 2018 06:50:30 +0000 (06:50 +0000)
committervisa <visa@openbsd.org>
Sun, 26 Aug 2018 06:50:30 +0000 (06:50 +0000)
While here, fix timeout handling in futex_twait(), and fix the return
value of functions awakener() and signaled().

OK mpi@

regress/sys/kern/futex/futex.c
regress/sys/kern/futex/futex.h

index f60f936..61816f2 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: futex.c,v 1.2 2017/04/30 10:11:03 mpi Exp $ */
+/*     $OpenBSD: futex.c,v 1.3 2018/08/26 06:50:30 visa Exp $ */
 /*
  * Copyright (c) 2017 Martin Pieuchot
  *
 
 #include <sys/time.h>
 #include <sys/futex.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
 
 #include <assert.h>
 #include <errno.h>
 #include <pthread.h>
 #include <signal.h>
+#include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 
 #include "futex.h"
 
 uint32_t lock = 0;
+uint32_t *shlock;
 
 void handler(int);
 void *signaled(void *);
@@ -36,21 +40,24 @@ void *awakener(void *);
 int
 main(int argc, char *argv[])
 {
+       char filename[] = "/tmp/futex.XXXXXXXX";
        struct sigaction sa;
-       struct timespec abs = { 0, 5000 };
+       struct timespec tmo = { 0, 5000 };
        pthread_t thread;
+       pid_t pid;
+       int fd, i, status;
 
        /* Invalid operation */
        assert(futex(&lock, 0xFFFF, 0, 0, NULL) == ENOSYS);
 
        /* Incorrect pointer */
-       assert(futex_twait((void *)0xdeadbeef, 1, 0, NULL) == EFAULT);
+       assert(futex_twait((void *)0xdeadbeef, 1, 0, NULL, 0) == EFAULT);
 
        /* If (lock != 1) return EAGAIN */
-       assert(futex_twait(&lock, 1, 0, NULL) == EAGAIN);
+       assert(futex_twait(&lock, 1, 0, NULL, 0) == EAGAIN);
 
        /* Deadlock for 5000ns */
-       assert(futex_twait(&lock, 0, CLOCK_REALTIME, &abs) == ETIMEDOUT);
+       assert(futex_twait(&lock, 0, CLOCK_REALTIME, &tmo, 0) == ETIMEDOUT);
 
        /* Interrupt a thread waiting on a futex. */
        memset(&sa, 0, sizeof(sa));
@@ -63,9 +70,55 @@ main(int argc, char *argv[])
 
        /* Wait until another thread awakes us. */
        assert(pthread_create(&thread, NULL, awakener, NULL) == 0);
-       assert(futex_twait(&lock, 0, 0, NULL) == 0);
+       assert(futex_twait(&lock, 0, 0, NULL, 0) == 0);
        assert(pthread_join(thread, NULL) == 0);
 
+       /* Create a uvm object for sharing a lock. */
+       fd = mkstemp(filename);
+       assert(fd != -1);
+       unlink(filename);
+       assert(ftruncate(fd, 65536) == 0);
+       shlock = mmap(NULL, sizeof(*shlock), PROT_READ | PROT_WRITE,
+           MAP_SHARED, fd, 0);
+       assert(shlock != MAP_FAILED);
+       close(fd);
+
+       /* Wake another process. */
+       pid = fork();
+       assert(pid != -1);
+       if (pid == 0) {
+               usleep(50000);
+               futex_wake(shlock, -1, 0);
+               _exit(0);
+       } else {
+               assert(futex_twait(shlock, 0, 0, NULL, 0) == 0);
+               assert(waitpid(pid, &status, 0) == pid);
+               assert(WIFEXITED(status));
+               assert(WEXITSTATUS(status) == 0);
+       }
+
+       /* Cannot wake another process using a private futex. */
+       for (i = 1; i < 4; i++) {
+               pid = fork();
+               assert(pid != -1);
+               if (pid == 0) {
+                       usleep(50000);
+                       futex_wake(shlock, -1,
+                           (i & 1) ? FUTEX_PRIVATE_FLAG : 0);
+                       _exit(0);
+               } else {
+                       tmo.tv_sec = 0;
+                       tmo.tv_nsec = 200000000;
+                       assert(futex_twait(shlock, 0, CLOCK_REALTIME, &tmo,
+                           (i & 2) ? FUTEX_PRIVATE_FLAG : 0) == ETIMEDOUT);
+                       assert(waitpid(pid, &status, 0) == pid);
+                       assert(WIFEXITED(status));
+                       assert(WEXITSTATUS(status) == 0);
+               }
+       }
+
+       assert(munmap(shlock, sizeof(*shlock)) == 0);
+
        return 0;
 }
 
@@ -78,12 +131,14 @@ void *
 signaled(void *arg)
 {
        /* Wait until receiving a signal. */
-       assert(futex_twait(&lock, 0, 0, NULL) == EINTR);
+       assert(futex_twait(&lock, 0, 0, NULL, 0) == EINTR);
+       return NULL;
 }
 
 void *
 awakener(void *arg)
 {
        usleep(100);
-       assert(futex_wake(&lock, -1) == 1);
+       assert(futex_wake(&lock, -1, 0) == 1);
+       return NULL;
 }
index c2b382f..828985c 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: futex.h,v 1.1 2017/04/30 09:03:58 mpi Exp $ */
+/*     $OpenBSD: futex.h,v 1.2 2018/08/26 06:50:30 visa Exp $ */
 /*
  * Copyright (c) 2017 Martin Pieuchot
  *
  */
 
 static inline int
-futex_wake(volatile uint32_t *p, int n)
+futex_wake(volatile uint32_t *p, int n, int priv)
 {
-       return futex(p, FUTEX_WAKE, n, NULL, NULL);
+       return futex(p, FUTEX_WAKE | priv, n, NULL, NULL);
 }
 
 static inline void
-futex_wait(volatile uint32_t *p, int val)
+futex_wait(volatile uint32_t *p, int val, int priv)
 {
        while (*p != (uint32_t)val)
-               futex(p, FUTEX_WAIT, val, NULL, NULL);
+               futex(p, FUTEX_WAIT | priv, val, NULL, NULL);
 }
 
 static inline int
 futex_twait(volatile uint32_t *p, int val, clockid_t clockid,
-    const struct timespec *abs)
+    const struct timespec *timeout, int priv)
 {
-       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);
+       return futex(p, FUTEX_WAIT | priv, val, timeout, NULL);
 }
 
 static inline int