diff --git a/GNUmakefile b/GNUmakefile index d8770c325..58568d3ec 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -972,6 +972,7 @@ endif @cp -rp lib/musl/crt/crt1.c build/release/tinygo/lib/musl/crt @cp -rp lib/musl/COPYRIGHT build/release/tinygo/lib/musl @cp -rp lib/musl/include build/release/tinygo/lib/musl + @cp -rp lib/musl/src/conf build/release/tinygo/lib/musl/src @cp -rp lib/musl/src/ctype build/release/tinygo/lib/musl/src @cp -rp lib/musl/src/env build/release/tinygo/lib/musl/src @cp -rp lib/musl/src/errno build/release/tinygo/lib/musl/src diff --git a/builder/musl.go b/builder/musl.go index 419533255..3f3a8d46c 100644 --- a/builder/musl.go +++ b/builder/musl.go @@ -124,6 +124,7 @@ var libMusl = Library{ librarySources: func(target string) ([]string, error) { arch := compileopts.MuslArchitecture(target) globs := []string{ + "conf/*.c", "ctype/*.c", "env/*.c", "errno/*.c", diff --git a/compileopts/config.go b/compileopts/config.go index 6cc87aabd..61efa439f 100644 --- a/compileopts/config.go +++ b/compileopts/config.go @@ -22,7 +22,7 @@ import ( // builder.Library struct but that's hard to do since we want to know the // library path in advance in several places). var libVersions = map[string]int{ - "musl": 2, + "musl": 3, } // Config keeps all configuration affecting the build in a single struct. diff --git a/src/internal/task/task_threads.c b/src/internal/task/task_threads.c index a14844f2e..6ada95fa8 100644 --- a/src/internal/task/task_threads.c +++ b/src/internal/task/task_threads.c @@ -6,6 +6,7 @@ #include #include #include +#include // BDWGC also uses SIGRTMIN+6 on Linux, which seems like a reasonable choice. #ifdef __linux__ @@ -29,7 +30,7 @@ struct state_pass { void tinygo_task_gc_pause(int sig); // Initialize the main thread. -void tinygo_task_init(void *mainTask, pthread_t *thread, void *context) { +void tinygo_task_init(void *mainTask, pthread_t *thread, int *numCPU, void *context) { // Make sure the current task pointer is set correctly for the main // goroutine as well. current_task = mainTask; @@ -43,6 +44,14 @@ void tinygo_task_init(void *mainTask, pthread_t *thread, void *context) { act.sa_flags = SA_SIGINFO; act.sa_handler = &tinygo_task_gc_pause; sigaction(taskPauseSignal, &act, NULL); + + // Obtain the number of CPUs available on program start (for NumCPU). + int num = sysconf(_SC_NPROCESSORS_ONLN); + if (num <= 0) { + // Fallback in case there is an error. + num = 1; + } + *numCPU = num; } void tinygo_task_exited(void*); diff --git a/src/internal/task/task_threads.go b/src/internal/task/task_threads.go index 1eb1fed7c..db204cb4e 100644 --- a/src/internal/task/task_threads.go +++ b/src/internal/task/task_threads.go @@ -38,6 +38,8 @@ type state struct { // Goroutine counter, starting at 0 for the main goroutine. var goroutineID uintptr +var numCPU int32 + var mainTask Task // Queue of tasks (see QueueNext) that currently exist in the program. @@ -53,7 +55,7 @@ func OnSystemStack() bool { // startup, before starting any other goroutines. func Init(sp uintptr) { mainTask.state.stackTop = sp - tinygo_task_init(&mainTask, &mainTask.state.thread) + tinygo_task_init(&mainTask, &mainTask.state.thread, &numCPU) } // Return the task struct for the current thread. @@ -259,7 +261,7 @@ func runtimePanic(msg string) // that the 't' parameter won't escape (because it will). // //go:linkname tinygo_task_init tinygo_task_init -func tinygo_task_init(t *Task, thread *threadID) +func tinygo_task_init(t *Task, thread *threadID, numCPU *int32) // Here same as for tinygo_task_init. // @@ -273,3 +275,7 @@ func tinygo_task_send_gc_signal(threadID) //export tinygo_task_current func tinygo_task_current() unsafe.Pointer + +func NumCPU() int { + return int(numCPU) +} diff --git a/src/runtime/debug.go b/src/runtime/debug.go index 139e18bcd..230515908 100644 --- a/src/runtime/debug.go +++ b/src/runtime/debug.go @@ -1,14 +1,5 @@ package runtime -// NumCPU returns the number of logical CPUs usable by the current process. -// -// The set of available CPUs is checked by querying the operating system -// at process startup. Changes to operating system CPU allocation after -// process startup are not reflected. -func NumCPU() int { - return 1 -} - // Stub for NumCgoCall, does not return the real value func NumCgoCall() int { return 0 diff --git a/src/runtime/scheduler_cooperative.go b/src/runtime/scheduler_cooperative.go index 82ec24bee..3cb1e3f98 100644 --- a/src/runtime/scheduler_cooperative.go +++ b/src/runtime/scheduler_cooperative.go @@ -60,6 +60,11 @@ func Gosched() { task.Pause() } +// NumCPU returns the number of logical CPUs usable by the current process. +func NumCPU() int { + return 1 +} + // Add this task to the sleep queue, assuming its state is set to sleeping. func addSleepTask(t *task.Task, duration timeUnit) { if schedulerDebug { diff --git a/src/runtime/scheduler_none.go b/src/runtime/scheduler_none.go index 82e720393..dc4b03b6e 100644 --- a/src/runtime/scheduler_none.go +++ b/src/runtime/scheduler_none.go @@ -44,6 +44,11 @@ func Gosched() { // There are no other goroutines, so there's nothing to schedule. } +// NumCPU returns the number of logical CPUs usable by the current process. +func NumCPU() int { + return 1 +} + func addTimer(tim *timerNode) { runtimePanic("timers not supported without a scheduler") } diff --git a/src/runtime/scheduler_threads.go b/src/runtime/scheduler_threads.go index e553a5b9c..292499354 100644 --- a/src/runtime/scheduler_threads.go +++ b/src/runtime/scheduler_threads.go @@ -50,6 +50,11 @@ func Gosched() { // operation, so is probably best not to use. } +// NumCPU returns the number of logical CPUs usable by the current process. +func NumCPU() int { + return task.NumCPU() +} + // Separate goroutine (thread) that runs timer callbacks when they expire. func timerRunner() { for {