Difficulty: Easy · Puzzle 3 of 6 · Topic: Deadlock Scenario Puzzles: Objection and Phase Stalls
Two parallel sequences share one bus lock and eventually freeze under error injection. Only failing seeds hit the deadlock.
semaphore bus_sem = new(1);
task send_req(my_item req);
bus_sem.get(1);
if (req.timeout_fault) begin
\`uvm_error("DRV", "timeout")
return; // bug: token never returned
end
drive_req(req);
bus_sem.put(1);
endtaskResource ownership must be balanced even in exceptional exits.
1) Add semaphore occupancy debug counters around get/put.
2) Reproduce with timeout_fault and observe token count never returns.
3) Refactor with cleanup block so put executes for all post-get exits.
4) Consider try/finally-style coding pattern for shared resources.
5) Add assertion: semaphore token count reaches initial value at phase end.Answer: Bug: return on timeout path leaks semaphore token, blocking all later requests. Fix: always put token after successful get, regardless of error path.
Checked by running the code in Verilator 5; the printed output supports the answer above. Plain-SV semaphore model of the leaked token: the second request blocks forever until the error path also does put.
People suspect simulator scheduling; this is deterministic resource leak.
Would a mailbox-based arbitration model be safer here than manual semaphores? Model answer: No: a one-slot mailbox used as a token has the same leak if the return path skips the put. The real fix is structural: a wrapper task that does get, calls the body, and put in one place so every path (including error returns) executes the put. Assert the token count equals the initial value at end of phase.
First I check whether the later requests are all blocked on the same semaphore, because that points at a resource that was never returned. The root cause is that the return on the timeout path leaks the semaphore token, so every later request waits forever. This is a deterministic resource leak, not simulator scheduling. I confirm it by counting gets against puts, and the fix is to put the token back after every successful get, whatever the error path.