summaryrefslogtreecommitdiffstats
path: root/libc-top-half
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--libc-top-half/musl/include/pthread.h2
-rw-r--r--libc-top-half/musl/include/unistd.h2
-rw-r--r--libc-top-half/musl/src/env/__init_tls.c51
-rw-r--r--libc-top-half/musl/src/include/pthread.h2
-rw-r--r--libc-top-half/musl/src/internal/pthread_impl.h5
-rw-r--r--libc-top-half/musl/src/thread/__wait.c2
-rw-r--r--libc-top-half/musl/src/thread/pthread_attr_get.c4
-rw-r--r--libc-top-half/musl/src/thread/pthread_barrier_destroy.c2
-rw-r--r--libc-top-half/musl/src/thread/pthread_barrier_wait.c8
-rw-r--r--libc-top-half/musl/src/thread/pthread_create.c52
-rw-r--r--libc-top-half/musl/src/thread/wasm32/wasi_thread_start.s31
11 files changed, 144 insertions, 17 deletions
diff --git a/libc-top-half/musl/include/pthread.h b/libc-top-half/musl/include/pthread.h
index 01fe5f2..b14fe82 100644
--- a/libc-top-half/musl/include/pthread.h
+++ b/libc-top-half/musl/include/pthread.h
@@ -85,7 +85,9 @@ extern "C" {
int pthread_create(pthread_t *__restrict, const pthread_attr_t *__restrict, void *(*)(void *), void *__restrict);
int pthread_detach(pthread_t);
+#ifdef __wasilibc_unmodified_upstream
_Noreturn void pthread_exit(void *);
+#endif
int pthread_join(pthread_t, void **);
#ifdef __GNUC__
diff --git a/libc-top-half/musl/include/unistd.h b/libc-top-half/musl/include/unistd.h
index b5cb5c6..0be83e3 100644
--- a/libc-top-half/musl/include/unistd.h
+++ b/libc-top-half/musl/include/unistd.h
@@ -336,7 +336,9 @@ pid_t gettid(void);
#endif
#define _POSIX_VDISABLE 0
+#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT)
#define _POSIX_THREADS _POSIX_VERSION
+#endif
#define _POSIX_THREAD_PROCESS_SHARED _POSIX_VERSION
#define _POSIX_THREAD_SAFE_FUNCTIONS _POSIX_VERSION
#define _POSIX_THREAD_ATTR_STACKADDR _POSIX_VERSION
diff --git a/libc-top-half/musl/src/env/__init_tls.c b/libc-top-half/musl/src/env/__init_tls.c
index ee785bc..ece8d24 100644
--- a/libc-top-half/musl/src/env/__init_tls.c
+++ b/libc-top-half/musl/src/env/__init_tls.c
@@ -16,6 +16,43 @@
volatile int __thread_list_lock;
#ifndef __wasilibc_unmodified_upstream
+
+/* These symbols are generated by wasm-ld. __stack_high/__stack_low
+ * symbols are only available in LLVM v16 and higher, therefore they're
+ * defined as weak symbols and if not available, __heap_base/__data_end
+ * is used instead.
+ *
+ * TODO: remove usage of __heap_base/__data_end for stack size calculation
+ * once we drop support for LLVM v15 and older.
+ */
+extern unsigned char __heap_base;
+extern unsigned char __data_end;
+extern unsigned char __global_base;
+extern weak unsigned char __stack_high;
+extern weak unsigned char __stack_low;
+
+static inline void setup_default_stack_size()
+{
+ ptrdiff_t stack_size;
+
+ if (&__stack_high)
+ stack_size = &__stack_high - &__stack_low;
+ else {
+ unsigned char *sp;
+ __asm__(
+ ".globaltype __stack_pointer, i32\n"
+ "global.get __stack_pointer\n"
+ "local.set %0\n"
+ : "=r"(sp));
+ stack_size = sp > &__global_base ? &__heap_base - &__data_end : (ptrdiff_t)&__global_base;
+ }
+
+ if (stack_size > __default_stacksize)
+ __default_stacksize =
+ stack_size < DEFAULT_STACK_MAX ?
+ stack_size : DEFAULT_STACK_MAX;
+}
+
void __wasi_init_tp() {
__init_tp((void *)__get_tp());
}
@@ -31,6 +68,20 @@ int __init_tp(void *p)
if (!r) libc.can_do_threads = 1;
td->detach_state = DT_JOINABLE;
td->tid = __syscall(SYS_set_tid_address, &__thread_list_lock);
+#else
+ setup_default_stack_size();
+ td->detach_state = DT_JOINABLE;
+ /*
+ * Initialize the TID to a value which doesn't conflict with
+ * host-allocated TIDs, so that TID-based locks can work.
+ *
+ * Note:
+ * - Host-allocated TIDs range from 1 to 0x1fffffff. (inclusive)
+ * - __tl_lock and __lockfile uses TID 0 as "unlocked".
+ * - __lockfile relies on the fact the most significant two bits
+ * of TIDs are 0.
+ */
+ td->tid = 0x3fffffff;
#endif
td->locale = &libc.global_locale;
td->robust_list.head = &td->robust_list.head;
diff --git a/libc-top-half/musl/src/include/pthread.h b/libc-top-half/musl/src/include/pthread.h
index 7167d3e..0aba813 100644
--- a/libc-top-half/musl/src/include/pthread.h
+++ b/libc-top-half/musl/src/include/pthread.h
@@ -7,7 +7,9 @@ hidden int __pthread_once(pthread_once_t *, void (*)(void));
hidden void __pthread_testcancel(void);
hidden int __pthread_setcancelstate(int, int *);
hidden int __pthread_create(pthread_t *restrict, const pthread_attr_t *restrict, void *(*)(void *), void *restrict);
+#ifdef __wasilibc_unmodified_upstream
hidden _Noreturn void __pthread_exit(void *);
+#endif
hidden int __pthread_join(pthread_t, void **);
hidden int __pthread_mutex_lock(pthread_mutex_t *);
hidden int __pthread_mutex_trylock(pthread_mutex_t *);
diff --git a/libc-top-half/musl/src/internal/pthread_impl.h b/libc-top-half/musl/src/internal/pthread_impl.h
index a6d188b..1e7b974 100644
--- a/libc-top-half/musl/src/internal/pthread_impl.h
+++ b/libc-top-half/musl/src/internal/pthread_impl.h
@@ -216,7 +216,12 @@ extern hidden unsigned __default_stacksize;
extern hidden unsigned __default_guardsize;
#define DEFAULT_STACK_SIZE 131072
+#ifdef __wasilibc_unmodified_upstream
#define DEFAULT_GUARD_SIZE 8192
+#else
+/* guard doesn't make much sense without mprotect. */
+#define DEFAULT_GUARD_SIZE 0
+#endif
#define DEFAULT_STACK_MAX (8<<20)
#define DEFAULT_GUARD_MAX (1<<20)
diff --git a/libc-top-half/musl/src/thread/__wait.c b/libc-top-half/musl/src/thread/__wait.c
index c0e4aac..7ffa987 100644
--- a/libc-top-half/musl/src/thread/__wait.c
+++ b/libc-top-half/musl/src/thread/__wait.c
@@ -48,7 +48,7 @@ void __wait(volatile int *addr, volatile int *waiters, int val, int priv)
__syscall(SYS_futex, addr, FUTEX_WAIT|priv, val, 0) != -ENOSYS
|| __syscall(SYS_futex, addr, FUTEX_WAIT, val, 0);
#else
- __wasilibc_futex_wait(addr, FUTEX_WAIT, val, 0);
+ __wasilibc_futex_wait(addr, FUTEX_WAIT, val, -1);
#endif
}
if (waiters) a_dec(waiters);
diff --git a/libc-top-half/musl/src/thread/pthread_attr_get.c b/libc-top-half/musl/src/thread/pthread_attr_get.c
index f12ff44..0ac251c 100644
--- a/libc-top-half/musl/src/thread/pthread_attr_get.c
+++ b/libc-top-half/musl/src/thread/pthread_attr_get.c
@@ -17,6 +17,7 @@ int pthread_attr_getinheritsched(const pthread_attr_t *restrict a, int *restrict
return 0;
}
+#ifdef __wasilibc_unmodified_upstream /* WASI has no CPU scheduling support. */
int pthread_attr_getschedparam(const pthread_attr_t *restrict a, struct sched_param *restrict param)
{
param->sched_priority = a->_a_prio;
@@ -28,6 +29,7 @@ int pthread_attr_getschedpolicy(const pthread_attr_t *restrict a, int *restrict
*policy = a->_a_policy;
return 0;
}
+#endif
int pthread_attr_getscope(const pthread_attr_t *restrict a, int *restrict scope)
{
@@ -56,11 +58,13 @@ int pthread_barrierattr_getpshared(const pthread_barrierattr_t *restrict a, int
return 0;
}
+#ifdef __wasilibc_unmodified_upstream /* Forward declaration of WASI's `__clockid` type. */
int pthread_condattr_getclock(const pthread_condattr_t *restrict a, clockid_t *restrict clk)
{
*clk = a->__attr & 0x7fffffff;
return 0;
}
+#endif
int pthread_condattr_getpshared(const pthread_condattr_t *restrict a, int *restrict pshared)
{
diff --git a/libc-top-half/musl/src/thread/pthread_barrier_destroy.c b/libc-top-half/musl/src/thread/pthread_barrier_destroy.c
index 4ce0b2e..a347a2c 100644
--- a/libc-top-half/musl/src/thread/pthread_barrier_destroy.c
+++ b/libc-top-half/musl/src/thread/pthread_barrier_destroy.c
@@ -9,7 +9,9 @@ int pthread_barrier_destroy(pthread_barrier_t *b)
while ((v = b->_b_lock) & INT_MAX)
__wait(&b->_b_lock, 0, v, 0);
}
+#ifdef __wasilibc_unmodified_upstream /* WASI does not understand processes or locking between them. */
__vm_wait();
+#endif
}
return 0;
}
diff --git a/libc-top-half/musl/src/thread/pthread_barrier_wait.c b/libc-top-half/musl/src/thread/pthread_barrier_wait.c
index cc2a8bb..0891b71 100644
--- a/libc-top-half/musl/src/thread/pthread_barrier_wait.c
+++ b/libc-top-half/musl/src/thread/pthread_barrier_wait.c
@@ -23,7 +23,9 @@ static int pshared_barrier_wait(pthread_barrier_t *b)
__wait(&b->_b_count, &b->_b_waiters2, v, 0);
}
+#ifdef __wasilibc_unmodified_upstream /* WASI does not understand processes or locking between them. */
__vm_lock();
+#endif
/* Ensure all threads have a vm lock before proceeding */
if (a_fetch_add(&b->_b_count, -1)==1-limit) {
@@ -44,7 +46,9 @@ static int pshared_barrier_wait(pthread_barrier_t *b)
if (v==INT_MIN+1 || (v==1 && w))
__wake(&b->_b_lock, 1, 0);
+#ifdef __wasilibc_unmodified_upstream /* WASI does not understand processes or locking between them. */
__vm_unlock();
+#endif
return ret;
}
@@ -84,8 +88,12 @@ int pthread_barrier_wait(pthread_barrier_t *b)
a_spin();
a_inc(&inst->finished);
while (inst->finished == 1)
+#ifdef __wasilibc_unmodified_upstream
__syscall(SYS_futex,&inst->finished,FUTEX_WAIT|FUTEX_PRIVATE,1,0) != -ENOSYS
|| __syscall(SYS_futex,&inst->finished,FUTEX_WAIT,1,0);
+#else
+ __futexwait(&inst->finished, 1, 0);
+#endif
return PTHREAD_BARRIER_SERIAL_THREAD;
}
diff --git a/libc-top-half/musl/src/thread/pthread_create.c b/libc-top-half/musl/src/thread/pthread_create.c
index 1aa7be7..676e2cc 100644
--- a/libc-top-half/musl/src/thread/pthread_create.c
+++ b/libc-top-half/musl/src/thread/pthread_create.c
@@ -60,7 +60,11 @@ void __tl_sync(pthread_t td)
if (tl_lock_waiters) __wake(&__thread_list_lock, 1, 0);
}
+#ifdef __wasilibc_unmodified_upstream
_Noreturn void __pthread_exit(void *result)
+#else
+static void __pthread_exit(void *result)
+#endif
{
pthread_t self = __pthread_self();
sigset_t set;
@@ -191,7 +195,7 @@ _Noreturn void __pthread_exit(void *result)
__tl_unlock();
free(self->map_base);
// Can't use `exit()` here, because it is too high level
- for (;;) __wasi_proc_exit(0);
+ return;
}
#endif
@@ -212,7 +216,6 @@ _Noreturn void __pthread_exit(void *result)
// do it manually here
__tl_unlock();
// Can't use `exit()` here, because it is too high level
- for (;;) __wasi_proc_exit(0);
#endif
}
@@ -235,9 +238,14 @@ struct start_args {
volatile int control;
unsigned long sig_mask[_NSIG/8/sizeof(long)];
#else
+ /*
+ * Note: the offset of the "stack" and "tls_base" members
+ * in this structure is hardcoded in wasi_thread_start.
+ */
+ void *stack;
+ void *tls_base;
void *(*start_func)(void *);
void *start_arg;
- void *tls_base;
#endif
};
@@ -271,32 +279,41 @@ static int start_c11(void *p)
return 0;
}
#else
-__attribute__((export_name("wasi_thread_start")))
-_Noreturn void wasi_thread_start(int tid, void *p)
+
+/*
+ * We want to ensure wasi_thread_start is linked whenever
+ * pthread_create is used. The following reference is to ensure that.
+ * Otherwise, the linker doesn't notice the dependency because
+ * wasi_thread_start is used indirectly via a wasm export.
+ */
+void wasi_thread_start(int tid, void *p);
+hidden void *__dummy_reference = wasi_thread_start;
+
+hidden void __wasi_thread_start_C(int tid, void *p)
{
struct start_args *args = p;
- __asm__(".globaltype __tls_base, i32\n"
- "local.get %0\n"
- "global.set __tls_base\n"
- :: "r"(args->tls_base));
pthread_t self = __pthread_self();
// Set the thread ID (TID) on the pthread structure. The TID is stored
// atomically since it is also stored by the parent thread; this way,
// whichever thread (parent or child) reaches this point first can proceed
// without waiting.
atomic_store((atomic_int *) &(self->tid), tid);
- // Set the stack pointer.
- __asm__(".globaltype __stack_pointer, i32\n"
- "local.get %0\n"
- "global.set __stack_pointer\n"
- :: "r"(self->stack));
// Execute the user's start function.
- int (*start)(void*) = (int(*)(void*)) args->start_func;
- __pthread_exit((void *)(uintptr_t)start(args->start_arg));
+ __pthread_exit(args->start_func(args->start_arg));
}
#endif
+#ifdef __wasilibc_unmodified_upstream
#define ROUND(x) (((x)+PAGE_SIZE-1)&-PAGE_SIZE)
+#else
+/*
+ * As we allocate stack with malloc() instead of mmap/mprotect,
+ * there is no point to round it up to PAGE_SIZE.
+ * Instead, round up to a sane alignment.
+ * Note: PAGE_SIZE is rather big on WASM. (65536)
+ */
+#define ROUND(x) (((x)+16-1)&-16)
+#endif
/* pthread_key_create.c overrides this */
static volatile size_t dummy = 0;
@@ -484,6 +501,7 @@ int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict att
/* Correct the stack size */
new->stack_size = stack - stack_limit;
+ args->stack = new->stack; /* just for convenience of asm trampoline */
args->start_func = entry;
args->start_arg = arg;
args->tls_base = (void*)new_tls_base;
@@ -561,5 +579,7 @@ fail:
return EAGAIN;
}
+#ifdef __wasilibc_unmodified_upstream
weak_alias(__pthread_exit, pthread_exit);
+#endif
weak_alias(__pthread_create, pthread_create);
diff --git a/libc-top-half/musl/src/thread/wasm32/wasi_thread_start.s b/libc-top-half/musl/src/thread/wasm32/wasi_thread_start.s
new file mode 100644
index 0000000..0fe9854
--- /dev/null
+++ b/libc-top-half/musl/src/thread/wasm32/wasi_thread_start.s
@@ -0,0 +1,31 @@
+ .text
+
+ .export_name wasi_thread_start, wasi_thread_start
+
+ .globaltype __stack_pointer, i32
+ .globaltype __tls_base, i32
+ .functype __wasi_thread_start_C (i32, i32) -> ()
+
+ .hidden wasi_thread_start
+ .globl wasi_thread_start
+ .type wasi_thread_start,@function
+
+wasi_thread_start:
+ .functype wasi_thread_start (i32, i32) -> ()
+
+ # Set up the minimum C environment.
+ # Note: offsetof(start_arg, stack) == 0
+ local.get 1 # start_arg
+ i32.load 0 # stack
+ global.set __stack_pointer
+
+ local.get 1 # start_arg
+ i32.load 4 # tls_base
+ global.set __tls_base
+
+ # Make the C function do the rest of work.
+ local.get 0 # tid
+ local.get 1 # start_arg
+ call __wasi_thread_start_C
+
+ end_function