diff --git a/mythtv/programs/mythbackend/scheduler.cpp b/mythtv/programs/mythbackend/scheduler.cpp
index eed332a..4b75569 100644
--- a/mythtv/programs/mythbackend/scheduler.cpp
+++ b/mythtv/programs/mythbackend/scheduler.cpp
@@ -1806,80 +1806,89 @@ void Scheduler::run(void)
     RecIter   startIter       = reclist.begin();
     QDateTime idleSince       = QDateTime();
     int       maxSleep        = 60000; // maximum sleep time in milliseconds
-    int       schedRunTime    = 30; // max scheduler run time in seconds
+    int       schedRunTime    = 0; // max scheduler run time in seconds
     bool      statuschanged   = false;
+    QDateTime nextStartTime   = MythDate::current().addDays(1);
+    QDateTime nextSleepTime   = MythDate::current().addMSecs(maxSleep);
 
     while (doRun)
     {
-        reclist_changed = false;
+        if (!doRun)
+            break;
+
+        // If something changed, it might have short circuited a pass
+        // through the list or changed the next run times.  Start a
+        // new pass immediately to take care of anything that still
+        // needs attention right now and reset the run times.
+        if (reclist_changed)
+        {
+            nextStartTime = MythDate::current();
+            reclist_changed = false;
+        }
+
+        nextSleepTime = min(nextSleepTime, nextStartTime);
+        nextSleepTime.addMSecs(-nextSleepTime.time().msec());
 
         QDateTime curtime = MythDate::current();
-        int secs_to_next = (startIter != reclist.end()) ?
-            curtime.secsTo((*startIter)->GetRecordingStartTime()) : 60*60;
+        int secs_to_next = max(curtime.secsTo(nextStartTime), 0);
+        int sched_sleep = max(curtime.msecsTo(nextSleepTime), (qint64)0);
+        LOG(VB_GENERAL, LOG_INFO,
+            QString("### s2n: %1 ss: %2)")
+            .arg(secs_to_next).arg(sched_sleep));
 
         // If we're about to start a recording don't do any reschedules...
         // instead sleep for a bit
-        if (secs_to_next < (schedRunTime + 2))
+        if (secs_to_next < schedRunTime + 2)
         {
-            int msecs = CalcTimeToNextHandleRecordingEvent(
-                curtime, startIter, reclist, prerollseconds, maxSleep);
             LOG(VB_SCHEDULE, LOG_INFO,
                 QString("sleeping for %1 ms (s2n: %2 sr: %3)")
-                    .arg(msecs).arg(secs_to_next).arg(schedRunTime));
-            if (msecs < 100)
-                (void) ::usleep(msecs * 1000);
+                .arg(sched_sleep).arg(secs_to_next).arg(schedRunTime));
+            if (sched_sleep < 100)
+                (void) ::usleep(sched_sleep);
             else
-                reschedWait.wait(&schedLock, msecs);
+            {
+                if (reschedWait.wait(&schedLock, sched_sleep))
+                    continue;
+            }
+        }
+        else if (!HaveQueuedRequests())
+        {
+            LOG(VB_SCHEDULE, LOG_INFO,
+                QString("sleeping for %1 ms (interuptable)").arg(sched_sleep));
+            if (reschedWait.wait(&schedLock, sched_sleep))
+                continue;
         }
         else
         {
-            if (!HaveQueuedRequests())
-            {
-                int sched_sleep = (secs_to_next - schedRunTime - 1) * 1000;
-                sched_sleep = min(sched_sleep, maxSleep);
-                if (secs_to_next < prerollseconds + (maxSleep/1000))
-                    sched_sleep = min(sched_sleep, 5000);
-                LOG(VB_SCHEDULE, LOG_INFO,
-                    QString("sleeping for %1 ms (interuptable)")
-                        .arg(sched_sleep));
-                reschedWait.wait(&schedLock, sched_sleep);
-                if (!doRun)
-                    break;
-            }
+            // The master backend is a long lived program, so
+            // we reload some key settings on each reschedule.
+            prerollseconds  =
+                gCoreContext->GetNumSetting("RecordPreRoll", 0);
+            wakeThreshold =
+                gCoreContext->GetNumSetting("WakeUpThreshold", 300);
+            idleTimeoutSecs =
+                gCoreContext->GetNumSetting("idleTimeoutSecs", 0);
+            idleWaitForRecordingTime =
+                gCoreContext->GetNumSetting("idleWaitForRecordingTime", 15);
+            tuningTimeout =
+                gCoreContext->GetNumSetting("tuningTimeout", 180);
 
             QTime t; t.start();
-            if (HaveQueuedRequests() && HandleReschedule())
+
+            if (HandleReschedule())
             {
                 statuschanged = true;
                 startIter = reclist.begin();
-
-                // The master backend is a long lived program, so
-                // we reload some key settings on each reschedule.
-                prerollseconds  =
-                    gCoreContext->GetNumSetting("RecordPreRoll", 0);
-                wakeThreshold =
-                    gCoreContext->GetNumSetting("WakeUpThreshold", 300);
-                idleTimeoutSecs =
-                    gCoreContext->GetNumSetting("idleTimeoutSecs", 0);
-                idleWaitForRecordingTime =
-                    gCoreContext->GetNumSetting("idleWaitForRecordingTime", 15);
-                tuningTimeout =
-                    gCoreContext->GetNumSetting("tuningTimeout", 180);
             }
 
-            int e = t.elapsed();
-            if (e > 0)
-            {
-                schedRunTime = (firstRun) ? 0 : schedRunTime;
-                schedRunTime =
-                    max((int)(((e + 999) / 1000) * 1.5f), schedRunTime);
-            }
+            schedRunTime = max((int)(((t.elapsed() + 999) / 1000) * 1.5f),
+                               schedRunTime);
 
             if (firstRun)
             {
+                firstRun = false;
                 blockShutdown &= HandleRunSchedulerStartup(
                     prerollseconds, idleWaitForRecordingTime);
-                firstRun = false;
 
                 // HandleRunSchedulerStartup releases the schedLock so the
                 // reclist may have changed. If it has go to top of loop
@@ -1902,6 +1911,9 @@ void Scheduler::run(void)
             }
         }
 
