Protect pbs with proper (aka locked) refcounting.
The PlaybackSock must not be immediatly deleted on connectionClosed()
if some other requests are still using it. This leads to segfaults in
the MBE when the SBE disconnects (#11306).
diff --git a/mythtv/programs/mythbackend/encoderlink.cpp b/mythtv/programs/mythbackend/encoderlink.cpp
index ff8724d..feef450 100644
a
|
b
|
using namespace std; |
15 | 15 | #include "storagegroup.h" |
16 | 16 | #include "backendutil.h" |
17 | 17 | #include "compat.h" |
| 18 | #include "referencecounter.h" |
18 | 19 | |
19 | 20 | #define LOC QString("EncoderLink(%1): ").arg(m_capturecardnum) |
20 | 21 | #define LOC_ERR QString("EncoderLink(%1) Error: ").arg(m_capturecardnum) |
… |
… |
EncoderLink::EncoderLink(int capturecardnum, PlaybackSock *lsock, |
50 | 51 | lastSleepTime = MythDate::current(); |
51 | 52 | lastWakeTime = MythDate::current(); |
52 | 53 | |
53 | | if (sock) |
54 | | sock->IncrRef(); |
| 54 | HasSockAndIncrRef(); |
55 | 55 | } |
56 | 56 | |
57 | 57 | /** \fn EncoderLink::EncoderLink(int, TVRec *) |
… |
… |
EncoderLink::~EncoderLink(void) |
84 | 84 | SetSocket(NULL); |
85 | 85 | } |
86 | 86 | |
| 87 | /** \fn Encoder::HasSockAndIncrRef() |
| 88 | * \brief Atomicly checks if sock is not null and increases its refcount. |
| 89 | */ |
| 90 | bool EncoderLink::HasSockAndIncrRef() |
| 91 | { |
| 92 | QMutexLocker locker(&sockLock); |
| 93 | if (sock) |
| 94 | { |
| 95 | sock->IncrRef(); |
| 96 | return true; |
| 97 | } |
| 98 | return false; |
| 99 | } |
| 100 | |
| 101 | /** \fn Encoder::HasSockAndDecrRef() |
| 102 | * \brief Atomicly checks if sock is not null and decreases its refcount. |
| 103 | */ |
| 104 | bool EncoderLink::HasSockAndDecrRef() |
| 105 | { |
| 106 | QMutexLocker locker(&sockLock); |
| 107 | if (sock) |
| 108 | { |
| 109 | sock->DecrRef(); |
| 110 | return true; |
| 111 | } |
| 112 | return false; |
| 113 | } |
| 114 | |
87 | 115 | /** \fn EncoderLink::SetSocket(PlaybackSock *lsock) |
88 | 116 | * \brief Used to set the socket for a non-local EncoderLink |
89 | 117 | * |
… |
… |
void EncoderLink::SetSocket(PlaybackSock *lsock) |
108 | 136 | SetSleepStatus(sStatus_Undefined); |
109 | 137 | } |
110 | 138 | |
111 | | if (sock) |
112 | | sock->DecrRef(); |
| 139 | HasSockAndDecrRef(); |
113 | 140 | sock = lsock; |
114 | 141 | } |
115 | 142 | |
… |
… |
bool EncoderLink::IsBusy(TunedInputInfo *busy_input, int time_buffer) |
132 | 159 | if (local) |
133 | 160 | return tv->IsBusy(busy_input, time_buffer); |
134 | 161 | |
135 | | if (sock) |
| 162 | if (HasSockAndIncrRef()) |
| 163 | { |
| 164 | ReferenceLocker rlocker(sock); |
136 | 165 | return sock->IsBusy(m_capturecardnum, busy_input, time_buffer); |
| 166 | } |
137 | 167 | |
138 | 168 | return false; |
139 | 169 | } |
… |
… |
TVState EncoderLink::GetState(void) |
174 | 204 | |
175 | 205 | if (local) |
176 | 206 | retval = tv->GetState(); |
177 | | else if (sock) |
| 207 | else if (HasSockAndIncrRef()) |
| 208 | { |
| 209 | ReferenceLocker rlocker(sock); |
178 | 210 | retval = (TVState)sock->GetEncoderState(m_capturecardnum); |
| 211 | } |
179 | 212 | else |
180 | 213 | LOG(VB_GENERAL, LOG_ERR, QString("Broken for card: %1") |
181 | 214 | .arg(m_capturecardnum)); |
… |
… |
TVState EncoderLink::GetState(void) |
187 | 220 | * \brief Returns the flag state of the recorder. |
188 | 221 | * \sa TVRec::GetFlags(void) const, \ref recorder_subsystem |
189 | 222 | */ |
190 | | uint EncoderLink::GetFlags(void) const |
| 223 | uint EncoderLink::GetFlags(void) |
191 | 224 | { |
192 | 225 | uint retval = 0; |
193 | 226 | |
… |
… |
uint EncoderLink::GetFlags(void) const |
196 | 229 | |
197 | 230 | if (local) |
198 | 231 | retval = tv->GetFlags(); |
199 | | else if (sock) |
| 232 | else if (HasSockAndIncrRef()) |
| 233 | { |
| 234 | ReferenceLocker rlocker(sock); |
200 | 235 | retval = sock->GetEncoderState(m_capturecardnum); |
| 236 | } |
201 | 237 | else |
202 | 238 | LOG(VB_GENERAL, LOG_ERR, LOC + "GetFlags failed"); |
203 | 239 | |
… |
… |
bool EncoderLink::MatchesRecording(const ProgramInfo *rec) |
244 | 280 | } |
245 | 281 | else |
246 | 282 | { |
247 | | if (sock) |
| 283 | if (HasSockAndIncrRef()) |
| 284 | { |
| 285 | ReferenceLocker rlocker(sock); |
248 | 286 | retval = sock->EncoderIsRecording(m_capturecardnum, rec); |
| 287 | } |
249 | 288 | } |
250 | 289 | |
251 | 290 | return retval; |
… |
… |
void EncoderLink::RecordPending(const ProgramInfo *rec, int secsleft, |
264 | 303 | { |
265 | 304 | if (local) |
266 | 305 | tv->RecordPending(rec, secsleft, hasLater); |
267 | | else if (sock) |
| 306 | else if (HasSockAndIncrRef()) |
| 307 | { |
| 308 | ReferenceLocker rlocker(sock); |
268 | 309 | sock->RecordPending(m_capturecardnum, rec, secsleft, hasLater); |
| 310 | } |
269 | 311 | } |
270 | 312 | |
271 | 313 | /** \fn EncoderLink::WouldConflict(const ProgramInfo*) |
… |
… |
bool EncoderLink::WouldConflict(const ProgramInfo *rec) |
287 | 329 | /// Checks if program is stored locally |
288 | 330 | bool EncoderLink::CheckFile(ProgramInfo *pginfo) |
289 | 331 | { |
290 | | if (sock) |
| 332 | if (HasSockAndIncrRef()) |
| 333 | { |
| 334 | ReferenceLocker rlocker(sock); |
291 | 335 | return sock->CheckFile(pginfo); |
| 336 | } |
292 | 337 | |
293 | 338 | pginfo->SetPathname(GetPlaybackURL(pginfo)); |
294 | 339 | return pginfo->IsLocal(); |
… |
… |
bool EncoderLink::CheckFile(ProgramInfo *pginfo) |
301 | 346 | */ |
302 | 347 | void EncoderLink::GetDiskSpace(QStringList &o_strlist) |
303 | 348 | { |
304 | | if (sock) |
| 349 | if (HasSockAndIncrRef()) |
| 350 | { |
| 351 | ReferenceLocker rlocker(sock); |
305 | 352 | sock->GetDiskSpace(o_strlist); |
| 353 | } |
306 | 354 | } |
307 | 355 | |
308 | 356 | /** \fn EncoderLink::GetMaxBitrate() |
… |
… |
long long EncoderLink::GetMaxBitrate() |
315 | 363 | { |
316 | 364 | if (local) |
317 | 365 | return tv->GetMaxBitrate(); |
318 | | else if (sock) |
| 366 | else if (HasSockAndIncrRef()) |
| 367 | { |
| 368 | ReferenceLocker rlocker(sock); |
319 | 369 | return sock->GetMaxBitrate(m_capturecardnum); |
| 370 | } |
320 | 371 | |
321 | 372 | return -1; |
322 | 373 | } |
… |
… |
int EncoderLink::SetSignalMonitoringRate(int rate, int notifyFrontend) |
339 | 390 | { |
340 | 391 | if (local) |
341 | 392 | return tv->SetSignalMonitoringRate(rate, notifyFrontend); |
342 | | else if (sock) |
| 393 | else if (HasSockAndIncrRef()) |
| 394 | { |
| 395 | ReferenceLocker rlocker(sock); |
343 | 396 | return sock->SetSignalMonitoringRate(m_capturecardnum, rate, |
344 | 397 | notifyFrontend); |
| 398 | } |
345 | 399 | return -1; |
346 | 400 | } |
347 | 401 | |
… |
… |
int EncoderLink::SetSignalMonitoringRate(int rate, int notifyFrontend) |
349 | 403 | */ |
350 | 404 | bool EncoderLink::GoToSleep(void) |
351 | 405 | { |
352 | | if (IsLocal() || !sock) |
| 406 | if (IsLocal() || !HasSockAndIncrRef()) |
353 | 407 | return false; |
| 408 | ReferenceLocker rlocker(sock); |
354 | 409 | |
355 | 410 | lastSleepTime = MythDate::current(); |
356 | 411 | |
… |
… |
RecStatusType EncoderLink::StartRecording(const ProgramInfo *rec) |
387 | 442 | |
388 | 443 | if (local) |
389 | 444 | retval = tv->StartRecording(rec); |
390 | | else if (sock) |
| 445 | else if (HasSockAndIncrRef()) |
| 446 | { |
| 447 | ReferenceLocker rlocker(sock); |
391 | 448 | retval = sock->StartRecording(m_capturecardnum, rec); |
| 449 | } |
392 | 450 | else |
393 | 451 | LOG(VB_GENERAL, LOG_ERR, |
394 | 452 | QString("Wanted to start recording on recorder %1,\n\t\t\t" |
… |
… |
RecStatusType EncoderLink::GetRecordingStatus(void) |
411 | 469 | |
412 | 470 | if (local) |
413 | 471 | retval = tv->GetRecordingStatus(); |
414 | | else if (sock) |
| 472 | else if (HasSockAndIncrRef()) |
| 473 | { |
| 474 | ReferenceLocker rlocker(sock); |
415 | 475 | retval = sock->GetRecordingStatus(m_capturecardnum); |
| 476 | } |
416 | 477 | else |
417 | 478 | LOG(VB_GENERAL, LOG_ERR, |
418 | 479 | QString("Wanted to get status on recorder %1,\n\t\t\t" |
… |
… |
ProgramInfo *EncoderLink::GetRecording(void) |
441 | 502 | |
442 | 503 | if (local) |
443 | 504 | info = tv->GetRecording(); |
444 | | else if (sock) |
| 505 | else if (HasSockAndIncrRef()) |
| 506 | { |
| 507 | ReferenceLocker rlocker(sock); |
445 | 508 | info = sock->GetRecording(m_capturecardnum); |
| 509 | } |
446 | 510 | |
447 | 511 | return info; |
448 | 512 | } |
… |
… |
void EncoderLink::CancelNextRecording(bool cancel) |
610 | 674 | { |
611 | 675 | if (local) |
612 | 676 | tv->CancelNextRecording(cancel); |
613 | | else |
| 677 | else if (HasSockAndIncrRef()) |
| 678 | { |
| 679 | ReferenceLocker rlocker(sock); |
614 | 680 | sock->CancelNextRecording(m_capturecardnum, cancel); |
| 681 | } |
615 | 682 | } |
616 | 683 | |
617 | 684 | /** \fn EncoderLink::SpawnLiveTV(LiveTVChain*, bool, QString) |
… |
… |
void EncoderLink::SetNextLiveTVDir(QString dir) |
693 | 760 | { |
694 | 761 | if (local) |
695 | 762 | tv->SetNextLiveTVDir(dir); |
696 | | else |
| 763 | else if (HasSockAndIncrRef()) |
| 764 | { |
| 765 | ReferenceLocker rlocker(sock); |
697 | 766 | sock->SetNextLiveTVDir(m_capturecardnum, dir); |
| 767 | } |
698 | 768 | } |
699 | 769 | |
700 | 770 | /** \fn EncoderLink::GetFreeInputs(const vector<uint>&) const |
… |
… |
void EncoderLink::SetNextLiveTVDir(QString dir) |
703 | 773 | * \sa TVRec::GetFreeInputs(const vector<uint>&) const |
704 | 774 | */ |
705 | 775 | vector<InputInfo> EncoderLink::GetFreeInputs( |
706 | | const vector<uint> &excluded_cardids) const |
| 776 | const vector<uint> &excluded_cardids) |
707 | 777 | { |
708 | 778 | vector<InputInfo> list; |
709 | 779 | |
710 | 780 | if (local) |
711 | 781 | list = tv->GetFreeInputs(excluded_cardids); |
712 | | else |
| 782 | else if (HasSockAndIncrRef()) |
| 783 | { |
| 784 | ReferenceLocker rlocker(sock); |
713 | 785 | list = sock->GetFreeInputs(m_capturecardnum, excluded_cardids); |
| 786 | } |
714 | 787 | |
715 | 788 | return list; |
716 | 789 | } |
diff --git a/mythtv/programs/mythbackend/encoderlink.h b/mythtv/programs/mythbackend/encoderlink.h
index 35707c0..77a3e76 100644
a
|
b
|
|
3 | 3 | |
4 | 4 | #include <QString> |
5 | 5 | #include <QMap> |
| 6 | #include <QMutex> |
6 | 7 | |
7 | 8 | #include "tv.h" |
8 | 9 | #include "programinfo.h" |
… |
… |
class EncoderLink |
82 | 83 | bool IsBusyRecording(void); |
83 | 84 | |
84 | 85 | TVState GetState(); |
85 | | uint GetFlags(void) const; |
| 86 | uint GetFlags(void); |
86 | 87 | bool IsRecording(const ProgramInfo *rec); // scheduler call only. |
87 | 88 | |
88 | 89 | bool MatchesRecording(const ProgramInfo *rec); |
… |
… |
class EncoderLink |
109 | 110 | void PauseRecorder(void); |
110 | 111 | void SetLiveRecording(int); |
111 | 112 | void SetNextLiveTVDir(QString dir); |
112 | | vector<InputInfo> GetFreeInputs(const vector<uint> &excluded_cards) const; |
| 113 | vector<InputInfo> GetFreeInputs(const vector<uint> &excluded_cards); |
113 | 114 | QString GetInput(void) const; |
114 | 115 | QString SetInput(QString); |
115 | 116 | void ToggleChannelFavorite(QString); |
… |
… |
class EncoderLink |
137 | 138 | QString channame, QString xmltv); |
138 | 139 | |
139 | 140 | private: |
| 141 | bool HasSockAndIncrRef(); |
| 142 | bool HasSockAndDecrRef(); |
| 143 | |
140 | 144 | int m_capturecardnum; |
141 | 145 | |
142 | 146 | PlaybackSock *sock; |
| 147 | QMutex sockLock; |
143 | 148 | QString hostname; |
144 | 149 | |
145 | 150 | TVRec *tv; |