g0 has a fixed and larger stack. This allows Go to perform operations where a bigger stack is needed, and when it is preferable for the stack not to grow.
On calling go func() {}, GO delegates the goroutine creation to g0 before putting it in local queue. Newly created goroutines are placed on top of local queue and are run on priority.
stopping the world, scanning the stack of the goroutines, and some of the marking and sweeping operations.
When needed, Go increases the size of the goroutines. This operation is done by g0 in the prolog functions.
Go limits the number of OS thread running thanks to GOMAXPROCS variable simultaneously. That means Go has to schedule and manage goroutines on each of the running threads. This role is delegated to a special goroutine, called g0, that is the first goroutine created for EACH OS thread. Then, it will schedule ready goroutines to run on the threads.
Example:
ch := make(chan int)
[...]
ch <- v
When blocking on channels, the current goroutine will be parked (in waiting mode) and will not be pushed to any queues. g0 replaces this parked goroutine and does round one scheduling. The local queue has priority over global queue.
The parked goroutine gets unblocked as soon as a receiver comes with reading the channel.
v := <-ch
The goroutine receiving the message will switch to g0 and unlock the parked goroutine by putting it on the local queue.