Allow DtlsTransport::Information() to be called off-thread
Bug: chromium:907849
Change-Id: I7e89aa21f26cbd858fa9845375681e5e6781fece
Reviewed-on: https://webrtc-review.googlesource.com/c/122503
Reviewed-by: Fredrik Solenberg <solenberg@webrtc.org>
Reviewed-by: Henrik Boström <hbos@webrtc.org>
Commit-Queue: Harald Alvestrand <hta@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#26686}
diff --git a/api/dtls_transport_interface.h b/api/dtls_transport_interface.h
index ff3b107..7f35a23 100644
--- a/api/dtls_transport_interface.h
+++ b/api/dtls_transport_interface.h
@@ -55,15 +55,16 @@
};
// A DTLS transport, as represented to the outside world.
-// This object is created on the signaling thread, and can only be
-// accessed on that thread.
+// This object is created on the network thread, and can only be
+// accessed on that thread, except for functions explicitly marked otherwise.
// References can be held by other threads, and destruction can therefore
// be initiated by other threads.
class DtlsTransportInterface : public rtc::RefCountInterface {
public:
// Returns a pointer to the ICE transport that is owned by the DTLS transport.
virtual rtc::scoped_refptr<IceTransportInterface> ice_transport() = 0;
- // These functions can only be called from the signalling thread.
+ // Returns information on the state of the DtlsTransport.
+ // This function can be called from other threads.
virtual DtlsTransportInformation Information() = 0;
// Observer management.
virtual void RegisterObserver(DtlsTransportObserverInterface* observer) = 0;
diff --git a/pc/dtls_transport.cc b/pc/dtls_transport.cc
index 62a75f2..66e2787 100644
--- a/pc/dtls_transport.cc
+++ b/pc/dtls_transport.cc
@@ -43,69 +43,86 @@
// Implementation of DtlsTransportInterface
DtlsTransport::DtlsTransport(
std::unique_ptr<cricket::DtlsTransportInternal> internal)
- : signaling_thread_(rtc::Thread::Current()),
+ : owner_thread_(rtc::Thread::Current()),
+ info_(DtlsTransportState::kNew),
internal_dtls_transport_(std::move(internal)) {
RTC_DCHECK(internal_dtls_transport_.get());
internal_dtls_transport_->SignalDtlsState.connect(
this, &DtlsTransport::OnInternalDtlsState);
ice_transport_ = new rtc::RefCountedObject<IceTransportWithPointer>(
internal_dtls_transport_->ice_transport());
+ UpdateInformation();
}
DtlsTransport::~DtlsTransport() {
// We depend on the signaling thread to call Clear() before dropping
// its last reference to this object.
- RTC_DCHECK(signaling_thread_->IsCurrent() || !internal_dtls_transport_);
+ RTC_DCHECK(owner_thread_->IsCurrent() || !internal_dtls_transport_);
}
DtlsTransportInformation DtlsTransport::Information() {
- RTC_DCHECK(signaling_thread_->IsCurrent());
- if (internal()) {
- return DtlsTransportInformation(TranslateState(internal()->dtls_state()));
- } else {
- return DtlsTransportInformation(DtlsTransportState::kClosed);
- }
+ rtc::CritScope scope(&lock_);
+ return info_;
}
void DtlsTransport::RegisterObserver(DtlsTransportObserverInterface* observer) {
- RTC_DCHECK(signaling_thread_->IsCurrent());
+ RTC_DCHECK_RUN_ON(owner_thread_);
RTC_DCHECK(observer);
observer_ = observer;
}
void DtlsTransport::UnregisterObserver() {
- RTC_DCHECK(signaling_thread_->IsCurrent());
+ RTC_DCHECK_RUN_ON(owner_thread_);
observer_ = nullptr;
}
rtc::scoped_refptr<IceTransportInterface> DtlsTransport::ice_transport() {
+ RTC_DCHECK_RUN_ON(owner_thread_);
+ rtc::CritScope scope(&lock_);
return ice_transport_;
}
// Internal functions
void DtlsTransport::Clear() {
- RTC_DCHECK(signaling_thread_->IsCurrent());
+ RTC_DCHECK_RUN_ON(owner_thread_);
RTC_DCHECK(internal());
- if (internal()->dtls_state() != cricket::DTLS_TRANSPORT_CLOSED) {
- internal_dtls_transport_.reset();
- if (observer_) {
- observer_->OnStateChange(Information());
- }
- } else {
- internal_dtls_transport_.reset();
+ bool must_send_event =
+ (internal()->dtls_state() != cricket::DTLS_TRANSPORT_CLOSED);
+ // The destructor of cricket::DtlsTransportInternal calls back
+ // into DtlsTransport, so we can't hold the lock while releasing.
+ std::unique_ptr<cricket::DtlsTransportInternal> transport_to_release;
+ {
+ rtc::CritScope scope(&lock_);
+ transport_to_release = std::move(internal_dtls_transport_);
+ ice_transport_->Clear();
}
- ice_transport_->Clear();
+ UpdateInformation();
+ if (observer_ && must_send_event) {
+ observer_->OnStateChange(Information());
+ }
}
void DtlsTransport::OnInternalDtlsState(
cricket::DtlsTransportInternal* transport,
cricket::DtlsTransportState state) {
- RTC_DCHECK(signaling_thread_->IsCurrent());
+ RTC_DCHECK_RUN_ON(owner_thread_);
RTC_DCHECK(transport == internal());
RTC_DCHECK(state == internal()->dtls_state());
+ UpdateInformation();
if (observer_) {
observer_->OnStateChange(Information());
}
}
+void DtlsTransport::UpdateInformation() {
+ RTC_DCHECK_RUN_ON(owner_thread_);
+ rtc::CritScope scope(&lock_);
+ if (internal_dtls_transport_) {
+ info_ = DtlsTransportInformation(
+ TranslateState(internal_dtls_transport_->dtls_state()));
+ } else {
+ info_ = DtlsTransportInformation(DtlsTransportState::kClosed);
+ }
+}
+
} // namespace webrtc
diff --git a/pc/dtls_transport.h b/pc/dtls_transport.h
index 535c7eb..0251716 100644
--- a/pc/dtls_transport.h
+++ b/pc/dtls_transport.h
@@ -28,7 +28,11 @@
class DtlsTransport : public DtlsTransportInterface,
public sigslot::has_slots<> {
public:
- // This object must be constructed on the signaling thread.
+ // This object must be constructed and updated on a consistent thread,
+ // the same thread as the one the cricket::DtlsTransportInternal object
+ // lives on.
+ // The Information() function can be called from a different thread,
+ // such as the signalling thread.
explicit DtlsTransport(
std::unique_ptr<cricket::DtlsTransportInternal> internal);
@@ -39,10 +43,12 @@
void Clear();
cricket::DtlsTransportInternal* internal() {
+ rtc::CritScope scope(&lock_);
return internal_dtls_transport_.get();
}
const cricket::DtlsTransportInternal* internal() const {
+ rtc::CritScope scope(&lock_);
return internal_dtls_transport_.get();
}
@@ -52,11 +58,16 @@
private:
void OnInternalDtlsState(cricket::DtlsTransportInternal* transport,
cricket::DtlsTransportState state);
+ void UpdateInformation();
DtlsTransportObserverInterface* observer_ = nullptr;
- rtc::Thread* signaling_thread_;
- std::unique_ptr<cricket::DtlsTransportInternal> internal_dtls_transport_;
- rtc::scoped_refptr<IceTransportWithPointer> ice_transport_;
+ rtc::Thread* owner_thread_;
+ rtc::CriticalSection lock_;
+ DtlsTransportInformation info_ RTC_GUARDED_BY(lock_);
+ std::unique_ptr<cricket::DtlsTransportInternal> internal_dtls_transport_
+ RTC_GUARDED_BY(lock_);
+ rtc::scoped_refptr<IceTransportWithPointer> ice_transport_
+ RTC_GUARDED_BY(lock_);
};
} // namespace webrtc