From 853dc6b5a7a4fc16559e7e7fbe4546a33bba89d6 Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Tue, 28 Jan 2025 15:12:50 +0100 Subject: [PATCH] darwin: add threading support and use it by default --- compileopts/target.go | 3 ++- src/internal/task/darwin.go | 11 +++++++++++ src/internal/task/task_threads.c | 30 +++++++++++++++++++++++++++--- 3 files changed, 40 insertions(+), 4 deletions(-) create mode 100644 src/internal/task/darwin.go diff --git a/compileopts/target.go b/compileopts/target.go index 3c5fd62390..2da0a9f35c 100644 --- a/compileopts/target.go +++ b/compileopts/target.go @@ -385,7 +385,7 @@ func defaultTarget(options *Options) (*TargetSpec, error) { platformVersion = "11.0.0" // first macosx platform with arm64 support } llvmvendor = "apple" - spec.Scheduler = "tasks" + spec.Scheduler = "threads" spec.Linker = "ld.lld" spec.Libc = "darwin-libSystem" // Use macosx* instead of darwin, otherwise darwin/arm64 will refer to @@ -399,6 +399,7 @@ func defaultTarget(options *Options) (*TargetSpec, error) { ) spec.ExtraFiles = append(spec.ExtraFiles, "src/internal/futex/futex_darwin.c", + "src/internal/task/task_threads.c", "src/runtime/os_darwin.c", "src/runtime/runtime_unix.c", "src/runtime/signal.c") diff --git a/src/internal/task/darwin.go b/src/internal/task/darwin.go new file mode 100644 index 0000000000..47d9172650 --- /dev/null +++ b/src/internal/task/darwin.go @@ -0,0 +1,11 @@ +//go:build darwin + +package task + +import "unsafe" + +// MacOS uses a pointer so unsafe.Pointer should be fine: +// +// typedef struct _opaque_pthread_t *__darwin_pthread_t; +// typedef __darwin_pthread_t pthread_t; +type threadID unsafe.Pointer diff --git a/src/internal/task/task_threads.c b/src/internal/task/task_threads.c index a14844f2ef..2502be2eb9 100644 --- a/src/internal/task/task_threads.c +++ b/src/internal/task/task_threads.c @@ -2,15 +2,23 @@ #define _GNU_SOURCE #include -#include #include #include #include -// BDWGC also uses SIGRTMIN+6 on Linux, which seems like a reasonable choice. #ifdef __linux__ +#include + +// BDWGC also uses SIGRTMIN+6 on Linux, which seems like a reasonable choice. #define taskPauseSignal (SIGRTMIN + 6) -#endif + +#elif __APPLE__ +#include +// Use an arbitrary signal number (31-63) in the hope that it isn't used +// elsewhere. +#define taskPauseSignal 60 + +#endif // __linux__, __APPLE__ // Pointer to the current task.Task structure. // Ideally the entire task.Task structure would be a thread-local variable but @@ -22,7 +30,11 @@ struct state_pass { void *args; void *task; uintptr_t *stackTop; + #if __APPLE__ + dispatch_semaphore_t startlock; + #else sem_t startlock; + #endif }; // Handle the GC pause in Go. @@ -60,7 +72,11 @@ static void* start_wrapper(void *arg) { // Notify the caller that the thread has successfully started and // initialized. + #if __APPLE__ + dispatch_semaphore_signal(state->startlock); + #else sem_post(&state->startlock); + #endif // Run the goroutine function. start(args); @@ -84,11 +100,19 @@ int tinygo_task_start(uintptr_t fn, void *args, void *task, pthread_t *thread, u .task = task, .stackTop = stackTop, }; + #if __APPLE__ + state.startlock = dispatch_semaphore_create(0); + #else sem_init(&state.startlock, 0, 0); + #endif int result = pthread_create(thread, NULL, &start_wrapper, &state); // Wait until the thread has been created and read all state_pass variables. + #if __APPLE__ + dispatch_semaphore_wait(state.startlock, DISPATCH_TIME_FOREVER); + #else sem_wait(&state.startlock); + #endif return result; }