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 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 @@ -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))