github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/src/internal/task/task_stack_tinygoriscv.go (about)

     1  //go:build scheduler.tasks && 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 scheduler_riscv.S that relies on the
    11  // exact layout of this struct.
    12  type calleeSavedRegs struct {
    13  	s0  uintptr // x8 (fp)
    14  	s1  uintptr // x9
    15  	s2  uintptr // x18
    16  	s3  uintptr // x19
    17  	s4  uintptr // x20
    18  	s5  uintptr // x21
    19  	s6  uintptr // x22
    20  	s7  uintptr // x23
    21  	s8  uintptr // x24
    22  	s9  uintptr // x25
    23  	s10 uintptr // x26
    24  	s11 uintptr // x27
    25  
    26  	pc uintptr
    27  }
    28  
    29  // archInit runs architecture-specific setup for the goroutine startup.
    30  func (s *state) archInit(r *calleeSavedRegs, fn uintptr, args unsafe.Pointer) {
    31  	// Store the initial sp for the startTask function (implemented in assembly).
    32  	s.sp = uintptr(unsafe.Pointer(r))
    33  
    34  	// Initialize the registers.
    35  	// These will be popped off of the stack on the first resume of the goroutine.
    36  
    37  	// Start the function at tinygo_startTask (defined in src/internal/task/task_stack_riscv.S).
    38  	// This assembly code calls a function (passed in s0) with a single argument
    39  	// (passed in s1). After the function returns, it calls Pause().
    40  	r.pc = uintptr(unsafe.Pointer(&startTask))
    41  
    42  	// Pass the function to call in s0.
    43  	// This function is a compiler-generated wrapper which loads arguments out
    44  	// of a struct pointer. See createGoroutineStartWrapper (defined in
    45  	// compiler/goroutine.go) for more information.
    46  	r.s0 = fn
    47  
    48  	// Pass the pointer to the arguments struct in s1.
    49  	r.s1 = uintptr(args)
    50  }
    51  
    52  func (s *state) resume() {
    53  	swapTask(s.sp, &systemStack)
    54  }
    55  
    56  func (s *state) pause() {
    57  	newStack := systemStack
    58  	systemStack = 0
    59  	swapTask(newStack, &s.sp)
    60  }
    61  
    62  // SystemStack returns the system stack pointer when called from a task stack.
    63  // When called from the system stack, it returns 0.
    64  func SystemStack() uintptr {
    65  	return systemStack
    66  }