Go channels are implemented as hchan structures containing a circular buffer and two wait queues (recvq and sendq) of sudog objects that block goroutines waiting to send or receive. When a send or receive operation cannot proceed immediately, the runtime creates a sudog, links it into the appropriate queue within the hchan, and parks the goroutine until a matching operation wakes it up.
// src/runtime/chan.go
type hchan struct {
qcount uint // total data in the queue
dataqsiz uint // size of the circular queue
buf unsafe.Pointer // points to an array of dataqsiz elements
recvq waitq // list of recv waiters (sudogs)
sendq waitq // list of send waiters (sudogs)
lock mutex // protects all fields
}
type waitq struct {
first *sudog
last *sudog
}