summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2020-01-28 23:23:47 +0100
committerCarl Hetherington <cth@carlh.net>2020-02-16 21:23:42 +0100
commit4b38c8f429407ec09609236fc7b2349459536571 (patch)
tree5b68a09ead560205e2dd3aaed4e81f50fbde959b
parentc259c459f5d326e7c42806b41de06c71ad4a3ad8 (diff)
Fix deadlock during content examination.
Before this fix, the following situation could happen in threads A and B: A: Some DONE signal happens; this triggers setup_pieces which takes a lock on the player mutex. B: FFmpegContent::examine takes a lock on the content mutex. B: FFmpegContent::examine adds a stream B: That causes STREAMS PENDING to be emitted. B: This tries to take a lock on the player mutex so it can update _suspended A: setup_pieces tries to access some content information, hence tries to take a lock on the content mutex. Now B is holding the CL and awaiting the PL and A is holding the PL and awaiting the CL. It feels like the root cause of this is that while setup_pieces is happening another change (which would itself cause setup_pieces) is announced, and this isn't dealt with properly. There are two steps here; _suspended is protected with an atomic rather than using _mutex, and also it can cope with being updated recursively. Backported from df48c75c38dd788835a93540aea243a2dac4bb10 in v2.15.x
-rw-r--r--src/lib/player.cc10
-rw-r--r--src/lib/player.h4
2 files changed, 6 insertions, 8 deletions
diff --git a/src/lib/player.cc b/src/lib/player.cc
index 30b49d186..1d83b9b5a 100644
--- a/src/lib/player.cc
+++ b/src/lib/player.cc
@@ -85,7 +85,7 @@ int const PlayerProperty::DCP_DECODE_REDUCTION = 704;
Player::Player (shared_ptr<const Film> film, shared_ptr<const Playlist> playlist)
: _film (film)
, _playlist (playlist)
- , _suspended (false)
+ , _suspended (0)
, _ignore_video (false)
, _ignore_audio (false)
, _ignore_text (false)
@@ -237,19 +237,17 @@ void
Player::playlist_content_change (ChangeType type, int property, bool frequent)
{
if (type == CHANGE_TYPE_PENDING) {
- boost::mutex::scoped_lock lm (_mutex);
/* The player content is probably about to change, so we can't carry on
until that has happened and we've rebuilt our pieces. Stop pass()
and seek() from working until then.
*/
- _suspended = true;
+ ++_suspended;
} else if (type == CHANGE_TYPE_DONE) {
/* A change in our content has gone through. Re-build our pieces. */
setup_pieces ();
- _suspended = false;
+ --_suspended;
} else if (type == CHANGE_TYPE_CANCELLED) {
- boost::mutex::scoped_lock lm (_mutex);
- _suspended = false;
+ --_suspended;
}
Change (type, property, frequent);
diff --git a/src/lib/player.h b/src/lib/player.h
index 8a81146c9..65ab1279f 100644
--- a/src/lib/player.h
+++ b/src/lib/player.h
@@ -145,8 +145,8 @@ private:
boost::shared_ptr<const Film> _film;
boost::shared_ptr<const Playlist> _playlist;
- /** true if we are suspended (i.e. pass() and seek() do nothing) */
- bool _suspended;
+ /** > 0 if we are suspended (i.e. pass() and seek() do nothing) */
+ boost::atomic<int> _suspended;
std::list<boost::shared_ptr<Piece> > _pieces;
/** Size of the image in the DCP (e.g. 1990x1080 for flat) */