summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--HISTORY.h7
-rw-r--r--lib/vdrlocks.h31
-rw-r--r--status.c193
-rw-r--r--timer.c23
-rw-r--r--update.c3
-rw-r--r--update.h15
6 files changed, 149 insertions, 123 deletions
diff --git a/HISTORY.h b/HISTORY.h
index 3c84f71..280151c 100644
--- a/HISTORY.h
+++ b/HISTORY.h
@@ -5,8 +5,8 @@
*
*/
-#define _VERSION "1.1.68"
-#define VERSION_DATE "11.06.2017"
+#define _VERSION "1.1.69"
+#define VERSION_DATE "22.06.2017"
#define DB_API 4
@@ -19,6 +19,9 @@
/*
* ------------------------------------
+2017-06-22 version 1.1.69 (horchi)
+ - change: More rework of lock handling
+
2017-06-11: version 1.1.68 (horchi)
- change: Added lock macros for easier handling the vdr versions
diff --git a/lib/vdrlocks.h b/lib/vdrlocks.h
index a3a1f2b..5032f09 100644
--- a/lib/vdrlocks.h
+++ b/lib/vdrlocks.h
@@ -31,12 +31,41 @@
# define GET_TIMERS_WRITE(name) cTimers* name = &Timers;
#endif
-
//***************************************************************************
// Channel List Lock Macros
//***************************************************************************
+#if defined (APIVERSNUM) && (APIVERSNUM >= 20301)
+# define GET_CHANNELS_READ(name) USE_LIST_LOCK_READ(Channels); \
+ const cChannels* name = Channels;
+#else
+# define GET_CHANNELS_READ(name) cChannels* name = &Channels;
+#endif
+
+#if defined (APIVERSNUM) && (APIVERSNUM >= 20301)
+# define GET_CHANNELS_WRITE(name) USE_LIST_LOCK_WRITE(Channels); \
+ cChannels* name = Channels;
+#else
+# define GET_CHANNELS_WRITE(name) cChannels* name = &Channels;
+#endif
+
+//***************************************************************************
+// Recording List Lock Macros
+//***************************************************************************
+
+#if defined (APIVERSNUM) && (APIVERSNUM >= 20301)
+# define GET_RECORDINGS_READ(name) USE_LIST_LOCK_READ(Recordings); \
+ const cRecordings* name = Recordings;
+#else
+# define GET_RECORDINGS_READ(name) cRecordings* name = &Recordings;
+#endif
+#if defined (APIVERSNUM) && (APIVERSNUM >= 20301)
+# define GET_RECORDINGS_WRITE(name) USE_LIST_LOCK_WRITE(Recordings); \
+ cRecordings* name = Recordings;
+#else
+# define GET_RECORDINGS_WRITE(name) cRecordings* name = &Recordings;
+#endif
//***************************************************************************
# endif // VDR_PLUGIN
diff --git a/status.c b/status.c
index 329b852..48b01dd 100644
--- a/status.c
+++ b/status.c
@@ -67,7 +67,7 @@ struct tIndexTs
}
};
-int RecLengthInSecs(const cRecording *pRecording)
+int RecLengthInSecs(const cRecording* pRecording)
{
struct stat buf;
cString fullname = cString::sprintf("%s%s", pRecording->FileName(), IsPesRecording(pRecording) ? LOC_INDEXFILESUFFIX ".vdr" : LOC_INDEXFILESUFFIX);
@@ -108,105 +108,114 @@ void cUpdate::TimerChange(const cTimer* Timer, eTimerChange Change)
}
//***************************************************************************
-// Recording Notification
+// Recording Notification (cStatus::MsgRecording(....))
//***************************************************************************
void cUpdate::Recording(const cDevice* Device, const char* Name, const char* FileName, bool On)
{
- cMutexLock lock(&runningRecMutex);
- const int allowedBreakDuration = 2;
+ RecordingAction action;
// Recording of 'Peter Hase' has 'started' [/srv/vdr/video.00/Peter_Hase/2014-10-08.11.05.18-0.rec]
// Recording of '(null)' has 'stopped' [/srv/vdr/video.00/Peter_Hase/2014-10-08.11.05.18-0.rec]
tell(1, "Recording of '%s' has '%s' [%s]", Name, On ? "started" : "stopped", FileName);
- // at start of recording store event details to recording directory (info.epg2vdr)
+ // schedule this notification to perfrom it in oure context not in the cStatus Interface context
+ // due to the needed list locks!
+
+ action.name = Name;
+ action.fileName = FileName;
+ action.cardIndex = Device->CardIndex();
+ action.on = On;
+ pendingRecordingActions.push(action);
if (On)
pendingNewRecordings.push(FileName);
- // get timers lock
+ recordingStateChangedTrigger = yes;
+ waitCondition.Broadcast(); // wakeup
+}
-#if defined (APIVERSNUM) && (APIVERSNUM >= 20301)
- LOCK_TIMERS_READ;
- const cTimers* timers = Timers;
- // cTimersLock timersLock(false);
- // const cTimers* timers = timersLock.Timers();
-#else
- const cTimers* timers = &Timers;
-#endif
+//***************************************************************************
+// Perform Pending Recording Notification
+// (got by cStatus::MsgRecording(....) above)
+//***************************************************************************
- // recording started ...
+int cUpdate::performRecordingActions()
+{
+ const int allowedBreakDuration = 2;
- if (On && Name)
+ GET_TIMERS_READ(timers); // get timers lock
+ GET_RECORDINGS_READ(recordings); // recordings lock
+
+ while (!pendingNewRecordings.empty())
{
- for (const cTimer* ti = timers->First(); ti; ti = timers->Next(ti))
+ cMutexLock lock(&runningRecMutex);
+ RecordingAction action = pendingRecordingActions.front();
+ pendingRecordingActions.pop();
+
+ if (action.on && action.name.length()) // recording started ...
{
- if (ti->Recording()) // timer nimmt gerade auf
+ for (const cTimer* ti = timers->First(); ti; ti = timers->Next(ti))
{
- cRunningRecording* recording = 0;
+ if (ti->Recording()) // timer nimmt gerade auf
+ {
+ cRunningRecording* recording = 0;
- // check if already known
+ // check if already known
- for (cRunningRecording* rr = runningRecordings.First(); rr; rr = runningRecordings.Next(rr))
- {
- if (rr->timer == ti)
+ for (cRunningRecording* rr = runningRecordings.First(); rr; rr = runningRecordings.Next(rr))
{
- recording = rr;
- break;
+ if (rr->timer == ti)
+ {
+ recording = rr;
+ break;
+ }
}
- }
- if (recording) // already handled -> a resume?!
- {
- tell(1, "Info: Detected resume of '%s' on device %d", Name, Device->CardIndex());
- continue;
- }
+ if (recording) // already handled -> a resume?!
+ {
+ tell(1, "Info: Detected resume of '%s' on device %d", action.name.c_str(), action.cardIndex);
+ continue;
+ }
- int doneid = na;
- contentOfTag(ti, "doneid", doneid);
+ int doneid = na;
+ contentOfTag(ti, "doneid", doneid);
- recording = new cRunningRecording(ti, doneid);
- runningRecordings.Add(recording);
- tell(1, "Info: Recording '%s' with doneid %d added to running list", Name, doneid);
+ recording = new cRunningRecording(ti, doneid);
+ runningRecordings.Add(recording);
+ tell(1, "Info: Recording '%s' with doneid %d added to running list", action.name.c_str(), doneid);
+ }
}
}
- }
-
- // recording stopped ...
- if (!On)
- {
- // loop over running recordings ..
+ // recording stopped ...
- for (cRunningRecording* rr = runningRecordings.First(); rr; rr = runningRecordings.Next(rr))
+ if (!action.on)
{
- const cTimer* pendingTimer = 0;
- int complete;
- double recFraction = 100.0;
- long timerLengthSecs = rr->timer->StopTime() - rr->timer->StartTime();
- bool vpsUsed = rr->timer->HasFlags(tfVps) && rr->timer->Event() && rr->timer->Event()->Vps();
-
- // check if timer still exists
+ // loop over running recordings ..
- for (pendingTimer = timers->First(); pendingTimer; pendingTimer = timers->Next(pendingTimer))
+ for (cRunningRecording* rr = runningRecordings.First(); rr; rr = runningRecordings.Next(rr))
{
- if (pendingTimer == rr->timer)
- break;
- }
+ const cRecording* pRecording = recordings->GetByName(action.fileName.c_str());
+ const cTimer* pendingTimer = 0;
+ int complete;
+ double recFraction = 100.0;
+ long timerLengthSecs = rr->timer->StopTime() - rr->timer->StartTime();
+ bool vpsUsed = rr->timer->HasFlags(tfVps) && rr->timer->Event() && rr->timer->Event()->Vps();
- // still recording :o ?
+ // check if timer still exists
- if (pendingTimer && pendingTimer->Recording())
- continue;
+ for (pendingTimer = timers->First(); pendingTimer; pendingTimer = timers->Next(pendingTimer))
+ {
+ if (pendingTimer == rr->timer)
+ break;
+ }
-#if defined (APIVERSNUM) && (APIVERSNUM >= 20301)
- cStateKey stateKey;
+ // still recording :o ?
- if (const cRecordings* recordings = cRecordings::GetRecordingsRead(stateKey))
- {
- const cRecording* pRecording = recordings->GetByName(FileName);
+ if (pendingTimer && pendingTimer->Recording())
+ continue;
if (pRecording && timerLengthSecs)
{
@@ -214,54 +223,42 @@ void cUpdate::Recording(const cDevice* Device, const char* Name, const char* Fil
recFraction = double(recLen) * 100 / timerLengthSecs;
}
- stateKey.Remove();
- }
-#else
- const cRecording* pRecording = Recordings.GetByName(FileName);
-
- if (pRecording && timerLengthSecs)
- {
- int recLen = RecLengthInSecs(pRecording);
- recFraction = double(recLen) * 100 / timerLengthSecs;
- }
-#endif
-
- // assure timer has reached it's end or at least 90% (vps) / 98% were recorded
+ // assure timer has reached it's end or at least 90% (vps) / 98% were recorded
- complete = recFraction >= (vpsUsed ? 90 : 98);
+ complete = recFraction >= (vpsUsed ? 90 : 98);
- if (complete)
- tell(1, "Info: Finished: '%s'; recorded %d%%; VPS %s",
- rr->timer->File(), (int)round(recFraction), vpsUsed ? "Yes": "No");
- else
- tell(1, "Info: Finished: '%s' (not complete! - recorded only %d%%); VPS %s",
- rr->timer->File(), (int)round(recFraction), vpsUsed ? "Yes": "No");
+ if (complete)
+ tell(1, "Info: Finished: '%s'; recorded %d%%; VPS %s",
+ rr->timer->File(), (int)round(recFraction), vpsUsed ? "Yes": "No");
+ else
+ tell(1, "Info: Finished: '%s' (not complete! - recorded only %d%%); VPS %s",
+ rr->timer->File(), (int)round(recFraction), vpsUsed ? "Yes": "No");
- if (complete)
- rr->lastBreak = 0; // reset break
- else if (!rr->lastBreak)
- rr->lastBreak = time(0); // store first break
+ if (complete)
+ rr->lastBreak = 0; // reset break
+ else if (!rr->lastBreak)
+ rr->lastBreak = time(0); // store first break
- if (!rr->lastBreak || (time(0) - rr->lastBreak) > allowedBreakDuration)
- {
- char* infoTxt;
+ if (!rr->lastBreak || (time(0) - rr->lastBreak) > allowedBreakDuration)
+ {
+ char* infoTxt;
- asprintf(&infoTxt, "Recording '%s' finished - %s complete (%d%%)",
- rr->timer->File(), complete ? "" : "NOT", (int)round(recFraction));
+ asprintf(&infoTxt, "Recording '%s' finished - %s complete (%d%%)",
+ rr->timer->File(), complete ? "" : "NOT", (int)round(recFraction));
- tell(1, "Info: %s", infoTxt);
+ tell(1, "Info: %s", infoTxt);
- rr->finished = yes;
- rr->failed = !complete;
- rr->setInfo(infoTxt);
+ rr->finished = yes;
+ rr->failed = !complete;
+ rr->setInfo(infoTxt);
- free(infoTxt);
+ free(infoTxt);
+ }
}
}
}
- recordingStateChangedTrigger = yes;
- waitCondition.Broadcast(); // wakeup
+ return done;
}
//***************************************************************************
diff --git a/timer.c b/timer.c
index de44862..5faa03f 100644
--- a/timer.c
+++ b/timer.c
@@ -66,27 +66,8 @@ int cUpdate::performTimerJobs()
selectPendingTimerActions->freeResult();
}
- // get timers lock
-
-#if defined (APIVERSNUM) && (APIVERSNUM >= 20301)
- LOCK_TIMERS_WRITE;
- cTimers* timers = Timers;
- // cTimersLock timersLock(true);
- // cTimers* timers = timersLock.Timers();
-#else
- cTimers* timers = &Timers;
-#endif
-
- // get channels lock
-
-#if defined (APIVERSNUM) && (APIVERSNUM >= 20301)
- LOCK_CHANNELS_WRITE;
- const cChannels* channels = Channels;
- // cChannelsLock channelsLock(false);
- // const cChannels* channels = channelsLock.Channels();
-#else
- cChannels* channels = &Channels;
-#endif
+ GET_TIMERS_WRITE(timers); // get timers lock
+ GET_CHANNELS_READ(channels); // get channels lock
// get schedules lock
diff --git a/update.c b/update.c
index d51ca32..48fb523 100644
--- a/update.c
+++ b/update.c
@@ -1224,6 +1224,9 @@ void cUpdate::Action()
if (dbConnected() && recordingStateChangedTrigger)
{
+ if (!pendingRecordingActions.empty())
+ performRecordingActions();
+
if (Epg2VdrConfig.shareInWeb)
recordingChanged(); // update timer state
diff --git a/update.h b/update.h
index 0ea9b86..fe3b796 100644
--- a/update.h
+++ b/update.h
@@ -16,6 +16,7 @@
#include "lib/common.h"
#include "lib/db.h"
#include "lib/epgservice.h"
+#include "lib/vdrlocks.h"
#include "epg2vdr.h"
#include "parameters.h"
@@ -146,6 +147,16 @@ class cUpdate : public cThread, public cStatus, public cParameters
char channelId[100];
};
+ // struct to store a recording action delieverd by the status interface
+
+ struct RecordingAction
+ {
+ std::string name;
+ std::string fileName;
+ int cardIndex;
+ bool on;
+ };
+
// functions
int initDb();
@@ -189,6 +200,7 @@ class cUpdate : public cThread, public cStatus, public cParameters
int cleanupDeletedRecordings(int force = no);
int updateRecordingDirectory(const cRecording* recording);
int updatePendingRecordingInfoFiles(const cRecordings* recordings);
+ int performRecordingActions();
int storeAllRecordingInfoFiles();
int updateRecordingInfoFiles();
@@ -273,7 +285,8 @@ class cUpdate : public cThread, public cStatus, public cParameters
cDbValue* viewMergeSource;
cDbValue* viewLongDescription;
- std::queue<std::string> pendingNewRecordings; // recordings to store details
+ std::queue<std::string> pendingNewRecordings; // recordings to store details (obsolete if pendingRecordingActions implemented finally)
+ std::queue<RecordingAction> pendingRecordingActions; // recordings actions (start/stop)
std::vector<TimerId> deletedTimers;
static const char* auxFields[];