I’m the author of that paper and can explain exactly why the driver will not call item_done before it calls get_next_item().
When you’re in one thread, all other threads are either sleeping or coming up next in the scheduler. The driver’s run phase launches a driver thread which calls item_done(). When the agent executes the stop_sequences and triggers reset_driver, that is the active thread. By triggering reset_driver, the next thread that will be executed will wake the driver’s run_phase which kills the driver task thread and resets the interface signals.
Having been killed, the run phase continues its forever loop and launches a brand new driver task, then waits for reset_driver to be triggered (again).
Once the new driver task’s thread starts, it will call get_next… from the sequencer before it calls item_done. Thus, the order between the sequencer and the driver is maintained.
Why is this not overkill? Because by disabling (killing) the driver thread, you are wiping out all local variables and/or state that the driver was using. It very neatly does this for you rather than having to track all such values yourself.
The same is true for the scoreboard and any other components that might launch threads outside of the run phase.