Here is a working futex implementation for OpenBSD. This diff touches
the kernel and librthread.

* get rid of tickets from rthreads, they were getting in the way and are
    unused anyway
* replace all struct _spinlock with int
* use futexes instead of spinlocks everywhere within librthread
* librthread no longer calls sched_yield(), nor does it spin

Any comments?

Index: lib/librthread/Makefile
===================================================================
RCS file: /cvs/src/lib/librthread/Makefile,v
retrieving revision 1.43
diff -u -p -r1.43 Makefile
--- lib/librthread/Makefile     1 Jun 2016 04:34:18 -0000       1.43
+++ lib/librthread/Makefile     2 Sep 2016 13:09:44 -0000
@@ -18,7 +18,8 @@ CFLAGS+=-DNO_PIC
 VERSION_SCRIPT= ${.CURDIR}/Symbols.map
 
 .PATH: ${.CURDIR}/arch/${MACHINE_CPU}
-SRCS=  rthread.c \
+SRCS=  futex.c \
+       rthread.c \
        rthread_attr.c \
        rthread_barrier.c \
        rthread_barrier_attr.c \
Index: lib/librthread/futex.c
===================================================================
RCS file: lib/librthread/futex.c
diff -N lib/librthread/futex.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ lib/librthread/futex.c      2 Sep 2016 13:09:44 -0000
@@ -0,0 +1,41 @@
+#include <sys/futex.h>
+
+#include <pthread.h>
+#include "thread_private.h"
+#include "rthread.h"
+
+inline int
+futex_lock(volatile int *val)
+{
+       int c;
+
+       if ((c = __sync_val_compare_and_swap(val, 0, 1)) != 0) {
+               do {
+                       if (c == 2 || __sync_val_compare_and_swap(val, 1, 2) != 
0) {
+                               futex(val, FUTEX_WAIT, 2, NULL, NULL, 0);
+                       }
+               } while ((c = __sync_val_compare_and_swap(val, 0, 2)) != 0);
+       }
+
+       return 0;
+}
+
+inline int
+futex_trylock(volatile int *val)
+{
+       if ((__sync_val_compare_and_swap(val, 0, 1)) != 0)
+               return 1;
+
+       return 0;
+}
+
+inline int
+futex_unlock(volatile int *val)
+{
+       if (__sync_sub_and_fetch(val, 1) != 0) {
+               *val = 0;
+               futex(val, FUTEX_WAKE, 1, NULL, NULL, 0);
+       }
+
+       return 0;
+}
Index: lib/librthread/rthread.c
===================================================================
RCS file: /cvs/src/lib/librthread/rthread.c,v
retrieving revision 1.92
diff -u -p -r1.92 rthread.c
--- lib/librthread/rthread.c    1 Sep 2016 10:41:02 -0000       1.92
+++ lib/librthread/rthread.c    2 Sep 2016 13:09:44 -0000
@@ -63,15 +63,15 @@ REDIRECT_SYSCALL(thrkill);
 
 static int concurrency_level;  /* not used */
 
-struct _spinlock _SPINLOCK_UNLOCKED_ASSIGN = _SPINLOCK_UNLOCKED;
+int _SPINLOCK_UNLOCKED_ASSIGN = _SPINLOCK_UNLOCKED;
 
 int _threads_ready;
 size_t _thread_pagesize;
 struct listhead _thread_list = LIST_HEAD_INITIALIZER(_thread_list);
-struct _spinlock _thread_lock = _SPINLOCK_UNLOCKED;
+int _thread_lock = 0;
 static struct pthread_queue _thread_gc_list
     = TAILQ_HEAD_INITIALIZER(_thread_gc_list);
