diff options
author | pommicket <pommicket@gmail.com> | 2022-02-20 13:18:21 -0800 |
---|---|---|
committer | pommicket <pommicket@gmail.com> | 2022-02-20 13:18:21 -0800 |
commit | 9bc8a11afeed3569736b89754012e3ca22ee10f6 (patch) | |
tree | 5f0ec0d5c05f879b1ee86adfa654ed3ef2178d5f /05/musl-0.6.0/src/thread | |
parent | 0f97a589b800bdb71dda05984192f0f66a52edaa (diff) |
conclusion
Diffstat (limited to '05/musl-0.6.0/src/thread')
73 files changed, 1066 insertions, 0 deletions
diff --git a/05/musl-0.6.0/src/thread/__futex.c b/05/musl-0.6.0/src/thread/__futex.c new file mode 100644 index 0000000..93352fa --- /dev/null +++ b/05/musl-0.6.0/src/thread/__futex.c @@ -0,0 +1,8 @@ +#include "futex.h" +#include "syscall.h" + +int __futex(volatile int *addr, int op, int val, void *ts) +{ + return syscall4(__NR_futex, (long)addr, op, val, (long)ts); +} + diff --git a/05/musl-0.6.0/src/thread/__lock.c b/05/musl-0.6.0/src/thread/__lock.c new file mode 100644 index 0000000..557c6a6 --- /dev/null +++ b/05/musl-0.6.0/src/thread/__lock.c @@ -0,0 +1,12 @@ +#define SYSCALL_RETURN_ERRNO +#include "pthread_impl.h" + +void __lock(volatile int *l) +{ + int spins=100000; + /* Do not use futexes because we insist that unlocking is a simple + * assignment to optimize non-pathological code with no contention. */ + while (a_xchg(l, 1)) + if (spins) spins--, a_spin(); + else syscall0(__NR_sched_yield); +} diff --git a/05/musl-0.6.0/src/thread/__set_thread_area.c b/05/musl-0.6.0/src/thread/__set_thread_area.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/05/musl-0.6.0/src/thread/__set_thread_area.c diff --git a/05/musl-0.6.0/src/thread/__timedwait.c b/05/musl-0.6.0/src/thread/__timedwait.c new file mode 100644 index 0000000..354def2 --- /dev/null +++ b/05/musl-0.6.0/src/thread/__timedwait.c @@ -0,0 +1,21 @@ +#include <time.h> +#include <errno.h> +#include "futex.h" +#define SYSCALL_RETURN_ERRNO +#include "syscall.h" +#include <stdio.h> +int __timedwait(volatile int *addr, int val, clockid_t clk, const struct timespec *at, int priv) +{ + struct timespec to; + if (at) { + clock_gettime(clk, &to); + to.tv_sec = at->tv_sec - to.tv_sec; + if ((to.tv_nsec = at->tv_nsec - to.tv_nsec) < 0) { + to.tv_sec--; + to.tv_nsec += 1000000000; + } + if (to.tv_sec < 0) return ETIMEDOUT; + } + if (priv) priv = 128; priv=0; + return syscall4(__NR_futex, (long)addr, FUTEX_WAIT | priv, val, at ? (long)&to : 0); +} diff --git a/05/musl-0.6.0/src/thread/__unmapself.c b/05/musl-0.6.0/src/thread/__unmapself.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/05/musl-0.6.0/src/thread/__unmapself.c diff --git a/05/musl-0.6.0/src/thread/__wait.c b/05/musl-0.6.0/src/thread/__wait.c new file mode 100644 index 0000000..8c249cd --- /dev/null +++ b/05/musl-0.6.0/src/thread/__wait.c @@ -0,0 +1,16 @@ +#define SYSCALL_RETURN_ERRNO +#include "pthread_impl.h" + +void __wait(volatile int *addr, volatile int *waiters, int val, int priv) +{ + int spins=50000; + if (priv) priv = 128; priv=0; + while (spins--) { + if (*addr==val) a_spin(); + else return; + } + if (waiters) a_inc(waiters); + while (*addr==val) + syscall4(__NR_futex, (long)addr, FUTEX_WAIT|priv, val, 0); + if (waiters) a_dec(waiters); +} diff --git a/05/musl-0.6.0/src/thread/__wake.c b/05/musl-0.6.0/src/thread/__wake.c new file mode 100644 index 0000000..048ddcc --- /dev/null +++ b/05/musl-0.6.0/src/thread/__wake.c @@ -0,0 +1,9 @@ +#define SYSCALL_RETURN_ERRNO +#include "pthread_impl.h" + +void __wake(volatile int *addr, int cnt, int priv) +{ + if (priv) priv = 128; priv=0; + if (cnt<0) cnt = INT_MAX; + syscall3(__NR_futex, (long)addr, FUTEX_WAKE | priv, cnt); +} diff --git a/05/musl-0.6.0/src/thread/cancellation.c b/05/musl-0.6.0/src/thread/cancellation.c new file mode 100644 index 0000000..ac1af30 --- /dev/null +++ b/05/musl-0.6.0/src/thread/cancellation.c @@ -0,0 +1,14 @@ +#include "pthread_impl.h" + +void __pthread_register_cancel(struct __ptcb *cb) +{ + struct pthread *self = pthread_self(); + cb->__next = self->cancelbuf; + self->cancelbuf = cb; +} + +void __pthread_unregister_cancel(struct __ptcb *cb) +{ + struct pthread *self = __pthread_self(); + self->cancelbuf = self->cancelbuf->__next; +} diff --git a/05/musl-0.6.0/src/thread/clone.c b/05/musl-0.6.0/src/thread/clone.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/05/musl-0.6.0/src/thread/clone.c diff --git a/05/musl-0.6.0/src/thread/i386/__set_thread_area.s b/05/musl-0.6.0/src/thread/i386/__set_thread_area.s new file mode 100644 index 0000000..9bf698b --- /dev/null +++ b/05/musl-0.6.0/src/thread/i386/__set_thread_area.s @@ -0,0 +1,22 @@ +.text +.global __set_thread_area +.type __set_thread_area,%function +__set_thread_area: + pushl %ebx + movl 8(%esp),%ecx + movl $-1,4(%ecx) + movl %ecx,8(%ecx) + movl $0xfffff,12(%ecx) + movl $0x51,16(%ecx) + leal 4(%ecx),%ebx + movl $243,%eax + int $128 + popl %ebx + testl %eax,%eax + jnz 1f + movl 4(%ecx),%ecx + leal 3(,%ecx,8),%ecx + movw %cx,%gs +1: + ret +.size __set_thread_area,.-__set_thread_area diff --git a/05/musl-0.6.0/src/thread/i386/__unmapself.s b/05/musl-0.6.0/src/thread/i386/__unmapself.s new file mode 100644 index 0000000..5c67496 --- /dev/null +++ b/05/musl-0.6.0/src/thread/i386/__unmapself.s @@ -0,0 +1,22 @@ +.text +.global __unmapself +.type __unmapself,%function +__unmapself: + call 1f + .long -1 + .long -1 +1: popl %ecx + xorl %ebx,%ebx + xorl %edx,%edx + movl $8,%esi + movl $175,%eax + int $128 + movl $91,%eax + movl 4(%esp),%ebx + movl 8(%esp),%ecx + int $128 + xorl %ebx,%ebx + movl $1,%eax + int $128 + +.size __unmapself,.-__unmapself diff --git a/05/musl-0.6.0/src/thread/i386/clone.s b/05/musl-0.6.0/src/thread/i386/clone.s new file mode 100644 index 0000000..53405cf --- /dev/null +++ b/05/musl-0.6.0/src/thread/i386/clone.s @@ -0,0 +1,27 @@ +.text +.global __uniclone +.type __uniclone,%function +__uniclone: + movl 4(%esp),%ecx + subl $24,%ecx + movl 8(%esp),%eax + movl %eax,16(%ecx) + movl 12(%esp),%eax + movl %eax,24(%ecx) + pushl %ebx + pushl %esi + pushl %edi + pushl %ebp + movl %eax,8(%eax) + leal 20(%eax),%edx + leal 4(%eax),%esi + movl %edx,%edi + movl $0x7d0f00,%ebx + movl $120,%eax + int $128 + popl %ebp + popl %edi + popl %esi + popl %ebx + ret +.size __uniclone,.-__uniclone diff --git a/05/musl-0.6.0/src/thread/pthread_attr_destroy.c b/05/musl-0.6.0/src/thread/pthread_attr_destroy.c new file mode 100644 index 0000000..b5845dd --- /dev/null +++ b/05/musl-0.6.0/src/thread/pthread_attr_destroy.c @@ -0,0 +1,6 @@ +#include "pthread_impl.h" + +int pthread_attr_destroy(pthread_attr_t *a) +{ + return 0; +} diff --git a/05/musl-0.6.0/src/thread/pthread_attr_getdetachstate.c b/05/musl-0.6.0/src/thread/pthread_attr_getdetachstate.c new file mode 100644 index 0000000..de65c25 --- /dev/null +++ b/05/musl-0.6.0/src/thread/pthread_attr_getdetachstate.c @@ -0,0 +1,7 @@ +#include "pthread_impl.h" + +int pthread_attr_getdetachstate(pthread_attr_t *a, int *state) +{ + *state = a->_a_detach; + return 0; +} diff --git a/05/musl-0.6.0/src/thread/pthread_attr_getguardsize.c b/05/musl-0.6.0/src/thread/pthread_attr_getguardsize.c new file mode 100644 index 0000000..e6b9ee2 --- /dev/null +++ b/05/musl-0.6.0/src/thread/pthread_attr_getguardsize.c @@ -0,0 +1,7 @@ +#include "pthread_impl.h" + +int pthread_attr_getguardsize(pthread_attr_t *a, size_t *size) +{ + *size = a->_a_guardsize + DEFAULT_GUARD_SIZE; + return 0; +} diff --git a/05/musl-0.6.0/src/thread/pthread_attr_getscope.c b/05/musl-0.6.0/src/thread/pthread_attr_getscope.c new file mode 100644 index 0000000..0cb224d --- /dev/null +++ b/05/musl-0.6.0/src/thread/pthread_attr_getscope.c @@ -0,0 +1,6 @@ +#include "pthread_impl.h" + +int pthread_attr_getscope(pthread_attr_t *a, int *scope) +{ + return 0; +} diff --git a/05/musl-0.6.0/src/thread/pthread_attr_getstacksize.c b/05/musl-0.6.0/src/thread/pthread_attr_getstacksize.c new file mode 100644 index 0000000..900dc9f --- /dev/null +++ b/05/musl-0.6.0/src/thread/pthread_attr_getstacksize.c @@ -0,0 +1,7 @@ +#include "pthread_impl.h" + +int pthread_attr_getstacksize(pthread_attr_t *a, size_t *size) +{ + *size = a->_a_stacksize + DEFAULT_STACK_SIZE; + return 0; +} diff --git a/05/musl-0.6.0/src/thread/pthread_attr_init.c b/05/musl-0.6.0/src/thread/pthread_attr_init.c new file mode 100644 index 0000000..d91bf15 --- /dev/null +++ b/05/musl-0.6.0/src/thread/pthread_attr_init.c @@ -0,0 +1,7 @@ +#include "pthread_impl.h" + +int pthread_attr_init(pthread_attr_t *a) +{ + memset(a, 0, sizeof *a); + return 0; +} diff --git a/05/musl-0.6.0/src/thread/pthread_attr_setdetachstate.c b/05/musl-0.6.0/src/thread/pthread_attr_setdetachstate.c new file mode 100644 index 0000000..bfffba8 --- /dev/null +++ b/05/musl-0.6.0/src/thread/pthread_attr_setdetachstate.c @@ -0,0 +1,7 @@ +#include "pthread_impl.h" + +int pthread_attr_setdetachstate(pthread_attr_t *a, int state) +{ + a->_a_detach = state; + return 0; +} diff --git a/05/musl-0.6.0/src/thread/pthread_attr_setguardsize.c b/05/musl-0.6.0/src/thread/pthread_attr_setguardsize.c new file mode 100644 index 0000000..9f21d24 --- /dev/null +++ b/05/musl-0.6.0/src/thread/pthread_attr_setguardsize.c @@ -0,0 +1,8 @@ +#include "pthread_impl.h" + +int pthread_attr_setguardsize(pthread_attr_t *a, size_t size) +{ + if (size > SIZE_MAX/8) return EINVAL; + a->_a_guardsize = size - DEFAULT_GUARD_SIZE; + return 0; +} diff --git a/05/musl-0.6.0/src/thread/pthread_attr_setscope.c b/05/musl-0.6.0/src/thread/pthread_attr_setscope.c new file mode 100644 index 0000000..a970a81 --- /dev/null +++ b/05/musl-0.6.0/src/thread/pthread_attr_setscope.c @@ -0,0 +1,6 @@ +#include "pthread_impl.h" + +int pthread_attr_setscope(pthread_attr_t *a, int scope) +{ + return 0; +} diff --git a/05/musl-0.6.0/src/thread/pthread_attr_setstacksize.c b/05/musl-0.6.0/src/thread/pthread_attr_setstacksize.c new file mode 100644 index 0000000..df16b98 --- /dev/null +++ b/05/musl-0.6.0/src/thread/pthread_attr_setstacksize.c @@ -0,0 +1,8 @@ +#include "pthread_impl.h" + +int pthread_attr_setstacksize(pthread_attr_t *a, size_t size) +{ + if (size-PAGE_SIZE > SIZE_MAX/4) return EINVAL; + a->_a_stacksize = size - DEFAULT_STACK_SIZE; + return 0; +} diff --git a/05/musl-0.6.0/src/thread/pthread_barrier_destroy.c b/05/musl-0.6.0/src/thread/pthread_barrier_destroy.c new file mode 100644 index 0000000..2898c41 --- /dev/null +++ b/05/musl-0.6.0/src/thread/pthread_barrier_destroy.c @@ -0,0 +1,6 @@ +#include "pthread_impl.h" + +int pthread_barrier_destroy(pthread_barrier_t *b) +{ + return 0; +} diff --git a/05/musl-0.6.0/src/thread/pthread_barrier_init.c b/05/musl-0.6.0/src/thread/pthread_barrier_init.c new file mode 100644 index 0000000..736d101 --- /dev/null +++ b/05/musl-0.6.0/src/thread/pthread_barrier_init.c @@ -0,0 +1,8 @@ +#include "pthread_impl.h" + +int pthread_barrier_init(pthread_barrier_t *b, const pthread_barrierattr_t *a, unsigned count) +{ + if (!count) return EINVAL; + *b = (pthread_barrier_t){ ._b_limit = count-1 }; + return 0; +} diff --git a/05/musl-0.6.0/src/thread/pthread_barrier_wait.c b/05/musl-0.6.0/src/thread/pthread_barrier_wait.c new file mode 100644 index 0000000..7bfadb9 --- /dev/null +++ b/05/musl-0.6.0/src/thread/pthread_barrier_wait.c @@ -0,0 +1,31 @@ +#include "pthread_impl.h" + +int pthread_barrier_wait(pthread_barrier_t *b) +{ + int cur; + + /* Trivial case: count was set at 1 */ + if (!b->_b_limit) return PTHREAD_BARRIER_SERIAL_THREAD; + + /* Wait for anyone still suspended at previous use of barrier */ + while ((cur=b->_b_left)) + __wait(&b->_b_left, &b->_b_waiters, cur, 0); + + /* If we are the last to reach barrier, reset it and wake others */ + if (a_fetch_add(&b->_b_count, 1) == b->_b_limit) { + b->_b_left = b->_b_limit; + b->_b_count = 0; + __wake(&b->_b_count, -1, 0); + return PTHREAD_BARRIER_SERIAL_THREAD; + } + + /* Wait for our peers to reach the barrier */ + while ((cur=b->_b_count)) + __wait(&b->_b_count, 0, cur, 0); + + /* If we're the last to wake up and barrier is awaiting reuse */ + if (a_fetch_add(&b->_b_left, -1) == 1 && b->_b_waiters) + __wake(&b->_b_left, -1, 0); + + return 0; +} diff --git a/05/musl-0.6.0/src/thread/pthread_cancel.c b/05/musl-0.6.0/src/thread/pthread_cancel.c new file mode 100644 index 0000000..9397ffe --- /dev/null +++ b/05/musl-0.6.0/src/thread/pthread_cancel.c @@ -0,0 +1,7 @@ +#define SYSCALL_RETURN_ERRNO +#include "pthread_impl.h" + +int pthread_cancel(pthread_t t) +{ + return syscall3(__NR_tgkill, t->pid, t->tid, SIGCANCEL); +} diff --git a/05/musl-0.6.0/src/thread/pthread_cond_broadcast.c b/05/musl-0.6.0/src/thread/pthread_cond_broadcast.c new file mode 100644 index 0000000..1d378c0 --- /dev/null +++ b/05/musl-0.6.0/src/thread/pthread_cond_broadcast.c @@ -0,0 +1,8 @@ +#include "pthread_impl.h" + +int pthread_cond_broadcast(pthread_cond_t *c) +{ + c->_c_block = 0; + __wake(&c->_c_block, -1, 0); + return 0; +} diff --git a/05/musl-0.6.0/src/thread/pthread_cond_destroy.c b/05/musl-0.6.0/src/thread/pthread_cond_destroy.c new file mode 100644 index 0000000..1d21a5a --- /dev/null +++ b/05/musl-0.6.0/src/thread/pthread_cond_destroy.c @@ -0,0 +1,6 @@ +#include "pthread_impl.h" + +int pthread_cond_destroy(pthread_cond_t *c) +{ + return 0; +} diff --git a/05/musl-0.6.0/src/thread/pthread_cond_init.c b/05/musl-0.6.0/src/thread/pthread_cond_init.c new file mode 100644 index 0000000..3394860 --- /dev/null +++ b/05/musl-0.6.0/src/thread/pthread_cond_init.c @@ -0,0 +1,7 @@ +#include "pthread_impl.h" + +int pthread_cond_init(pthread_cond_t *c, const pthread_condattr_t *a) +{ + memset(c, 0, sizeof *c); + return 0; +} diff --git a/05/musl-0.6.0/src/thread/pthread_cond_signal.c b/05/musl-0.6.0/src/thread/pthread_cond_signal.c new file mode 100644 index 0000000..574f5c7 --- /dev/null +++ b/05/musl-0.6.0/src/thread/pthread_cond_signal.c @@ -0,0 +1,8 @@ +#include "pthread_impl.h" + +int pthread_cond_signal(pthread_cond_t *c) +{ + c->_c_block = 0; + __wake(&c->_c_block, 1, 0); + return 0; +} diff --git a/05/musl-0.6.0/src/thread/pthread_cond_timedwait.c b/05/musl-0.6.0/src/thread/pthread_cond_timedwait.c new file mode 100644 index 0000000..b0214b4 --- /dev/null +++ b/05/musl-0.6.0/src/thread/pthread_cond_timedwait.c @@ -0,0 +1,26 @@ +#include "pthread_impl.h" + +static void relock(void *m) +{ + pthread_mutex_lock(m); +} + +int pthread_cond_timedwait(pthread_cond_t *c, pthread_mutex_t *m, const struct timespec *ts) +{ + int r, e=0; + CANCELPT(0); + + pthread_cleanup_push(relock, m); + c->_c_block = 1; + if ((r=pthread_mutex_unlock(m))) return r; + + CANCELPT(1); + e = __timedwait(&c->_c_block, 1, CLOCK_REALTIME, ts, 0); + CANCELPT(0); + + pthread_cleanup_pop(0); + if ((r=pthread_mutex_lock(m))) return r; + + CANCELPT(0); + return e; +} diff --git a/05/musl-0.6.0/src/thread/pthread_cond_wait.c b/05/musl-0.6.0/src/thread/pthread_cond_wait.c new file mode 100644 index 0000000..eb70e5f --- /dev/null +++ b/05/musl-0.6.0/src/thread/pthread_cond_wait.c @@ -0,0 +1,6 @@ +#include "pthread_impl.h" + +int pthread_cond_wait(pthread_cond_t *c, pthread_mutex_t *m) +{ + return pthread_cond_timedwait(c, m, 0); +} diff --git a/05/musl-0.6.0/src/thread/pthread_create.c b/05/musl-0.6.0/src/thread/pthread_create.c new file mode 100644 index 0000000..06d554b --- /dev/null +++ b/05/musl-0.6.0/src/thread/pthread_create.c @@ -0,0 +1,228 @@ +#include "pthread_impl.h" + +void __pthread_unwind_next(struct __ptcb *cb) +{ + int i, j, not_finished; + pthread_t self; + + if (cb->__next) longjmp((void *)cb->__next->__jb, 1); + + self = pthread_self(); + if (self->cancel) self->result = PTHREAD_CANCELLED; + + if (!a_fetch_add(&libc.threads_minus_1, -1)) + exit(0); + + LOCK(&self->exitlock); + + not_finished = self->tsd_used; + for (j=0; not_finished && j<PTHREAD_DESTRUCTOR_ITERATIONS; j++) { + not_finished = 0; + for (i=0; i<PTHREAD_KEYS_MAX; i++) { + if (self->tsd[i] && libc.tsd_keys[i]) { + void *tmp = self->tsd[i]; + self->tsd[i] = 0; + libc.tsd_keys[i](tmp); + not_finished = 1; + } + } + } + + if (self->detached && self->map_base) + __unmapself(self->map_base, self->map_size); + + __syscall_exit(0); +} + +static void docancel(struct pthread *self) +{ + struct __ptcb cb = { .__next = self->cancelbuf }; + __pthread_unwind_next(&cb); +} + +static void cancel_handler(int sig, siginfo_t *si, void *ctx) +{ + struct pthread *self = __pthread_self(); + self->cancel = 1; + if (self->canceldisable || (!self->cancelasync && !self->cancelpoint)) + return; + docancel(self); +} + +static void cancelpt(int x) +{ + struct pthread *self = __pthread_self(); + if (self->canceldisable) return; + self->cancelpoint = x; + if (self->cancel) docancel(self); +} + +/* "rsyscall" is a mechanism by which a thread can synchronously force all + * other threads to perform an arbitrary syscall. It is necessary to work + * around the non-conformant implementation of setuid() et al on Linux, + * which affect only the calling thread and not the whole process. This + * implementation performs some tricks with signal delivery to work around + * the fact that it does not keep any list of threads in userspace. */ + +static struct { + volatile int lock, hold, blocks, cnt; + unsigned long arg[6]; + int nr; + int err; +} rs; + +static void rsyscall_handler(int sig, siginfo_t *si, void *ctx) +{ + if (rs.cnt == libc.threads_minus_1) return; + + if (syscall6(rs.nr, rs.arg[0], rs.arg[1], rs.arg[2], + rs.arg[3], rs.arg[4], rs.arg[5]) < 0 && !rs.err) rs.err=errno; + + a_inc(&rs.cnt); + __wake(&rs.cnt, 1, 1); + while(rs.hold) + __wait(&rs.hold, 0, 1, 1); + a_dec(&rs.cnt); + if (!rs.cnt) __wake(&rs.cnt, 1, 1); +} + +static int rsyscall(int nr, long a, long b, long c, long d, long e, long f) +{ + int i, ret; + sigset_t set = { 0 }; + struct pthread *self = __pthread_self(); + sigaddset(&set, SIGSYSCALL); + + LOCK(&rs.lock); + while ((i=rs.blocks)) + __wait(&rs.blocks, 0, i, 1); + + __libc_sigprocmask(SIG_BLOCK, &set, 0); + + rs.nr = nr; + rs.arg[0] = a; rs.arg[1] = b; + rs.arg[2] = c; rs.arg[3] = d; + rs.arg[4] = d; rs.arg[5] = f; + rs.hold = 1; + rs.err = 0; + rs.cnt = 0; + + /* Dispatch signals until all threads respond */ + for (i=libc.threads_minus_1; i; i--) + sigqueue(self->pid, SIGSYSCALL, (union sigval){0}); + while ((i=rs.cnt) < libc.threads_minus_1) { + sigqueue(self->pid, SIGSYSCALL, (union sigval){0}); + __wait(&rs.cnt, 0, i, 1); + } + + /* Handle any lingering signals with no-op */ + __libc_sigprocmask(SIG_UNBLOCK, &set, 0); + + /* Resume other threads' signal handlers and wait for them */ + rs.hold = 0; + __wake(&rs.hold, -1, 0); + while((i=rs.cnt)) __wait(&rs.cnt, 0, i, 1); + + if (rs.err) errno = rs.err, ret = -1; + else ret = syscall6(nr, a, b, c, d, e, f); + + UNLOCK(&rs.lock); + return ret; +} + +static void init_threads() +{ + struct sigaction sa = { .sa_flags = SA_SIGINFO | SA_RESTART }; + libc.lock = __lock; + libc.cancelpt = cancelpt; + libc.rsyscall = rsyscall; + sa.sa_sigaction = cancel_handler; + __libc_sigaction(SIGCANCEL, &sa, 0); + sigaddset(&sa.sa_mask, SIGSYSCALL); + sigaddset(&sa.sa_mask, SIGCANCEL); + sa.sa_sigaction = rsyscall_handler; + __libc_sigaction(SIGSYSCALL, &sa, 0); + sigprocmask(SIG_UNBLOCK, &sa.sa_mask, 0); +} + +static int start(void *p) +{ + struct pthread *self = p; + pthread_exit(self->start(self->start_arg)); + return 0; +} + +int __uniclone(void *, int (*)(), void *); + +#define ROUND(x) (((x)+PAGE_SIZE-1)&-PAGE_SIZE) + +#if 0 +/* pthread_key_create.c overrides this */ +static const size_t dummy = 0; +weak_alias(dummy, __pthread_tsd_size); +#else +extern size_t __pthread_tsd_size; +#endif + +int pthread_create(pthread_t *res, const pthread_attr_t *attr, void *(*entry)(void *), void *arg) +{ + static int init; + int ret; + size_t size, guard; + struct pthread *self = pthread_self(), *new; + unsigned char *map, *stack, *tsd; + static const pthread_attr_t default_attr; + + if (!self) return errno = ENOSYS; + if (!init && ++init) init_threads(); + + if (!attr) attr = &default_attr; + guard = ROUND(attr->_a_guardsize + DEFAULT_GUARD_SIZE); + size = guard + ROUND(attr->_a_stacksize + DEFAULT_STACK_SIZE); + size += __pthread_tsd_size; + map = mmap(0, size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANON, -1, 0); + if (!map) return EAGAIN; + mprotect(map, guard, PROT_NONE); + + tsd = map + size - __pthread_tsd_size; + new = (void *)(tsd - sizeof *new - PAGE_SIZE%sizeof *new); + new->map_base = map; + new->map_size = size; + new->pid = self->pid; + new->errno_ptr = &new->errno_val; + new->start = entry; + new->start_arg = arg; + new->self = new; + new->tsd = (void *)tsd; + new->detached = attr->_a_detach; + new->attr = *attr; + memcpy(new->tlsdesc, self->tlsdesc, sizeof new->tlsdesc); + new->tlsdesc[1] = (uintptr_t)new; + stack = (void *)((uintptr_t)new-1 & ~(uintptr_t)15); + + /* We must synchronize new thread creation with rsyscall + * delivery. This looks to be the least expensive way: */ + a_inc(&rs.blocks); + while (rs.lock) __wait(&rs.lock, 0, 1, 1); + + a_inc(&libc.threads_minus_1); + ret = __uniclone(stack, start, new); + + a_dec(&rs.blocks); + if (rs.lock) __wake(&rs.blocks, 1, 1); + + if (ret < 0) { + a_dec(&libc.threads_minus_1); + munmap(map, size); + return EAGAIN; + } + *res = new; + return 0; +} + +void pthread_exit(void *result) +{ + struct pthread *self = pthread_self(); + self->result = result; + docancel(self); +} diff --git a/05/musl-0.6.0/src/thread/pthread_detach.c b/05/musl-0.6.0/src/thread/pthread_detach.c new file mode 100644 index 0000000..f0eae3e --- /dev/null +++ b/05/musl-0.6.0/src/thread/pthread_detach.c @@ -0,0 +1,11 @@ +#include "pthread_impl.h" + +int pthread_detach(pthread_t t) +{ + /* Cannot detach a thread that's already exiting */ + if (a_xchg(&t->exitlock, 1)) + return pthread_join(t, 0); + t->detached = 1; + t->exitlock = 0; + return 0; +} diff --git a/05/musl-0.6.0/src/thread/pthread_equal.c b/05/musl-0.6.0/src/thread/pthread_equal.c new file mode 100644 index 0000000..a55d280 --- /dev/null +++ b/05/musl-0.6.0/src/thread/pthread_equal.c @@ -0,0 +1,6 @@ +#include <pthread.h> + +int pthread_equal(pthread_t a, pthread_t b) +{ + return a==b; +} diff --git a/05/musl-0.6.0/src/thread/pthread_getspecific.c b/05/musl-0.6.0/src/thread/pthread_getspecific.c new file mode 100644 index 0000000..a6ca27d --- /dev/null +++ b/05/musl-0.6.0/src/thread/pthread_getspecific.c @@ -0,0 +1,8 @@ +#include "pthread_impl.h" + +void *pthread_getspecific(pthread_key_t k) +{ + struct pthread *self = pthread_self(); + if (!self->tsd) return 0; + return self->tsd[k]; +} diff --git a/05/musl-0.6.0/src/thread/pthread_join.c b/05/musl-0.6.0/src/thread/pthread_join.c new file mode 100644 index 0000000..5210ed4 --- /dev/null +++ b/05/musl-0.6.0/src/thread/pthread_join.c @@ -0,0 +1,12 @@ +#include "pthread_impl.h" + +int pthread_join(pthread_t t, void **res) +{ + int tmp = t->tid; + CANCELPT_BEGIN; + if (tmp) __wait(&t->tid, 0, tmp, 1); + CANCELPT_END; + if (res) *res = t->result; + if (t->map_base) munmap(t->map_base, t->map_size); + return 0; +} diff --git a/05/musl-0.6.0/src/thread/pthread_key_create.c b/05/musl-0.6.0/src/thread/pthread_key_create.c new file mode 100644 index 0000000..efc3804 --- /dev/null +++ b/05/musl-0.6.0/src/thread/pthread_key_create.c @@ -0,0 +1,25 @@ +#include "pthread_impl.h" + +const size_t __pthread_tsd_size = sizeof(void *) * PTHREAD_KEYS_MAX; + +static void nodtor(void *dummy) +{ +} + +int pthread_key_create(pthread_key_t *k, void (*dtor)(void *)) +{ + static void (*keys[PTHREAD_KEYS_MAX])(void *); + int i = (uintptr_t)&k / 16 % PTHREAD_KEYS_MAX; + int j = i; + + libc.tsd_keys = keys; + if (!dtor) dtor = nodtor; + /* Cheap trick - &k cannot match any destructor pointer */ + while (a_cas_p(keys+j, 0, &k) + && (j=(j+1)%PTHREAD_KEYS_MAX) != i); + if (keys[j] != (void (*)(void *))&k) + return EAGAIN; + keys[j] = dtor; + *k = j; + return 0; +} diff --git a/05/musl-0.6.0/src/thread/pthread_key_delete.c b/05/musl-0.6.0/src/thread/pthread_key_delete.c new file mode 100644 index 0000000..4914ebb --- /dev/null +++ b/05/musl-0.6.0/src/thread/pthread_key_delete.c @@ -0,0 +1,7 @@ +#include "pthread_impl.h" + +int pthread_key_delete(pthread_key_t k) +{ + if (libc.tsd_keys) libc.tsd_keys[k] = 0; + return 0; +} diff --git a/05/musl-0.6.0/src/thread/pthread_kill.c b/05/musl-0.6.0/src/thread/pthread_kill.c new file mode 100644 index 0000000..9d85fa5 --- /dev/null +++ b/05/musl-0.6.0/src/thread/pthread_kill.c @@ -0,0 +1,7 @@ +#define SYSCALL_RETURN_ERRNO +#include "pthread_impl.h" + +int pthread_kill(pthread_t t, int sig) +{ + return syscall3(__NR_tgkill, t->pid, t->tid, sig); +} diff --git a/05/musl-0.6.0/src/thread/pthread_mutex_destroy.c b/05/musl-0.6.0/src/thread/pthread_mutex_destroy.c new file mode 100644 index 0000000..6d49e68 --- /dev/null +++ b/05/musl-0.6.0/src/thread/pthread_mutex_destroy.c @@ -0,0 +1,6 @@ +#include <pthread.h> + +int pthread_mutex_destroy(pthread_mutex_t *mutex) +{ + return 0; +} diff --git a/05/musl-0.6.0/src/thread/pthread_mutex_init.c b/05/musl-0.6.0/src/thread/pthread_mutex_init.c new file mode 100644 index 0000000..d453543 --- /dev/null +++ b/05/musl-0.6.0/src/thread/pthread_mutex_init.c @@ -0,0 +1,9 @@ +#include "pthread_impl.h" + +int pthread_mutex_init(pthread_mutex_t *m, const pthread_mutexattr_t *a) +{ + memset(m, 0, sizeof *m); + if (a) { + } + return 0; +} diff --git a/05/musl-0.6.0/src/thread/pthread_mutex_lock.c b/05/musl-0.6.0/src/thread/pthread_mutex_lock.c new file mode 100644 index 0000000..15ede3f --- /dev/null +++ b/05/musl-0.6.0/src/thread/pthread_mutex_lock.c @@ -0,0 +1,9 @@ +#include "pthread_impl.h" + +int pthread_mutex_lock(pthread_mutex_t *m) +{ + int r; + while ((r=pthread_mutex_trylock(m)) == EBUSY) + __wait(&m->_m_lock, &m->_m_waiters, 1, 0); + return r; +} diff --git a/05/musl-0.6.0/src/thread/pthread_mutex_timedlock.c b/05/musl-0.6.0/src/thread/pthread_mutex_timedlock.c new file mode 100644 index 0000000..20ce012 --- /dev/null +++ b/05/musl-0.6.0/src/thread/pthread_mutex_timedlock.c @@ -0,0 +1,15 @@ +#include "pthread_impl.h" + +int pthread_mutex_timedlock(pthread_mutex_t *m, const struct timespec *at) +{ + int r, w=0; + while ((r=pthread_mutex_trylock(m)) == EBUSY) { + if (!w) a_inc(&m->_m_waiters), w++; + if (__timedwait(&m->_m_lock, 1, CLOCK_REALTIME, at, 0) == ETIMEDOUT) { + if (w) a_dec(&m->_m_waiters); + return ETIMEDOUT; + } + } + if (w) a_dec(&m->_m_waiters); + return r; +} diff --git a/05/musl-0.6.0/src/thread/pthread_mutex_trylock.c b/05/musl-0.6.0/src/thread/pthread_mutex_trylock.c new file mode 100644 index 0000000..29268fd --- /dev/null +++ b/05/musl-0.6.0/src/thread/pthread_mutex_trylock.c @@ -0,0 +1,28 @@ +#include "pthread_impl.h" + +int pthread_mutex_trylock(pthread_mutex_t *m) +{ + if (m->_m_type == PTHREAD_MUTEX_RECURSIVE) { + pthread_t self = pthread_self(); + if (m->_m_owner == self->tid) { + if ((unsigned)m->_m_lock >= INT_MAX) return EAGAIN; + a_inc(&m->_m_lock); + return 0; + } + if (a_fetch_add(&m->_m_lock, 1)) { + if (a_fetch_add(&m->_m_lock, -1)==1 && m->_m_waiters) + __wake(&m->_m_lock, 1, 0); + return EBUSY; + } + m->_m_owner = self->tid; + return 0; + } + + if (a_xchg(&m->_m_lock, 1)) + if (m->_m_type == PTHREAD_MUTEX_ERRORCHECK + && m->_m_owner == pthread_self()->tid) return EDEADLK; + else return EBUSY; + if (m->_m_type == PTHREAD_MUTEX_ERRORCHECK) + m->_m_owner = pthread_self()->tid; + return 0; +} diff --git a/05/musl-0.6.0/src/thread/pthread_mutex_unlock.c b/05/musl-0.6.0/src/thread/pthread_mutex_unlock.c new file mode 100644 index 0000000..0275eb5 --- /dev/null +++ b/05/musl-0.6.0/src/thread/pthread_mutex_unlock.c @@ -0,0 +1,19 @@ +#include "pthread_impl.h" + +int pthread_mutex_unlock(pthread_mutex_t *m) +{ + if (m->_m_type == PTHREAD_MUTEX_RECURSIVE) { + if (a_fetch_add(&m->_m_lock, -1)==1 && m->_m_waiters) + __wake(&m->_m_lock, 1, 0); + return 0; + } + + if (m->_m_type == PTHREAD_MUTEX_ERRORCHECK + && m->_m_owner != pthread_self()->tid) + return EPERM; + + m->_m_owner = 0; + m->_m_lock = 0; + if (m->_m_waiters) __wake(&m->_m_lock, 1, 0); + return 0; +} diff --git a/05/musl-0.6.0/src/thread/pthread_mutexattr_destroy.c b/05/musl-0.6.0/src/thread/pthread_mutexattr_destroy.c new file mode 100644 index 0000000..9fd6974 --- /dev/null +++ b/05/musl-0.6.0/src/thread/pthread_mutexattr_destroy.c @@ -0,0 +1,6 @@ +#include "pthread_impl.h" + +int pthread_mutexattr_destroy(pthread_mutexattr_t *a) +{ + return 0; +} diff --git a/05/musl-0.6.0/src/thread/pthread_mutexattr_gettype.c b/05/musl-0.6.0/src/thread/pthread_mutexattr_gettype.c new file mode 100644 index 0000000..9edb16c --- /dev/null +++ b/05/musl-0.6.0/src/thread/pthread_mutexattr_gettype.c @@ -0,0 +1,7 @@ +#include "pthread_impl.h" + +int pthread_mutexattr_gettype(const pthread_mutexattr_t *a, int *type) +{ + *type = *a & 3; + return 0; +} diff --git a/05/musl-0.6.0/src/thread/pthread_mutexattr_init.c b/05/musl-0.6.0/src/thread/pthread_mutexattr_init.c new file mode 100644 index 0000000..ea63106 --- /dev/null +++ b/05/musl-0.6.0/src/thread/pthread_mutexattr_init.c @@ -0,0 +1,7 @@ +#include "pthread_impl.h" + +int pthread_mutexattr_init(pthread_mutexattr_t *a) +{ + memset(a, 0, sizeof *a); + return 0; +} diff --git a/05/musl-0.6.0/src/thread/pthread_mutexattr_settype.c b/05/musl-0.6.0/src/thread/pthread_mutexattr_settype.c new file mode 100644 index 0000000..4e85950 --- /dev/null +++ b/05/musl-0.6.0/src/thread/pthread_mutexattr_settype.c @@ -0,0 +1,8 @@ +#include "pthread_impl.h" + +int pthread_mutexattr_settype(pthread_mutexattr_t *a, int type) +{ + if ((unsigned)type > 2) return EINVAL; + *a = (*a & ~3) | type; + return 0; +} diff --git a/05/musl-0.6.0/src/thread/pthread_once.c b/05/musl-0.6.0/src/thread/pthread_once.c new file mode 100644 index 0000000..7223005 --- /dev/null +++ b/05/musl-0.6.0/src/thread/pthread_once.c @@ -0,0 +1,38 @@ +#include "pthread_impl.h" + +static void undo(void *control) +{ + a_store(control, 0); + __wake(control, 1, 0); +} + +int pthread_once(pthread_once_t *control, void (*init)(void)) +{ + static int waiters; + + /* Return immediately if init finished before */ + if (*control == 2) return 0; + + /* Try to enter initializing state. Three possibilities: + * 0 - we're the first or the other cancelled; run init + * 1 - another thread is running init; wait + * 2 - another thread finished running init; just return */ + + for (;;) switch (a_swap(control, 1)) { + case 0: + break; + case 1: + __wait(control, &waiters, 1, 0); + continue; + case 2: + a_store(control, 2); + return 0; + } + + pthread_cleanup_push(undo, control); + init(); + pthread_cleanup_pop(0); + + if (waiters) __wake(control, -1, 0); + return 0; +} diff --git a/05/musl-0.6.0/src/thread/pthread_rwlock_destroy.c b/05/musl-0.6.0/src/thread/pthread_rwlock_destroy.c new file mode 100644 index 0000000..49ecfbd --- /dev/null +++ b/05/musl-0.6.0/src/thread/pthread_rwlock_destroy.c @@ -0,0 +1,6 @@ +#include "pthread_impl.h" + +int pthread_rwlock_destroy(pthread_rwlock_t *rw) +{ + return 0; +} diff --git a/05/musl-0.6.0/src/thread/pthread_rwlock_init.c b/05/musl-0.6.0/src/thread/pthread_rwlock_init.c new file mode 100644 index 0000000..f87d566 --- /dev/null +++ b/05/musl-0.6.0/src/thread/pthread_rwlock_init.c @@ -0,0 +1,9 @@ +#include "pthread_impl.h" + +int pthread_rwlock_init(pthread_rwlock_t *rw, const pthread_rwlockattr_t *a) +{ + memset(rw, 0, sizeof *rw); + if (a) { + } + return 0; +} diff --git a/05/musl-0.6.0/src/thread/pthread_rwlock_rdlock.c b/05/musl-0.6.0/src/thread/pthread_rwlock_rdlock.c new file mode 100644 index 0000000..2986350 --- /dev/null +++ b/05/musl-0.6.0/src/thread/pthread_rwlock_rdlock.c @@ -0,0 +1,8 @@ +#include "pthread_impl.h" + +int pthread_rwlock_rdlock(pthread_rwlock_t *rw) +{ + while (pthread_rwlock_tryrdlock(rw)) + __wait(&rw->_rw_wrlock, &rw->_rw_waiters, 1, 0); + return 0; +} diff --git a/05/musl-0.6.0/src/thread/pthread_rwlock_timedrdlock.c b/05/musl-0.6.0/src/thread/pthread_rwlock_timedrdlock.c new file mode 100644 index 0000000..1e76a8e --- /dev/null +++ b/05/musl-0.6.0/src/thread/pthread_rwlock_timedrdlock.c @@ -0,0 +1,15 @@ +#include "pthread_impl.h" + +int pthread_rwlock_timedrdlock(pthread_rwlock_t *rw, const struct timespec *at) +{ + int w=0; + while (pthread_rwlock_tryrdlock(rw)) { + if (!w) a_inc(&rw->_rw_waiters), w++; + if (__timedwait(&rw->_rw_wrlock, 1, CLOCK_REALTIME, at, 0)==ETIMEDOUT) { + if (w) a_dec(&rw->_rw_waiters); + return ETIMEDOUT; + } + } + if (w) a_dec(&rw->_rw_waiters); + return 0; +} diff --git a/05/musl-0.6.0/src/thread/pthread_rwlock_timedwrlock.c b/05/musl-0.6.0/src/thread/pthread_rwlock_timedwrlock.c new file mode 100644 index 0000000..9682774 --- /dev/null +++ b/05/musl-0.6.0/src/thread/pthread_rwlock_timedwrlock.c @@ -0,0 +1,17 @@ +#include "pthread_impl.h" + +int pthread_rwlock_timedwrlock(pthread_rwlock_t *rw, const struct timespec *at) +{ + int nr, *p, w=0; + while (pthread_rwlock_trywrlock(rw)==EAGAIN) { + if (!w) a_inc(&rw->_rw_waiters), w++; + if ((nr=rw->_rw_readers)) p = &rw->_rw_readers; + else nr=1, p = &rw->_rw_wrlock; + if (__timedwait(p, nr, CLOCK_REALTIME, at, 0)==ETIMEDOUT) { + if (w) a_dec(&rw->_rw_waiters); + return ETIMEDOUT; + } + } + if (w) a_dec(&rw->_rw_waiters); + return 0; +} diff --git a/05/musl-0.6.0/src/thread/pthread_rwlock_tryrdlock.c b/05/musl-0.6.0/src/thread/pthread_rwlock_tryrdlock.c new file mode 100644 index 0000000..fc1d532 --- /dev/null +++ b/05/musl-0.6.0/src/thread/pthread_rwlock_tryrdlock.c @@ -0,0 +1,13 @@ +#include "pthread_impl.h" + +int pthread_rwlock_tryrdlock(pthread_rwlock_t *rw) +{ + a_inc(&rw->_rw_readers); + if (rw->_rw_wrlock) { + a_dec(&rw->_rw_readers); + if (rw->_rw_waiters && !rw->_rw_readers) + __wake(&rw->_rw_readers, 1, 0); + return EAGAIN; + } + return 0; +} diff --git a/05/musl-0.6.0/src/thread/pthread_rwlock_trywrlock.c b/05/musl-0.6.0/src/thread/pthread_rwlock_trywrlock.c new file mode 100644 index 0000000..1bcf7c9 --- /dev/null +++ b/05/musl-0.6.0/src/thread/pthread_rwlock_trywrlock.c @@ -0,0 +1,13 @@ +#include "pthread_impl.h" + +int pthread_rwlock_trywrlock(pthread_rwlock_t *rw) +{ + if (a_xchg(&rw->_rw_wrlock, 1)) + return EAGAIN; + if (rw->_rw_readers) { + a_store(&rw->_rw_wrlock, 0); + return EAGAIN; + } + rw->_rw_owner = pthread_self()->tid; + return 0; +} diff --git a/05/musl-0.6.0/src/thread/pthread_rwlock_unlock.c b/05/musl-0.6.0/src/thread/pthread_rwlock_unlock.c new file mode 100644 index 0000000..060e3fe --- /dev/null +++ b/05/musl-0.6.0/src/thread/pthread_rwlock_unlock.c @@ -0,0 +1,17 @@ +#include "pthread_impl.h" + +int pthread_rwlock_unlock(pthread_rwlock_t *rw) +{ + struct pthread *self = pthread_self(); + if (rw->_rw_owner == self->tid) { + rw->_rw_owner = 0; + a_store(&rw->_rw_wrlock, 0); + if (rw->_rw_waiters) + __wake(&rw->_rw_wrlock, -1, 0); + return 0; + } + a_dec(&rw->_rw_readers); + if (rw->_rw_waiters && !rw->_rw_readers) + __wake(&rw->_rw_readers, 1, 0); + return 0; +} diff --git a/05/musl-0.6.0/src/thread/pthread_rwlock_wrlock.c b/05/musl-0.6.0/src/thread/pthread_rwlock_wrlock.c new file mode 100644 index 0000000..8fd9ad1 --- /dev/null +++ b/05/musl-0.6.0/src/thread/pthread_rwlock_wrlock.c @@ -0,0 +1,13 @@ +#include "pthread_impl.h" + +int pthread_rwlock_wrlock(pthread_rwlock_t *rw) +{ + int nr; + while (pthread_rwlock_trywrlock(rw)==EAGAIN) { + if ((nr=rw->_rw_readers)) + __wait(&rw->_rw_readers, &rw->_rw_waiters, nr, 0); + else + __wait(&rw->_rw_wrlock, &rw->_rw_waiters, 1, 0); + } + return 0; +} diff --git a/05/musl-0.6.0/src/thread/pthread_self.c b/05/musl-0.6.0/src/thread/pthread_self.c new file mode 100644 index 0000000..3a4d4c5 --- /dev/null +++ b/05/musl-0.6.0/src/thread/pthread_self.c @@ -0,0 +1,33 @@ +#include "pthread_impl.h" + +static struct pthread main_thread; + +#undef errno +static int *errno_location() +{ + return __pthread_self()->errno_ptr; +} + +static int init_main_thread() +{ + main_thread.self = &main_thread; + if (__set_thread_area(&main_thread) < 0) + return -1; + syscall1(__NR_set_tid_address, (long)&main_thread.tid); + main_thread.errno_ptr = __errno_location(); + libc.errno_location = errno_location; + main_thread.tid = main_thread.pid = getpid(); + return 0; +} + +pthread_t pthread_self() +{ + static int init, failed; + if (!init) { + if (failed) return 0; + if (init_main_thread() < 0) failed = 1; + if (failed) return 0; + init = 1; + } + return __pthread_self(); +} diff --git a/05/musl-0.6.0/src/thread/pthread_setcancelstate.c b/05/musl-0.6.0/src/thread/pthread_setcancelstate.c new file mode 100644 index 0000000..23c3885 --- /dev/null +++ b/05/musl-0.6.0/src/thread/pthread_setcancelstate.c @@ -0,0 +1,10 @@ +#include "pthread_impl.h" + +int pthread_setcancelstate(int new, int *old) +{ + struct pthread *self = pthread_self(); + if (old) *old = self->canceldisable; + if ((unsigned)new > 1) return EINVAL; + self->canceldisable = new; + return 0; +} diff --git a/05/musl-0.6.0/src/thread/pthread_setcanceltype.c b/05/musl-0.6.0/src/thread/pthread_setcanceltype.c new file mode 100644 index 0000000..c73db22 --- /dev/null +++ b/05/musl-0.6.0/src/thread/pthread_setcanceltype.c @@ -0,0 +1,10 @@ +#include "pthread_impl.h" + +int pthread_setcanceltype(int new, int *old) +{ + struct pthread *self = pthread_self(); + if (old) *old = self->cancelasync; + if ((unsigned)new > 1) return EINVAL; + self->cancelasync = new; + return 0; +} diff --git a/05/musl-0.6.0/src/thread/pthread_setspecific.c b/05/musl-0.6.0/src/thread/pthread_setspecific.c new file mode 100644 index 0000000..171cef4 --- /dev/null +++ b/05/musl-0.6.0/src/thread/pthread_setspecific.c @@ -0,0 +1,18 @@ +#include "pthread_impl.h" + +int pthread_setspecific(pthread_key_t k, const void *x) +{ + struct pthread *self = pthread_self(); + /* Handle the case of the main thread */ + if (!self->tsd) { + if (!x) return 0; + if (!(self->tsd = calloc(sizeof(void *), PTHREAD_KEYS_MAX))) + return ENOMEM; + } + /* Avoid unnecessary COW */ + if (self->tsd[k] != x) { + self->tsd[k] = (void *)x; + self->tsd_used = 1; + } + return 0; +} diff --git a/05/musl-0.6.0/src/thread/pthread_spin_destroy.c b/05/musl-0.6.0/src/thread/pthread_spin_destroy.c new file mode 100644 index 0000000..e65a820 --- /dev/null +++ b/05/musl-0.6.0/src/thread/pthread_spin_destroy.c @@ -0,0 +1,6 @@ +#include "pthread_impl.h" + +int pthread_spin_destroy(pthread_spinlock_t *s) +{ + return 0; +} diff --git a/05/musl-0.6.0/src/thread/pthread_spin_init.c b/05/musl-0.6.0/src/thread/pthread_spin_init.c new file mode 100644 index 0000000..681881c --- /dev/null +++ b/05/musl-0.6.0/src/thread/pthread_spin_init.c @@ -0,0 +1,6 @@ +#include "pthread_impl.h" + +int pthread_spin_init(pthread_spinlock_t *s, int shared) +{ + return *s = 0; +} diff --git a/05/musl-0.6.0/src/thread/pthread_spin_lock.c b/05/musl-0.6.0/src/thread/pthread_spin_lock.c new file mode 100644 index 0000000..59fa6ea --- /dev/null +++ b/05/musl-0.6.0/src/thread/pthread_spin_lock.c @@ -0,0 +1,7 @@ +#include "pthread_impl.h" + +int pthread_spin_lock(pthread_spinlock_t *s) +{ + while (a_xchg(s, 1)); + return 0; +} diff --git a/05/musl-0.6.0/src/thread/pthread_spin_trylock.c b/05/musl-0.6.0/src/thread/pthread_spin_trylock.c new file mode 100644 index 0000000..c12696b --- /dev/null +++ b/05/musl-0.6.0/src/thread/pthread_spin_trylock.c @@ -0,0 +1,6 @@ +#include "pthread_impl.h" + +int pthread_spin_trylock(pthread_spinlock_t *s) +{ + return -a_xchg(s, 1) & EBUSY; +} diff --git a/05/musl-0.6.0/src/thread/pthread_spin_unlock.c b/05/musl-0.6.0/src/thread/pthread_spin_unlock.c new file mode 100644 index 0000000..a7eab33 --- /dev/null +++ b/05/musl-0.6.0/src/thread/pthread_spin_unlock.c @@ -0,0 +1,6 @@ +#include "pthread_impl.h" + +int pthread_spin_unlock(pthread_spinlock_t *s) +{ + return *s = 0; +} diff --git a/05/musl-0.6.0/src/thread/pthread_testcancel.c b/05/musl-0.6.0/src/thread/pthread_testcancel.c new file mode 100644 index 0000000..774b706 --- /dev/null +++ b/05/musl-0.6.0/src/thread/pthread_testcancel.c @@ -0,0 +1,7 @@ +#include "pthread_impl.h" + +void pthread_testcancel() +{ + CANCELPT_BEGIN; + CANCELPT_END; +} diff --git a/05/musl-0.6.0/src/thread/x86_64/__set_thread_area.s b/05/musl-0.6.0/src/thread/x86_64/__set_thread_area.s new file mode 100644 index 0000000..faf73ec --- /dev/null +++ b/05/musl-0.6.0/src/thread/x86_64/__set_thread_area.s @@ -0,0 +1,11 @@ +/* Copyright 2011 Nicholas J. Kain, licensed GNU LGPL 2.1 or later */ +.text +.global __set_thread_area +.type __set_thread_area,%function +__set_thread_area: + mov %rdi,%rsi /* shift for syscall */ + movl $0x1002,%edi /* SET_FS register */ + movl $158,%eax /* set fs segment to */ + syscall /* arch_prctl(SET_FS, arg)*/ + ret +.size __set_thread_area,.-__set_thread_area diff --git a/05/musl-0.6.0/src/thread/x86_64/__unmapself.s b/05/musl-0.6.0/src/thread/x86_64/__unmapself.s new file mode 100644 index 0000000..59092ea --- /dev/null +++ b/05/musl-0.6.0/src/thread/x86_64/__unmapself.s @@ -0,0 +1,24 @@ +/* Copyright 2011 Nicholas J. Kain, licensed GNU LGPL 2.1 or later */ +.text +.global __unmapself +.type __unmapself,%function +__unmapself: + call 1f /* glibc ABI compat */ + .long -1 + .long -1 +1: push %rsi /* save arg2 for munmap */ + push %rdx /* save arg3 for munmap */ + mov %rdi,%rsi /* rt_sigprocmask() args: move arg1 to rsi */ + xor %rdi,%rdi + xor %rdx,%rdx + movq $8,%r10 + movl $14,%eax /* __NR_rt_sigprocmask */ + syscall /* call rt_sigprocmask(0,arg1,0,8) */ + pop %rsi /* munmap() args: reload from stack */ + pop %rdi + movl $11,%eax /* __NR_munmap */ + syscall /* munmap(arg2,arg3) */ + xor %rdi,%rdi /* exit() args: always return success */ + movl $60,%eax /* __NR_exit */ + syscall /* exit(0) */ +.size __unmapself,.-__unmapself diff --git a/05/musl-0.6.0/src/thread/x86_64/clone.s b/05/musl-0.6.0/src/thread/x86_64/clone.s new file mode 100644 index 0000000..3cefd93 --- /dev/null +++ b/05/musl-0.6.0/src/thread/x86_64/clone.s @@ -0,0 +1,22 @@ +/* Copyright 2011 Nicholas J. Kain, licensed GNU LGPL 2.1 or later */ +.text +.global __uniclone +.type __uniclone,%function +/* rdi = child_stack, rsi = start, rdx = pthread_struct */ +__uniclone: + subq $8,%rsp /* pad parent stack to prevent branch later */ + subq $16,%rdi /* grow child_stack */ + mov %rsi,8(%rdi) /* push start onto child_stack as return ptr */ + mov %rdx,0(%rdi) /* push pthread_struct onto child_stack */ + mov %rdx,%r8 /* r8 = tls */ + mov %rdi,%rsi /* rsi = child_stack */ + leaq 40(%rdx),%r10 /* r10 = child_id */ + movl $56,%eax /* clone syscall number */ + movl $0x7d0f00,%edi /* rdi = flags */ + mov %r10,%rdx /* rdx = parent_id */ + syscall /* clone(flags, child_stack, parent_id, + * child_id, tls) */ + pop %rdi /* child stack: restore pthread_struct + * parent stack: undo rsp displacement */ + ret +.size __uniclone,.-__uniclone |