mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-04 19:17:47 +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.
76 lines
2.3 KiB
Go
76 lines
2.3 KiB
Go
package task
|
|
|
|
import (
|
|
"unsafe"
|
|
)
|
|
|
|
// Task is a state of goroutine for scheduling purposes.
|
|
type Task struct {
|
|
// Next is a field which can be used to make a linked list of tasks.
|
|
Next *Task
|
|
|
|
// Ptr is a field which can be used for storing a pointer.
|
|
Ptr unsafe.Pointer
|
|
|
|
// Data is a field which can be used for storing state information.
|
|
Data uint64
|
|
|
|
// gcData holds data for the GC.
|
|
gcData gcData
|
|
|
|
// state is the underlying running state of the task.
|
|
state state
|
|
|
|
// This is needed for some crypto packages.
|
|
FipsIndicator uint8
|
|
|
|
// State of the goroutine: running, paused, or must-resume-next-pause.
|
|
// This extra field doesn't increase memory usage on 32-bit CPUs and above,
|
|
// since it falls into the padding of the FipsIndicator bit above.
|
|
RunState uint8
|
|
|
|
// DeferFrame stores a pointer to the (stack allocated) defer frame of the
|
|
// goroutine that is used for the recover builtin.
|
|
DeferFrame unsafe.Pointer
|
|
}
|
|
|
|
const (
|
|
// Initial state: the goroutine state is saved on the stack.
|
|
RunStatePaused = iota
|
|
|
|
// The goroutine is running right now.
|
|
RunStateRunning
|
|
|
|
// The goroutine is running, but already marked as "can resume".
|
|
// The next call to Pause() won't actually pause the goroutine.
|
|
RunStateResuming
|
|
)
|
|
|
|
// DataUint32 returns the Data field as a uint32. The value is only valid after
|
|
// setting it through SetDataUint32 or by storing to it using DataAtomicUint32.
|
|
func (t *Task) DataUint32() uint32 {
|
|
return *(*uint32)(unsafe.Pointer(&t.Data))
|
|
}
|
|
|
|
// SetDataUint32 updates the uint32 portion of the Data field (which could be
|
|
// the first 4 or last 4 bytes depending on the architecture endianness).
|
|
func (t *Task) SetDataUint32(val uint32) {
|
|
*(*uint32)(unsafe.Pointer(&t.Data)) = val
|
|
}
|
|
|
|
// DataAtomicUint32 returns the Data field as an atomic-if-needed Uint32 value.
|
|
func (t *Task) DataAtomicUint32() *Uint32 {
|
|
return (*Uint32)(unsafe.Pointer(&t.Data))
|
|
}
|
|
|
|
// getGoroutineStackSize is a compiler intrinsic that returns the stack size for
|
|
// the given function and falls back to the default stack size. It is replaced
|
|
// with a load from a special section just before codegen.
|
|
func getGoroutineStackSize(fn uintptr) uintptr
|
|
|
|
//go:linkname runtime_alloc runtime.alloc
|
|
func runtime_alloc(size uintptr, layout unsafe.Pointer) unsafe.Pointer
|
|
|
|
//go:linkname scheduleTask runtime.scheduleTask
|
|
func scheduleTask(*Task)
|