github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/src/internal/task/task_stack_386.go (about) 1 //go:build scheduler.tasks && 386 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_386.S that relies on the exact 11 // layout of this struct. 12 type calleeSavedRegs struct { 13 ebx uintptr 14 esi uintptr 15 edi uintptr 16 ebp uintptr 17 18 pc uintptr 19 20 // Pad this struct so that tasks start on a 16-byte aligned stack. 21 _ [3]uintptr 22 } 23 24 // archInit runs architecture-specific setup for the goroutine startup. 25 func (s *state) archInit(r *calleeSavedRegs, fn uintptr, args unsafe.Pointer) { 26 // Store the initial sp for the startTask function (implemented in assembly). 27 s.sp = uintptr(unsafe.Pointer(r)) 28 29 // Initialize the registers. 30 // These will be popped off of the stack on the first resume of the goroutine. 31 32 // Start the function at tinygo_startTask (defined in 33 // src/internal/task/task_stack_386.S). This assembly code calls a function 34 // (passed in EBX) with a single argument (passed in ESI). After the 35 // function returns, it calls Pause(). 36 r.pc = uintptr(unsafe.Pointer(&startTask)) 37 38 // Pass the function to call in EBX. 39 // This function is a compiler-generated wrapper which loads arguments out 40 // of a struct pointer. See createGoroutineStartWrapper (defined in 41 // compiler/goroutine.go) for more information. 42 r.ebx = fn 43 44 // Pass the pointer to the arguments struct in ESI. 45 r.esi = uintptr(args) 46 } 47 48 func (s *state) resume() { 49 swapTask(s.sp, &systemStack) 50 } 51 52 func (s *state) pause() { 53 newStack := systemStack 54 systemStack = 0 55 swapTask(newStack, &s.sp) 56 } 57 58 // SystemStack returns the system stack pointer when called from a task stack. 59 // When called from the system stack, it returns 0. 60 func SystemStack() uintptr { 61 return systemStack 62 }