From 1f9832b44990621e8ad2ec493d3f1b15132b19cc Mon Sep 17 00:00:00 2001
From: Klaus Schmidinger <vdr@tvdr.de>
Date: Sun, 4 Mar 2018 14:15:07 +0100
Subject: Assigning events to timers no longer triggers sending a POLL to all
 peer VDRs

---
 HISTORY  |  1 +
 svdrp.c  | 21 ++++++++++-----------
 svdrp.h  |  7 ++++++-
 thread.c |  3 +--
 tools.h  |  7 ++++++-
 vdr.c    | 33 ++++++++++++++++++---------------
 6 files changed, 42 insertions(+), 30 deletions(-)

diff --git a/HISTORY b/HISTORY
index 869fd049..b11775e5 100644
--- a/HISTORY
+++ b/HISTORY
@@ -9295,3 +9295,4 @@ Video Disk Recorder Revision History
   in tools.c.
 - Modified cStateLock's SetExplicitModify() and IncState() (changed to SetModified()) to
   allow for the introduction of syncing a separate cStateKey to a cStateLock.
+- Assigning events to timers no longer triggers sending a POLL to all peer VDRs.
diff --git a/svdrp.c b/svdrp.c
index b85e13ba..32f9f882 100644
--- a/svdrp.c
+++ b/svdrp.c
@@ -10,7 +10,7 @@
  * and interact with the Video Disk Recorder - or write a full featured
  * graphical interface that sits on top of an SVDRP connection.
  *
- * $Id: svdrp.c 4.32 2018/03/01 14:45:57 kls Exp $
+ * $Id: svdrp.c 4.33 2018/03/04 14:15:07 kls Exp $
  */
 
 #include "svdrp.h"
@@ -37,7 +37,6 @@
 #include "recording.h"
 #include "remote.h"
 #include "skins.h"
-#include "thread.h"
 #include "timers.h"
 #include "videodir.h"
 
@@ -568,12 +567,13 @@ cSVDRPServerParams::cSVDRPServerParams(const char *Params)
 
 // --- cSVDRPClientHandler ---------------------------------------------------
 
