- Path:
src/runtime/chan.go
Compilation
When you make a chan with make
function, the compiler will expand the expression to the makechan
implementation. The actual expansion happens
at cmd/compile/internal/walk/expr.go
. The runtime will determine whether to use makechan
or makechan64
.
Type Definitions
type _type
_type
is used as the internal representation of a go
type. The same structure is defined multiple times across the go
runtime.
_type
stores the following fields:
type chantype
makechan
only uses chantype.elem
, the other fields are used by the type system.
type waitq
waitq
is a queue of waiting goroutines. There’s a special flag to check whether goroutine has grabbed the channel locks but not removed itself from waitq
.
If the flag is true, dequeue
will continue and try to find the next valid goroutine.
type hchan
hchan
used a circular queue to save the buffered channel data.
Runtime Implementation
makechan
- Check the element’s size and alignment, and the expected
chan
’s size. - Allocate the memory for
hchan
. The memory allocation is very dense and the runtime will try to utilize the memory at its best effort.
chansend
- Check whether the channel is unresponsive and return.
- Lock the channel
- Check whether the channel is closed.
- Get a receiver from
waitq
, and send the data directly to that goroutine, then return true. - If the channel buffer is not full yet,
memmove
the data to the circular queue, then return true. - If it’s not a blocking operation, return false.
- Block the current goroutine, and put it on the
sendq
.
send
send
will send the data to the target goroutine. It happens when the target goroutine is waiting and the data arrived on the channel.
The send
operation will copy the data directly to the target goroutine’s stack, and make the target goroutine as ready state.
chanrecv
- Check whether the channel is unresponsive and return.
- Lock the channel
- If the queue is closed and the circular queue is empty, return.
- If there’s a waiting goroutine on
sendq
,recv
immediately and return. - Move the data from the circular queue to the target memory address.
- If it’s not a blocking operation, return false.
- Block the current goroutine, and put it on the
waitq
.
recv
recv
happens under a similar condition to send
.
- If the channel is unbuffered,
recvDirect
from the sending goroutine to receiving goroutine. - Read the data from the circular queue first, and move the data to the target memory address.
- Mark the sending goroutine as ready to run. Note that the receiving goroutine is already running.
What’s Next
- Go’s typing system
- Go’s routines implementation.