|
Message-Id: <84b57c4f92b17384a2acdb2909d7ad8290abe31f.1409524413.git.Jens.Gustedt@inria.fr> Date: Mon, 01 Sep 2014 00:47:26 +0200 From: Jens Gustedt <Jens.Gustedt@...ia.fr> To: musl@...ts.openwall.com Subject: [PATCH 7/9] add the thrd_xxxxxx functions The major difficulty with C threads versus pthread is that the thread start functions have different signatures. Basing the C threads implementation on pthreads therefore needs to do some ugly cast with function pointers and function results. We try to be the least intrusive for the existing pthreads implementation, to make sure we don't break anything and also to ease maintenance and simultaneous improvement of the code base later on. Unfortunately this is not completely trivial. Not only are some calling conventions different, but also the level of requested detail for error returns varies in the two models. Where POSIX maps most possible errors of pthread_create to EAGAIN, C threads require the condition of being out of memory to be identified. --- src/internal/pthread_impl.h | 2 ++ src/sched/thrd_yield.c | 7 +++++++ src/thread/pthread_create.c | 32 +++++++++++++++++++++----------- src/thread/thrd_create.c | 14 ++++++++++++++ src/thread/thrd_current.c | 11 +++++++++++ src/thread/thrd_detach.c | 11 +++++++++++ src/thread/thrd_equal.c | 6 ++++++ src/thread/thrd_exit.c | 10 ++++++++++ src/thread/thrd_join.c | 12 ++++++++++++ src/time/thrd_sleep.c | 14 +++++++------- 10 files changed, 101 insertions(+), 18 deletions(-) create mode 100644 src/sched/thrd_yield.c create mode 100644 src/thread/thrd_create.c create mode 100644 src/thread/thrd_current.c create mode 100644 src/thread/thrd_detach.c create mode 100644 src/thread/thrd_equal.c create mode 100644 src/thread/thrd_exit.c create mode 100644 src/thread/thrd_join.c 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/sched/thrd_yield.c b/src/sched/thrd_yield.c new file mode 100644 index 0000000..09d534b --- /dev/null +++ b/src/sched/thrd_yield.c @@ -0,0 +1,7 @@ +#include <sched.h> +#include "syscall.h" + +void thrd_yield() +{ + syscall(SYS_sched_yield); +} diff --git a/src/thread/pthread_create.c b/src/thread/pthread_create.c index ed265fb..c1feb62 100644 --- a/src/thread/pthread_create.c +++ b/src/thread/pthread_create.c @@ -4,10 +4,12 @@ #include "libc.h" #include <sys/mman.h> #include <string.h> +#include <threads.h> void *__mmap(void *, size_t, int, int, int, off_t); int __munmap(void *, size_t); int __mprotect(void *, size_t, int); +_Noreturn void __thrd_exit(int); static void dummy_0() { @@ -123,6 +125,14 @@ static int start(void *p) return 0; } +static int start_c11(void *p) +{ + thrd_t self = p; + int (*start)(void*) = (int(*)(void*)) self->start; + __thrd_exit(start(self->start_arg)); + return 0; +} + #define ROUND(x) (((x)+PAGE_SIZE-1)&-PAGE_SIZE) /* pthread_key_create.c overrides this */ @@ -143,10 +153,10 @@ static void init_file_lock(FILE *f) void *__copy_tls(unsigned char *); -static 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; - size_t size, guard; + int ret, c11 = (attrp == __ATTRP_C11_THREAD); + size_t size, guard = 0; struct pthread *self, *new; unsigned char *map = 0, *stack = 0, *tsd = 0, *stack_limit; unsigned flags = CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND @@ -167,7 +177,7 @@ static int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restr self->tsd = (void **)__pthread_tsd_main; libc.threaded = 1; } - if (attrp) attr = *attrp; + if (attrp && !c11) attr = *attrp; __acquire_ptc(); @@ -196,14 +206,14 @@ static int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restr if (!tsd) { if (guard) { map = __mmap(0, size, PROT_NONE, MAP_PRIVATE|MAP_ANON, -1, 0); - if (map == MAP_FAILED) goto fail; + if (map == MAP_FAILED) goto fail_nomem; if (__mprotect(map+guard, size-guard, PROT_READ|PROT_WRITE)) { __munmap(map, size); - goto fail; + goto fail_nomem; } } else { map = __mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0); - if (map == MAP_FAILED) goto fail; + if (map == MAP_FAILED) goto fail_nomem; } tsd = map + size - __pthread_tsd_size; if (!stack) { @@ -234,7 +244,7 @@ static int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restr 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(); @@ -245,7 +255,7 @@ static int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restr if (ret < 0) { a_dec(&libc.threads_minus_1); if (map) __munmap(map, size); - return EAGAIN; + return (!c11 || ret != -ENOMEM) ? EAGAIN : ENOMEM; } if (do_sched) { @@ -258,9 +268,9 @@ static int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restr *res = new; return 0; -fail: +fail_nomem: __release_ptc(); - return EAGAIN; + return c11 ? ENOMEM : EAGAIN; } weak_alias(__pthread_exit, pthread_exit); diff --git a/src/thread/thrd_create.c b/src/thread/thrd_create.c new file mode 100644 index 0000000..09c1d9e --- /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 ENOMEM: return thrd_nomem; + /* The call may also return ENOSYS or EAGAIN. */ + default: return thrd_error; + } +} diff --git a/src/thread/thrd_current.c b/src/thread/thrd_current.c new file mode 100644 index 0000000..d9dabde --- /dev/null +++ b/src/thread/thrd_current.c @@ -0,0 +1,11 @@ +#include "pthread_impl.h" +#include <threads.h> + +/* Not all arch have __pthread_self as a symbol. On some this results + in some magic. So this "call" to __pthread_self is not necessary a + tail call. In particular, other than the appearance, thrd_current + can not be implemented as a weak symbol. */ +thrd_t thrd_current() +{ + return __pthread_self(); +} diff --git a/src/thread/thrd_detach.c b/src/thread/thrd_detach.c new file mode 100644 index 0000000..b0b153c --- /dev/null +++ b/src/thread/thrd_detach.c @@ -0,0 +1,11 @@ +#include <threads.h> + +int __pthread_detach(thrd_t t); + +int thrd_detach(thrd_t t) +{ + /* This internal function never fails, so it always returns + * 0. Under the assumption that thrd_success is 0 this is a + * tail call. */ + return __pthread_detach(t); +} diff --git a/src/thread/thrd_equal.c b/src/thread/thrd_equal.c new file mode 100644 index 0000000..ac49a44 --- /dev/null +++ b/src/thread/thrd_equal.c @@ -0,0 +1,6 @@ +#include <threads.h> + +int (thrd_equal)(thrd_t a, thrd_t b) +{ + return a==b; +} diff --git a/src/thread/thrd_exit.c b/src/thread/thrd_exit.c new file mode 100644 index 0000000..50952ac --- /dev/null +++ b/src/thread/thrd_exit.c @@ -0,0 +1,10 @@ +#include "pthread_impl.h" +#include <threads.h> + +_Noreturn void __pthread_exit(void *); + +_Noreturn void __thrd_exit(int result) { + __pthread_exit((void*)(intptr_t)result); +} + +weak_alias(__thrd_exit, thrd_exit); 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/time/thrd_sleep.c b/src/time/thrd_sleep.c index 3dbfe47..d8eaafd 100644 --- a/src/time/thrd_sleep.c +++ b/src/time/thrd_sleep.c @@ -5,21 +5,21 @@ #include "threads.h" /* Roughly __syscall already returns the right thing: 0 if all went - well or a negative error indication, otherwise. */ + * well or a negative error indication, otherwise. */ int thrd_sleep(const struct timespec *req, struct timespec *rem) { int ret = __syscall(SYS_nanosleep, req, rem); switch (ret) { case 0: return 0; - /* error described by POSIX: */ - /* EINTR The nanosleep() function was interrupted by a signal. */ - /* The C11 wording is: */ - /* -1 if it has been interrupted by a signal */ + /* error described by POSIX: + * EINTR The nanosleep() function was interrupted by a signal. + * The C11 wording is: + * -1 if it has been interrupted by a signal */ case -EINTR: return -1; - /* EINVAL: described by POSIX */ - /* EFAULT: described for linux */ + /* EINVAL: described by POSIX + * EFAULT: described for linux */ default: return -2; } -- 1.7.10.4
Powered by blists - more mailing lists
Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.