+cStateKey StateKeySVDRPRemoteTimersPoll(true);
+
 class cSVDRPClientHandler : public cThread {
 private:
   cMutex mutex;
   int tcpPort;
   cSocket udpSocket;
-  cStateKey timersStateKey;
   cVector<cSVDRPClient *> clientConnections;
   void SendDiscover(void);
   void HandleClientConnection(void);
@@ -597,7 +597,6 @@ static cSVDRPClientHandler *SVDRPClientHandler = NULL;
 cSVDRPClientHandler::cSVDRPClientHandler(int TcpPort, int UdpPort)
 :cThread("SVDRP client handler", true)
 ,udpSocket(UdpPort, false)
-,timersStateKey(true)
 {
   tcpPort = TcpPort;
 }
@@ -627,11 +626,11 @@ void cSVDRPClientHandler::SendDiscover(void)
 void cSVDRPClientHandler::ProcessConnections(void)
 {
   cString PollTimersCmd;
-  if (cTimers::GetTimersRead(timersStateKey, 100)) {
+  if (cTimers::GetTimersRead(StateKeySVDRPRemoteTimersPoll, 100)) {
      PollTimersCmd = cString::sprintf("POLL %s TIMERS", Setup.SVDRPHostName);
-     timersStateKey.Remove();
+     StateKeySVDRPRemoteTimersPoll.Remove();
      }
-  else if (timersStateKey.TimedOut())
+  else if (StateKeySVDRPRemoteTimersPoll.TimedOut())
      return; // try again next time
   for (int i = 0; i < clientConnections.Size(); i++) {
       cSVDRPClient *Client = clientConnections[i];
@@ -639,9 +638,9 @@ void cSVDRPClientHandler::ProcessConnections(void)
          if (Client->HasFetchFlag(sffTimers)) {
             cStringList RemoteTimers;
             if (Client->GetRemoteTimers(RemoteTimers)) {
-               if (cTimers *Timers = cTimers::GetTimersWrite(timersStateKey, 100)) {
+               if (cTimers *Timers = cTimers::GetTimersWrite(StateKeySVDRPRemoteTimersPoll, 100)) {
                   bool TimersModified = Timers->StoreRemoteTimers(Client->ServerName(), &RemoteTimers);
-                  timersStateKey.Remove(TimersModified);
+                  StateKeySVDRPRemoteTimersPoll.Remove(TimersModified);
                   }
                else
                   Client->SetFetchFlag(sffTimers); // try again next time
@@ -653,9 +652,9 @@ void cSVDRPClientHandler::ProcessConnections(void)
             }
          }
       else {
-         cTimers *Timers = cTimers::GetTimersWrite(timersStateKey);
+         cTimers *Timers = cTimers::GetTimersWrite(StateKeySVDRPRemoteTimersPoll);
          bool TimersModified = Timers->StoreRemoteTimers(Client->ServerName(), NULL);
-         timersStateKey.Remove(TimersModified);
+         StateKeySVDRPRemoteTimersPoll.Remove(TimersModified);
          delete Client;
          clientConnections.Remove(i);
          i--;
diff --git a/svdrp.h b/svdrp.h
index 6973ddd0..167209c4 100644
--- a/svdrp.h
+++ b/svdrp.h
@@ -4,12 +4,13 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: svdrp.h 4.9 2018/02/25 13:38:59 kls Exp $
+ * $Id: svdrp.h 4.10 2018/03/04 12:26:17 kls Exp $
  */
 
 #ifndef __SVDRP_H
 #define __SVDRP_H
 
+#include "thread.h"
 #include "tools.h"
 
 enum eSvdrpPeerModes {
@@ -23,6 +24,10 @@ enum eSvdrpFetchFlags {
   sffTimers = 0b0001,
   };
 
+extern cStateKey StateKeySVDRPRemoteTimersPoll;
+     ///< Controls whether a change to the local list of timers needs to result in
+     ///< sending a POLL to the remote clients.
+
 void SetSVDRPPorts(int TcpPort, int UdpPort);
 void SetSVDRPGrabImageDir(const char *GrabImageDir);
 void StartSVDRPHandler(void);
diff --git a/thread.c b/thread.c
index d2640378..0bc12226 100644
--- a/thread.c
+++ b/thread.c
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: thread.c 4.12 2018/03/04 11:23:09 kls Exp $
+ * $Id: thread.c 4.13 2018/03/04 13:17:04 kls Exp $
  */
 
 #include "thread.h"
@@ -877,7 +877,6 @@ bool cStateKey::StateChanged(void)
      return state != stateLock->state;
   else
      return true;
-  return false;
 }
 
 // --- cIoThrottle -----------------------------------------------------------
diff --git a/tools.h b/tools.h
index d65847dc..614130d0 100644
--- a/tools.h
+++ b/tools.h
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: tools.h 4.15 2018/02/28 10:13:40 kls Exp $
+ * $Id: tools.h 4.16 2018/03/04 14:06:36 kls Exp $
  */
 
 #ifndef __TOOLS_H
@@ -559,6 +559,11 @@ public:
        ///< Contains() function to check whether an object you are holding a pointer
        ///< to is still in the list. Note that the garbage collector is purged when
        ///< the usual housekeeping is done.
+  void SetSyncStateKey(cStateKey &StateKey) { stateLock.SetSyncStateKey(StateKey); }
+       ///< When making changes to this list (while holding a write lock) that shall
+       ///< not affect some other code that reacts to such changes, this function can
+       ///< be called with the StateKey used by that other code.
+       ///< See cStateLock::SetSyncStateKey() for details.
   void SetUseGarbageCollector(void) { useGarbageCollector = true; }
   void SetExplicitModify(void);
        ///< If you have obtained a write lock on this list, and you don't want it to
diff --git a/vdr.c b/vdr.c
index 54207ce1..f9e5bb8f 100644
--- a/vdr.c
+++ b/vdr.c
@@ -22,7 +22,7 @@
  *
  * The project's page is at http://www.tvdr.de
  *
- * $Id: vdr.c 4.23 2018/02/25 13:45:24 kls Exp $
+ * $Id: vdr.c 4.24 2018/03/04 14:00:29 kls Exp $
  */
 
 #include <getopt.h>
@@ -1078,25 +1078,28 @@ int main(int argc, char *argv[])
            PreviousChannel[PreviousChannelIndex ^= 1] = LastChannel;
         {
           // Timers and Recordings:
-          bool TimersModified = false;
-          static cStateKey TimersStateKey(true);
-          if (cTimers::GetTimersRead(TimersStateKey))
-             TimersStateKey.Remove();
+          static cStateKey TimersStateKey;
           cTimers *Timers = cTimers::GetTimersWrite(TimersStateKey);
-          // Assign events to timers:
-          static cStateKey SchedulesStateKey;
-          if (const cSchedules *Schedules = cSchedules::GetSchedulesRead(SchedulesStateKey))
-             TimersModified |= Timers->SetEvents(Schedules);
+          {
+            // Assign events to timers:
+            static cStateKey SchedulesStateKey;
+            if (TimersStateKey.StateChanged())
+               SchedulesStateKey.Reset(); // we assign events if either the Timers or the Schedules have changed
+            bool TimersModified = false;
+            if (const cSchedules *Schedules = cSchedules::GetSchedulesRead(SchedulesStateKey)) {
+               Timers->SetSyncStateKey(StateKeySVDRPRemoteTimersPoll);
+               if (Timers->SetEvents(Schedules))
+                  TimersModified = true;
+               SchedulesStateKey.Remove();
+               }
+            TimersStateKey.Remove(TimersModified); // we need to remove the key here, so that syncing StateKeySVDRPRemoteTimersPoll takes effect!
+          }
           // Must do all following calls with the exact same time!
           // Process ongoing recordings:
+          Timers = cTimers::GetTimersWrite(TimersStateKey);
+          bool TimersModified = false;
           if (cRecordControls::Process(Timers, Now))
              TimersModified = true;
-          // Must keep the lock on the schedules until after processing the record
-          // controls, in order to avoid short interrupts in case the current event
-          // is replaced by a new one (which some broadcasters do, instead of just
-          // modifying the current event's data):
-          if (SchedulesStateKey.InLock())
-             SchedulesStateKey.Remove();
           // Start new recordings:
           if (cTimer *Timer = Timers->GetMatch(Now)) {
              if (!cRecordControls::Start(Timers, Timer))
-- 
cgit v1.2.3