Remove deadlock in WebRtcVideoEngine2.

Acquiring stream_lock_ in WebRtcVideoChannel2 in a callback from Call
forms a lock-order inversion between process-thread locks and libjingle
locks, manifesting as CPU adaptation requests blocking on stream
creation that is blocked on the CPU adaptation request finishing.

R=asapersson@webrtc.org, mflodman@webrtc.org
BUG=4535,chromium:475065

Review URL: https://webrtc-codereview.appspot.com/50679004

Cr-Commit-Position: refs/heads/master@{#8985}
This commit is contained in:
Peter Boström 2015-04-13 15:34:32 +02:00
parent 6fc2d2f487
commit e7b221f476
2 changed files with 37 additions and 30 deletions

View File

@ -633,6 +633,7 @@ WebRtcVideoChannel2::WebRtcVideoChannel2(
external_decoder_factory_(external_decoder_factory) {
SetDefaultOptions();
options_.SetAll(options);
options_.cpu_overuse_detection.Get(&signal_cpu_adaptation_);
webrtc::Call::Config config(this);
config.overuse_callback = this;
if (voice_engine != NULL) {
@ -1144,13 +1145,15 @@ bool WebRtcVideoChannel2::SetCapturer(uint32 ssrc, VideoCapturer* capturer) {
LOG(LS_INFO) << "SetCapturer: " << ssrc << " -> "
<< (capturer != NULL ? "(capturer)" : "NULL");
assert(ssrc != 0);
rtc::CritScope stream_lock(&stream_crit_);
if (send_streams_.find(ssrc) == send_streams_.end()) {
LOG(LS_ERROR) << "No sending stream on ssrc " << ssrc;
return false;
}
if (!send_streams_[ssrc]->SetCapturer(capturer)) {
return false;
{
rtc::CritScope stream_lock(&stream_crit_);
if (send_streams_.find(ssrc) == send_streams_.end()) {
LOG(LS_ERROR) << "No sending stream on ssrc " << ssrc;
return false;
}
if (!send_streams_[ssrc]->SetCapturer(capturer)) {
return false;
}
}
if (capturer) {
@ -1158,6 +1161,10 @@ bool WebRtcVideoChannel2::SetCapturer(uint32 ssrc, VideoCapturer* capturer) {
!FindHeaderExtension(send_rtp_extensions_,
kRtpVideoRotationHeaderExtension));
}
{
rtc::CritScope lock(&capturer_crit_);
capturers_[ssrc] = capturer;
}
return true;
}
@ -1333,6 +1340,10 @@ bool WebRtcVideoChannel2::SetOptions(const VideoOptions& options) {
// No new options to set.
return true;
}
{
rtc::CritScope lock(&capturer_crit_);
options_.cpu_overuse_detection.Get(&signal_cpu_adaptation_);
}
rtc::DiffServCodePoint dscp = options_.dscp.GetWithDefaultIfUnset(false)
? rtc::DSCP_AF41
: rtc::DSCP_DEFAULT;
@ -1372,14 +1383,18 @@ void WebRtcVideoChannel2::OnMessage(rtc::Message* msg) {
}
void WebRtcVideoChannel2::OnLoadUpdate(Load load) {
rtc::CritScope stream_lock(&stream_crit_);
for (std::map<uint32, WebRtcVideoSendStream*>::iterator it =
send_streams_.begin();
it != send_streams_.end();
++it) {
it->second->OnCpuResolutionRequest(load == kOveruse
? CoordinatedVideoAdapter::DOWNGRADE
: CoordinatedVideoAdapter::UPGRADE);
// OnLoadUpdate can not take any locks that are held while creating streams
// etc. Doing so establishes lock-order inversions between the webrtc process
// thread on stream creation and locks such as stream_crit_ while calling out.
rtc::CritScope stream_lock(&capturer_crit_);
if (!signal_cpu_adaptation_)
return;
for (auto& kv : capturers_) {
if (kv.second != nullptr && kv.second->video_adapter() != nullptr) {
kv.second->video_adapter()->OnCpuResolutionRequest(
load == kOveruse ? CoordinatedVideoAdapter::DOWNGRADE
: CoordinatedVideoAdapter::UPGRADE);
}
}
}
@ -1962,18 +1977,6 @@ void WebRtcVideoChannel2::WebRtcVideoSendStream::SetMaxBitrateBps(
last_dimensions_.width = 0;
SetDimensions(width, last_dimensions_.height, last_dimensions_.is_screencast);
}
void WebRtcVideoChannel2::WebRtcVideoSendStream::OnCpuResolutionRequest(
CoordinatedVideoAdapter::AdaptRequest adapt_request) {
rtc::CritScope cs(&lock_);
bool adapt_cpu;
parameters_.options.cpu_overuse_detection.Get(&adapt_cpu);
if (!adapt_cpu)
return;
if (capturer_ == NULL || capturer_->video_adapter() == NULL)
return;
capturer_->video_adapter()->OnCpuResolutionRequest(adapt_request);
}
void WebRtcVideoChannel2::WebRtcVideoSendStream::RecreateWebRtcStream() {
if (stream_ != NULL) {

View File

@ -295,9 +295,6 @@ class WebRtcVideoChannel2 : public rtc::MessageHandler,
void SetMaxBitrateBps(int max_bitrate_bps);
void OnCpuResolutionRequest(
CoordinatedVideoAdapter::AdaptRequest adapt_request);
private:
// Parameters needed to reconstruct the underlying stream.
// webrtc::VideoSendStream doesn't support setting a lot of options on the
@ -497,6 +494,13 @@ class WebRtcVideoChannel2 : public rtc::MessageHandler,
DefaultUnsignalledSsrcHandler default_unsignalled_ssrc_handler_;
UnsignalledSsrcHandler* const unsignalled_ssrc_handler_;
// Separate list of set capturers used to signal CPU adaptation. These should
// not be locked while calling methods that take other locks to prevent
// lock-order inversions.
rtc::CriticalSection capturer_crit_;
bool signal_cpu_adaptation_ GUARDED_BY(capturer_crit_);
std::map<uint32, VideoCapturer*> capturers_ GUARDED_BY(capturer_crit_);
rtc::CriticalSection stream_crit_;
// Using primary-ssrc (first ssrc) as key.
std::map<uint32, WebRtcVideoSendStream*> send_streams_