From 116b6a5ef01f5b8841eb46b536173785ac7e4670 Mon Sep 17 00:00:00 2001 From: visa Date: Sun, 26 Aug 2018 06:50:30 +0000 Subject: [PATCH] Add test cases for private versus non-private futexes. 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 | 71 ++++++++++++++++++++++++++++++---- regress/sys/kern/futex/futex.h | 30 ++++---------- 2 files changed, 70 insertions(+), 31 deletions(-) diff --git a/regress/sys/kern/futex/futex.c b/regress/sys/kern/futex/futex.c index f60f9362067..61816f2e888 100644 --- a/regress/sys/kern/futex/futex.c +++ b/regress/sys/kern/futex/futex.c @@ -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 * @@ -17,17 +17,21 @@ #include #include +#include +#include #include #include #include #include +#include #include #include #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; } diff --git a/regress/sys/kern/futex/futex.h b/regress/sys/kern/futex/futex.h index c2b382f04f0..828985c72cc 100644 --- a/regress/sys/kern/futex/futex.h +++ b/regress/sys/kern/futex/futex.h @@ -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 * @@ -16,39 +16,23 @@ */ 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 -- 2.20.1