diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 9a07ecce..07cb746a 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -2627,6 +2627,7 @@ J for making cEpgHandlers::BeginSegmentTransfer() boolean for suggesting to change tEventID back to u_int32_t for adding the 'aux' member to cEvent + for reporting a possible deadlock when quickly zapping through encrypted channels Peter Pinnau for reporting that 'uint32_t' requires including stdint.h in font.h on some systems diff --git a/HISTORY b/HISTORY index 16d77b9b..0b412acb 100644 --- a/HISTORY +++ b/HISTORY @@ -9162,7 +9162,7 @@ Video Disk Recorder Revision History a subdirectory. - SVDRP peering can now be limited to the default SVDRP host (see MANUAL for details). -2018-01-17: Version 2.3.9 +2018-01-28: Version 2.3.9 - Updated the Italian OSD texts (thanks to Diego Pierotto). - Updated the Finnish OSD texts (thanks to Rolf Ahrenberg). @@ -9245,3 +9245,5 @@ Video Disk Recorder Revision History - Now using the 'example' macro in vdr.5 (thanks to Chris Mayo). - Now unlocking the Recordings list before displaying an error message in cMenuPathEdit::ApplyChanges() and cReplayControl::Stop() (reported by Matthias Senzel). +- Fixed a possible deadlock when quickly zapping through encrypted channels (reported + by Jörg Wendel). diff --git a/ci.c b/ci.c index b6ea3269..3eb40cb6 100644 --- a/ci.c +++ b/ci.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: ci.c 4.18 2017/06/19 12:13:38 kls Exp $ + * $Id: ci.c 4.19 2018/01/28 11:14:40 kls Exp $ */ #include "ci.h" @@ -122,6 +122,8 @@ private: uchar *bufp; uchar mtdCatBuffer[TS_SIZE]; // TODO: handle multi packet CATs! int length; + cMutex mutex; + bool handlingPid; void AddEmmPid(int Pid); void DelEmmPids(void); public: @@ -130,6 +132,15 @@ public: virtual void Receive(const uchar *Data, int Length); bool HasCaPids(void) const { return NumPids() - emmPids.Size() - 1 > 0; } void Reset(void) { DelEmmPids(); catVersion = -1; } + bool HandlingPid(void); + ///< The cCaPidReceiver adds/deletes PIDs to/from the base class cReceiver, + ///< which in turn does the same on the cDevice it is attached to. The cDevice + ///< then sets the PIDs on the assigned cCamSlot, which can cause a deadlock on the + ///< cCamSlot's mutex if a cReceiver is detached from the device at the same time. + ///< Since these PIDs, however, are none that have to be decrypted, + ///< it is not necessary to set them in the CAM. Therefore this function is + ///< used in cCamSlot::SetPid() to detect this situation, and thus avoid the + ///< deadlock. }; cCaPidReceiver::cCaPidReceiver(void) @@ -137,7 +148,11 @@ cCaPidReceiver::cCaPidReceiver(void) catVersion = -1; bufp = NULL; length = 0; + handlingPid = false; + cMutexLock MutexLock(&mutex); + handlingPid = true; AddPid(CATPID); + handlingPid = false; } void cCaPidReceiver::AddEmmPid(int Pid) @@ -147,14 +162,20 @@ void cCaPidReceiver::AddEmmPid(int Pid) return; } emmPids.Append(Pid); + cMutexLock MutexLock(&mutex); + handlingPid = true; AddPid(Pid); + handlingPid = false; } void cCaPidReceiver::DelEmmPids(void) { + cMutexLock MutexLock(&mutex); + handlingPid = true; for (int i = 0; i < emmPids.Size(); i++) DelPid(emmPids[i]); emmPids.Clear(); + handlingPid = false; } void cCaPidReceiver::Receive(const uchar *Data, int Length) @@ -239,6 +260,12 @@ void cCaPidReceiver::Receive(const uchar *Data, int Length) } } +bool cCaPidReceiver::HandlingPid(void) +{ + cMutexLock MutexLock(&mutex); + return handlingPid; +} + // --- cCaActivationReceiver ------------------------------------------------- // A receiver that is used to make the device stay on a given channel and @@ -2588,6 +2615,8 @@ void cCamSlot::AddPid(int ProgramNumber, int Pid, int StreamType) void cCamSlot::SetPid(int Pid, bool Active) { + if (caPidReceiver && caPidReceiver->HandlingPid()) + return; cMutexLock MutexLock(&mutex); for (cCiCaProgramData *p = caProgramList.First(); p; p = caProgramList.Next(p)) { for (cCiCaPidData *q = p->pidList.First(); q; q = p->pidList.Next(q)) {