Reputation: 979
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?
Upvotes: 4
Views: 1718
Reputation: 979
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.
Upvotes: 6