+        nextStartTime = MythDate::current().addDays(1);
+        nextSleepTime = MythDate::current().addMSecs(maxSleep);
+
         // Skip past recordings that are already history
         // (i.e. AddHistory() has been called setting oldrecstatus)
         for ( ; startIter != reclist.end(); ++startIter)
@@ -1920,7 +1932,8 @@ void Scheduler::run(void)
         for (RecIter it = startIter; it != reclist.end() && !done; ++it)
         {
             done = HandleRecording(
-                **it, statuschanged, prerollseconds, tuningTimeout);
+                **it, statuschanged, nextStartTime, nextSleepTime,
+                prerollseconds, tuningTimeout);
         }
 
         // HandleRecording() and HandleTuning() temporarily unlocks
@@ -1962,73 +1975,6 @@ void Scheduler::run(void)
     RunEpilog();
 }
 
-int Scheduler::CalcTimeToNextHandleRecordingEvent(
-    const QDateTime &curtime,
-    RecConstIter startIter, const RecList &reclist,
-    int prerollseconds, int max_sleep /*ms*/)
-{
-    if (startIter == reclist.end())
-        return max_sleep;
-
-    int msecs = max_sleep;
-    for (RecConstIter i = startIter; i != reclist.end() && (msecs > 0); ++i)
-    {
-        // Check on recordings that we've told to start, but have
-        // not yet started every second or so.
-        if ((*i)->GetRecordingStatus() == rsTuning)
-        {
-            msecs = min(msecs, 1000);
-            continue;
-        }
-
-        // These recordings have already been handled..
-        if ((*i)->GetRecordingStatus() == (*i)->oldrecstatus)
-            continue;
-
-        int secs_to_next = curtime.secsTo((*i)->GetRecordingStartTime());
-
-        if ((*i)->GetRecordingStatus() == rsWillRecord &&
-            !recPendingList.contains((*i)->MakeUniqueSchedulerKey()))
-            secs_to_next -= 30;
-
-        if (secs_to_next < 0)
-        {
-            msecs = 0;
-            break;
-        }
-
-        // This is what normally breaks us out of the loop...
-        if (secs_to_next > max_sleep)
-        {
-            msecs = min(msecs, max_sleep);
-            break;
-        }
-
-        if (secs_to_next > 31)
-        {
-            msecs = min(msecs, 30 * 1000);
-            continue;
-        }
-
-        if ((secs_to_next-1) * 1000 > msecs)
-            continue;
-
-        if (secs_to_next < 15)
-        {
-            QTime st = (*i)->GetRecordingStartTime().time();
-            int tmp = curtime.time().msecsTo(st);
-            tmp = (tmp < 0) ? tmp + 86400000 : tmp;
-            msecs = (tmp > 15*1000) ? 0 : min(msecs, tmp);
-        }
-        else
-        {
-            msecs = min(msecs, (secs_to_next-1) * 1000);
-        }
-    }
-
-    return min(msecs, max_sleep);
-}
-
 void Scheduler::ResetDuplicates(uint recordid, uint findid,
                                 const QString &title, const QString &subtitle,
                                 const QString &descrip,
@@ -2132,7 +2078,7 @@ bool Scheduler::HandleReschedule(void)
         if (request.size() < 1 || tokens.size() < 1)
         {
             LOG(VB_GENERAL, LOG_ERR, "Empty Reschedule request received");
-            return false;
+            continue;
         }
 
         LOG(VB_GENERAL, LOG_INFO, QString("Reschedule requested for %1")
@@ -2438,20 +2384,23 @@ void Scheduler::HandleWakeSlave(RecordingInfo &ri, int prerollseconds)
 
 bool Scheduler::HandleRecording(
     RecordingInfo &ri, bool &statuschanged,
+    QDateTime &nextStartTime, QDateTime &nextSleepTime,
     int prerollseconds, int tuningTimeout)
 {
     if (ri.GetRecordingStatus() == rsTuning)
     {
-        HandleTuning(ri, statuschanged, tuningTimeout);
+        HandleTuning(ri, statuschanged, nextSleepTime, tuningTimeout);
         return reclist_changed;
     }
 
     if (ri.GetRecordingStatus() != rsWillRecord)
     {
-        if (ri.GetRecordingStatus() != ri.oldrecstatus &&
-            ri.GetRecordingStartTime() <= MythDate::current())
+        if (ri.GetRecordingStatus() != ri.oldrecstatus)
         {
-            ri.AddHistory(false);
+            if (ri.GetRecordingStartTime() <= MythDate::current())
+                ri.AddHistory(false);
+            else
+                nextSleepTime = min(nextSleepTime, ri.GetRecordingStartTime());
         }
         return false;
     }
@@ -2463,20 +2412,30 @@ bool Scheduler::HandleRecording(
 
     // This check needs to be shorter than the related one in
     // SchedLiveTV().
-    if (secsleft - prerollseconds < 60)
+    if (secsleft - prerollseconds > 60)
     {
-        if (!recPendingList.contains(schedid))
-        {
-            recPendingList[schedid] = false;
-            // If we haven't rescheduled in a while, do so now to
-            // accomodate LiveTV.
-            if (schedTime.secsTo(curtime) > 30)
-                EnqueuePlace("PrepareToRecord");
-        }
+        nextStartTime = min(nextStartTime, ri.GetRecordingStartTime());
+        nextSleepTime = min(nextSleepTime, curtime
+                           .addSecs(secsleft - prerollseconds - 60));
+        return true;
+    }
+
+    if (!recPendingList.contains(schedid))
+    {
+        recPendingList[schedid] = false;
+        // If we haven't rescheduled in a while, do so now to
+        // accomodate LiveTV.
+        if (schedTime.secsTo(curtime) > 30)
+            EnqueuePlace("PrepareToRecord");
     }
 
     if (secsleft - prerollseconds > 35)
-        return true;
+    {
+        nextStartTime = min(nextStartTime, ri.GetRecordingStartTime());
+        nextSleepTime = min(nextSleepTime, curtime
+                           .addSecs(secsleft - prerollseconds - 35));
+        return false;
+    }
 
     QMap<int, EncoderLink*>::iterator tvit = m_tvList->find(ri.GetCardID());
     if (tvit == m_tvList->end())
@@ -2515,26 +2474,28 @@ bool Scheduler::HandleRecording(
     // changes.
     RecordingInfo tempri(ri);
 
-    schedLock.unlock();
-    bool isBusyRecording = IsBusyRecording(&tempri);
-    schedLock.lock();
-    if (reclist_changed)
-        return reclist_changed;
-
-    if (prerollseconds > 0 && !isBusyRecording)
+    // Try to use preroll.  If we can't right now, try again in a
+    // little while in case the recorder frees up.
+    if (prerollseconds > 0)
     {
-        // Will use pre-roll settings only if no other
-        // program is currently being recorded
-        secsleft -= prerollseconds;
-    }
+        schedLock.unlock();
+        bool isBusyRecording = IsBusyRecording(&tempri);
+        schedLock.lock();
+        if (reclist_changed)
+            return reclist_changed;
 
-#if 0
-    LOG(VB_GENERAL, LOG_DEBUG, QString("%1 seconds until %2").
-            .arg(secsleft) .arg(ri.GetTitle()));
-#endif
+        if (isBusyRecording)
+            nextSleepTime = min(nextSleepTime, curtime.addSecs(5));
+        else
+            secsleft -= prerollseconds;
+    }
 
     if (secsleft > 30)
+    {
+        nextStartTime = min(nextStartTime, ri.GetRecordingStartTime());
+        nextSleepTime = min(nextSleepTime, curtime.addSecs(secsleft - 30));
         return false;
+    }
 
     if (nexttv->IsWaking())
     {
@@ -2568,6 +2529,8 @@ bool Scheduler::HandleRecording(
             EnqueuePlace("SlaveNotAwake");
         }
 
+        nextStartTime = min(nextStartTime, ri.GetRecordingStartTime());
+        nextSleepTime = min(nextSleepTime, curtime.addSecs(1));
         return false;
     }
 
@@ -2598,7 +2561,11 @@ bool Scheduler::HandleRecording(
     }
 
     if (secsleft > 0)
+    {
+        nextStartTime = min(nextStartTime, ri.GetRecordingStartTime());
+        nextSleepTime = min(nextSleepTime, curtime.addSecs(secsleft));
         return false;
+    }
 
     QDateTime recstartts = MythDate::current(true).addSecs(30);
     recstartts = QDateTime(
@@ -2622,6 +2589,9 @@ bool Scheduler::HandleRecording(
             recStatus = nexttv->StartRecording(&tempri);
             schedLock.lock();
 
+            if (recStatus == rsTuning)
+                nextSleepTime = min(nextSleepTime, curtime.addSecs(1));
+
             // activate auto expirer
             if (m_expirer)
                 m_expirer->Update(ri.GetCardID(), fsID, true);
@@ -2672,7 +2642,8 @@ void Scheduler::HandleRecordingStatusChange(
 }
 
 void Scheduler::HandleTuning(
-    RecordingInfo &ri, bool &statuschanged, int tuningTimeout)
+    RecordingInfo &ri, bool &statuschanged, QDateTime &nextSleepTime,
+    int tuningTimeout)
 {
     if (rsTuning != ri.GetRecordingStatus())
         return;
@@ -2709,6 +2680,10 @@ void Scheduler::HandleTuning(
                             "%1 seconds, has been exceeded.")
                     .arg(tuningTimeout));
             }
+            else
+            {
+                nextSleepTime = min(nextSleepTime, curtime.addSecs(1));
+            }
         }
     }
 
diff --git a/mythtv/programs/mythbackend/scheduler.h b/mythtv/programs/mythbackend/scheduler.h
index fedab8f..be4e9a4 100644
--- a/mythtv/programs/mythbackend/scheduler.h
+++ b/mythtv/programs/mythbackend/scheduler.h
@@ -159,10 +159,6 @@ class Scheduler : public MThread, public MythScheduler
                          const RecList &reclist);
     void FillDirectoryInfoCache(bool force = false);
 
-    int CalcTimeToNextHandleRecordingEvent(
-        const QDateTime &curtime,
-        RecConstIter startIter, const RecList &reclist,
-        int prerollseconds, int max_sleep /*ms*/);
     void OldRecordedFixups(void);
     void ResetDuplicates(uint recordid, uint findid, const QString &title,
                          const QString &subtitle, const QString &descrip,
@@ -171,11 +167,11 @@ class Scheduler : public MThread, public MythScheduler
     bool HandleRunSchedulerStartup(
         int prerollseconds, int idleWaitForRecordingTime);
     void HandleWakeSlave(RecordingInfo &ri, int prerollseconds);
-    bool HandleRecording(
-        RecordingInfo &ri, bool &statuschanged,
-        int prerollseconds, int tuningTimeout);
-    void HandleTuning(
-        RecordingInfo &ri, bool &statuschanged, int tuningTimeout);
+    bool HandleRecording(RecordingInfo &ri, bool &statuschanged,
+                         QDateTime &nextStartTime, QDateTime &nextSleepTime,
+                         int prerollseconds, int tuningTimeout);
+    void HandleTuning(RecordingInfo &ri, bool &statuschanged,
+                      QDateTime &nextSleepTime, int tuningTimeout);
     void HandleRecordingStatusChange(
         RecordingInfo &ri, RecStatusTypes recStatus, const QString &details);
     void HandleIdleShutdown(