-static struct _spinlock _thread_gc_lock = _SPINLOCK_UNLOCKED;
+int _thread_gc_lock = 0;
 static struct pthread _initial_thread;
 
 struct pthread_attr _rthread_attr_default = {
@@ -88,23 +88,22 @@ struct pthread_attr _rthread_attr_defaul
 /*
  * internal support functions
  */
-void
-_spinlock(volatile struct _spinlock *lock)
+inline void
+_spinlock(volatile int *lock)
 {
-       while (_atomic_lock(&lock->ticket))
-               sched_yield();
+       futex_lock(lock);
 }
 
-int
-_spinlocktry(volatile struct _spinlock *lock)
+inline int
+_spinlocktry(volatile int *lock)
 {
-       return 0 == _atomic_lock(&lock->ticket);
+       return 0 == futex_trylock(lock);
 }
 
-void
-_spinunlock(volatile struct _spinlock *lock)
+inline void
+_spinunlock(volatile int *lock)
 {
-       lock->ticket = _ATOMIC_LOCK_UNLOCKED;
+       futex_unlock(lock);
 }
 
 static void
@@ -643,7 +642,7 @@ _thread_dump_info(void)
 void
 _rthread_dl_lock(int what)
 {
-       static struct _spinlock lock = _SPINLOCK_UNLOCKED;
+       static int lock = _SPINLOCK_UNLOCKED;
        static pthread_t owner = NULL;
        static struct pthread_queue lockers = TAILQ_HEAD_INITIALIZER(lockers);
        static int count = 0;
@@ -658,8 +657,7 @@ _rthread_dl_lock(int what)
                } else if (owner != self) {
                        TAILQ_INSERT_TAIL(&lockers, self, waiting);
                        while (owner != self) {
-                               __thrsleep(self, 0 | _USING_TICKETS, NULL,
-                                   &lock.ticket, NULL);
+                               __thrsleep(self, 0, NULL, &lock, NULL);
                                _spinlock(&lock);
                        }
                }
Index: lib/librthread/rthread.h
===================================================================
RCS file: /cvs/src/lib/librthread/rthread.h,v
retrieving revision 1.58
diff -u -p -r1.58 rthread.h
--- lib/librthread/rthread.h    7 May 2016 19:05:22 -0000       1.58
+++ lib/librthread/rthread.h    2 Sep 2016 13:09:44 -0000
@@ -37,18 +37,8 @@
 #define RTHREAD_STACK_SIZE_DEF (256 * 1024)
 #endif
 
-#define _USING_TICKETS 0
-/*
- * tickets don't work yet? (or seem much slower, with lots of system time)
- * until then, keep the struct around to avoid excessive changes going
- * back and forth.
- */
-struct _spinlock {
-       _atomic_lock_t ticket;
-};
-
-#define        _SPINLOCK_UNLOCKED { _ATOMIC_LOCK_UNLOCKED }
-extern struct _spinlock _SPINLOCK_UNLOCKED_ASSIGN;
+#define        _SPINLOCK_UNLOCKED _ATOMIC_LOCK_UNLOCKED
+extern int _SPINLOCK_UNLOCKED_ASSIGN;
 
 struct stack {
        SLIST_ENTRY(stack)      link;   /* link for free default stacks */
@@ -60,7 +50,7 @@ struct stack {
 };
 
 struct __sem {
-       struct _spinlock lock;
+       int lock;
        volatile int waitcount;
        volatile int value;
        int shared;
@@ -69,7 +59,7 @@ struct __sem {
 TAILQ_HEAD(pthread_queue, pthread);
 
 struct pthread_mutex {
-       struct _spinlock lock;
+       int lock;
        struct pthread_queue lockers;
        int type;
        pthread_t owner;
@@ -84,7 +74,7 @@ struct pthread_mutex_attr {
 };
 
 struct pthread_cond {
-       struct _spinlock lock;
+       int lock;
        struct pthread_queue waiters;
        struct pthread_mutex *mutex;
        clockid_t clock;
@@ -95,7 +85,7 @@ struct pthread_cond_attr {
 };
 
 struct pthread_rwlock {
-       struct _spinlock lock;
+       int lock;
        pthread_t owner;
        struct pthread_queue writers;
        int readers;
@@ -150,7 +140,7 @@ struct pthread_barrierattr {
 };
 
 struct pthread_spinlock {
-       struct _spinlock lock;
+       int lock;
        pthread_t owner;
 };
 
@@ -158,7 +148,7 @@ struct tib;
 struct pthread {
        struct __sem donesem;
        unsigned int flags;
-       struct _spinlock flags_lock;
+       int flags_lock;
        struct tib *tib;
        void *retval;
        void *(*fn)(void *);
@@ -192,9 +182,9 @@ struct pthread {
        (((size) + (_thread_pagesize - 1)) & ~(_thread_pagesize - 1))
 
 __BEGIN_HIDDEN_DECLS
-void   _spinlock(volatile struct _spinlock *);
-int    _spinlocktry(volatile struct _spinlock *);
-void   _spinunlock(volatile struct _spinlock *);
+void   _spinlock(volatile int *);
+int    _spinlocktry(volatile int *);
+void   _spinunlock(volatile int *);
 int    _sem_wait(sem_t, int, const struct timespec *, int *);
 int    _sem_post(sem_t);
 
@@ -213,7 +203,7 @@ void        _thread_malloc_reinit(void);
 extern int _threads_ready;
 extern size_t _thread_pagesize;
 extern LIST_HEAD(listhead, pthread) _thread_list;
-extern struct _spinlock _thread_lock;
+extern int _thread_lock;
 extern struct pthread_attr _rthread_attr_default;
 __END_HIDDEN_DECLS
 
@@ -226,3 +216,8 @@ int __thrsleep(const volatile void *, cl
            volatile void *, const int *);
 int    __thrwakeup(const volatile void *, int n);
 int    __thrsigdivert(sigset_t, siginfo_t *, const struct timespec *);
+
+/* futex.c */
+int    futex_lock(volatile int *);
+int    futex_trylock(volatile int *);
+int    futex_unlock(volatile int *);
Index: lib/librthread/rthread_file.c
===================================================================
RCS file: /cvs/src/lib/librthread/rthread_file.c,v
retrieving revision 1.8
diff -u -p -r1.8 rthread_file.c
--- lib/librthread/rthread_file.c       7 May 2016 19:05:22 -0000       1.8
+++ lib/librthread/rthread_file.c       2 Sep 2016 13:09:44 -0000
@@ -87,7 +87,7 @@ static struct static_file_lock {
 } flh[NUM_HEADS];
 
 /* Lock for accesses to the hash table: */
-static struct _spinlock        hash_lock       = _SPINLOCK_UNLOCKED;
+static int     hash_lock       = _SPINLOCK_UNLOCKED;
 
 /*
  * Find a lock structure for a FILE, return NULL if the file is
@@ -205,8 +205,7 @@ _thread_flockfile(FILE * fp)
                 */
                TAILQ_INSERT_TAIL(&p->lockers,self,waiting);
                while (p->owner != self) {
-                       __thrsleep(self, 0 | _USING_TICKETS, NULL,
-                           &hash_lock.ticket, NULL);
+                       __thrsleep(self, 0, NULL, &hash_lock, NULL);
                        _spinlock(&hash_lock);
                }
        }
Index: lib/librthread/rthread_libc.c
===================================================================
RCS file: /cvs/src/lib/librthread/rthread_libc.c,v
retrieving revision 1.16
diff -u -p -r1.16 rthread_libc.c
--- lib/librthread/rthread_libc.c       1 Sep 2016 10:56:46 -0000       1.16
+++ lib/librthread/rthread_libc.c       2 Sep 2016 13:09:44 -0000
@@ -201,7 +201,7 @@ _thread_malloc_reinit(void)
 /*
  * atexit lock
  */
-static struct _spinlock atexit_lock = _SPINLOCK_UNLOCKED;
+int atexit_lock = 0;
 
 void
 _thread_atexit_lock(void)
@@ -218,7 +218,7 @@ _thread_atexit_unlock(void)
 /*
  * atfork lock
  */
-static struct _spinlock atfork_lock = _SPINLOCK_UNLOCKED;
+int atfork_lock = 0;
 
 void
 _thread_atfork_lock(void)
@@ -235,7 +235,7 @@ _thread_atfork_unlock(void)
 /*
  * arc4random lock
  */
-static struct _spinlock arc4_lock = _SPINLOCK_UNLOCKED;
+int arc4_lock = 0;
 
 void
 _thread_arc4_lock(void)
Index: lib/librthread/rthread_rwlock.c
===================================================================
RCS file: /cvs/src/lib/librthread/rthread_rwlock.c,v
retrieving revision 1.6
diff -u -p -r1.6 rthread_rwlock.c
--- lib/librthread/rthread_rwlock.c     2 Apr 2016 19:56:53 -0000       1.6
+++ lib/librthread/rthread_rwlock.c     2 Sep 2016 13:09:45 -0000
@@ -31,7 +31,7 @@
 #include "rthread.h"
 
 
-static struct _spinlock rwlock_init_lock = _SPINLOCK_UNLOCKED;
+int rwlock_init_lock = 0;
 
 int
 pthread_rwlock_init(pthread_rwlock_t *lockp,
@@ -117,8 +117,8 @@ _rthread_rwlock_rdlock(pthread_rwlock_t 
                error = EDEADLK;
        else {
                do {
-                       if (__thrsleep(lock, CLOCK_REALTIME | _USING_TICKETS,
-                           abstime, &lock->lock.ticket, NULL) == EWOULDBLOCK)
+                       if (__thrsleep(lock, CLOCK_REALTIME,
+                           abstime, &lock->lock, NULL) == EWOULDBLOCK)
                                return (ETIMEDOUT);
                        _spinlock(&lock->lock);
                } while (lock->owner != NULL || !TAILQ_EMPTY(&lock->writers));
@@ -180,9 +180,8 @@ _rthread_rwlock_wrlock(pthread_rwlock_t 
                /* gotta block */
                TAILQ_INSERT_TAIL(&lock->writers, thread, waiting);
                do {
-                       do_wait = __thrsleep(thread, CLOCK_REALTIME |
-                           _USING_TICKETS, abstime,
-                           &lock->lock.ticket, NULL) != EWOULDBLOCK;
+                       do_wait = __thrsleep(thread, CLOCK_REALTIME, abstime,
+                           &lock->lock, NULL) != EWOULDBLOCK;
                        _spinlock(&lock->lock);
                } while (lock->owner != thread && do_wait);
 
Index: lib/librthread/rthread_sem.c
===================================================================
RCS file: /cvs/src/lib/librthread/rthread_sem.c,v
retrieving revision 1.23
diff -u -p -r1.23 rthread_sem.c
--- lib/librthread/rthread_sem.c        7 May 2016 19:05:22 -0000       1.23
+++ lib/librthread/rthread_sem.c        2 Sep 2016 13:09:45 -0000
@@ -71,9 +71,8 @@ _sem_wait(sem_t sem, int tryonly, const 
        } else {
                sem->waitcount++;
                do {
-                       r = __thrsleep(ident, CLOCK_REALTIME |
-                           _USING_TICKETS, abstime, &sem->lock.ticket,
-                           delayed_cancel);
+                       r = __thrsleep(ident, CLOCK_REALTIME, abstime,
+                           &sem->lock, delayed_cancel);
                        _spinlock(&sem->lock);
                        /* ignore interruptions other than cancelation */
                        if (r == EINTR && (delayed_cancel == NULL ||
Index: lib/librthread/rthread_stack.c
===================================================================
RCS file: /cvs/src/lib/librthread/rthread_stack.c,v
retrieving revision 1.15
diff -u -p -r1.15 rthread_stack.c
--- lib/librthread/rthread_stack.c      1 Sep 2016 10:56:46 -0000       1.15
+++ lib/librthread/rthread_stack.c      2 Sep 2016 13:09:45 -0000
@@ -18,7 +18,7 @@
  * attributes for possible reuse.
  */
 static SLIST_HEAD(, stack) def_stacks = SLIST_HEAD_INITIALIZER(head);
-static struct _spinlock def_stacks_lock = _SPINLOCK_UNLOCKED;
+int def_stacks_lock = 0;
 
 struct stack *
 _rthread_alloc_stack(pthread_t thread)
Index: lib/librthread/rthread_sync.c
===================================================================
RCS file: /cvs/src/lib/librthread/rthread_sync.c,v
retrieving revision 1.42
diff -u -p -r1.42 rthread_sync.c
--- lib/librthread/rthread_sync.c       7 May 2016 19:05:22 -0000       1.42
+++ lib/librthread/rthread_sync.c       2 Sep 2016 13:09:45 -0000
@@ -32,7 +32,7 @@
 #include "rthread.h"
 #include "cancel.h"            /* in libc/include */
 
-static struct _spinlock static_init_lock = _SPINLOCK_UNLOCKED;
+int static_init_lock = 0;
 
 /*
  * mutexen
@@ -130,9 +130,8 @@ _rthread_mutex_lock(pthread_mutex_t *mut
                                abort();
 
                        /* self-deadlock, possibly until timeout */
-                       while (__thrsleep(self, CLOCK_REALTIME |
-                           _USING_TICKETS, abstime,
-                           &mutex->lock.ticket, NULL) != EWOULDBLOCK)
+                       while (__thrsleep(self, CLOCK_REALTIME, abstime,
+                           &mutex->lock, NULL) != EWOULDBLOCK)
                                _spinlock(&mutex->lock);
                        return (ETIMEDOUT);
                }
@@ -148,8 +147,8 @@ _rthread_mutex_lock(pthread_mutex_t *mut
                /* add to the wait queue and block until at the head */
                TAILQ_INSERT_TAIL(&mutex->lockers, self, waiting);
                while (mutex->owner != self) {
-                       ret = __thrsleep(self, CLOCK_REALTIME | _USING_TICKETS,
-                           abstime, &mutex->lock.ticket, NULL);
+                       ret = __thrsleep(self, CLOCK_REALTIME, abstime,
+                           &mutex->lock, NULL);
                        _spinlock(&mutex->lock);
                        assert(mutex->owner != NULL);
                        if (ret == EWOULDBLOCK) {
@@ -360,8 +359,8 @@ pthread_cond_timedwait(pthread_cond_t *c
 
        /* wait until we're the owner of the mutex again */
        while (mutex->owner != self) {
-               error = __thrsleep(self, cond->clock | _USING_TICKETS, abstime,
-                   &mutex->lock.ticket, &self->delayed_cancel);
+               error = __thrsleep(self, cond->clock, abstime,
+                   &mutex->lock, &self->delayed_cancel);
 
                /*
                 * If abstime == NULL, then we're definitely waiting
@@ -510,8 +509,8 @@ pthread_cond_wait(pthread_cond_t *condp,
 
        /* wait until we're the owner of the mutex again */
        while (mutex->owner != self) {
-               error = __thrsleep(self, 0 | _USING_TICKETS, NULL,
-                   &mutex->lock.ticket, &self->delayed_cancel);
+               error = __thrsleep(self, 0, NULL, &mutex->lock,
+                   &self->delayed_cancel);
 
                /*
                 * If we took a normal signal (not from
Index: lib/librthread/rthread_tls.c
===================================================================
RCS file: /cvs/src/lib/librthread/rthread_tls.c,v
retrieving revision 1.17
diff -u -p -r1.17 rthread_tls.c
--- lib/librthread/rthread_tls.c        2 Apr 2016 19:56:53 -0000       1.17
+++ lib/librthread/rthread_tls.c        2 Sep 2016 13:09:45 -0000
@@ -27,7 +27,7 @@
 #include "rthread.h"
 
 static struct rthread_key rkeys[PTHREAD_KEYS_MAX];
-static struct _spinlock rkeyslock = _SPINLOCK_UNLOCKED;
+int rkeyslock = 0;
 
 int
 pthread_key_create(pthread_key_t *key, void (*destructor)(void*))
Index: sys/conf/files
===================================================================
RCS file: /cvs/src/sys/conf/files,v
retrieving revision 1.625
diff -u -p -r1.625 files
--- sys/conf/files      1 Sep 2016 10:06:33 -0000       1.625
+++ sys/conf/files      2 Sep 2016 13:09:47 -0000
@@ -660,6 +660,7 @@ file kern/kern_event.c
 file kern/kern_exec.c
 file kern/kern_exit.c
 file kern/kern_fork.c
+file kern/kern_futex.c
 file kern/kern_kthread.c
 file kern/kern_ktrace.c                        ktrace
 file kern/kern_lock.c
Index: sys/kern/init_sysent.c
===================================================================
RCS file: /cvs/src/sys/kern/init_sysent.c,v
retrieving revision 1.184
diff -u -p -r1.184 init_sysent.c
--- sys/kern/init_sysent.c      27 Jun 2016 16:52:01 -0000      1.184
+++ sys/kern/init_sysent.c      2 Sep 2016 13:09:48 -0000
@@ -751,5 +751,7 @@ struct sysent sysent[] = {
            sys___set_tcb },                    /* 329 = __set_tcb */
        { 0, 0, SY_NOLOCK | 0,
            sys___get_tcb },                    /* 330 = __get_tcb */
+       { 6, s(struct sys_futex_args), 0,
+           sys_futex },                        /* 331 = futex */
 };
 
Index: sys/kern/kern_futex.c
===================================================================
RCS file: sys/kern/kern_futex.c
diff -N sys/kern/kern_futex.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ sys/kern/kern_futex.c       2 Sep 2016 13:09:49 -0000
@@ -0,0 +1,143 @@
+/*     $OpenBSD$       */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+
+#include <sys/signal.h>
+#include <sys/mount.h>
+#include <sys/socket.h>
+#include <sys/syscallargs.h>
+#include <sys/proc.h>
+#include <sys/futex.h>
+#include <sys/param.h>
+#include <sys/ktrace.h>
+#include <sys/kernel.h>
+
+int
+futex_wait(struct proc *p, struct sys_futex_args *v)
+{
+       struct sys_futex_args /* {
+               syscallarg(void *) uaddr;
+               syscallarg(int) futex_op;
+               syscallarg(int) val;
+               syscallarg(const struct timespec *) tp;
+               syscallarg(int *) uaddr2;
+               syscallarg(int) val3;
+       } */ *uap = v;
+       void *uaddr = SCARG(uap, uaddr);
+       int val = SCARG(uap, val);
+       int futex_op = SCARG(uap, futex_op);
+       uint64_t to_ticks = 0;
+       int uval;
+       int error;
+       int abort;
+
+       if ((error = copyin(uaddr, &uval, sizeof uval)))
+               return error;
+       if (val != uval)
+               return EWOULDBLOCK;
+       if (SCARG(uap, tp) != NULL) {
+               struct timespec now;
+               struct timespec tsp;
+               int clock_id;
+
+               if ((error = copyin(SCARG(uap, tp), &tsp, sizeof(tsp))))
+                       return error;
+
+               clock_id = futex_op & FUTEX_CLOCK_REALTIME ?
+                       CLOCK_REALTIME : CLOCK_MONOTONIC;
+
+               clock_id = CLOCK_MONOTONIC;
+
+               if ((error = clock_gettime(p, clock_id, &now)))
+                       return error;
+
+#ifdef KTRACE
+               if (KTRPOINT(p, KTR_STRUCT))
+                       ktrabstimespec(p, &tsp);
+#endif
+               
+               if (timespeccmp(&tsp, &now, <))
+                       return EWOULDBLOCK;
+
+               timespecsub(&tsp, &now, &tsp);
+               to_ticks = (uint64_t)hz * tsp.tv_sec +
+                   (tsp.tv_nsec + tick * 1000 - 1) / (tick * 1000) + 1;
+               if (to_ticks > INT_MAX)
+                       to_ticks = INT_MAX;
+       }
+
+       /* XXX emulate 'abort' from thrsleep */
+       if (SCARG(uap, uaddr2) != NULL) {
+               if ((error = copyin(SCARG(uap, uaddr2), &abort,
+                   sizeof(abort))) != 0)
+                       return error;
+               if (abort)
+                       return EINTR;
+       }
+
+       p->p_futslpid = (long)uaddr;
+       error = tsleep(&p->p_futslpid, PUSER | PCATCH, "futex", (int)to_ticks);
+
+       if (error == ERESTART)
+               error = EINTR;
+
+       return error;
+}
+
+int
+futex_wake(struct proc *p, struct sys_futex_args *v)
+{
+       struct sys_futex_args /* {
+               syscallarg(void *) uaddr;
+               syscallarg(int) futex_op;
+               syscallarg(int) val;
+               syscallarg(const struct timespec *) tp;
+               syscallarg(int *) uaddr2;
+               syscallarg(int) val3;
+       } */ *uap = v;
+       void *uaddr = SCARG(uap, uaddr);
+       int n = SCARG(uap, val);
+       int found = 0;
+       struct proc *q;
+
+       TAILQ_FOREACH(q, &p->p_p->ps_threads, p_thr_link) {
+               if (q->p_futslpid == (long)uaddr) {
+                       wakeup_one(&q->p_futslpid);
+                       q->p_futslpid = 0;
+                       if (++found == n)
+                               break;
+               }
+       }
+
+       return found ? 0 : ESRCH;
+}
+
+int
+sys_futex(struct proc *p, void *v, register_t *retval)
+{
+       struct sys_futex_args /* {
+               syscallarg(void *) uaddr;
+               syscallarg(int) futex_op;
+               syscallarg(int) val;
+               syscallarg(const struct timespec *) tp;
+               syscallarg(int *) uaddr2;
+               syscallarg(int) val3;
+       } */ *uap = v;
+       int op = SCARG(uap, futex_op);
+
+       *retval = 0;
+       
+       switch (op) {
+       case FUTEX_WAIT:
+               *retval = futex_wait(p, uap);
+               break;
+       case FUTEX_WAKE:
+               *retval = futex_wake(p, uap);
+               break;
+       default:
+               *retval = EINVAL;
+               break;
+       }
+       return 0;
+}
Index: sys/kern/kern_pledge.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_pledge.c,v
retrieving revision 1.181
diff -u -p -r1.181 kern_pledge.c
--- sys/kern/kern_pledge.c      31 Aug 2016 07:22:43 -0000      1.181
+++ sys/kern/kern_pledge.c      2 Sep 2016 13:09:50 -0000
@@ -260,6 +260,7 @@ const uint64_t pledge_syscalls[SYS_MAXSY
        [SYS___tfork] = PLEDGE_STDIO,
        [SYS_sched_yield] = PLEDGE_STDIO,
        [SYS___thrsleep] = PLEDGE_STDIO,
+       [SYS_futex] = PLEDGE_ALWAYS,
        [SYS___thrwakeup] = PLEDGE_STDIO,
        [SYS___threxit] = PLEDGE_STDIO,
        [SYS___thrsigdivert] = PLEDGE_STDIO,
Index: sys/kern/kern_synch.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_synch.c,v
retrieving revision 1.133
diff -u -p -r1.133 kern_synch.c
--- sys/kern/kern_synch.c       6 Jul 2016 15:53:01 -0000       1.133
+++ sys/kern/kern_synch.c       2 Sep 2016 13:09:51 -0000
@@ -59,7 +59,7 @@
 #endif
 
 int    thrsleep(struct proc *, struct sys___thrsleep_args *);
-int    thrsleep_unlock(void *, int);
+int    thrsleep_unlock(struct proc *, void *, int);
 
 /*
  * We're only looking at 7 bits of the address; everything is
@@ -454,25 +454,27 @@ sys_sched_yield(struct proc *p, void *v,
 }
 
 int
-thrsleep_unlock(void *lock, int lockflags)
+thrsleep_unlock(struct proc *p, void *lock, int lockflags)
 {
        static _atomic_lock_t unlocked = _ATOMIC_LOCK_UNLOCKED;
        _atomic_lock_t *atomiclock = lock;
-       uint32_t *ticket = lock;
-       uint32_t ticketvalue;
        int error;
 
        if (!lock)
                return (0);
 
-       if (lockflags) {
-               if ((error = copyin(ticket, &ticketvalue, sizeof(ticketvalue))))
-                       return (error);
-               ticketvalue++;
-               error = copyout(&ticketvalue, ticket, sizeof(ticketvalue));
-       } else {
-               error = copyout(&unlocked, atomiclock, sizeof(unlocked));
+       error = copyout(&unlocked, atomiclock, sizeof(unlocked));
+
+       struct proc *q;
+
+       TAILQ_FOREACH(q, &p->p_p->ps_threads, p_thr_link) {
+               if (q->p_futslpid == (long)lock) {
+                       wakeup_one(&q->p_futslpid);
+                       q->p_futslpid = 0;
+                       break;
+               }
        }
+
        return (error);
 }
 
@@ -510,7 +512,7 @@ thrsleep(struct proc *p, struct sys___th
 
                if (timespeccmp(tsp, &now, <)) {
                        /* already passed: still do the unlock */
-                       if ((error = thrsleep_unlock(lock, lockflags)))
+                       if ((error = thrsleep_unlock(p, lock, lockflags)))
                                return (error);
                        return (EWOULDBLOCK);
                }
@@ -524,7 +526,7 @@ thrsleep(struct proc *p, struct sys___th
 
        p->p_thrslpid = ident;
 
-       if ((error = thrsleep_unlock(lock, lockflags))) {
+       if ((error = thrsleep_unlock(p, lock, lockflags))) {
                goto out;
        }
 
Index: sys/kern/syscalls.c
===================================================================
RCS file: /cvs/src/sys/kern/syscalls.c,v
retrieving revision 1.183
diff -u -p -r1.183 syscalls.c
--- sys/kern/syscalls.c 27 Jun 2016 16:52:01 -0000      1.183
+++ sys/kern/syscalls.c 2 Sep 2016 13:09:54 -0000
@@ -393,4 +393,5 @@ char *syscallnames[] = {
        "#328 (obsolete __tfork51)",            /* 328 = obsolete __tfork51 */
        "__set_tcb",                    /* 329 = __set_tcb */
        "__get_tcb",                    /* 330 = __get_tcb */
+       "futex",                        /* 331 = futex */
 };
Index: sys/kern/syscalls.master
===================================================================
RCS file: /cvs/src/sys/kern/syscalls.master,v
retrieving revision 1.173
diff -u -p -r1.173 syscalls.master
--- sys/kern/syscalls.master    27 Jun 2016 16:50:07 -0000      1.173
+++ sys/kern/syscalls.master    2 Sep 2016 13:09:54 -0000
@@ -563,3 +563,6 @@
 328    OBSOL           __tfork51
 329    STD NOLOCK      { void sys___set_tcb(void *tcb); }
 330    STD NOLOCK      { void *sys___get_tcb(void); }
+331    STD             { void sys_futex(void *uaddr, int futex_op, int val, \
+                          const struct timespec *tp, int *uaddr2, \
+                          int val3); }
Index: sys/sys/futex.h
===================================================================
RCS file: sys/sys/futex.h
diff -N sys/sys/futex.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ sys/sys/futex.h     2 Sep 2016 13:09:59 -0000
@@ -0,0 +1,17 @@
+/*     $OpenBSD$       */
+
+#ifndef _SYS_FUTEX_H_
+#define _SYS_FUTEX_H_
+
+#include <sys/types.h>
+
+#define        FUTEX_WAIT              0
+#define        FUTEX_WAKE              1
+
+#define        FUTEX_CLOCK_REALTIME    256
+
+__BEGIN_DECLS
+int    futex(volatile void *, int, int, const struct timespec *, int *, int);
+__END_DECLS
+
+#endif /* !_SYS_FUTEX_H_ */
Index: sys/sys/proc.h
===================================================================
RCS file: /cvs/src/sys/sys/proc.h,v
retrieving revision 1.224
diff -u -p -r1.224 proc.h
--- sys/sys/proc.h      27 Jun 2016 19:55:02 -0000      1.224
+++ sys/sys/proc.h      2 Sep 2016 13:10:00 -0000
@@ -297,6 +297,7 @@ struct proc {
        int     p_dupfd;         /* Sideways return value from filedescopen. 
XXX */
 
        long    p_thrslpid;     /* for thrsleep syscall */
+       long    p_futslpid;     /* for futex syscall */
 
        /* scheduling */
        u_int   p_estcpu;        /* Time averaged value of p_cpticks. */
Index: sys/sys/syscall.h
===================================================================
RCS file: /cvs/src/sys/sys/syscall.h,v
retrieving revision 1.182
diff -u -p -r1.182 syscall.h
--- sys/sys/syscall.h   27 Jun 2016 16:52:01 -0000      1.182
+++ sys/sys/syscall.h   2 Sep 2016 13:10:01 -0000
@@ -1,4 +1,4 @@
-/*     $OpenBSD: syscall.h,v 1.182 2016/06/27 16:52:01 jsing Exp $     */
+/*     $OpenBSD$       */
 
 /*
  * System call numbers.
@@ -702,4 +702,7 @@
 /* syscall: "__get_tcb" ret: "void *" args: */
 #define        SYS___get_tcb   330
 
-#define        SYS_MAXSYSCALL  331
+/* syscall: "futex" ret: "void" args: "void *" "int" "int" "const struct 
timespec *" "int *" "int" */
+#define        SYS_futex       331
+
+#define        SYS_MAXSYSCALL  332
Index: sys/sys/syscallargs.h
===================================================================
RCS file: /cvs/src/sys/sys/syscallargs.h,v
retrieving revision 1.185
diff -u -p -r1.185 syscallargs.h
--- sys/sys/syscallargs.h       27 Jun 2016 16:52:01 -0000      1.185
+++ sys/sys/syscallargs.h       2 Sep 2016 13:10:02 -0000
@@ -1,4 +1,4 @@
-/*     $OpenBSD: syscallargs.h,v 1.185 2016/06/27 16:52:01 jsing Exp $ */
+/*     $OpenBSD$       */
 
 /*
  * System call argument lists.
@@ -1098,6 +1098,15 @@ struct sys___set_tcb_args {
        syscallarg(void *) tcb;
 };
 
+struct sys_futex_args {
+       syscallarg(void *) uaddr;
+       syscallarg(int) futex_op;
+       syscallarg(int) val;
+       syscallarg(const struct timespec *) tp;
+       syscallarg(int *) uaddr2;
+       syscallarg(int) val3;
+};
+
 /*
  * System call prototypes.
  */
@@ -1347,3 +1356,4 @@ int       sys_symlinkat(struct proc *, void *,
 int    sys_unlinkat(struct proc *, void *, register_t *);
 int    sys___set_tcb(struct proc *, void *, register_t *);
 int    sys___get_tcb(struct proc *, void *, register_t *);
+int    sys_futex(struct proc *, void *, register_t *);

-- 
Michal Mazurek

Reply via email to