player/Control: pass std::unique_lock<> to Cond::wait()

This commit is contained in:
Max Kellermann 2019-04-26 18:47:22 +02:00
parent cf348f9fae
commit dedc4b4b10
3 changed files with 51 additions and 44 deletions

View File

@ -45,11 +45,12 @@ PlayerControl::~PlayerControl() noexcept
} }
bool bool
PlayerControl::WaitOutputConsumed(unsigned threshold) noexcept PlayerControl::WaitOutputConsumed(std::unique_lock<Mutex> &lock,
unsigned threshold) noexcept
{ {
bool result = outputs.CheckPipe() < threshold; bool result = outputs.CheckPipe() < threshold;
if (!result && command == PlayerCommand::NONE) { if (!result && command == PlayerCommand::NONE) {
Wait(); Wait(lock);
result = outputs.CheckPipe() < threshold; result = outputs.CheckPipe() < threshold;
} }
@ -64,13 +65,13 @@ PlayerControl::Play(std::unique_ptr<DetachedSong> song)
assert(song != nullptr); assert(song != nullptr);
const std::lock_guard<Mutex> protect(mutex); std::unique_lock<Mutex> lock(mutex);
SeekLocked(std::move(song), SongTime::zero()); SeekLocked(lock, std::move(song), SongTime::zero());
if (state == PlayerState::PAUSE) if (state == PlayerState::PAUSE)
/* if the player was paused previously, we need to /* if the player was paused previously, we need to
unpause it */ unpause it */
PauseLocked(); PauseLocked(lock);
} }
void void
@ -116,10 +117,10 @@ PlayerControl::Kill() noexcept
} }
void void
PlayerControl::PauseLocked() noexcept PlayerControl::PauseLocked(std::unique_lock<Mutex> &lock) noexcept
{ {
if (state != PlayerState::STOP) { if (state != PlayerState::STOP) {
SynchronousCommand(PlayerCommand::PAUSE); SynchronousCommand(lock, PlayerCommand::PAUSE);
idle_add(IDLE_PLAYER); idle_add(IDLE_PLAYER);
} }
} }
@ -127,8 +128,8 @@ PlayerControl::PauseLocked() noexcept
void void
PlayerControl::LockPause() noexcept PlayerControl::LockPause() noexcept
{ {
const std::lock_guard<Mutex> protect(mutex); std::unique_lock<Mutex> lock(mutex);
PauseLocked(); PauseLocked(lock);
} }
void void
@ -137,7 +138,7 @@ PlayerControl::LockSetPause(bool pause_flag) noexcept
if (!thread.IsDefined()) if (!thread.IsDefined())
return; return;
const std::lock_guard<Mutex> protect(mutex); std::unique_lock<Mutex> lock(mutex);
switch (state) { switch (state) {
case PlayerState::STOP: case PlayerState::STOP:
@ -145,12 +146,12 @@ PlayerControl::LockSetPause(bool pause_flag) noexcept
case PlayerState::PLAY: case PlayerState::PLAY:
if (pause_flag) if (pause_flag)
PauseLocked(); PauseLocked(lock);
break; break;
case PlayerState::PAUSE: case PlayerState::PAUSE:
if (!pause_flag) if (!pause_flag)
PauseLocked(); PauseLocked(lock);
break; break;
} }
} }
@ -167,9 +168,9 @@ PlayerControl::LockGetStatus() noexcept
{ {
PlayerStatus status; PlayerStatus status;
const std::lock_guard<Mutex> protect(mutex); std::unique_lock<Mutex> lock(mutex);
if (!occupied && thread.IsDefined()) if (!occupied && thread.IsDefined())
SynchronousCommand(PlayerCommand::REFRESH); SynchronousCommand(lock, PlayerCommand::REFRESH);
status.state = state; status.state = state;
@ -233,23 +234,25 @@ PlayerControl::LockEnqueueSong(std::unique_ptr<DetachedSong> song) noexcept
assert(thread.IsDefined()); assert(thread.IsDefined());
assert(song != nullptr); assert(song != nullptr);
const std::lock_guard<Mutex> protect(mutex); std::unique_lock<Mutex> lock(mutex);
EnqueueSongLocked(std::move(song)); EnqueueSongLocked(lock, std::move(song));
} }
void void
PlayerControl::EnqueueSongLocked(std::unique_ptr<DetachedSong> song) noexcept PlayerControl::EnqueueSongLocked(std::unique_lock<Mutex> &lock,
std::unique_ptr<DetachedSong> song) noexcept
{ {
assert(song != nullptr); assert(song != nullptr);
assert(next_song == nullptr); assert(next_song == nullptr);
next_song = std::move(song); next_song = std::move(song);
seek_time = SongTime::zero(); seek_time = SongTime::zero();
SynchronousCommand(PlayerCommand::QUEUE); SynchronousCommand(lock, PlayerCommand::QUEUE);
} }
void void
PlayerControl::SeekLocked(std::unique_ptr<DetachedSong> song, SongTime t) PlayerControl::SeekLocked(std::unique_lock<Mutex> &lock,
std::unique_ptr<DetachedSong> song, SongTime t)
{ {
assert(song != nullptr); assert(song != nullptr);
@ -258,21 +261,21 @@ PlayerControl::SeekLocked(std::unique_ptr<DetachedSong> song, SongTime t)
/* optimization TODO: if the decoder happens to decode that /* optimization TODO: if the decoder happens to decode that
song already, don't cancel that */ song already, don't cancel that */
if (next_song != nullptr) if (next_song != nullptr)
SynchronousCommand(PlayerCommand::CANCEL); SynchronousCommand(lock, PlayerCommand::CANCEL);
assert(next_song == nullptr); assert(next_song == nullptr);
ClearError(); ClearError();
next_song = std::move(song); next_song = std::move(song);
seek_time = t; seek_time = t;
SynchronousCommand(PlayerCommand::SEEK); SynchronousCommand(lock, PlayerCommand::SEEK);
assert(next_song == nullptr); assert(next_song == nullptr);
/* the SEEK command is asynchronous; until completion, the /* the SEEK command is asynchronous; until completion, the
"seeking" flag is set */ "seeking" flag is set */
while (seeking) while (seeking)
ClientWait(); ClientWait(lock);
if (error_type != PlayerError::NONE) { if (error_type != PlayerError::NONE) {
assert(error); assert(error);
@ -290,8 +293,8 @@ PlayerControl::LockSeek(std::unique_ptr<DetachedSong> song, SongTime t)
assert(song != nullptr); assert(song != nullptr);
const std::lock_guard<Mutex> protect(mutex); std::unique_lock<Mutex> lock(mutex);
SeekLocked(std::move(song), t); SeekLocked(lock, std::move(song), t);
} }
void void

View File

@ -368,10 +368,10 @@ private:
* valid in the player thread. The object must be locked * valid in the player thread. The object must be locked
* prior to calling this function. * prior to calling this function.
*/ */
void Wait() noexcept { void Wait(std::unique_lock<Mutex> &lock) noexcept {
assert(thread.IsInside()); assert(thread.IsInside());
cond.wait(mutex); cond.wait(lock);
} }
/** /**
@ -391,10 +391,10 @@ private:
* *
* Caller must lock the object. * Caller must lock the object.
*/ */
void ClientWait() noexcept { void ClientWait(std::unique_lock<Mutex> &lock) noexcept {
assert(!thread.IsInside()); assert(!thread.IsInside());
client_cond.wait(mutex); client_cond.wait(lock);
} }
/** /**
@ -426,11 +426,12 @@ private:
* @param threshold the maximum number of chunks in the pipe * @param threshold the maximum number of chunks in the pipe
* @return true if there are less than #threshold chunks in the pipe * @return true if there are less than #threshold chunks in the pipe
*/ */
bool WaitOutputConsumed(unsigned threshold) noexcept; bool WaitOutputConsumed(std::unique_lock<Mutex> &lock,
unsigned threshold) noexcept;
bool LockWaitOutputConsumed(unsigned threshold) noexcept { bool LockWaitOutputConsumed(unsigned threshold) noexcept {
const std::lock_guard<Mutex> protect(mutex); std::unique_lock<Mutex> lock(mutex);
return WaitOutputConsumed(threshold); return WaitOutputConsumed(lock, threshold);
} }
/** /**
@ -439,9 +440,9 @@ private:
* To be called from the main thread. Caller must lock the * To be called from the main thread. Caller must lock the
* object. * object.
*/ */
void WaitCommandLocked() noexcept { void WaitCommandLocked(std::unique_lock<Mutex> &lock) noexcept {
while (command != PlayerCommand::NONE) while (command != PlayerCommand::NONE)
ClientWait(); ClientWait(lock);
} }
/** /**
@ -451,12 +452,13 @@ private:
* To be called from the main thread. Caller must lock the * To be called from the main thread. Caller must lock the
* object. * object.
*/ */
void SynchronousCommand(PlayerCommand cmd) noexcept { void SynchronousCommand(std::unique_lock<Mutex> &lock,
PlayerCommand cmd) noexcept {
assert(command == PlayerCommand::NONE); assert(command == PlayerCommand::NONE);
command = cmd; command = cmd;
Signal(); Signal();
WaitCommandLocked(); WaitCommandLocked(lock);
} }
/** /**
@ -467,11 +469,11 @@ private:
* object. * object.
*/ */
void LockSynchronousCommand(PlayerCommand cmd) noexcept { void LockSynchronousCommand(PlayerCommand cmd) noexcept {
const std::lock_guard<Mutex> protect(mutex); std::unique_lock<Mutex> lock(mutex);
SynchronousCommand(cmd); SynchronousCommand(lock, cmd);
} }
void PauseLocked() noexcept; void PauseLocked(std::unique_lock<Mutex> &lock) noexcept;
void ClearError() noexcept { void ClearError() noexcept {
error_type = PlayerError::NONE; error_type = PlayerError::NONE;
@ -535,12 +537,14 @@ private:
*/ */
std::unique_ptr<DetachedSong> ReadTaggedSong() noexcept; std::unique_ptr<DetachedSong> ReadTaggedSong() noexcept;
void EnqueueSongLocked(std::unique_ptr<DetachedSong> song) noexcept; void EnqueueSongLocked(std::unique_lock<Mutex> &lock,
std::unique_ptr<DetachedSong> song) noexcept;
/** /**
* Throws on error. * Throws on error.
*/ */
void SeekLocked(std::unique_ptr<DetachedSong> song, SongTime t); void SeekLocked(std::unique_lock<Mutex> &lock,
std::unique_ptr<DetachedSong> song, SongTime t);
/** /**
* Caller must lock the object. * Caller must lock the object.

View File

@ -515,7 +515,7 @@ Player::CheckDecoderStartup(std::unique_lock<Mutex> &lock) noexcept
/* the decoder is ready and ok */ /* the decoder is ready and ok */
if (output_open && if (output_open &&
!pc.WaitOutputConsumed(1)) !pc.WaitOutputConsumed(lock, 1))
/* the output devices havn't finished playing /* the output devices havn't finished playing
all chunks yet - wait for that */ all chunks yet - wait for that */
return true; return true;
@ -1037,7 +1037,7 @@ Player::Run() noexcept
if (paused) { if (paused) {
if (pc.command == PlayerCommand::NONE) if (pc.command == PlayerCommand::NONE)
pc.Wait(); pc.Wait(lock);
} else if (!pipe->IsEmpty()) { } else if (!pipe->IsEmpty()) {
/* at least one music chunk is ready - send it /* at least one music chunk is ready - send it
to the audio output */ to the audio output */
@ -1128,7 +1128,7 @@ try {
MusicBuffer buffer(buffer_chunks); MusicBuffer buffer(buffer_chunks);
const std::lock_guard<Mutex> lock(mutex); std::unique_lock<Mutex> lock(mutex);
while (1) { while (1) {
switch (command) { switch (command) {
@ -1201,7 +1201,7 @@ try {
break; break;
case PlayerCommand::NONE: case PlayerCommand::NONE:
Wait(); Wait(lock);
break; break;
} }
} }