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 /recording.h | |
parent | 8a7bc6a0bbf60cae8b6391a630880aad5cba3363 (diff) | |
download | vdr-3cd5294d8a337ee5cd2ec894c9fbe04ad3a7690d.tar.gz vdr-3cd5294d8a337ee5cd2ec894c9fbe04ad3a7690d.tar.bz2 |
Implemented strict locking of global lists
Diffstat (limited to 'recording.h')
-rw-r--r-- | recording.h | 105 |
1 files changed, 63 insertions, 42 deletions
diff --git a/recording.h b/recording.h index dca5ee3d..cebd2ee0 100644 --- a/recording.h +++ b/recording.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: recording.h 4.2 2015/04/28 09:26:02 kls Exp $ + * $Id: recording.h 4.3 2015/08/29 14:12:14 kls Exp $ */ #ifndef __RECORDING_H @@ -41,7 +41,6 @@ enum eRecordingUsage { }; void RemoveDeletedRecordings(void); -void ClearVanishedRecordings(void); void AssertFreeDiskSpace(int Priority = 0, bool Force = false); ///< The special Priority value -1 means that we shall get rid of any ///< deleted recordings faster than normal (because we're cutting). @@ -129,8 +128,9 @@ public: int Priority(void) const { return priority; } int Lifetime(void) const { return lifetime; } time_t Deleted(void) const { return deleted; } + void SetDeleted(void) { deleted = time(NULL); } virtual int Compare(const cListObject &ListObject) const; - bool IsInPath(const char *Path); + bool IsInPath(const char *Path) const; ///< Returns true if this recording is stored anywhere under the given Path. ///< If Path is NULL or an empty string, the entire video directory is checked. cString Folder(void) const; @@ -140,7 +140,7 @@ public: ///< Returns the base name of this recording (without the ///< video directory and folder). For use in menus etc. const char *Name(void) const { return name; } - ///< Returns the full name of the recording (without the video directory. + ///< Returns the full name of the recording (without the video directory). ///< For use in menus etc. const char *FileName(void) const; ///< Returns the full path name to the recording directory, including the @@ -166,7 +166,7 @@ public: bool IsEdited(void) const; bool IsPesRecording(void) const { return isPesRecording; } bool IsOnVideoDirectoryFileSystem(void) const; - bool HasMarks(void); + bool HasMarks(void) const; ///< Returns true if this recording has any editing marks. bool DeleteMarks(void); ///< Deletes the editing marks from this recording (if any). @@ -216,49 +216,54 @@ public: ///< as in time-shift). }; -class cRecordings : public cList<cRecording>, public cThread { +class cVideoDirectoryScannerThread; + +class cRecordings : public cList<cRecording> { private: + static cRecordings recordings; + static cRecordings deletedRecordings; static char *updateFileName; - bool deleted; - bool initial; - time_t lastUpdate; - int state; - const char *UpdateFileName(void); - void Refresh(bool Foreground = false); - bool ScanVideoDir(const char *DirName, bool Foreground = false, int LinkLevel = 0, int DirLevel = 0); -protected: - virtual void Action(void); + static time_t lastUpdate; + static cVideoDirectoryScannerThread *videoDirectoryScannerThread; + static const char *UpdateFileName(void); public: cRecordings(bool Deleted = false); virtual ~cRecordings(); - bool Load(void) { return Update(true); } - ///< Loads the current list of recordings and returns true if there - ///< is anything in it (for compatibility with older plugins - use - ///< Update(true) instead). - bool Update(bool Wait = false); + static const cRecordings *GetRecordingsRead(cStateKey &StateKey, int TimeoutMs = 0) { return recordings.Lock(StateKey, false, TimeoutMs) ? &recordings : NULL; } + ///< Gets the list of recordings for read access. + ///< See cTimers::GetTimersRead() for details. + static cRecordings *GetRecordingsWrite(cStateKey &StateKey, int TimeoutMs = 0) { return recordings.Lock(StateKey, true, TimeoutMs) ? &recordings : NULL; } + ///< Gets the list of recordings for write access. + ///< See cTimers::GetTimersWrite() for details. + static const cRecordings *GetDeletedRecordingsRead(cStateKey &StateKey, int TimeoutMs = 0) { return deletedRecordings.Lock(StateKey, false, TimeoutMs) ? &deletedRecordings : NULL; } + ///< Gets the list of deleted recordings for read access. + ///< See cTimers::GetTimersRead() for details. + static cRecordings *GetDeletedRecordingsWrite(cStateKey &StateKey, int TimeoutMs = 0) { return deletedRecordings.Lock(StateKey, true, TimeoutMs) ? &deletedRecordings : NULL; } + ///< Gets the list of deleted recordings for write access. + ///< See cTimers::GetTimersWrite() for details. + static void Update(bool Wait = false); ///< Triggers an update of the list of recordings, which will run ///< as a separate thread if Wait is false. If Wait is true, the ///< function returns only after the update has completed. - ///< Returns true if Wait is true and there is anything in the list - ///< of recordings, false otherwise. - void TouchUpdate(void); + static void TouchUpdate(void); ///< Touches the '.update' file in the video directory, so that other ///< instances of VDR that access the same video directory can be triggered ///< to update their recordings list. - bool NeedsUpdate(void); - void ChangeState(void) { state++; } - bool StateChanged(int &State); + ///< This function is 'const', because it doesn't actually modify the list + ///< of recordings. + static bool NeedsUpdate(void); void ResetResume(const char *ResumeFileName = NULL); void ClearSortNames(void); - cRecording *GetByName(const char *FileName); + const cRecording *GetByName(const char *FileName) const; + cRecording *GetByName(const char *FileName) { return const_cast<cRecording *>(static_cast<const cRecordings *>(this)->GetByName(FileName)); } void AddByName(const char *FileName, bool TriggerUpdate = true); void DelByName(const char *FileName); void UpdateByName(const char *FileName); - int TotalFileSizeMB(void); - double MBperMinute(void); + int TotalFileSizeMB(void) const; + double MBperMinute(void) const; ///< Returns the average data rate (in MB/min) of all recordings, or -1 if ///< this value is unknown. - int PathIsInUse(const char *Path); + int PathIsInUse(const char *Path) const; ///< Checks whether any recording in the given Path is currently in use and therefore ///< the whole Path shall not be tampered with. Returns 0 (ruNone) if no recording ///< is in use. @@ -266,7 +271,7 @@ public: ///< If several recordings in the Path are currently in use, the return value will ///< be the combination of all individual recordings' flags. ///< If Path is NULL or an empty string, the entire video directory is checked. - int GetNumRecordingsInPath(const char *Path); + int GetNumRecordingsInPath(const char *Path) const; ///< Returns the total number of recordings in the given Path, including all ///< sub-folders of Path. ///< If Path is NULL or an empty string, the entire video directory is checked. @@ -281,10 +286,19 @@ public: ///< if all recordings have been successfully added to the RecordingsHandler. }; -/// Any access to Recordings that loops through the list of recordings -/// needs to hold a thread lock on this object! -extern cRecordings Recordings; -extern cRecordings DeletedRecordings; +// Provide lock controlled access to the list: + +DEF_LIST_LOCK(Recordings); +DEF_LIST_LOCK2(Recordings, DeletedRecordings); + +// These macros provide a convenient way of locking the global recordings 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_RECORDINGS_READ USE_LIST_LOCK_READ(Recordings) +#define LOCK_RECORDINGS_WRITE USE_LIST_LOCK_WRITE(Recordings) +#define LOCK_DELETEDRECORDINGS_READ USE_LIST_LOCK_READ2(Recordings, DeletedRecordings) +#define LOCK_DELETEDRECORDINGS_WRITE USE_LIST_LOCK_WRITE2(Recordings, DeletedRecordings) class cRecordingsHandlerEntry; @@ -350,7 +364,7 @@ public: bool Save(FILE *f); }; -class cMarks : public cConfig<cMark>, public cMutex { +class cMarks : public cConfig<cMark> { private: cString recordingFileName; cString fileName; @@ -360,9 +374,11 @@ private: time_t lastFileTime; time_t lastChange; public: + cMarks(void): cConfig<cMark>("Marks") {}; static cString MarksFileName(const cRecording *Recording); ///< Returns the marks file name for the given Recording (regardless whether such ///< a file actually exists). + static bool DeleteMarksFile(const cRecording *Recording); bool Load(const char *RecordingFileName, double FramesPerSecond = DEFAULTFRAMESPERSECOND, bool IsPesRecording = false); bool Update(void); bool Save(void); @@ -374,22 +390,27 @@ public: ///< calls to Del(), or any of the functions that return a "cMark *", in case ///< an other thread might modifiy the list while the returned pointer is ///< considered valid. - cMark *Get(int Position); - cMark *GetPrev(int Position); - cMark *GetNext(int Position); - cMark *GetNextBegin(cMark *EndMark = NULL); + const cMark *Get(int Position) const; + const cMark *GetPrev(int Position) const; + const cMark *GetNext(int Position) const; + const cMark *GetNextBegin(const cMark *EndMark = NULL) const; ///< Returns the next "begin" mark after EndMark, skipping any marks at the ///< same position as EndMark. If EndMark is NULL, the first actual "begin" ///< will be returned (if any). - cMark *GetNextEnd(cMark *BeginMark); + const cMark *GetNextEnd(const cMark *BeginMark) const; ///< Returns the next "end" mark after BeginMark, skipping any marks at the ///< same position as BeginMark. - int GetNumSequences(void); + int GetNumSequences(void) const; ///< Returns the actual number of sequences to be cut from the recording. ///< If there is only one actual "begin" mark, and it is positioned at index ///< 0 (the beginning of the recording), and there is no "end" mark, the ///< return value is 0, which means that the result is the same as the original ///< recording. + cMark *Get(int Position) { return const_cast<cMark *>(static_cast<const cMarks *>(this)->Get(Position)); } + cMark *GetPrev(int Position) { return const_cast<cMark *>(static_cast<const cMarks *>(this)->GetPrev(Position)); } + cMark *GetNext(int Position) { return const_cast<cMark *>(static_cast<const cMarks *>(this)->GetNext(Position)); } + cMark *GetNextBegin(const cMark *EndMark = NULL) { return const_cast<cMark *>(static_cast<const cMarks *>(this)->GetNextBegin(EndMark)); } + cMark *GetNextEnd(const cMark *BeginMark) { return const_cast<cMark *>(static_cast<const cMarks *>(this)->GetNextEnd(BeginMark)); } }; #define RUC_BEFORERECORDING "before" |