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  }