mirror of
https://github.com/vdr-projects/vdr.git
synced 2025-12-26 23:06:44 +01:00
Implemented strict locking of global lists
This commit is contained in:
105
recording.h
105
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"
|
||||
|
||||
Reference in New Issue
Block a user