The scheduler needs somewhere to keep the tasks that are ready to run. That is the run queue - a plain first-in, first-out line. Today you build it, because the order tasks leave this queue is what makes every later interleaving exact.
Build a first-in, first-out run queue with enqueue, dequeue, and length.
Cooperative scheduling is fair because it is first-in, first-out: a task that becomes ready waits behind everyone who was already waiting, and no task can jump the line. That single rule is what makes round-robin interleaving deterministic later - when two tasks both yield, the one that yielded first runs first.
Today the queue is a plain slice: enqueue appends to the back, dequeue removes from the front. That is the whole data structure. Keeping enqueue-at-back and dequeue-at-front straight now matters enormously - reverse them and every trace in this project comes out backwards. The scheduler you build next lesson does nothing but pull from this queue.
// a queue is just a slice used front-to-backtype runq struct{ items []*Task }func (q *runq) enqueue(t *Task) { q.items = append(q.items, t) } // to the backfunc (q *runq) dequeue() *Task { // from the frontt := q.items[0]q.items = q.items[1:]return t}func (q *runq) len() int { return len(q.items) }