From a38829c692edaeeff3a1b00e85464fcba5eeab36 Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Mon, 4 Aug 2025 11:39:13 +0200 Subject: [PATCH] internal/task: use -stack-size flag when starting a new thread Found this bug while trying to use the upstream testing package instead of our own. The io/fs package wasn't passing, because the test was run in a separate goroutine (and therefore a separate thread, with its own stack) instead of all in the same thread with our own stack creation/switching implementation. --- src/internal/task/task_threads.c | 8 ++++++-- src/internal/task/task_threads.go | 4 ++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/internal/task/task_threads.c b/src/internal/task/task_threads.c index e427f5af0..8c071f9e5 100644 --- a/src/internal/task/task_threads.c +++ b/src/internal/task/task_threads.c @@ -101,7 +101,7 @@ static void* start_wrapper(void *arg) { }; // Start a new goroutine in an OS thread. -int tinygo_task_start(uintptr_t fn, void *args, void *task, pthread_t *thread, uintptr_t *stackTop, void *context) { +int tinygo_task_start(uintptr_t fn, void *args, void *task, pthread_t *thread, uintptr_t *stackTop, uintptr_t stackSize, void *context) { // Sanity check. Should get optimized away. if (sizeof(pthread_t) != sizeof(void*)) { __builtin_trap(); @@ -118,7 +118,11 @@ int tinygo_task_start(uintptr_t fn, void *args, void *task, pthread_t *thread, u #else sem_init(&state.startlock, 0, 0); #endif - int result = pthread_create(thread, NULL, &start_wrapper, &state); + pthread_attr_t attrs; + pthread_attr_init(&attrs); + pthread_attr_setstacksize(&attrs, stackSize); + int result = pthread_create(thread, &attrs, &start_wrapper, &state); + pthread_attr_destroy(&attrs); // Wait until the thread has been created and read all state_pass variables. #if __APPLE__ diff --git a/src/internal/task/task_threads.go b/src/internal/task/task_threads.go index b5d3c5ca4..48d647f16 100644 --- a/src/internal/task/task_threads.go +++ b/src/internal/task/task_threads.go @@ -109,7 +109,7 @@ func start(fn uintptr, args unsafe.Pointer, stackSize uintptr) { // and the stop-the-world GC won't see threads that haven't started yet or // are not fully started yet. activeTaskLock.Lock() - errCode := tinygo_task_start(fn, args, t, &t.state.thread, &t.state.stackTop) + errCode := tinygo_task_start(fn, args, t, &t.state.thread, &t.state.stackTop, stackSize) if errCode != 0 { runtimePanic("could not start thread") } @@ -266,7 +266,7 @@ func tinygo_task_init(t *Task, thread *threadID, numCPU *int32) // Here same as for tinygo_task_init. // //go:linkname tinygo_task_start tinygo_task_start -func tinygo_task_start(fn uintptr, args unsafe.Pointer, t *Task, thread *threadID, stackTop *uintptr) int32 +func tinygo_task_start(fn uintptr, args unsafe.Pointer, t *Task, thread *threadID, stackTop *uintptr, stackSize uintptr) int32 // Pause the thread by sending it a signal. //