diff options
Diffstat (limited to 'main/musl')
-rw-r--r-- | main/musl/0001-v1.1.4-to-d86af2a0.patch | 137 | ||||
-rw-r--r-- | main/musl/0002-d86af2a0-to-4992ace9.patch | 1083 | ||||
-rw-r--r-- | main/musl/0003-4992ace9-to-6e2bb7ac.patch | 745 | ||||
-rw-r--r-- | main/musl/0004-6e2bb7ac-to-4674809b.patch | 68 | ||||
-rw-r--r-- | main/musl/0005-4674809b-to-3e936ce8.patch | 3400 | ||||
-rw-r--r-- | main/musl/1002-check-lockcount-in-funlockfile.patch | 17 | ||||
-rw-r--r-- | main/musl/APKBUILD | 35 |
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 e29d0ae981..0000000000 --- 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 ed0eb65226..0000000000 --- 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 f5c9b40b6e..0000000000 --- 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 62710e321c..0000000000 --- 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 9180e7eab6..0000000000 --- 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 a2ae3a1360..0000000000 --- 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 1998acee67..d8f8c9fda8 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 |