diff --git a/src/internal/task/task_threads.go b/src/internal/task/task_threads.go index 40e14df194..c175bedbfc 100644 --- a/src/internal/task/task_threads.go +++ b/src/internal/task/task_threads.go @@ -202,6 +202,11 @@ func CoroExit(next *Task) { tinygo_task_exit() } +// Yield yields the current thread to the OS scheduler. +func Yield() { + sched_yield() +} + // scanWaitGroup is used to wait on until all threads have finished the current state transition. var scanWaitGroup waitGroup @@ -372,6 +377,9 @@ func tinygo_task_send_gc_signal(threadID) //export tinygo_task_current func tinygo_task_current() unsafe.Pointer +//export sched_yield +func sched_yield() int32 + func NumCPU() int { return int(numCPU) } diff --git a/src/runtime/runtime_unix.go b/src/runtime/runtime_unix.go index e1273059b7..14b544b991 100644 --- a/src/runtime/runtime_unix.go +++ b/src/runtime/runtime_unix.go @@ -418,9 +418,6 @@ func signal_disable(s uint32) { func signal_waitUntilIdle() { // Wait until signal_recv has processed all signals. for receivedSignals.Load() != 0 { - // TODO: this becomes a busy loop when using threads. - // We might want to pause until signal_recv has no more incoming signals - // to process. Gosched() } } diff --git a/src/runtime/scheduler_threads.go b/src/runtime/scheduler_threads.go index 90615b08d8..a6c7750d6e 100644 --- a/src/runtime/scheduler_threads.go +++ b/src/runtime/scheduler_threads.go @@ -61,9 +61,9 @@ func scheduleTaskNoWake(t *task.Task) { } func Gosched() { - // Each goroutine runs in a thread, so there's not much we can do here. - // There is sched_yield but it's only really intended for realtime - // operation, so is probably best not to use. + // Each goroutine runs in a thread, so yield the thread to let other + // goroutines make progress. + task.Yield() } // NumCPU returns the number of logical CPUs usable by the current process.