Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
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.