github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/src/internal/task/task_stack_arm.go (about) 1 //go:build scheduler.tasks && arm && !cortexm && !avr && !xtensa && !tinygo.riscv 2 3 package task 4 5 import "unsafe" 6 7 var systemStack uintptr 8 9 // calleeSavedRegs is the list of registers that must be saved and restored when 10 // switching between tasks. Also see task_stack_arm.S that relies on the exact 11 // layout of this struct. 12 type calleeSavedRegs struct { 13 r4 uintptr 14 r5 uintptr 15 r6 uintptr 16 r7 uintptr 17 r8 uintptr 18 r9 uintptr 19 r10 uintptr 20 r11 uintptr 21 22 pc uintptr 23 } 24 25 // archInit runs architecture-specific setup for the goroutine startup. 26 func (s *state) archInit(r *calleeSavedRegs, fn uintptr, args unsafe.Pointer) { 27 // Store the initial sp for the startTask function (implemented in assembly). 28 s.sp = uintptr(unsafe.Pointer(r)) 29 30 // Initialize the registers. 31 // These will be popped off of the stack on the first resume of the goroutine. 32 33 // Start the function at tinygo_startTask (defined in src/internal/task/task_stack_arm.S). 34 // This assembly code calls a function (passed in r4) with a single argument 35 // (passed in r5). After the function returns, it calls Pause(). 36 r.pc = uintptr(unsafe.Pointer(&startTask)) 37 38 // Pass the function to call in r4. 39 // This function is a compiler-generated wrapper which loads arguments out of a struct pointer. 40 // See createGoroutineStartWrapper (defined in compiler/goroutine.go) for more information. 41 r.r4 = fn 42 43 // Pass the pointer to the arguments struct in r5. 44 r.r5 = uintptr(args) 45 } 46 47 func (s *state) resume() { 48 swapTask(s.sp, &systemStack) 49 } 50 51 func (s *state) pause() { 52 newStack := systemStack 53 systemStack = 0 54 swapTask(newStack, &s.sp) 55 } 56 57 // SystemStack returns the system stack pointer when called from a task stack. 58 // When called from the system stack, it returns 0. 59 func SystemStack() uintptr { 60 return systemStack 61 }