diff options
author | Klaus Schmidinger <vdr@tvdr.de> | 2015-09-01 11:14:27 +0200 |
---|---|---|
committer | Klaus Schmidinger <vdr@tvdr.de> | 2015-09-01 11:14:27 +0200 |
commit | 3cd5294d8a337ee5cd2ec894c9fbe04ad3a7690d (patch) | |
tree | da57ce74189de9bfb27e1a747063c37cd62de501 /epg.h | |
parent | 8a7bc6a0bbf60cae8b6391a630880aad5cba3363 (diff) | |
download | vdr-3cd5294d8a337ee5cd2ec894c9fbe04ad3a7690d.tar.gz vdr-3cd5294d8a337ee5cd2ec894c9fbe04ad3a7690d.tar.bz2 |
Implemented strict locking of global lists
Diffstat (limited to 'epg.h')
-rw-r--r-- | epg.h | 72 |
1 files changed, 41 insertions, 31 deletions
@@ -7,7 +7,7 @@ * Original version (as used in VDR before 1.3.0) written by * Robert Schneider <Robert.Schneider@web.de> and Rolf Hakenes <hakenes@hippomi.de>. * - * $Id: epg.h 3.1 2013/08/23 10:50:05 kls Exp $ + * $Id: epg.h 4.1 2015/08/09 11:25:04 kls Exp $ */ #ifndef __EPG_H @@ -66,13 +66,15 @@ public: class cSchedule; -typedef u_int32_t tEventID; +typedef u_int16_t tEventID; class cEvent : public cListObject { friend class cSchedule; private: + static cMutex numTimersMutex; // Protects numTimers, because it might be accessed from parallel read locks // The sequence of these parameters is optimized for minimal memory waste! cSchedule *schedule; // The Schedule this event belongs to + mutable u_int16_t numTimers;// The number of timers that use this event tEventID eventID; // Event ID of this event uchar tableID; // Table ID this event came from uchar version; // Version number of section this event came from @@ -109,7 +111,9 @@ public: time_t Vps(void) const { return vps; } time_t Seen(void) const { return seen; } bool SeenWithin(int Seconds) const { return time(NULL) - seen < Seconds; } - bool HasTimer(void) const; + void IncNumTimers(void) const; + void DecNumTimers(void) const; + bool HasTimer(void) const { return numTimers > 0; } bool IsRunning(bool OrAboutToStart = false) const; static const char *ContentToString(uchar Content); cString GetParentalRatingString(void) const; @@ -120,7 +124,7 @@ public: void SetEventID(tEventID EventID); void SetTableID(uchar TableID); void SetVersion(uchar Version); - void SetRunningStatus(int RunningStatus, cChannel *Channel = NULL); + void SetRunningStatus(int RunningStatus, const cChannel *Channel = NULL); void SetTitle(const char *Title); void SetShortText(const char *ShortText); void SetDescription(const char *Description); @@ -142,28 +146,33 @@ class cSchedules; class cSchedule : public cListObject { private: + static cMutex numTimersMutex; // Protects numTimers, because it might be accessed from parallel read locks tChannelID channelID; cList<cEvent> events; cHash<cEvent> eventsHashID; cHash<cEvent> eventsHashStartTime; + mutable u_int16_t numTimers;// The number of timers that use this schedule bool hasRunning; - time_t modified; + int modified; time_t presentSeen; public: cSchedule(tChannelID ChannelID); tChannelID ChannelID(void) const { return channelID; } - time_t Modified(void) const { return modified; } + bool Modified(int &State) const { bool Result = State != modified; State = modified; return Result; } time_t PresentSeen(void) const { return presentSeen; } bool PresentSeenWithin(int Seconds) const { return time(NULL) - presentSeen < Seconds; } - void SetModified(void) { modified = time(NULL); } + void SetModified(void) { modified++; } void SetPresentSeen(void) { presentSeen = time(NULL); } - void SetRunningStatus(cEvent *Event, int RunningStatus, cChannel *Channel = NULL); + void SetRunningStatus(cEvent *Event, int RunningStatus, const cChannel *Channel = NULL); void ClrRunningStatus(cChannel *Channel = NULL); void ResetVersions(void); void Sort(void); void DropOutdated(time_t SegmentStart, time_t SegmentEnd, uchar TableID, uchar Version); void Cleanup(time_t Time); void Cleanup(void); + void IncNumTimers(void) const; + void DecNumTimers(void) const; + bool HasTimer(void) const { return numTimers > 0; } cEvent *AddEvent(cEvent *Event); void DelEvent(cEvent *Event); void HashEvent(cEvent *Event); @@ -177,35 +186,23 @@ public: static bool Read(FILE *f, cSchedules *Schedules); }; -class cSchedulesLock { -private: - bool locked; -public: - cSchedulesLock(bool WriteLock = false, int TimeoutMs = 0); - ~cSchedulesLock(); - bool Locked(void) { return locked; } - }; - class cSchedules : public cList<cSchedule> { friend class cSchedule; - friend class cSchedulesLock; private: - cRwLock rwlock; static cSchedules schedules; static char *epgDataFileName; static time_t lastDump; - static time_t modified; public: + cSchedules(void); + static const cSchedules *GetSchedulesRead(cStateKey &StateKey, int TimeoutMs = 0); + ///< Gets the list of schedules for read access. + ///< See cTimers::GetTimersRead() for details. + static cSchedules *GetSchedulesWrite(cStateKey &StateKey, int TimeoutMs = 0); + ///< Gets the list of schedules for write access. + ///< See cTimers::GetTimersWrite() for details. static void SetEpgDataFileName(const char *FileName); - static const cSchedules *Schedules(cSchedulesLock &SchedulesLock); - ///< Caller must provide a cSchedulesLock which has to survive the entire - ///< time the returned cSchedules is accessed. Once the cSchedules is no - ///< longer used, the cSchedulesLock must be destroyed. - static time_t Modified(void) { return modified; } - static void SetModified(cSchedule *Schedule); static void Cleanup(bool Force = false); static void ResetVersions(void); - static bool ClearAll(void); static bool Dump(FILE *f = NULL, const char *Prefix = "", eDumpMode DumpMode = dmAll, time_t AtTime = 0); static bool Read(FILE *f = NULL); cSchedule *AddSchedule(tChannelID ChannelID); @@ -213,6 +210,17 @@ public: const cSchedule *GetSchedule(const cChannel *Channel, bool AddIfMissing = false) const; }; +// Provide lock controlled access to the list: + +DEF_LIST_LOCK(Schedules); + +// These macros provide a convenient way of locking the global schedules list +// and making sure the lock is released as soon as the current scope is left +// (note that these macros wait forever to obtain the lock!): + +#define LOCK_SCHEDULES_READ USE_LIST_LOCK_READ(Schedules); +#define LOCK_SCHEDULES_WRITE USE_LIST_LOCK_WRITE(Schedules); + class cEpgDataReader : public cThread { public: cEpgDataReader(void); @@ -273,12 +281,14 @@ public: virtual bool DropOutdated(cSchedule *Schedule, time_t SegmentStart, time_t SegmentEnd, uchar TableID, uchar Version) { return false; } ///< Takes a look at all EPG events between SegmentStart and SegmentEnd and ///< drops outdated events. - virtual bool BeginSegmentTransfer(const cChannel *Channel, bool OnlyRunningStatus) { return false; } + virtual bool BeginSegmentTransfer(const cChannel *Channel, bool Dummy) { return false; } // TODO remove obsolete Dummy ///< Called directly after IgnoreChannel() before any other handler method is called. ///< Designed to give handlers the possibility to prepare a database transaction. - virtual bool EndSegmentTransfer(bool Modified, bool OnlyRunningStatus) { return false; } + ///< Dummy is for backward compatibility and may be removed in a future version. + virtual bool EndSegmentTransfer(bool Modified, bool Dummy) { return false; } // TODO remove obsolete Dummy ///< Called after the segment data has been processed. ///< At this point handlers should close/commit/rollback any pending database transactions. + ///< Dummy is for backward compatibility and may be removed in a future version. }; class cEpgHandlers : public cList<cEpgHandler> { @@ -301,8 +311,8 @@ public: void HandleEvent(cEvent *Event); void SortSchedule(cSchedule *Schedule); void DropOutdated(cSchedule *Schedule, time_t SegmentStart, time_t SegmentEnd, uchar TableID, uchar Version); - void BeginSegmentTransfer(const cChannel *Channel, bool OnlyRunningStatus); - void EndSegmentTransfer(bool Modified, bool OnlyRunningStatus); + void BeginSegmentTransfer(const cChannel *Channel); + void EndSegmentTransfer(bool Modified); }; extern cEpgHandlers EpgHandlers; |