Browse Source

add pthread_attr_setstack interface (and get)

i originally omitted these (optional, per POSIX) interfaces because i
considered them backwards implementation details. however, someone
later brought to my attention a fairly legitimate use case: allocating
thread stacks in memory that's setup for sharing and/or fast transfer
between CPU and GPU so that the thread can move data to a GPU directly
from automatic-storage buffers without having to go through additional
buffer copies.

perhaps there are other situations in which these interfaces are
useful too.
Rich Felker 12 years ago
parent
commit
819006a88b

+ 2 - 1
src/internal/pthread_impl.h

@@ -59,7 +59,8 @@ struct __timer {
 
 #define _a_stacksize __u.__s[0]
 #define _a_guardsize __u.__s[1]
-#define _a_detach __u.__i[2*__SU+0]
+#define _a_stackaddr __u.__s[2]
+#define _a_detach __u.__i[3*__SU+0]
 #define _m_type __u.__i[0]
 #define _m_lock __u.__i[1]
 #define _m_waiters __u.__i[2]

+ 10 - 0
src/thread/pthread_attr_getstack.c

@@ -0,0 +1,10 @@
+#include "pthread_impl.h"
+
+int pthread_attr_getstack(const pthread_attr_t *a, void **addr, size_t *size)
+{
+	if (!a->_a_stackaddr)
+		return EINVAL;
+	*size = a->_a_stacksize + DEFAULT_STACK_SIZE;
+	*addr = (void *)(a->_a_stackaddr - *size);
+	return 0;
+}

+ 14 - 0
src/thread/pthread_attr_setstack.c

@@ -0,0 +1,14 @@
+#include "pthread_impl.h"
+
+/* pthread_key_create.c overrides this */
+static const size_t dummy = 0;
+weak_alias(dummy, __pthread_tsd_size);
+
+int pthread_attr_setstack(pthread_attr_t *a, void *addr, size_t size)
+{
+	if (size-PTHREAD_STACK_MIN-__pthread_tsd_size > SIZE_MAX/4)
+		return EINVAL;
+	a->_a_stackaddr = (size_t)addr + size;
+	a->_a_stacksize = size - DEFAULT_STACK_SIZE;
+	return 0;
+}

+ 13 - 9
src/thread/pthread_create.c

@@ -98,16 +98,20 @@ int pthread_create(pthread_t *res, const pthread_attr_t *attr, void *(*entry)(vo
 		libc.threaded = 1;
 	}
 
-	if (attr) {
-		guard = ROUND(attr->_a_guardsize + DEFAULT_GUARD_SIZE);
-		size = guard + ROUND(attr->_a_stacksize + DEFAULT_STACK_SIZE);
+	if (attr && attr->_a_stackaddr) {
+		map = 0;
+		tsd = (void *)(attr->_a_stackaddr-__pthread_tsd_size & -16);
+	} else {
+		if (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, MAP_PRIVATE|MAP_ANON, -1, 0);
+		if (map == MAP_FAILED) return EAGAIN;
+		if (guard) mprotect(map, guard, PROT_NONE);
+		tsd = map + size - __pthread_tsd_size;
 	}
-	size += __pthread_tsd_size;
-	map = mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0);
-	if (map == MAP_FAILED) return EAGAIN;
-	if (guard) 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;