AsyncResolver: avoid hanging the WorkerThread.
There's a problem where the destruction of the contained rtc::Thread will join the spawned thread blocked on getaddrinfo(). However, getaddrinfo() is sometimes slow and this behavior hinders packet traffic when it happens. Fix this by using the brand new detachable PlatformThread support. Fixed: b:181572711, webrtc:12659 Change-Id: I0b7e0cca3b8b1b3ed22328d940b1bb95cacb5e24 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/214780 Commit-Queue: Markus Handell <handellm@webrtc.org> Reviewed-by: Tommi <tommi@webrtc.org> Cr-Commit-Position: refs/heads/master@{#33804}
This commit is contained in:
parent
c5bac77159
commit
1366b0f841
@ -795,6 +795,7 @@ rtc_library("threading") {
|
||||
":socket_server",
|
||||
":timeutils",
|
||||
"../api:function_view",
|
||||
"../api:refcountedbase",
|
||||
"../api:scoped_refptr",
|
||||
"../api:sequence_checker",
|
||||
"../api/task_queue",
|
||||
|
||||
@ -10,9 +10,14 @@
|
||||
|
||||
#include "rtc_base/async_resolver.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "api/ref_counted_base.h"
|
||||
#include "rtc_base/synchronization/mutex.h"
|
||||
#include "rtc_base/thread_annotations.h"
|
||||
|
||||
#if defined(WEBRTC_WIN)
|
||||
#include <ws2spi.h>
|
||||
#include <ws2tcpip.h>
|
||||
@ -30,6 +35,7 @@
|
||||
#include "api/task_queue/task_queue_base.h"
|
||||
#include "rtc_base/ip_address.h"
|
||||
#include "rtc_base/logging.h"
|
||||
#include "rtc_base/platform_thread.h"
|
||||
#include "rtc_base/task_queue.h"
|
||||
#include "rtc_base/task_utils/to_queued_task.h"
|
||||
#include "rtc_base/third_party/sigslot/sigslot.h" // for signal_with_thread...
|
||||
@ -87,30 +93,67 @@ int ResolveHostname(const std::string& hostname,
|
||||
#endif // !__native_client__
|
||||
}
|
||||
|
||||
AsyncResolver::AsyncResolver() : error_(-1) {}
|
||||
struct AsyncResolver::State : public RefCountedBase {
|
||||
webrtc::Mutex mutex;
|
||||
enum class Status {
|
||||
kLive,
|
||||
kDead
|
||||
} status RTC_GUARDED_BY(mutex) = Status::kLive;
|
||||
};
|
||||
|
||||
AsyncResolver::AsyncResolver() : error_(-1), state_(new State) {}
|
||||
|
||||
AsyncResolver::~AsyncResolver() {
|
||||
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
||||
|
||||
// Ensure the thread isn't using a stale reference to the current task queue,
|
||||
// or calling into ResolveDone post destruction.
|
||||
webrtc::MutexLock lock(&state_->mutex);
|
||||
state_->status = State::Status::kDead;
|
||||
}
|
||||
|
||||
void RunResolution(void* obj) {
|
||||
std::function<void()>* function_ptr =
|
||||
static_cast<std::function<void()>*>(obj);
|
||||
(*function_ptr)();
|
||||
delete function_ptr;
|
||||
}
|
||||
|
||||
void AsyncResolver::Start(const SocketAddress& addr) {
|
||||
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
||||
RTC_DCHECK(!destroy_called_);
|
||||
addr_ = addr;
|
||||
webrtc::TaskQueueBase* current_task_queue = webrtc::TaskQueueBase::Current();
|
||||
popup_thread_ = Thread::Create();
|
||||
popup_thread_->Start();
|
||||
popup_thread_->PostTask(webrtc::ToQueuedTask(
|
||||
[this, flag = safety_.flag(), addr, current_task_queue] {
|
||||
auto thread_function =
|
||||
[this, addr, caller_task_queue = webrtc::TaskQueueBase::Current(),
|
||||
state = state_] {
|
||||
std::vector<IPAddress> addresses;
|
||||
int error =
|
||||
ResolveHostname(addr.hostname().c_str(), addr.family(), &addresses);
|
||||
current_task_queue->PostTask(webrtc::ToQueuedTask(
|
||||
std::move(flag), [this, error, addresses = std::move(addresses)] {
|
||||
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
||||
ResolveDone(std::move(addresses), error);
|
||||
}));
|
||||
}));
|
||||
webrtc::MutexLock lock(&state->mutex);
|
||||
if (state->status == State::Status::kLive) {
|
||||
caller_task_queue->PostTask(webrtc::ToQueuedTask(
|
||||
[this, error, addresses = std::move(addresses), state] {
|
||||
bool live;
|
||||
{
|
||||
// ResolveDone can lead to instance destruction, so make sure
|
||||
// we don't deadlock.
|
||||
webrtc::MutexLock lock(&state->mutex);
|
||||
live = state->status == State::Status::kLive;
|
||||
}
|
||||
if (live) {
|
||||
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
||||
ResolveDone(std::move(addresses), error);
|
||||
}
|
||||
}));
|
||||
}
|
||||
};
|
||||
PlatformThread thread(RunResolution,
|
||||
new std::function<void()>(std::move(thread_function)),
|
||||
"NameResolution", ThreadAttributes().SetDetached());
|
||||
thread.Start();
|
||||
// Although |thread| is detached, the PlatformThread contract mandates to call
|
||||
// Stop() before destruction. The call doesn't actually stop anything.
|
||||
thread.Stop();
|
||||
}
|
||||
|
||||
bool AsyncResolver::GetResolvedAddress(int family, SocketAddress* addr) const {
|
||||
|
||||
@ -17,12 +17,13 @@
|
||||
#include <winsock2.h> // NOLINT
|
||||
#endif
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "api/sequence_checker.h"
|
||||
#include "rtc_base/async_resolver_interface.h"
|
||||
#include "rtc_base/event.h"
|
||||
#include "rtc_base/ip_address.h"
|
||||
#include "rtc_base/ref_counted_object.h"
|
||||
#include "rtc_base/socket_address.h"
|
||||
#include "rtc_base/system/no_unique_address.h"
|
||||
#include "rtc_base/system/rtc_export.h"
|
||||
@ -52,6 +53,9 @@ class RTC_EXPORT AsyncResolver : public AsyncResolverInterface {
|
||||
const std::vector<IPAddress>& addresses() const;
|
||||
|
||||
private:
|
||||
// Fwd decl.
|
||||
struct State;
|
||||
|
||||
void ResolveDone(std::vector<IPAddress> addresses, int error)
|
||||
RTC_EXCLUSIVE_LOCKS_REQUIRED(sequence_checker_);
|
||||
void MaybeSelfDestruct();
|
||||
@ -59,11 +63,10 @@ class RTC_EXPORT AsyncResolver : public AsyncResolverInterface {
|
||||
SocketAddress addr_ RTC_GUARDED_BY(sequence_checker_);
|
||||
std::vector<IPAddress> addresses_ RTC_GUARDED_BY(sequence_checker_);
|
||||
int error_ RTC_GUARDED_BY(sequence_checker_);
|
||||
webrtc::ScopedTaskSafety safety_ RTC_GUARDED_BY(sequence_checker_);
|
||||
std::unique_ptr<Thread> popup_thread_ RTC_GUARDED_BY(sequence_checker_);
|
||||
bool recursion_check_ =
|
||||
false; // Protects against SignalDone calling into Destroy.
|
||||
bool destroy_called_ = false;
|
||||
scoped_refptr<State> state_;
|
||||
RTC_NO_UNIQUE_ADDRESS webrtc::SequenceChecker sequence_checker_;
|
||||
};
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user