summaryrefslogtreecommitdiffstats
path: root/main/musl
diff options
context:
space:
mode:
authorTimo Teräs <timo.teras@iki.fi>2014-08-20 10:27:05 +0300
committerTimo Teräs <timo.teras@iki.fi>2014-08-20 10:27:05 +0300
commitc899e9941b773827ef155a4b42c6b9a950841f80 (patch)
treedec0ae30cc4d7caaf8ac6854c7b5a65ac6010e36 /main/musl
parent94f2e3a93ab0837d47962643dd976aa5b2d7d5c4 (diff)
downloadaports-c899e9941b773827ef155a4b42c6b9a950841f80.tar.bz2
aports-c899e9941b773827ef155a4b42c6b9a950841f80.tar.xz
main/musl: git snapshot of 2014-08-18
includes private futex support and mutex/condvar rework and fixes.
Diffstat (limited to 'main/musl')
-rw-r--r--main/musl/0002-d86af2a0-to-4992ace9.patch1083
-rw-r--r--main/musl/APKBUILD6
2 files changed, 1088 insertions, 1 deletions
diff --git a/main/musl/0002-d86af2a0-to-4992ace9.patch b/main/musl/0002-d86af2a0-to-4992ace9.patch
new file mode 100644
index 000000000..ed0eb6522
--- /dev/null
+++ b/main/musl/0002-d86af2a0-to-4992ace9.patch
@@ -0,0 +1,1083 @@
+diff --git a/arch/arm/bits/alltypes.h.in b/arch/arm/bits/alltypes.h.in
+index bd23a6a..0d750cc 100644
+--- a/arch/arm/bits/alltypes.h.in
++++ b/arch/arm/bits/alltypes.h.in
+@@ -17,7 +17,7 @@ TYPEDEF long time_t;
+ TYPEDEF long suseconds_t;
+
+ TYPEDEF struct { union { int __i[9]; unsigned __s[9]; } __u; } pthread_attr_t;
+-TYPEDEF struct { union { int __i[6]; void *__p[6]; } __u; } pthread_mutex_t;
++TYPEDEF struct { union { int __i[6]; volatile void *volatile __p[6]; } __u; } pthread_mutex_t;
+ TYPEDEF struct { union { int __i[12]; void *__p[12]; } __u; } pthread_cond_t;
+ TYPEDEF struct { union { int __i[8]; void *__p[8]; } __u; } pthread_rwlock_t;
+ TYPEDEF struct { union { int __i[5]; void *__p[5]; } __u; } pthread_barrier_t;
+diff --git a/arch/i386/bits/alltypes.h.in b/arch/i386/bits/alltypes.h.in
+index efd2c07..502c882 100644
+--- a/arch/i386/bits/alltypes.h.in
++++ b/arch/i386/bits/alltypes.h.in
+@@ -31,7 +31,7 @@ TYPEDEF long time_t;
+ TYPEDEF long suseconds_t;
+
+ TYPEDEF struct { union { int __i[9]; unsigned __s[9]; } __u; } pthread_attr_t;
+-TYPEDEF struct { union { int __i[6]; void *__p[6]; } __u; } pthread_mutex_t;
++TYPEDEF struct { union { int __i[6]; volatile void *volatile __p[6]; } __u; } pthread_mutex_t;
+ TYPEDEF struct { union { int __i[12]; void *__p[12]; } __u; } pthread_cond_t;
+ TYPEDEF struct { union { int __i[8]; void *__p[8]; } __u; } pthread_rwlock_t;
+ TYPEDEF struct { union { int __i[5]; void *__p[5]; } __u; } pthread_barrier_t;
+diff --git a/arch/microblaze/bits/alltypes.h.in b/arch/microblaze/bits/alltypes.h.in
+index 6bd7942..4657d14 100644
+--- a/arch/microblaze/bits/alltypes.h.in
++++ b/arch/microblaze/bits/alltypes.h.in
+@@ -17,7 +17,7 @@ TYPEDEF long time_t;
+ TYPEDEF long suseconds_t;
+
+ TYPEDEF struct { union { int __i[9]; unsigned __s[9]; } __u; } pthread_attr_t;
+-TYPEDEF struct { union { int __i[6]; void *__p[6]; } __u; } pthread_mutex_t;
++TYPEDEF struct { union { int __i[6]; volatile void *volatile __p[6]; } __u; } pthread_mutex_t;
+ TYPEDEF struct { union { int __i[12]; void *__p[12]; } __u; } pthread_cond_t;
+ TYPEDEF struct { union { int __i[8]; void *__p[8]; } __u; } pthread_rwlock_t;
+ TYPEDEF struct { union { int __i[5]; void *__p[5]; } __u; } pthread_barrier_t;
+diff --git a/arch/mips/bits/alltypes.h.in b/arch/mips/bits/alltypes.h.in
+index 6bd7942..4657d14 100644
+--- a/arch/mips/bits/alltypes.h.in
++++ b/arch/mips/bits/alltypes.h.in
+@@ -17,7 +17,7 @@ TYPEDEF long time_t;
+ TYPEDEF long suseconds_t;
+
+ TYPEDEF struct { union { int __i[9]; unsigned __s[9]; } __u; } pthread_attr_t;
+-TYPEDEF struct { union { int __i[6]; void *__p[6]; } __u; } pthread_mutex_t;
++TYPEDEF struct { union { int __i[6]; volatile void *volatile __p[6]; } __u; } pthread_mutex_t;
+ TYPEDEF struct { union { int __i[12]; void *__p[12]; } __u; } pthread_cond_t;
+ TYPEDEF struct { union { int __i[8]; void *__p[8]; } __u; } pthread_rwlock_t;
+ TYPEDEF struct { union { int __i[5]; void *__p[5]; } __u; } pthread_barrier_t;
+diff --git a/arch/or1k/bits/alltypes.h.in b/arch/or1k/bits/alltypes.h.in
+index bd23a6a..0d750cc 100644
+--- a/arch/or1k/bits/alltypes.h.in
++++ b/arch/or1k/bits/alltypes.h.in
+@@ -17,7 +17,7 @@ TYPEDEF long time_t;
+ TYPEDEF long suseconds_t;
+
+ TYPEDEF struct { union { int __i[9]; unsigned __s[9]; } __u; } pthread_attr_t;
+-TYPEDEF struct { union { int __i[6]; void *__p[6]; } __u; } pthread_mutex_t;
++TYPEDEF struct { union { int __i[6]; volatile void *volatile __p[6]; } __u; } pthread_mutex_t;
+ TYPEDEF struct { union { int __i[12]; void *__p[12]; } __u; } pthread_cond_t;
+ TYPEDEF struct { union { int __i[8]; void *__p[8]; } __u; } pthread_rwlock_t;
+ TYPEDEF struct { union { int __i[5]; void *__p[5]; } __u; } pthread_barrier_t;
+diff --git a/arch/powerpc/bits/alltypes.h.in b/arch/powerpc/bits/alltypes.h.in
+index e9d8dd8..378124c 100644
+--- a/arch/powerpc/bits/alltypes.h.in
++++ b/arch/powerpc/bits/alltypes.h.in
+@@ -17,7 +17,7 @@ TYPEDEF long time_t;
+ TYPEDEF long suseconds_t;
+
+ TYPEDEF struct { union { int __i[9]; unsigned __s[9]; } __u; } pthread_attr_t;
+-TYPEDEF struct { union { int __i[6]; void *__p[6]; } __u; } pthread_mutex_t;
++TYPEDEF struct { union { int __i[6]; volatile void *volatile __p[6]; } __u; } pthread_mutex_t;
+ TYPEDEF struct { union { int __i[12]; void *__p[12]; } __u; } pthread_cond_t;
+ TYPEDEF struct { union { int __i[8]; void *__p[8]; } __u; } pthread_rwlock_t;
+ TYPEDEF struct { union { int __i[5]; void *__p[5]; } __u; } pthread_barrier_t;
+diff --git a/arch/sh/bits/alltypes.h.in b/arch/sh/bits/alltypes.h.in
+index e9d8dd8..378124c 100644
+--- a/arch/sh/bits/alltypes.h.in
++++ b/arch/sh/bits/alltypes.h.in
+@@ -17,7 +17,7 @@ TYPEDEF long time_t;
+ TYPEDEF long suseconds_t;
+
+ TYPEDEF struct { union { int __i[9]; unsigned __s[9]; } __u; } pthread_attr_t;
+-TYPEDEF struct { union { int __i[6]; void *__p[6]; } __u; } pthread_mutex_t;
++TYPEDEF struct { union { int __i[6]; volatile void *volatile __p[6]; } __u; } pthread_mutex_t;
+ TYPEDEF struct { union { int __i[12]; void *__p[12]; } __u; } pthread_cond_t;
+ TYPEDEF struct { union { int __i[8]; void *__p[8]; } __u; } pthread_rwlock_t;
+ TYPEDEF struct { union { int __i[5]; void *__p[5]; } __u; } pthread_barrier_t;
+diff --git a/arch/x32/bits/alltypes.h.in b/arch/x32/bits/alltypes.h.in
+index b077fc9..8930efa 100644
+--- a/arch/x32/bits/alltypes.h.in
++++ b/arch/x32/bits/alltypes.h.in
+@@ -22,7 +22,7 @@ TYPEDEF long long time_t;
+ TYPEDEF long long suseconds_t;
+
+ TYPEDEF struct { union { int __i[14]; unsigned long __s[7]; } __u; } pthread_attr_t;
+-TYPEDEF struct { union { int __i[10]; void *__p[5]; } __u; } pthread_mutex_t;
++TYPEDEF struct { union { int __i[10]; volatile void *volatile __p[5]; } __u; } pthread_mutex_t;
+ TYPEDEF struct { union { int __i[12]; void *__p[6]; } __u; } pthread_cond_t;
+ TYPEDEF struct { union { int __i[14]; void *__p[7]; } __u; } pthread_rwlock_t;
+ TYPEDEF struct { union { int __i[8]; void *__p[4]; } __u; } pthread_barrier_t;
+diff --git a/arch/x86_64/bits/alltypes.h.in b/arch/x86_64/bits/alltypes.h.in
+index 277e944..34b7d6a 100644
+--- a/arch/x86_64/bits/alltypes.h.in
++++ b/arch/x86_64/bits/alltypes.h.in
+@@ -22,7 +22,7 @@ TYPEDEF long time_t;
+ TYPEDEF long suseconds_t;
+
+ TYPEDEF struct { union { int __i[14]; unsigned long __s[7]; } __u; } pthread_attr_t;
+-TYPEDEF struct { union { int __i[10]; void *__p[5]; } __u; } pthread_mutex_t;
++TYPEDEF struct { union { int __i[10]; volatile void *volatile __p[5]; } __u; } pthread_mutex_t;
+ TYPEDEF struct { union { int __i[12]; void *__p[6]; } __u; } pthread_cond_t;
+ TYPEDEF struct { union { int __i[14]; void *__p[7]; } __u; } pthread_rwlock_t;
+ TYPEDEF struct { union { int __i[8]; void *__p[4]; } __u; } pthread_barrier_t;
+diff --git a/src/internal/pthread_impl.h b/src/internal/pthread_impl.h
+index 650e811..2d090f8 100644
+--- a/src/internal/pthread_impl.h
++++ b/src/internal/pthread_impl.h
+@@ -33,9 +33,9 @@ struct pthread {
+ pthread_attr_t attr;
+ volatile int dead;
+ struct {
+- void **head;
++ volatile void *volatile head;
+ long off;
+- void *pending;
++ volatile void *volatile pending;
+ } robust_list;
+ int unblock_cancel;
+ int timer_id;
+@@ -66,16 +66,16 @@ struct __timer {
+ #define _m_prev __u.__p[3]
+ #define _m_next __u.__p[4]
+ #define _m_count __u.__i[5]
+-#define _c_mutex __u.__p[0]
++#define _c_shared __u.__p[0]
+ #define _c_seq __u.__i[2]
+ #define _c_waiters __u.__i[3]
+ #define _c_clock __u.__i[4]
+-#define _c_lock __u.__i[5]
+-#define _c_lockwait __u.__i[6]
+-#define _c_waiters2 __u.__i[7]
+-#define _c_destroy __u.__i[8]
++#define _c_lock __u.__i[8]
++#define _c_head __u.__p[1]
++#define _c_tail __u.__p[5]
+ #define _rw_lock __u.__i[0]
+ #define _rw_waiters __u.__i[1]
++#define _rw_shared __u.__i[2]
+ #define _b_lock __u.__i[0]
+ #define _b_waiters __u.__i[1]
+ #define _b_limit __u.__i[2]
+@@ -108,8 +108,13 @@ void __unmapself(void *, size_t);
+
+ int __timedwait(volatile int *, int, clockid_t, const struct timespec *, void (*)(void *), void *, int);
+ void __wait(volatile int *, volatile int *, int, int);
+-#define __wake(addr, cnt, priv) \
+- __syscall(SYS_futex, addr, FUTEX_WAKE, (cnt)<0?INT_MAX:(cnt))
++static inline void __wake(volatile void *addr, int cnt, int priv)
++{
++ if (priv) priv = 128;
++ if (cnt<0) cnt = INT_MAX;
++ __syscall(SYS_futex, addr, FUTEX_WAKE|priv, cnt) != -EINVAL ||
++ __syscall(SYS_futex, addr, FUTEX_WAKE, cnt);
++}
+
+ void __acquire_ptc();
+ void __release_ptc();
+diff --git a/src/mman/mmap.c b/src/mman/mmap.c
+index 1917a54..56e39a7 100644
+--- a/src/mman/mmap.c
++++ b/src/mman/mmap.c
+@@ -16,8 +16,6 @@ weak_alias(dummy0, __vm_unlock);
+
+ void *__mmap(void *start, size_t len, int prot, int flags, int fd, off_t off)
+ {
+- void *ret;
+-
+ if (off & OFF_MASK) {
+ errno = EINVAL;
+ return MAP_FAILED;
+@@ -26,14 +24,15 @@ void *__mmap(void *start, size_t len, int prot, int flags, int fd, off_t off)
+ errno = ENOMEM;
+ return MAP_FAILED;
+ }
+- if (flags & MAP_FIXED) __vm_lock(-1);
++ if (flags & MAP_FIXED) {
++ __vm_lock(-1);
++ __vm_unlock();
++ }
+ #ifdef SYS_mmap2
+- ret = (void *)syscall(SYS_mmap2, start, len, prot, flags, fd, off/UNIT);
++ return (void *)syscall(SYS_mmap2, start, len, prot, flags, fd, off/UNIT);
+ #else
+- ret = (void *)syscall(SYS_mmap, start, len, prot, flags, fd, off);
++ return (void *)syscall(SYS_mmap, start, len, prot, flags, fd, off);
+ #endif
+- if (flags & MAP_FIXED) __vm_unlock();
+- return ret;
+ }
+
+ weak_alias(__mmap, mmap);
+diff --git a/src/mman/munmap.c b/src/mman/munmap.c
+index 8488d75..359c691 100644
+--- a/src/mman/munmap.c
++++ b/src/mman/munmap.c
+@@ -11,8 +11,8 @@ int __munmap(void *start, size_t len)
+ {
+ int ret;
+ __vm_lock(-1);
+- ret = syscall(SYS_munmap, start, len);
+ __vm_unlock();
++ ret = syscall(SYS_munmap, start, len);
+ return ret;
+ }
+
+diff --git a/src/thread/__timedwait.c b/src/thread/__timedwait.c
+index 302273a..39eb996 100644
+--- a/src/thread/__timedwait.c
++++ b/src/thread/__timedwait.c
+@@ -4,12 +4,15 @@
+ #include "futex.h"
+ #include "syscall.h"
+
+-static int do_wait(volatile int *addr, int val,
+- clockid_t clk, const struct timespec *at, int priv)
++int __timedwait(volatile int *addr, int val,
++ clockid_t clk, const struct timespec *at,
++ void (*cleanup)(void *), void *arg, int priv)
+ {
+- int r;
++ int r, cs;
+ struct timespec to, *top=0;
+
++ if (priv) priv = 128;
++
+ if (at) {
+ if (at->tv_nsec >= 1000000000UL) return EINVAL;
+ if (clock_gettime(clk, &to)) return EINVAL;
+@@ -22,21 +25,12 @@ static int do_wait(volatile int *addr, int val,
+ top = &to;
+ }
+
+- r = -__syscall_cp(SYS_futex, addr, FUTEX_WAIT, val, top);
+- if (r == EINTR || r == EINVAL || r == ETIMEDOUT) return r;
+- return 0;
+-}
+-
+-int __timedwait(volatile int *addr, int val,
+- clockid_t clk, const struct timespec *at,
+- void (*cleanup)(void *), void *arg, int priv)
+-{
+- int r, cs;
+-
+ if (!cleanup) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
+ pthread_cleanup_push(cleanup, arg);
+
+- r = do_wait(addr, val, clk, at, priv);
++ r = -__syscall_cp(SYS_futex, addr, FUTEX_WAIT|priv, val, top);
++ if (r == EINVAL) r = -__syscall_cp(SYS_futex, addr, FUTEX_WAIT, val, top);
++ if (r != EINTR && r != ETIMEDOUT) r = 0;
+
+ pthread_cleanup_pop(0);
+ if (!cleanup) pthread_setcancelstate(cs, 0);
+diff --git a/src/thread/__wait.c b/src/thread/__wait.c
+index a1e4780..ec1e820 100644
+--- a/src/thread/__wait.c
++++ b/src/thread/__wait.c
+@@ -3,13 +3,15 @@
+ void __wait(volatile int *addr, volatile int *waiters, int val, int priv)
+ {
+ int spins=10000;
+- if (priv) priv = 128; priv=0;
++ if (priv) priv = 128;
+ while (spins--) {
+ if (*addr==val) a_spin();
+ else return;
+ }
+ if (waiters) a_inc(waiters);
+- while (*addr==val)
+- __syscall(SYS_futex, addr, FUTEX_WAIT|priv, val, 0);
++ while (*addr==val) {
++ __syscall(SYS_futex, addr, FUTEX_WAIT|priv, val, 0) != -EINVAL
++ || __syscall(SYS_futex, addr, FUTEX_WAIT, val, 0);
++ }
+ if (waiters) a_dec(waiters);
+ }
+diff --git a/src/thread/pthread_attr_get.c b/src/thread/pthread_attr_get.c
+index 03fc91e..3d296bf 100644
+--- a/src/thread/pthread_attr_get.c
++++ b/src/thread/pthread_attr_get.c
+@@ -75,7 +75,7 @@ int pthread_mutexattr_getprotocol(const pthread_mutexattr_t *restrict a, int *re
+ }
+ int pthread_mutexattr_getpshared(const pthread_mutexattr_t *restrict a, int *restrict pshared)
+ {
+- *pshared = a->__attr>>31;
++ *pshared = a->__attr / 128U % 2;
+ return 0;
+ }
+
+diff --git a/src/thread/pthread_barrier_wait.c b/src/thread/pthread_barrier_wait.c
+index 5e60338..6b329c9 100644
+--- a/src/thread/pthread_barrier_wait.c
++++ b/src/thread/pthread_barrier_wait.c
+@@ -87,7 +87,8 @@ int pthread_barrier_wait(pthread_barrier_t *b)
+ a_spin();
+ a_inc(&inst->finished);
+ while (inst->finished == 1)
+- __syscall(SYS_futex, &inst->finished, FUTEX_WAIT,1,0);
++ __syscall(SYS_futex,&inst->finished,FUTEX_WAIT|128,1,0) != -EINTR
++ || __syscall(SYS_futex,&inst->finished,FUTEX_WAIT,1,0);
+ return PTHREAD_BARRIER_SERIAL_THREAD;
+ }
+
+diff --git a/src/thread/pthread_cond_broadcast.c b/src/thread/pthread_cond_broadcast.c
+index 0901daf..69f840f 100644
+--- a/src/thread/pthread_cond_broadcast.c
++++ b/src/thread/pthread_cond_broadcast.c
+@@ -1,39 +1,12 @@
+ #include "pthread_impl.h"
+
++int __private_cond_signal(pthread_cond_t *, int);
++
+ int pthread_cond_broadcast(pthread_cond_t *c)
+ {
+- pthread_mutex_t *m;
+-
++ if (!c->_c_shared) return __private_cond_signal(c, -1);
+ if (!c->_c_waiters) return 0;
+-
+ a_inc(&c->_c_seq);
+-
+- /* If cond var is process-shared, simply wake all waiters. */
+- if (c->_c_mutex == (void *)-1) {
+- __wake(&c->_c_seq, -1, 0);
+- return 0;
+- }
+-
+- /* Block waiters from returning so we can use the mutex. */
+- while (a_swap(&c->_c_lock, 1))
+- __wait(&c->_c_lock, &c->_c_lockwait, 1, 1);
+- if (!c->_c_waiters)
+- goto out;
+- m = c->_c_mutex;
+-
+- /* Move waiter count to the mutex */
+- a_fetch_add(&m->_m_waiters, c->_c_waiters2);
+- c->_c_waiters2 = 0;
+-
+- /* Perform the futex requeue, waking one waiter unless we know
+- * that the calling thread holds the mutex. */
+- __syscall(SYS_futex, &c->_c_seq, FUTEX_REQUEUE,
+- !m->_m_type || (m->_m_lock&INT_MAX)!=__pthread_self()->tid,
+- INT_MAX, &m->_m_lock);
+-
+-out:
+- a_store(&c->_c_lock, 0);
+- if (c->_c_lockwait) __wake(&c->_c_lock, 1, 0);
+-
++ __wake(&c->_c_seq, -1, 0);
+ return 0;
+ }
+diff --git a/src/thread/pthread_cond_destroy.c b/src/thread/pthread_cond_destroy.c
+index a096c55..8c55516 100644
+--- a/src/thread/pthread_cond_destroy.c
++++ b/src/thread/pthread_cond_destroy.c
+@@ -2,12 +2,13 @@
+
+ int pthread_cond_destroy(pthread_cond_t *c)
+ {
+- int priv = c->_c_mutex != (void *)-1;
+- int cnt;
+- c->_c_destroy = 1;
+- if (c->_c_waiters)
+- __wake(&c->_c_seq, -1, priv);
+- while ((cnt = c->_c_waiters))
+- __wait(&c->_c_waiters, 0, cnt, priv);
++ if (c->_c_shared && c->_c_waiters) {
++ int cnt;
++ a_or(&c->_c_waiters, 0x80000000);
++ a_inc(&c->_c_seq);
++ __wake(&c->_c_seq, -1, 0);
++ while ((cnt = c->_c_waiters) & 0x7fffffff)
++ __wait(&c->_c_waiters, 0, cnt, 0);
++ }
+ return 0;
+ }
+diff --git a/src/thread/pthread_cond_init.c b/src/thread/pthread_cond_init.c
+index 357ecd5..8c484dd 100644
+--- a/src/thread/pthread_cond_init.c
++++ b/src/thread/pthread_cond_init.c
+@@ -5,7 +5,7 @@ int pthread_cond_init(pthread_cond_t *restrict c, const pthread_condattr_t *rest
+ *c = (pthread_cond_t){0};
+ if (a) {
+ c->_c_clock = a->__attr & 0x7fffffff;
+- if (a->__attr>>31) c->_c_mutex = (void *)-1;
++ if (a->__attr>>31) c->_c_shared = (void *)-1;
+ }
+ return 0;
+ }
+diff --git a/src/thread/pthread_cond_signal.c b/src/thread/pthread_cond_signal.c
+index 71bcdcd..119c00a 100644
+--- a/src/thread/pthread_cond_signal.c
++++ b/src/thread/pthread_cond_signal.c
+@@ -1,9 +1,12 @@
+ #include "pthread_impl.h"
+
++int __private_cond_signal(pthread_cond_t *, int);
++
+ int pthread_cond_signal(pthread_cond_t *c)
+ {
++ if (!c->_c_shared) return __private_cond_signal(c, 1);
+ if (!c->_c_waiters) return 0;
+ a_inc(&c->_c_seq);
+- if (c->_c_waiters) __wake(&c->_c_seq, 1, 0);
++ __wake(&c->_c_seq, 1, 0);
+ return 0;
+ }
+diff --git a/src/thread/pthread_cond_timedwait.c b/src/thread/pthread_cond_timedwait.c
+index 99d62cc..c5cf66c 100644
+--- a/src/thread/pthread_cond_timedwait.c
++++ b/src/thread/pthread_cond_timedwait.c
+@@ -1,47 +1,130 @@
+ #include "pthread_impl.h"
+
+-struct cm {
+- pthread_cond_t *c;
+- pthread_mutex_t *m;
++/*
++ * struct waiter
++ *
++ * Waiter objects have automatic storage on the waiting thread, and
++ * are used in building a linked list representing waiters currently
++ * waiting on the condition variable or a group of waiters woken
++ * together by a broadcast or signal; in the case of signal, this is a
++ * degenerate list of one member.
++ *
++ * Waiter lists attached to the condition variable itself are
++ * protected by the lock on the cv. Detached waiter lists are never
++ * modified again, but can only be traversed in reverse order, and are
++ * protected by the "barrier" locks in each node, which are unlocked
++ * in turn to control wake order.
++ *
++ * Since process-shared cond var semantics do not necessarily allow
++ * one thread to see another's automatic storage (they may be in
++ * different processes), the waiter list is not used for the
++ * process-shared case, but the structure is still used to store data
++ * needed by the cancellation cleanup handler.
++ */
++
++struct waiter {
++ struct waiter *prev, *next;
++ int state, barrier, mutex_ret;
++ int *notify;
++ pthread_mutex_t *mutex;
++ pthread_cond_t *cond;
++ int shared;
+ };
+
+-static void unwait(pthread_cond_t *c, pthread_mutex_t *m)
++/* Self-synchronized-destruction-safe lock functions */
++
++static inline void lock(volatile int *l)
+ {
+- /* Removing a waiter is non-trivial if we could be using requeue
+- * based broadcast signals, due to mutex access issues, etc. */
++ if (a_cas(l, 0, 1)) {
++ a_cas(l, 1, 2);
++ do __wait(l, 0, 2, 1);
++ while (a_cas(l, 0, 2));
++ }
++}
+
+- if (c->_c_mutex == (void *)-1) {
+- a_dec(&c->_c_waiters);
+- if (c->_c_destroy) __wake(&c->_c_waiters, 1, 0);
++static inline void unlock(volatile int *l)
++{
++ if (a_swap(l, 0)==2)
++ __wake(l, 1, 1);
++}
++
++static inline void unlock_requeue(volatile int *l, volatile int *r, int w)
++{
++ a_store(l, 0);
++ if (w) __wake(l, 1, 1);
++ else __syscall(SYS_futex, l, FUTEX_REQUEUE|128, 0, 1, r) != -EINVAL
++ || __syscall(SYS_futex, l, FUTEX_REQUEUE, 0, 1, r);
++}
++
++enum {
++ WAITING,
++ SIGNALED,
++ LEAVING,
++};
++
++static void unwait(void *arg)
++{
++ struct waiter *node = arg;
++
++ if (node->shared) {
++ pthread_cond_t *c = node->cond;
++ pthread_mutex_t *m = node->mutex;
++ if (a_fetch_add(&c->_c_waiters, -1) == -0x7fffffff)
++ __wake(&c->_c_waiters, 1, 0);
++ node->mutex_ret = pthread_mutex_lock(m);
+ return;
+ }
+
+- while (a_swap(&c->_c_lock, 1))
+- __wait(&c->_c_lock, &c->_c_lockwait, 1, 1);
++ int oldstate = a_cas(&node->state, WAITING, LEAVING);
++
++ if (oldstate == WAITING) {
++ /* Access to cv object is valid because this waiter was not
++ * yet signaled and a new signal/broadcast cannot return
++ * after seeing a LEAVING waiter without getting notified
++ * via the futex notify below. */
++
++ pthread_cond_t *c = node->cond;
++ lock(&c->_c_lock);
++
++ if (c->_c_head == node) c->_c_head = node->next;
++ else if (node->prev) node->prev->next = node->next;
++ if (c->_c_tail == node) c->_c_tail = node->prev;
++ else if (node->next) node->next->prev = node->prev;
++
++ unlock(&c->_c_lock);
++
++ if (node->notify) {
++ if (a_fetch_add(node->notify, -1)==1)
++ __wake(node->notify, 1, 1);
++ }
++ } else {
++ /* Lock barrier first to control wake order. */
++ lock(&node->barrier);
++ }
+
+- if (c->_c_waiters2) c->_c_waiters2--;
+- else a_dec(&m->_m_waiters);
++ node->mutex_ret = pthread_mutex_lock(node->mutex);
+
+- a_store(&c->_c_lock, 0);
+- if (c->_c_lockwait) __wake(&c->_c_lock, 1, 1);
++ if (oldstate == WAITING) return;
+
+- a_dec(&c->_c_waiters);
+- if (c->_c_destroy) __wake(&c->_c_waiters, 1, 1);
+-}
++ if (!node->next) a_inc(&node->mutex->_m_waiters);
+
+-static void cleanup(void *p)
+-{
+- struct cm *cm = p;
+- unwait(cm->c, cm->m);
+- pthread_mutex_lock(cm->m);
++ /* Unlock the barrier that's holding back the next waiter, and
++ * either wake it or requeue it to the mutex. */
++ if (node->prev) {
++ unlock_requeue(&node->prev->barrier,
++ &node->mutex->_m_lock,
++ node->mutex->_m_type & 128);
++ } else {
++ a_dec(&node->mutex->_m_waiters);
++ }
+ }
+
+ int pthread_cond_timedwait(pthread_cond_t *restrict c, pthread_mutex_t *restrict m, const struct timespec *restrict ts)
+ {
+- struct cm cm = { .c=c, .m=m };
+- int r, e=0, seq;
++ struct waiter node = { .cond = c, .mutex = m };
++ int e, seq, *fut, clock = c->_c_clock;
+
+- if (m->_m_type && (m->_m_lock&INT_MAX) != __pthread_self()->tid)
++ if ((m->_m_type&15) && (m->_m_lock&INT_MAX) != __pthread_self()->tid)
+ return EPERM;
+
+ if (ts && ts->tv_nsec >= 1000000000UL)
+@@ -49,28 +132,68 @@ int pthread_cond_timedwait(pthread_cond_t *restrict c, pthread_mutex_t *restrict
+
+ pthread_testcancel();
+
+- a_inc(&c->_c_waiters);
+-
+- if (c->_c_mutex != (void *)-1) {
+- c->_c_mutex = m;
+- while (a_swap(&c->_c_lock, 1))
+- __wait(&c->_c_lock, &c->_c_lockwait, 1, 1);
+- c->_c_waiters2++;
+- a_store(&c->_c_lock, 0);
+- if (c->_c_lockwait) __wake(&c->_c_lock, 1, 1);
++ if (c->_c_shared) {
++ node.shared = 1;
++ fut = &c->_c_seq;
++ seq = c->_c_seq;
++ a_inc(&c->_c_waiters);
++ } else {
++ lock(&c->_c_lock);
++
++ seq = node.barrier = 2;
++ fut = &node.barrier;
++ node.state = WAITING;
++ node.next = c->_c_head;
++ c->_c_head = &node;
++ if (!c->_c_tail) c->_c_tail = &node;
++ else node.next->prev = &node;
++
++ unlock(&c->_c_lock);
+ }
+
+- seq = c->_c_seq;
+-
+ pthread_mutex_unlock(m);
+
+- do e = __timedwait(&c->_c_seq, seq, c->_c_clock, ts, cleanup, &cm, 0);
+- while (c->_c_seq == seq && (!e || e==EINTR));
++ do e = __timedwait(fut, seq, clock, ts, unwait, &node, !node.shared);
++ while (*fut==seq && (!e || e==EINTR));
+ if (e == EINTR) e = 0;
+
+- unwait(c, m);
++ unwait(&node);
++
++ return node.mutex_ret ? node.mutex_ret : e;
++}
++
++int __private_cond_signal(pthread_cond_t *c, int n)
++{
++ struct waiter *p, *first=0;
++ int ref = 0, cur;
++
++ lock(&c->_c_lock);
++ for (p=c->_c_tail; n && p; p=p->prev) {
++ if (a_cas(&p->state, WAITING, SIGNALED) != WAITING) {
++ ref++;
++ p->notify = &ref;
++ } else {
++ n--;
++ if (!first) first=p;
++ }
++ }
++ /* Split the list, leaving any remainder on the cv. */
++ if (p) {
++ if (p->next) p->next->prev = 0;
++ p->next = 0;
++ } else {
++ c->_c_head = 0;
++ }
++ c->_c_tail = p;
++ unlock(&c->_c_lock);
++
++ /* Wait for any waiters in the LEAVING state to remove
++ * themselves from the list before returning or allowing
++ * signaled threads to proceed. */
++ while ((cur = ref)) __wait(&ref, 0, cur, 1);
+
+- if ((r=pthread_mutex_lock(m))) return r;
++ /* Allow first signaled waiter, if any, to proceed. */
++ if (first) unlock(&first->barrier);
+
+- return e;
++ return 0;
+ }
+diff --git a/src/thread/pthread_create.c b/src/thread/pthread_create.c
+index e77e54a..c8c117b 100644
+--- a/src/thread/pthread_create.c
++++ b/src/thread/pthread_create.c
+@@ -10,6 +10,7 @@ static void dummy_0()
+ weak_alias(dummy_0, __acquire_ptc);
+ weak_alias(dummy_0, __release_ptc);
+ weak_alias(dummy_0, __pthread_tsd_run_dtors);
++weak_alias(dummy_0, __do_private_robust_list);
+
+ _Noreturn void pthread_exit(void *result)
+ {
+@@ -63,6 +64,8 @@ _Noreturn void pthread_exit(void *result)
+ a_dec(&libc.bytelocale_cnt_minus_1);
+ }
+
++ __do_private_robust_list();
++
+ if (self->detached && self->map_base) {
+ /* Detached threads must avoid the kernel clear_child_tid
+ * feature, since the virtual address will have been
+diff --git a/src/thread/pthread_mutex_consistent.c b/src/thread/pthread_mutex_consistent.c
+index 65da29f..96b83b5 100644
+--- a/src/thread/pthread_mutex_consistent.c
++++ b/src/thread/pthread_mutex_consistent.c
+@@ -2,9 +2,9 @@
+
+ int pthread_mutex_consistent(pthread_mutex_t *m)
+ {
+- if (m->_m_type < 8) return EINVAL;
+- if ((m->_m_lock & 0x3fffffff) != __pthread_self()->tid)
++ if (!(m->_m_type & 8)) return EINVAL;
++ if ((m->_m_lock & 0x7fffffff) != __pthread_self()->tid)
+ return EPERM;
+- m->_m_type -= 8;
++ m->_m_type &= ~8U;
+ return 0;
+ }
+diff --git a/src/thread/pthread_mutex_init.c b/src/thread/pthread_mutex_init.c
+index 9d85a35..acf45a7 100644
+--- a/src/thread/pthread_mutex_init.c
++++ b/src/thread/pthread_mutex_init.c
+@@ -3,6 +3,6 @@
+ int pthread_mutex_init(pthread_mutex_t *restrict m, const pthread_mutexattr_t *restrict a)
+ {
+ *m = (pthread_mutex_t){0};
+- if (a) m->_m_type = a->__attr & 7;
++ if (a) m->_m_type = a->__attr;
+ return 0;
+ }
+diff --git a/src/thread/pthread_mutex_lock.c b/src/thread/pthread_mutex_lock.c
+index 42b5af6..2a9a3aa 100644
+--- a/src/thread/pthread_mutex_lock.c
++++ b/src/thread/pthread_mutex_lock.c
+@@ -2,7 +2,8 @@
+
+ int pthread_mutex_lock(pthread_mutex_t *m)
+ {
+- if (m->_m_type == PTHREAD_MUTEX_NORMAL && !a_cas(&m->_m_lock, 0, EBUSY))
++ if ((m->_m_type&15) == PTHREAD_MUTEX_NORMAL
++ && !a_cas(&m->_m_lock, 0, EBUSY))
+ return 0;
+
+ return pthread_mutex_timedlock(m, 0);
+diff --git a/src/thread/pthread_mutex_timedlock.c b/src/thread/pthread_mutex_timedlock.c
+index 7b1afc0..2a959d2 100644
+--- a/src/thread/pthread_mutex_timedlock.c
++++ b/src/thread/pthread_mutex_timedlock.c
+@@ -2,21 +2,23 @@
+
+ int pthread_mutex_timedlock(pthread_mutex_t *restrict m, const struct timespec *restrict at)
+ {
+- int r, t;
+-
+- if (m->_m_type == PTHREAD_MUTEX_NORMAL && !a_cas(&m->_m_lock, 0, EBUSY))
++ if ((m->_m_type&15) == PTHREAD_MUTEX_NORMAL
++ && !a_cas(&m->_m_lock, 0, EBUSY))
+ return 0;
+
++ int r, t, priv = (m->_m_type & 128) ^ 128;
++
+ while ((r=pthread_mutex_trylock(m)) == EBUSY) {
+- if (!(r=m->_m_lock) || (r&0x40000000)) continue;
++ if (!(r=m->_m_lock) || ((r&0x40000000) && (m->_m_type&4)))
++ continue;
+ if ((m->_m_type&3) == PTHREAD_MUTEX_ERRORCHECK
+- && (r&0x1fffffff) == __pthread_self()->tid)
++ && (r&0x7fffffff) == __pthread_self()->tid)
+ return EDEADLK;
+
+ a_inc(&m->_m_waiters);
+ t = r | 0x80000000;
+ a_cas(&m->_m_lock, r, t);
+- r = __timedwait(&m->_m_lock, t, CLOCK_REALTIME, at, 0, 0, 0);
++ r = __timedwait(&m->_m_lock, t, CLOCK_REALTIME, at, 0, 0, priv);
+ a_dec(&m->_m_waiters);
+ if (r && r != EINTR) break;
+ }
+diff --git a/src/thread/pthread_mutex_trylock.c b/src/thread/pthread_mutex_trylock.c
+index 00ad65d..e851517 100644
+--- a/src/thread/pthread_mutex_trylock.c
++++ b/src/thread/pthread_mutex_trylock.c
+@@ -1,52 +1,58 @@
+ #include "pthread_impl.h"
+
+-int pthread_mutex_trylock(pthread_mutex_t *m)
++int __pthread_mutex_trylock_owner(pthread_mutex_t *m)
+ {
+- int tid, old, own;
+- pthread_t self;
+-
+- if (m->_m_type == PTHREAD_MUTEX_NORMAL)
+- return a_cas(&m->_m_lock, 0, EBUSY) & EBUSY;
+-
+- self = __pthread_self();
+- tid = self->tid;
+-
+- if (m->_m_type >= 4) {
+- if (!self->robust_list.off)
+- __syscall(SYS_set_robust_list,
+- &self->robust_list, 3*sizeof(long));
++ int old, own;
++ int type = m->_m_type & 15;
++ pthread_t self = __pthread_self();
++ int tid = self->tid;
++
++ if (!self->robust_list.off) {
++ __syscall(SYS_set_robust_list, &self->robust_list, 3*sizeof(long));
++ self->robust_list.head = &self->robust_list.head;
+ self->robust_list.off = (char*)&m->_m_lock-(char *)&m->_m_next;
+- self->robust_list.pending = &m->_m_next;
+ }
+
+ old = m->_m_lock;
+ own = old & 0x7fffffff;
+- if (own == tid && (m->_m_type&3) == PTHREAD_MUTEX_RECURSIVE) {
++ if (own == tid && (type&3) == PTHREAD_MUTEX_RECURSIVE) {
+ if ((unsigned)m->_m_count >= INT_MAX) return EAGAIN;
+ m->_m_count++;
+ return 0;
+ }
++ if (own == 0x40000000) return ENOTRECOVERABLE;
+
+- if ((own && !(own & 0x40000000)) || a_cas(&m->_m_lock, old, tid)!=old)
+- return EBUSY;
+-
+- if (m->_m_type < 4) return 0;
++ if (m->_m_type & 128) {
++ if (m->_m_waiters) tid |= 0x80000000;
++ self->robust_list.pending = &m->_m_next;
++ }
+
+- if (m->_m_type >= 8) {
+- m->_m_lock = 0;
+- return ENOTRECOVERABLE;
++ if ((own && (!(own & 0x40000000) || !(type & 4)))
++ || a_cas(&m->_m_lock, old, tid) != old) {
++ self->robust_list.pending = 0;
++ return EBUSY;
+ }
+- m->_m_next = self->robust_list.head;
++
++ volatile void *next = self->robust_list.head;
++ m->_m_next = next;
+ m->_m_prev = &self->robust_list.head;
+- if (self->robust_list.head)
+- self->robust_list.head[-1] = &m->_m_next;
++ if (next != &self->robust_list.head) *(volatile void *volatile *)
++ ((char *)next - sizeof(void *)) = &m->_m_next;
+ self->robust_list.head = &m->_m_next;
+ self->robust_list.pending = 0;
++
+ if (own) {
+ m->_m_count = 0;
+- m->_m_type += 8;
++ m->_m_type |= 8;
+ return EOWNERDEAD;
+ }
+
+ return 0;
+ }
++
++int pthread_mutex_trylock(pthread_mutex_t *m)
++{
++ if ((m->_m_type&15) == PTHREAD_MUTEX_NORMAL)
++ return a_cas(&m->_m_lock, 0, EBUSY) & EBUSY;
++ return __pthread_mutex_trylock_owner(m);
++}
+diff --git a/src/thread/pthread_mutex_unlock.c b/src/thread/pthread_mutex_unlock.c
+index b4bd74b..46761d9 100644
+--- a/src/thread/pthread_mutex_unlock.c
++++ b/src/thread/pthread_mutex_unlock.c
+@@ -8,30 +8,31 @@ int pthread_mutex_unlock(pthread_mutex_t *m)
+ pthread_t self;
+ int waiters = m->_m_waiters;
+ int cont;
+- int robust = 0;
++ int type = m->_m_type & 15;
++ int priv = (m->_m_type & 128) ^ 128;
+
+- if (m->_m_type != PTHREAD_MUTEX_NORMAL) {
+- if (!m->_m_lock)
+- return EPERM;
++ if (type != PTHREAD_MUTEX_NORMAL) {
+ self = __pthread_self();
+- if ((m->_m_lock&0x1fffffff) != self->tid)
++ if ((m->_m_lock&0x7fffffff) != self->tid)
+ return EPERM;
+- if ((m->_m_type&3) == PTHREAD_MUTEX_RECURSIVE && m->_m_count)
++ if ((type&3) == PTHREAD_MUTEX_RECURSIVE && m->_m_count)
+ return m->_m_count--, 0;
+- if (m->_m_type >= 4) {
+- robust = 1;
++ if (!priv) {
+ self->robust_list.pending = &m->_m_next;
+- *(void **)m->_m_prev = m->_m_next;
+- if (m->_m_next) ((void **)m->_m_next)[-1] = m->_m_prev;
+ __vm_lock_impl(+1);
+ }
++ volatile void *prev = m->_m_prev;
++ volatile void *next = m->_m_next;
++ *(volatile void *volatile *)prev = next;
++ if (next != &self->robust_list.head) *(volatile void *volatile *)
++ ((char *)next - sizeof(void *)) = prev;
+ }
+- cont = a_swap(&m->_m_lock, 0);
+- if (robust) {
++ cont = a_swap(&m->_m_lock, (type & 8) ? 0x40000000 : 0);
++ if (type != PTHREAD_MUTEX_NORMAL && !priv) {
+ self->robust_list.pending = 0;
+ __vm_unlock_impl();
+ }
+ if (waiters || cont<0)
+- __wake(&m->_m_lock, 1, 0);
++ __wake(&m->_m_lock, 1, priv);
+ return 0;
+ }
+diff --git a/src/thread/pthread_mutexattr_setpshared.c b/src/thread/pthread_mutexattr_setpshared.c
+index 8c7a1e2..100f6ff 100644
+--- a/src/thread/pthread_mutexattr_setpshared.c
++++ b/src/thread/pthread_mutexattr_setpshared.c
+@@ -3,7 +3,7 @@
+ int pthread_mutexattr_setpshared(pthread_mutexattr_t *a, int pshared)
+ {
+ if (pshared > 1U) return EINVAL;
+- a->__attr &= 0x7fffffff;
+- a->__attr |= pshared<<31;
++ a->__attr &= ~128U;
++ a->__attr |= pshared<<7;
+ return 0;
+ }
+diff --git a/src/thread/pthread_mutexattr_setrobust.c b/src/thread/pthread_mutexattr_setrobust.c
+index dcfa4cf..d062788 100644
+--- a/src/thread/pthread_mutexattr_setrobust.c
++++ b/src/thread/pthread_mutexattr_setrobust.c
+@@ -1,4 +1,28 @@
+ #include "pthread_impl.h"
++#include <stddef.h>
++
++void __do_private_robust_list()
++{
++ pthread_t self = __pthread_self();
++ volatile void *volatile *p;
++ volatile void *volatile *prev;
++ volatile void *volatile *next;
++ pthread_mutex_t *m;
++
++ prev = &self->robust_list.head;
++ for (p=self->robust_list.head; p&&p!=&self->robust_list.head; p=next) {
++ next = *p;
++ m = (void *)((char *)p - offsetof(pthread_mutex_t, _m_next));
++ if (!(m->_m_type & 128)) {
++ int waiters = m->_m_waiters;
++ *prev = next;
++ int cont = a_swap(&m->_m_lock, self->tid|0x40000000);
++ if (cont < 0 || waiters) __wake(&m->_m_lock, 1, 1);
++ } else {
++ prev = p;
++ }
++ }
++}
+
+ int pthread_mutexattr_setrobust(pthread_mutexattr_t *a, int robust)
+ {
+diff --git a/src/thread/pthread_once.c b/src/thread/pthread_once.c
+index e01f6d4..2eb0f93 100644
+--- a/src/thread/pthread_once.c
++++ b/src/thread/pthread_once.c
+@@ -3,7 +3,7 @@
+ static void undo(void *control)
+ {
+ a_store(control, 0);
+- __wake(control, 1, 0);
++ __wake(control, 1, 1);
+ }
+
+ int pthread_once(pthread_once_t *control, void (*init)(void))
+@@ -25,10 +25,10 @@ int pthread_once(pthread_once_t *control, void (*init)(void))
+ pthread_cleanup_pop(0);
+
+ a_store(control, 2);
+- if (waiters) __wake(control, -1, 0);
++ if (waiters) __wake(control, -1, 1);
+ return 0;
+ case 1:
+- __wait(control, &waiters, 1, 0);
++ __wait(control, &waiters, 1, 1);
+ continue;
+ case 2:
+ return 0;
+diff --git a/src/thread/pthread_rwlock_init.c b/src/thread/pthread_rwlock_init.c
+index 82df52e..a2c0b47 100644
+--- a/src/thread/pthread_rwlock_init.c
++++ b/src/thread/pthread_rwlock_init.c
+@@ -3,7 +3,6 @@
+ int pthread_rwlock_init(pthread_rwlock_t *restrict rw, const pthread_rwlockattr_t *restrict a)
+ {
+ *rw = (pthread_rwlock_t){0};
+- if (a) {
+- }
++ if (a) rw->_rw_shared = a->__attr[0]*128;
+ return 0;
+ }
+diff --git a/src/thread/pthread_rwlock_timedrdlock.c b/src/thread/pthread_rwlock_timedrdlock.c
+index c0c94c9..a2b4d44 100644
+--- a/src/thread/pthread_rwlock_timedrdlock.c
++++ b/src/thread/pthread_rwlock_timedrdlock.c
+@@ -8,7 +8,7 @@ int pthread_rwlock_timedrdlock(pthread_rwlock_t *restrict rw, const struct times
+ t = r | 0x80000000;
+ a_inc(&rw->_rw_waiters);
+ a_cas(&rw->_rw_lock, r, t);
+- r = __timedwait(&rw->_rw_lock, t, CLOCK_REALTIME, at, 0, 0, 0);
++ r = __timedwait(&rw->_rw_lock, t, CLOCK_REALTIME, at, 0, 0, rw->_rw_shared^128);
+ a_dec(&rw->_rw_waiters);
+ if (r && r != EINTR) return r;
+ }
+diff --git a/src/thread/pthread_rwlock_timedwrlock.c b/src/thread/pthread_rwlock_timedwrlock.c
+index 339a167..63a32ec 100644
+--- a/src/thread/pthread_rwlock_timedwrlock.c
++++ b/src/thread/pthread_rwlock_timedwrlock.c
+@@ -8,7 +8,7 @@ int pthread_rwlock_timedwrlock(pthread_rwlock_t *restrict rw, const struct times
+ t = r | 0x80000000;
+ a_inc(&rw->_rw_waiters);
+ a_cas(&rw->_rw_lock, r, t);
+- r = __timedwait(&rw->_rw_lock, t, CLOCK_REALTIME, at, 0, 0, 0);
++ r = __timedwait(&rw->_rw_lock, t, CLOCK_REALTIME, at, 0, 0, rw->_rw_shared^128);
+ a_dec(&rw->_rw_waiters);
+ if (r && r != EINTR) return r;
+ }
+diff --git a/src/thread/pthread_rwlock_unlock.c b/src/thread/pthread_rwlock_unlock.c
+index a6d2085..7b5eec8 100644
+--- a/src/thread/pthread_rwlock_unlock.c
++++ b/src/thread/pthread_rwlock_unlock.c
+@@ -2,7 +2,7 @@
+
+ int pthread_rwlock_unlock(pthread_rwlock_t *rw)
+ {
+- int val, cnt, waiters, new;
++ int val, cnt, waiters, new, priv = rw->_rw_shared^128;
+
+ do {
+ val = rw->_rw_lock;
+@@ -12,7 +12,7 @@ int pthread_rwlock_unlock(pthread_rwlock_t *rw)
+ } while (a_cas(&rw->_rw_lock, val, new) != val);
+
+ if (!new && (waiters || val<0))
+- __wake(&rw->_rw_lock, cnt, 0);
++ __wake(&rw->_rw_lock, cnt, priv);
+
+ return 0;
+ }
+diff --git a/src/thread/sem_init.c b/src/thread/sem_init.c
+index e8e419c..5509243 100644
+--- a/src/thread/sem_init.c
++++ b/src/thread/sem_init.c
+@@ -10,5 +10,6 @@ int sem_init(sem_t *sem, int pshared, unsigned value)
+ }
+ sem->__val[0] = value;
+ sem->__val[1] = 0;
++ sem->__val[2] = pshared ? 0 : 128;
+ return 0;
+ }
+diff --git a/src/thread/sem_post.c b/src/thread/sem_post.c
+index 14a2dfe..31e3293 100644
+--- a/src/thread/sem_post.c
++++ b/src/thread/sem_post.c
+@@ -3,7 +3,7 @@
+
+ int sem_post(sem_t *sem)
+ {
+- int val, waiters;
++ int val, waiters, priv = sem->__val[2];
+ do {
+ val = sem->__val[0];
+ waiters = sem->__val[1];
+@@ -12,6 +12,6 @@ int sem_post(sem_t *sem)
+ return -1;
+ }
+ } while (a_cas(sem->__val, val, val+1+(val<0)) != val);
+- if (val<0 || waiters) __wake(sem->__val, 1, 0);
++ if (val<0 || waiters) __wake(sem->__val, 1, priv);
+ return 0;
+ }
+diff --git a/src/thread/sem_timedwait.c b/src/thread/sem_timedwait.c
+index 6d0d011..bfcb6dc 100644
+--- a/src/thread/sem_timedwait.c
++++ b/src/thread/sem_timedwait.c
+@@ -12,7 +12,7 @@ int sem_timedwait(sem_t *restrict sem, const struct timespec *restrict at)
+ int r;
+ a_inc(sem->__val+1);
+ a_cas(sem->__val, 0, -1);
+- r = __timedwait(sem->__val, -1, CLOCK_REALTIME, at, cleanup, sem->__val+1, 0);
++ r = __timedwait(sem->__val, -1, CLOCK_REALTIME, at, cleanup, sem->__val+1, sem->__val[2]);
+ a_dec(sem->__val+1);
+ if (r) {
+ errno = r;
diff --git a/main/musl/APKBUILD b/main/musl/APKBUILD
index 806e37c84..925f01742 100644
--- a/main/musl/APKBUILD
+++ b/main/musl/APKBUILD
@@ -2,7 +2,7 @@
# Maintainer: Timo Teräs <timo.teras@iki.fi>
pkgname=musl
pkgver=1.1.4
-pkgrel=3
+pkgrel=4
pkgdesc="the musl c library (libc) implementation"
url="http://www.musl-libc.org/"
arch="all"
@@ -14,6 +14,7 @@ install="$pkgname.post-upgrade"
subpackages="$pkgname-dev $pkgname-utils $pkgname-dbg"
source="http://www.musl-libc.org/releases/musl-$pkgver.tar.gz
0001-v1.1.4-to-d86af2a0.patch
+ 0002-d86af2a0-to-4992ace9.patch
1001-add-basic-dns-record-parsing-functions.patch
1002-fix-handling-of-zero-length-domain-names-in-dn_expan.patch
1003-remove-ulimit-fiddling-from-setxid.patch
@@ -121,6 +122,7 @@ utils() {
md5sums="f18f3bdbe088438cd64a5313c19a7312 musl-1.1.4.tar.gz
7e6f4c4e0992f73d61963959d7fbbaa5 0001-v1.1.4-to-d86af2a0.patch
+04eef5b44c0b56b79055340bee1febc2 0002-d86af2a0-to-4992ace9.patch
2371eb1ce057fcb709a0e6a81f0d356c 1001-add-basic-dns-record-parsing-functions.patch
4b0771addf78eb0c4f0210792c99335a 1002-fix-handling-of-zero-length-domain-names-in-dn_expan.patch
71b2a4dcc39c436a6b89173943424043 1003-remove-ulimit-fiddling-from-setxid.patch
@@ -132,6 +134,7 @@ md5sums="f18f3bdbe088438cd64a5313c19a7312 musl-1.1.4.tar.gz
45f92f8d59cf84d765de698a9578dbf4 iconv.c"
sha256sums="658c65ad3c3a9b281a96c5281e75720c758d91fcaae35ab987f2fdfb4f88f5cd musl-1.1.4.tar.gz
2966fe530dfda4affca61375d16a4d03140ddf3beb39df90b9f5f0b10558eb5d 0001-v1.1.4-to-d86af2a0.patch
+c7521464f3096befb5b44d303819e9169a43a6a5a3c93566ac1cdf523a6a389d 0002-d86af2a0-to-4992ace9.patch
75053a31f6b84a64846d92c0ec631c76d7f747a9c0dc92a6dc1aa1bddfe2ea76 1001-add-basic-dns-record-parsing-functions.patch
65129391cbc63cda4387f6dae13cc91b346cf5d9a936494dbc4d4a7687af49a0 1002-fix-handling-of-zero-length-domain-names-in-dn_expan.patch
fb542c2bd5081ff2f601c519edb3dac8f54ca5c888f44bc6cfb84e6565472025 1003-remove-ulimit-fiddling-from-setxid.patch
@@ -143,6 +146,7 @@ d87d0cbb3690ae2c5d8cc218349fd8278b93855dd625deaf7ae50e320aad247c getconf.c
f79a2930a2e5bb0624321589edf8b889d1e9b603e01e6b7ae214616605b3fdd7 iconv.c"
sha512sums="a46fb1db23f518beaa959e9bebcb3bf0574e583c197792d30dcd52b3974e3c285594984207043d317859fc5552f1d303a5686e9fbe3b8825df6346de7f917f9f musl-1.1.4.tar.gz
6ef512bd4c05ae3a24493c4cffeac71953bb7383aaf88d2012f95b1e13dfa5f09ad3fc24b7f0d08e0d3788bcdf7195a1a8e639ec56b2ac01551a403398ac003e 0001-v1.1.4-to-d86af2a0.patch
+0e892a0d0e2abf09cb52d27759769a4cdd39ebd87fb1af89f502da00a4c9453309291aeb69862d60d88a8d0a0c2517aabcc92b50214d67279b12113b3c5a0157 0002-d86af2a0-to-4992ace9.patch
5b8ffa0a50419581adbf6ce2dae5797774022551c6331fa5aa2ff13635eb72b74eedd8a92cb478d45d73e1956af2f588669681ac414f3a255abd4d8ba8579448 1001-add-basic-dns-record-parsing-functions.patch
3ffe3eb575ddc0f17abb952a1effd1545fd8d81c019b2f700f74d811f5c076ae20c332df755866c74dfffa9909e7900e667d3d73992d0ca85279056ce623fee3 1002-fix-handling-of-zero-length-domain-names-in-dn_expan.patch
dae010b45419fcab64410568466f659cdc874e63113025e2cbc2fbab047b470fec23851ecbef08886505924482a069caf37c16b483b6922535fbd31832f1c4a3 1003-remove-ulimit-fiddling-from-setxid.patch