add C11 thread creation and related thread functions
authorRich Felker <dalias@aerifal.cx>
Sun, 7 Sep 2014 14:28:08 +0000 (10:28 -0400)
committerRich Felker <dalias@aerifal.cx>
Sun, 7 Sep 2014 14:28:08 +0000 (10:28 -0400)
based on patch by Jens Gustedt.

the main difficulty here is handling the difference between start
function signatures and thread return types for C11 threads versus
POSIX threads. pointers to void are assumed to be able to represent
faithfully all values of int. the function pointer for the thread
start function is cast to an incorrect type for passing through
pthread_create, but is cast back to its correct type before calling so
that the behavior of the call is well-defined.

changes to the existing threads implementation were kept minimal to
reduce the risk of regressions, and duplication of code that carries
implementation-specific assumptions was avoided for ease and safety of
future maintenance.

src/internal/pthread_impl.h
src/thread/pthread_create.c
src/thread/pthread_detach.c
src/thread/pthread_equal.c
src/thread/pthread_self.c
src/thread/thrd_create.c [new file with mode: 0644]
src/thread/thrd_exit.c [new file with mode: 0644]
src/thread/thrd_join.c [new file with mode: 0644]
src/thread/thrd_sleep.c [new file with mode: 0644]
src/thread/thrd_yield.c [new file with mode: 0644]

index 74c62cce81774cdcdbcb9f0f586788c6a98fb9d4..ae6e60b5ebc6d4bfd28ee9bb8adc136b8321d5dd 100644 (file)
@@ -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
index c170a999cb0b2ddc070e56ebe215585f9e482944..1a47ed15eebf96d0c8d5de4aea54108bc8cc3f53 100644 (file)
@@ -119,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;
 }
 
@@ -145,7 +153,7 @@ 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 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;
@@ -167,7 +175,7 @@ int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict att
                self->tsd = (void **)__pthread_tsd_main;
                libc.threaded = 1;
        }
-       if (attrp) attr = *attrp;
+       if (attrp && !c11) attr = *attrp;
 
        __acquire_ptc();
 
@@ -234,7 +242,7 @@ int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict att
        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();
 
index 4e45463489153a1ffdbae4858268a1d204356513..ed77f74d520bff3a16ef5e055f08bbf021fe91d4 100644 (file)
@@ -1,8 +1,9 @@
 #include "pthread_impl.h"
+#include <threads.h>
 
 int __pthread_join(pthread_t, void **);
 
-int __pthread_detach(pthread_t t)
+static int __pthread_detach(pthread_t t)
 {
        /* Cannot detach a thread that's already exiting */
        if (a_swap(t->exitlock, 1))
@@ -13,3 +14,4 @@ int __pthread_detach(pthread_t t)
 }
 
 weak_alias(__pthread_detach, pthread_detach);
+weak_alias(__pthread_detach, thrd_detach);
index 3e3df4fda37db0f3aafb47e8fda60c38ea575ae4..7c31482af3f8fec7710d0e995ef8d40cf149ebe4 100644 (file)
@@ -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);
index 5f9e6516ac922742b308da019a974876c0f0e507..241a6202d2ea5e15ca53a5e8676398f6c5c95b8e 100644 (file)
@@ -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/thrd_create.c b/src/thread/thrd_create.c
new file mode 100644 (file)
index 0000000..e033669
--- /dev/null
@@ -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 (file)
index 0000000..b66bd99
--- /dev/null
@@ -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 (file)
index 0000000..ac66789
--- /dev/null
@@ -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 (file)
index 0000000..e8dfe40
--- /dev/null
@@ -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 (file)
index 0000000..f7ad132
--- /dev/null
@@ -0,0 +1,7 @@
+#include <threads.h>
+#include "syscall.h"
+
+void thrd_yield()
+{
+       __syscall(SYS_sched_yield);
+}