OK, got it. It's down to the perils of comparing floats to ints (and that doesn't only bite on equality comparisons!).
If a power timer and recording timer are set for the same time, and the power timer code runs before the recording timer code, then the power timer checks whether it should back off by calling
recordingsActive(900) (15-minute margin):
Code: Select all
def recordingsActive(margin):
recordTimer = NavigationInstance.instance.RecordTimer
return (
recordTimer.isRecording() or
abs(recordTimer.getNextRecordingTime() - time()) <= margin or
abs(recordTimer.getNextZapTime() - time()) <= margin
)
Because the recording timer has not yet run, the recording will still be in
StatePrepared, not in
StateRunning, and if there are no other recordings running, then
recordTimer.isRecording() returns
False.
You'd expect that the margin test on
recordTimer.getNextRecordingTime() would succeed, but if the recording that's about to start is the only one starting within the margin, then there's a problem here:
Code: Select all
def getNextRecordingTimeOld(self):
now = time()
for timer in self.timer_list:
next_act = timer.getNextActivation()
if timer.justplay or next_act < now:
continue
return next_act
return -1
def getNextRecordingTime(self):
nextrectime = self.getNextRecordingTimeOld()
... irrelevant stuff ...
return nextrectime
getNextActivation() will return the integer "current time" as the time for the next activation of the recording timer (it's about to start), however,
now is in floating point time, and will be slightly later than the start time of the recording timer. The recording timer start time will be something like ...12340, and
now will be something like ...1234.001, so
next_act < now will fail, and
getNextRecordingTime() will return -1. That corresponds to the time 1969-12-31T23:59, which is well outside the margin of 15 minutes, so the power timer code concludes that there's no recording interfering with its operation and starts the shutdown sequence.
The bug will only be triggered if the power timer activates at the same second as the recording timer is due to start recording, but runs before it: in my tests, because they have the same time, and in Grumpy_Geoff's case, because the power timer triggered 5 minutes before the recording timer and was deferred for 5 minutes (power timers defer for 5min, 10min, 20min, 40min ... 60min, and then stay at 60min deferrals) The problem could also be caused by a power timer triggering exactly 15min (5 + 10 min) before the recording timer starts. A power timer triggering before that time will correctly shut the PVR down, and allow the recording timer to restart it.
It should be fixable by doing
now = int(time()) in
getNextRecordingTimeOld(), since the operations should take much less than 1 second to complete. There still may be a potential race condition if some other thread (or Linux process) grabs all the CPUs for more than a second while that code is trying to run.