I'm trying to break down how the Go scheduler works, and what I'm seeing in runtime/proc.go is:
schedule function calls execute to run a goroutineexecute explicitly says this function never returns. It calls gogo function defined in one of the assembly files.gogo function performs a jump to the address of the first instruction of a new goroutine.schedule function is called again, so we're back to step 1.If my understanding is correct, then how does this scheme avoid stack overflow? Does it have something to do with "infinite" stacks that automatically increase their size, or am I missing something here?
So I spent some time researching the subject and can now try to answer my own question. The whole goroutine lifecycle turned out to be a bit more complex:
g0, which is kind of a main goroutine of a thread. Any call to go func changes the stack from whatever current goroutine it was called from to g0 (this is done in proc.go:newproc).proc.go:newproc1), its stack (and/or program counter, PC) is constructed in a way that it looks like it was called by goexit function. This is done to guarantee that when goroutine completes and returns, it is returned to goexit.schedule is called and a goroutine is chosen to run, the execute function executes it (== jumps to its address via the gogo assembly function).goexit function, implemented in assembly.proc.go:goexit1 (not sure why this extra step in assembly is needed).goexit1 function changes current stack to g0. This is done with a call to mcall ("Machine thread call"), which executes whatever function is received in an argument. In this case the function supplied to mcall is goexit0.mcall, implemented in assembly, jumps to the address of g0's stack frame (SP) and performs a CALL to goexit0.goexit0 function is executed in the context of g0. It puts a completed goroutine on a list of free goroutines, and frees its stack if it was previously increased.goexit0 calls schedule again, which chooses a goroutine to run, so we get back to step 3.So indeed there seems to be no recursion here. The scheduled goroutine itself never calls schedule: this is done by a special goroutine g0.
I'm still not sure if I captured all the details though, so comments and additional answers are appreciated.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With