Futexes for OpenBSD

classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

Futexes for OpenBSD

Michal Mazurek-2
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 | Threaded
Open this post in threaded view
|

Re: Futexes for OpenBSD

Amit Kulkarni-5
The new files should have the ISC/OpenBSD license inserted at the top.

IMHO, the ticket changes are a separate diff and you will be able to commit
that part first.

Also, replacing struct _spinlock with int is also a separate diff.

Those changes don't clash with futexes, so less chance of being reverted.

Thanks


On Fri, Sep 2, 2016 at 8:36 AM, Michal Mazurek <[hidden email]> wrote:

> 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 | Threaded
Open this post in threaded view
|

Re: Futexes for OpenBSD

Jonathan Gray-11
In reply to this post by Michal Mazurek-2
On Fri, Sep 02, 2016 at 03:36:50PM +0200, Michal Mazurek wrote:

> 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?

Atomic sync builtins are missing on arm, hppa and superh.
This diff will break those architectures.

>
> 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 | Threaded
Open this post in threaded view
|

Re: Futexes for OpenBSD

Gregor Best-2
In reply to this post by Michal Mazurek-2
On Fri, Sep 02, 2016 at 03:36:50PM +0200, Michal Mazurek wrote:

> 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?
> [...]

There's a tiny bit missing from the patch:

Index: libc/Symbols.list
===================================================================
RCS file: /mnt/media/cvs/src/lib/libc/Symbols.list,v
retrieving revision 1.49
diff -u -p -r1.49 Symbols.list
--- libc/Symbols.list   1 Sep 2016 10:41:02 -0000       1.49
+++ libc/Symbols.list   3 Sep 2016 09:54:58 -0000
@@ -272,6 +272,7 @@ fstatat
 fstatfs
 fsync
 ftruncate
+futex
 futimens
 futimes
 getdents
Index: libc/sys/Makefile.inc
===================================================================
RCS file: /mnt/media/cvs/src/lib/libc/sys/Makefile.inc,v
retrieving revision 1.146
diff -u -p -r1.146 Makefile.inc
--- libc/sys/Makefile.inc       4 Jul 2016 18:01:44 -0000       1.146
+++ libc/sys/Makefile.inc       3 Sep 2016 09:53:03 -0000
@@ -87,6 +87,7 @@ DASM= ${ASM:.o=.do}
 # syscalls that CANNOT FAIL.  They can return whatever value they want,
 # they just never want to set errno.
 ASM_NOERR=__get_tcb.o __set_tcb.o __threxit.o __thrsleep.o __thrwakeup.o \
+       futex.o \
        getdtablecount.o getegid.o geteuid.o getgid.o getlogin_r.o \
        getpgrp.o getpid.o getppid.o getrtable.o getthrid.o getuid.o \
        issetugid.o \

Otherwise, the  calls to  futex() in librthread  can't be  resolved. I'm
currently building Firefox to see how it works out.

--
        Gregor
--

Honesty is the best policy, but insanity is a better defense.

Reply | Threaded
Open this post in threaded view
|

Re: Futexes for OpenBSD

Michal Mazurek-2
In reply to this post by Michal Mazurek-2
Resending a diff that works with the current tree.

Comments?

Index: sys/conf/files
===================================================================
RCS file: /cvs/src/sys/conf/files,v
retrieving revision 1.627
diff -u -p -r1.627 files
--- sys/conf/files 4 Sep 2016 09:22:28 -0000 1.627
+++ sys/conf/files 4 Sep 2016 13:12:39 -0000
@@ -661,6 +661,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 4 Sep 2016 13:12:40 -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 4 Sep 2016 13:12:40 -0000
@@ -0,0 +1,148 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2016
+ *
+ * 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/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;
+
+ 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;
+ }
+
+ 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 4 Sep 2016 13:12:40 -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.134
diff -u -p -r1.134 kern_synch.c
--- sys/kern/kern_synch.c 3 Sep 2016 15:06:06 -0000 1.134
+++ sys/kern/kern_synch.c 4 Sep 2016 13:12:40 -0000
@@ -59,7 +59,7 @@
 #endif
 
 int thrsleep(struct proc *, struct sys___thrsleep_args *);
