mirror of
https://git.proxmox.com/git/wasi-libc
synced 2025-07-27 16:45:36 +00:00
threads: implement init of TLS and stack pointer (#342)
* threads: implement init of TLS and stack pointer * fix: rename wasi_snapshot_preview2_thread_spawn to wasi_thread_spawn Signed-off-by: Harald Hoyer <harald@profian.com> * fix: change signature of wasi_thread_start Signed-off-by: Harald Hoyer <harald@profian.com> * fix: pthread_exit for WASI Can't use `exit()` because it is too high level. Have to unlock the thread list. Signed-off-by: Harald Hoyer <harald@profian.com> * fix: initialize struct pthread for the main thread Signed-off-by: Harald Hoyer <harald@profian.com> * fix: store the aligned stack minus `struct start_args` Signed-off-by: Harald Hoyer <harald@profian.com> Signed-off-by: Harald Hoyer <harald@profian.com> Co-authored-by: Harald Hoyer <harald@profian.com>
This commit is contained in:
parent
b99173e177
commit
a00bf321ee
8
Makefile
8
Makefile
@ -192,9 +192,16 @@ LIBC_TOP_HALF_MUSL_SOURCES = \
|
|||||||
ifeq ($(THREAD_MODEL), posix)
|
ifeq ($(THREAD_MODEL), posix)
|
||||||
LIBC_TOP_HALF_MUSL_SOURCES += \
|
LIBC_TOP_HALF_MUSL_SOURCES += \
|
||||||
$(addprefix $(LIBC_TOP_HALF_MUSL_SRC_DIR)/, \
|
$(addprefix $(LIBC_TOP_HALF_MUSL_SRC_DIR)/, \
|
||||||
|
env/__init_tls.c \
|
||||||
|
stdio/__lockfile.c \
|
||||||
thread/__lock.c \
|
thread/__lock.c \
|
||||||
thread/__wait.c \
|
thread/__wait.c \
|
||||||
thread/__timedwait.c \
|
thread/__timedwait.c \
|
||||||
|
thread/default_attr.c \
|
||||||
|
thread/pthread_attr_destroy.c \
|
||||||
|
thread/pthread_attr_init.c \
|
||||||
|
thread/pthread_attr_setstack.c \
|
||||||
|
thread/pthread_attr_setstacksize.c \
|
||||||
thread/pthread_cleanup_push.c \
|
thread/pthread_cleanup_push.c \
|
||||||
thread/pthread_cond_broadcast.c \
|
thread/pthread_cond_broadcast.c \
|
||||||
thread/pthread_cond_destroy.c \
|
thread/pthread_cond_destroy.c \
|
||||||
@ -235,6 +242,7 @@ LIBC_TOP_HALF_MUSL_SOURCES += \
|
|||||||
thread/pthread_rwlockattr_init.c \
|
thread/pthread_rwlockattr_init.c \
|
||||||
thread/pthread_rwlockattr_setpshared.c \
|
thread/pthread_rwlockattr_setpshared.c \
|
||||||
thread/pthread_setcancelstate.c \
|
thread/pthread_setcancelstate.c \
|
||||||
|
thread/pthread_self.c \
|
||||||
thread/pthread_testcancel.c \
|
thread/pthread_testcancel.c \
|
||||||
thread/sem_destroy.c \
|
thread/sem_destroy.c \
|
||||||
thread/sem_getvalue.c \
|
thread/sem_getvalue.c \
|
||||||
|
@ -23,6 +23,7 @@ __c_locale
|
|||||||
__clock
|
__clock
|
||||||
__clock_gettime
|
__clock_gettime
|
||||||
__clock_nanosleep
|
__clock_nanosleep
|
||||||
|
__copy_tls
|
||||||
__cos
|
__cos
|
||||||
__cosdf
|
__cosdf
|
||||||
__cosl
|
__cosl
|
||||||
@ -38,6 +39,8 @@ __ctype_tolower_loc
|
|||||||
__ctype_toupper_loc
|
__ctype_toupper_loc
|
||||||
__cxa_atexit
|
__cxa_atexit
|
||||||
__cxa_finalize
|
__cxa_finalize
|
||||||
|
__default_guardsize
|
||||||
|
__default_stacksize
|
||||||
__des_setkey
|
__des_setkey
|
||||||
__do_cleanup_pop
|
__do_cleanup_pop
|
||||||
__do_cleanup_push
|
__do_cleanup_push
|
||||||
@ -87,6 +90,7 @@ __getopt_msg
|
|||||||
__gmtime_r
|
__gmtime_r
|
||||||
__hwcap
|
__hwcap
|
||||||
__inet_aton
|
__inet_aton
|
||||||
|
__init_tp
|
||||||
__intscan
|
__intscan
|
||||||
__invtrigl_R
|
__invtrigl_R
|
||||||
__isalnum_l
|
__isalnum_l
|
||||||
@ -144,6 +148,7 @@ __locale_lock
|
|||||||
__locale_lockptr
|
__locale_lockptr
|
||||||
__localtime_r
|
__localtime_r
|
||||||
__lock
|
__lock
|
||||||
|
__lockfile
|
||||||
__log2_data
|
__log2_data
|
||||||
__log2f_data
|
__log2f_data
|
||||||
__log_data
|
__log_data
|
||||||
@ -265,6 +270,7 @@ __tan
|
|||||||
__tandf
|
__tandf
|
||||||
__tanl
|
__tanl
|
||||||
__testcancel
|
__testcancel
|
||||||
|
__thread_list_lock
|
||||||
__timedwait
|
__timedwait
|
||||||
__timedwait_cp
|
__timedwait_cp
|
||||||
__tl_lock
|
__tl_lock
|
||||||
@ -288,6 +294,7 @@ __tsearch_balance
|
|||||||
__uflow
|
__uflow
|
||||||
__unlist_locked_file
|
__unlist_locked_file
|
||||||
__unlock
|
__unlock
|
||||||
|
__unlockfile
|
||||||
__uselocale
|
__uselocale
|
||||||
__utc
|
__utc
|
||||||
__wait
|
__wait
|
||||||
@ -318,6 +325,7 @@ __wasi_fd_seek
|
|||||||
__wasi_fd_sync
|
__wasi_fd_sync
|
||||||
__wasi_fd_tell
|
__wasi_fd_tell
|
||||||
__wasi_fd_write
|
__wasi_fd_write
|
||||||
|
__wasi_init_tp
|
||||||
__wasi_path_create_directory
|
__wasi_path_create_directory
|
||||||
__wasi_path_filestat_get
|
__wasi_path_filestat_get
|
||||||
__wasi_path_filestat_set_times
|
__wasi_path_filestat_set_times
|
||||||
@ -371,6 +379,7 @@ __wasilibc_nocwd_scandirat
|
|||||||
__wasilibc_nocwd_symlinkat
|
__wasilibc_nocwd_symlinkat
|
||||||
__wasilibc_nocwd_utimensat
|
__wasilibc_nocwd_utimensat
|
||||||
__wasilibc_open_nomode
|
__wasilibc_open_nomode
|
||||||
|
__wasilibc_pthread_self
|
||||||
__wasilibc_register_preopened_fd
|
__wasilibc_register_preopened_fd
|
||||||
__wasilibc_rename_newat
|
__wasilibc_rename_newat
|
||||||
__wasilibc_rename_oldat
|
__wasilibc_rename_oldat
|
||||||
@ -953,6 +962,10 @@ program_invocation_name
|
|||||||
program_invocation_short_name
|
program_invocation_short_name
|
||||||
pselect
|
pselect
|
||||||
psignal
|
psignal
|
||||||
|
pthread_attr_destroy
|
||||||
|
pthread_attr_init
|
||||||
|
pthread_attr_setstack
|
||||||
|
pthread_attr_setstacksize
|
||||||
pthread_cond_broadcast
|
pthread_cond_broadcast
|
||||||
pthread_cond_destroy
|
pthread_cond_destroy
|
||||||
pthread_cond_init
|
pthread_cond_init
|
||||||
@ -992,6 +1005,7 @@ pthread_rwlock_wrlock
|
|||||||
pthread_rwlockattr_destroy
|
pthread_rwlockattr_destroy
|
||||||
pthread_rwlockattr_init
|
pthread_rwlockattr_init
|
||||||
pthread_rwlockattr_setpshared
|
pthread_rwlockattr_setpshared
|
||||||
|
pthread_self
|
||||||
pthread_setcancelstate
|
pthread_setcancelstate
|
||||||
pthread_testcancel
|
pthread_testcancel
|
||||||
pthread_timedjoin_np
|
pthread_timedjoin_np
|
||||||
@ -1182,6 +1196,7 @@ tfind
|
|||||||
tgamma
|
tgamma
|
||||||
tgammaf
|
tgammaf
|
||||||
tgammal
|
tgammal
|
||||||
|
thrd_current
|
||||||
thrd_sleep
|
thrd_sleep
|
||||||
time
|
time
|
||||||
timegm
|
timegm
|
||||||
|
@ -1,7 +1,4 @@
|
|||||||
__addtf3
|
__addtf3
|
||||||
__copy_tls
|
|
||||||
__default_guardsize
|
|
||||||
__default_stacksize
|
|
||||||
__divtf3
|
__divtf3
|
||||||
__eqtf2
|
__eqtf2
|
||||||
__extenddftf2
|
__extenddftf2
|
||||||
@ -59,19 +56,18 @@ __imported_wasi_snapshot_preview1_sock_accept
|
|||||||
__imported_wasi_snapshot_preview1_sock_recv
|
__imported_wasi_snapshot_preview1_sock_recv
|
||||||
__imported_wasi_snapshot_preview1_sock_send
|
__imported_wasi_snapshot_preview1_sock_send
|
||||||
__imported_wasi_snapshot_preview1_sock_shutdown
|
__imported_wasi_snapshot_preview1_sock_shutdown
|
||||||
__imported_wasi_snapshot_preview2_thread_spawn
|
__imported_wasi_thread_spawn
|
||||||
__letf2
|
__letf2
|
||||||
__lockfile
|
|
||||||
__lttf2
|
__lttf2
|
||||||
__main_argc_argv
|
__main_argc_argv
|
||||||
__netf2
|
__netf2
|
||||||
__stack_pointer
|
__stack_pointer
|
||||||
__subtf3
|
__subtf3
|
||||||
__thread_list_lock
|
__tls_align
|
||||||
__tls_base
|
__tls_base
|
||||||
|
__tls_size
|
||||||
__trunctfdf2
|
__trunctfdf2
|
||||||
__trunctfsf2
|
__trunctfsf2
|
||||||
__unlockfile
|
|
||||||
__unordtf2
|
__unordtf2
|
||||||
__wasilibc_pthread_self
|
|
||||||
__wasm_call_ctors
|
__wasm_call_ctors
|
||||||
|
__wasm_init_tls
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#ifdef _REENTRANT
|
#ifdef _REENTRANT
|
||||||
#include <stdatomic.h>
|
#include <stdatomic.h>
|
||||||
|
extern void __wasi_init_tp(void);
|
||||||
#endif
|
#endif
|
||||||
#include <wasi/api.h>
|
#include <wasi/api.h>
|
||||||
extern void __wasm_call_ctors(void);
|
extern void __wasm_call_ctors(void);
|
||||||
@ -29,6 +30,10 @@ void _start(void) {
|
|||||||
started = 1;
|
started = 1;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef _REENTRANT
|
||||||
|
__wasi_init_tp();
|
||||||
|
#endif
|
||||||
|
|
||||||
// The linker synthesizes this to call constructors.
|
// The linker synthesizes this to call constructors.
|
||||||
__wasm_call_ctors();
|
__wasm_call_ctors();
|
||||||
|
|
||||||
|
@ -660,13 +660,13 @@ __wasi_errno_t __wasi_sock_shutdown(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _REENTRANT
|
#ifdef _REENTRANT
|
||||||
int32_t __imported_wasi_snapshot_preview2_thread_spawn(int32_t arg0) __attribute__((
|
int32_t __imported_wasi_thread_spawn(int32_t arg0) __attribute__((
|
||||||
__import_module__("wasi_snapshot_preview2"),
|
__import_module__("wasi"),
|
||||||
__import_name__("thread_spawn")
|
__import_name__("thread_spawn")
|
||||||
));
|
));
|
||||||
|
|
||||||
__wasi_errno_t __wasi_thread_spawn(void* start_arg) {
|
__wasi_errno_t __wasi_thread_spawn(void* start_arg) {
|
||||||
int32_t ret = __imported_wasi_snapshot_preview2_thread_spawn((int32_t) start_arg);
|
int32_t ret = __imported_wasi_thread_spawn((int32_t) start_arg);
|
||||||
return (uint16_t) ret;
|
return (uint16_t) ret;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,11 +1,5 @@
|
|||||||
static inline uintptr_t __get_tp(void) {
|
extern _Thread_local struct __pthread __wasilibc_pthread_self;
|
||||||
#if _REENTRANT
|
|
||||||
int val;
|
static inline uintptr_t __get_tp() {
|
||||||
__asm__("global.get __wasilibc_pthread_self\n"
|
return (uintptr_t)&__wasilibc_pthread_self;
|
||||||
"local.set %0"
|
|
||||||
: "=r"(val));
|
|
||||||
return val;
|
|
||||||
#else
|
|
||||||
return 0;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
33
libc-top-half/musl/src/env/__init_tls.c
vendored
33
libc-top-half/musl/src/env/__init_tls.c
vendored
@ -1,7 +1,11 @@
|
|||||||
|
#ifdef __wasilibc_unmodified_upstream
|
||||||
#define SYSCALL_NO_TLS 1
|
#define SYSCALL_NO_TLS 1
|
||||||
#include <elf.h>
|
#include <elf.h>
|
||||||
|
#endif
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
#ifdef __wasilibc_unmodified_upstream
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
|
#endif
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include "pthread_impl.h"
|
#include "pthread_impl.h"
|
||||||
@ -11,15 +15,23 @@
|
|||||||
|
|
||||||
volatile int __thread_list_lock;
|
volatile int __thread_list_lock;
|
||||||
|
|
||||||
|
#ifndef __wasilibc_unmodified_upstream
|
||||||
|
void __wasi_init_tp() {
|
||||||
|
__init_tp((void *)__get_tp());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
int __init_tp(void *p)
|
int __init_tp(void *p)
|
||||||
{
|
{
|
||||||
pthread_t td = p;
|
pthread_t td = p;
|
||||||
td->self = td;
|
td->self = td;
|
||||||
|
#ifdef __wasilibc_unmodified_upstream
|
||||||
int r = __set_thread_area(TP_ADJ(p));
|
int r = __set_thread_area(TP_ADJ(p));
|
||||||
if (r < 0) return -1;
|
if (r < 0) return -1;
|
||||||
if (!r) libc.can_do_threads = 1;
|
if (!r) libc.can_do_threads = 1;
|
||||||
td->detach_state = DT_JOINABLE;
|
td->detach_state = DT_JOINABLE;
|
||||||
td->tid = __syscall(SYS_set_tid_address, &__thread_list_lock);
|
td->tid = __syscall(SYS_set_tid_address, &__thread_list_lock);
|
||||||
|
#endif
|
||||||
td->locale = &libc.global_locale;
|
td->locale = &libc.global_locale;
|
||||||
td->robust_list.head = &td->robust_list.head;
|
td->robust_list.head = &td->robust_list.head;
|
||||||
td->sysinfo = __sysinfo;
|
td->sysinfo = __sysinfo;
|
||||||
@ -27,6 +39,8 @@ int __init_tp(void *p)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __wasilibc_unmodified_upstream
|
||||||
|
|
||||||
static struct builtin_tls {
|
static struct builtin_tls {
|
||||||
char c;
|
char c;
|
||||||
struct pthread pt;
|
struct pthread pt;
|
||||||
@ -35,9 +49,15 @@ static struct builtin_tls {
|
|||||||
#define MIN_TLS_ALIGN offsetof(struct builtin_tls, pt)
|
#define MIN_TLS_ALIGN offsetof(struct builtin_tls, pt)
|
||||||
|
|
||||||
static struct tls_module main_tls;
|
static struct tls_module main_tls;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __wasilibc_unmodified_upstream
|
||||||
|
extern void __wasm_init_tls(void*);
|
||||||
|
#endif
|
||||||
|
|
||||||
void *__copy_tls(unsigned char *mem)
|
void *__copy_tls(unsigned char *mem)
|
||||||
{
|
{
|
||||||
|
#ifdef __wasilibc_unmodified_upstream
|
||||||
pthread_t td;
|
pthread_t td;
|
||||||
struct tls_module *p;
|
struct tls_module *p;
|
||||||
size_t i;
|
size_t i;
|
||||||
@ -69,8 +89,20 @@ void *__copy_tls(unsigned char *mem)
|
|||||||
dtv[0] = libc.tls_cnt;
|
dtv[0] = libc.tls_cnt;
|
||||||
td->dtv = dtv;
|
td->dtv = dtv;
|
||||||
return td;
|
return td;
|
||||||
|
#else
|
||||||
|
size_t tls_align = __builtin_wasm_tls_align();
|
||||||
|
volatile void* tls_base = __builtin_wasm_tls_base();
|
||||||
|
mem += tls_align;
|
||||||
|
mem -= (uintptr_t)mem & (tls_align-1);
|
||||||
|
__wasm_init_tls(mem);
|
||||||
|
__asm__("local.get %0\n"
|
||||||
|
"global.set __tls_base\n"
|
||||||
|
:: "r"(tls_base));
|
||||||
|
return mem;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __wasilibc_unmodified_upstream
|
||||||
#if ULONG_MAX == 0xffffffff
|
#if ULONG_MAX == 0xffffffff
|
||||||
typedef Elf32_Phdr Phdr;
|
typedef Elf32_Phdr Phdr;
|
||||||
#else
|
#else
|
||||||
@ -151,3 +183,4 @@ static void static_init_tls(size_t *aux)
|
|||||||
}
|
}
|
||||||
|
|
||||||
weak_alias(static_init_tls, __init_tls);
|
weak_alias(static_init_tls, __init_tls);
|
||||||
|
#endif
|
||||||
|
@ -18,8 +18,10 @@ struct tls_module {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct __libc {
|
struct __libc {
|
||||||
#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT)
|
#ifdef __wasilibc_unmodified_upstream
|
||||||
char can_do_threads;
|
char can_do_threads;
|
||||||
|
#endif
|
||||||
|
#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT)
|
||||||
char threaded;
|
char threaded;
|
||||||
#endif
|
#endif
|
||||||
#ifdef __wasilibc_unmodified_upstream // WASI doesn't currently use any code that needs "secure" mode
|
#ifdef __wasilibc_unmodified_upstream // WASI doesn't currently use any code that needs "secure" mode
|
||||||
@ -32,7 +34,7 @@ struct __libc {
|
|||||||
#ifdef __wasilibc_unmodified_upstream // WASI has no auxv
|
#ifdef __wasilibc_unmodified_upstream // WASI has no auxv
|
||||||
size_t *auxv;
|
size_t *auxv;
|
||||||
#endif
|
#endif
|
||||||
#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT)
|
#ifdef __wasilibc_unmodified_upstream // WASI use different TLS implement
|
||||||
struct tls_module *tls_head;
|
struct tls_module *tls_head;
|
||||||
size_t tls_size, tls_align, tls_cnt;
|
size_t tls_size, tls_align, tls_cnt;
|
||||||
#endif
|
#endif
|
||||||
|
@ -25,8 +25,10 @@ struct pthread {
|
|||||||
/* Part 1 -- these fields may be external or
|
/* Part 1 -- these fields may be external or
|
||||||
* internal (accessed via asm) ABI. Do not change. */
|
* internal (accessed via asm) ABI. Do not change. */
|
||||||
struct pthread *self;
|
struct pthread *self;
|
||||||
|
#ifdef __wasilibc_unmodified_upstream
|
||||||
#ifndef TLS_ABOVE_TP
|
#ifndef TLS_ABOVE_TP
|
||||||
uintptr_t *dtv;
|
uintptr_t *dtv;
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
struct pthread *prev, *next; /* non-ABI */
|
struct pthread *prev, *next; /* non-ABI */
|
||||||
uintptr_t sysinfo;
|
uintptr_t sysinfo;
|
||||||
|
@ -12,6 +12,8 @@
|
|||||||
#include <stdatomic.h>
|
#include <stdatomic.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <stdalign.h>
|
||||||
|
|
||||||
static void dummy_0()
|
static void dummy_0()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -158,6 +160,14 @@ _Noreturn void __pthread_exit(void *result)
|
|||||||
self->prev->next = self->next;
|
self->prev->next = self->next;
|
||||||
self->prev = self->next = self;
|
self->prev = self->next = self;
|
||||||
|
|
||||||
|
#ifndef __wasilibc_unmodified_upstream
|
||||||
|
/* On Linux, the thread is created with CLONE_CHILD_CLEARTID,
|
||||||
|
* and this lock will unlock by kernel when this thread terminates.
|
||||||
|
* So we should unlock it here in WebAssembly.
|
||||||
|
* See also set_tid_address(2) */
|
||||||
|
__tl_unlock();
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
#ifdef __wasilibc_unmodified_upstream
|
||||||
if (state==DT_DETACHED && self->map_base) {
|
if (state==DT_DETACHED && self->map_base) {
|
||||||
/* Detached threads must block even implementation-internal
|
/* Detached threads must block even implementation-internal
|
||||||
@ -174,6 +184,15 @@ _Noreturn void __pthread_exit(void *result)
|
|||||||
* and then exits without touching the stack. */
|
* and then exits without touching the stack. */
|
||||||
__unmapself(self->map_base, self->map_size);
|
__unmapself(self->map_base, self->map_size);
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
if (state==DT_DETACHED && self->map_base) {
|
||||||
|
// __syscall(SYS_exit) would unlock the thread, list
|
||||||
|
// do it manually here
|
||||||
|
__tl_unlock();
|
||||||
|
free(self->map_base);
|
||||||
|
// Can't use `exit()` here, because it is too high level
|
||||||
|
for (;;) __wasi_proc_exit(0);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Wake any joiner. */
|
/* Wake any joiner. */
|
||||||
@ -189,7 +208,11 @@ _Noreturn void __pthread_exit(void *result)
|
|||||||
#ifdef __wasilibc_unmodified_upstream
|
#ifdef __wasilibc_unmodified_upstream
|
||||||
for (;;) __syscall(SYS_exit, 0);
|
for (;;) __syscall(SYS_exit, 0);
|
||||||
#else
|
#else
|
||||||
for (;;) exit(0);
|
// __syscall(SYS_exit) would unlock the thread, list
|
||||||
|
// do it manually here
|
||||||
|
__tl_unlock();
|
||||||
|
// Can't use `exit()` here, because it is too high level
|
||||||
|
for (;;) __wasi_proc_exit(0);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,7 +237,7 @@ struct start_args {
|
|||||||
#else
|
#else
|
||||||
void *(*start_func)(void *);
|
void *(*start_func)(void *);
|
||||||
void *start_arg;
|
void *start_arg;
|
||||||
struct pthread *thread;
|
void *tls_base;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -249,22 +272,27 @@ static int start_c11(void *p)
|
|||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
__attribute__((export_name("wasi_thread_start")))
|
__attribute__((export_name("wasi_thread_start")))
|
||||||
int wasi_thread_start(int tid, void *p)
|
_Noreturn void wasi_thread_start(int tid, void *p)
|
||||||
{
|
{
|
||||||
struct start_args *args = 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
|
// 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,
|
// atomically since it is also stored by the parent thread; this way,
|
||||||
// whichever thread (parent or child) reaches this point first can proceed
|
// whichever thread (parent or child) reaches this point first can proceed
|
||||||
// without waiting.
|
// without waiting.
|
||||||
atomic_store((atomic_int *) &(args->thread->tid), tid);
|
atomic_store((atomic_int *) &(self->tid), tid);
|
||||||
// Save the pointer to the pthread structure as the global `pthread_self`.
|
// Set the stack pointer.
|
||||||
__asm__("local.set %0\n"
|
__asm__(".globaltype __stack_pointer, i32\n"
|
||||||
"global.set __wasilibc_pthread_self\n"
|
"local.get %0\n"
|
||||||
: "=r"(args->thread));
|
"global.set __stack_pointer\n"
|
||||||
|
:: "r"(self->stack));
|
||||||
// Execute the user's start function.
|
// Execute the user's start function.
|
||||||
int (*start)(void*) = (int(*)(void*)) args->start_func;
|
int (*start)(void*) = (int(*)(void*)) args->start_func;
|
||||||
__pthread_exit((void *)(uintptr_t)start(args->start_arg));
|
__pthread_exit((void *)(uintptr_t)start(args->start_arg));
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -299,8 +327,18 @@ int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict att
|
|||||||
#endif
|
#endif
|
||||||
pthread_attr_t attr = { 0 };
|
pthread_attr_t attr = { 0 };
|
||||||
sigset_t set;
|
sigset_t set;
|
||||||
|
#ifndef __wasilibc_unmodified_upstream
|
||||||
|
size_t tls_size = __builtin_wasm_tls_size();
|
||||||
|
size_t tls_align = __builtin_wasm_tls_align();
|
||||||
|
void* tls_base = __builtin_wasm_tls_base();
|
||||||
|
void* new_tls_base;
|
||||||
|
size_t tls_offset;
|
||||||
|
tls_size += tls_align;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __wasilibc_unmodified_upstream
|
||||||
if (!libc.can_do_threads) return ENOSYS;
|
if (!libc.can_do_threads) return ENOSYS;
|
||||||
|
#endif
|
||||||
self = __pthread_self();
|
self = __pthread_self();
|
||||||
if (!libc.threaded) {
|
if (!libc.threaded) {
|
||||||
for (FILE *f=*__ofl_lock(); f; f=f->next)
|
for (FILE *f=*__ofl_lock(); f; f=f->next)
|
||||||
@ -327,7 +365,11 @@ int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict att
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (attr._a_stackaddr) {
|
if (attr._a_stackaddr) {
|
||||||
|
#ifdef __wasilibc_unmodified_upstream
|
||||||
size_t need = libc.tls_size + __pthread_tsd_size;
|
size_t need = libc.tls_size + __pthread_tsd_size;
|
||||||
|
#else
|
||||||
|
size_t need = tls_size + __pthread_tsd_size;
|
||||||
|
#endif
|
||||||
size = attr._a_stacksize;
|
size = attr._a_stacksize;
|
||||||
stack = (void *)(attr._a_stackaddr & -16);
|
stack = (void *)(attr._a_stackaddr & -16);
|
||||||
stack_limit = (void *)(attr._a_stackaddr - size);
|
stack_limit = (void *)(attr._a_stackaddr - size);
|
||||||
@ -336,7 +378,11 @@ int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict att
|
|||||||
* application's stack space. */
|
* application's stack space. */
|
||||||
if (need < size/8 && need < 2048) {
|
if (need < size/8 && need < 2048) {
|
||||||
tsd = stack - __pthread_tsd_size;
|
tsd = stack - __pthread_tsd_size;
|
||||||
|
#ifdef __wasilibc_unmodified_upstream
|
||||||
stack = tsd - libc.tls_size;
|
stack = tsd - libc.tls_size;
|
||||||
|
#else
|
||||||
|
stack = tsd - tls_size;
|
||||||
|
#endif
|
||||||
memset(stack, 0, need);
|
memset(stack, 0, need);
|
||||||
} else {
|
} else {
|
||||||
size = ROUND(need);
|
size = ROUND(need);
|
||||||
@ -345,7 +391,11 @@ int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict att
|
|||||||
} else {
|
} else {
|
||||||
guard = ROUND(attr._a_guardsize);
|
guard = ROUND(attr._a_guardsize);
|
||||||
size = guard + ROUND(attr._a_stacksize
|
size = guard + ROUND(attr._a_stacksize
|
||||||
|
#ifdef __wasilibc_unmodified_upstream
|
||||||
+ libc.tls_size + __pthread_tsd_size);
|
+ libc.tls_size + __pthread_tsd_size);
|
||||||
|
#else
|
||||||
|
+ tls_size + __pthread_tsd_size);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!tsd) {
|
if (!tsd) {
|
||||||
@ -368,12 +418,22 @@ int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict att
|
|||||||
#endif
|
#endif
|
||||||
tsd = map + size - __pthread_tsd_size;
|
tsd = map + size - __pthread_tsd_size;
|
||||||
if (!stack) {
|
if (!stack) {
|
||||||
|
#ifdef __wasilibc_unmodified_upstream
|
||||||
stack = tsd - libc.tls_size;
|
stack = tsd - libc.tls_size;
|
||||||
|
#else
|
||||||
|
stack = tsd - tls_size;
|
||||||
|
#endif
|
||||||
stack_limit = map + guard;
|
stack_limit = map + guard;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __wasilibc_unmodified_upstream
|
||||||
new = __copy_tls(tsd - libc.tls_size);
|
new = __copy_tls(tsd - libc.tls_size);
|
||||||
|
#else
|
||||||
|
new_tls_base = __copy_tls(tsd - tls_size);
|
||||||
|
tls_offset = new_tls_base - tls_base;
|
||||||
|
new = (void*)((uintptr_t)self + tls_offset);
|
||||||
|
#endif
|
||||||
new->map_base = map;
|
new->map_base = map;
|
||||||
new->map_size = size;
|
new->map_size = size;
|
||||||
new->stack = stack;
|
new->stack = stack;
|
||||||
@ -394,12 +454,12 @@ int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict att
|
|||||||
/* Setup argument structure for the new thread on its stack.
|
/* Setup argument structure for the new thread on its stack.
|
||||||
* It's safe to access from the caller only until the thread
|
* It's safe to access from the caller only until the thread
|
||||||
* list is unlocked. */
|
* list is unlocked. */
|
||||||
|
#ifdef __wasilibc_unmodified_upstream
|
||||||
stack -= (uintptr_t)stack % sizeof(uintptr_t);
|
stack -= (uintptr_t)stack % sizeof(uintptr_t);
|
||||||
stack -= sizeof(struct start_args);
|
stack -= sizeof(struct start_args);
|
||||||
struct start_args *args = (void *)stack;
|
struct start_args *args = (void *)stack;
|
||||||
args->start_func = entry;
|
args->start_func = entry;
|
||||||
args->start_arg = arg;
|
args->start_arg = arg;
|
||||||
#ifdef __wasilibc_unmodified_upstream
|
|
||||||
args->control = attr._a_sched ? 1 : 0;
|
args->control = attr._a_sched ? 1 : 0;
|
||||||
|
|
||||||
/* Application signals (but not the synccall signal) must be
|
/* Application signals (but not the synccall signal) must be
|
||||||
@ -414,9 +474,19 @@ int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict att
|
|||||||
args->sig_mask[(SIGCANCEL-1)/8/sizeof(long)] &=
|
args->sig_mask[(SIGCANCEL-1)/8/sizeof(long)] &=
|
||||||
~(1UL<<((SIGCANCEL-1)%(8*sizeof(long))));
|
~(1UL<<((SIGCANCEL-1)%(8*sizeof(long))));
|
||||||
#else
|
#else
|
||||||
/* The new thread needs a pointer to the pthread struct so that it can set
|
/* Align the stack to struct start_args */
|
||||||
* up its `wasilibc_pthread_self` global. */
|
stack -= sizeof(struct start_args);
|
||||||
args->thread = new;
|
stack -= (uintptr_t)stack % alignof(struct start_args);
|
||||||
|
struct start_args *args = (void *)stack;
|
||||||
|
|
||||||
|
/* Align the stack to 16 and store it */
|
||||||
|
new->stack = (void *)((uintptr_t) stack & -16);
|
||||||
|
/* Correct the stack size */
|
||||||
|
new->stack_size = stack - stack_limit;
|
||||||
|
|
||||||
|
args->start_func = entry;
|
||||||
|
args->start_arg = arg;
|
||||||
|
args->tls_base = (void*)new_tls_base;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
__tl_lock();
|
__tl_lock();
|
||||||
@ -457,7 +527,7 @@ int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict att
|
|||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
ret = -EAGAIN;
|
ret = -EAGAIN;
|
||||||
} else {
|
} else {
|
||||||
atomic_store((atomic_int *) &(args->thread->tid), ret);
|
atomic_store((atomic_int *) &(new->tid), ret);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -3,9 +3,7 @@
|
|||||||
|
|
||||||
#if !defined(__wasilibc_unmodified_upstream) && defined(__wasm__) && \
|
#if !defined(__wasilibc_unmodified_upstream) && defined(__wasm__) && \
|
||||||
defined(_REENTRANT)
|
defined(_REENTRANT)
|
||||||
// We need some place to store the thread ID. This WebAssembly global fits the
|
_Thread_local struct pthread __wasilibc_pthread_self;
|
||||||
// bill and is used by `__get_tp` elsewhere.
|
|
||||||
__asm__(".globaltype __wasilibc_pthread_self, i32\n");
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static pthread_t __pthread_self_internal()
|
static pthread_t __pthread_self_internal()
|
||||||
|
Loading…
Reference in New Issue
Block a user