Fix BaseChannel destructor when network thread differ from worker thread
BUG=webrtc:5645
R=pthatcher@webrtc.org
Review URL: https://codereview.webrtc.org/1970223002 .
Cr-Commit-Position: refs/heads/master@{#12740}
diff --git a/webrtc/pc/channel.cc b/webrtc/pc/channel.cc
index 7e4d5d2..67c16ec 100644
--- a/webrtc/pc/channel.cc
+++ b/webrtc/pc/channel.cc
@@ -183,8 +183,6 @@
ASSERT(worker_thread_ == rtc::Thread::Current());
Deinit();
StopConnectionMonitor();
- // Send any outstanding RTCP packets.
- network_thread_->Invoke<void>(Bind(&BaseChannel::FlushRtcpMessages_n, this));
// Eats any outstanding messages or packets.
worker_thread_->Clear(&invoker_);
worker_thread_->Clear(this);
@@ -194,21 +192,40 @@
delete media_channel_;
// Note that we don't just call SetTransportChannel_n(nullptr) because that
// would call a pure virtual method which we can't do from a destructor.
- network_thread_->Invoke<void>(Bind(&BaseChannel::DeinitNetwork_n, this));
+ network_thread_->Invoke<void>(
+ Bind(&BaseChannel::DestroyTransportChannels_n, this));
LOG(LS_INFO) << "Destroyed channel";
}
-void BaseChannel::DeinitNetwork_n() {
+void BaseChannel::DisconnectTransportChannels_n() {
+ // Send any outstanding RTCP packets.
+ FlushRtcpMessages_n();
+
+ // Stop signals from transport channels, but keep them alive because
+ // media_channel may use them from a different thread.
if (transport_channel_) {
DisconnectFromTransportChannel(transport_channel_);
+ }
+ if (rtcp_transport_channel_) {
+ DisconnectFromTransportChannel(rtcp_transport_channel_);
+ }
+
+ // Clear pending read packets/messages.
+ network_thread_->Clear(&invoker_);
+ network_thread_->Clear(this);
+}
+
+void BaseChannel::DestroyTransportChannels_n() {
+ if (transport_channel_) {
transport_controller_->DestroyTransportChannel_n(
transport_name_, cricket::ICE_CANDIDATE_COMPONENT_RTP);
}
if (rtcp_transport_channel_) {
- DisconnectFromTransportChannel(rtcp_transport_channel_);
transport_controller_->DestroyTransportChannel_n(
transport_name_, cricket::ICE_CANDIDATE_COMPONENT_RTCP);
}
+ // Clear pending send packets/messages.
+ network_thread_->Clear(&invoker_);
network_thread_->Clear(this);
}
@@ -243,6 +260,11 @@
void BaseChannel::Deinit() {
RTC_DCHECK(worker_thread_->IsCurrent());
media_channel_->SetInterface(NULL);
+ // Packets arrive on the network thread, processing packets calls virtual
+ // functions, so need to stop this process in Deinit that is called in
+ // derived classes destructor.
+ network_thread_->Invoke<void>(
+ Bind(&BaseChannel::DisconnectTransportChannels_n, this));
}
bool BaseChannel::SetTransport(const std::string& transport_name) {
diff --git a/webrtc/pc/channel.h b/webrtc/pc/channel.h
index df75245..2f66f12 100644
--- a/webrtc/pc/channel.h
+++ b/webrtc/pc/channel.h
@@ -314,7 +314,8 @@
private:
bool InitNetwork_n();
- void DeinitNetwork_n();
+ void DisconnectTransportChannels_n();
+ void DestroyTransportChannels_n();
void SignalSentPacket_n(TransportChannel* channel,
const rtc::SentPacket& sent_packet);
void SignalSentPacket_w(const rtc::SentPacket& sent_packet);
diff --git a/webrtc/pc/channel_unittest.cc b/webrtc/pc/channel_unittest.cc
index d15748f..81339cf 100644
--- a/webrtc/pc/channel_unittest.cc
+++ b/webrtc/pc/channel_unittest.cc
@@ -1000,6 +1000,19 @@
EXPECT_TRUE(CheckNoRtp2());
}
+ void TestDeinit() {
+ CreateChannels(RTCP, RTCP);
+ EXPECT_TRUE(SendInitiate());
+ EXPECT_TRUE(SendAccept());
+ SendRtp1();
+ SendRtp2();
+ SendRtcp1();
+ SendRtcp2();
+ // Do not wait, destroy channels.
+ channel1_.reset(nullptr);
+ channel2_.reset(nullptr);
+ }
+
// Check that RTCP is not transmitted if both sides don't support RTCP.
void SendNoRtcpToNoRtcp() {
CreateChannels(0, 0);
@@ -2076,6 +2089,10 @@
EXPECT_TRUE(media_channel1_->dtmf_info_queue().empty());
}
+TEST_F(VoiceChannelSingleThreadTest, TestDeinit) {
+ Base::TestDeinit();
+}
+
TEST_F(VoiceChannelSingleThreadTest, TestSetContents) {
Base::TestSetContents();
}
@@ -2402,6 +2419,10 @@
EXPECT_TRUE(media_channel1_->dtmf_info_queue().empty());
}
+TEST_F(VoiceChannelDoubleThreadTest, TestDeinit) {
+ Base::TestDeinit();
+}
+
TEST_F(VoiceChannelDoubleThreadTest, TestSetContents) {
Base::TestSetContents();
}
@@ -2726,6 +2747,10 @@
Base::TestInit();
}
+TEST_F(VideoChannelSingleThreadTest, TestDeinit) {
+ Base::TestDeinit();
+}
+
TEST_F(VideoChannelSingleThreadTest, TestSetContents) {
Base::TestSetContents();
}
@@ -2966,6 +2991,10 @@
Base::TestInit();
}
+TEST_F(VideoChannelDoubleThreadTest, TestDeinit) {
+ Base::TestDeinit();
+}
+
TEST_F(VideoChannelDoubleThreadTest, TestSetContents) {
Base::TestSetContents();
}
@@ -3277,6 +3306,10 @@
EXPECT_FALSE(media_channel1_->IsStreamMuted(0));
}
+TEST_F(DataChannelSingleThreadTest, TestDeinit) {
+ Base::TestDeinit();
+}
+
TEST_F(DataChannelSingleThreadTest, TestSetContents) {
Base::TestSetContents();
}
@@ -3417,6 +3450,10 @@
EXPECT_FALSE(media_channel1_->IsStreamMuted(0));
}
+TEST_F(DataChannelDoubleThreadTest, TestDeinit) {
+ Base::TestDeinit();
+}
+
TEST_F(DataChannelDoubleThreadTest, TestSetContents) {
Base::TestSetContents();
}