Difficulty: Medium · Puzzle 5 of 6 · Topic: Semaphore & Mailbox Puzzles
Producer sends two items after both consumers are blocked on get. Is consumer wake-up order guaranteed?
module tb;
mailbox #(int) mb = new();
task consumer(string name);
int v;
mb.get(v);
$display("[%0t] %s got %0d", $time, name, v);
endtask
initial fork
consumer("C1");
consumer("C2");
join_none
initial begin
#5 mb.put(10);
#0 mb.put(20);
#1 $finish;
end
endmoduleMailbox preserves message FIFO, but waiter scheduling fairness is not strict across processes.
1) Message order in mailbox is FIFO: 10 then 20.
2) The two consumers are fork ... join_none children, and the LRM leaves the start order of such children undefined, so even which consumer blocks first in mb.get is undefined.
3) The LRM also says nothing about the order in which several blocked get calls are served, so which blocked consumer receives 10 is not defined.
4) A run printing C1 got 10 / C2 got 20 (Verilator 5.048) is legal, and so is C2 got 10 / C1 got 20. The two lines are also at the same time, so their print order is not defined either.Answer: Data order is FIFO (10 then 20), but the consumer-to-item mapping and the print order are not guaranteed: join_none child start order is undefined and the LRM does not define the service order of several blocked get calls. C2 got 10 / C1 got 20 is a legal outcome.
Checked by running the code in Verilator 5; the printed output supports the answer above. Verilator serves the blocked getters in fork order; the LRM does not require that. Forking the consumers in the other order swaps who gets 10, so the mapping is legal either way; only the FIFO data order (10, 20) is guaranteed.
Assuming blocked getter wake-up order is deterministic across all tools can break regressions.
How would you enforce deterministic ownership (per-agent mailbox or tagged routing)?
The data order is first in, first out, so ten then twenty, but which consumer gets which is not guaranteed. The start order of join_none children is undefined, and the LRM does not define the service order of several blocked gets, so consumer two getting ten is a legal outcome, and so is the print order. The trap is assuming the wake-up order from one tool's run. I would make the test not depend on it, for example with tagged items, and check this on a second simulator.