Index: webrtc/base/thread.cc |
diff --git a/webrtc/base/thread.cc b/webrtc/base/thread.cc |
deleted file mode 100644 |
index 9174cd1bd6de531f80d6a200bf3c4afd4498c521..0000000000000000000000000000000000000000 |
--- a/webrtc/base/thread.cc |
+++ /dev/null |
@@ -1,558 +0,0 @@ |
-/* |
- * 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 "webrtc/base/thread.h" |
- |
-#if defined(WEBRTC_WIN) |
-#include <comdef.h> |
-#elif defined(WEBRTC_POSIX) |
-#include <time.h> |
-#endif |
- |
-#include "webrtc/base/checks.h" |
-#include "webrtc/base/logging.h" |
-#include "webrtc/base/nullsocketserver.h" |
-#include "webrtc/base/platform_thread.h" |
-#include "webrtc/base/stringutils.h" |
-#include "webrtc/base/timeutils.h" |
-#include "webrtc/base/trace_event.h" |
- |
-namespace rtc { |
- |
-ThreadManager* ThreadManager::Instance() { |
- RTC_DEFINE_STATIC_LOCAL(ThreadManager, thread_manager, ()); |
- 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(); |
- thread->WrapCurrentWithThreadManager(manager, true); |
- } |
-#endif |
- |
- return thread; |
-} |
- |
-#if defined(WEBRTC_POSIX) |
-#if !defined(WEBRTC_MAC) |
-ThreadManager::ThreadManager() { |
- main_thread_ref_ = CurrentThreadRef(); |
- pthread_key_create(&key_, nullptr); |
-} |
-#endif |
- |
-Thread *ThreadManager::CurrentThread() { |
- return static_cast<Thread *>(pthread_getspecific(key_)); |
-} |
- |
-void ThreadManager::SetCurrentThread(Thread *thread) { |
- pthread_setspecific(key_, thread); |
-} |
-#endif |
- |
-#if defined(WEBRTC_WIN) |
-ThreadManager::ThreadManager() { |
- main_thread_ref_ = CurrentThreadRef(); |
- key_ = TlsAlloc(); |
-} |
- |
-Thread *ThreadManager::CurrentThread() { |
- return static_cast<Thread *>(TlsGetValue(key_)); |
-} |
- |
-void ThreadManager::SetCurrentThread(Thread *thread) { |
- TlsSetValue(key_, thread); |
-} |
-#endif |
- |
-Thread *ThreadManager::WrapCurrentThread() { |
- Thread* result = CurrentThread(); |
- if (nullptr == result) { |
- result = new Thread(); |
- 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() : Thread(SocketServer::CreateDefault()) {} |
- |
-Thread::Thread(SocketServer* ss) |
- : MessageQueue(ss, false), |
- running_(true, false), |
-#if defined(WEBRTC_WIN) |
- thread_(nullptr), |
- thread_id_(0), |
-#endif |
- owned_(true), |
- blocking_calls_allowed_(true) { |
- SetName("Thread", this); // default name |
- DoInit(); |
-} |
- |
-Thread::Thread(std::unique_ptr<SocketServer> ss) |
- : MessageQueue(std::move(ss), false), |
- running_(true, false), |
-#if defined(WEBRTC_WIN) |
- thread_(nullptr), |
- thread_id_(0), |
-#endif |
- owned_(true), |
- blocking_calls_allowed_(true) { |
- SetName("Thread", this); // default name |
- 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) { |
- LOG_ERR(LS_WARNING) << "nanosleep() returning early"; |
- return false; |
- } |
- return true; |
-#endif |
-} |
- |
-bool Thread::SetName(const std::string& name, const void* obj) { |
- if (running()) return false; |
- name_ = name; |
- if (obj) { |
- char buf[16]; |
- sprintfn(buf, sizeof(buf), " 0x%p", obj); |
- name_ += buf; |
- } |
- return true; |
-} |
- |
-bool Thread::Start(Runnable* runnable) { |
- RTC_DCHECK(owned_); |
- if (!owned_) return false; |
- RTC_DCHECK(!running()); |
- if (running()) 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(); |
- |
- ThreadInit* init = new ThreadInit; |
- init->thread = this; |
- init->runnable = runnable; |
-#if defined(WEBRTC_WIN) |
- thread_ = CreateThread(nullptr, 0, PreRun, init, 0, &thread_id_); |
- if (thread_) { |
- running_.Set(); |
- } else { |
- return false; |
- } |
-#elif defined(WEBRTC_POSIX) |
- pthread_attr_t attr; |
- pthread_attr_init(&attr); |
- |
- int error_code = pthread_create(&thread_, &attr, PreRun, init); |
- if (0 != error_code) { |
- LOG(LS_ERROR) << "Unable to create pthread, error " << error_code; |
- return false; |
- } |
- running_.Set(); |
-#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_)) { |
- LOG_GLE(LS_ERROR) << "When unwrapping thread, failed to close handle."; |
- } |
- thread_ = nullptr; |
- } |
-#endif |
- running_.Reset(); |
-} |
- |
-void Thread::SafeWrapCurrent() { |
- WrapCurrentWithThreadManager(ThreadManager::Instance(), false); |
-} |
- |
-void Thread::Join() { |
- if (running()) { |
- RTC_DCHECK(!IsCurrent()); |
- if (Current() && !Current()->blocking_calls_allowed_) { |
- 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) |
- void *pv; |
- pthread_join(thread_, &pv); |
-#endif |
- running_.Reset(); |
- } |
-} |
- |
-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_MAC) |
-#if defined(WEBRTC_WIN) |
-DWORD WINAPI Thread::PreRun(LPVOID pv) { |
-#else |
-void* Thread::PreRun(void* pv) { |
-#endif |
- ThreadInit* init = static_cast<ThreadInit*>(pv); |
- ThreadManager::Instance()->SetCurrentThread(init->thread); |
- rtc::SetCurrentThreadName(init->thread->name_.c_str()); |
- if (init->runnable) { |
- init->runnable->Run(init->thread); |
- } else { |
- init->thread->Run(); |
- } |
- delete init; |
-#ifdef WEBRTC_WIN |
- return 0; |
-#else |
- return nullptr; |
-#endif |
-} |
-#endif |
- |
-void Thread::Run() { |
- ProcessMessages(kForever); |
-} |
- |
-bool Thread::IsOwned() { |
- 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(); |
- |
- smsg.msg.phandler->OnMessage(&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); |
-} |
- |
-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; |
- } |
- |
- MessageQueue::Clear(phandler, id, removed); |
-} |
- |
-#if !defined(WEBRTC_MAC) |
-// Note that these methods have a separate implementation for mac and ios |
-// defined in webrtc/base/thread_darwin.mm. |
-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) { |
- Message msg; |
- if (!Get(&msg, cmsNext)) |
- return !IsQuitting(); |
- Dispatch(&msg); |
- |
- if (cmsLoop != kForever) { |
- cmsNext = static_cast<int>(TimeUntil(msEnd)); |
- if (cmsNext < 0) |
- return true; |
- } |
- } |
-} |
-#endif |
- |
-bool Thread::WrapCurrentWithThreadManager(ThreadManager* thread_manager, |
- bool need_synchronize_access) { |
- if (running()) |
- return false; |
- |
-#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_) { |
- 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; |
- running_.Set(); |
- thread_manager->SetCurrentThread(this); |
- return true; |
-} |
- |
-AutoThread::AutoThread() { |
- if (!ThreadManager::Instance()->CurrentThread()) { |
- ThreadManager::Instance()->SetCurrentThread(this); |
- } |
-} |
- |
-AutoThread::~AutoThread() { |
- Stop(); |
- if (ThreadManager::Instance()->CurrentThread() == this) { |
- ThreadManager::Instance()->SetCurrentThread(nullptr); |
- } |
-} |
- |
-AutoSocketServerThread::AutoSocketServerThread(SocketServer* ss) |
- : Thread(ss) { |
- old_thread_ = ThreadManager::Instance()->CurrentThread(); |
- 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); |
- rtc::ThreadManager::Instance()->SetCurrentThread(old_thread_); |
- if (old_thread_) { |
- MessageQueueManager::Add(old_thread_); |
- } |
-} |
- |
-} // namespace rtc |