summaryrefslogtreecommitdiffstats
path: root/main/musl
diff options
context:
space:
mode:
authorTimo Teräs <timo.teras@iki.fi>2014-10-14 21:50:35 +0300
committerTimo Teräs <timo.teras@iki.fi>2014-10-14 21:52:10 +0300
commitf5b047ec81b9141b6bd1f2c808e63fb459b59c20 (patch)
treeb43d5e37e77d663b805d2ec97a683099d8d6b6d2 /main/musl
parent1b45ba234d485dcda04d8203edd54cfbd1c5cf9b (diff)
downloadaports-f5b047ec81b9141b6bd1f2c808e63fb459b59c20.tar.bz2
aports-f5b047ec81b9141b6bd1f2c808e63fb459b59c20.tar.xz
main/musl: upgrade to 1.1.5
Diffstat (limited to 'main/musl')
-rw-r--r--main/musl/0001-v1.1.4-to-d86af2a0.patch137
-rw-r--r--main/musl/0002-d86af2a0-to-4992ace9.patch1083
-rw-r--r--main/musl/0003-4992ace9-to-6e2bb7ac.patch745
-rw-r--r--main/musl/0004-6e2bb7ac-to-4674809b.patch68
-rw-r--r--main/musl/0005-4674809b-to-3e936ce8.patch3400
-rw-r--r--main/musl/1002-check-lockcount-in-funlockfile.patch17
-rw-r--r--main/musl/APKBUILD35
7 files changed, 5 insertions, 5480 deletions
diff --git a/main/musl/0001-v1.1.4-to-d86af2a0.patch b/main/musl/0001-v1.1.4-to-d86af2a0.patch
deleted file mode 100644
index e29d0ae98..000000000
--- a/main/musl/0001-v1.1.4-to-d86af2a0.patch
+++ /dev/null
@@ -1,137 +0,0 @@
-diff --git a/include/ctype.h b/include/ctype.h
-index 8f0d168..a6f44df 100644
---- a/include/ctype.h
-+++ b/include/ctype.h
-@@ -22,13 +22,18 @@ int isxdigit(int);
- int tolower(int);
- int toupper(int);
-
-+static __inline int __isspace(int _c)
-+{
-+ return _c == ' ' || (unsigned)_c-'\t' < 5;
-+}
-+
- #define isalpha(a) ((((unsigned)(a)|32)-'a') < 26)
- #define isdigit(a) (((unsigned)(a)-'0') < 10)
- #define islower(a) (((unsigned)(a)-'a') < 26)
- #define isupper(a) (((unsigned)(a)-'A') < 26)
- #define isprint(a) (((unsigned)(a)-0x20) < 0x5f)
- #define isgraph(a) (((unsigned)(a)-0x21) < 0x5e)
--
-+#define isspace(a) __isspace(a)
-
-
- #if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) \
-diff --git a/include/sched.h b/include/sched.h
-index 4394b64..3e34a72 100644
---- a/include/sched.h
-+++ b/include/sched.h
-@@ -123,7 +123,7 @@ __CPU_op_func_S(XOR, ^)
- #define CPU_XOR(d,s1,s2) CPU_XOR_S(sizeof(cpu_set_t),d,s1,s2)
- #define CPU_COUNT(set) CPU_COUNT_S(sizeof(cpu_set_t),set)
- #define CPU_ZERO(set) CPU_ZERO_S(sizeof(cpu_set_t),set)
--#define CPU_EQUAL(set) CPU_EQUAL_S(sizeof(cpu_set_t),set)
-+#define CPU_EQUAL(s1,s2) CPU_EQUAL_S(sizeof(cpu_set_t),s1,s2)
-
- #endif
-
-diff --git a/include/stdlib.h b/include/stdlib.h
-index f034c6e..db569d9 100644
---- a/include/stdlib.h
-+++ b/include/stdlib.h
-@@ -144,12 +144,12 @@ int mkostemps (char *, int, int);
- void *valloc (size_t);
- void *memalign(size_t, size_t);
- int getloadavg(double *, int);
-+int clearenv(void);
- #define WCOREDUMP(s) ((s) & 0x80)
- #define WIFCONTINUED(s) ((s) == 0xffff)
- #endif
-
- #ifdef _GNU_SOURCE
--int clearenv(void);
- int ptsname_r(int, char *, size_t);
- char *ecvt(double, int, int *, int *);
- char *fcvt(double, int, int *, int *);
-diff --git a/src/ctype/isspace.c b/src/ctype/isspace.c
-index 7dff20d..231e907 100644
---- a/src/ctype/isspace.c
-+++ b/src/ctype/isspace.c
-@@ -1,5 +1,6 @@
- #include <ctype.h>
- #include "libc.h"
-+#undef isspace
-
- int isspace(int c)
- {
-diff --git a/src/env/__init_tls.c b/src/env/__init_tls.c
-index 6cca968..ddc2a73 100644
---- a/src/env/__init_tls.c
-+++ b/src/env/__init_tls.c
-@@ -91,12 +91,11 @@ void __init_tls(size_t *aux)
- libc.tls_size = 2*sizeof(void *)+T.size+T.align+sizeof(struct pthread);
-
- if (libc.tls_size > sizeof builtin_tls) {
-+#ifndef SYS_mmap2
-+#define SYS_mmap2 SYS_mmap
-+#endif
- mem = (void *)__syscall(
--#ifdef SYS_mmap2
- SYS_mmap2,
--#else
-- SYS_mmap,
--#endif
- 0, libc.tls_size, PROT_READ|PROT_WRITE,
- MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
- /* -4095...-1 cast to void * will crash on dereference anyway,
-diff --git a/src/ldso/dynlink.c b/src/ldso/dynlink.c
-index 12f14f7..c90fe99 100644
---- a/src/ldso/dynlink.c
-+++ b/src/ldso/dynlink.c
-@@ -1603,10 +1603,14 @@ static int invalid_dso_handle(void *h)
- }
- void *dlopen(const char *file, int mode)
- {
-+ strcpy(errbuf, "Dynamic loading not supported");
-+ errflag = 1;
- return 0;
- }
- void *__dlsym(void *restrict p, const char *restrict s, void *restrict ra)
- {
-+ errflag = 1;
-+ snprintf(errbuf, sizeof errbuf, "Symbol not found: %s", s);
- return 0;
- }
- int __dladdr (const void *addr, Dl_info *info)
-diff --git a/src/locale/pleval.c b/src/locale/pleval.c
-index 961dabc..d60058d 100644
---- a/src/locale/pleval.c
-+++ b/src/locale/pleval.c
-@@ -28,14 +28,6 @@ struct st {
- int op;
- };
-
--/* TODO: this should go into ctypes.h */
--#undef isspace
--#define isspace(a) __isspace(a)
--static __inline int __isspace(int _c)
--{
-- return _c == ' ' || (unsigned)_c-'\t' < 5;
--}
--
- static const char *skipspace(const char *s)
- {
- while (isspace(*s)) s++;
-diff --git a/src/misc/mntent.c b/src/misc/mntent.c
-index 3eafba5..a16d652 100644
---- a/src/misc/mntent.c
-+++ b/src/misc/mntent.c
-@@ -10,7 +10,7 @@ FILE *setmntent(const char *name, const char *mode)
-
- int endmntent(FILE *f)
- {
-- fclose(f);
-+ if (f) fclose(f);
- return 1;
- }
-
diff --git a/main/musl/0002-d86af2a0-to-4992ace9.patch b/main/musl/0002-d86af2a0-to-4992ace9.patch
deleted file mode 100644
index ed0eb6522..000000000
--- a/main/musl/0002-d86af2a0-to-4992ace9.patch
+++ /dev/null
@@ -1,1083 +0,0 @@
-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/0003-4992ace9-to-6e2bb7ac.patch b/main/musl/0003-4992ace9-to-6e2bb7ac.patch
deleted file mode 100644
index f5c9b40b6..000000000
--- a/main/musl/0003-4992ace9-to-6e2bb7ac.patch
+++ /dev/null
@@ -1,745 +0,0 @@
-diff --git a/arch/arm/atomic.h b/arch/arm/atomic.h
-index 302e6d8..738f528 100644
---- a/arch/arm/atomic.h
-+++ b/arch/arm/atomic.h
-@@ -103,6 +103,7 @@ static inline void a_store(volatile int *p, int x)
-
- static inline void a_spin()
- {
-+ __k_cas(0, 0, &(int){0});
- }
-
- static inline void a_crash()
-diff --git a/arch/arm/bits/alltypes.h.in b/arch/arm/bits/alltypes.h.in
-index 0d750cc..183c4c4 100644
---- a/arch/arm/bits/alltypes.h.in
-+++ b/arch/arm/bits/alltypes.h.in
-@@ -13,6 +13,8 @@ TYPEDEF unsigned wint_t;
- TYPEDEF float float_t;
- TYPEDEF double double_t;
-
-+TYPEDEF struct { long long __ll; long double __ld; } max_align_t;
-+
- TYPEDEF long time_t;
- TYPEDEF long suseconds_t;
-
-diff --git a/arch/i386/bits/alltypes.h.in b/arch/i386/bits/alltypes.h.in
-index 502c882..8ba8f6f 100644
---- a/arch/i386/bits/alltypes.h.in
-+++ b/arch/i386/bits/alltypes.h.in
-@@ -27,6 +27,8 @@ TYPEDEF long double float_t;
- TYPEDEF long double double_t;
- #endif
-
-+TYPEDEF struct { _Alignas(8) long long __ll; long double __ld; } max_align_t;
-+
- TYPEDEF long time_t;
- TYPEDEF long suseconds_t;
-
-diff --git a/arch/microblaze/atomic.h b/arch/microblaze/atomic.h
-index 96265fe..abb79b5 100644
---- a/arch/microblaze/atomic.h
-+++ b/arch/microblaze/atomic.h
-@@ -97,6 +97,7 @@ static inline void a_store(volatile int *p, int x)
-
- static inline void a_spin()
- {
-+ a_cas(&(int){0}, 0, 0);
- }
-
- static inline void a_crash()
-diff --git a/arch/microblaze/bits/alltypes.h.in b/arch/microblaze/bits/alltypes.h.in
-index 4657d14..a03e1b8 100644
---- a/arch/microblaze/bits/alltypes.h.in
-+++ b/arch/microblaze/bits/alltypes.h.in
-@@ -13,6 +13,8 @@ TYPEDEF unsigned wint_t;
- TYPEDEF float float_t;
- TYPEDEF double double_t;
-
-+TYPEDEF struct { long long __ll; long double __ld; } max_align_t;
-+
- TYPEDEF long time_t;
- TYPEDEF long suseconds_t;
-
-diff --git a/arch/mips/atomic.h b/arch/mips/atomic.h
-index 3ec0358..cc5bf49 100644
---- a/arch/mips/atomic.h
-+++ b/arch/mips/atomic.h
-@@ -137,6 +137,7 @@ static inline void a_store(volatile int *p, int x)
-
- static inline void a_spin()
- {
-+ a_cas(&(int){0}, 0, 0);
- }
-
- static inline void a_crash()
-diff --git a/arch/mips/bits/alltypes.h.in b/arch/mips/bits/alltypes.h.in
-index 4657d14..a03e1b8 100644
---- a/arch/mips/bits/alltypes.h.in
-+++ b/arch/mips/bits/alltypes.h.in
-@@ -13,6 +13,8 @@ TYPEDEF unsigned wint_t;
- TYPEDEF float float_t;
- TYPEDEF double double_t;
-
-+TYPEDEF struct { long long __ll; long double __ld; } max_align_t;
-+
- TYPEDEF long time_t;
- TYPEDEF long suseconds_t;
-
-diff --git a/arch/or1k/atomic.h b/arch/or1k/atomic.h
-index 5b0411b..f9e6981 100644
---- a/arch/or1k/atomic.h
-+++ b/arch/or1k/atomic.h
-@@ -74,6 +74,7 @@ static inline void a_store(volatile int *p, int x)
-
- static inline void a_spin()
- {
-+ a_cas(&(int){0}, 0, 0);
- }
-
- static inline void a_crash()
-diff --git a/arch/or1k/bits/alltypes.h.in b/arch/or1k/bits/alltypes.h.in
-index 0d750cc..183c4c4 100644
---- a/arch/or1k/bits/alltypes.h.in
-+++ b/arch/or1k/bits/alltypes.h.in
-@@ -13,6 +13,8 @@ TYPEDEF unsigned wint_t;
- TYPEDEF float float_t;
- TYPEDEF double double_t;
-
-+TYPEDEF struct { long long __ll; long double __ld; } max_align_t;
-+
- TYPEDEF long time_t;
- TYPEDEF long suseconds_t;
-
-diff --git a/arch/powerpc/atomic.h b/arch/powerpc/atomic.h
-index 1044886..1c50361 100644
---- a/arch/powerpc/atomic.h
-+++ b/arch/powerpc/atomic.h
-@@ -80,6 +80,7 @@ static inline void a_store(volatile int *p, int x)
-
- static inline void a_spin()
- {
-+ a_cas(&(int){0}, 0, 0);
- }
-
- static inline void a_crash()
-diff --git a/arch/powerpc/bits/alltypes.h.in b/arch/powerpc/bits/alltypes.h.in
-index 378124c..ee7f137 100644
---- a/arch/powerpc/bits/alltypes.h.in
-+++ b/arch/powerpc/bits/alltypes.h.in
-@@ -13,6 +13,8 @@ TYPEDEF unsigned wint_t;
- TYPEDEF float float_t;
- TYPEDEF double double_t;
-
-+TYPEDEF struct { long long __ll; long double __ld; } max_align_t;
-+
- TYPEDEF long time_t;
- TYPEDEF long suseconds_t;
-
-diff --git a/arch/sh/atomic.h b/arch/sh/atomic.h
-index 93ab54f..b95bbff 100644
---- a/arch/sh/atomic.h
-+++ b/arch/sh/atomic.h
-@@ -53,6 +53,7 @@ static inline void a_dec(volatile int *x)
-
- static inline void a_spin()
- {
-+ a_cas(&(int){0}, 0, 0);
- }
-
- static inline void a_crash()
-diff --git a/arch/sh/bits/alltypes.h.in b/arch/sh/bits/alltypes.h.in
-index 378124c..ee7f137 100644
---- a/arch/sh/bits/alltypes.h.in
-+++ b/arch/sh/bits/alltypes.h.in
-@@ -13,6 +13,8 @@ TYPEDEF unsigned wint_t;
- TYPEDEF float float_t;
- TYPEDEF double double_t;
-
-+TYPEDEF struct { long long __ll; long double __ld; } max_align_t;
-+
- TYPEDEF long time_t;
- TYPEDEF long suseconds_t;
-
-diff --git a/arch/x32/bits/alltypes.h.in b/arch/x32/bits/alltypes.h.in
-index 8930efa..8e396c9 100644
---- a/arch/x32/bits/alltypes.h.in
-+++ b/arch/x32/bits/alltypes.h.in
-@@ -18,6 +18,8 @@ TYPEDEF float float_t;
- TYPEDEF double double_t;
- #endif
-
-+TYPEDEF struct { long long __ll; long double __ld; } max_align_t;
-+
- TYPEDEF long long time_t;
- TYPEDEF long long suseconds_t;
-
-diff --git a/arch/x86_64/bits/alltypes.h.in b/arch/x86_64/bits/alltypes.h.in
-index 34b7d6a..7b4f3e7 100644
---- a/arch/x86_64/bits/alltypes.h.in
-+++ b/arch/x86_64/bits/alltypes.h.in
-@@ -18,6 +18,8 @@ TYPEDEF float float_t;
- TYPEDEF double double_t;
- #endif
-
-+TYPEDEF struct { long long __ll; long double __ld; } max_align_t;
-+
- TYPEDEF long time_t;
- TYPEDEF long suseconds_t;
-
-diff --git a/include/assert.h b/include/assert.h
-index ab745db..1ee02a4 100644
---- a/include/assert.h
-+++ b/include/assert.h
-@@ -8,6 +8,10 @@
- #define assert(x) ((void)((x) || (__assert_fail(#x, __FILE__, __LINE__, __func__),0)))
- #endif
-
-+#ifndef __cplusplus
-+#define static_assert _Static_assert
-+#endif
-+
- #ifdef __cplusplus
- extern "C" {
- #endif
-diff --git a/include/float.h b/include/float.h
-index 2b2ad39..161e167 100644
---- a/include/float.h
-+++ b/include/float.h
-@@ -11,8 +11,10 @@
- #define FLT_MANT_DIG 24
- #define FLT_MIN_EXP (-125)
- #define FLT_MAX_EXP 128
-+#define FLT_HAS_SUBNORM 1
-
- #define FLT_DIG 6
-+#define FLT_DECIMAL_DIG 9
- #define FLT_MIN_10_EXP (-37)
- #define FLT_MAX_10_EXP 38
-
-@@ -24,11 +26,16 @@
- #define DBL_MANT_DIG 53
- #define DBL_MIN_EXP (-1021)
- #define DBL_MAX_EXP 1024
-+#define DBL_HAS_SUBNORM 1
-
- #define DBL_DIG 15
-+#define DBL_DECIMAL_DIG 17
- #define DBL_MIN_10_EXP (-307)
- #define DBL_MAX_10_EXP 308
-
-+#define LDBL_HAS_SUBNORM 1
-+#define LDBL_DECIMAL_DIG DECIMAL_DIG
-+
- #include <bits/float.h>
-
- #endif
-diff --git a/include/malloc.h b/include/malloc.h
-index e69de29..35f8b19 100644
---- a/include/malloc.h
-+++ b/include/malloc.h
-@@ -0,0 +1,25 @@
-+#ifndef _MALLOC_H
-+#define _MALLOC_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#define __NEED_size_t
-+
-+#include <bits/alltypes.h>
-+
-+void *malloc (size_t);
-+void *calloc (size_t, size_t);
-+void *realloc (void *, size_t);
-+void free (void *);
-+void *valloc (size_t);
-+void *memalign(size_t, size_t);
-+
-+size_t malloc_usable_size(void *);
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif
-diff --git a/include/stdalign.h b/include/stdalign.h
-index b6e50ae..2cc94be 100644
---- a/include/stdalign.h
-+++ b/include/stdalign.h
-@@ -1,6 +1,8 @@
- #ifndef _STDALIGN_H
- #define _STDALIGN_H
-
-+#ifndef __cplusplus
-+
- /* this whole header only works in C11 or with compiler extensions */
- #if __STDC_VERSION__ < 201112L && defined( __GNUC__)
- #define _Alignas(t) __attribute__((__aligned__(t)))
-@@ -9,6 +11,9 @@
-
- #define alignas _Alignas
- #define alignof _Alignof
-+
-+#endif
-+
- #define __alignas_is_defined 1
- #define __alignof_is_defined 1
-
-diff --git a/include/stddef.h b/include/stddef.h
-index 0a32919..bd75385 100644
---- a/include/stddef.h
-+++ b/include/stddef.h
-@@ -10,6 +10,9 @@
- #define __NEED_ptrdiff_t
- #define __NEED_size_t
- #define __NEED_wchar_t
-+#if __STDC_VERSION__ >= 201112L || __cplusplus >= 201103L
-+#define __NEED_max_align_t
-+#endif
-
- #include <bits/alltypes.h>
-
-diff --git a/include/stdnoreturn.h b/include/stdnoreturn.h
-index 60d924a..5c6aeeb 100644
---- a/include/stdnoreturn.h
-+++ b/include/stdnoreturn.h
-@@ -1,5 +1,7 @@
- #ifndef _STDNORETURN_H
- #define _STDNORETURN_H
-+#ifndef __cplusplus
- #include <features.h>
- #define noreturn _Noreturn
- #endif
-+#endif
-diff --git a/src/internal/pthread_impl.h b/src/internal/pthread_impl.h
-index 2d090f8..74c62cc 100644
---- a/src/internal/pthread_impl.h
-+++ b/src/internal/pthread_impl.h
-@@ -44,6 +44,7 @@ struct pthread {
- int exitlock[2];
- int startlock[2];
- unsigned long sigmask[_NSIG/8/sizeof(long)];
-+ void *stdio_locks;
- };
-
- struct __timer {
-@@ -112,7 +113,7 @@ 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|priv, cnt) != -ENOSYS ||
- __syscall(SYS_futex, addr, FUTEX_WAKE, cnt);
- }
-
-diff --git a/src/internal/stdio_impl.h b/src/internal/stdio_impl.h
-index 79be9fd..d659522 100644
---- a/src/internal/stdio_impl.h
-+++ b/src/internal/stdio_impl.h
-@@ -46,6 +46,7 @@ struct _IO_FILE {
- void *mustbezero_2;
- unsigned char *shend;
- off_t shlim, shcnt;
-+ FILE *prev_locked, *next_locked;
- };
-
- size_t __stdio_read(FILE *, unsigned char *, size_t);
-diff --git a/src/malloc/malloc_usable_size.c b/src/malloc/malloc_usable_size.c
-new file mode 100644
-index 0000000..8cccd9d
---- /dev/null
-+++ b/src/malloc/malloc_usable_size.c
-@@ -0,0 +1,17 @@
-+#include <malloc.h>
-+
-+void *(*const __realloc_dep)(void *, size_t) = realloc;
-+
-+struct chunk {
-+ size_t psize, csize;
-+ struct chunk *next, *prev;
-+};
-+
-+#define OVERHEAD (2*sizeof(size_t))
-+#define CHUNK_SIZE(c) ((c)->csize & -2)
-+#define MEM_TO_CHUNK(p) (struct chunk *)((char *)(p) - OVERHEAD)
-+
-+size_t malloc_usable_size(void *p)
-+{
-+ return CHUNK_SIZE(MEM_TO_CHUNK(p)) - OVERHEAD;
-+}
-diff --git a/src/network/dn_expand.c b/src/network/dn_expand.c
-index 849df19..d9b3393 100644
---- a/src/network/dn_expand.c
-+++ b/src/network/dn_expand.c
-@@ -4,11 +4,13 @@
- int __dn_expand(const unsigned char *base, const unsigned char *end, const unsigned char *src, char *dest, int space)
- {
- const unsigned char *p = src;
-- char *dend = dest + (space > 254 ? 254 : space);
-+ char *dend, *dbegin = dest;
- int len = -1, i, j;
-- if (p==end || !*p) return -1;
-+ if (p==end || space <= 0) return -1;
-+ dend = dest + (space > 254 ? 254 : space);
- /* detect reference loop using an iteration counter */
- for (i=0; i < end-base; i+=2) {
-+ /* loop invariants: p<end, dest<dend */
- if (*p & 0xc0) {
- if (p+1==end) return -1;
- j = ((p[0] & 0x3f) << 8) | p[1];
-@@ -16,11 +18,12 @@ int __dn_expand(const unsigned char *base, const unsigned char *end, const unsig
- if (j >= end-base) return -1;
- p = base+j;
- } else if (*p) {
-- j = *p+1;
-- if (j>=end-p || j>dend-dest) return -1;
-- while (--j) *dest++ = *++p;
-- *dest++ = *++p ? '.' : 0;
-+ if (dest != dbegin) *dest++ = '.';
-+ j = *p++;
-+ if (j >= end-p || j >= dend-dest) return -1;
-+ while (j--) *dest++ = *p++;
- } else {
-+ *dest = 0;
- if (len < 0) len = p+1-src;
- return len;
- }
-diff --git a/src/stdio/fclose.c b/src/stdio/fclose.c
-index 38e8a1e..317b3c9 100644
---- a/src/stdio/fclose.c
-+++ b/src/stdio/fclose.c
-@@ -1,4 +1,8 @@
- #include "stdio_impl.h"
-+#include "libc.h"
-+
-+static void dummy(FILE *f) { }
-+weak_alias(dummy, __unlist_locked_file);
-
- int fclose(FILE *f)
- {
-@@ -7,6 +11,8 @@ int fclose(FILE *f)
-
- FFINALLOCK(f);
-
-+ __unlist_locked_file(f);
-+
- if (!(perm = f->flags & F_PERM)) {
- OFLLOCK();
- if (f->prev) f->prev->next = f->next;
-diff --git a/src/stdio/fgets.c b/src/stdio/fgets.c
-index b01a418..d3f9819 100644
---- a/src/stdio/fgets.c
-+++ b/src/stdio/fgets.c
-@@ -10,14 +10,16 @@ char *fgets(char *restrict s, int n, FILE *restrict f)
- size_t k;
- int c;
-
-+ FLOCK(f);
-+
- if (n--<=1) {
-+ f->mode |= f->mode-1;
-+ FUNLOCK(f);
- if (n) return 0;
- *s = 0;
- return s;
- }
-
-- FLOCK(f);
--
- while (n) {
- z = memchr(f->rpos, '\n', f->rend - f->rpos);
- k = z ? z - f->rpos + 1 : f->rend - f->rpos;
-@@ -34,7 +36,7 @@ char *fgets(char *restrict s, int n, FILE *restrict f)
- n--;
- if ((*p++ = c) == '\n') break;
- }
-- *p = 0;
-+ if (s) *p = 0;
-
- FUNLOCK(f);
-
-diff --git a/src/stdio/fputs.c b/src/stdio/fputs.c
-index 1112b19..4737f44 100644
---- a/src/stdio/fputs.c
-+++ b/src/stdio/fputs.c
-@@ -3,9 +3,7 @@
-
- int fputs(const char *restrict s, FILE *restrict f)
- {
-- size_t l = strlen(s);
-- if (!l) return 0;
-- return (int)fwrite(s, l, 1, f) - 1;
-+ return (int)fwrite(s, strlen(s), 1, f) - 1;
- }
-
- weak_alias(fputs, fputs_unlocked);
-diff --git a/src/stdio/fread.c b/src/stdio/fread.c
-index c461256..33a65f5 100644
---- a/src/stdio/fread.c
-+++ b/src/stdio/fread.c
-@@ -8,11 +8,10 @@ size_t fread(void *restrict destv, size_t size, size_t nmemb, FILE *restrict f)
- unsigned char *dest = destv;
- size_t len = size*nmemb, l = len, k;
-
-- /* Never touch the file if length is zero.. */
-- if (!l) return 0;
--
- FLOCK(f);
-
-+ f->mode |= f->mode-1;
-+
- if (f->rend - f->rpos > 0) {
- /* First exhaust the buffer. */
- k = MIN(f->rend - f->rpos, l);
-diff --git a/src/stdio/ftrylockfile.c b/src/stdio/ftrylockfile.c
-index 56cccaf..6f9a4b8 100644
---- a/src/stdio/ftrylockfile.c
-+++ b/src/stdio/ftrylockfile.c
-@@ -2,9 +2,26 @@
- #include "pthread_impl.h"
- #include <limits.h>
-
-+void __do_orphaned_stdio_locks()
-+{
-+ FILE *f;
-+ for (f=__pthread_self()->stdio_locks; f; f=f->next_locked)
-+ a_store(&f->lock, 0x40000000);
-+}
-+
-+void __unlist_locked_file(FILE *f)
-+{
-+ if (f->lockcount) {
-+ if (f->next_locked) f->next_locked->prev_locked = f->prev_locked;
-+ if (f->prev_locked) f->prev_locked->next_locked = f->next_locked;
-+ else __pthread_self()->stdio_locks = f->next_locked;
-+ }
-+}
-+
- int ftrylockfile(FILE *f)
- {
-- int tid = __pthread_self()->tid;
-+ pthread_t self = __pthread_self();
-+ int tid = self->tid;
- if (f->lock == tid) {
- if (f->lockcount == LONG_MAX)
- return -1;
-@@ -15,5 +32,8 @@ int ftrylockfile(FILE *f)
- if (f->lock || a_cas(&f->lock, 0, tid))
- return -1;
- f->lockcount = 1;
-+ f->prev_locked = 0;
-+ f->next_locked = self->stdio_locks;
-+ self->stdio_locks = f;
- return 0;
- }
-diff --git a/src/stdio/funlockfile.c b/src/stdio/funlockfile.c
-index f8a2a07..30a07ef 100644
---- a/src/stdio/funlockfile.c
-+++ b/src/stdio/funlockfile.c
-@@ -1,7 +1,15 @@
- #include "stdio_impl.h"
- #include "pthread_impl.h"
-
-+void __unlist_locked_file(FILE *);
-+
- void funlockfile(FILE *f)
- {
-- if (!--f->lockcount) __unlockfile(f);
-+ if (f->lockcount == 1) {
-+ __unlist_locked_file(f);
-+ f->lockcount = 0;
-+ __unlockfile(f);
-+ } else {
-+ f->lockcount--;
-+ }
- }
-diff --git a/src/stdio/fwrite.c b/src/stdio/fwrite.c
-index d5f6542..81ec271 100644
---- a/src/stdio/fwrite.c
-+++ b/src/stdio/fwrite.c
-@@ -28,7 +28,6 @@ size_t __fwritex(const unsigned char *restrict s, size_t l, FILE *restrict f)
- size_t fwrite(const void *restrict src, size_t size, size_t nmemb, FILE *restrict f)
- {
- size_t k, l = size*nmemb;
-- if (!l) return l;
- FLOCK(f);
- k = __fwritex(src, l, f);
- FUNLOCK(f);
-diff --git a/src/thread/__timedwait.c b/src/thread/__timedwait.c
-index 39eb996..d6f1233 100644
---- a/src/thread/__timedwait.c
-+++ b/src/thread/__timedwait.c
-@@ -29,7 +29,7 @@ int __timedwait(volatile int *addr, int val,
- pthread_cleanup_push(cleanup, arg);
-
- 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 == ENOSYS) r = -__syscall_cp(SYS_futex, addr, FUTEX_WAIT, val, top);
- if (r != EINTR && r != ETIMEDOUT) r = 0;
-
- pthread_cleanup_pop(0);
-diff --git a/src/thread/__wait.c b/src/thread/__wait.c
-index ec1e820..01ee598 100644
---- a/src/thread/__wait.c
-+++ b/src/thread/__wait.c
-@@ -2,15 +2,15 @@
-
- void __wait(volatile int *addr, volatile int *waiters, int val, int priv)
- {
-- int spins=10000;
-+ int spins=100;
- if (priv) priv = 128;
-- while (spins--) {
-+ while (spins-- && (!waiters || !*waiters)) {
- if (*addr==val) a_spin();
- else return;
- }
- if (waiters) a_inc(waiters);
- while (*addr==val) {
-- __syscall(SYS_futex, addr, FUTEX_WAIT|priv, val, 0) != -EINVAL
-+ __syscall(SYS_futex, addr, FUTEX_WAIT|priv, val, 0) != -ENOSYS
- || __syscall(SYS_futex, addr, FUTEX_WAIT, val, 0);
- }
- if (waiters) a_dec(waiters);
-diff --git a/src/thread/pthread_barrier_wait.c b/src/thread/pthread_barrier_wait.c
-index 6b329c9..e15abb8 100644
---- a/src/thread/pthread_barrier_wait.c
-+++ b/src/thread/pthread_barrier_wait.c
-@@ -79,7 +79,7 @@ int pthread_barrier_wait(pthread_barrier_t *b)
- /* First thread to enter the barrier becomes the "instance owner" */
- if (!inst) {
- struct instance new_inst = { 0 };
-- int spins = 10000;
-+ int spins = 200;
- b->_b_inst = inst = &new_inst;
- a_store(&b->_b_lock, 0);
- if (b->_b_waiters) __wake(&b->_b_lock, 1, 1);
-@@ -87,7 +87,7 @@ 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|128,1,0) != -EINTR
-+ __syscall(SYS_futex,&inst->finished,FUTEX_WAIT|128,1,0) != -ENOSYS
- || __syscall(SYS_futex,&inst->finished,FUTEX_WAIT,1,0);
- return PTHREAD_BARRIER_SERIAL_THREAD;
- }
-diff --git a/src/thread/pthread_cond_timedwait.c b/src/thread/pthread_cond_timedwait.c
-index c5cf66c..2d192b0 100644
---- a/src/thread/pthread_cond_timedwait.c
-+++ b/src/thread/pthread_cond_timedwait.c
-@@ -52,7 +52,7 @@ 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
-+ else __syscall(SYS_futex, l, FUTEX_REQUEUE|128, 0, 1, r) != -ENOSYS
- || __syscall(SYS_futex, l, FUTEX_REQUEUE, 0, 1, r);
- }
-
-diff --git a/src/thread/pthread_create.c b/src/thread/pthread_create.c
-index c8c117b..e441bda 100644
---- a/src/thread/pthread_create.c
-+++ b/src/thread/pthread_create.c
-@@ -3,6 +3,7 @@
- #include "stdio_impl.h"
- #include "libc.h"
- #include <sys/mman.h>
-+#include <string.h>
-
- static void dummy_0()
- {
-@@ -11,6 +12,7 @@ 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);
-+weak_alias(dummy_0, __do_orphaned_stdio_locks);
-
- _Noreturn void pthread_exit(void *result)
- {
-@@ -65,6 +67,7 @@ _Noreturn void pthread_exit(void *result)
- }
-
- __do_private_robust_list();
-+ __do_orphaned_stdio_locks();
-
- if (self->detached && self->map_base) {
- /* Detached threads must avoid the kernel clear_child_tid
-@@ -175,6 +178,7 @@ int pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict attrp
- if (need < size/8 && need < 2048) {
- tsd = stack - __pthread_tsd_size;
- stack = tsd - libc.tls_size;
-+ memset(stack, 0, need);
- } else {
- size = ROUND(need);
- guard = 0;
-diff --git a/src/thread/pthread_mutex_timedlock.c b/src/thread/pthread_mutex_timedlock.c
-index 2a959d2..ae883f9 100644
---- a/src/thread/pthread_mutex_timedlock.c
-+++ b/src/thread/pthread_mutex_timedlock.c
-@@ -8,6 +8,12 @@ int pthread_mutex_timedlock(pthread_mutex_t *restrict m, const struct timespec *
-
- int r, t, priv = (m->_m_type & 128) ^ 128;
-
-+ r = pthread_mutex_trylock(m);
-+ if (r != EBUSY) return r;
-+
-+ int spins = 100;
-+ while (spins-- && m->_m_lock && !m->_m_waiters) a_spin();
-+
- while ((r=pthread_mutex_trylock(m)) == EBUSY) {
- if (!(r=m->_m_lock) || ((r&0x40000000) && (m->_m_type&4)))
- continue;
-diff --git a/src/thread/pthread_rwlock_timedrdlock.c b/src/thread/pthread_rwlock_timedrdlock.c
-index a2b4d44..ea50da4 100644
---- a/src/thread/pthread_rwlock_timedrdlock.c
-+++ b/src/thread/pthread_rwlock_timedrdlock.c
-@@ -3,6 +3,13 @@
- int pthread_rwlock_timedrdlock(pthread_rwlock_t *restrict rw, const struct timespec *restrict at)
- {
- int r, t;
-+
-+ r = pthread_rwlock_tryrdlock(rw);
-+ if (r != EBUSY) return r;
-+
-+ int spins = 100;
-+ while (spins-- && rw->_rw_lock && !rw->_rw_waiters) a_spin();
-+
- while ((r=pthread_rwlock_tryrdlock(rw))==EBUSY) {
- if (!(r=rw->_rw_lock) || (r&0x7fffffff)!=0x7fffffff) continue;
- t = r | 0x80000000;
-diff --git a/src/thread/pthread_rwlock_timedwrlock.c b/src/thread/pthread_rwlock_timedwrlock.c
-index 63a32ec..8d04f56 100644
---- a/src/thread/pthread_rwlock_timedwrlock.c
-+++ b/src/thread/pthread_rwlock_timedwrlock.c
-@@ -3,6 +3,13 @@
- int pthread_rwlock_timedwrlock(pthread_rwlock_t *restrict rw, const struct timespec *restrict at)
- {
- int r, t;
-+
-+ r = pthread_rwlock_trywrlock(rw);
-+ if (r != EBUSY) return r;
-+
-+ int spins = 100;
-+ while (spins-- && rw->_rw_lock && !rw->_rw_waiters) a_spin();
-+
- while ((r=pthread_rwlock_trywrlock(rw))==EBUSY) {
- if (!(r=rw->_rw_lock)) continue;
- t = r | 0x80000000;
-diff --git a/src/thread/sem_timedwait.c b/src/thread/sem_timedwait.c
-index bfcb6dc..b5a60ad 100644
---- a/src/thread/sem_timedwait.c
-+++ b/src/thread/sem_timedwait.c
-@@ -8,6 +8,11 @@ static void cleanup(void *p)
-
- int sem_timedwait(sem_t *restrict sem, const struct timespec *restrict at)
- {
-+ if (!sem_trywait(sem)) return 0;
-+
-+ int spins = 100;
-+ while (spins-- && sem->__val[0] <= 0 && !sem->__val[1]) a_spin();
-+
- while (sem_trywait(sem)) {
- int r;
- a_inc(sem->__val+1);
diff --git a/main/musl/0004-6e2bb7ac-to-4674809b.patch b/main/musl/0004-6e2bb7ac-to-4674809b.patch
deleted file mode 100644
index 62710e321..000000000
--- a/main/musl/0004-6e2bb7ac-to-4674809b.patch
+++ /dev/null
@@ -1,68 +0,0 @@
-diff --git a/src/ctype/iswlower.c b/src/ctype/iswlower.c
-index c754fb9..79df44a 100644
---- a/src/ctype/iswlower.c
-+++ b/src/ctype/iswlower.c
-@@ -3,7 +3,7 @@
-
- int iswlower(wint_t wc)
- {
-- return towupper(wc) != wc || wc == 0xdf;
-+ return towupper(wc) != wc;
- }
-
- int __iswlower_l(wint_t c, locale_t l)
-diff --git a/src/ctype/towctrans.c b/src/ctype/towctrans.c
-index 5e0889b..6af6187 100644
---- a/src/ctype/towctrans.c
-+++ b/src/ctype/towctrans.c
-@@ -151,7 +151,6 @@ static const unsigned short pairs[][2] = {
- { 0x03f7, 0x03f8 },
- { 0x03fa, 0x03fb },
- { 0x1e60, 0x1e9b },
-- { 0xdf, 0xdf },
- { 0x1e9e, 0xdf },
-
- { 0x1f59, 0x1f51 },
-diff --git a/src/network/getnameinfo.c b/src/network/getnameinfo.c
-index 588ed76..2ba66e3 100644
---- a/src/network/getnameinfo.c
-+++ b/src/network/getnameinfo.c
-@@ -113,11 +113,10 @@ static void reverse_services(char *buf, int port, int dgram)
-
- static int dns_parse_callback(void *c, int rr, const void *data, int len, const void *packet)
- {
-- char tmp[256];
- if (rr != RR_PTR) return 0;
- if (__dn_expand(packet, (const unsigned char *)packet + 512,
-- data, tmp, sizeof tmp) > 0)
-- strcpy(c, tmp);
-+ data, c, 256) <= 0)
-+ *(char *)c = 0;
- return 0;
-
- }
-diff --git a/src/thread/pthread_join.c b/src/thread/pthread_join.c
-index 719c91c..abd2d66 100644
---- a/src/thread/pthread_join.c
-+++ b/src/thread/pthread_join.c
-@@ -8,6 +8,7 @@ static void dummy(void *p)
- int pthread_join(pthread_t t, void **res)
- {
- int tmp;
-+ pthread_testcancel();
- while ((tmp = t->tid)) __timedwait(&t->tid, tmp, 0, 0, dummy, 0, 0);
- if (res) *res = t->result;
- if (t->map_base) munmap(t->map_base, t->map_size);
-diff --git a/src/thread/sem_timedwait.c b/src/thread/sem_timedwait.c
-index b5a60ad..68dcb50 100644
---- a/src/thread/sem_timedwait.c
-+++ b/src/thread/sem_timedwait.c
-@@ -8,6 +8,8 @@ static void cleanup(void *p)
-
- int sem_timedwait(sem_t *restrict sem, const struct timespec *restrict at)
- {
-+ pthread_testcancel();
-+
- if (!sem_trywait(sem)) return 0;
-
- int spins = 100;
diff --git a/main/musl/0005-4674809b-to-3e936ce8.patch b/main/musl/0005-4674809b-to-3e936ce8.patch
deleted file mode 100644
index 9180e7eab..000000000
--- a/main/musl/0005-4674809b-to-3e936ce8.patch
+++ /dev/null
@@ -1,3400 +0,0 @@
-diff --git a/arch/arm/bits/alltypes.h.in b/arch/arm/bits/alltypes.h.in
-index 183c4c4..bbe3ce6 100644
---- a/arch/arm/bits/alltypes.h.in
-+++ b/arch/arm/bits/alltypes.h.in
-@@ -20,6 +20,8 @@ TYPEDEF long suseconds_t;
-
- TYPEDEF struct { union { int __i[9]; unsigned __s[9]; } __u; } pthread_attr_t;
- TYPEDEF struct { union { int __i[6]; volatile void *volatile __p[6]; } __u; } pthread_mutex_t;
-+TYPEDEF struct { union { int __i[6]; volatile void *volatile __p[6]; } __u; } mtx_t;
- TYPEDEF struct { union { int __i[12]; void *__p[12]; } __u; } pthread_cond_t;
-+TYPEDEF struct { union { int __i[12]; void *__p[12]; } __u; } cnd_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 8ba8f6f..646922b 100644
---- a/arch/i386/bits/alltypes.h.in
-+++ b/arch/i386/bits/alltypes.h.in
-@@ -27,13 +27,19 @@ TYPEDEF long double float_t;
- TYPEDEF long double double_t;
- #endif
-
-+#ifdef __cplusplus
-+TYPEDEF struct { alignas(8) long long __ll; long double __ld; } max_align_t;
-+#else
- TYPEDEF struct { _Alignas(8) long long __ll; long double __ld; } max_align_t;
-+#endif
-
- 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]; volatile void *volatile __p[6]; } __u; } pthread_mutex_t;
-+TYPEDEF struct { union { int __i[6]; volatile void *volatile __p[6]; } __u; } mtx_t;
- TYPEDEF struct { union { int __i[12]; void *__p[12]; } __u; } pthread_cond_t;
-+TYPEDEF struct { union { int __i[12]; void *__p[12]; } __u; } cnd_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 a03e1b8..95f1ebb 100644
---- a/arch/microblaze/bits/alltypes.h.in
-+++ b/arch/microblaze/bits/alltypes.h.in
-@@ -20,6 +20,8 @@ TYPEDEF long suseconds_t;
-
- TYPEDEF struct { union { int __i[9]; unsigned __s[9]; } __u; } pthread_attr_t;
- TYPEDEF struct { union { int __i[6]; volatile void *volatile __p[6]; } __u; } pthread_mutex_t;
-+TYPEDEF struct { union { int __i[6]; volatile void *volatile __p[6]; } __u; } mtx_t;
- TYPEDEF struct { union { int __i[12]; void *__p[12]; } __u; } pthread_cond_t;
-+TYPEDEF struct { union { int __i[12]; void *__p[12]; } __u; } cnd_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 a03e1b8..95f1ebb 100644
---- a/arch/mips/bits/alltypes.h.in
-+++ b/arch/mips/bits/alltypes.h.in
-@@ -20,6 +20,8 @@ TYPEDEF long suseconds_t;
-
- TYPEDEF struct { union { int __i[9]; unsigned __s[9]; } __u; } pthread_attr_t;
- TYPEDEF struct { union { int __i[6]; volatile void *volatile __p[6]; } __u; } pthread_mutex_t;
-+TYPEDEF struct { union { int __i[6]; volatile void *volatile __p[6]; } __u; } mtx_t;
- TYPEDEF struct { union { int __i[12]; void *__p[12]; } __u; } pthread_cond_t;
-+TYPEDEF struct { union { int __i[12]; void *__p[12]; } __u; } cnd_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 183c4c4..bbe3ce6 100644
---- a/arch/or1k/bits/alltypes.h.in
-+++ b/arch/or1k/bits/alltypes.h.in
-@@ -20,6 +20,8 @@ TYPEDEF long suseconds_t;
-
- TYPEDEF struct { union { int __i[9]; unsigned __s[9]; } __u; } pthread_attr_t;
- TYPEDEF struct { union { int __i[6]; volatile void *volatile __p[6]; } __u; } pthread_mutex_t;
-+TYPEDEF struct { union { int __i[6]; volatile void *volatile __p[6]; } __u; } mtx_t;
- TYPEDEF struct { union { int __i[12]; void *__p[12]; } __u; } pthread_cond_t;
-+TYPEDEF struct { union { int __i[12]; void *__p[12]; } __u; } cnd_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 ee7f137..7446ab4 100644
---- a/arch/powerpc/bits/alltypes.h.in
-+++ b/arch/powerpc/bits/alltypes.h.in
-@@ -20,6 +20,8 @@ TYPEDEF long suseconds_t;
-
- TYPEDEF struct { union { int __i[9]; unsigned __s[9]; } __u; } pthread_attr_t;
- TYPEDEF struct { union { int __i[6]; volatile void *volatile __p[6]; } __u; } pthread_mutex_t;
-+TYPEDEF struct { union { int __i[6]; volatile void *volatile __p[6]; } __u; } mtx_t;
- TYPEDEF struct { union { int __i[12]; void *__p[12]; } __u; } pthread_cond_t;
-+TYPEDEF struct { union { int __i[12]; void *__p[12]; } __u; } cnd_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 ee7f137..7446ab4 100644
---- a/arch/sh/bits/alltypes.h.in
-+++ b/arch/sh/bits/alltypes.h.in
-@@ -20,6 +20,8 @@ TYPEDEF long suseconds_t;
-
- TYPEDEF struct { union { int __i[9]; unsigned __s[9]; } __u; } pthread_attr_t;
- TYPEDEF struct { union { int __i[6]; volatile void *volatile __p[6]; } __u; } pthread_mutex_t;
-+TYPEDEF struct { union { int __i[6]; volatile void *volatile __p[6]; } __u; } mtx_t;
- TYPEDEF struct { union { int __i[12]; void *__p[12]; } __u; } pthread_cond_t;
-+TYPEDEF struct { union { int __i[12]; void *__p[12]; } __u; } cnd_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 8e396c9..a469d5c 100644
---- a/arch/x32/bits/alltypes.h.in
-+++ b/arch/x32/bits/alltypes.h.in
-@@ -25,6 +25,8 @@ 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]; volatile void *volatile __p[5]; } __u; } pthread_mutex_t;
-+TYPEDEF struct { union { int __i[10]; volatile void *volatile __p[5]; } __u; } mtx_t;
- TYPEDEF struct { union { int __i[12]; void *__p[6]; } __u; } pthread_cond_t;
-+TYPEDEF struct { union { int __i[12]; void *__p[6]; } __u; } cnd_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 7b4f3e7..2ce8e4a 100644
---- a/arch/x86_64/bits/alltypes.h.in
-+++ b/arch/x86_64/bits/alltypes.h.in
-@@ -25,6 +25,8 @@ TYPEDEF long suseconds_t;
-
- TYPEDEF struct { union { int __i[14]; unsigned long __s[7]; } __u; } pthread_attr_t;
- TYPEDEF struct { union { int __i[10]; volatile void *volatile __p[5]; } __u; } pthread_mutex_t;
-+TYPEDEF struct { union { int __i[10]; volatile void *volatile __p[5]; } __u; } mtx_t;
- TYPEDEF struct { union { int __i[12]; void *__p[6]; } __u; } pthread_cond_t;
-+TYPEDEF struct { union { int __i[12]; void *__p[6]; } __u; } cnd_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/include/fcntl.h b/include/fcntl.h
-index 2d8fa6e..ff9fcb9 100644
---- a/include/fcntl.h
-+++ b/include/fcntl.h
-@@ -46,6 +46,10 @@ int posix_fallocate(int, off_t, off_t);
- #define O_WRONLY 01
- #define O_RDWR 02
-
-+#define F_OFD_GETLK 36
-+#define F_OFD_SETLK 37
-+#define F_OFD_SETLKW 38
-+
- #define F_DUPFD_CLOEXEC 1030
-
- #define F_RDLCK 0
-diff --git a/include/features.h b/include/features.h
-index 294c61d..3cc3e57 100644
---- a/include/features.h
-+++ b/include/features.h
-@@ -1,10 +1,14 @@
- #ifndef _FEATURES_H
- #define _FEATURES_H
-
--#ifdef _ALL_SOURCE
-+#if defined(_ALL_SOURCE) && !defined(_GNU_SOURCE)
- #define _GNU_SOURCE 1
- #endif
-
-+#if defined(_DEFAULT_SOURCE) && !defined(_BSD_SOURCE)
-+#define _BSD_SOURCE 1
-+#endif
-+
- #if !defined(_POSIX_SOURCE) && !defined(_POSIX_C_SOURCE) \
- && !defined(_XOPEN_SOURCE) && !defined(_GNU_SOURCE) \
- && !defined(_BSD_SOURCE) && !defined(__STRICT_ANSI__)
-diff --git a/include/glob.h b/include/glob.h
-index 9fbbaa6..76f6c1c 100644
---- a/include/glob.h
-+++ b/include/glob.h
-@@ -39,6 +39,7 @@ void globfree(glob_t *);
- #if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE)
- #define glob64 glob
- #define globfree64 globfree
-+#define glob64_t glob_t
- #endif
-
- #ifdef __cplusplus
-diff --git a/include/signal.h b/include/signal.h
-index c36e4d5..87301ba 100644
---- a/include/signal.h
-+++ b/include/signal.h
-@@ -196,7 +196,7 @@ void psignal(int, const char *);
-
- #endif
-
--#if defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE)
-+#if defined(_XOPEN_SOURCE) || defined(_BSD_SOURCE) || defined(_GNU_SOURCE)
- int killpg(pid_t, int);
- int sigaltstack(const stack_t *__restrict, stack_t *__restrict);
- int sighold(int);
-diff --git a/include/stdlib.h b/include/stdlib.h
-index db569d9..97ce5a7 100644
---- a/include/stdlib.h
-+++ b/include/stdlib.h
-@@ -114,9 +114,6 @@ long int random (void);
- void srandom (unsigned int);
- char *initstate (unsigned int, char *, size_t);
- char *setstate (char *);
--#endif
--
--#if defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE)
- int putenv (char *);
- int posix_openpt (int);
- int grantpt (int);
-diff --git a/include/sys/stat.h b/include/sys/stat.h
-index c6abab5..82a6490 100644
---- a/include/sys/stat.h
-+++ b/include/sys/stat.h
-@@ -100,8 +100,9 @@ int lchmod(const char *, mode_t);
- #define fstat64 fstat
- #define lstat64 lstat
- #define fstatat64 fstatat
--#define blksize64_t blksize_t
- #define blkcnt64_t blkcnt_t
-+#define fsblkcnt64_t fsblkcnt_t
-+#define fsfilcnt64_t fsfilcnt_t
- #define ino64_t ino_t
- #define off64_t off_t
- #endif
-diff --git a/include/sys/types.h b/include/sys/types.h
-index f00db03..75e489c 100644
---- a/include/sys/types.h
-+++ b/include/sys/types.h
-@@ -73,7 +73,6 @@ typedef unsigned long long u_quad_t;
- #endif
-
- #if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE)
--#define blksize64_t blksize_t
- #define blkcnt64_t blkcnt_t
- #define fsblkcnt64_t fsblkcnt_t
- #define fsfilcnt64_t fsfilcnt_t
-diff --git a/include/threads.h b/include/threads.h
-new file mode 100644
-index 0000000..0e5836c
---- /dev/null
-+++ b/include/threads.h
-@@ -0,0 +1,85 @@
-+#ifndef _THREADS_H
-+#define _THREADS_H
-+
-+#include <features.h>
-+#include <time.h>
-+
-+#ifdef __cplusplus
-+extern "C" {
-+typedef unsigned long thrd_t;
-+#else
-+typedef struct __pthread *thrd_t;
-+#define thread_local _Thread_local
-+#endif
-+
-+typedef int once_flag;
-+typedef unsigned tss_t;
-+typedef int (*thrd_start_t)(void *);
-+typedef void (*tss_dtor_t)(void *);
-+
-+#define __NEED_cnd_t
-+#define __NEED_mtx_t
-+
-+#include <bits/alltypes.h>
-+
-+#define TSS_DTOR_ITERATIONS 4
-+
-+enum {
-+ thrd_success = 0,
-+ thrd_busy = 1,
-+ thrd_error = 2,
-+ thrd_nomem = 3,
-+ thrd_timedout = 4,
-+};
-+
-+enum {
-+ mtx_plain = 0,
-+ mtx_recursive = 1,
-+ mtx_timed = 2,
-+};
-+
-+#define ONCE_FLAG_INIT 0
-+
-+int thrd_create(thrd_t *, thrd_start_t, void *);
-+_Noreturn void thrd_exit(int);
-+
-+int thrd_detach(thrd_t);
-+int thrd_join(thrd_t, int *);
-+
-+int thrd_sleep(const struct timespec *, struct timespec *);
-+void thrd_yield(void);
-+
-+thrd_t thrd_current(void);
-+int thrd_equal(thrd_t, thrd_t);
-+#define thrd_equal(A, B) ((A) == (B))
-+
-+void call_once(once_flag *, void (*)(void));
-+
-+int mtx_init(mtx_t *, int);
-+void mtx_destroy(mtx_t *);
-+
-+int mtx_lock(mtx_t *);
-+int mtx_timedlock(mtx_t *__restrict, const struct timespec *__restrict);
-+int mtx_trylock(mtx_t *);
-+int mtx_unlock(mtx_t *);
-+
-+int cnd_init(cnd_t *);
-+void cnd_destroy(cnd_t *);
-+
-+int cnd_broadcast(cnd_t *);
-+int cnd_signal(cnd_t *);
-+
-+int cnd_timedwait(cnd_t *__restrict, mtx_t *__restrict, const struct timespec *__restrict);
-+int cnd_wait(cnd_t *, mtx_t *);
-+
-+int tss_create(tss_t *, tss_dtor_t);
-+void tss_delete(tss_t key);
-+
-+int tss_set(tss_t, void *);
-+void *tss_get(tss_t);
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif
-diff --git a/include/time.h b/include/time.h
-index dc88070..16ec08a 100644
---- a/include/time.h
-+++ b/include/time.h
-@@ -17,11 +17,11 @@ extern "C" {
- #define __NEED_size_t
- #define __NEED_time_t
- #define __NEED_clock_t
-+#define __NEED_struct_timespec
-
- #if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) \
- || defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) \
- || defined(_BSD_SOURCE)
--#define __NEED_struct_timespec
- #define __NEED_clockid_t
- #define __NEED_timer_t
- #define __NEED_pid_t
-@@ -59,9 +59,11 @@ struct tm *gmtime (const time_t *);
- struct tm *localtime (const time_t *);
- char *asctime (const struct tm *);
- char *ctime (const time_t *);
-+int timespec_get(struct timespec *, int);
-
- #define CLOCKS_PER_SEC 1000000L
-
-+#define TIME_UTC 1
-
- #if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) \
- || defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) \
-@@ -114,7 +116,7 @@ int timer_getoverrun (timer_t);
- #endif
-
-
--#if defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE)
-+#if defined(_XOPEN_SOURCE) || defined(_BSD_SOURCE) || defined(_GNU_SOURCE)
- char *strptime (const char *__restrict, const char *__restrict, struct tm *__restrict);
- extern int daylight;
- extern long timezone;
-diff --git a/include/unistd.h b/include/unistd.h
-index ac6055a..0fe75d5 100644
---- a/include/unistd.h
-+++ b/include/unistd.h
-@@ -140,9 +140,6 @@ int lockf(int, int, off_t);
- long gethostid(void);
- int nice(int);
- void sync(void);
--#endif
--
--#if defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE)
- pid_t setpgrp(void);
- char *crypt(const char *, const char *);
- void encrypt(char *, int);
-diff --git a/src/aio/aio_cancel.c b/src/aio/aio_cancel.c
-index 5a753b1..16fc431 100644
---- a/src/aio/aio_cancel.c
-+++ b/src/aio/aio_cancel.c
-@@ -1,6 +1,7 @@
- #include <aio.h>
- #include <pthread.h>
- #include <errno.h>
-+#include "libc.h"
-
- int aio_cancel(int fd, struct aiocb *cb)
- {
-@@ -14,3 +15,5 @@ int aio_cancel(int fd, struct aiocb *cb)
- }
- return cb->__err==EINPROGRESS ? AIO_NOTCANCELED : AIO_ALLDONE;
- }
-+
-+LFS64(aio_cancel);
-diff --git a/src/aio/aio_error.c b/src/aio/aio_error.c
-index a780fd3..fd42ea1 100644
---- a/src/aio/aio_error.c
-+++ b/src/aio/aio_error.c
-@@ -1,6 +1,9 @@
- #include <aio.h>
-+#include "libc.h"
-
- int aio_error(const struct aiocb *cb)
- {
- return cb->__err;
- }
-+
-+LFS64(aio_error);
-diff --git a/src/aio/aio_fsync.c b/src/aio/aio_fsync.c
-index 0ac6ea8..6e1a70a 100644
---- a/src/aio/aio_fsync.c
-+++ b/src/aio/aio_fsync.c
-@@ -1,5 +1,6 @@
- #include <aio.h>
- #include <errno.h>
-+#include "libc.h"
-
- int aio_fsync(int op, struct aiocb *cb)
- {
-@@ -7,3 +8,5 @@ int aio_fsync(int op, struct aiocb *cb)
- errno = EINVAL;
- return -1;
- }
-+
-+LFS64(aio_fsync);
-diff --git a/src/aio/aio_readwrite.c b/src/aio/aio_readwrite.c
-index 2278226..8753ffd 100644
---- a/src/aio/aio_readwrite.c
-+++ b/src/aio/aio_readwrite.c
-@@ -105,3 +105,6 @@ int aio_write(struct aiocb *cb)
- cb->aio_lio_opcode = LIO_WRITE;
- return new_req(cb);
- }
-+
-+LFS64(aio_read);
-+LFS64(aio_write);
-diff --git a/src/aio/aio_return.c b/src/aio/aio_return.c
-index df10bdb..c1ce450 100644
---- a/src/aio/aio_return.c
-+++ b/src/aio/aio_return.c
-@@ -1,6 +1,9 @@
- #include <aio.h>
-+#include "libc.h"
-
- ssize_t aio_return(struct aiocb *cb)
- {
- return cb->__ret;
- }
-+
-+LFS64(aio_return);
-diff --git a/src/aio/aio_suspend.c b/src/aio/aio_suspend.c
-index 39a1d3a..dcdf601 100644
---- a/src/aio/aio_suspend.c
-+++ b/src/aio/aio_suspend.c
-@@ -1,6 +1,7 @@
- #include <aio.h>
- #include <errno.h>
- #include "pthread_impl.h"
-+#include "libc.h"
-
- /* Due to the requirement that aio_suspend be async-signal-safe, we cannot
- * use any locks, wait queues, etc. that would make it more efficient. The
-@@ -55,3 +56,5 @@ int aio_suspend(const struct aiocb *const cbs[], int cnt, const struct timespec
- }
- }
- }
-+
-+LFS64(aio_suspend);
-diff --git a/src/aio/lio_listio.c b/src/aio/lio_listio.c
-index 75ed225..bd37767 100644
---- a/src/aio/lio_listio.c
-+++ b/src/aio/lio_listio.c
-@@ -141,3 +141,4 @@ int lio_listio(int mode, struct aiocb *restrict const *restrict cbs, int cnt, st
- return 0;
- }
-
-+LFS64(lio_listio);
-diff --git a/src/conf/fpathconf.c b/src/conf/fpathconf.c
-index 28c4345..8eb037e 100644
---- a/src/conf/fpathconf.c
-+++ b/src/conf/fpathconf.c
-@@ -27,7 +27,7 @@ long fpathconf(int fd, int name)
- [_PC_SYMLINK_MAX] = SYMLINK_MAX,
- [_PC_2_SYMLINKS] = 1
- };
-- if (name > sizeof(values)/sizeof(values[0])) {
-+ if (name >= sizeof(values)/sizeof(values[0])) {
- errno = EINVAL;
- return -1;
- }
-diff --git a/src/dirent/versionsort.c b/src/dirent/versionsort.c
-index 9769610..410cb70 100644
---- a/src/dirent/versionsort.c
-+++ b/src/dirent/versionsort.c
-@@ -1,8 +1,12 @@
- #define _GNU_SOURCE
- #include <string.h>
- #include <dirent.h>
-+#include "libc.h"
-
- int versionsort(const struct dirent **a, const struct dirent **b)
- {
- return strverscmp((*a)->d_name, (*b)->d_name);
- }
-+
-+#undef versionsort64
-+LFS64(versionsort);
-diff --git a/src/internal/intscan.c b/src/internal/intscan.c
-index 69350ef..65d497e 100644
---- a/src/internal/intscan.c
-+++ b/src/internal/intscan.c
-@@ -83,6 +83,7 @@ unsigned long long __intscan(FILE *f, unsigned base, int pok, unsigned long long
- for (; val[c]<base; c=shgetc(f));
- errno = ERANGE;
- y = lim;
-+ if (lim&1) neg = 0;
- }
- done:
- shunget(f);
-diff --git a/src/internal/pthread_impl.h b/src/internal/pthread_impl.h
-index 74c62cc..ae6e60b 100644
---- a/src/internal/pthread_impl.h
-+++ b/src/internal/pthread_impl.h
-@@ -128,4 +128,6 @@ void __restore_sigs(void *);
- #define DEFAULT_STACK_SIZE 81920
- #define DEFAULT_GUARD_SIZE PAGE_SIZE
-
-+#define __ATTRP_C11_THREAD ((void*)(uintptr_t)-1)
-+
- #endif
-diff --git a/src/locale/__lctrans.c b/src/locale/__lctrans.c
-index 2769c08..15994c5 100644
---- a/src/locale/__lctrans.c
-+++ b/src/locale/__lctrans.c
-@@ -2,7 +2,7 @@
- #include "locale_impl.h"
- #include "libc.h"
-
--const char *dummy(const char *msg, const struct __locale_map *lm)
-+static const char *dummy(const char *msg, const struct __locale_map *lm)
- {
- return msg;
- }
-diff --git a/src/math/__polevll.c b/src/math/__polevll.c
-index a272865..ce1a840 100644
---- a/src/math/__polevll.c
-+++ b/src/math/__polevll.c
-@@ -56,6 +56,8 @@
-
- #include "libm.h"
-
-+#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
-+#else
- /*
- * Polynomial evaluator:
- * P[0] x^n + P[1] x^(n-1) + ... + P[n]
-@@ -88,3 +90,4 @@ long double __p1evll(long double x, const long double *P, int n)
-
- return y;
- }
-+#endif
-diff --git a/src/math/exp10.c b/src/math/exp10.c
-index 16d704a..9f5e3c2 100644
---- a/src/math/exp10.c
-+++ b/src/math/exp10.c
-@@ -1,5 +1,6 @@
- #define _GNU_SOURCE
- #include <math.h>
-+#include <stdint.h>
- #include "libc.h"
-
- double exp10(double x)
-@@ -11,7 +12,9 @@ double exp10(double x)
- 1e10, 1e11, 1e12, 1e13, 1e14, 1e15
- };
- double n, y = modf(x, &n);
-- if (fabs(n) < 16) {
-+ union {double f; uint64_t i;} u = {n};
-+ /* fabs(n) < 16 without raising invalid on nan */
-+ if ((u.i>>52 & 0x7ff) < 0x3ff+4) {
- if (!y) return p10[(int)n+15];
- y = exp2(3.32192809488736234787031942948939 * y);
- return y * p10[(int)n+15];
-diff --git a/src/math/exp10f.c b/src/math/exp10f.c
-index 5fd1af9..7a8d447 100644
---- a/src/math/exp10f.c
-+++ b/src/math/exp10f.c
-@@ -1,5 +1,6 @@
- #define _GNU_SOURCE
- #include <math.h>
-+#include <stdint.h>
- #include "libc.h"
-
- float exp10f(float x)
-@@ -9,7 +10,9 @@ float exp10f(float x)
- 1, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7
- };
- float n, y = modff(x, &n);
-- if (fabsf(n) < 8) {
-+ union {float f; uint32_t i;} u = {n};
-+ /* fabsf(n) < 8 without raising invalid on nan */
-+ if ((u.i>>23 & 0xff) < 0x7f+3) {
- if (!y) return p10[(int)n+7];
- y = exp2f(3.32192809488736234787031942948939f * y);
- return y * p10[(int)n+7];
-diff --git a/src/math/exp10l.c b/src/math/exp10l.c
-index 22a4636..b758ebf 100644
---- a/src/math/exp10l.c
-+++ b/src/math/exp10l.c
-@@ -1,7 +1,15 @@
- #define _GNU_SOURCE
-+#include <float.h>
- #include <math.h>
- #include "libc.h"
-+#include "libm.h"
-
-+#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
-+long double exp10l(long double x)
-+{
-+ return exp10(x);
-+}
-+#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384
- long double exp10l(long double x)
- {
- static const long double p10[] = {
-@@ -11,12 +19,15 @@ long double exp10l(long double x)
- 1e10, 1e11, 1e12, 1e13, 1e14, 1e15
- };
- long double n, y = modfl(x, &n);
-- if (fabsl(n) < 16) {
-+ union ldshape u = {n};
-+ /* fabsl(n) < 16 without raising invalid on nan */
-+ if ((u.i.se & 0x7fff) < 0x3fff+4) {
- if (!y) return p10[(int)n+15];
- y = exp2l(3.32192809488736234787031942948939L * y);
- return y * p10[(int)n+15];
- }
- return powl(10.0, x);
- }
-+#endif
-
- weak_alias(exp10l, pow10l);
-diff --git a/src/mman/mprotect.c b/src/mman/mprotect.c
-index f488486..535787b 100644
---- a/src/mman/mprotect.c
-+++ b/src/mman/mprotect.c
-@@ -2,10 +2,12 @@
- #include "libc.h"
- #include "syscall.h"
-
--int mprotect(void *addr, size_t len, int prot)
-+int __mprotect(void *addr, size_t len, int prot)
- {
- size_t start, end;
- start = (size_t)addr & -PAGE_SIZE;
- end = (size_t)((char *)addr + len + PAGE_SIZE-1) & -PAGE_SIZE;
- return syscall(SYS_mprotect, start, end-start, prot);
- }
-+
-+weak_alias(__mprotect, mprotect);
-diff --git a/src/network/getnameinfo.c b/src/network/getnameinfo.c
-index 2ba66e3..3484fc6 100644
---- a/src/network/getnameinfo.c
-+++ b/src/network/getnameinfo.c
-@@ -96,7 +96,7 @@ static void reverse_services(char *buf, int port, int dgram)
- if ((p=strchr(line, '#'))) *p++='\n', *p=0;
-
- for (p=line; *p && !isspace(*p); p++);
-- if (!p) continue;
-+ if (!*p) continue;
- *p++ = 0;
- svport = strtoul(p, &z, 10);
-
-diff --git a/src/network/lookup_serv.c b/src/network/lookup_serv.c
-index bf4cba0..a9be0f3 100644
---- a/src/network/lookup_serv.c
-+++ b/src/network/lookup_serv.c
-@@ -52,7 +52,6 @@ int __lookup_serv(struct service buf[static MAXSERVS], const char *name, int pro
-
- /* Skip past canonical name at beginning of line */
- for (p=line; *p && !isspace(*p); p++);
-- if (!p) continue;
-
- port = strtoul(p, &z, 10);
- if (port > 65535 || z==p) continue;
-diff --git a/src/regex/regcomp.c b/src/regex/regcomp.c
-index d907627..4cdaa1e 100644
---- a/src/regex/regcomp.c
-+++ b/src/regex/regcomp.c
-@@ -34,6 +34,7 @@
- #include <regex.h>
- #include <limits.h>
- #include <stdint.h>
-+#include <ctype.h>
-
- #include "tre.h"
-
-@@ -135,108 +136,88 @@ typedef struct {
- tre_ast_node_t *right;
- } tre_union_t;
-
--static tre_ast_node_t *
--tre_ast_new_node(tre_mem_t mem, tre_ast_type_t type, size_t size);
--
--static tre_ast_node_t *
--tre_ast_new_literal(tre_mem_t mem, int code_min, int code_max, int position);
--
--static tre_ast_node_t *
--tre_ast_new_iter(tre_mem_t mem, tre_ast_node_t *arg, int min, int max,
-- int minimal);
--
--static tre_ast_node_t *
--tre_ast_new_union(tre_mem_t mem, tre_ast_node_t *left, tre_ast_node_t *right);
--
--static tre_ast_node_t *
--tre_ast_new_catenation(tre_mem_t mem, tre_ast_node_t *left,
-- tre_ast_node_t *right);
--
-
- static tre_ast_node_t *
--tre_ast_new_node(tre_mem_t mem, tre_ast_type_t type, size_t size)
-+tre_ast_new_node(tre_mem_t mem, int type, void *obj)
- {
-- tre_ast_node_t *node;
--
-- node = tre_mem_calloc(mem, sizeof(*node));
-- if (!node)
-- return NULL;
-- node->obj = tre_mem_calloc(mem, size);
-- if (!node->obj)
-- return NULL;
-- node->type = type;
-- node->nullable = -1;
-- node->submatch_id = -1;
--
-- return node;
-+ tre_ast_node_t *node = tre_mem_calloc(mem, sizeof *node);
-+ if (!node || !obj)
-+ return 0;
-+ node->obj = obj;
-+ node->type = type;
-+ node->nullable = -1;
-+ node->submatch_id = -1;
-+ return node;
- }
-
- static tre_ast_node_t *
- tre_ast_new_literal(tre_mem_t mem, int code_min, int code_max, int position)
- {
-- tre_ast_node_t *node;
-- tre_literal_t *lit;
--
-- node = tre_ast_new_node(mem, LITERAL, sizeof(tre_literal_t));
-- if (!node)
-- return NULL;
-- lit = node->obj;
-- lit->code_min = code_min;
-- lit->code_max = code_max;
-- lit->position = position;
--
-- return node;
-+ tre_ast_node_t *node;
-+ tre_literal_t *lit;
-+
-+ lit = tre_mem_calloc(mem, sizeof *lit);
-+ node = tre_ast_new_node(mem, LITERAL, lit);
-+ if (!node)
-+ return 0;
-+ lit->code_min = code_min;
-+ lit->code_max = code_max;
-+ lit->position = position;
-+ return node;
- }
-
- static tre_ast_node_t *
--tre_ast_new_iter(tre_mem_t mem, tre_ast_node_t *arg, int min, int max,
-- int minimal)
-+tre_ast_new_iter(tre_mem_t mem, tre_ast_node_t *arg, int min, int max, int minimal)
- {
-- tre_ast_node_t *node;
-- tre_iteration_t *iter;
--
-- node = tre_ast_new_node(mem, ITERATION, sizeof(tre_iteration_t));
-- if (!node)
-- return NULL;
-- iter = node->obj;
-- iter->arg = arg;
-- iter->min = min;
-- iter->max = max;
-- iter->minimal = minimal;
-- node->num_submatches = arg->num_submatches;
--
-- return node;
-+ tre_ast_node_t *node;
-+ tre_iteration_t *iter;
-+
-+ iter = tre_mem_calloc(mem, sizeof *iter);
-+ node = tre_ast_new_node(mem, ITERATION, iter);
-+ if (!node)
-+ return 0;
-+ iter->arg = arg;
-+ iter->min = min;
-+ iter->max = max;
-+ iter->minimal = minimal;
-+ node->num_submatches = arg->num_submatches;
-+ return node;
- }
-
- static tre_ast_node_t *
- tre_ast_new_union(tre_mem_t mem, tre_ast_node_t *left, tre_ast_node_t *right)
- {
-- tre_ast_node_t *node;
--
-- node = tre_ast_new_node(mem, UNION, sizeof(tre_union_t));
-- if (node == NULL)
-- return NULL;
-- ((tre_union_t *)node->obj)->left = left;
-- ((tre_union_t *)node->obj)->right = right;
-- node->num_submatches = left->num_submatches + right->num_submatches;
--
-- return node;
-+ tre_ast_node_t *node;
-+ tre_union_t *un;
-+
-+ if (!left)
-+ return right;
-+ un = tre_mem_calloc(mem, sizeof *un);
-+ node = tre_ast_new_node(mem, UNION, un);
-+ if (!node || !right)
-+ return 0;
-+ un->left = left;
-+ un->right = right;
-+ node->num_submatches = left->num_submatches + right->num_submatches;
-+ return node;
- }
-
- static tre_ast_node_t *
--tre_ast_new_catenation(tre_mem_t mem, tre_ast_node_t *left,
-- tre_ast_node_t *right)
-+tre_ast_new_catenation(tre_mem_t mem, tre_ast_node_t *left, tre_ast_node_t *right)
- {
-- tre_ast_node_t *node;
--
-- node = tre_ast_new_node(mem, CATENATION, sizeof(tre_catenation_t));
-- if (node == NULL)
-- return NULL;
-- ((tre_catenation_t *)node->obj)->left = left;
-- ((tre_catenation_t *)node->obj)->right = right;
-- node->num_submatches = left->num_submatches + right->num_submatches;
--
-- return node;
-+ tre_ast_node_t *node;
-+ tre_catenation_t *cat;
-+
-+ if (!left)
-+ return right;
-+ cat = tre_mem_calloc(mem, sizeof *cat);
-+ node = tre_ast_new_node(mem, CATENATION, cat);
-+ if (!node)
-+ return 0;
-+ cat->left = left;
-+ cat->right = right;
-+ node->num_submatches = left->num_submatches + right->num_submatches;
-+ return node;
- }
-
-
-@@ -412,1077 +393,654 @@ define_popf(voidptr, void *)
-
- /* Parse context. */
- typedef struct {
-- /* Memory allocator. The AST is allocated using this. */
-- tre_mem_t mem;
-- /* Stack used for keeping track of regexp syntax. */
-- tre_stack_t *stack;
-- /* The parse result. */
-- tre_ast_node_t *result;
-- /* The regexp to parse and its length. */
-- const char *re;
-- /* The first character of the entire regexp. */
-- const char *re_start;
-- /* Current submatch ID. */
-- int submatch_id;
-- /* Current position (number of literal). */
-- int position;
-- /* The highest back reference or -1 if none seen so far. */
-- int max_backref;
-- /* This flag is set if the regexp uses approximate matching. */
-- int have_approx;
-- /* Compilation flags. */
-- int cflags;
-- /* If this flag is set the top-level submatch is not captured. */
-- int nofirstsub;
-+ /* Memory allocator. The AST is allocated using this. */
-+ tre_mem_t mem;
-+ /* Stack used for keeping track of regexp syntax. */
-+ tre_stack_t *stack;
-+ /* The parsed node after a parse function returns. */
-+ tre_ast_node_t *n;
-+ /* Position in the regexp pattern after a parse function returns. */
-+ const char *s;
-+ /* The first character of the regexp. */
-+ const char *re;
-+ /* Current submatch ID. */
-+ int submatch_id;
-+ /* Current position (number of literal). */
-+ int position;
-+ /* The highest back reference or -1 if none seen so far. */
-+ int max_backref;
-+ /* Compilation flags. */
-+ int cflags;
- } tre_parse_ctx_t;
-
--/* Parses a wide character regexp pattern into a syntax tree. This parser
-- handles both syntaxes (BRE and ERE), including the TRE extensions. */
--static reg_errcode_t
--tre_parse(tre_parse_ctx_t *ctx);
--
--
--/*
-- This parser is just a simple recursive descent parser for POSIX.2
-- regexps. The parser supports both the obsolete default syntax and
-- the "extended" syntax, and some nonstandard extensions.
--*/
--
--/* Characters with special meanings in regexp syntax. */
--#define CHAR_PIPE '|'
--#define CHAR_LPAREN '('
--#define CHAR_RPAREN ')'
--#define CHAR_LBRACE '{'
--#define CHAR_RBRACE '}'
--#define CHAR_LBRACKET '['
--#define CHAR_RBRACKET ']'
--#define CHAR_MINUS '-'
--#define CHAR_STAR '*'
--#define CHAR_QUESTIONMARK '?'
--#define CHAR_PLUS '+'
--#define CHAR_PERIOD '.'
--#define CHAR_COLON ':'
--#define CHAR_EQUAL '='
--#define CHAR_COMMA ','
--#define CHAR_CARET '^'
--#define CHAR_DOLLAR '$'
--#define CHAR_BACKSLASH '\\'
--#define CHAR_HASH '#'
--#define CHAR_TILDE '~'
--
--
- /* Some macros for expanding \w, \s, etc. */
--static const struct tre_macro_struct {
-- const char c;
-- const char *expansion;
--} tre_macros[] =
-- { {'t', "\t"}, {'n', "\n"}, {'r', "\r"},
-- {'f', "\f"}, {'a', "\a"}, {'e', "\033"},
-- {'w', "[[:alnum:]_]"}, {'W', "[^[:alnum:]_]"}, {'s', "[[:space:]]"},
-- {'S', "[^[:space:]]"}, {'d', "[[:digit:]]"}, {'D', "[^[:digit:]]"},
-- { 0, NULL }
-- };
--
-+static const struct {
-+ char c;
-+ const char *expansion;
-+} tre_macros[] = {
-+ {'t', "\t"}, {'n', "\n"}, {'r', "\r"},
-+ {'f', "\f"}, {'a', "\a"}, {'e', "\033"},
-+ {'w', "[[:alnum:]_]"}, {'W', "[^[:alnum:]_]"}, {'s', "[[:space:]]"},
-+ {'S', "[^[:space:]]"}, {'d', "[[:digit:]]"}, {'D', "[^[:digit:]]"},
-+ { 0, 0 }
-+};
-
- /* Expands a macro delimited by `regex' and `regex_end' to `buf', which
- must have at least `len' items. Sets buf[0] to zero if the there
- is no match in `tre_macros'. */
--static const char *
--tre_expand_macro(const char *regex)
-+static const char *tre_expand_macro(const char *s)
- {
-- int i;
--
-- if (!*regex)
-- return 0;
--
-- for (i = 0; tre_macros[i].expansion && tre_macros[i].c != *regex; i++);
-- return tre_macros[i].expansion;
-+ int i;
-+ for (i = 0; tre_macros[i].c && tre_macros[i].c != *s; i++);
-+ return tre_macros[i].expansion;
- }
-
--static reg_errcode_t
--tre_new_item(tre_mem_t mem, int min, int max, int *i, int *max_i,
-- tre_ast_node_t ***items)
-+static int
-+tre_compare_lit(const void *a, const void *b)
- {
-- reg_errcode_t status;
-- tre_ast_node_t **array = *items;
-- /* Allocate more space if necessary. */
-- if (*i >= *max_i)
-- {
-- tre_ast_node_t **new_items;
-- /* If the array is already 1024 items large, give up -- there's
-- probably an error in the regexp (e.g. not a '\0' terminated
-- string and missing ']') */
-- if (*max_i > 1024)
-- return REG_ESPACE;
-- *max_i *= 2;
-- new_items = xrealloc(array, sizeof(*array) * *max_i);
-- if (new_items == NULL)
-- return REG_ESPACE;
-- *items = array = new_items;
-- }
-- array[*i] = tre_ast_new_literal(mem, min, max, -1);
-- status = array[*i] == NULL ? REG_ESPACE : REG_OK;
-- (*i)++;
-- return status;
-+ const tre_literal_t *const *la = a;
-+ const tre_literal_t *const *lb = b;
-+ /* assumes the range of valid code_min is < INT_MAX */
-+ return la[0]->code_min - lb[0]->code_min;
- }
-
-+struct literals {
-+ tre_mem_t mem;
-+ tre_literal_t **a;
-+ int len;
-+ int cap;
-+};
-
--static int
--tre_compare_items(const void *a, const void *b)
-+static tre_literal_t *tre_new_lit(struct literals *p)
- {
-- const tre_ast_node_t *node_a = *(tre_ast_node_t * const *)a;
-- const tre_ast_node_t *node_b = *(tre_ast_node_t * const *)b;
-- tre_literal_t *l_a = node_a->obj, *l_b = node_b->obj;
-- int a_min = l_a->code_min, b_min = l_b->code_min;
--
-- if (a_min < b_min)
-- return -1;
-- else if (a_min > b_min)
-- return 1;
-- else
-- return 0;
-+ tre_literal_t **a;
-+ if (p->len >= p->cap) {
-+ if (p->cap >= 1<<15)
-+ return 0;
-+ p->cap *= 2;
-+ a = xrealloc(p->a, p->cap * sizeof *p->a);
-+ if (!a)
-+ return 0;
-+ p->a = a;
-+ }
-+ a = p->a + p->len++;
-+ *a = tre_mem_calloc(p->mem, sizeof **a);
-+ return *a;
- }
-
--/* Maximum number of character classes that can occur in a negated bracket
-- expression. */
--#define MAX_NEG_CLASSES 64
--
--/* Maximum length of character class names. */
--#define MAX_CLASS_NAME
--
--static reg_errcode_t
--tre_parse_bracket_items(tre_parse_ctx_t *ctx, int negate,
-- tre_ctype_t neg_classes[], int *num_neg_classes,
-- tre_ast_node_t ***items, int *num_items,
-- int *items_size)
-+static int add_icase_literals(struct literals *ls, int min, int max)
- {
-- const char *re = ctx->re;
-- reg_errcode_t status = REG_OK;
-- tre_ctype_t class = (tre_ctype_t)0;
-- int i = *num_items;
-- int max_i = *items_size;
-- int skip;
--
-- /* Build an array of the items in the bracket expression. */
-- while (status == REG_OK)
-- {
-- skip = 0;
-- if (!*re)
-- {
-- status = REG_EBRACK;
-- }
-- else if (*re == CHAR_RBRACKET && re > ctx->re)
-- {
-- re++;
-- break;
-+ tre_literal_t *lit;
-+ int b, e, c;
-+ for (c=min; c<=max; ) {
-+ /* assumes islower(c) and isupper(c) are exclusive
-+ and toupper(c)!=c if islower(c).
-+ multiple opposite case characters are not supported */
-+ if (tre_islower(c)) {
-+ b = e = tre_toupper(c);
-+ for (c++, e++; c<=max; c++, e++)
-+ if (tre_toupper(c) != e) break;
-+ } else if (tre_isupper(c)) {
-+ b = e = tre_tolower(c);
-+ for (c++, e++; c<=max; c++, e++)
-+ if (tre_tolower(c) != e) break;
-+ } else {
-+ c++;
-+ continue;
-+ }
-+ lit = tre_new_lit(ls);
-+ if (!lit)
-+ return -1;
-+ lit->code_min = b;
-+ lit->code_max = e-1;
-+ lit->position = -1;
- }
-- else
-- {
-- tre_cint_t min = 0, max = 0;
-- wchar_t wc;
-- int clen = mbtowc(&wc, re, -1);
-+ return 0;
-+}
-
-- if (clen<0) clen=1, wc=WEOF;
-
-- class = (tre_ctype_t)0;
-- if (*(re + clen) == CHAR_MINUS && *(re + clen + 1) != CHAR_RBRACKET)
-- {
-- min = wc;
-- re += clen+1;
-- clen = mbtowc(&wc, re, -1);
-- if (clen<0) clen=1, wc=WEOF;
-- max = wc;
-- re += clen;
-- /* XXX - Should use collation order instead of encoding values
-- in character ranges. */
-- if (min > max)
-- status = REG_ERANGE;
-- }
-- else if (*re == CHAR_LBRACKET && *(re + 1) == CHAR_PERIOD)
-- status = REG_ECOLLATE;
-- else if (*re == CHAR_LBRACKET && *(re + 1) == CHAR_EQUAL)
-- status = REG_ECOLLATE;
-- else if (*re == CHAR_LBRACKET && *(re + 1) == CHAR_COLON)
-- {
-- char tmp_str[64];
-- const char *endptr = re + 2;
-- int len;
-- while (*endptr && *endptr != CHAR_COLON)
-- endptr++;
-- if (*endptr)
-- {
-- len = MIN(endptr - re - 2, 63);
-- strncpy(tmp_str, re + 2, len);
-- tmp_str[len] = '\0';
-- class = tre_ctype(tmp_str);
-- if (!class)
-- status = REG_ECTYPE;
-- re = endptr + 2;
-- }
-- else
-- status = REG_ECTYPE;
-- min = 0;
-- max = TRE_CHAR_MAX;
-- }
-- else
-- {
-- if (*re == CHAR_MINUS && *(re + 1) != CHAR_RBRACKET
-- && ctx->re != re)
-- /* Two ranges are not allowed to share and endpoint. */
-- status = REG_ERANGE;
-- min = max = wc;
-- re += clen;
-- }
-+/* Maximum number of character classes in a negated bracket expression. */
-+#define MAX_NEG_CLASSES 64
-
-- if (status != REG_OK)
-- break;
-+struct neg {
-+ int negate;
-+ int len;
-+ tre_ctype_t a[MAX_NEG_CLASSES];
-+};
-
-- if (class && negate)
-- if (*num_neg_classes >= MAX_NEG_CLASSES)
-- status = REG_ESPACE;
-- else
-- neg_classes[(*num_neg_classes)++] = class;
-- else if (!skip)
-- {
-- status = tre_new_item(ctx->mem, min, max, &i, &max_i, items);
-- if (status != REG_OK)
-- break;
-- ((tre_literal_t*)((*items)[i-1])->obj)->class = class;
-- }
-+// TODO: parse bracket into a set of non-overlapping [lo,hi] ranges
-
-- /* Add opposite-case counterpoints if REG_ICASE is present.
-- This is broken if there are more than two "same" characters. */
-- if (ctx->cflags & REG_ICASE && !class && status == REG_OK && !skip)
-- {
-- tre_cint_t cmin, ccurr;
-+/*
-+bracket grammar:
-+Bracket = '[' List ']' | '[^' List ']'
-+List = Term | List Term
-+Term = Char | Range | Chclass | Eqclass
-+Range = Char '-' Char | Char '-' '-'
-+Char = Coll | coll_single
-+Meta = ']' | '-'
-+Coll = '[.' coll_single '.]' | '[.' coll_multi '.]' | '[.' Meta '.]'
-+Eqclass = '[=' coll_single '=]' | '[=' coll_multi '=]'
-+Chclass = '[:' class ':]'
-+
-+coll_single is a single char collating element but it can be
-+ '-' only at the beginning or end of a List and
-+ ']' only at the beginning of a List and
-+ '^' anywhere except after the openning '['
-+*/
-
-- while (min <= max)
-- {
-- if (tre_islower(min))
-- {
-- cmin = ccurr = tre_toupper(min++);
-- while (tre_islower(min) && tre_toupper(min) == ccurr + 1
-- && min <= max)
-- ccurr = tre_toupper(min++);
-- status = tre_new_item(ctx->mem, cmin, ccurr,
-- &i, &max_i, items);
-- }
-- else if (tre_isupper(min))
-- {
-- cmin = ccurr = tre_tolower(min++);
-- while (tre_isupper(min) && tre_tolower(min) == ccurr + 1
-- && min <= max)
-- ccurr = tre_tolower(min++);
-- status = tre_new_item(ctx->mem, cmin, ccurr,
-- &i, &max_i, items);
-- }
-- else min++;
-- if (status != REG_OK)
-- break;
-+static reg_errcode_t parse_bracket_terms(tre_parse_ctx_t *ctx, const char *s, struct literals *ls, struct neg *neg)
-+{
-+ const char *start = s;
-+ tre_ctype_t class;
-+ int min, max;
-+ wchar_t wc;
-+ int len;
-+
-+ for (;;) {
-+ class = 0;
-+ len = mbtowc(&wc, s, -1);
-+ if (len <= 0)
-+ return *s ? REG_BADPAT : REG_EBRACK;
-+ if (*s == ']' && s != start) {
-+ ctx->s = s+1;
-+ return REG_OK;
-+ }
-+ if (*s == '-' && s != start && s[1] != ']' &&
-+ /* extension: [a-z--@] is accepted as [a-z]|[--@] */
-+ (s[1] != '-' || s[2] == ']'))
-+ return REG_ERANGE;
-+ if (*s == '[' && (s[1] == '.' || s[1] == '='))
-+ /* collating symbols and equivalence classes are not supported */
-+ return REG_ECOLLATE;
-+ if (*s == '[' && s[1] == ':') {
-+ char tmp[CHARCLASS_NAME_MAX+1];
-+ s += 2;
-+ for (len=0; len < CHARCLASS_NAME_MAX && s[len]; len++) {
-+ if (s[len] == ':') {
-+ memcpy(tmp, s, len);
-+ tmp[len] = 0;
-+ class = tre_ctype(tmp);
-+ break;
-+ }
-+ }
-+ if (!class || s[len+1] != ']')
-+ return REG_ECTYPE;
-+ min = 0;
-+ max = TRE_CHAR_MAX;
-+ s += len+2;
-+ } else {
-+ min = max = wc;
-+ s += len;
-+ if (*s == '-' && s[1] != ']') {
-+ s++;
-+ len = mbtowc(&wc, s, -1);
-+ max = wc;
-+ /* XXX - Should use collation order instead of
-+ encoding values in character ranges. */
-+ if (len <= 0 || min > max)
-+ return REG_ERANGE;
-+ s += len;
-+ }
-+ }
-+
-+ if (class && neg->negate) {
-+ if (neg->len >= MAX_NEG_CLASSES)
-+ return REG_ESPACE;
-+ neg->a[neg->len++] = class;
-+ } else {
-+ tre_literal_t *lit = tre_new_lit(ls);
-+ if (!lit)
-+ return REG_ESPACE;
-+ lit->code_min = min;
-+ lit->code_max = max;
-+ lit->class = class;
-+ lit->position = -1;
-+
-+ /* Add opposite-case codepoints if REG_ICASE is present.
-+ It seems that POSIX requires that bracket negation
-+ should happen before case-folding, but most practical
-+ implementations do it the other way around. Changing
-+ the order would need efficient representation of
-+ case-fold ranges and bracket range sets even with
-+ simple patterns so this is ok for now. */
-+ if (ctx->cflags & REG_ICASE && !class)
-+ if (add_icase_literals(ls, min, max))
-+ return REG_ESPACE;
- }
-- if (status != REG_OK)
-- break;
-- }
- }
-- }
-- *num_items = i;
-- *items_size = max_i;
-- ctx->re = re;
-- return status;
- }
-
--static reg_errcode_t
--tre_parse_bracket(tre_parse_ctx_t *ctx, tre_ast_node_t **result)
-+static reg_errcode_t parse_bracket(tre_parse_ctx_t *ctx, const char *s)
- {
-- tre_ast_node_t *node = NULL;
-- int negate = 0;
-- reg_errcode_t status = REG_OK;
-- tre_ast_node_t **items, *u, *n;
-- int i = 0, j, max_i = 32, curr_max, curr_min;
-- tre_ctype_t neg_classes[MAX_NEG_CLASSES];
-- int num_neg_classes = 0;
--
-- /* Start off with an array of `max_i' elements. */
-- items = xmalloc(sizeof(*items) * max_i);
-- if (items == NULL)
-- return REG_ESPACE;
--
-- if (*ctx->re == CHAR_CARET)
-- {
-- negate = 1;
-- ctx->re++;
-- }
--
-- status = tre_parse_bracket_items(ctx, negate, neg_classes, &num_neg_classes,
-- &items, &i, &max_i);
--
-- if (status != REG_OK)
-- goto parse_bracket_done;
--
-- /* Sort the array if we need to negate it. */
-- if (negate)
-- qsort(items, (unsigned)i, sizeof(*items), tre_compare_items);
--
-- curr_max = curr_min = 0;
-- /* Build a union of the items in the array, negated if necessary. */
-- for (j = 0; j < i && status == REG_OK; j++)
-- {
-- int min, max;
-- tre_literal_t *l = items[j]->obj;
-- min = l->code_min;
-- max = l->code_max;
--
-- if (negate)
-- {
-- if (min < curr_max)
-- {
-- /* Overlap. */
-- curr_max = MAX(max + 1, curr_max);
-- l = NULL;
-- }
-- else
-- {
-- /* No overlap. */
-- curr_max = min - 1;
-- if (curr_max >= curr_min)
-- {
-- l->code_min = curr_min;
-- l->code_max = curr_max;
-+ int i, max, min, negmax, negmin;
-+ tre_ast_node_t *node = 0, *n;
-+ tre_ctype_t *nc = 0;
-+ tre_literal_t *lit;
-+ struct literals ls;
-+ struct neg neg;
-+ reg_errcode_t err;
-+
-+ ls.mem = ctx->mem;
-+ ls.len = 0;
-+ ls.cap = 32;
-+ ls.a = xmalloc(ls.cap * sizeof *ls.a);
-+ if (!ls.a)
-+ return REG_ESPACE;
-+ neg.len = 0;
-+ neg.negate = *s == '^';
-+ if (neg.negate)
-+ s++;
-+
-+ err = parse_bracket_terms(ctx, s, &ls, &neg);
-+ if (err != REG_OK)
-+ goto parse_bracket_done;
-+
-+ if (neg.negate) {
-+ /* Sort the array if we need to negate it. */
-+ qsort(ls.a, ls.len, sizeof *ls.a, tre_compare_lit);
-+ /* extra lit for the last negated range */
-+ lit = tre_new_lit(&ls);
-+ if (!lit) {
-+ err = REG_ESPACE;
-+ goto parse_bracket_done;
- }
-- else
-- {
-- l = NULL;
-+ lit->code_min = TRE_CHAR_MAX+1;
-+ lit->code_max = TRE_CHAR_MAX+1;
-+ lit->position = -1;
-+ /* negated classes */
-+ if (neg.len) {
-+ nc = tre_mem_alloc(ctx->mem, (neg.len+1)*sizeof *neg.a);
-+ if (!nc) {
-+ err = REG_ESPACE;
-+ goto parse_bracket_done;
-+ }
-+ memcpy(nc, neg.a, neg.len*sizeof *neg.a);
-+ nc[neg.len] = 0;
- }
-- curr_min = curr_max = max + 1;
-- }
- }
-
-- if (l != NULL)
-- {
-- int k;
-- l->position = ctx->position;
-- if (num_neg_classes > 0)
-- {
-- l->neg_classes = tre_mem_alloc(ctx->mem,
-- (sizeof(*l->neg_classes)
-- * (num_neg_classes + 1)));
-- if (l->neg_classes == NULL)
-- {
-- status = REG_ESPACE;
-- break;
-+ /* Build a union of the items in the array, negated if necessary. */
-+ negmax = negmin = 0;
-+ for (i = 0; i < ls.len; i++) {
-+ lit = ls.a[i];
-+ min = lit->code_min;
-+ max = lit->code_max;
-+ if (neg.negate) {
-+ if (min <= negmin) {
-+ /* Overlap. */
-+ negmin = MAX(max + 1, negmin);
-+ continue;
-+ }
-+ negmax = min - 1;
-+ lit->code_min = negmin;
-+ lit->code_max = negmax;
-+ negmin = max + 1;
- }
-- for (k = 0; k < num_neg_classes; k++)
-- l->neg_classes[k] = neg_classes[k];
-- l->neg_classes[k] = (tre_ctype_t)0;
-- }
-- else
-- l->neg_classes = NULL;
-- if (node == NULL)
-- node = items[j];
-- else
-- {
-- u = tre_ast_new_union(ctx->mem, node, items[j]);
-- if (u == NULL)
-- status = REG_ESPACE;
-- node = u;
-- }
-- }
-- }
--
-- if (status != REG_OK)
-- goto parse_bracket_done;
--
-- if (negate)
-- {
-- int k;
-- n = tre_ast_new_literal(ctx->mem, curr_min, TRE_CHAR_MAX, ctx->position);
-- if (n == NULL)
-- status = REG_ESPACE;
-- else
-- {
-- tre_literal_t *l = n->obj;
-- if (num_neg_classes > 0)
-- {
-- l->neg_classes = tre_mem_alloc(ctx->mem,
-- (sizeof(*l->neg_classes)
-- * (num_neg_classes + 1)));
-- if (l->neg_classes == NULL)
-- {
-- status = REG_ESPACE;
-- goto parse_bracket_done;
-+ lit->position = ctx->position;
-+ lit->neg_classes = nc;
-+ n = tre_ast_new_node(ctx->mem, LITERAL, lit);
-+ node = tre_ast_new_union(ctx->mem, node, n);
-+ if (!node) {
-+ err = REG_ESPACE;
-+ break;
- }
-- for (k = 0; k < num_neg_classes; k++)
-- l->neg_classes[k] = neg_classes[k];
-- l->neg_classes[k] = (tre_ctype_t)0;
-- }
-- else
-- l->neg_classes = NULL;
-- if (node == NULL)
-- node = n;
-- else
-- {
-- u = tre_ast_new_union(ctx->mem, node, n);
-- if (u == NULL)
-- status = REG_ESPACE;
-- node = u;
-- }
- }
-- }
--
-- if (status != REG_OK)
-- goto parse_bracket_done;
-
--#ifdef TRE_DEBUG
-- tre_ast_print(node);
--#endif /* TRE_DEBUG */
--
-- parse_bracket_done:
-- xfree(items);
-- ctx->position++;
-- *result = node;
-- return status;
-+parse_bracket_done:
-+ xfree(ls.a);
-+ ctx->position++;
-+ ctx->n = node;
-+ return err;
- }
-
--
--/* Parses a positive decimal integer. Returns -1 if the string does not
-- contain a valid number. */
--static int
--tre_parse_int(const char **regex)
-+static const char *parse_dup_count(const char *s, int *n)
- {
-- int num = -1;
-- const char *r = *regex;
-- while (*r-'0'<10U)
-- {
-- if (num < 0)
-- num = 0;
-- num = num * 10 + *r - '0';
-- r++;
-- }
-- *regex = r;
-- return num;
-+ *n = -1;
-+ if (!isdigit(*s))
-+ return s;
-+ *n = 0;
-+ for (;;) {
-+ *n = 10 * *n + (*s - '0');
-+ s++;
-+ if (!isdigit(*s) || *n > RE_DUP_MAX)
-+ break;
-+ }
-+ return s;
- }
-
--
--static reg_errcode_t
--tre_parse_bound(tre_parse_ctx_t *ctx, tre_ast_node_t **result)
-+static reg_errcode_t parse_dup(tre_parse_ctx_t *ctx, const char *s)
- {
-- int min, max;
-- const char *r = ctx->re;
-- int minimal = 0;
--
-- /* Parse number (minimum repetition count). */
-- min = -1;
-- if (*r >= '0' && *r <= '9') {
-- min = tre_parse_int(&r);
-- }
--
-- /* Parse comma and second number (maximum repetition count). */
-- max = min;
-- if (*r == CHAR_COMMA)
-- {
-- r++;
-- max = tre_parse_int(&r);
-- }
--
-- /* Check that the repeat counts are sane. */
-- if ((max >= 0 && min > max) || max > RE_DUP_MAX)
-- return REG_BADBR;
--
-- /* Missing }. */
-- if (!*r)
-- return REG_EBRACE;
--
-- /* Empty contents of {}. */
-- if (r == ctx->re)
-- return REG_BADBR;
--
-- /* Parse the ending '}' or '\}'.*/
-- if (ctx->cflags & REG_EXTENDED)
-- {
-- if (*r != CHAR_RBRACE)
-- return REG_BADBR;
-- r++;
-- }
-- else
-- {
-- if (*r != CHAR_BACKSLASH || *(r + 1) != CHAR_RBRACE)
-- return REG_BADBR;
-- r += 2;
-- }
--
-- /* Create the AST node(s). */
-- if (min == 0 && max == 0)
-- {
-- *result = tre_ast_new_literal(ctx->mem, EMPTY, -1, -1);
-- if (*result == NULL)
-- return REG_ESPACE;
-- }
-- else
-- {
-- if (min < 0 && max < 0)
-- /* Only approximate parameters set, no repetitions. */
-- min = max = 1;
--
-- *result = tre_ast_new_iter(ctx->mem, *result, min, max, minimal);
-- if (!*result)
-- return REG_ESPACE;
-- }
--
-- ctx->re = r;
-- return REG_OK;
-+ int min, max;
-+
-+ s = parse_dup_count(s, &min);
-+ if (*s == ',')
-+ s = parse_dup_count(s+1, &max);
-+ else
-+ max = min;
-+
-+ if (
-+ (max < min && max >= 0) ||
-+ max > RE_DUP_MAX ||
-+ min > RE_DUP_MAX ||
-+ min < 0 ||
-+ (!(ctx->cflags & REG_EXTENDED) && *s++ != '\\') ||
-+ *s++ != '}'
-+ )
-+ return REG_BADBR;
-+
-+ if (min == 0 && max == 0)
-+ ctx->n = tre_ast_new_literal(ctx->mem, EMPTY, -1, -1);
-+ else
-+ ctx->n = tre_ast_new_iter(ctx->mem, ctx->n, min, max, 0);
-+ if (!ctx->n)
-+ return REG_ESPACE;
-+ ctx->s = s;
-+ return REG_OK;
- }
-
--typedef enum {
-- PARSE_RE = 0,
-- PARSE_ATOM,
-- PARSE_MARK_FOR_SUBMATCH,
-- PARSE_BRANCH,
-- PARSE_PIECE,
-- PARSE_CATENATION,
-- PARSE_POST_CATENATION,
-- PARSE_UNION,
-- PARSE_POST_UNION,
-- PARSE_POSTFIX,
-- PARSE_RESTORE_CFLAGS
--} tre_parse_re_stack_symbol_t;
--
--
--static reg_errcode_t
--tre_parse(tre_parse_ctx_t *ctx)
-+static int hexval(unsigned c)
- {
-- tre_ast_node_t *result = NULL;
-- tre_parse_re_stack_symbol_t symbol;
-- reg_errcode_t status = REG_OK;
-- tre_stack_t *stack = ctx->stack;
-- int bottom = tre_stack_num_objects(stack);
-- int depth = 0;
-- wchar_t wc;
-- int clen;
--
-- if (!ctx->nofirstsub)
-- {
-- STACK_PUSH(stack, int, ctx->submatch_id);
-- STACK_PUSH(stack, int, PARSE_MARK_FOR_SUBMATCH);
-- ctx->submatch_id++;
-- }
-- STACK_PUSH(stack, int, PARSE_RE);
-- ctx->re_start = ctx->re;
--
--
-- /* The following is basically just a recursive descent parser. I use
-- an explicit stack instead of recursive functions mostly because of
-- two reasons: compatibility with systems which have an overflowable
-- call stack, and efficiency (both in lines of code and speed). */
-- while (tre_stack_num_objects(stack) > bottom && status == REG_OK)
-- {
-- if (status != REG_OK)
-- break;
-- symbol = tre_stack_pop_int(stack);
-- switch (symbol)
-- {
-- case PARSE_RE:
-- /* Parse a full regexp. A regexp is one or more branches,
-- separated by the union operator `|'. */
-- if (ctx->cflags & REG_EXTENDED)
-- STACK_PUSHX(stack, int, PARSE_UNION);
-- STACK_PUSHX(stack, int, PARSE_BRANCH);
-- break;
--
-- case PARSE_BRANCH:
-- /* Parse a branch. A branch is one or more pieces, concatenated.
-- A piece is an atom possibly followed by a postfix operator. */
-- STACK_PUSHX(stack, int, PARSE_CATENATION);
-- STACK_PUSHX(stack, int, PARSE_PIECE);
-- break;
--
-- case PARSE_PIECE:
-- /* Parse a piece. A piece is an atom possibly followed by one
-- or more postfix operators. */
-- STACK_PUSHX(stack, int, PARSE_POSTFIX);
-- STACK_PUSHX(stack, int, PARSE_ATOM);
-- break;
--
-- case PARSE_CATENATION:
-- /* If the expression has not ended, parse another piece. */
-- {
-- tre_char_t c;
-- if (!*ctx->re)
-- break;
-- c = *ctx->re;
-- if (ctx->cflags & REG_EXTENDED && c == CHAR_PIPE)
-- break;
-- if ((ctx->cflags & REG_EXTENDED
-- && c == CHAR_RPAREN && depth > 0)
-- || (!(ctx->cflags & REG_EXTENDED)
-- && (c == CHAR_BACKSLASH
-- && *(ctx->re + 1) == CHAR_RPAREN)))
-- {
-- if (!(ctx->cflags & REG_EXTENDED) && depth == 0)
-- status = REG_EPAREN;
-- depth--;
-- if (!(ctx->cflags & REG_EXTENDED))
-- ctx->re += 2;
-- break;
-- }
--
-- {
-- /* Default case, left associative concatenation. */
-- STACK_PUSHX(stack, int, PARSE_CATENATION);
-- STACK_PUSHX(stack, voidptr, result);
-- STACK_PUSHX(stack, int, PARSE_POST_CATENATION);
-- STACK_PUSHX(stack, int, PARSE_PIECE);
-- }
-- break;
-- }
--
-- case PARSE_POST_CATENATION:
-- {
-- tre_ast_node_t *tree = tre_stack_pop_voidptr(stack);
-- tre_ast_node_t *tmp_node;
-- tmp_node = tre_ast_new_catenation(ctx->mem, tree, result);
-- if (!tmp_node)
-- return REG_ESPACE;
-- result = tmp_node;
-- break;
-- }
--
-- case PARSE_UNION:
-- switch (*ctx->re)
-- {
-- case CHAR_PIPE:
-- STACK_PUSHX(stack, int, PARSE_UNION);
-- STACK_PUSHX(stack, voidptr, result);
-- STACK_PUSHX(stack, int, PARSE_POST_UNION);
-- STACK_PUSHX(stack, int, PARSE_BRANCH);
-- ctx->re++;
-- break;
--
-- case CHAR_RPAREN:
-- ctx->re++;
-- break;
--
-- default:
-- break;
-- }
-- break;
--
-- case PARSE_POST_UNION:
-- {
-- tre_ast_node_t *tmp_node;
-- tre_ast_node_t *tree = tre_stack_pop_voidptr(stack);
-- tmp_node = tre_ast_new_union(ctx->mem, tree, result);
-- if (!tmp_node)
-- return REG_ESPACE;
-- result = tmp_node;
-- break;
-- }
--
-- case PARSE_POSTFIX:
-- /* Parse postfix operators. */
-- switch (*ctx->re)
-- {
-- case CHAR_PLUS:
-- case CHAR_QUESTIONMARK:
-- if (!(ctx->cflags & REG_EXTENDED))
-- break;
-- /*FALLTHROUGH*/
-- case CHAR_STAR:
-- {
-- tre_ast_node_t *tmp_node;
-- int minimal = 0;
-- int rep_min = 0;
-- int rep_max = -1;
--
-- if (*ctx->re == CHAR_PLUS)
-- rep_min = 1;
-- if (*ctx->re == CHAR_QUESTIONMARK)
-- rep_max = 1;
--
-- ctx->re++;
-- tmp_node = tre_ast_new_iter(ctx->mem, result, rep_min, rep_max,
-- minimal);
-- if (tmp_node == NULL)
-- return REG_ESPACE;
-- result = tmp_node;
-- STACK_PUSHX(stack, int, PARSE_POSTFIX);
-- }
-- break;
--
-- case CHAR_BACKSLASH:
-- /* "\{" is special without REG_EXTENDED */
-- if (!(ctx->cflags & REG_EXTENDED)
-- && *(ctx->re + 1) == CHAR_LBRACE)
-- {
-- ctx->re++;
-- goto parse_brace;
-- }
-- else
-- break;
--
-- case CHAR_LBRACE:
-- /* "{" is literal without REG_EXTENDED */
-- if (!(ctx->cflags & REG_EXTENDED))
-- break;
--
-- parse_brace:
-- ctx->re++;
-+ if (c-'0'<10) return c-'0';
-+ c |= 32;
-+ if (c-'a'<6) return c-'a'+10;
-+ return -1;
-+}
-
-- status = tre_parse_bound(ctx, &result);
-- if (status != REG_OK)
-- return status;
-- STACK_PUSHX(stack, int, PARSE_POSTFIX);
-- break;
-- }
-- break;
-+static reg_errcode_t marksub(tre_parse_ctx_t *ctx, tre_ast_node_t *node, int subid)
-+{
-+ if (node->submatch_id >= 0) {
-+ tre_ast_node_t *n = tre_ast_new_literal(ctx->mem, EMPTY, -1, -1);
-+ if (!n)
-+ return REG_ESPACE;
-+ n = tre_ast_new_catenation(ctx->mem, n, node);
-+ if (!n)
-+ return REG_ESPACE;
-+ n->num_submatches = node->num_submatches;
-+ node = n;
-+ }
-+ node->submatch_id = subid;
-+ node->num_submatches++;
-+ ctx->n = node;
-+ return REG_OK;
-+}
-
-- case PARSE_ATOM:
-- /* Parse an atom. An atom is a regular expression enclosed in `()',
-- an empty set of `()', a bracket expression, `.', `^', `$',
-- a `\' followed by a character, or a single character. */
-+/*
-+BRE grammar:
-+Regex = Branch | '^' | '$' | '^$' | '^' Branch | Branch '$' | '^' Branch '$'
-+Branch = Atom | Branch Atom
-+Atom = char | quoted_char | '.' | Bracket | Atom Dup | '\(' Branch '\)' | back_ref
-+Dup = '*' | '\{' Count '\}' | '\{' Count ',\}' | '\{' Count ',' Count '\}'
-
-- switch (*ctx->re)
-- {
-- case CHAR_LPAREN: /* parenthesized subexpression */
-+(leading ^ and trailing $ in a sub expr may be an anchor or literal as well)
-
-- if (ctx->cflags & REG_EXTENDED)
-- {
-- lparen:
-- depth++;
-- {
-- ctx->re++;
-- /* First parse a whole RE, then mark the resulting tree
-- for submatching. */
-- STACK_PUSHX(stack, int, ctx->submatch_id);
-- STACK_PUSHX(stack, int, PARSE_MARK_FOR_SUBMATCH);
-- STACK_PUSHX(stack, int, PARSE_RE);
-- ctx->submatch_id++;
-- }
-- }
-- else
-- goto parse_literal;
-- break;
-+ERE grammar:
-+Regex = Branch | Regex '|' Branch
-+Branch = Atom | Branch Atom
-+Atom = char | quoted_char | '.' | Bracket | Atom Dup | '(' Regex ')' | '^' | '$'
-+Dup = '*' | '+' | '?' | '{' Count '}' | '{' Count ',}' | '{' Count ',' Count '}'
-
-- case CHAR_LBRACKET: /* bracket expression */
-- ctx->re++;
-- status = tre_parse_bracket(ctx, &result);
-- if (status != REG_OK)
-- return status;
-- break;
-+(a*+?, ^*, $+, \X, {, (|a) are unspecified)
-+*/
-
-- case CHAR_BACKSLASH:
-- /* If this is "\(" or "\)" chew off the backslash and
-- try again. */
-- if (!(ctx->cflags & REG_EXTENDED) && *(ctx->re + 1) == CHAR_LPAREN)
-- {
-- ctx->re++;
-- goto lparen;
-- }
-- if (!(ctx->cflags & REG_EXTENDED) && *(ctx->re + 1) == CHAR_RPAREN)
-- {
-- goto empty_atom;
-+static reg_errcode_t parse_atom(tre_parse_ctx_t *ctx, const char *s)
-+{
-+ int len, ere = ctx->cflags & REG_EXTENDED;
-+ const char *p;
-+ tre_ast_node_t *node;
-+ wchar_t wc;
-+ switch (*s) {
-+ case '[':
-+ return parse_bracket(ctx, s+1);
-+ case '\\':
-+ p = tre_expand_macro(s+1);
-+ if (p) {
-+ /* assume \X expansion is a single atom */
-+ reg_errcode_t err = parse_atom(ctx, p);
-+ ctx->s = s+2;
-+ return err;
- }
--
-- /* If a macro is used, parse the expanded macro recursively. */
-- {
-- const char *buf = tre_expand_macro(ctx->re + 1);
-- if (buf)
-- {
-- tre_parse_ctx_t subctx;
-- memcpy(&subctx, ctx, sizeof(subctx));
-- subctx.re = buf;
-- subctx.nofirstsub = 1;
-- status = tre_parse(&subctx);
-- if (status != REG_OK)
-- return status;
-- ctx->re += 2;
-- ctx->position = subctx.position;
-- result = subctx.result;
-- break;
-- }
-- }
--
-- if (!ctx->re[1])
-- /* Trailing backslash. */
-- return REG_EESCAPE;
--
-- ctx->re++;
-- switch (*ctx->re)
-- {
-+ /* extensions: \b, \B, \<, \>, \xHH \x{HHHH} */
-+ switch (*++s) {
-+ case 0:
-+ return REG_EESCAPE;
- case 'b':
-- result = tre_ast_new_literal(ctx->mem, ASSERTION,
-- ASSERT_AT_WB, -1);
-- ctx->re++;
-- break;
-+ node = tre_ast_new_literal(ctx->mem, ASSERTION, ASSERT_AT_WB, -1);
-+ break;
- case 'B':
-- result = tre_ast_new_literal(ctx->mem, ASSERTION,
-- ASSERT_AT_WB_NEG, -1);
-- ctx->re++;
-- break;
-+ node = tre_ast_new_literal(ctx->mem, ASSERTION, ASSERT_AT_WB_NEG, -1);
-+ break;
- case '<':
-- result = tre_ast_new_literal(ctx->mem, ASSERTION,
-- ASSERT_AT_BOW, -1);
-- ctx->re++;
-- break;
-+ node = tre_ast_new_literal(ctx->mem, ASSERTION, ASSERT_AT_BOW, -1);
-+ break;
- case '>':
-- result = tre_ast_new_literal(ctx->mem, ASSERTION,
-- ASSERT_AT_EOW, -1);
-- ctx->re++;
-- break;
-+ node = tre_ast_new_literal(ctx->mem, ASSERTION, ASSERT_AT_EOW, -1);
-+ break;
- case 'x':
-- ctx->re++;
-- if (ctx->re[0] != CHAR_LBRACE)
-- {
-- /* 8 bit hex char. */
-- char tmp[3] = {0, 0, 0};
-- long val;
--
-- if (tre_isxdigit(ctx->re[0]))
-- {
-- tmp[0] = (char)ctx->re[0];
-- ctx->re++;
-+ s++;
-+ int i, v = 0, c;
-+ len = 2;
-+ if (*s == '{') {
-+ len = 8;
-+ s++;
- }
-- if (tre_isxdigit(ctx->re[0]))
-- {
-- tmp[1] = (char)ctx->re[0];
-- ctx->re++;
-+ for (i=0; i<len && v<0x110000; i++) {
-+ c = hexval(s[i]);
-+ if (c < 0) break;
-+ v = 16*v + c;
- }
-- val = strtol(tmp, NULL, 16);
-- result = tre_ast_new_literal(ctx->mem, (int)val,
-- (int)val, ctx->position);
-- ctx->position++;
-- break;
-- }
-- else if (*ctx->re)
-- {
-- /* Wide char. */
-- char tmp[32];
-- long val;
-- int i = 0;
-- ctx->re++;
-- while (*ctx->re && i < sizeof tmp)
-- {
-- if (ctx->re[0] == CHAR_RBRACE)
-- break;
-- if (tre_isxdigit(ctx->re[0]))
-- {
-- tmp[i] = (char)ctx->re[0];
-- i++;
-- ctx->re++;
-- continue;
-- }
-- return REG_EBRACE;
-+ s += i;
-+ if (len == 8) {
-+ if (*s != '}')
-+ return REG_EBRACE;
-+ s++;
- }
-- ctx->re++;
-- tmp[i] = 0;
-- val = strtol(tmp, NULL, 16);
-- result = tre_ast_new_literal(ctx->mem, (int)val, (int)val,
-- ctx->position);
-- ctx->position++;
-- break;
-- }
-- /*FALLTHROUGH*/
--
-+ node = tre_ast_new_literal(ctx->mem, v, v, ctx->position);
-+ ctx->position++;
-+ s--;
-+ break;
- default:
-- if (tre_isdigit(*ctx->re))
-- {
-- /* Back reference. */
-- int val = *ctx->re - '0';
-- result = tre_ast_new_literal(ctx->mem, BACKREF, val,
-- ctx->position);
-- if (result == NULL)
-- return REG_ESPACE;
-- ctx->position++;
-- ctx->max_backref = MAX(val, ctx->max_backref);
-- ctx->re++;
-- }
-- else
-- {
-- /* Escaped character. */
-- result = tre_ast_new_literal(ctx->mem, *ctx->re, *ctx->re,
-- ctx->position);
-- ctx->position++;
-- ctx->re++;
-- }
-- break;
-- }
-- if (result == NULL)
-- return REG_ESPACE;
-- break;
--
-- case CHAR_PERIOD: /* the any-symbol */
-- if (ctx->cflags & REG_NEWLINE)
-- {
-- tre_ast_node_t *tmp1;
-- tre_ast_node_t *tmp2;
-- tmp1 = tre_ast_new_literal(ctx->mem, 0, '\n' - 1,
-- ctx->position);
-- if (!tmp1)
-- return REG_ESPACE;
-- tmp2 = tre_ast_new_literal(ctx->mem, '\n' + 1, TRE_CHAR_MAX,
-- ctx->position + 1);
-- if (!tmp2)
-- return REG_ESPACE;
-- result = tre_ast_new_union(ctx->mem, tmp1, tmp2);
-- if (!result)
-- return REG_ESPACE;
-- ctx->position += 2;
-- }
-- else
-- {
-- result = tre_ast_new_literal(ctx->mem, 0, TRE_CHAR_MAX,
-- ctx->position);
-- if (!result)
-- return REG_ESPACE;
-- ctx->position++;
-+ if (isdigit(*s)) {
-+ /* back reference */
-+ int val = *s - '0';
-+ node = tre_ast_new_literal(ctx->mem, BACKREF, val, ctx->position);
-+ ctx->max_backref = MAX(val, ctx->max_backref);
-+ } else {
-+ /* extension: accept unknown escaped char
-+ as a literal */
-+ node = tre_ast_new_literal(ctx->mem, *s, *s, ctx->position);
-+ }
-+ ctx->position++;
- }
-- ctx->re++;
-- break;
--
-- case CHAR_CARET: /* beginning of line assertion */
-- /* '^' has a special meaning everywhere in EREs, and at
-- beginning of BRE. */
-- if (ctx->cflags & REG_EXTENDED
-- || ctx->re == ctx->re_start)
-- {
-- if (!(ctx->cflags & REG_EXTENDED))
-- STACK_PUSHX(stack, int, PARSE_CATENATION);
-- result = tre_ast_new_literal(ctx->mem, ASSERTION,
-- ASSERT_AT_BOL, -1);
-- if (result == NULL)
-- return REG_ESPACE;
-- ctx->re++;
-+ s++;
-+ break;
-+ case '.':
-+ if (ctx->cflags & REG_NEWLINE) {
-+ tre_ast_node_t *tmp1, *tmp2;
-+ tmp1 = tre_ast_new_literal(ctx->mem, 0, '\n'-1, ctx->position++);
-+ tmp2 = tre_ast_new_literal(ctx->mem, '\n'+1, TRE_CHAR_MAX, ctx->position++);
-+ if (tmp1 && tmp2)
-+ node = tre_ast_new_union(ctx->mem, tmp1, tmp2);
-+ else
-+ node = 0;
-+ } else {
-+ node = tre_ast_new_literal(ctx->mem, 0, TRE_CHAR_MAX, ctx->position++);
- }
-- else
-- goto parse_literal;
-- break;
--
-- case CHAR_DOLLAR: /* end of line assertion. */
-- /* '$' is special everywhere in EREs, and in the end of the
-- string in BREs. */
-- if (ctx->cflags & REG_EXTENDED
-- || !*(ctx->re + 1))
-- {
-- result = tre_ast_new_literal(ctx->mem, ASSERTION,
-- ASSERT_AT_EOL, -1);
-- if (result == NULL)
-- return REG_ESPACE;
-- ctx->re++;
-+ s++;
-+ break;
-+ case '^':
-+ /* '^' has a special meaning everywhere in EREs, and at beginning of BRE. */
-+ if (!ere && s != ctx->re)
-+ goto parse_literal;
-+ node = tre_ast_new_literal(ctx->mem, ASSERTION, ASSERT_AT_BOL, -1);
-+ s++;
-+ break;
-+ case '$':
-+ /* '$' is special everywhere in EREs, and in the end of the string in BREs. */
-+ if (!ere && s[1])
-+ goto parse_literal;
-+ node = tre_ast_new_literal(ctx->mem, ASSERTION, ASSERT_AT_EOL, -1);
-+ s++;
-+ break;
-+ case '*':
-+ case '|':
-+ case '{':
-+ case '+':
-+ case '?':
-+ if (!ere)
-+ goto parse_literal;
-+ case 0:
-+ node = tre_ast_new_literal(ctx->mem, EMPTY, -1, -1);
-+ break;
-+ default:
-+parse_literal:
-+ len = mbtowc(&wc, s, -1);
-+ if (len < 0)
-+ return REG_BADPAT;
-+ if (ctx->cflags & REG_ICASE && (tre_isupper(wc) || tre_islower(wc))) {
-+ tre_ast_node_t *tmp1, *tmp2;
-+ /* multiple opposite case characters are not supported */
-+ tmp1 = tre_ast_new_literal(ctx->mem, tre_toupper(wc), tre_toupper(wc), ctx->position);
-+ tmp2 = tre_ast_new_literal(ctx->mem, tre_tolower(wc), tre_tolower(wc), ctx->position);
-+ if (tmp1 && tmp2)
-+ node = tre_ast_new_union(ctx->mem, tmp1, tmp2);
-+ else
-+ node = 0;
-+ } else {
-+ node = tre_ast_new_literal(ctx->mem, wc, wc, ctx->position);
- }
-- else
-- goto parse_literal;
-- break;
--
-- case CHAR_RPAREN:
-- if (!depth)
-- goto parse_literal;
-- case CHAR_STAR:
-- case CHAR_PIPE:
-- case CHAR_LBRACE:
-- case CHAR_PLUS:
-- case CHAR_QUESTIONMARK:
-- if (!(ctx->cflags & REG_EXTENDED))
-- goto parse_literal;
--
-- case 0:
-- empty_atom:
-- result = tre_ast_new_literal(ctx->mem, EMPTY, -1, -1);
-- if (!result)
-+ ctx->position++;
-+ s += len;
-+ break;
-+ }
-+ if (!node)
- return REG_ESPACE;
-- break;
-+ ctx->n = node;
-+ ctx->s = s;
-+ return REG_OK;
-+}
-
-- default:
-- parse_literal:
-+#define PUSHPTR(err, s, v) do { \
-+ if ((err = tre_stack_push_voidptr(s, v)) != REG_OK) \
-+ return err; \
-+} while(0)
-
-- clen = mbtowc(&wc, ctx->re, -1);
-- if (clen<0) clen=1, wc=WEOF;
-+#define PUSHINT(err, s, v) do { \
-+ if ((err = tre_stack_push_int(s, v)) != REG_OK) \
-+ return err; \
-+} while(0)
-
-- /* Note that we can't use an tre_isalpha() test here, since there
-- may be characters which are alphabetic but neither upper or
-- lower case. */
-- if (ctx->cflags & REG_ICASE
-- && (tre_isupper(wc) || tre_islower(wc)))
-- {
-- tre_ast_node_t *tmp1;
-- tre_ast_node_t *tmp2;
--
-- /* XXX - Can there be more than one opposite-case
-- counterpoints for some character in some locale? Or
-- more than two characters which all should be regarded
-- the same character if case is ignored? If yes, there
-- does not seem to be a portable way to detect it. I guess
-- that at least for multi-character collating elements there
-- could be several opposite-case counterpoints, but they
-- cannot be supported portably anyway. */
-- tmp1 = tre_ast_new_literal(ctx->mem, tre_toupper(wc),
-- tre_toupper(wc),
-- ctx->position);
-- if (!tmp1)
-- return REG_ESPACE;
-- tmp2 = tre_ast_new_literal(ctx->mem, tre_tolower(wc),
-- tre_tolower(wc),
-- ctx->position);
-- if (!tmp2)
-- return REG_ESPACE;
-- result = tre_ast_new_union(ctx->mem, tmp1, tmp2);
-- if (!result)
-- return REG_ESPACE;
-+static reg_errcode_t tre_parse(tre_parse_ctx_t *ctx)
-+{
-+ tre_ast_node_t *nbranch=0, *nunion=0;
-+ int ere = ctx->cflags & REG_EXTENDED;
-+ const char *s = ctx->re;
-+ int subid = 0;
-+ int depth = 0;
-+ reg_errcode_t err;
-+ tre_stack_t *stack = ctx->stack;
-+
-+ PUSHINT(err, stack, subid++);
-+ for (;;) {
-+ if ((!ere && *s == '\\' && s[1] == '(') ||
-+ (ere && *s == '(')) {
-+ PUSHPTR(err, stack, nunion);
-+ PUSHPTR(err, stack, nbranch);
-+ PUSHINT(err, stack, subid++);
-+ s++;
-+ if (!ere)
-+ s++;
-+ depth++;
-+ nbranch = nunion = 0;
-+ continue;
- }
-- else
-- {
-- result = tre_ast_new_literal(ctx->mem, wc, wc,
-- ctx->position);
-- if (!result)
-- return REG_ESPACE;
-+ if ((!ere && *s == '\\' && s[1] == ')') ||
-+ (ere && *s == ')' && depth)) {
-+ ctx->n = tre_ast_new_literal(ctx->mem, EMPTY, -1, -1);
-+ if (!ctx->n)
-+ return REG_ESPACE;
-+ } else {
-+ err = parse_atom(ctx, s);
-+ if (err != REG_OK)
-+ return err;
-+ s = ctx->s;
- }
-- ctx->position++;
-- ctx->re += clen;
-- break;
-- }
-- break;
--
-- case PARSE_MARK_FOR_SUBMATCH:
-- {
-- int submatch_id = tre_stack_pop_int(stack);
-
-- if (result->submatch_id >= 0)
-- {
-- tre_ast_node_t *n, *tmp_node;
-- n = tre_ast_new_literal(ctx->mem, EMPTY, -1, -1);
-- if (n == NULL)
-- return REG_ESPACE;
-- tmp_node = tre_ast_new_catenation(ctx->mem, n, result);
-- if (tmp_node == NULL)
-- return REG_ESPACE;
-- tmp_node->num_submatches = result->num_submatches;
-- result = tmp_node;
-- }
-- result->submatch_id = submatch_id;
-- result->num_submatches++;
-- break;
-- }
--
-- case PARSE_RESTORE_CFLAGS:
-- ctx->cflags = tre_stack_pop_int(stack);
-- break;
-+ parse_iter:
-+ /* extension: repetitions are accepted after an empty node
-+ eg. (+), ^*, a$?, a|{2} */
-+ switch (*s) {
-+ case '+':
-+ case '?':
-+ if (!ere)
-+ break;
-+ /* fallthrough */
-+ case '*':;
-+ int min=0, max=-1;
-+ if (*s == '+')
-+ min = 1;
-+ if (*s == '?')
-+ max = 1;
-+ s++;
-+ ctx->n = tre_ast_new_iter(ctx->mem, ctx->n, min, max, 0);
-+ if (!ctx->n)
-+ return REG_ESPACE;
-+ /* extension: multiple consecutive *+?{,} is unspecified,
-+ but (a+)+ has to be supported so accepting a++ makes
-+ sense, note however that the RE_DUP_MAX limit can be
-+ circumvented: (a{255}){255} uses a lot of memory.. */
-+ goto parse_iter;
-+ case '\\':
-+ if (ere || s[1] != '{')
-+ break;
-+ s++;
-+ goto parse_brace;
-+ case '{':
-+ if (!ere)
-+ break;
-+ parse_brace:
-+ err = parse_dup(ctx, s+1);
-+ if (err != REG_OK)
-+ return err;
-+ s = ctx->s;
-+ goto parse_iter;
-+ }
-
-- default:
-- assert(0);
-- break;
-+ nbranch = tre_ast_new_catenation(ctx->mem, nbranch, ctx->n);
-+ if ((ere && *s == '|') ||
-+ (ere && *s == ')' && depth) ||
-+ (!ere && *s == '\\' && s[1] == ')') ||
-+ !*s) {
-+ /* extension: empty branch is unspecified (), (|a), (a|)
-+ here they are not rejected but match on empty string */
-+ int c = *s;
-+ nunion = tre_ast_new_union(ctx->mem, nunion, nbranch);
-+ nbranch = 0;
-+ if (c != '|') {
-+ if (c == '\\') {
-+ if (!depth) return REG_EPAREN;
-+ s+=2;
-+ } else if (c == ')')
-+ s++;
-+ depth--;
-+ err = marksub(ctx, nunion, tre_stack_pop_int(stack));
-+ if (err != REG_OK)
-+ return err;
-+ if (!c && depth<0) {
-+ ctx->submatch_id = subid;
-+ return REG_OK;
-+ }
-+ if (!c || depth<0)
-+ return REG_EPAREN;
-+ nbranch = tre_stack_pop_voidptr(stack);
-+ nunion = tre_stack_pop_voidptr(stack);
-+ goto parse_iter;
-+ }
-+ s++;
-+ }
- }
-- }
--
-- /* Check for missing closing parentheses. */
-- if (depth > 0)
-- return REG_EPAREN;
--
-- if (status == REG_OK)
-- ctx->result = result;
--
-- return status;
- }
-
-
--
- /***********************************************************************
- from tre-compile.c
- ***********************************************************************/
-@@ -3122,12 +2680,7 @@ regcomp(regex_t *restrict preg, const char *restrict regex, int cflags)
- if (errcode != REG_OK)
- ERROR_EXIT(errcode);
- preg->re_nsub = parse_ctx.submatch_id - 1;
-- tree = parse_ctx.result;
--
-- /* Back references and approximate matching cannot currently be used
-- in the same regexp. */
-- if (parse_ctx.max_backref >= 0 && parse_ctx.have_approx)
-- ERROR_EXIT(REG_BADPAT);
-+ tree = parse_ctx.n;
-
- #ifdef TRE_DEBUG
- tre_ast_print(tree);
-@@ -3142,7 +2695,7 @@ regcomp(regex_t *restrict preg, const char *restrict regex, int cflags)
- if (tnfa == NULL)
- ERROR_EXIT(REG_ESPACE);
- tnfa->have_backrefs = parse_ctx.max_backref >= 0;
-- tnfa->have_approx = parse_ctx.have_approx;
-+ tnfa->have_approx = 0;
- tnfa->num_submatches = parse_ctx.submatch_id;
-
- /* Set up tags for submatch addressing. If REG_NOSUB is set and the
-diff --git a/src/regex/regexec.c b/src/regex/regexec.c
-index 2e35b83..16c5d0a 100644
---- a/src/regex/regexec.c
-+++ b/src/regex/regexec.c
-@@ -52,7 +52,7 @@ tre_fill_pmatch(size_t nmatch, regmatch_t pmatch[], int cflags,
- #define GET_NEXT_WCHAR() do { \
- prev_c = next_c; pos += pos_add_next; \
- if ((pos_add_next = mbtowc(&next_c, str_byte, MB_LEN_MAX)) <= 0) { \
-- if (pos_add_next < 0) return REG_NOMATCH; \
-+ if (pos_add_next < 0) { ret = REG_NOMATCH; goto error_exit; } \
- else pos_add_next++; \
- } \
- str_byte += pos_add_next; \
-@@ -181,6 +181,7 @@ tre_tnfa_run_parallel(const tre_tnfa_t *tnfa, const void *string,
- int reg_notbol = eflags & REG_NOTBOL;
- int reg_noteol = eflags & REG_NOTEOL;
- int reg_newline = tnfa->cflags & REG_NEWLINE;
-+ reg_errcode_t ret;
-
- char *buf;
- tre_tnfa_transition_t *trans_i;
-@@ -439,11 +440,11 @@ tre_tnfa_run_parallel(const tre_tnfa_t *tnfa, const void *string,
- reach_next_i->state = NULL;
- }
-
-- if (buf)
-- xfree(buf);
--
- *match_end_ofs = match_eo;
-- return match_eo >= 0 ? REG_OK : REG_NOMATCH;
-+ ret = match_eo >= 0 ? REG_OK : REG_NOMATCH;
-+error_exit:
-+ xfree(buf);
-+ return ret;
- }
-
-
-diff --git a/src/stdio/ftrylockfile.c b/src/stdio/ftrylockfile.c
-index 6f9a4b8..eb13c83 100644
---- a/src/stdio/ftrylockfile.c
-+++ b/src/stdio/ftrylockfile.c
-@@ -34,6 +34,7 @@ int ftrylockfile(FILE *f)
- f->lockcount = 1;
- f->prev_locked = 0;
- f->next_locked = self->stdio_locks;
-+ if (f->next_locked) f->next_locked->prev_locked = f;
- self->stdio_locks = f;
- return 0;
- }
-diff --git a/src/thread/__timedwait.c b/src/thread/__timedwait.c
-index d6f1233..c9ec70c 100644
---- a/src/thread/__timedwait.c
-+++ b/src/thread/__timedwait.c
-@@ -4,6 +4,9 @@
- #include "futex.h"
- #include "syscall.h"
-
-+int __pthread_setcancelstate(int, int *);
-+int __clock_gettime(clockid_t, struct timespec *);
-+
- int __timedwait(volatile int *addr, int val,
- clockid_t clk, const struct timespec *at,
- void (*cleanup)(void *), void *arg, int priv)
-@@ -15,7 +18,7 @@ int __timedwait(volatile int *addr, int val,
-
- if (at) {
- if (at->tv_nsec >= 1000000000UL) return EINVAL;
-- if (clock_gettime(clk, &to)) return EINVAL;
-+ if (__clock_gettime(clk, &to)) return EINVAL;
- to.tv_sec = at->tv_sec - to.tv_sec;
- if ((to.tv_nsec = at->tv_nsec - to.tv_nsec) < 0) {
- to.tv_sec--;
-@@ -25,7 +28,7 @@ int __timedwait(volatile int *addr, int val,
- top = &to;
- }
-
-- if (!cleanup) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
-+ if (!cleanup) __pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
- pthread_cleanup_push(cleanup, arg);
-
- r = -__syscall_cp(SYS_futex, addr, FUTEX_WAIT|priv, val, top);
-@@ -33,7 +36,7 @@ int __timedwait(volatile int *addr, int val,
- if (r != EINTR && r != ETIMEDOUT) r = 0;
-
- pthread_cleanup_pop(0);
-- if (!cleanup) pthread_setcancelstate(cs, 0);
-+ if (!cleanup) __pthread_setcancelstate(cs, 0);
-
- return r;
- }
-diff --git a/src/thread/call_once.c b/src/thread/call_once.c
-new file mode 100644
-index 0000000..a7bc935
---- /dev/null
-+++ b/src/thread/call_once.c
-@@ -0,0 +1,8 @@
-+#include <threads.h>
-+
-+int __pthread_once(once_flag *, void (*)(void));
-+
-+void call_once(once_flag *flag, void (*func)(void))
-+{
-+ __pthread_once(flag, func);
-+}
-diff --git a/src/thread/cnd_broadcast.c b/src/thread/cnd_broadcast.c
-new file mode 100644
-index 0000000..85d4d3e
---- /dev/null
-+++ b/src/thread/cnd_broadcast.c
-@@ -0,0 +1,10 @@
-+#include <threads.h>
-+
-+int __private_cond_signal(cnd_t *, int);
-+
-+int cnd_broadcast(cnd_t *c)
-+{
-+ /* This internal function never fails, and always returns zero,
-+ * which matches the value thrd_success is defined with. */
-+ return __private_cond_signal(c, -1);
-+}
-diff --git a/src/thread/cnd_destroy.c b/src/thread/cnd_destroy.c
-new file mode 100644
-index 0000000..453c90b
---- /dev/null
-+++ b/src/thread/cnd_destroy.c
-@@ -0,0 +1,6 @@
-+#include <threads.h>
-+
-+void cnd_destroy(cnd_t *c)
-+{
-+ /* For private cv this is a no-op */
-+}
-diff --git a/src/thread/cnd_init.c b/src/thread/cnd_init.c
-new file mode 100644
-index 0000000..18c5085
---- /dev/null
-+++ b/src/thread/cnd_init.c
-@@ -0,0 +1,7 @@
-+#include <threads.h>
-+
-+int cnd_init(cnd_t *c)
-+{
-+ *c = (cnd_t){ 0 };
-+ return thrd_success;
-+}
-diff --git a/src/thread/cnd_signal.c b/src/thread/cnd_signal.c
-new file mode 100644
-index 0000000..1211260
---- /dev/null
-+++ b/src/thread/cnd_signal.c
-@@ -0,0 +1,10 @@
-+#include <threads.h>
-+
-+int __private_cond_signal(cnd_t *, int);
-+
-+int cnd_signal(cnd_t *c)
-+{
-+ /* This internal function never fails, and always returns zero,
-+ * which matches the value thrd_success is defined with. */
-+ return __private_cond_signal(c, 1);
-+}
-diff --git a/src/thread/cnd_timedwait.c b/src/thread/cnd_timedwait.c
-new file mode 100644
-index 0000000..5997679
---- /dev/null
-+++ b/src/thread/cnd_timedwait.c
-@@ -0,0 +1,15 @@
-+#include <threads.h>
-+#include <errno.h>
-+
-+int __pthread_cond_timedwait(cnd_t *restrict, mtx_t *restrict, const struct timespec *restrict);
-+
-+int cnd_timedwait(cnd_t *restrict c, mtx_t *restrict m, const struct timespec *restrict ts)
-+{
-+ int ret = __pthread_cond_timedwait(c, m, ts);
-+ switch (ret) {
-+ /* May also return EINVAL or EPERM. */
-+ default: return thrd_error;
-+ case 0: return thrd_success;
-+ case ETIMEDOUT: return thrd_timedout;
-+ }
-+}
-diff --git a/src/thread/cnd_wait.c b/src/thread/cnd_wait.c
-new file mode 100644
-index 0000000..602796f
---- /dev/null
-+++ b/src/thread/cnd_wait.c
-@@ -0,0 +1,9 @@
-+#include <threads.h>
-+
-+int cnd_wait(cnd_t *c, mtx_t *m)
-+{
-+ /* Calling cnd_timedwait with a null pointer is an extension.
-+ * It is convenient here to avoid duplication of the logic
-+ * for return values. */
-+ return cnd_timedwait(c, m, 0);
-+}
-diff --git a/src/thread/mtx_destroy.c b/src/thread/mtx_destroy.c
-new file mode 100644
-index 0000000..40a0899
---- /dev/null
-+++ b/src/thread/mtx_destroy.c
-@@ -0,0 +1,5 @@
-+#include <threads.h>
-+
-+void mtx_destroy(mtx_t *mtx)
-+{
-+}
-diff --git a/src/thread/mtx_init.c b/src/thread/mtx_init.c
-new file mode 100644
-index 0000000..4826f76
---- /dev/null
-+++ b/src/thread/mtx_init.c
-@@ -0,0 +1,10 @@
-+#include "pthread_impl.h"
-+#include <threads.h>
-+
-+int mtx_init(mtx_t *m, int type)
-+{
-+ *m = (mtx_t){
-+ ._m_type = ((type&mtx_recursive) ? PTHREAD_MUTEX_RECURSIVE : PTHREAD_MUTEX_NORMAL),
-+ };
-+ return thrd_success;
-+}
-diff --git a/src/thread/mtx_lock.c b/src/thread/mtx_lock.c
-new file mode 100644
-index 0000000..5c2415c
---- /dev/null
-+++ b/src/thread/mtx_lock.c
-@@ -0,0 +1,12 @@
-+#include "pthread_impl.h"
-+#include <threads.h>
-+
-+int mtx_lock(mtx_t *m)
-+{
-+ if (m->_m_type == PTHREAD_MUTEX_NORMAL && !a_cas(&m->_m_lock, 0, EBUSY))
-+ return thrd_success;
-+ /* Calling mtx_timedlock with a null pointer is an extension.
-+ * It is convenient, here to avoid duplication of the logic
-+ * for return values. */
-+ return mtx_timedlock(m, 0);
-+}
-diff --git a/src/thread/mtx_timedlock.c b/src/thread/mtx_timedlock.c
-new file mode 100644
-index 0000000..bcc152c
---- /dev/null
-+++ b/src/thread/mtx_timedlock.c
-@@ -0,0 +1,14 @@
-+#include <threads.h>
-+#include <errno.h>
-+
-+int __pthread_mutex_timedlock(mtx_t *restrict, const struct timespec *restrict);
-+
-+int mtx_timedlock(mtx_t *restrict m, const struct timespec *restrict ts)
-+{
-+ int ret = __pthread_mutex_timedlock(m, ts);
-+ switch (ret) {
-+ default: return thrd_error;
-+ case 0: return thrd_success;
-+ case ETIMEDOUT: return thrd_timedout;
-+ }
-+}
-diff --git a/src/thread/mtx_trylock.c b/src/thread/mtx_trylock.c
-new file mode 100644
-index 0000000..61e7694
---- /dev/null
-+++ b/src/thread/mtx_trylock.c
-@@ -0,0 +1,17 @@
-+#include "pthread_impl.h"
-+#include <threads.h>
-+
-+int __pthread_mutex_trylock(mtx_t *);
-+
-+int mtx_trylock(mtx_t *m)
-+{
-+ if (m->_m_type == PTHREAD_MUTEX_NORMAL)
-+ return (a_cas(&m->_m_lock, 0, EBUSY) & EBUSY) ? thrd_busy : thrd_success;
-+
-+ int ret = __pthread_mutex_trylock(m);
-+ switch (ret) {
-+ default: return thrd_error;
-+ case 0: return thrd_success;
-+ case EBUSY: return thrd_busy;
-+ }
-+}
-diff --git a/src/thread/mtx_unlock.c b/src/thread/mtx_unlock.c
-new file mode 100644
-index 0000000..5033ace
---- /dev/null
-+++ b/src/thread/mtx_unlock.c
-@@ -0,0 +1,11 @@
-+#include <threads.h>
-+
-+int __pthread_mutex_unlock(mtx_t *);
-+
-+int mtx_unlock(mtx_t *mtx)
-+{
-+ /* The only cases where pthread_mutex_unlock can return an
-+ * error are undefined behavior for C11 mtx_unlock, so we can
-+ * assume it does not return an error and simply tail call. */
-+ return __pthread_mutex_unlock(mtx);
-+}
-diff --git a/src/thread/pthread_cond_timedwait.c b/src/thread/pthread_cond_timedwait.c
-index 2d192b0..0a80d30 100644
---- a/src/thread/pthread_cond_timedwait.c
-+++ b/src/thread/pthread_cond_timedwait.c
-@@ -1,5 +1,9 @@
- #include "pthread_impl.h"
-
-+void __pthread_testcancel(void);
-+int __pthread_mutex_lock(pthread_mutex_t *);
-+int __pthread_mutex_unlock(pthread_mutex_t *);
-+
- /*
- * struct waiter
- *
-@@ -119,7 +123,7 @@ static void unwait(void *arg)
- }
- }
-
--int pthread_cond_timedwait(pthread_cond_t *restrict c, pthread_mutex_t *restrict m, const struct timespec *restrict ts)
-+int __pthread_cond_timedwait(pthread_cond_t *restrict c, pthread_mutex_t *restrict m, const struct timespec *restrict ts)
- {
- struct waiter node = { .cond = c, .mutex = m };
- int e, seq, *fut, clock = c->_c_clock;
-@@ -130,7 +134,7 @@ int pthread_cond_timedwait(pthread_cond_t *restrict c, pthread_mutex_t *restrict
- if (ts && ts->tv_nsec >= 1000000000UL)
- return EINVAL;
-
-- pthread_testcancel();
-+ __pthread_testcancel();
-
- if (c->_c_shared) {
- node.shared = 1;
-@@ -151,7 +155,7 @@ int pthread_cond_timedwait(pthread_cond_t *restrict c, pthread_mutex_t *restrict
- unlock(&c->_c_lock);
- }
-
-- pthread_mutex_unlock(m);
-+ __pthread_mutex_unlock(m);
-
- do e = __timedwait(fut, seq, clock, ts, unwait, &node, !node.shared);
- while (*fut==seq && (!e || e==EINTR));
-@@ -197,3 +201,5 @@ int __private_cond_signal(pthread_cond_t *c, int n)
-
- return 0;
- }
-+
-+weak_alias(__pthread_cond_timedwait, pthread_cond_timedwait);
-diff --git a/src/thread/pthread_create.c b/src/thread/pthread_create.c
-index e441bda..1a47ed1 100644
---- a/src/thread/pthread_create.c
-+++ b/src/thread/pthread_create.c
-@@ -5,6 +5,10 @@
- #include <sys/mman.h>
- #include <string.h>
-
-+void *__mmap(void *, size_t, int, int, int, off_t);
-+int __munmap(void *, size_t);
-+int __mprotect(void *, size_t, int);
-+
- static void dummy_0()
- {
- }
-@@ -14,7 +18,7 @@ weak_alias(dummy_0, __pthread_tsd_run_dtors);
- weak_alias(dummy_0, __do_private_robust_list);
- weak_alias(dummy_0, __do_orphaned_stdio_locks);
-
--_Noreturn void pthread_exit(void *result)
-+_Noreturn void __pthread_exit(void *result)
- {
- pthread_t self = __pthread_self();
- sigset_t set;
-@@ -115,7 +119,15 @@ static int start(void *p)
- if (self->unblock_cancel)
- __syscall(SYS_rt_sigprocmask, SIG_UNBLOCK,
- SIGPT_SET, 0, _NSIG/8);
-- pthread_exit(self->start(self->start_arg));
-+ __pthread_exit(self->start(self->start_arg));
-+ return 0;
-+}
-+
-+static int start_c11(void *p)
-+{
-+ pthread_t self = p;
-+ int (*start)(void*) = (int(*)(void*)) self->start;
-+ __pthread_exit((void *)(uintptr_t)start(self->start_arg));
- return 0;
- }
-
-@@ -139,9 +151,9 @@ static void init_file_lock(FILE *f)
-
- void *__copy_tls(unsigned char *);
-
--int pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict attrp, void *(*entry)(void *), void *restrict arg)
-+int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict attrp, void *(*entry)(void *), void *restrict arg)
- {
-- int ret;
-+ int ret, c11 = (attrp == __ATTRP_C11_THREAD);
- size_t size, guard;
- struct pthread *self, *new;
- unsigned char *map = 0, *stack = 0, *tsd = 0, *stack_limit;
-@@ -163,7 +175,7 @@ int pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict attrp
- self->tsd = (void **)__pthread_tsd_main;
- libc.threaded = 1;
- }
-- if (attrp) attr = *attrp;
-+ if (attrp && !c11) attr = *attrp;
-
- __acquire_ptc();
-
-@@ -191,14 +203,14 @@ int pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict attrp
-
- if (!tsd) {
- if (guard) {
-- map = mmap(0, size, PROT_NONE, MAP_PRIVATE|MAP_ANON, -1, 0);
-+ map = __mmap(0, size, PROT_NONE, MAP_PRIVATE|MAP_ANON, -1, 0);
- if (map == MAP_FAILED) goto fail;
-- if (mprotect(map+guard, size-guard, PROT_READ|PROT_WRITE)) {
-- munmap(map, size);
-+ if (__mprotect(map+guard, size-guard, PROT_READ|PROT_WRITE)) {
-+ __munmap(map, size);
- goto fail;
- }
- } else {
-- map = mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0);
-+ map = __mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0);
- if (map == MAP_FAILED) goto fail;
- }
- tsd = map + size - __pthread_tsd_size;
-@@ -230,7 +242,7 @@ int pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict attrp
- new->canary = self->canary;
-
- a_inc(&libc.threads_minus_1);
-- ret = __clone(start, stack, flags, new, &new->tid, TP_ADJ(new), &new->tid);
-+ ret = __clone((c11 ? start_c11 : start), stack, flags, new, &new->tid, TP_ADJ(new), &new->tid);
-
- __release_ptc();
-
-@@ -240,7 +252,7 @@ int pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict attrp
-
- if (ret < 0) {
- a_dec(&libc.threads_minus_1);
-- if (map) munmap(map, size);
-+ if (map) __munmap(map, size);
- return EAGAIN;
- }
-
-@@ -258,3 +270,6 @@ fail:
- __release_ptc();
- return EAGAIN;
- }
-+
-+weak_alias(__pthread_exit, pthread_exit);
-+weak_alias(__pthread_create, pthread_create);
-diff --git a/src/thread/pthread_detach.c b/src/thread/pthread_detach.c
-index 651c38e..ed77f74 100644
---- a/src/thread/pthread_detach.c
-+++ b/src/thread/pthread_detach.c
-@@ -1,11 +1,17 @@
- #include "pthread_impl.h"
-+#include <threads.h>
-
--int pthread_detach(pthread_t t)
-+int __pthread_join(pthread_t, void **);
-+
-+static int __pthread_detach(pthread_t t)
- {
- /* Cannot detach a thread that's already exiting */
- if (a_swap(t->exitlock, 1))
-- return pthread_join(t, 0);
-+ return __pthread_join(t, 0);
- t->detached = 2;
- __unlock(t->exitlock);
- return 0;
- }
-+
-+weak_alias(__pthread_detach, pthread_detach);
-+weak_alias(__pthread_detach, thrd_detach);
-diff --git a/src/thread/pthread_equal.c b/src/thread/pthread_equal.c
-index 3e3df4f..7c31482 100644
---- a/src/thread/pthread_equal.c
-+++ b/src/thread/pthread_equal.c
-@@ -1,6 +1,11 @@
- #include <pthread.h>
-+#include <threads.h>
-+#include "libc.h"
-
--int (pthread_equal)(pthread_t a, pthread_t b)
-+static int __pthread_equal(pthread_t a, pthread_t b)
- {
- return a==b;
- }
-+
-+weak_alias(__pthread_equal, pthread_equal);
-+weak_alias(__pthread_equal, thrd_equal);
-diff --git a/src/thread/pthread_getspecific.c b/src/thread/pthread_getspecific.c
-index b2a282c..d9342a5 100644
---- a/src/thread/pthread_getspecific.c
-+++ b/src/thread/pthread_getspecific.c
-@@ -1,7 +1,11 @@
- #include "pthread_impl.h"
-+#include <threads.h>
-
--void *pthread_getspecific(pthread_key_t k)
-+static void *__pthread_getspecific(pthread_key_t k)
- {
- struct pthread *self = __pthread_self();
- return self->tsd[k];
- }
-+
-+weak_alias(__pthread_getspecific, pthread_getspecific);
-+weak_alias(__pthread_getspecific, tss_get);
-diff --git a/src/thread/pthread_join.c b/src/thread/pthread_join.c
-index abd2d66..19e6b54 100644
---- a/src/thread/pthread_join.c
-+++ b/src/thread/pthread_join.c
-@@ -1,16 +1,20 @@
- #include "pthread_impl.h"
- #include <sys/mman.h>
-
-+int __munmap(void *, size_t);
-+
- static void dummy(void *p)
- {
- }
-
--int pthread_join(pthread_t t, void **res)
-+int __pthread_join(pthread_t t, void **res)
- {
- int tmp;
- pthread_testcancel();
- while ((tmp = t->tid)) __timedwait(&t->tid, tmp, 0, 0, dummy, 0, 0);
- if (res) *res = t->result;
-- if (t->map_base) munmap(t->map_base, t->map_size);
-+ if (t->map_base) __munmap(t->map_base, t->map_size);
- return 0;
- }
-+
-+weak_alias(__pthread_join, pthread_join);
-diff --git a/src/thread/pthread_key_create.c b/src/thread/pthread_key_create.c
-index a9187f7..bfcd597 100644
---- a/src/thread/pthread_key_create.c
-+++ b/src/thread/pthread_key_create.c
-@@ -9,7 +9,7 @@ static void nodtor(void *dummy)
- {
- }
-
--int pthread_key_create(pthread_key_t *k, void (*dtor)(void *))
-+int __pthread_key_create(pthread_key_t *k, void (*dtor)(void *))
- {
- unsigned i = (uintptr_t)&k / 16 % PTHREAD_KEYS_MAX;
- unsigned j = i;
-@@ -31,7 +31,7 @@ int pthread_key_create(pthread_key_t *k, void (*dtor)(void *))
- return EAGAIN;
- }
-
--int pthread_key_delete(pthread_key_t k)
-+int __pthread_key_delete(pthread_key_t k)
- {
- keys[k] = 0;
- return 0;
-@@ -53,3 +53,6 @@ void __pthread_tsd_run_dtors()
- }
- }
- }
-+
-+weak_alias(__pthread_key_delete, pthread_key_delete);
-+weak_alias(__pthread_key_create, pthread_key_create);
-diff --git a/src/thread/pthread_mutex_lock.c b/src/thread/pthread_mutex_lock.c
-index 2a9a3aa..d0c93ca 100644
---- a/src/thread/pthread_mutex_lock.c
-+++ b/src/thread/pthread_mutex_lock.c
-@@ -1,10 +1,14 @@
- #include "pthread_impl.h"
-
--int pthread_mutex_lock(pthread_mutex_t *m)
-+int __pthread_mutex_timedlock(pthread_mutex_t *restrict, const struct timespec *restrict);
-+
-+int __pthread_mutex_lock(pthread_mutex_t *m)
- {
- if ((m->_m_type&15) == PTHREAD_MUTEX_NORMAL
- && !a_cas(&m->_m_lock, 0, EBUSY))
- return 0;
-
-- return pthread_mutex_timedlock(m, 0);
-+ return __pthread_mutex_timedlock(m, 0);
- }
-+
-+weak_alias(__pthread_mutex_lock, pthread_mutex_lock);
-diff --git a/src/thread/pthread_mutex_timedlock.c b/src/thread/pthread_mutex_timedlock.c
-index ae883f9..16241ee 100644
---- a/src/thread/pthread_mutex_timedlock.c
-+++ b/src/thread/pthread_mutex_timedlock.c
-@@ -1,6 +1,6 @@
- #include "pthread_impl.h"
-
--int pthread_mutex_timedlock(pthread_mutex_t *restrict m, const struct timespec *restrict at)
-+int __pthread_mutex_timedlock(pthread_mutex_t *restrict m, const struct timespec *restrict at)
- {
- if ((m->_m_type&15) == PTHREAD_MUTEX_NORMAL
- && !a_cas(&m->_m_lock, 0, EBUSY))
-@@ -30,3 +30,5 @@ int pthread_mutex_timedlock(pthread_mutex_t *restrict m, const struct timespec *
- }
- return r;
- }
-+
-+weak_alias(__pthread_mutex_timedlock, pthread_mutex_timedlock);
-diff --git a/src/thread/pthread_mutex_trylock.c b/src/thread/pthread_mutex_trylock.c
-index e851517..cb93565 100644
---- a/src/thread/pthread_mutex_trylock.c
-+++ b/src/thread/pthread_mutex_trylock.c
-@@ -50,9 +50,11 @@ int __pthread_mutex_trylock_owner(pthread_mutex_t *m)
- return 0;
- }
-
--int pthread_mutex_trylock(pthread_mutex_t *m)
-+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);
- }
-+
-+weak_alias(__pthread_mutex_trylock, pthread_mutex_trylock);
-diff --git a/src/thread/pthread_mutex_unlock.c b/src/thread/pthread_mutex_unlock.c
-index 46761d9..a7f39c7 100644
---- a/src/thread/pthread_mutex_unlock.c
-+++ b/src/thread/pthread_mutex_unlock.c
-@@ -3,7 +3,7 @@
- void __vm_lock_impl(int);
- void __vm_unlock_impl(void);
-
--int pthread_mutex_unlock(pthread_mutex_t *m)
-+int __pthread_mutex_unlock(pthread_mutex_t *m)
- {
- pthread_t self;
- int waiters = m->_m_waiters;
-@@ -36,3 +36,5 @@ int pthread_mutex_unlock(pthread_mutex_t *m)
- __wake(&m->_m_lock, 1, priv);
- return 0;
- }
-+
-+weak_alias(__pthread_mutex_unlock, pthread_mutex_unlock);
-diff --git a/src/thread/pthread_once.c b/src/thread/pthread_once.c
-index 2eb0f93..05ebe69 100644
---- a/src/thread/pthread_once.c
-+++ b/src/thread/pthread_once.c
-@@ -6,7 +6,7 @@ static void undo(void *control)
- __wake(control, 1, 1);
- }
-
--int pthread_once(pthread_once_t *control, void (*init)(void))
-+int __pthread_once(pthread_once_t *control, void (*init)(void))
- {
- static int waiters;
-
-@@ -34,3 +34,5 @@ int pthread_once(pthread_once_t *control, void (*init)(void))
- return 0;
- }
- }
-+
-+weak_alias(__pthread_once, pthread_once);
-diff --git a/src/thread/pthread_self.c b/src/thread/pthread_self.c
-index 5f9e651..241a620 100644
---- a/src/thread/pthread_self.c
-+++ b/src/thread/pthread_self.c
-@@ -1,6 +1,11 @@
- #include "pthread_impl.h"
-+#include <threads.h>
-+#include "libc.h"
-
--pthread_t pthread_self()
-+static pthread_t __pthread_self_internal()
- {
- return __pthread_self();
- }
-+
-+weak_alias(__pthread_self_internal, pthread_self);
-+weak_alias(__pthread_self_internal, thrd_current);
-diff --git a/src/thread/pthread_setcancelstate.c b/src/thread/pthread_setcancelstate.c
-index 060bcdc..2268217 100644
---- a/src/thread/pthread_setcancelstate.c
-+++ b/src/thread/pthread_setcancelstate.c
-@@ -1,6 +1,6 @@
- #include "pthread_impl.h"
-
--int pthread_setcancelstate(int new, int *old)
-+int __pthread_setcancelstate(int new, int *old)
- {
- if (new > 1U) return EINVAL;
- if (!libc.has_thread_pointer) return ENOSYS;
-@@ -9,3 +9,5 @@ int pthread_setcancelstate(int new, int *old)
- self->canceldisable = new;
- return 0;
- }
-+
-+weak_alias(__pthread_setcancelstate, pthread_setcancelstate);
-diff --git a/src/thread/pthread_testcancel.c b/src/thread/pthread_testcancel.c
-index ba5f7c6..ee48e6d 100644
---- a/src/thread/pthread_testcancel.c
-+++ b/src/thread/pthread_testcancel.c
-@@ -7,7 +7,9 @@ static void dummy()
-
- weak_alias(dummy, __testcancel);
-
--void pthread_testcancel()
-+void __pthread_testcancel()
- {
- __testcancel();
- }
-+
-+weak_alias(__pthread_testcancel, pthread_testcancel);
-diff --git a/src/thread/thrd_create.c b/src/thread/thrd_create.c
-new file mode 100644
-index 0000000..e033669
---- /dev/null
-+++ b/src/thread/thrd_create.c
-@@ -0,0 +1,14 @@
-+#include "pthread_impl.h"
-+#include <threads.h>
-+
-+int __pthread_create(pthread_t *restrict, const pthread_attr_t *restrict, void *(*)(void *), void *restrict);
-+
-+int thrd_create(thrd_t *thr, thrd_start_t func, void *arg)
-+{
-+ int ret = __pthread_create(thr, __ATTRP_C11_THREAD, (void *(*)(void *))func, arg);
-+ switch (ret) {
-+ case 0: return thrd_success;
-+ case EAGAIN: return thrd_nomem;
-+ default: return thrd_error;
-+ }
-+}
-diff --git a/src/thread/thrd_exit.c b/src/thread/thrd_exit.c
-new file mode 100644
-index 0000000..b66bd99
---- /dev/null
-+++ b/src/thread/thrd_exit.c
-@@ -0,0 +1,9 @@
-+#include "pthread_impl.h"
-+#include <threads.h>
-+
-+_Noreturn void __pthread_exit(void *);
-+
-+_Noreturn void thrd_exit(int result)
-+{
-+ __pthread_exit((void*)(intptr_t)result);
-+}
-diff --git a/src/thread/thrd_join.c b/src/thread/thrd_join.c
-new file mode 100644
-index 0000000..ac66789
---- /dev/null
-+++ b/src/thread/thrd_join.c
-@@ -0,0 +1,12 @@
-+#include <stdint.h>
-+#include <threads.h>
-+
-+int __pthread_join(thrd_t, void**);
-+
-+int thrd_join(thrd_t t, int *res)
-+{
-+ void *pthread_res;
-+ __pthread_join(t, &pthread_res);
-+ if (res) *res = (int)(intptr_t)pthread_res;
-+ return thrd_success;
-+}
-diff --git a/src/thread/thrd_sleep.c b/src/thread/thrd_sleep.c
-new file mode 100644
-index 0000000..e8dfe40
---- /dev/null
-+++ b/src/thread/thrd_sleep.c
-@@ -0,0 +1,13 @@
-+#include <threads.h>
-+#include <errno.h>
-+#include "syscall.h"
-+
-+int thrd_sleep(const struct timespec *req, struct timespec *rem)
-+{
-+ int ret = __syscall(SYS_nanosleep, req, rem);
-+ switch (ret) {
-+ case 0: return 0;
-+ case -EINTR: return -1; /* value specified by C11 */
-+ default: return -2;
-+ }
-+}
-diff --git a/src/thread/thrd_yield.c b/src/thread/thrd_yield.c
-new file mode 100644
-index 0000000..f7ad132
---- /dev/null
-+++ b/src/thread/thrd_yield.c
-@@ -0,0 +1,7 @@
-+#include <threads.h>
-+#include "syscall.h"
-+
-+void thrd_yield()
-+{
-+ __syscall(SYS_sched_yield);
-+}
-diff --git a/src/thread/tss_create.c b/src/thread/tss_create.c
-new file mode 100644
-index 0000000..251d22b
---- /dev/null
-+++ b/src/thread/tss_create.c
-@@ -0,0 +1,11 @@
-+#include <threads.h>
-+
-+int __pthread_key_create(tss_t *, void (*)(void *));
-+
-+int tss_create(tss_t *tss, tss_dtor_t dtor)
-+{
-+ /* Different error returns are possible. C glues them together into
-+ * just failure notification. Can't be optimized to a tail call,
-+ * unless thrd_error equals EAGAIN. */
-+ return __pthread_key_create(tss, dtor) ? thrd_error : thrd_success;
-+}
-diff --git a/src/thread/tss_delete.c b/src/thread/tss_delete.c
-new file mode 100644
-index 0000000..35db103
---- /dev/null
-+++ b/src/thread/tss_delete.c
-@@ -0,0 +1,8 @@
-+#include <threads.h>
-+
-+int __pthread_key_delete(tss_t k);
-+
-+void tss_delete(tss_t key)
-+{
-+ __pthread_key_delete(key);
-+}
-diff --git a/src/thread/tss_set.c b/src/thread/tss_set.c
-new file mode 100644
-index 0000000..70c4fb7
---- /dev/null
-+++ b/src/thread/tss_set.c
-@@ -0,0 +1,13 @@
-+#include "pthread_impl.h"
-+#include <threads.h>
-+
-+int tss_set(tss_t k, void *x)
-+{
-+ struct pthread *self = __pthread_self();
-+ /* Avoid unnecessary COW */
-+ if (self->tsd[k] != x) {
-+ self->tsd[k] = x;
-+ self->tsd_used = 1;
-+ }
-+ return thrd_success;
-+}
-diff --git a/src/time/timespec_get.c b/src/time/timespec_get.c
-new file mode 100644
-index 0000000..03c5a77
---- /dev/null
-+++ b/src/time/timespec_get.c
-@@ -0,0 +1,12 @@
-+#include <time.h>
-+
-+int __clock_gettime(clockid_t, struct timespec *);
-+
-+/* There is no other implemented value than TIME_UTC; all other values
-+ * are considered erroneous. */
-+int timespec_get(struct timespec * ts, int base)
-+{
-+ if (base != TIME_UTC) return 0;
-+ int ret = __clock_gettime(CLOCK_REALTIME, ts);
-+ return ret < 0 ? 0 : base;
-+}
diff --git a/main/musl/1002-check-lockcount-in-funlockfile.patch b/main/musl/1002-check-lockcount-in-funlockfile.patch
deleted file mode 100644
index a2ae3a136..000000000
--- a/main/musl/1002-check-lockcount-in-funlockfile.patch
+++ /dev/null
@@ -1,17 +0,0 @@
-diff -ru musl-1.1.4.orig/src/stdio/funlockfile.c musl-1.1.4/src/stdio/funlockfile.c
---- musl-1.1.4.orig/src/stdio/funlockfile.c 2014-09-05 11:58:04.928864395 -0300
-+++ musl-1.1.4/src/stdio/funlockfile.c 2014-09-05 11:58:45.915533166 -0300
-@@ -1,10 +1,12 @@
- #include "stdio_impl.h"
- #include "pthread_impl.h"
-+#include "atomic.h"
-
- void __unlist_locked_file(FILE *);
-
- void funlockfile(FILE *f)
- {
-+ if (f->lockcount == 0) a_crash();
- if (f->lockcount == 1) {
- __unlist_locked_file(f);
- f->lockcount = 0;
-
diff --git a/main/musl/APKBUILD b/main/musl/APKBUILD
index 1998acee6..d8f8c9fda 100644
--- a/main/musl/APKBUILD
+++ b/main/musl/APKBUILD
@@ -1,8 +1,8 @@
# Contributor: William Pitcock <nenolod@dereferenced.org>
# Maintainer: Timo Teräs <timo.teras@iki.fi>
pkgname=musl
-pkgver=1.1.4
-pkgrel=8
+pkgver=1.1.5
+pkgrel=0
pkgdesc="the musl c library (libc) implementation"
url="http://www.musl-libc.org/"
arch="all"
@@ -13,14 +13,7 @@ makedepends="$depends_dev"
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
- 0003-4992ace9-to-6e2bb7ac.patch
- 0004-6e2bb7ac-to-4674809b.patch
- 0005-4674809b-to-3e936ce8.patch
-
1001-add-basic-dns-record-parsing-functions.patch
- 1002-check-lockcount-in-funlockfile.patch
1003-remove-ulimit-fiddling-from-setxid.patch
ldconfig
@@ -124,14 +117,8 @@ utils() {
install -D -m755 "$srcdir"/ldconfig "$subpkgdir"/sbin
}
-md5sums="f18f3bdbe088438cd64a5313c19a7312 musl-1.1.4.tar.gz
-7e6f4c4e0992f73d61963959d7fbbaa5 0001-v1.1.4-to-d86af2a0.patch
-04eef5b44c0b56b79055340bee1febc2 0002-d86af2a0-to-4992ace9.patch
-6710102c768f5a971b93100219de3fbb 0003-4992ace9-to-6e2bb7ac.patch
-294d3d382098977ea0770731a4803322 0004-6e2bb7ac-to-4674809b.patch
-5e7769c1f65acbdb9decf3012a70b411 0005-4674809b-to-3e936ce8.patch
+md5sums="94f8aa9dab80229fed68991bb9984cc5 musl-1.1.5.tar.gz
2371eb1ce057fcb709a0e6a81f0d356c 1001-add-basic-dns-record-parsing-functions.patch
-8a763b1853ee16d034abe038a0c44641 1002-check-lockcount-in-funlockfile.patch
71b2a4dcc39c436a6b89173943424043 1003-remove-ulimit-fiddling-from-setxid.patch
830d01f7821b978df770b06db3790921 ldconfig
61c6c1e84ed1df82abbe6d75e90cf21c getopt_long.c
@@ -139,14 +126,8 @@ md5sums="f18f3bdbe088438cd64a5313c19a7312 musl-1.1.4.tar.gz
57ef2c63b9ec6a2041694ace97d4ffa2 getconf.c
2b941c4251cac44988a4abfc50e21267 getent.c
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
-7a716e03084724e3776300d8ed498e835b2cad4321b638a3eec5a9d8f28de8d9 0003-4992ace9-to-6e2bb7ac.patch
-e727b50aa65886563960c10449f60e229ffb94dd3476df1098e877ce599358c4 0004-6e2bb7ac-to-4674809b.patch
-1672b904cf69c9c9b349e7b07f534663cd2083a878778db188f74104bfc051b5 0005-4674809b-to-3e936ce8.patch
+sha256sums="352362b1724cc9740f4c3ce0fe02aae45e4de9809ea4ac961f31aedc11b87393 musl-1.1.5.tar.gz
75053a31f6b84a64846d92c0ec631c76d7f747a9c0dc92a6dc1aa1bddfe2ea76 1001-add-basic-dns-record-parsing-functions.patch
-eebc0afce600cbe2f41055404c7735f1a7be6e262df602dbcbfde7321633bdd9 1002-check-lockcount-in-funlockfile.patch
fb542c2bd5081ff2f601c519edb3dac8f54ca5c888f44bc6cfb84e6565472025 1003-remove-ulimit-fiddling-from-setxid.patch
b4a2c06db38742e8c42c3c9838b285a7d8cdac6c091ff3df5ff9a15f1e41b9c7 ldconfig
d9b644ec20bc33e81a7c52b9fcf7973d835923a69faf50f03db45534b811bd96 getopt_long.c
@@ -154,14 +135,8 @@ d9b644ec20bc33e81a7c52b9fcf7973d835923a69faf50f03db45534b811bd96 getopt_long.c
d87d0cbb3690ae2c5d8cc218349fd8278b93855dd625deaf7ae50e320aad247c getconf.c
68373a55e89ce85c562d941ccf588337d6cc6c9c17689d695f65cd7607134bbe getent.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
-af92b766d2ca9fcf58b57c705b65ec0b60ecd9af1d38f1b9697a6b999baa56d8cb0ecf94bc02267022a13763e4a1a13a3f73bc03fdf73c0cd8f80126c2949a13 0003-4992ace9-to-6e2bb7ac.patch
-8aa879e31c3eb18f9b00ea98d25872d94cad9120c05a80419965dcf7d3a4e0a69c370b35e2871cb11b639bbcf606842a48d3ad64ec916bc34b2eb21d3c4a3efa 0004-6e2bb7ac-to-4674809b.patch
-7104eb3753135b5cd2a291552c6fbf36034d7169178ae45ef99d634a4055afa30a7e89ce7a01695b120c4a872ec51f1a837b34c4e83d69778b0248ca6c931d48 0005-4674809b-to-3e936ce8.patch
+sha512sums="4436887367137cbfc6d34e0f403b8dd36db2a55a5160681fef4de7cc0cb1be38487ea708e6aa6dc1328b61c62868b6cc19f099649c9d12e1ba812dfa8844b772 musl-1.1.5.tar.gz
5b8ffa0a50419581adbf6ce2dae5797774022551c6331fa5aa2ff13635eb72b74eedd8a92cb478d45d73e1956af2f588669681ac414f3a255abd4d8ba8579448 1001-add-basic-dns-record-parsing-functions.patch
-beb515f46fa7c18eafe72cc612c5e8877dd1fd083e05c427af3a2a4d4281df06c6c1727c39d136d8e3f267be8832ea133362f5088a2b6a26b33c9e184acf1884 1002-check-lockcount-in-funlockfile.patch
dae010b45419fcab64410568466f659cdc874e63113025e2cbc2fbab047b470fec23851ecbef08886505924482a069caf37c16b483b6922535fbd31832f1c4a3 1003-remove-ulimit-fiddling-from-setxid.patch
8d3a2d5315fc56fee7da9abb8b89bb38c6046c33d154c10d168fb35bfde6b0cf9f13042a3bceee34daf091bc409d699223735dcf19f382eeee1f6be34154f26f ldconfig
140f3f20d30bd95ebce8c41b8cc7f616c6cbedf4ea06c729c21014e74f6043796825cc40ebc5180620ea38173afdba23f09ebf6d8b11fa05440b14d23764fca9 getopt_long.c