1 //go:build scheduler.tasks && amd64 && !windows
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_amd64.S that relies on the exact
11 // layout of this struct.
12 type calleeSavedRegs struct {
13 rbx uintptr
14 rbp uintptr
15 r12 uintptr
16 r13 uintptr
17 r14 uintptr
18 r15 uintptr
19 20 pc uintptr
21 }
22 23 // archInit runs architecture-specific setup for the goroutine startup.
24 func (s *state) archInit(r *calleeSavedRegs, fn uintptr, args unsafe.Pointer) {
25 // Store the initial sp for the startTask function (implemented in assembly).
26 s.sp = uintptr(unsafe.Pointer(r))
27 28 // Initialize the registers.
29 // These will be popped off of the stack on the first resume of the goroutine.
30 31 // Start the function at moxie_startTask (defined in
32 // src/internal/task/task_stack_amd64.S). This assembly code calls a
33 // function (passed in r12) with a single argument (passed in r13). After
34 // the function returns, it calls Pause().
35 r.pc = uintptr(unsafe.Pointer(&startTask))
36 37 // Pass the function to call in r12.
38 // This function is a compiler-generated wrapper which loads arguments out
39 // of a struct pointer. See createGoroutineStartWrapper (defined in
40 // compiler/goroutine.go) for more information.
41 r.r12 = fn
42 43 // Pass the pointer to the arguments struct in r13.
44 r.r13 = 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 }
62