mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-06 20:13:40 +00:00
60f8a62978
This commit adds support for a scheduler that runs a scheduler on all available cores. It is meant to be used on baremetal systems with a fixed number of cores, such as the RP2040. The initial implementation adds support for multicore scheduling to the riscv-qemu target as a convenient testing target. This means that this new multicore scheduler is tested in CI, including a bunch of standard library tests (`make tinygo-test-baremetal`). This should ensure the new scheduler is reasonably well tested before trying to use it on harder-to-debug targets like the RP2040.
65 lines
1.4 KiB
Go
65 lines
1.4 KiB
Go
//go:build scheduler.cores
|
|
|
|
package task
|
|
|
|
import "runtime/interrupt"
|
|
|
|
// A futex is a way for userspace to wait with the pointer as the key, and for
|
|
// another thread to wake one or all waiting threads keyed on the same pointer.
|
|
//
|
|
// A futex does not change the underlying value, it only reads it before to prevent
|
|
// lost wake-ups.
|
|
type Futex struct {
|
|
Uint32
|
|
|
|
waiters Stack
|
|
}
|
|
|
|
// Atomically check for cmp to still be equal to the futex value and if so, go
|
|
// to sleep. Return true if we were definitely awoken by a call to Wake or
|
|
// WakeAll, and false if we can't be sure of that.
|
|
func (f *Futex) Wait(cmp uint32) (awoken bool) {
|
|
mask := lockFutex()
|
|
|
|
if f.Uint32.Load() != cmp {
|
|
unlockFutex(mask)
|
|
return false
|
|
}
|
|
|
|
// Push the current goroutine onto the waiter stack.
|
|
f.waiters.Push(Current())
|
|
|
|
unlockFutex(mask)
|
|
|
|
// Pause until this task is awoken by Wake/WakeAll.
|
|
Pause()
|
|
|
|
// We were awoken by a call to Wake or WakeAll. There is no chance for
|
|
// spurious wakeups.
|
|
return true
|
|
}
|
|
|
|
// Wake a single waiter.
|
|
func (f *Futex) Wake() {
|
|
mask := lockFutex()
|
|
if t := f.waiters.Pop(); t != nil {
|
|
scheduleTask(t)
|
|
}
|
|
unlockFutex(mask)
|
|
}
|
|
|
|
// Wake all waiters.
|
|
func (f *Futex) WakeAll() {
|
|
mask := lockFutex()
|
|
for t := f.waiters.Pop(); t != nil; t = f.waiters.Pop() {
|
|
scheduleTask(t)
|
|
}
|
|
unlockFutex(mask)
|
|
}
|
|
|
|
//go:linkname lockFutex runtime.lockFutex
|
|
func lockFutex() interrupt.State
|
|
|
|
//go:linkname unlockFutex runtime.unlockFutex
|
|
func unlockFutex(interrupt.State)
|