-int thrsleep_unlock(void *);
+int thrsleep_unlock(struct proc *, void *);
 
 /*
  * We're only looking at 7 bits of the address; everything is
@@ -454,15 +454,27 @@ sys_sched_yield(struct proc *p, void *v,
 }
 
 int
-thrsleep_unlock(void *lock)
+thrsleep_unlock(struct proc *p, void *lock)
 {
  static _atomic_lock_t unlocked = _ATOMIC_LOCK_UNLOCKED;
  _atomic_lock_t *atomiclock = lock;
+ struct proc *q;
+ int error;
 
  if (!lock)
  return 0;
 
- return copyout(&unlocked, atomiclock, sizeof(unlocked));
+ error = copyout(&unlocked, atomiclock, sizeof(unlocked));
+
+ 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;
 }
 
 static int globalsleepaddr;
@@ -498,7 +510,7 @@ thrsleep(struct proc *p, struct sys___th
 
  if (timespeccmp(tsp, &now, <)) {
  /* already passed: still do the unlock */
- if ((error = thrsleep_unlock(lock)))
+ if ((error = thrsleep_unlock(p, lock)))
  return (error);
  return (EWOULDBLOCK);
  }
@@ -512,7 +524,7 @@ thrsleep(struct proc *p, struct sys___th
 
  p->p_thrslpid = ident;
 
- if ((error = thrsleep_unlock(lock)))
+ if ((error = thrsleep_unlock(p, lock)))
  goto out;
 
  if (SCARG(uap, abort) != NULL) {
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 4 Sep 2016 13:12:40 -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 4 Sep 2016 13:12:40 -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 4 Sep 2016 13:12:40 -0000
@@ -0,0 +1,32 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2016
+ *
+ * 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.
+ */
+
+#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.226
diff -u -p -r1.226 proc.h
--- sys/sys/proc.h 3 Sep 2016 08:47:24 -0000 1.226
+++ sys/sys/proc.h 4 Sep 2016 13:12:40 -0000
@@ -302,6 +302,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 4 Sep 2016 13:12:40 -0000
@@ -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 4 Sep 2016 13:12:40 -0000
@@ -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 *);
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 4 Sep 2016 13:12:40 -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 4 Sep 2016 13:12:40 -0000
@@ -0,0 +1,58 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2016
+ *
+ * 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/futex.h>
+
+#include <pthread.h>
+#include "thread_private.h"
+#include "rthread.h"
+
+inline int
+futex_lock(volatile _atomic_lock_t *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 _atomic_lock_t *val)
+{
+ if ((__sync_val_compare_and_swap(val, 0, 1)) != 0)
+ return 1;
+
+ return 0;
+}
+
+inline int
+futex_unlock(volatile _atomic_lock_t *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.94
diff -u -p -r1.94 rthread.c
--- lib/librthread/rthread.c 4 Sep 2016 10:13:35 -0000 1.94
+++ lib/librthread/rthread.c 4 Sep 2016 13:12:40 -0000
@@ -89,20 +89,19 @@ struct pthread_attr _rthread_attr_defaul
 void
 _spinlock(volatile _atomic_lock_t *lock)
 {
- while (_atomic_lock(lock))
- sched_yield();
+ futex_lock(lock);
 }
 
 int
 _spinlocktry(volatile _atomic_lock_t *lock)
 {
- return 0 == _atomic_lock(lock);
+ return 0 == futex_trylock(lock);
 }
 
 void
 _spinunlock(volatile _atomic_lock_t *lock)
 {
- *lock = _ATOMIC_LOCK_UNLOCKED;
+ futex_unlock(lock);
 }
 
 static void
Index: lib/librthread/rthread.h
===================================================================
RCS file: /cvs/src/lib/librthread/rthread.h,v
retrieving revision 1.60
diff -u -p -r1.60 rthread.h
--- lib/librthread/rthread.h 4 Sep 2016 10:13:35 -0000 1.60
+++ lib/librthread/rthread.h 4 Sep 2016 13:12:40 -0000
@@ -215,3 +215,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 _atomic_lock_t *);
+int futex_trylock(volatile _atomic_lock_t *);
+int futex_unlock(volatile _atomic_lock_t *);
Index: lib/libc/Symbols.list
===================================================================
RCS file: /cvs/src/lib/libc/Symbols.list,v
retrieving revision 1.50
diff -u -p -r1.50 Symbols.list
--- lib/libc/Symbols.list 3 Sep 2016 16:25:03 -0000 1.50
+++ lib/libc/Symbols.list 4 Sep 2016 13:12:40 -0000
@@ -272,6 +272,7 @@ fstatat
 fstatfs
 fsync
 ftruncate
+futex
 futimens
 futimes
 getdents
Index: lib/libc/sys/Makefile.inc
===================================================================
RCS file: /cvs/src/lib/libc/sys/Makefile.inc,v
retrieving revision 1.146
diff -u -p -r1.146 Makefile.inc
--- lib/libc/sys/Makefile.inc 4 Jul 2016 18:01:44 -0000 1.146
+++ lib/libc/sys/Makefile.inc 4 Sep 2016 13:12:41 -0000
@@ -87,6 +87,7 @@ DASM= ${ASM:.o=.do}
 # syscalls that CANNOT FAIL.  They can return whatever value they want,
 # they just never want to set errno.
 ASM_NOERR=__get_tcb.o __set_tcb.o __threxit.o __thrsleep.o __thrwakeup.o \
+ futex.o \
  getdtablecount.o getegid.o geteuid.o getgid.o getlogin_r.o \
  getpgrp.o getpid.o getppid.o getrtable.o getthrid.o getuid.o \
  issetugid.o \


--
Michal Mazurek

Reply | Threaded
Open this post in threaded view
|

Re: Futexes for OpenBSD

Mark Kettenis
> Date: Sun, 4 Sep 2016 15:17:21 +0200
> From: Michal Mazurek <[hidden email]>
>
> Resending a diff that works with the current tree.
>
> Comments?

I believe it was said before, but this can't go in since it breaks
architectures that don't implement the __sync_xxx primitives.

> Index: sys/conf/files
> ===================================================================
> RCS file: /cvs/src/sys/conf/files,v
> retrieving revision 1.627
> diff -u -p -r1.627 files
> --- sys/conf/files 4 Sep 2016 09:22:28 -0000 1.627
> +++ sys/conf/files 4 Sep 2016 13:12:39 -0000
> @@ -661,6 +661,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 4 Sep 2016 13:12:40 -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 4 Sep 2016 13:12:40 -0000
> @@ -0,0 +1,148 @@
> +/* $OpenBSD$ */
> +/*
> + * Copyright (c) 2016
> + *
> + * 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/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;
> +
> + 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;
> + }
> +
> + 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 4 Sep 2016 13:12:40 -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.134
> diff -u -p -r1.134 kern_synch.c
> --- sys/kern/kern_synch.c 3 Sep 2016 15:06:06 -0000 1.134
> +++ sys/kern/kern_synch.c 4 Sep 2016 13:12:40 -0000
> @@ -59,7 +59,7 @@
>  #endif
>  
>  int thrsleep(struct proc *, struct sys___thrsleep_args *);
> -int thrsleep_unlock(void *);
> +int thrsleep_unlock(struct proc *, void *);
>  
>  /*
>   * We're only looking at 7 bits of the address; everything is
> @@ -454,15 +454,27 @@ sys_sched_yield(struct proc *p, void *v,
>  }
>  
>  int
> -thrsleep_unlock(void *lock)
> +thrsleep_unlock(struct proc *p, void *lock)
>  {
>   static _atomic_lock_t unlocked = _ATOMIC_LOCK_UNLOCKED;
>   _atomic_lock_t *atomiclock = lock;
> + struct proc *q;
> + int error;
>  
>   if (!lock)
>   return 0;
>  
> - return copyout(&unlocked, atomiclock, sizeof(unlocked));
> + error = copyout(&unlocked, atomiclock, sizeof(unlocked));
> +
> + 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;
>  }
>  
>  static int globalsleepaddr;
> @@ -498,7 +510,7 @@ thrsleep(struct proc *p, struct sys___th
>  
>   if (timespeccmp(tsp, &now, <)) {
>   /* already passed: still do the unlock */
> - if ((error = thrsleep_unlock(lock)))
> + if ((error = thrsleep_unlock(p, lock)))
>   return (error);
>   return (EWOULDBLOCK);
>   }
> @@ -512,7 +524,7 @@ thrsleep(struct proc *p, struct sys___th
>  
>   p->p_thrslpid = ident;
>  
> - if ((error = thrsleep_unlock(lock)))
> + if ((error = thrsleep_unlock(p, lock)))
>   goto out;
>  
>   if (SCARG(uap, abort) != NULL) {
> 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 4 Sep 2016 13:12:40 -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 4 Sep 2016 13:12:40 -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 4 Sep 2016 13:12:40 -0000
> @@ -0,0 +1,32 @@
> +/* $OpenBSD$ */
> +/*
> + * Copyright (c) 2016
> + *
> + * 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.
> + */
> +
> +#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.226
> diff -u -p -r1.226 proc.h
> --- sys/sys/proc.h 3 Sep 2016 08:47:24 -0000 1.226
> +++ sys/sys/proc.h 4 Sep 2016 13:12:40 -0000
> @@ -302,6 +302,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 4 Sep 2016 13:12:40 -0000
> @@ -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 4 Sep 2016 13:12:40 -0000
> @@ -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 *);
> 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 4 Sep 2016 13:12:40 -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 4 Sep 2016 13:12:40 -0000
> @@ -0,0 +1,58 @@
> +/* $OpenBSD$ */
> +/*
> + * Copyright (c) 2016
> + *
> + * 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/futex.h>
> +
> +#include <pthread.h>
> +#include "thread_private.h"
> +#include "rthread.h"
> +
> +inline int
> +futex_lock(volatile _atomic_lock_t *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 _atomic_lock_t *val)
> +{
> + if ((__sync_val_compare_and_swap(val, 0, 1)) != 0)
> + return 1;
> +
> + return 0;
> +}
> +
> +inline int
> +futex_unlock(volatile _atomic_lock_t *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.94
> diff -u -p -r1.94 rthread.c
> --- lib/librthread/rthread.c 4 Sep 2016 10:13:35 -0000 1.94
> +++ lib/librthread/rthread.c 4 Sep 2016 13:12:40 -0000
> @@ -89,20 +89,19 @@ struct pthread_attr _rthread_attr_defaul
>  void
>  _spinlock(volatile _atomic_lock_t *lock)
>  {
> - while (_atomic_lock(lock))
> - sched_yield();
> + futex_lock(lock);
>  }
>  
>  int
>  _spinlocktry(volatile _atomic_lock_t *lock)
>  {
> - return 0 == _atomic_lock(lock);
> + return 0 == futex_trylock(lock);
>  }
>  
>  void
>  _spinunlock(volatile _atomic_lock_t *lock)
>  {
> - *lock = _ATOMIC_LOCK_UNLOCKED;
> + futex_unlock(lock);
>  }
>  
>  static void
> Index: lib/librthread/rthread.h
> ===================================================================
> RCS file: /cvs/src/lib/librthread/rthread.h,v
> retrieving revision 1.60
> diff -u -p -r1.60 rthread.h
> --- lib/librthread/rthread.h 4 Sep 2016 10:13:35 -0000 1.60
> +++ lib/librthread/rthread.h 4 Sep 2016 13:12:40 -0000
> @@ -215,3 +215,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 _atomic_lock_t *);
> +int futex_trylock(volatile _atomic_lock_t *);
> +int futex_unlock(volatile _atomic_lock_t *);
> Index: lib/libc/Symbols.list
> ===================================================================
> RCS file: /cvs/src/lib/libc/Symbols.list,v
> retrieving revision 1.50
> diff -u -p -r1.50 Symbols.list
> --- lib/libc/Symbols.list 3 Sep 2016 16:25:03 -0000 1.50
> +++ lib/libc/Symbols.list 4 Sep 2016 13:12:40 -0000
> @@ -272,6 +272,7 @@ fstatat
>  fstatfs
>  fsync
>  ftruncate
> +futex
>  futimens
>  futimes
>  getdents
> Index: lib/libc/sys/Makefile.inc
> ===================================================================
> RCS file: /cvs/src/lib/libc/sys/Makefile.inc,v
> retrieving revision 1.146
> diff -u -p -r1.146 Makefile.inc
> --- lib/libc/sys/Makefile.inc 4 Jul 2016 18:01:44 -0000 1.146
> +++ lib/libc/sys/Makefile.inc 4 Sep 2016 13:12:41 -0000
> @@ -87,6 +87,7 @@ DASM= ${ASM:.o=.do}
>  # syscalls that CANNOT FAIL.  They can return whatever value they want,
>  # they just never want to set errno.
>  ASM_NOERR=__get_tcb.o __set_tcb.o __threxit.o __thrsleep.o __thrwakeup.o \
> + futex.o \
>   getdtablecount.o getegid.o geteuid.o getgid.o getlogin_r.o \
>   getpgrp.o getpid.o getppid.o getrtable.o getthrid.o getuid.o \
>   issetugid.o \
>
>
> --
> Michal Mazurek
>
>