Fix deadlock in video_receiver.cc.

In webrtc::vcm::VideoReceiver::ResetDecoder(), the lock order is:
1. take _receiveCritSect,
2. take process_crit_sect_

This conflicts with the follow code path:
1. webrtc::vcm::VideoReceiver::Process(), take process_crit_sect_
  call -> webrtc::vcm::VideoReceiver::NackList(),
2.  with nackStats=kNackKeyFrameRequest, take _receiveCritSect

BUG=2861
TEST=trybots
R=sprang@webrtc.org

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

git-svn-id: http://webrtc.googlecode.com/svn/trunk@5456 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
stefan@webrtc.org
2014-01-29 10:27:51 +00:00
parent 41907748cb
commit f7c6e743b3

View File

@ -121,8 +121,12 @@ int32_t VideoReceiver::Process() {
// Key frame requests // Key frame requests
if (_keyRequestTimer.TimeUntilProcess() == 0) { if (_keyRequestTimer.TimeUntilProcess() == 0) {
_keyRequestTimer.Processed(); _keyRequestTimer.Processed();
bool request_key_frame = false;
{
CriticalSectionScoped cs(process_crit_sect_.get()); CriticalSectionScoped cs(process_crit_sect_.get());
if (_scheduleKeyRequest && _frameTypeCallback != NULL) { request_key_frame = _scheduleKeyRequest && _frameTypeCallback != NULL;
}
if (request_key_frame) {
const int32_t ret = RequestKeyFrame(); const int32_t ret = RequestKeyFrame();
if (ret != VCM_OK && returnValue == VCM_OK) { if (ret != VCM_OK && returnValue == VCM_OK) {
returnValue = ret; returnValue = ret;
@ -135,19 +139,27 @@ int32_t VideoReceiver::Process() {
// disabled when NACK is off. // disabled when NACK is off.
if (_retransmissionTimer.TimeUntilProcess() == 0) { if (_retransmissionTimer.TimeUntilProcess() == 0) {
_retransmissionTimer.Processed(); _retransmissionTimer.Processed();
bool callback_registered = false;
uint16_t length;
{
CriticalSectionScoped cs(process_crit_sect_.get()); CriticalSectionScoped cs(process_crit_sect_.get());
if (_packetRequestCallback != NULL) { length = max_nack_list_size_;
uint16_t length = max_nack_list_size_; callback_registered = _packetRequestCallback != NULL;
}
if (callback_registered && length > 0) {
std::vector<uint16_t> nackList(length); std::vector<uint16_t> nackList(length);
const int32_t ret = NackList(&nackList[0], &length); const int32_t ret = NackList(&nackList[0], &length);
if (ret != VCM_OK && returnValue == VCM_OK) { if (ret != VCM_OK && returnValue == VCM_OK) {
returnValue = ret; returnValue = ret;
} }
if (length > 0) { if (ret == VCM_OK && length > 0) {
CriticalSectionScoped cs(process_crit_sect_.get());
if (_packetRequestCallback != NULL) {
_packetRequestCallback->ResendPackets(&nackList[0], length); _packetRequestCallback->ResendPackets(&nackList[0], length);
} }
} }
} }
}
return returnValue; return returnValue;
} }
@ -452,7 +464,7 @@ int32_t VideoReceiver::RequestSliceLossIndication(
int32_t VideoReceiver::RequestKeyFrame() { int32_t VideoReceiver::RequestKeyFrame() {
TRACE_EVENT0("webrtc", "RequestKeyFrame"); TRACE_EVENT0("webrtc", "RequestKeyFrame");
CriticalSectionScoped cs(process_crit_sect_.get()); CriticalSectionScoped process_cs(process_crit_sect_.get());
if (_frameTypeCallback != NULL) { if (_frameTypeCallback != NULL) {
const int32_t ret = _frameTypeCallback->RequestKeyFrame(); const int32_t ret = _frameTypeCallback->RequestKeyFrame();
if (ret < 0) { if (ret < 0) {
@ -547,6 +559,7 @@ int32_t VideoReceiver::Decode(const VCMEncodedFrame& frame) {
int32_t ret = _decoder->Decode(frame, clock_->TimeInMilliseconds()); int32_t ret = _decoder->Decode(frame, clock_->TimeInMilliseconds());
// Check for failed decoding, run frame type request callback if needed. // Check for failed decoding, run frame type request callback if needed.
bool request_key_frame = false;
if (ret < 0) { if (ret < 0) {
if (ret == VCM_ERROR_REQUEST_SLI) { if (ret == VCM_ERROR_REQUEST_SLI) {
return RequestSliceLossIndication( return RequestSliceLossIndication(
@ -557,44 +570,46 @@ int32_t VideoReceiver::Decode(const VCMEncodedFrame& frame) {
VCMId(_id), VCMId(_id),
"Failed to decode frame %u, requesting key frame", "Failed to decode frame %u, requesting key frame",
frame.TimeStamp()); frame.TimeStamp());
ret = RequestKeyFrame(); request_key_frame = true;
} }
} else if (ret == VCM_REQUEST_SLI) { } else if (ret == VCM_REQUEST_SLI) {
ret = RequestSliceLossIndication( ret = RequestSliceLossIndication(
_decodedFrameCallback.LastReceivedPictureID() + 1); _decodedFrameCallback.LastReceivedPictureID() + 1);
} }
if (!frame.Complete() || frame.MissingFrame()) { if (!frame.Complete() || frame.MissingFrame()) {
CriticalSectionScoped cs(process_crit_sect_.get());
switch (_keyRequestMode) { switch (_keyRequestMode) {
case kKeyOnKeyLoss: { case kKeyOnKeyLoss: {
if (frame.FrameType() == kVideoFrameKey) { if (frame.FrameType() == kVideoFrameKey) {
_scheduleKeyRequest = true; request_key_frame = true;
return VCM_OK; ret = VCM_OK;
} }
break; break;
} }
case kKeyOnLoss: { case kKeyOnLoss: {
_scheduleKeyRequest = true; request_key_frame = true;
return VCM_OK; ret = VCM_OK;
} }
default: default:
break; break;
} }
} }
if (request_key_frame) {
CriticalSectionScoped cs(process_crit_sect_.get());
_scheduleKeyRequest = true;
}
TRACE_EVENT_ASYNC_END0("webrtc", "Video", frame.TimeStamp()); TRACE_EVENT_ASYNC_END0("webrtc", "Video", frame.TimeStamp());
return ret; return ret;
} }
// Reset the decoder state // Reset the decoder state
int32_t VideoReceiver::ResetDecoder() { int32_t VideoReceiver::ResetDecoder() {
bool reset_key_request = false;
{
CriticalSectionScoped cs(_receiveCritSect); CriticalSectionScoped cs(_receiveCritSect);
if (_decoder != NULL) { if (_decoder != NULL) {
_receiver.Initialize(); _receiver.Initialize();
_timing.Reset(); _timing.Reset();
{ reset_key_request = true;
CriticalSectionScoped cs(process_crit_sect_.get());
_scheduleKeyRequest = false;
}
_decoder->Reset(); _decoder->Reset();
} }
if (_dualReceiver.State() != kPassive) { if (_dualReceiver.State() != kPassive) {
@ -604,6 +619,11 @@ int32_t VideoReceiver::ResetDecoder() {
_codecDataBase.ReleaseDecoder(_dualDecoder); _codecDataBase.ReleaseDecoder(_dualDecoder);
_dualDecoder = NULL; _dualDecoder = NULL;
} }
}
if (reset_key_request) {
CriticalSectionScoped cs(process_crit_sect_.get());
_scheduleKeyRequest = false;
}
return VCM_OK; return VCM_OK;
} }
@ -720,7 +740,6 @@ int32_t VideoReceiver::NackList(uint16_t* nackList, uint16_t* size) {
return VCM_MEMORY; return VCM_MEMORY;
} }
case kNackKeyFrameRequest: { case kNackKeyFrameRequest: {
CriticalSectionScoped cs(_receiveCritSect);
WEBRTC_TRACE(webrtc::kTraceWarning, WEBRTC_TRACE(webrtc::kTraceWarning,
webrtc::kTraceVideoCoding, webrtc::kTraceVideoCoding,
VCMId(_id), VCMId(_id),