Delete Channels without ChannelManager lock.
Triggered Helgrind error, as deleting a Channel will also unregister a
module which has called GetChannel(), resulting in a cyclic lock graph.
This change will also allow other threads to access the ChannelManager
instance while Channels are deleted.
R=xians@webrtc.org
Review URL: https://webrtc-codereview.appspot.com/1946005
git-svn-id: http://webrtc.googlecode.com/svn/trunk/webrtc@4505 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/voice_engine/channel_manager.cc b/voice_engine/channel_manager.cc
index 6cf935d..8110bb6 100644
--- a/voice_engine/channel_manager.cc
+++ b/voice_engine/channel_manager.cc
@@ -78,22 +78,34 @@
}
void ChannelManager::DestroyChannel(int32_t channel_id) {
- CriticalSectionScoped crit(lock_.get());
assert(channel_id >= 0);
+ // Holds a reference to a channel, this is used so that we never delete
+ // Channels while holding a lock, but rather when the method returns.
+ ChannelOwner reference(NULL);
+ {
+ CriticalSectionScoped crit(lock_.get());
- for (std::vector<ChannelOwner>::iterator it = channels_.begin();
- it != channels_.end();
- ++it) {
- if (it->channel()->ChannelId() == channel_id) {
- channels_.erase(it);
- break;
+ for (std::vector<ChannelOwner>::iterator it = channels_.begin();
+ it != channels_.end();
+ ++it) {
+ if (it->channel()->ChannelId() == channel_id) {
+ reference = *it;
+ channels_.erase(it);
+ break;
+ }
}
}
}
void ChannelManager::DestroyAllChannels() {
- CriticalSectionScoped crit(lock_.get());
- channels_.clear();
+ // Holds references so that Channels are not destroyed while holding this
+ // lock, but rather when the method returns.
+ std::vector<ChannelOwner> references;
+ {
+ CriticalSectionScoped crit(lock_.get());
+ references = channels_;
+ channels_.clear();
+ }
}
size_t ChannelManager::NumOfChannels() const {