Commit f8070900 authored by dalecurtis@google.com's avatar dalecurtis@google.com

Fix potential deadlock situation for ChromeOS sounds.

Lock order was inverted while stopping the stream which can lead
to deadlock.

BUG=327817,374135
TEST=No more lock inversion warning from TSANv2.
R=ajwong@chromium.org, dgreid@chromium.org
TBR=awong

Review URL: https://codereview.chromium.org/348843004

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@278885 0039d316-1c4b-4281-b951-d872f2087c98
parent 2256b5de
...@@ -281,8 +281,6 @@ char kTSanDefaultSuppressions[] = ...@@ -281,8 +281,6 @@ char kTSanDefaultSuppressions[] =
// http://crbug.com/374135 // http://crbug.com/374135
"race:media::AlsaWrapper::PcmWritei\n" "race:media::AlsaWrapper::PcmWritei\n"
"deadlock:media::AudioOutputDispatcherImpl::StopStream\n"
"deadlock:media::AudioStreamHandler::AudioStreamContainer::OnMoreData\n"
// False positive in libc's tzset_internal, http://crbug.com/379738. // False positive in libc's tzset_internal, http://crbug.com/379738.
"race:tzset_internal\n" "race:tzset_internal\n"
......
...@@ -37,12 +37,11 @@ class AudioStreamHandler::AudioStreamContainer ...@@ -37,12 +37,11 @@ class AudioStreamHandler::AudioStreamContainer
: public AudioOutputStream::AudioSourceCallback { : public AudioOutputStream::AudioSourceCallback {
public: public:
AudioStreamContainer(const WavAudioHandler& wav_audio) AudioStreamContainer(const WavAudioHandler& wav_audio)
: stream_(NULL), : started_(false),
wav_audio_(wav_audio), stream_(NULL),
cursor_(0), cursor_(0),
started_(false), delayed_stop_posted_(false),
delayed_stop_posted_(false) { wav_audio_(wav_audio) {}
}
virtual ~AudioStreamContainer() { virtual ~AudioStreamContainer() {
DCHECK(AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread()); DCHECK(AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread());
...@@ -58,8 +57,8 @@ class AudioStreamHandler::AudioStreamContainer ...@@ -58,8 +57,8 @@ class AudioStreamHandler::AudioStreamContainer
p.sample_rate(), p.sample_rate(),
p.bits_per_sample(), p.bits_per_sample(),
kDefaultFrameCount); kDefaultFrameCount);
stream_ = AudioManager::Get()->MakeAudioOutputStreamProxy( stream_ = AudioManager::Get()->MakeAudioOutputStreamProxy(params,
params, std::string()); std::string());
if (!stream_ || !stream_->Open()) { if (!stream_ || !stream_->Open()) {
LOG(ERROR) << "Failed to open an output stream."; LOG(ERROR) << "Failed to open an output stream.";
return; return;
...@@ -71,8 +70,8 @@ class AudioStreamHandler::AudioStreamContainer ...@@ -71,8 +70,8 @@ class AudioStreamHandler::AudioStreamContainer
base::AutoLock al(state_lock_); base::AutoLock al(state_lock_);
delayed_stop_posted_ = false; delayed_stop_posted_ = false;
stop_closure_.Reset(base::Bind( stop_closure_.Reset(base::Bind(&AudioStreamContainer::StopStream,
&AudioStreamContainer::StopStream, base::Unretained(this))); base::Unretained(this)));
if (started_) { if (started_) {
if (wav_audio_.AtEnd(cursor_)) if (wav_audio_.AtEnd(cursor_))
...@@ -81,9 +80,9 @@ class AudioStreamHandler::AudioStreamContainer ...@@ -81,9 +80,9 @@ class AudioStreamHandler::AudioStreamContainer
} }
cursor_ = 0; cursor_ = 0;
started_ = true;
} }
started_ = true;
if (g_audio_source_for_testing) if (g_audio_source_for_testing)
stream_->Start(g_audio_source_for_testing); stream_->Start(g_audio_source_for_testing);
else else
...@@ -99,6 +98,7 @@ class AudioStreamHandler::AudioStreamContainer ...@@ -99,6 +98,7 @@ class AudioStreamHandler::AudioStreamContainer
if (stream_) if (stream_)
stream_->Close(); stream_->Close();
stream_ = NULL; stream_ = NULL;
stop_closure_.Cancel();
} }
private: private:
...@@ -131,24 +131,25 @@ class AudioStreamHandler::AudioStreamContainer ...@@ -131,24 +131,25 @@ class AudioStreamHandler::AudioStreamContainer
void StopStream() { void StopStream() {
DCHECK(AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread()); DCHECK(AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread());
base::AutoLock al(state_lock_);
if (stream_ && started_) { if (stream_ && started_) {
// Do not hold the |state_lock_| while stopping the output stream.
stream_->Stop(); stream_->Stop();
if (g_observer_for_testing) if (g_observer_for_testing)
g_observer_for_testing->OnStop(cursor_); g_observer_for_testing->OnStop(cursor_);
} }
started_ = false; started_ = false;
} }
// Must only be accessed on the AudioManager::GetTaskRunner() thread.
bool started_;
AudioOutputStream* stream_; AudioOutputStream* stream_;
const WavAudioHandler wav_audio_; // All variables below must be accessed under |state_lock_| when |started_|.
base::Lock state_lock_; base::Lock state_lock_;
size_t cursor_; size_t cursor_;
bool started_;
bool delayed_stop_posted_; bool delayed_stop_posted_;
const WavAudioHandler wav_audio_;
base::CancelableClosure stop_closure_; base::CancelableClosure stop_closure_;
DISALLOW_COPY_AND_ASSIGN(AudioStreamContainer); DISALLOW_COPY_AND_ASSIGN(AudioStreamContainer);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment