Permalink
Browse files

Hopefully remove more scheduler/recorder deadlocks.

Change the scheduler to unlock schedLock when calling the recorder
synchronously.  If the recorder happens to be calling the scheduler at
the same time, this allows the recorder's call to grab the lock as
needed.

Fixes #10647, #10770 and #10771 .
  • Loading branch information...
gigem committed Jul 6, 2012
1 parent ed1bb0c commit ca273324961b95e300890ed40e833249b5460bd8
Showing with 41 additions and 18 deletions.
  1. +41 −18 mythtv/programs/mythbackend/scheduler.cpp
@@ -706,7 +706,10 @@ bool Scheduler::ChangeRecordingEnd(RecordingInfo *oldp, RecordingInfo *newp)
}
EncoderLink *tv = (*m_tvList)[oldp->GetCardID()];
- RecStatusType rs = tv->StartRecording(oldp);
+ RecordingInfo tempold(*oldp);
+ lockit.unlock();
+ RecStatusType rs = tv->StartRecording(&tempold);
+ lockit.relock();
if (rs != rsRecording)
{
LOG(VB_GENERAL, LOG_ERR,
@@ -833,8 +836,6 @@ void Scheduler::SlaveDisconnected(uint cardid)
void Scheduler::BuildWorkList(void)
{
- reclist_changed = false;
-
RecIter i = reclist.begin();
for (; i != reclist.end(); ++i)
{
@@ -1797,11 +1798,13 @@ void Scheduler::run(void)
QDateTime idleSince = QDateTime();
int maxSleep = 60000; // maximum sleep time in milliseconds
int schedRunTime = 30; // max scheduler run time in seconds
+ bool statuschanged = false;
while (doRun)
{
+ reclist_changed = false;
+
QDateTime curtime = MythDate::current();
- bool statuschanged = false;
int secs_to_next = (startIter != reclist.end()) ?
curtime.secsTo((*startIter)->GetRecordingStartTime()) : 60*60;
@@ -1911,6 +1914,12 @@ void Scheduler::run(void)
**it, statuschanged, prerollseconds, tuningTimeout);
}
+ // HandleRecording() and HandleTuning() temporarily unlocks
+ // schedLock. If anything changed, reclist iterators could be
+ // invalidated so start over.
+ if (reclist_changed)
+ continue;
+
/// Wake any slave backends that need waking
curtime = MythDate::current();
for (RecIter it = startIter; it != reclist.end(); ++it)
@@ -1936,6 +1945,8 @@ void Scheduler::run(void)
idleTimeoutSecs, idleWaitForRecordingTime,
statuschanged);
}
+
+ statuschanged = false;
}
RunEpilog();
@@ -2419,7 +2430,7 @@ bool Scheduler::HandleRecording(
if (ri.GetRecordingStatus() == rsTuning)
{
HandleTuning(ri, statuschanged, tuningTimeout);
- return false;
+ return reclist_changed;
}
if (ri.GetRecordingStatus() != rsWillRecord)
@@ -2485,7 +2496,14 @@ bool Scheduler::HandleRecording(
return false;
}
- if ((prerollseconds > 0) && !IsBusyRecording(&ri))
+ RecordingInfo tempri(ri);
+ schedLock.unlock();
+ bool isBusyRecording = IsBusyRecording(&tempri);
+ schedLock.lock();
+ if (reclist_changed)
+ return reclist_changed;
+
+ if (prerollseconds > 0 && !isBusyRecording)
{
// Will use pre-roll settings only if no other
// program is currently being recorded
@@ -2577,8 +2595,10 @@ bool Scheduler::HandleRecording(
{
if (ri.GetRecordingStatus() == rsWillRecord)
{
- recStatus = nexttv->StartRecording(&ri);
- ri.AddHistory(false);
+ tempri = ri;
+ schedLock.unlock();
+ recStatus = nexttv->StartRecording(&tempri);
+ schedLock.lock();
// activate auto expirer
if (m_expirer)
@@ -2589,7 +2609,7 @@ bool Scheduler::HandleRecording(
HandleRecordingStatusChange(ri, recStatus, details);
statuschanged = true;
- return false;
+ return reclist_changed;
}
void Scheduler::HandleRecordingStatusChange(
@@ -2600,15 +2620,13 @@ void Scheduler::HandleRecordingStatusChange(
ri.SetRecordingStatus(recStatus);
- if (rsTuning != recStatus)
- {
- bool doSchedAfterStart =
- ((rsRecording != recStatus) && (rsTuning != recStatus)) ||
- schedAfterStartMap[ri.GetRecordingRuleID()] ||
- (ri.GetParentRecordingRuleID() &&
- schedAfterStartMap[ri.GetParentRecordingRuleID()]);
- ri.AddHistory(doSchedAfterStart);
- }
+ bool doSchedAfterStart =
+ recStatus != rsTuning &&
+ (recStatus != rsRecording ||
+ schedAfterStartMap[ri.GetRecordingRuleID()] ||
+ (ri.GetParentRecordingRuleID() &&
+ schedAfterStartMap[ri.GetParentRecordingRuleID()]));
+ ri.AddHistory(doSchedAfterStart);
QString msg = (rsRecording == recStatus) ?
QString("Started recording") :
@@ -2649,7 +2667,12 @@ void Scheduler::HandleTuning(
}
else if (tuningTimeout > 0)
{
+ schedLock.unlock();
recStatus = (*tvit)->GetRecordingStatus();
+ schedLock.lock();
+ if (reclist_changed)
+ return;
+
if (rsTuning == recStatus)
{
// If tuning is still taking place this long after we

0 comments on commit ca27332

Please sign in to comment.