mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-13 22:00:47 +01:00

This CL was generated by running git ls-files | grep -P "(\.h|\.cc)$" | grep -v 'sdk/' | grep -v 'rtc_base/ssl_' | \ grep -v 'fake_rtc_certificate_generator.h' | grep -v 'modules/audio_device/win/' | \ grep -v 'system_wrappers/source/clock.cc' | grep -v 'rtc_base/trace_event.h' | \ grep -v 'modules/audio_coding/codecs/ilbc/' | grep -v 'screen_capturer_mac.h' | \ grep -v 'spl_inl_mips.h' | grep -v 'data_size_unittest.cc' | grep -v 'timestamp_unittest.cc' \ | xargs clang-format -i ; git cl format Most of these changes are clang-format grouping and reordering includes differently. Bug: webrtc:9340 Change-Id: Ic83ddbc169bfacd21883e381b5181c3dd4fe8a63 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/144051 Commit-Queue: Jonas Olsson <jonasolsson@webrtc.org> Reviewed-by: Karl Wiberg <kwiberg@webrtc.org> Cr-Commit-Position: refs/heads/master@{#28505}
621 lines
17 KiB
C++
621 lines
17 KiB
C++
/*
|
|
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license
|
|
* that can be found in the LICENSE file in the root of the source
|
|
* tree. An additional intellectual property rights grant can be found
|
|
* in the file PATENTS. All contributing project authors may
|
|
* be found in the AUTHORS file in the root of the source tree.
|
|
*/
|
|
|
|
#include "rtc_base/thread.h"
|
|
|
|
#if defined(WEBRTC_WIN)
|
|
#include <comdef.h>
|
|
#elif defined(WEBRTC_POSIX)
|
|
#include <time.h>
|
|
#else
|
|
#error "Either WEBRTC_WIN or WEBRTC_POSIX needs to be defined."
|
|
#endif
|
|
|
|
#if defined(WEBRTC_WIN)
|
|
// Disable warning that we don't care about:
|
|
// warning C4722: destructor never returns, potential memory leak
|
|
#pragma warning(disable : 4722)
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <utility>
|
|
|
|
#include "rtc_base/checks.h"
|
|
#include "rtc_base/critical_section.h"
|
|
#include "rtc_base/logging.h"
|
|
#include "rtc_base/null_socket_server.h"
|
|
#include "rtc_base/time_utils.h"
|
|
#include "rtc_base/trace_event.h"
|
|
|
|
#if defined(WEBRTC_MAC)
|
|
#include "rtc_base/system/cocoa_threading.h"
|
|
|
|
/*
|
|
* These are forward-declarations for methods that are part of the
|
|
* ObjC runtime. They are declared in the private header objc-internal.h.
|
|
* These calls are what clang inserts when using @autoreleasepool in ObjC,
|
|
* but here they are used directly in order to keep this file C++.
|
|
* https://clang.llvm.org/docs/AutomaticReferenceCounting.html#runtime-support
|
|
*/
|
|
extern "C" {
|
|
void* objc_autoreleasePoolPush(void);
|
|
void objc_autoreleasePoolPop(void* pool);
|
|
}
|
|
|
|
namespace {
|
|
class ScopedAutoReleasePool {
|
|
public:
|
|
ScopedAutoReleasePool() : pool_(objc_autoreleasePoolPush()) {}
|
|
~ScopedAutoReleasePool() { objc_autoreleasePoolPop(pool_); }
|
|
|
|
private:
|
|
void* const pool_;
|
|
};
|
|
} // namespace
|
|
#endif
|
|
|
|
namespace rtc {
|
|
|
|
ThreadManager* ThreadManager::Instance() {
|
|
static ThreadManager* const thread_manager = new ThreadManager();
|
|
return thread_manager;
|
|
}
|
|
|
|
ThreadManager::~ThreadManager() {
|
|
// By above RTC_DEFINE_STATIC_LOCAL.
|
|
RTC_NOTREACHED() << "ThreadManager should never be destructed.";
|
|
}
|
|
|
|
// static
|
|
Thread* Thread::Current() {
|
|
ThreadManager* manager = ThreadManager::Instance();
|
|
Thread* thread = manager->CurrentThread();
|
|
|
|
#ifndef NO_MAIN_THREAD_WRAPPING
|
|
// Only autowrap the thread which instantiated the ThreadManager.
|
|
if (!thread && manager->IsMainThread()) {
|
|
thread = new Thread(SocketServer::CreateDefault());
|
|
thread->WrapCurrentWithThreadManager(manager, true);
|
|
}
|
|
#endif
|
|
|
|
return thread;
|
|
}
|
|
|
|
#if defined(WEBRTC_POSIX)
|
|
ThreadManager::ThreadManager() : main_thread_ref_(CurrentThreadRef()) {
|
|
#if defined(WEBRTC_MAC)
|
|
InitCocoaMultiThreading();
|
|
#endif
|
|
pthread_key_create(&key_, nullptr);
|
|
}
|
|
|
|
Thread* ThreadManager::CurrentThread() {
|
|
return static_cast<Thread*>(pthread_getspecific(key_));
|
|
}
|
|
|
|
void ThreadManager::SetCurrentThread(Thread* thread) {
|
|
#if RTC_DLOG_IS_ON
|
|
if (CurrentThread() && thread) {
|
|
RTC_DLOG(LS_ERROR) << "SetCurrentThread: Overwriting an existing value?";
|
|
}
|
|
#endif // RTC_DLOG_IS_ON
|
|
pthread_setspecific(key_, thread);
|
|
}
|
|
#endif
|
|
|
|
#if defined(WEBRTC_WIN)
|
|
ThreadManager::ThreadManager()
|
|
: key_(TlsAlloc()), main_thread_ref_(CurrentThreadRef()) {}
|
|
|
|
Thread* ThreadManager::CurrentThread() {
|
|
return static_cast<Thread*>(TlsGetValue(key_));
|
|
}
|
|
|
|
void ThreadManager::SetCurrentThread(Thread* thread) {
|
|
RTC_DCHECK(!CurrentThread() || !thread);
|
|
TlsSetValue(key_, thread);
|
|
}
|
|
#endif
|
|
|
|
Thread* ThreadManager::WrapCurrentThread() {
|
|
Thread* result = CurrentThread();
|
|
if (nullptr == result) {
|
|
result = new Thread(SocketServer::CreateDefault());
|
|
result->WrapCurrentWithThreadManager(this, true);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
void ThreadManager::UnwrapCurrentThread() {
|
|
Thread* t = CurrentThread();
|
|
if (t && !(t->IsOwned())) {
|
|
t->UnwrapCurrent();
|
|
delete t;
|
|
}
|
|
}
|
|
|
|
bool ThreadManager::IsMainThread() {
|
|
return IsThreadRefEqual(CurrentThreadRef(), main_thread_ref_);
|
|
}
|
|
|
|
Thread::ScopedDisallowBlockingCalls::ScopedDisallowBlockingCalls()
|
|
: thread_(Thread::Current()),
|
|
previous_state_(thread_->SetAllowBlockingCalls(false)) {}
|
|
|
|
Thread::ScopedDisallowBlockingCalls::~ScopedDisallowBlockingCalls() {
|
|
RTC_DCHECK(thread_->IsCurrent());
|
|
thread_->SetAllowBlockingCalls(previous_state_);
|
|
}
|
|
|
|
Thread::Thread(SocketServer* ss) : Thread(ss, /*do_init=*/true) {}
|
|
|
|
Thread::Thread(std::unique_ptr<SocketServer> ss)
|
|
: Thread(std::move(ss), /*do_init=*/true) {}
|
|
|
|
Thread::Thread(SocketServer* ss, bool do_init)
|
|
: MessageQueue(ss, /*do_init=*/false) {
|
|
SetName("Thread", this); // default name
|
|
if (do_init) {
|
|
DoInit();
|
|
}
|
|
}
|
|
|
|
Thread::Thread(std::unique_ptr<SocketServer> ss, bool do_init)
|
|
: MessageQueue(std::move(ss), false) {
|
|
SetName("Thread", this); // default name
|
|
if (do_init) {
|
|
DoInit();
|
|
}
|
|
}
|
|
|
|
Thread::~Thread() {
|
|
Stop();
|
|
DoDestroy();
|
|
}
|
|
|
|
bool Thread::IsCurrent() const {
|
|
return ThreadManager::Instance()->CurrentThread() == this;
|
|
}
|
|
|
|
std::unique_ptr<Thread> Thread::CreateWithSocketServer() {
|
|
return std::unique_ptr<Thread>(new Thread(SocketServer::CreateDefault()));
|
|
}
|
|
|
|
std::unique_ptr<Thread> Thread::Create() {
|
|
return std::unique_ptr<Thread>(
|
|
new Thread(std::unique_ptr<SocketServer>(new NullSocketServer())));
|
|
}
|
|
|
|
bool Thread::SleepMs(int milliseconds) {
|
|
AssertBlockingIsAllowedOnCurrentThread();
|
|
|
|
#if defined(WEBRTC_WIN)
|
|
::Sleep(milliseconds);
|
|
return true;
|
|
#else
|
|
// POSIX has both a usleep() and a nanosleep(), but the former is deprecated,
|
|
// so we use nanosleep() even though it has greater precision than necessary.
|
|
struct timespec ts;
|
|
ts.tv_sec = milliseconds / 1000;
|
|
ts.tv_nsec = (milliseconds % 1000) * 1000000;
|
|
int ret = nanosleep(&ts, nullptr);
|
|
if (ret != 0) {
|
|
RTC_LOG_ERR(LS_WARNING) << "nanosleep() returning early";
|
|
return false;
|
|
}
|
|
return true;
|
|
#endif
|
|
}
|
|
|
|
bool Thread::SetName(const std::string& name, const void* obj) {
|
|
RTC_DCHECK(!IsRunning());
|
|
|
|
name_ = name;
|
|
if (obj) {
|
|
// The %p specifier typically produce at most 16 hex digits, possibly with a
|
|
// 0x prefix. But format is implementation defined, so add some margin.
|
|
char buf[30];
|
|
snprintf(buf, sizeof(buf), " 0x%p", obj);
|
|
name_ += buf;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool Thread::Start() {
|
|
RTC_DCHECK(!IsRunning());
|
|
|
|
if (IsRunning())
|
|
return false;
|
|
|
|
Restart(); // reset IsQuitting() if the thread is being restarted
|
|
|
|
// Make sure that ThreadManager is created on the main thread before
|
|
// we start a new thread.
|
|
ThreadManager::Instance();
|
|
|
|
owned_ = true;
|
|
|
|
#if defined(WEBRTC_WIN)
|
|
thread_ = CreateThread(nullptr, 0, PreRun, this, 0, &thread_id_);
|
|
if (!thread_) {
|
|
return false;
|
|
}
|
|
#elif defined(WEBRTC_POSIX)
|
|
pthread_attr_t attr;
|
|
pthread_attr_init(&attr);
|
|
|
|
int error_code = pthread_create(&thread_, &attr, PreRun, this);
|
|
if (0 != error_code) {
|
|
RTC_LOG(LS_ERROR) << "Unable to create pthread, error " << error_code;
|
|
thread_ = 0;
|
|
return false;
|
|
}
|
|
RTC_DCHECK(thread_);
|
|
#endif
|
|
return true;
|
|
}
|
|
|
|
bool Thread::WrapCurrent() {
|
|
return WrapCurrentWithThreadManager(ThreadManager::Instance(), true);
|
|
}
|
|
|
|
void Thread::UnwrapCurrent() {
|
|
// Clears the platform-specific thread-specific storage.
|
|
ThreadManager::Instance()->SetCurrentThread(nullptr);
|
|
#if defined(WEBRTC_WIN)
|
|
if (thread_ != nullptr) {
|
|
if (!CloseHandle(thread_)) {
|
|
RTC_LOG_GLE(LS_ERROR)
|
|
<< "When unwrapping thread, failed to close handle.";
|
|
}
|
|
thread_ = nullptr;
|
|
thread_id_ = 0;
|
|
}
|
|
#elif defined(WEBRTC_POSIX)
|
|
thread_ = 0;
|
|
#endif
|
|
}
|
|
|
|
void Thread::SafeWrapCurrent() {
|
|
WrapCurrentWithThreadManager(ThreadManager::Instance(), false);
|
|
}
|
|
|
|
void Thread::Join() {
|
|
if (!IsRunning())
|
|
return;
|
|
|
|
RTC_DCHECK(!IsCurrent());
|
|
if (Current() && !Current()->blocking_calls_allowed_) {
|
|
RTC_LOG(LS_WARNING) << "Waiting for the thread to join, "
|
|
<< "but blocking calls have been disallowed";
|
|
}
|
|
|
|
#if defined(WEBRTC_WIN)
|
|
RTC_DCHECK(thread_ != nullptr);
|
|
WaitForSingleObject(thread_, INFINITE);
|
|
CloseHandle(thread_);
|
|
thread_ = nullptr;
|
|
thread_id_ = 0;
|
|
#elif defined(WEBRTC_POSIX)
|
|
pthread_join(thread_, nullptr);
|
|
thread_ = 0;
|
|
#endif
|
|
}
|
|
|
|
bool Thread::SetAllowBlockingCalls(bool allow) {
|
|
RTC_DCHECK(IsCurrent());
|
|
bool previous = blocking_calls_allowed_;
|
|
blocking_calls_allowed_ = allow;
|
|
return previous;
|
|
}
|
|
|
|
// static
|
|
void Thread::AssertBlockingIsAllowedOnCurrentThread() {
|
|
#if !defined(NDEBUG)
|
|
Thread* current = Thread::Current();
|
|
RTC_DCHECK(!current || current->blocking_calls_allowed_);
|
|
#endif
|
|
}
|
|
|
|
// static
|
|
#if defined(WEBRTC_WIN)
|
|
DWORD WINAPI Thread::PreRun(LPVOID pv) {
|
|
#else
|
|
void* Thread::PreRun(void* pv) {
|
|
#endif
|
|
Thread* thread = static_cast<Thread*>(pv);
|
|
ThreadManager::Instance()->SetCurrentThread(thread);
|
|
rtc::SetCurrentThreadName(thread->name_.c_str());
|
|
#if defined(WEBRTC_MAC)
|
|
ScopedAutoReleasePool pool;
|
|
#endif
|
|
thread->Run();
|
|
|
|
ThreadManager::Instance()->SetCurrentThread(nullptr);
|
|
#ifdef WEBRTC_WIN
|
|
return 0;
|
|
#else
|
|
return nullptr;
|
|
#endif
|
|
} // namespace rtc
|
|
|
|
void Thread::Run() {
|
|
ProcessMessages(kForever);
|
|
}
|
|
|
|
bool Thread::IsOwned() {
|
|
RTC_DCHECK(IsRunning());
|
|
return owned_;
|
|
}
|
|
|
|
void Thread::Stop() {
|
|
MessageQueue::Quit();
|
|
Join();
|
|
}
|
|
|
|
void Thread::Send(const Location& posted_from,
|
|
MessageHandler* phandler,
|
|
uint32_t id,
|
|
MessageData* pdata) {
|
|
if (IsQuitting())
|
|
return;
|
|
|
|
// Sent messages are sent to the MessageHandler directly, in the context
|
|
// of "thread", like Win32 SendMessage. If in the right context,
|
|
// call the handler directly.
|
|
Message msg;
|
|
msg.posted_from = posted_from;
|
|
msg.phandler = phandler;
|
|
msg.message_id = id;
|
|
msg.pdata = pdata;
|
|
if (IsCurrent()) {
|
|
phandler->OnMessage(&msg);
|
|
return;
|
|
}
|
|
|
|
AssertBlockingIsAllowedOnCurrentThread();
|
|
|
|
AutoThread thread;
|
|
Thread* current_thread = Thread::Current();
|
|
RTC_DCHECK(current_thread != nullptr); // AutoThread ensures this
|
|
|
|
bool ready = false;
|
|
{
|
|
CritScope cs(&crit_);
|
|
_SendMessage smsg;
|
|
smsg.thread = current_thread;
|
|
smsg.msg = msg;
|
|
smsg.ready = &ready;
|
|
sendlist_.push_back(smsg);
|
|
}
|
|
|
|
// Wait for a reply
|
|
WakeUpSocketServer();
|
|
|
|
bool waited = false;
|
|
crit_.Enter();
|
|
while (!ready) {
|
|
crit_.Leave();
|
|
// We need to limit "ReceiveSends" to |this| thread to avoid an arbitrary
|
|
// thread invoking calls on the current thread.
|
|
current_thread->ReceiveSendsFromThread(this);
|
|
current_thread->socketserver()->Wait(kForever, false);
|
|
waited = true;
|
|
crit_.Enter();
|
|
}
|
|
crit_.Leave();
|
|
|
|
// Our Wait loop above may have consumed some WakeUp events for this
|
|
// MessageQueue, that weren't relevant to this Send. Losing these WakeUps can
|
|
// cause problems for some SocketServers.
|
|
//
|
|
// Concrete example:
|
|
// Win32SocketServer on thread A calls Send on thread B. While processing the
|
|
// message, thread B Posts a message to A. We consume the wakeup for that
|
|
// Post while waiting for the Send to complete, which means that when we exit
|
|
// this loop, we need to issue another WakeUp, or else the Posted message
|
|
// won't be processed in a timely manner.
|
|
|
|
if (waited) {
|
|
current_thread->socketserver()->WakeUp();
|
|
}
|
|
}
|
|
|
|
void Thread::ReceiveSends() {
|
|
ReceiveSendsFromThread(nullptr);
|
|
}
|
|
|
|
void Thread::ReceiveSendsFromThread(const Thread* source) {
|
|
// Receive a sent message. Cleanup scenarios:
|
|
// - thread sending exits: We don't allow this, since thread can exit
|
|
// only via Join, so Send must complete.
|
|
// - thread receiving exits: Wakeup/set ready in Thread::Clear()
|
|
// - object target cleared: Wakeup/set ready in Thread::Clear()
|
|
_SendMessage smsg;
|
|
|
|
crit_.Enter();
|
|
while (PopSendMessageFromThread(source, &smsg)) {
|
|
crit_.Leave();
|
|
|
|
Dispatch(&smsg.msg);
|
|
|
|
crit_.Enter();
|
|
*smsg.ready = true;
|
|
smsg.thread->socketserver()->WakeUp();
|
|
}
|
|
crit_.Leave();
|
|
}
|
|
|
|
bool Thread::PopSendMessageFromThread(const Thread* source, _SendMessage* msg) {
|
|
for (std::list<_SendMessage>::iterator it = sendlist_.begin();
|
|
it != sendlist_.end(); ++it) {
|
|
if (it->thread == source || source == nullptr) {
|
|
*msg = *it;
|
|
sendlist_.erase(it);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void Thread::InvokeInternal(const Location& posted_from,
|
|
MessageHandler* handler) {
|
|
TRACE_EVENT2("webrtc", "Thread::Invoke", "src_file_and_line",
|
|
posted_from.file_and_line(), "src_func",
|
|
posted_from.function_name());
|
|
Send(posted_from, handler);
|
|
}
|
|
|
|
bool Thread::IsProcessingMessagesForTesting() {
|
|
return (owned_ || IsCurrent()) &&
|
|
MessageQueue::IsProcessingMessagesForTesting();
|
|
}
|
|
|
|
void Thread::Clear(MessageHandler* phandler,
|
|
uint32_t id,
|
|
MessageList* removed) {
|
|
CritScope cs(&crit_);
|
|
|
|
// Remove messages on sendlist_ with phandler
|
|
// Object target cleared: remove from send list, wakeup/set ready
|
|
// if sender not null.
|
|
|
|
std::list<_SendMessage>::iterator iter = sendlist_.begin();
|
|
while (iter != sendlist_.end()) {
|
|
_SendMessage smsg = *iter;
|
|
if (smsg.msg.Match(phandler, id)) {
|
|
if (removed) {
|
|
removed->push_back(smsg.msg);
|
|
} else {
|
|
delete smsg.msg.pdata;
|
|
}
|
|
iter = sendlist_.erase(iter);
|
|
*smsg.ready = true;
|
|
smsg.thread->socketserver()->WakeUp();
|
|
continue;
|
|
}
|
|
++iter;
|
|
}
|
|
|
|
ClearInternal(phandler, id, removed);
|
|
}
|
|
|
|
bool Thread::ProcessMessages(int cmsLoop) {
|
|
// Using ProcessMessages with a custom clock for testing and a time greater
|
|
// than 0 doesn't work, since it's not guaranteed to advance the custom
|
|
// clock's time, and may get stuck in an infinite loop.
|
|
RTC_DCHECK(GetClockForTesting() == nullptr || cmsLoop == 0 ||
|
|
cmsLoop == kForever);
|
|
int64_t msEnd = (kForever == cmsLoop) ? 0 : TimeAfter(cmsLoop);
|
|
int cmsNext = cmsLoop;
|
|
|
|
while (true) {
|
|
#if defined(WEBRTC_MAC)
|
|
ScopedAutoReleasePool pool;
|
|
#endif
|
|
Message msg;
|
|
if (!Get(&msg, cmsNext))
|
|
return !IsQuitting();
|
|
Dispatch(&msg);
|
|
|
|
if (cmsLoop != kForever) {
|
|
cmsNext = static_cast<int>(TimeUntil(msEnd));
|
|
if (cmsNext < 0)
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool Thread::WrapCurrentWithThreadManager(ThreadManager* thread_manager,
|
|
bool need_synchronize_access) {
|
|
RTC_DCHECK(!IsRunning());
|
|
|
|
#if defined(WEBRTC_WIN)
|
|
if (need_synchronize_access) {
|
|
// We explicitly ask for no rights other than synchronization.
|
|
// This gives us the best chance of succeeding.
|
|
thread_ = OpenThread(SYNCHRONIZE, FALSE, GetCurrentThreadId());
|
|
if (!thread_) {
|
|
RTC_LOG_GLE(LS_ERROR) << "Unable to get handle to thread.";
|
|
return false;
|
|
}
|
|
thread_id_ = GetCurrentThreadId();
|
|
}
|
|
#elif defined(WEBRTC_POSIX)
|
|
thread_ = pthread_self();
|
|
#endif
|
|
owned_ = false;
|
|
thread_manager->SetCurrentThread(this);
|
|
return true;
|
|
}
|
|
|
|
bool Thread::IsRunning() {
|
|
#if defined(WEBRTC_WIN)
|
|
return thread_ != nullptr;
|
|
#elif defined(WEBRTC_POSIX)
|
|
return thread_ != 0;
|
|
#endif
|
|
}
|
|
|
|
AutoThread::AutoThread()
|
|
: Thread(SocketServer::CreateDefault(), /*do_init=*/false) {
|
|
if (!ThreadManager::Instance()->CurrentThread()) {
|
|
// DoInit registers with MessageQueueManager. Do that only if we intend to
|
|
// be rtc::Thread::Current(), otherwise ProcessAllMessageQueuesInternal will
|
|
// post a message to a queue that no running thread is serving.
|
|
DoInit();
|
|
ThreadManager::Instance()->SetCurrentThread(this);
|
|
}
|
|
}
|
|
|
|
AutoThread::~AutoThread() {
|
|
Stop();
|
|
DoDestroy();
|
|
if (ThreadManager::Instance()->CurrentThread() == this) {
|
|
ThreadManager::Instance()->SetCurrentThread(nullptr);
|
|
}
|
|
}
|
|
|
|
AutoSocketServerThread::AutoSocketServerThread(SocketServer* ss)
|
|
: Thread(ss, /*do_init=*/false) {
|
|
DoInit();
|
|
old_thread_ = ThreadManager::Instance()->CurrentThread();
|
|
// Temporarily set the current thread to nullptr so that we can keep checks
|
|
// around that catch unintentional pointer overwrites.
|
|
rtc::ThreadManager::Instance()->SetCurrentThread(nullptr);
|
|
rtc::ThreadManager::Instance()->SetCurrentThread(this);
|
|
if (old_thread_) {
|
|
MessageQueueManager::Remove(old_thread_);
|
|
}
|
|
}
|
|
|
|
AutoSocketServerThread::~AutoSocketServerThread() {
|
|
RTC_DCHECK(ThreadManager::Instance()->CurrentThread() == this);
|
|
// Some tests post destroy messages to this thread. To avoid memory
|
|
// leaks, we have to process those messages. In particular
|
|
// P2PTransportChannelPingTest, relying on the message posted in
|
|
// cricket::Connection::Destroy.
|
|
ProcessMessages(0);
|
|
// Stop and destroy the thread before clearing it as the current thread.
|
|
// Sometimes there are messages left in the MessageQueue that will be
|
|
// destroyed by DoDestroy, and sometimes the destructors of the message and/or
|
|
// its contents rely on this thread still being set as the current thread.
|
|
Stop();
|
|
DoDestroy();
|
|
rtc::ThreadManager::Instance()->SetCurrentThread(nullptr);
|
|
rtc::ThreadManager::Instance()->SetCurrentThread(old_thread_);
|
|
if (old_thread_) {
|
|
MessageQueueManager::Add(old_thread_);
|
|
}
|
|
}
|
|
|
|
} // namespace rtc
|