mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-03 18:47:47 +00:00
3a2188fc7b
This type can be used to jump back to a previous position in a program
from inside an interrupt. This is useful for baremetal systems that
implement wfi but not wfe, and therefore have no easy (race-free) way to
wait until a flag gets changed inside an interrupt. This is an issue on
RISC-V, where this is racy (the interrupt might happen after the check
but before the wfi instruction):
configureInterrupt()
for flag.Load() != 0 {
riscv.Asm("wfi")
}
63 lines
1.5 KiB
Go
63 lines
1.5 KiB
Go
package interrupt
|
|
|
|
// A checkpoint is a setjmp like buffer, that can be used as a flag for
|
|
// interrupts.
|
|
//
|
|
// It can be used as follows:
|
|
//
|
|
// // global var
|
|
// var c Checkpoint
|
|
//
|
|
// // to set up the checkpoint and wait for it
|
|
// if c.Save() {
|
|
// setupInterrupt()
|
|
// for {
|
|
// waitForInterrupt()
|
|
// }
|
|
// }
|
|
//
|
|
// // Inside the interrupt handler:
|
|
// if c.Saved() {
|
|
// c.Jump()
|
|
// }
|
|
type Checkpoint struct {
|
|
jumpSP uintptr
|
|
jumpPC uintptr
|
|
}
|
|
|
|
// Save the execution state in the given checkpoint, overwriting a previous
|
|
// saved checkpoint.
|
|
//
|
|
// This function returns twice: once the normal way after saving (returning
|
|
// true) and once after jumping (returning false).
|
|
//
|
|
// This function is a compiler intrinsic, it is not implemented in Go.
|
|
func (c *Checkpoint) Save() bool
|
|
|
|
// Returns whether a jump point was saved (and not erased due to a jump).
|
|
func (c *Checkpoint) Saved() bool {
|
|
return c.jumpPC != 0
|
|
}
|
|
|
|
// Jump to the point where the execution state was saved, and erase the saved
|
|
// jump point. This must *only* be called from inside an interrupt.
|
|
//
|
|
// This method does not return in the conventional way, it resumes execution at
|
|
// the last point a checkpoint was saved.
|
|
func (c *Checkpoint) Jump() {
|
|
if !c.Saved() {
|
|
panic("runtime/interrupt: no checkpoint was saved")
|
|
}
|
|
jumpPC := c.jumpPC
|
|
jumpSP := c.jumpSP
|
|
c.jumpPC = 0
|
|
c.jumpSP = 0
|
|
if jumpPC == 0 {
|
|
panic("jumping to 0")
|
|
}
|
|
checkpointJump(jumpSP, jumpPC)
|
|
}
|
|
|
|
//export tinygo_checkpointJump
|
|
func checkpointJump(jumpSP, jumpPC uintptr)
|