Each DOS command will call DD_L_ON_MOTOR, which will test to see if the motor is running. If not, it starts it and waits for the motor on time. With the changes in changeset 400:ac2e8c73fdab this means that the busy spin of the motor on time (1 sec normally) is stretched out and becomes much longer. It also means that a whole timeslice is wasted just spinning.
We could eliminate this cpu wastage and time dilation by starting the motor and waiting the motor on time using wait() or wait_until() which will put the thread to sleep before calling the relevant dos call.
Looking at the implementation of DD_L_ON_MOTOR, it clears the timer value first, then checks to see if the motor is on by inspecting the BANK678 variable. The ordering looks correct here to avoid stopping the motor (via interrupt code) just as we have decided it is already running.
The sequence of events interleave correctly with the interrupt timer decrement to produce the correct results. The worst case is that we turn the motor off once we have passed the code proposed here, then DD_L_ON_MOTOR performs the wait for us. Although it could mean a rare case when the motor on time is longer, there is no correctness issue.
Inspecting the loop in DD_L_ON_MOTOR, the default timing comes out (as expected) to 1 sec.
To implement this without making every thread waste 1 second, we need to use the same kind of approach as is used in the ROM already:
This probably makes sense to build into dos_springboard, rather than making all callers of it perform the above checks. In SpecOS, we should use dos_mutex to protect the clearing of the timer value and checking motor status too, and this will act as a natural barrier to other threads. Otherwise, it would be possible for a second thread to jump over the first thread which had just started sleeping, and the second thread would arrive at the FDD chip before it was ready.
Unfortunately it's not as simple as first thought. Some DOS calls will never result in the motor needing to be on, and some may only selectively turn on the motor if they need to (e.g. open of a M: file doesn't need the motor). The logic needed to determine this would simply duplicate what the +3DOS rom will do anyway.
It's probably simpler to shorten the motor on timeout slightly (in the initialisation code) to account for at least the minimal time dilation of an otherwise idle system. This will set a lower bound for the motor on time which should then be at least 1 second.