2014-05-13 18:00:26 +00:00
|
|
|
/*
|
|
|
|
|
* 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.
|
|
|
|
|
*/
|
|
|
|
|
|
2017-09-15 06:47:31 +02:00
|
|
|
#include "rtc_base/thread.h"
|
2014-05-13 18:00:26 +00:00
|
|
|
|
|
|
|
|
#if defined(WEBRTC_WIN)
|
|
|
|
|
#include <comdef.h>
|
|
|
|
|
#elif defined(WEBRTC_POSIX)
|
|
|
|
|
#include <time.h>
|
2017-12-04 15:18:23 +01:00
|
|
|
#else
|
|
|
|
|
#error "Either WEBRTC_WIN or WEBRTC_POSIX needs to be defined."
|
2014-05-13 18:00:26 +00:00
|
|
|
#endif
|
|
|
|
|
|
2018-05-21 12:20:39 +02:00
|
|
|
#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
|
|
|
|
|
|
2018-10-23 12:03:01 +02:00
|
|
|
#include <stdio.h>
|
2019-07-05 19:08:33 +02:00
|
|
|
|
2018-10-23 12:03:01 +02:00
|
|
|
#include <utility>
|
2018-10-05 15:39:24 +02:00
|
|
|
|
2017-09-15 06:47:31 +02:00
|
|
|
#include "rtc_base/checks.h"
|
2019-01-11 09:11:00 -08:00
|
|
|
#include "rtc_base/critical_section.h"
|
2017-09-15 06:47:31 +02:00
|
|
|
#include "rtc_base/logging.h"
|
2019-01-11 09:11:00 -08:00
|
|
|
#include "rtc_base/null_socket_server.h"
|
|
|
|
|
#include "rtc_base/time_utils.h"
|
2017-09-15 06:47:31 +02:00
|
|
|
#include "rtc_base/trace_event.h"
|
2014-05-13 18:00:26 +00:00
|
|
|
|
2018-10-12 12:57:49 +02:00
|
|
|
#if defined(WEBRTC_MAC)
|
|
|
|
|
#include "rtc_base/system/cocoa_threading.h"
|
2018-10-23 12:03:01 +02:00
|
|
|
|
2018-10-12 12:57:49 +02:00
|
|
|
/*
|
|
|
|
|
* 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
|
|
|
|
|
|
2014-05-13 18:00:26 +00:00
|
|
|
namespace rtc {
|
2019-12-11 11:21:53 -08:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
|
|
class MessageHandlerWithTask final : public MessageHandler {
|
|
|
|
|
public:
|
|
|
|
|
MessageHandlerWithTask() = default;
|
|
|
|
|
|
|
|
|
|
void OnMessage(Message* msg) override {
|
|
|
|
|
static_cast<rtc_thread_internal::MessageLikeTask*>(msg->pdata)->Run();
|
|
|
|
|
delete msg->pdata;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
~MessageHandlerWithTask() override {}
|
|
|
|
|
|
|
|
|
|
RTC_DISALLOW_COPY_AND_ASSIGN(MessageHandlerWithTask);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
} // namespace
|
2014-05-13 18:00:26 +00:00
|
|
|
|
|
|
|
|
ThreadManager* ThreadManager::Instance() {
|
2018-05-24 08:54:25 +02:00
|
|
|
static ThreadManager* const thread_manager = new ThreadManager();
|
|
|
|
|
return thread_manager;
|
2014-05-13 18:00:26 +00:00
|
|
|
}
|
|
|
|
|
|
2017-04-26 01:45:31 -07:00
|
|
|
ThreadManager::~ThreadManager() {
|
|
|
|
|
// By above RTC_DEFINE_STATIC_LOCAL.
|
|
|
|
|
RTC_NOTREACHED() << "ThreadManager should never be destructed.";
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-13 18:00:26 +00:00
|
|
|
// static
|
|
|
|
|
Thread* Thread::Current() {
|
2017-04-26 01:45:31 -07:00
|
|
|
ThreadManager* manager = ThreadManager::Instance();
|
|
|
|
|
Thread* thread = manager->CurrentThread();
|
|
|
|
|
|
2019-05-21 07:26:37 +00:00
|
|
|
#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
|
|
|
|
|
|
2017-04-26 01:45:31 -07:00
|
|
|
return thread;
|
2014-05-13 18:00:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if defined(WEBRTC_POSIX)
|
2019-05-21 07:26:37 +00:00
|
|
|
ThreadManager::ThreadManager() : main_thread_ref_(CurrentThreadRef()) {
|
2018-10-12 12:57:49 +02:00
|
|
|
#if defined(WEBRTC_MAC)
|
|
|
|
|
InitCocoaMultiThreading();
|
|
|
|
|
#endif
|
2017-02-27 14:06:41 -08:00
|
|
|
pthread_key_create(&key_, nullptr);
|
2014-05-13 18:00:26 +00:00
|
|
|
}
|
|
|
|
|
|
2018-06-19 15:03:05 +02:00
|
|
|
Thread* ThreadManager::CurrentThread() {
|
|
|
|
|
return static_cast<Thread*>(pthread_getspecific(key_));
|
2014-05-13 18:00:26 +00:00
|
|
|
}
|
|
|
|
|
|
2017-12-04 20:38:20 +01:00
|
|
|
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
|
2014-05-13 18:00:26 +00:00
|
|
|
pthread_setspecific(key_, thread);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if defined(WEBRTC_WIN)
|
2019-05-21 07:26:37 +00:00
|
|
|
ThreadManager::ThreadManager()
|
|
|
|
|
: key_(TlsAlloc()), main_thread_ref_(CurrentThreadRef()) {}
|
2014-05-13 18:00:26 +00:00
|
|
|
|
2018-06-19 15:03:05 +02:00
|
|
|
Thread* ThreadManager::CurrentThread() {
|
|
|
|
|
return static_cast<Thread*>(TlsGetValue(key_));
|
2014-05-13 18:00:26 +00:00
|
|
|
}
|
|
|
|
|
|
2018-06-19 15:03:05 +02:00
|
|
|
void ThreadManager::SetCurrentThread(Thread* thread) {
|
2017-12-04 15:18:23 +01:00
|
|
|
RTC_DCHECK(!CurrentThread() || !thread);
|
2014-05-13 18:00:26 +00:00
|
|
|
TlsSetValue(key_, thread);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2018-06-19 15:03:05 +02:00
|
|
|
Thread* ThreadManager::WrapCurrentThread() {
|
2014-05-13 18:00:26 +00:00
|
|
|
Thread* result = CurrentThread();
|
2017-02-27 14:06:41 -08:00
|
|
|
if (nullptr == result) {
|
2017-07-14 14:44:46 -07:00
|
|
|
result = new Thread(SocketServer::CreateDefault());
|
2014-09-18 16:45:21 +00:00
|
|
|
result->WrapCurrentWithThreadManager(this, true);
|
2014-05-13 18:00:26 +00:00
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ThreadManager::UnwrapCurrentThread() {
|
|
|
|
|
Thread* t = CurrentThread();
|
|
|
|
|
if (t && !(t->IsOwned())) {
|
|
|
|
|
t->UnwrapCurrent();
|
|
|
|
|
delete t;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-21 07:26:37 +00:00
|
|
|
bool ThreadManager::IsMainThread() {
|
|
|
|
|
return IsThreadRefEqual(CurrentThreadRef(), main_thread_ref_);
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-14 22:03:57 +00:00
|
|
|
Thread::ScopedDisallowBlockingCalls::ScopedDisallowBlockingCalls()
|
2018-06-19 15:03:05 +02:00
|
|
|
: thread_(Thread::Current()),
|
|
|
|
|
previous_state_(thread_->SetAllowBlockingCalls(false)) {}
|
2014-07-14 22:03:57 +00:00
|
|
|
|
|
|
|
|
Thread::ScopedDisallowBlockingCalls::~ScopedDisallowBlockingCalls() {
|
2017-01-12 05:15:36 -08:00
|
|
|
RTC_DCHECK(thread_->IsCurrent());
|
2014-07-14 22:03:57 +00:00
|
|
|
thread_->SetAllowBlockingCalls(previous_state_);
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-02 15:20:33 -08:00
|
|
|
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) {
|
2020-01-09 14:20:23 +01:00
|
|
|
socketserver()->SetMessageQueue(this);
|
2014-05-13 18:00:26 +00:00
|
|
|
SetName("Thread", this); // default name
|
2018-03-02 15:20:33 -08:00
|
|
|
if (do_init) {
|
|
|
|
|
DoInit();
|
|
|
|
|
}
|
2016-04-28 01:32:48 -07:00
|
|
|
}
|
|
|
|
|
|
2018-03-02 15:20:33 -08:00
|
|
|
Thread::Thread(std::unique_ptr<SocketServer> ss, bool do_init)
|
2017-12-04 15:18:23 +01:00
|
|
|
: MessageQueue(std::move(ss), false) {
|
2020-01-09 14:20:23 +01:00
|
|
|
socketserver()->SetMessageQueue(this);
|
2016-04-28 01:32:48 -07:00
|
|
|
SetName("Thread", this); // default name
|
2018-03-02 15:20:33 -08:00
|
|
|
if (do_init) {
|
|
|
|
|
DoInit();
|
|
|
|
|
}
|
2014-05-13 18:00:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Thread::~Thread() {
|
|
|
|
|
Stop();
|
2016-02-05 00:25:02 -08:00
|
|
|
DoDestroy();
|
2014-05-13 18:00:26 +00:00
|
|
|
}
|
|
|
|
|
|
2017-04-26 01:45:31 -07:00
|
|
|
bool Thread::IsCurrent() const {
|
|
|
|
|
return ThreadManager::Instance()->CurrentThread() == this;
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-28 01:32:48 -07:00
|
|
|
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())));
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-13 18:00:26 +00:00
|
|
|
bool Thread::SleepMs(int milliseconds) {
|
2014-07-14 22:03:57 +00:00
|
|
|
AssertBlockingIsAllowedOnCurrentThread();
|
|
|
|
|
|
2014-05-13 18:00:26 +00:00
|
|
|
#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;
|
2017-02-27 14:06:41 -08:00
|
|
|
int ret = nanosleep(&ts, nullptr);
|
2014-05-13 18:00:26 +00:00
|
|
|
if (ret != 0) {
|
2017-11-09 11:09:25 +01:00
|
|
|
RTC_LOG_ERR(LS_WARNING) << "nanosleep() returning early";
|
2014-05-13 18:00:26 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Thread::SetName(const std::string& name, const void* obj) {
|
2017-12-04 15:18:23 +01:00
|
|
|
RTC_DCHECK(!IsRunning());
|
|
|
|
|
|
2014-05-13 18:00:26 +00:00
|
|
|
name_ = name;
|
|
|
|
|
if (obj) {
|
2018-10-16 15:14:15 +02:00
|
|
|
// 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);
|
2014-05-13 18:00:26 +00:00
|
|
|
name_ += buf;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-11 09:24:14 +02:00
|
|
|
bool Thread::Start() {
|
2017-12-04 15:18:23 +01:00
|
|
|
RTC_DCHECK(!IsRunning());
|
|
|
|
|
|
|
|
|
|
if (IsRunning())
|
|
|
|
|
return false;
|
2014-05-13 18:00:26 +00:00
|
|
|
|
2016-07-22 13:30:05 +02:00
|
|
|
Restart(); // reset IsQuitting() if the thread is being restarted
|
2014-05-13 18:00:26 +00:00
|
|
|
|
|
|
|
|
// Make sure that ThreadManager is created on the main thread before
|
|
|
|
|
// we start a new thread.
|
|
|
|
|
ThreadManager::Instance();
|
|
|
|
|
|
2017-12-04 15:18:23 +01:00
|
|
|
owned_ = true;
|
|
|
|
|
|
2014-05-13 18:00:26 +00:00
|
|
|
#if defined(WEBRTC_WIN)
|
2019-06-11 09:24:14 +02:00
|
|
|
thread_ = CreateThread(nullptr, 0, PreRun, this, 0, &thread_id_);
|
2017-12-04 15:18:23 +01:00
|
|
|
if (!thread_) {
|
2014-05-13 18:00:26 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
#elif defined(WEBRTC_POSIX)
|
|
|
|
|
pthread_attr_t attr;
|
|
|
|
|
pthread_attr_init(&attr);
|
|
|
|
|
|
2019-06-11 09:24:14 +02:00
|
|
|
int error_code = pthread_create(&thread_, &attr, PreRun, this);
|
2014-05-13 18:00:26 +00:00
|
|
|
if (0 != error_code) {
|
2017-11-09 11:09:25 +01:00
|
|
|
RTC_LOG(LS_ERROR) << "Unable to create pthread, error " << error_code;
|
2017-12-04 15:18:23 +01:00
|
|
|
thread_ = 0;
|
2014-05-13 18:00:26 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
2017-12-04 15:18:23 +01:00
|
|
|
RTC_DCHECK(thread_);
|
2014-05-13 18:00:26 +00:00
|
|
|
#endif
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-18 16:45:21 +00:00
|
|
|
bool Thread::WrapCurrent() {
|
|
|
|
|
return WrapCurrentWithThreadManager(ThreadManager::Instance(), true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Thread::UnwrapCurrent() {
|
|
|
|
|
// Clears the platform-specific thread-specific storage.
|
2017-02-27 14:06:41 -08:00
|
|
|
ThreadManager::Instance()->SetCurrentThread(nullptr);
|
2014-09-18 16:45:21 +00:00
|
|
|
#if defined(WEBRTC_WIN)
|
2017-02-27 14:06:41 -08:00
|
|
|
if (thread_ != nullptr) {
|
2014-09-18 16:45:21 +00:00
|
|
|
if (!CloseHandle(thread_)) {
|
2017-11-09 11:09:25 +01:00
|
|
|
RTC_LOG_GLE(LS_ERROR)
|
|
|
|
|
<< "When unwrapping thread, failed to close handle.";
|
2014-09-18 16:45:21 +00:00
|
|
|
}
|
2017-02-27 14:06:41 -08:00
|
|
|
thread_ = nullptr;
|
2017-12-04 15:18:23 +01:00
|
|
|
thread_id_ = 0;
|
2014-09-18 16:45:21 +00:00
|
|
|
}
|
2017-12-04 15:18:23 +01:00
|
|
|
#elif defined(WEBRTC_POSIX)
|
|
|
|
|
thread_ = 0;
|
2014-09-18 16:45:21 +00:00
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Thread::SafeWrapCurrent() {
|
|
|
|
|
WrapCurrentWithThreadManager(ThreadManager::Instance(), false);
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-13 18:00:26 +00:00
|
|
|
void Thread::Join() {
|
2017-12-04 15:18:23 +01:00
|
|
|
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";
|
|
|
|
|
}
|
2014-09-26 16:57:07 +00:00
|
|
|
|
2014-05-13 18:00:26 +00:00
|
|
|
#if defined(WEBRTC_WIN)
|
2017-12-04 15:18:23 +01:00
|
|
|
RTC_DCHECK(thread_ != nullptr);
|
|
|
|
|
WaitForSingleObject(thread_, INFINITE);
|
|
|
|
|
CloseHandle(thread_);
|
|
|
|
|
thread_ = nullptr;
|
|
|
|
|
thread_id_ = 0;
|
2014-05-13 18:00:26 +00:00
|
|
|
#elif defined(WEBRTC_POSIX)
|
2017-12-04 15:18:23 +01:00
|
|
|
pthread_join(thread_, nullptr);
|
|
|
|
|
thread_ = 0;
|
2014-05-13 18:00:26 +00:00
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-14 22:03:57 +00:00
|
|
|
bool Thread::SetAllowBlockingCalls(bool allow) {
|
2017-01-12 05:15:36 -08:00
|
|
|
RTC_DCHECK(IsCurrent());
|
2014-07-14 22:03:57 +00:00
|
|
|
bool previous = blocking_calls_allowed_;
|
|
|
|
|
blocking_calls_allowed_ = allow;
|
|
|
|
|
return previous;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// static
|
|
|
|
|
void Thread::AssertBlockingIsAllowedOnCurrentThread() {
|
2015-10-30 16:08:48 -07:00
|
|
|
#if !defined(NDEBUG)
|
2014-07-14 22:03:57 +00:00
|
|
|
Thread* current = Thread::Current();
|
2017-01-12 05:15:36 -08:00
|
|
|
RTC_DCHECK(!current || current->blocking_calls_allowed_);
|
2014-07-14 22:03:57 +00:00
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-31 15:10:44 -08:00
|
|
|
// static
|
|
|
|
|
#if defined(WEBRTC_WIN)
|
|
|
|
|
DWORD WINAPI Thread::PreRun(LPVOID pv) {
|
|
|
|
|
#else
|
2014-05-13 18:00:26 +00:00
|
|
|
void* Thread::PreRun(void* pv) {
|
2017-01-31 15:10:44 -08:00
|
|
|
#endif
|
2019-06-11 09:24:14 +02:00
|
|
|
Thread* thread = static_cast<Thread*>(pv);
|
|
|
|
|
ThreadManager::Instance()->SetCurrentThread(thread);
|
|
|
|
|
rtc::SetCurrentThreadName(thread->name_.c_str());
|
2019-11-22 15:52:40 +01:00
|
|
|
CurrentTaskQueueSetter set_current_task_queue(thread);
|
2018-10-12 12:57:49 +02:00
|
|
|
#if defined(WEBRTC_MAC)
|
|
|
|
|
ScopedAutoReleasePool pool;
|
|
|
|
|
#endif
|
2019-06-11 09:24:14 +02:00
|
|
|
thread->Run();
|
|
|
|
|
|
2017-12-04 15:18:23 +01:00
|
|
|
ThreadManager::Instance()->SetCurrentThread(nullptr);
|
2017-01-31 15:10:44 -08:00
|
|
|
#ifdef WEBRTC_WIN
|
2017-02-22 00:42:11 -08:00
|
|
|
return 0;
|
2017-01-31 15:10:44 -08:00
|
|
|
#else
|
2017-02-22 00:42:11 -08:00
|
|
|
return nullptr;
|
2017-01-31 15:10:44 -08:00
|
|
|
#endif
|
2019-07-05 19:08:33 +02:00
|
|
|
} // namespace rtc
|
2014-05-13 18:00:26 +00:00
|
|
|
|
|
|
|
|
void Thread::Run() {
|
|
|
|
|
ProcessMessages(kForever);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Thread::IsOwned() {
|
2017-12-04 15:18:23 +01:00
|
|
|
RTC_DCHECK(IsRunning());
|
2014-05-13 18:00:26 +00:00
|
|
|
return owned_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Thread::Stop() {
|
|
|
|
|
MessageQueue::Quit();
|
|
|
|
|
Join();
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-10 14:17:27 -07:00
|
|
|
void Thread::Send(const Location& posted_from,
|
|
|
|
|
MessageHandler* phandler,
|
|
|
|
|
uint32_t id,
|
|
|
|
|
MessageData* pdata) {
|
2016-07-22 13:30:05 +02:00
|
|
|
if (IsQuitting())
|
2014-05-13 18:00:26 +00:00
|
|
|
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;
|
2016-06-10 14:17:27 -07:00
|
|
|
msg.posted_from = posted_from;
|
2014-05-13 18:00:26 +00:00
|
|
|
msg.phandler = phandler;
|
|
|
|
|
msg.message_id = id;
|
|
|
|
|
msg.pdata = pdata;
|
|
|
|
|
if (IsCurrent()) {
|
|
|
|
|
phandler->OnMessage(&msg);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-24 17:14:05 +00:00
|
|
|
AssertBlockingIsAllowedOnCurrentThread();
|
|
|
|
|
|
2014-05-13 18:00:26 +00:00
|
|
|
AutoThread thread;
|
2018-06-19 15:03:05 +02:00
|
|
|
Thread* current_thread = Thread::Current();
|
2017-02-27 14:06:41 -08:00
|
|
|
RTC_DCHECK(current_thread != nullptr); // AutoThread ensures this
|
2014-05-13 18:00:26 +00:00
|
|
|
|
|
|
|
|
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
|
2016-02-25 01:14:56 -08:00
|
|
|
WakeUpSocketServer();
|
2014-05-13 18:00:26 +00:00
|
|
|
|
|
|
|
|
bool waited = false;
|
|
|
|
|
crit_.Enter();
|
|
|
|
|
while (!ready) {
|
|
|
|
|
crit_.Leave();
|
2014-09-24 17:14:05 +00:00
|
|
|
// We need to limit "ReceiveSends" to |this| thread to avoid an arbitrary
|
|
|
|
|
// thread invoking calls on the current thread.
|
|
|
|
|
current_thread->ReceiveSendsFromThread(this);
|
2014-05-13 18:00:26 +00:00
|
|
|
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() {
|
2017-02-27 14:06:41 -08:00
|
|
|
ReceiveSendsFromThread(nullptr);
|
2014-09-24 17:14:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Thread::ReceiveSendsFromThread(const Thread* source) {
|
2014-05-13 18:00:26 +00:00
|
|
|
// 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()
|
2014-09-24 17:14:05 +00:00
|
|
|
_SendMessage smsg;
|
|
|
|
|
|
2014-05-13 18:00:26 +00:00
|
|
|
crit_.Enter();
|
2014-09-24 17:14:05 +00:00
|
|
|
while (PopSendMessageFromThread(source, &smsg)) {
|
2014-05-13 18:00:26 +00:00
|
|
|
crit_.Leave();
|
2014-09-24 17:14:05 +00:00
|
|
|
|
2018-06-26 20:04:43 -07:00
|
|
|
Dispatch(&smsg.msg);
|
2014-09-24 17:14:05 +00:00
|
|
|
|
2014-05-13 18:00:26 +00:00
|
|
|
crit_.Enter();
|
|
|
|
|
*smsg.ready = true;
|
|
|
|
|
smsg.thread->socketserver()->WakeUp();
|
|
|
|
|
}
|
|
|
|
|
crit_.Leave();
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-24 17:14:05 +00:00
|
|
|
bool Thread::PopSendMessageFromThread(const Thread* source, _SendMessage* msg) {
|
|
|
|
|
for (std::list<_SendMessage>::iterator it = sendlist_.begin();
|
|
|
|
|
it != sendlist_.end(); ++it) {
|
2017-02-27 14:06:41 -08:00
|
|
|
if (it->thread == source || source == nullptr) {
|
2014-09-24 17:14:05 +00:00
|
|
|
*msg = *it;
|
|
|
|
|
sendlist_.erase(it);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-10 14:17:27 -07:00
|
|
|
void Thread::InvokeInternal(const Location& posted_from,
|
2019-11-29 12:56:43 +01:00
|
|
|
rtc::FunctionView<void()> functor) {
|
2019-12-03 10:14:05 -08:00
|
|
|
TRACE_EVENT2("webrtc", "Thread::Invoke", "src_file", posted_from.file_name(),
|
|
|
|
|
"src_func", posted_from.function_name());
|
2019-11-29 12:56:43 +01:00
|
|
|
|
|
|
|
|
class FunctorMessageHandler : public MessageHandler {
|
|
|
|
|
public:
|
|
|
|
|
explicit FunctorMessageHandler(rtc::FunctionView<void()> functor)
|
|
|
|
|
: functor_(functor) {}
|
|
|
|
|
void OnMessage(Message* msg) override { functor_(); }
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
rtc::FunctionView<void()> functor_;
|
|
|
|
|
} handler(functor);
|
|
|
|
|
|
|
|
|
|
Send(posted_from, &handler);
|
2015-03-17 14:25:37 +00:00
|
|
|
}
|
|
|
|
|
|
2019-11-22 15:52:40 +01:00
|
|
|
void Thread::QueuedTaskHandler::OnMessage(Message* msg) {
|
|
|
|
|
RTC_DCHECK(msg);
|
|
|
|
|
auto* data = static_cast<ScopedMessageData<webrtc::QueuedTask>*>(msg->pdata);
|
|
|
|
|
std::unique_ptr<webrtc::QueuedTask> task = std::move(data->data());
|
|
|
|
|
// MessageQueue expects handler to own Message::pdata when OnMessage is called
|
|
|
|
|
// Since MessageData is no longer needed, delete it.
|
|
|
|
|
delete data;
|
|
|
|
|
|
|
|
|
|
// QueuedTask interface uses Run return value to communicate who owns the
|
|
|
|
|
// task. false means QueuedTask took the ownership.
|
|
|
|
|
if (!task->Run())
|
|
|
|
|
task.release();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Thread::PostTask(std::unique_ptr<webrtc::QueuedTask> task) {
|
|
|
|
|
// Though Post takes MessageData by raw pointer (last parameter), it still
|
|
|
|
|
// takes it with ownership.
|
|
|
|
|
Post(RTC_FROM_HERE, &queued_task_handler_,
|
|
|
|
|
/*id=*/0, new ScopedMessageData<webrtc::QueuedTask>(std::move(task)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Thread::PostDelayedTask(std::unique_ptr<webrtc::QueuedTask> task,
|
|
|
|
|
uint32_t milliseconds) {
|
|
|
|
|
// Though PostDelayed takes MessageData by raw pointer (last parameter),
|
|
|
|
|
// it still takes it with ownership.
|
|
|
|
|
PostDelayed(RTC_FROM_HERE, milliseconds, &queued_task_handler_,
|
|
|
|
|
/*id=*/0,
|
|
|
|
|
new ScopedMessageData<webrtc::QueuedTask>(std::move(task)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Thread::Delete() {
|
|
|
|
|
Stop();
|
|
|
|
|
delete this;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-06 08:42:44 +02:00
|
|
|
bool Thread::IsProcessingMessagesForTesting() {
|
|
|
|
|
return (owned_ || IsCurrent()) &&
|
|
|
|
|
MessageQueue::IsProcessingMessagesForTesting();
|
|
|
|
|
}
|
|
|
|
|
|
Use suffixed {uint,int}{8,16,32,64}_t types.
Removes the use of uint8, etc. in favor of uint8_t.
BUG=webrtc:5024
R=henrik.lundin@webrtc.org, henrikg@webrtc.org, perkj@webrtc.org, solenberg@webrtc.org, stefan@webrtc.org, tina.legrand@webrtc.org
Review URL: https://codereview.webrtc.org/1362503003 .
Cr-Commit-Position: refs/heads/master@{#10196}
2015-10-07 12:23:21 +02:00
|
|
|
void Thread::Clear(MessageHandler* phandler,
|
|
|
|
|
uint32_t id,
|
2014-05-13 18:00:26 +00:00
|
|
|
MessageList* removed) {
|
|
|
|
|
CritScope cs(&crit_);
|
|
|
|
|
|
|
|
|
|
// Remove messages on sendlist_ with phandler
|
|
|
|
|
// Object target cleared: remove from send list, wakeup/set ready
|
2017-02-27 14:06:41 -08:00
|
|
|
// if sender not null.
|
2014-05-13 18:00:26 +00:00
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-07 12:35:44 +02:00
|
|
|
ClearInternal(phandler, id, removed);
|
2014-05-13 18:00:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Thread::ProcessMessages(int cmsLoop) {
|
Update VirtualSocketServerTest to use a fake clock.
Since this is a test for a fake network, it's only natural that it uses
a fake clock as well. This makes the tests much faster, less flaky, and
lets them be moved out of "webrtc_nonparallel_tests", since they no
longer have a dependency on any "real" thing (sockets, or time) and
can be run in parallel as easily as any other tests.
As part of this CL, added the fake clock as an argument to
VirtualSocketServer's and TestClient's constructors, since these classes
have methods that wait synchronously for something to occur, and if the
test is using a fake clock, they need to advance it in order to make
progress.
Lastly, added a DCHECK in Thread::ProcessMessages. If called with a
nonzero time while a fake clock is used, it will get stuck in an
infinite loop; a DCHECK is easier to notice than an infinite loop.
BUG=webrtc:7727, webrtc:2409
Review-Url: https://codereview.webrtc.org/2927413002
Cr-Commit-Position: refs/heads/master@{#18544}
2017-06-12 14:30:28 -07:00
|
|
|
// 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);
|
2016-05-06 11:29:15 -07:00
|
|
|
int64_t msEnd = (kForever == cmsLoop) ? 0 : TimeAfter(cmsLoop);
|
2014-05-13 18:00:26 +00:00
|
|
|
int cmsNext = cmsLoop;
|
|
|
|
|
|
|
|
|
|
while (true) {
|
2018-10-12 12:57:49 +02:00
|
|
|
#if defined(WEBRTC_MAC)
|
|
|
|
|
ScopedAutoReleasePool pool;
|
|
|
|
|
#endif
|
2017-02-22 00:42:11 -08:00
|
|
|
Message msg;
|
|
|
|
|
if (!Get(&msg, cmsNext))
|
|
|
|
|
return !IsQuitting();
|
|
|
|
|
Dispatch(&msg);
|
|
|
|
|
|
|
|
|
|
if (cmsLoop != kForever) {
|
|
|
|
|
cmsNext = static_cast<int>(TimeUntil(msEnd));
|
|
|
|
|
if (cmsNext < 0)
|
|
|
|
|
return true;
|
2014-05-13 18:00:26 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-18 16:45:21 +00:00
|
|
|
bool Thread::WrapCurrentWithThreadManager(ThreadManager* thread_manager,
|
|
|
|
|
bool need_synchronize_access) {
|
2017-12-04 15:18:23 +01:00
|
|
|
RTC_DCHECK(!IsRunning());
|
2014-09-18 16:45:21 +00:00
|
|
|
|
2014-05-13 18:00:26 +00:00
|
|
|
#if defined(WEBRTC_WIN)
|
2014-09-18 16:45:21 +00:00
|
|
|
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_) {
|
2017-11-09 11:09:25 +01:00
|
|
|
RTC_LOG_GLE(LS_ERROR) << "Unable to get handle to thread.";
|
2014-09-18 16:45:21 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
thread_id_ = GetCurrentThreadId();
|
2014-05-13 18:00:26 +00:00
|
|
|
}
|
|
|
|
|
#elif defined(WEBRTC_POSIX)
|
|
|
|
|
thread_ = pthread_self();
|
|
|
|
|
#endif
|
|
|
|
|
owned_ = false;
|
|
|
|
|
thread_manager->SetCurrentThread(this);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-04 15:18:23 +01:00
|
|
|
bool Thread::IsRunning() {
|
|
|
|
|
#if defined(WEBRTC_WIN)
|
|
|
|
|
return thread_ != nullptr;
|
|
|
|
|
#elif defined(WEBRTC_POSIX)
|
|
|
|
|
return thread_ != 0;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-11 11:21:53 -08:00
|
|
|
// static
|
|
|
|
|
MessageHandler* Thread::GetPostTaskMessageHandler() {
|
|
|
|
|
// Allocate at first call, never deallocate.
|
|
|
|
|
static MessageHandler* handler = new MessageHandlerWithTask;
|
|
|
|
|
return handler;
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-02 15:20:33 -08:00
|
|
|
AutoThread::AutoThread()
|
|
|
|
|
: Thread(SocketServer::CreateDefault(), /*do_init=*/false) {
|
2014-05-13 18:00:26 +00:00
|
|
|
if (!ThreadManager::Instance()->CurrentThread()) {
|
2019-06-12 11:30:59 +02:00
|
|
|
// 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();
|
2014-05-13 18:00:26 +00:00
|
|
|
ThreadManager::Instance()->SetCurrentThread(this);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AutoThread::~AutoThread() {
|
|
|
|
|
Stop();
|
2017-10-19 10:17:12 -07:00
|
|
|
DoDestroy();
|
2014-05-13 18:00:26 +00:00
|
|
|
if (ThreadManager::Instance()->CurrentThread() == this) {
|
2017-02-27 14:06:41 -08:00
|
|
|
ThreadManager::Instance()->SetCurrentThread(nullptr);
|
2014-05-13 18:00:26 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-08 05:25:41 -07:00
|
|
|
AutoSocketServerThread::AutoSocketServerThread(SocketServer* ss)
|
2018-03-02 15:20:33 -08:00
|
|
|
: Thread(ss, /*do_init=*/false) {
|
|
|
|
|
DoInit();
|
2017-05-08 05:25:41 -07:00
|
|
|
old_thread_ = ThreadManager::Instance()->CurrentThread();
|
2017-12-04 15:18:23 +01:00
|
|
|
// Temporarily set the current thread to nullptr so that we can keep checks
|
|
|
|
|
// around that catch unintentional pointer overwrites.
|
|
|
|
|
rtc::ThreadManager::Instance()->SetCurrentThread(nullptr);
|
2017-05-08 05:25:41 -07:00
|
|
|
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);
|
2017-10-19 10:17:12 -07:00
|
|
|
// 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();
|
2017-12-04 15:18:23 +01:00
|
|
|
rtc::ThreadManager::Instance()->SetCurrentThread(nullptr);
|
2017-05-08 05:25:41 -07:00
|
|
|
rtc::ThreadManager::Instance()->SetCurrentThread(old_thread_);
|
|
|
|
|
if (old_thread_) {
|
|
|
|
|
MessageQueueManager::Add(old_thread_);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-13 18:00:26 +00:00
|
|
|
} // namespace rtc
|