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
|
|
|
|
2022-03-17 15:47:49 +01:00
|
|
|
#include "absl/strings/string_view.h"
|
2022-08-25 11:40:13 +00:00
|
|
|
#include "api/units/time_delta.h"
|
|
|
|
|
#include "rtc_base/socket_server.h"
|
2022-03-17 15:47:49 +01:00
|
|
|
|
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
|
|
|
|
2020-01-13 14:07:22 +01:00
|
|
|
#include "absl/algorithm/container.h"
|
2022-07-06 19:42:34 +02:00
|
|
|
#include "absl/cleanup/cleanup.h"
|
2021-02-10 14:31:24 +01:00
|
|
|
#include "api/sequence_checker.h"
|
2017-09-15 06:47:31 +02:00
|
|
|
#include "rtc_base/checks.h"
|
2020-07-16 16:16:09 +02:00
|
|
|
#include "rtc_base/deprecated/recursive_critical_section.h"
|
2020-09-04 16:33:25 +02:00
|
|
|
#include "rtc_base/event.h"
|
2021-01-15 10:41:01 +01:00
|
|
|
#include "rtc_base/internal/default_socket_server.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 {
|
|
|
|
|
|
2022-08-24 18:35:45 +02:00
|
|
|
using ::webrtc::TimeDelta;
|
|
|
|
|
|
2020-01-13 14:07:22 +01:00
|
|
|
class RTC_SCOPED_LOCKABLE MarkProcessingCritScope {
|
|
|
|
|
public:
|
2020-07-16 16:16:09 +02:00
|
|
|
MarkProcessingCritScope(const RecursiveCriticalSection* cs,
|
|
|
|
|
size_t* processing) RTC_EXCLUSIVE_LOCK_FUNCTION(cs)
|
2020-01-13 14:07:22 +01:00
|
|
|
: cs_(cs), processing_(processing) {
|
|
|
|
|
cs_->Enter();
|
|
|
|
|
*processing_ += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
~MarkProcessingCritScope() RTC_UNLOCK_FUNCTION() {
|
|
|
|
|
*processing_ -= 1;
|
|
|
|
|
cs_->Leave();
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-12 05:24:58 +09:00
|
|
|
MarkProcessingCritScope(const MarkProcessingCritScope&) = delete;
|
|
|
|
|
MarkProcessingCritScope& operator=(const MarkProcessingCritScope&) = delete;
|
|
|
|
|
|
2020-01-13 14:07:22 +01:00
|
|
|
private:
|
2020-07-16 16:16:09 +02:00
|
|
|
const RecursiveCriticalSection* const cs_;
|
2020-01-13 14:07:22 +01:00
|
|
|
size_t* processing_;
|
|
|
|
|
};
|
|
|
|
|
|
2019-12-11 11:21:53 -08:00
|
|
|
} // 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.
|
2021-11-15 16:57:07 +01:00
|
|
|
RTC_DCHECK_NOTREACHED() << "ThreadManager should never be destructed.";
|
2017-04-26 01:45:31 -07:00
|
|
|
}
|
|
|
|
|
|
2020-01-13 14:07:22 +01:00
|
|
|
// static
|
|
|
|
|
void ThreadManager::Add(Thread* message_queue) {
|
|
|
|
|
return Instance()->AddInternal(message_queue);
|
|
|
|
|
}
|
|
|
|
|
void ThreadManager::AddInternal(Thread* message_queue) {
|
|
|
|
|
CritScope cs(&crit_);
|
|
|
|
|
// Prevent changes while the list of message queues is processed.
|
|
|
|
|
RTC_DCHECK_EQ(processing_, 0);
|
|
|
|
|
message_queues_.push_back(message_queue);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// static
|
|
|
|
|
void ThreadManager::Remove(Thread* message_queue) {
|
|
|
|
|
return Instance()->RemoveInternal(message_queue);
|
|
|
|
|
}
|
|
|
|
|
void ThreadManager::RemoveInternal(Thread* message_queue) {
|
|
|
|
|
{
|
|
|
|
|
CritScope cs(&crit_);
|
|
|
|
|
// Prevent changes while the list of message queues is processed.
|
|
|
|
|
RTC_DCHECK_EQ(processing_, 0);
|
|
|
|
|
std::vector<Thread*>::iterator iter;
|
|
|
|
|
iter = absl::c_find(message_queues_, message_queue);
|
|
|
|
|
if (iter != message_queues_.end()) {
|
|
|
|
|
message_queues_.erase(iter);
|
|
|
|
|
}
|
2020-03-03 10:48:05 +01:00
|
|
|
#if RTC_DCHECK_IS_ON
|
|
|
|
|
RemoveFromSendGraph(message_queue);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if RTC_DCHECK_IS_ON
|
|
|
|
|
void ThreadManager::RemoveFromSendGraph(Thread* thread) {
|
|
|
|
|
for (auto it = send_graph_.begin(); it != send_graph_.end();) {
|
|
|
|
|
if (it->first == thread) {
|
|
|
|
|
it = send_graph_.erase(it);
|
|
|
|
|
} else {
|
|
|
|
|
it->second.erase(thread);
|
|
|
|
|
++it;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ThreadManager::RegisterSendAndCheckForCycles(Thread* source,
|
|
|
|
|
Thread* target) {
|
2020-09-04 16:33:25 +02:00
|
|
|
RTC_DCHECK(source);
|
|
|
|
|
RTC_DCHECK(target);
|
|
|
|
|
|
2020-03-03 10:48:05 +01:00
|
|
|
CritScope cs(&crit_);
|
|
|
|
|
std::deque<Thread*> all_targets({target});
|
|
|
|
|
// We check the pre-existing who-sends-to-who graph for any path from target
|
|
|
|
|
// to source. This loop is guaranteed to terminate because per the send graph
|
|
|
|
|
// invariant, there are no cycles in the graph.
|
2020-05-26 17:43:17 +08:00
|
|
|
for (size_t i = 0; i < all_targets.size(); i++) {
|
|
|
|
|
const auto& targets = send_graph_[all_targets[i]];
|
2020-03-03 10:48:05 +01:00
|
|
|
all_targets.insert(all_targets.end(), targets.begin(), targets.end());
|
2020-01-13 14:07:22 +01:00
|
|
|
}
|
2020-03-03 10:48:05 +01:00
|
|
|
RTC_CHECK_EQ(absl::c_count(all_targets, source), 0)
|
|
|
|
|
<< " send loop between " << source->name() << " and " << target->name();
|
|
|
|
|
|
|
|
|
|
// We may now insert source -> target without creating a cycle, since there
|
|
|
|
|
// was no path from target to source per the prior CHECK.
|
|
|
|
|
send_graph_[source].insert(target);
|
2020-01-13 14:07:22 +01:00
|
|
|
}
|
2020-03-03 10:48:05 +01:00
|
|
|
#endif
|
2020-01-13 14:07:22 +01:00
|
|
|
|
|
|
|
|
// static
|
|
|
|
|
void ThreadManager::ProcessAllMessageQueuesForTesting() {
|
|
|
|
|
return Instance()->ProcessAllMessageQueuesInternal();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ThreadManager::ProcessAllMessageQueuesInternal() {
|
|
|
|
|
// This works by posting a delayed message at the current time and waiting
|
|
|
|
|
// for it to be dispatched on all queues, which will ensure that all messages
|
|
|
|
|
// that came before it were also dispatched.
|
2022-06-27 09:47:02 +02:00
|
|
|
std::atomic<int> queues_not_done(0);
|
2020-01-13 14:07:22 +01:00
|
|
|
|
|
|
|
|
{
|
|
|
|
|
MarkProcessingCritScope cs(&crit_, &processing_);
|
|
|
|
|
for (Thread* queue : message_queues_) {
|
|
|
|
|
if (!queue->IsProcessingMessagesForTesting()) {
|
|
|
|
|
// If the queue is not processing messages, it can
|
|
|
|
|
// be ignored. If we tried to post a message to it, it would be dropped
|
|
|
|
|
// or ignored.
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2022-08-24 18:35:45 +02:00
|
|
|
queues_not_done.fetch_add(1);
|
|
|
|
|
// Whether the task is processed, or the thread is simply cleared,
|
|
|
|
|
// queues_not_done gets decremented.
|
|
|
|
|
absl::Cleanup sub = [&queues_not_done] { queues_not_done.fetch_sub(1); };
|
|
|
|
|
// Post delayed task instead of regular task to wait for all delayed tasks
|
|
|
|
|
// that are ready for processing.
|
|
|
|
|
queue->PostDelayedTask([sub = std::move(sub)] {}, TimeDelta::Zero());
|
2020-01-13 14:07:22 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rtc::Thread* current = rtc::Thread::Current();
|
|
|
|
|
// Note: One of the message queues may have been on this thread, which is
|
|
|
|
|
// why we can't synchronously wait for queues_not_done to go to 0; we need
|
|
|
|
|
// to process messages as well.
|
2022-06-27 09:47:02 +02:00
|
|
|
while (queues_not_done.load() > 0) {
|
2020-01-13 14:07:22 +01:00
|
|
|
if (current) {
|
|
|
|
|
current->ProcessMessages(0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
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();
|
|
|
|
|
|
|
|
|
|
return thread;
|
2014-05-13 18:00:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if defined(WEBRTC_POSIX)
|
2022-02-07 10:35:29 +01:00
|
|
|
ThreadManager::ThreadManager() {
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Thread* ThreadManager::CurrentThread() {
|
|
|
|
|
return static_cast<Thread*>(pthread_getspecific(key_));
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-14 11:12:26 +01:00
|
|
|
void ThreadManager::SetCurrentThreadInternal(Thread* thread) {
|
2014-05-13 18:00:26 +00:00
|
|
|
pthread_setspecific(key_, thread);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if defined(WEBRTC_WIN)
|
2022-02-07 10:35:29 +01:00
|
|
|
ThreadManager::ThreadManager() : key_(TlsAlloc()) {}
|
2014-05-13 18:00:26 +00:00
|
|
|
|
|
|
|
|
Thread* ThreadManager::CurrentThread() {
|
|
|
|
|
return static_cast<Thread*>(TlsGetValue(key_));
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-14 11:12:26 +01:00
|
|
|
void ThreadManager::SetCurrentThreadInternal(Thread* thread) {
|
2014-05-13 18:00:26 +00:00
|
|
|
TlsSetValue(key_, thread);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2020-01-14 11:12:26 +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
|
2020-05-15 10:11:56 +02:00
|
|
|
|
|
|
|
|
if (thread) {
|
|
|
|
|
thread->EnsureIsCurrentTaskQueue();
|
|
|
|
|
} else {
|
|
|
|
|
Thread* current = CurrentThread();
|
|
|
|
|
if (current) {
|
|
|
|
|
// The current thread is being cleared, e.g. as a result of
|
|
|
|
|
// UnwrapCurrent() being called or when a thread is being stopped
|
|
|
|
|
// (see PreRun()). This signals that the Thread instance is being detached
|
|
|
|
|
// from the thread, which also means that TaskQueue::Current() must not
|
|
|
|
|
// return a pointer to the Thread instance.
|
|
|
|
|
current->ClearCurrentTaskQueue();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-14 11:12:26 +01:00
|
|
|
SetCurrentThreadInternal(thread);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void rtc::ThreadManager::ChangeCurrentThreadForTest(rtc::Thread* thread) {
|
|
|
|
|
SetCurrentThreadInternal(thread);
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-13 18:00:26 +00:00
|
|
|
Thread* ThreadManager::WrapCurrentThread() {
|
|
|
|
|
Thread* result = CurrentThread();
|
2017-02-27 14:06:41 -08:00
|
|
|
if (nullptr == result) {
|
2021-01-15 10:41:01 +01:00
|
|
|
result = new Thread(CreateDefaultSocketServer());
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-14 22:03:57 +00:00
|
|
|
Thread::ScopedDisallowBlockingCalls::ScopedDisallowBlockingCalls()
|
|
|
|
|
: thread_(Thread::Current()),
|
|
|
|
|
previous_state_(thread_->SetAllowBlockingCalls(false)) {}
|
|
|
|
|
|
|
|
|
|
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_);
|
|
|
|
|
}
|
|
|
|
|
|
Add utility to count the number of blocking thread invokes.
This is useful to understand how often we block in certain parts of the
api and track improvements/regressions.
There are two macros, both are only active for RTC_DCHECK_IS_ON builds:
* RTC_LOG_THREAD_BLOCK_COUNT()
Example:
void MyClass::MyFunction() {
RTC_LOG_THREAD_BLOCK_COUNT();
thread_->Invoke<void>([this](){ DoStuff(); });
}
When executing this function during a test, the output could be:
(my_file.cc:2): Blocking MyFunction: total=1 (actual=1, would=0)
The words 'actual' and 'would' reflect whether an actual thread switch
was made, or if in the case of a test using the same thread for more
than one role (e.g. signaling, worker, network are all the same thread)
that an actual thread switch did not occur but it would have occurred
in the case of having dedicated threads. The 'total' count is the sum.
* RTC_DCHECK_BLOCK_COUNT_NO_MORE_THAN(x)
Example:
void MyClass::MyFunction() {
RTC_LOG_THREAD_BLOCK_COUNT();
thread_->Invoke<void>([this](){ DoStuff(); });
thread_->Invoke<void>([this](){ MoreStuff(); });
RTC_DCHECK_BLOCK_COUNT_NO_MORE_THAN(1);
}
When a function is known to have blocking calls and we want to not
regress from the currently known number of blocking calls, we can use
this macro to state that at a certain point in a function, below
where RTC_LOG_THREAD_BLOCK_COUNT() is called, there must have occurred
no more than |x| (total) blocking calls. If more occur, a DCHECK will
hit and print out what the actual number of calls was:
# Fatal error in: my_file.cc, line 5
# last system error: 60
# Check failed: blocked_call_count_printer.GetTotalBlockedCallCount() <= 1 (2 vs. 1)
Bug: webrtc:12649
Change-Id: Ibac4f85f00b89680601dba54a651eac95a0f45d3
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/213782
Commit-Queue: Tommi <tommi@webrtc.org>
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#33632}
2021-04-07 10:08:28 +02:00
|
|
|
#if RTC_DCHECK_IS_ON
|
|
|
|
|
Thread::ScopedCountBlockingCalls::ScopedCountBlockingCalls(
|
|
|
|
|
std::function<void(uint32_t, uint32_t)> callback)
|
|
|
|
|
: thread_(Thread::Current()),
|
|
|
|
|
base_blocking_call_count_(thread_->GetBlockingCallCount()),
|
|
|
|
|
base_could_be_blocking_call_count_(
|
|
|
|
|
thread_->GetCouldBeBlockingCallCount()),
|
|
|
|
|
result_callback_(std::move(callback)) {}
|
|
|
|
|
|
|
|
|
|
Thread::ScopedCountBlockingCalls::~ScopedCountBlockingCalls() {
|
2021-04-14 12:54:10 +02:00
|
|
|
if (GetTotalBlockedCallCount() >= min_blocking_calls_for_callback_) {
|
|
|
|
|
result_callback_(GetBlockingCallCount(), GetCouldBeBlockingCallCount());
|
|
|
|
|
}
|
Add utility to count the number of blocking thread invokes.
This is useful to understand how often we block in certain parts of the
api and track improvements/regressions.
There are two macros, both are only active for RTC_DCHECK_IS_ON builds:
* RTC_LOG_THREAD_BLOCK_COUNT()
Example:
void MyClass::MyFunction() {
RTC_LOG_THREAD_BLOCK_COUNT();
thread_->Invoke<void>([this](){ DoStuff(); });
}
When executing this function during a test, the output could be:
(my_file.cc:2): Blocking MyFunction: total=1 (actual=1, would=0)
The words 'actual' and 'would' reflect whether an actual thread switch
was made, or if in the case of a test using the same thread for more
than one role (e.g. signaling, worker, network are all the same thread)
that an actual thread switch did not occur but it would have occurred
in the case of having dedicated threads. The 'total' count is the sum.
* RTC_DCHECK_BLOCK_COUNT_NO_MORE_THAN(x)
Example:
void MyClass::MyFunction() {
RTC_LOG_THREAD_BLOCK_COUNT();
thread_->Invoke<void>([this](){ DoStuff(); });
thread_->Invoke<void>([this](){ MoreStuff(); });
RTC_DCHECK_BLOCK_COUNT_NO_MORE_THAN(1);
}
When a function is known to have blocking calls and we want to not
regress from the currently known number of blocking calls, we can use
this macro to state that at a certain point in a function, below
where RTC_LOG_THREAD_BLOCK_COUNT() is called, there must have occurred
no more than |x| (total) blocking calls. If more occur, a DCHECK will
hit and print out what the actual number of calls was:
# Fatal error in: my_file.cc, line 5
# last system error: 60
# Check failed: blocked_call_count_printer.GetTotalBlockedCallCount() <= 1 (2 vs. 1)
Bug: webrtc:12649
Change-Id: Ibac4f85f00b89680601dba54a651eac95a0f45d3
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/213782
Commit-Queue: Tommi <tommi@webrtc.org>
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#33632}
2021-04-07 10:08:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32_t Thread::ScopedCountBlockingCalls::GetBlockingCallCount() const {
|
|
|
|
|
return thread_->GetBlockingCallCount() - base_blocking_call_count_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32_t Thread::ScopedCountBlockingCalls::GetCouldBeBlockingCallCount() const {
|
|
|
|
|
return thread_->GetCouldBeBlockingCallCount() -
|
|
|
|
|
base_could_be_blocking_call_count_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32_t Thread::ScopedCountBlockingCalls::GetTotalBlockedCallCount() const {
|
|
|
|
|
return GetBlockingCallCount() + GetCouldBeBlockingCallCount();
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
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)
|
2022-08-24 12:19:46 +02:00
|
|
|
: delayed_next_num_(0),
|
2020-01-13 14:07:22 +01:00
|
|
|
fInitialized_(false),
|
|
|
|
|
fDestroyed_(false),
|
|
|
|
|
stop_(0),
|
|
|
|
|
ss_(ss) {
|
|
|
|
|
RTC_DCHECK(ss);
|
|
|
|
|
ss_->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)
|
2020-01-13 14:07:22 +01:00
|
|
|
: Thread(ss.get(), do_init) {
|
|
|
|
|
own_ss_ = std::move(ss);
|
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
|
|
|
}
|
|
|
|
|
|
2020-01-13 14:07:22 +01:00
|
|
|
void Thread::DoInit() {
|
|
|
|
|
if (fInitialized_) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fInitialized_ = true;
|
|
|
|
|
ThreadManager::Add(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Thread::DoDestroy() {
|
|
|
|
|
if (fDestroyed_) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fDestroyed_ = true;
|
|
|
|
|
// The signal is done from here to ensure
|
|
|
|
|
// that it always gets called when the queue
|
|
|
|
|
// is going away.
|
|
|
|
|
if (ss_) {
|
|
|
|
|
ss_->SetMessageQueue(nullptr);
|
|
|
|
|
}
|
2021-04-19 12:18:27 +02:00
|
|
|
ThreadManager::Remove(this);
|
2022-09-16 17:26:10 +02:00
|
|
|
// Clear.
|
|
|
|
|
messages_ = {};
|
|
|
|
|
delayed_messages_ = {};
|
2020-01-13 14:07:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SocketServer* Thread::socketserver() {
|
|
|
|
|
return ss_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Thread::WakeUpSocketServer() {
|
|
|
|
|
ss_->WakeUp();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Thread::Quit() {
|
2022-06-27 09:47:02 +02:00
|
|
|
stop_.store(1, std::memory_order_release);
|
2020-01-13 14:07:22 +01:00
|
|
|
WakeUpSocketServer();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Thread::IsQuitting() {
|
2022-06-27 09:47:02 +02:00
|
|
|
return stop_.load(std::memory_order_acquire) != 0;
|
2020-01-13 14:07:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Thread::Restart() {
|
2022-06-27 09:47:02 +02:00
|
|
|
stop_.store(0, std::memory_order_release);
|
2020-01-13 14:07:22 +01:00
|
|
|
}
|
|
|
|
|
|
2022-09-16 17:26:10 +02:00
|
|
|
absl::AnyInvocable<void() &&> Thread::Get(int cmsWait) {
|
2020-01-13 14:07:22 +01:00
|
|
|
// Get w/wait + timer scan / dispatch + socket / event multiplexer dispatch
|
|
|
|
|
|
|
|
|
|
int64_t cmsTotal = cmsWait;
|
|
|
|
|
int64_t cmsElapsed = 0;
|
|
|
|
|
int64_t msStart = TimeMillis();
|
|
|
|
|
int64_t msCurrent = msStart;
|
|
|
|
|
while (true) {
|
|
|
|
|
// Check for posted events
|
|
|
|
|
int64_t cmsDelayNext = kForever;
|
2022-08-24 18:35:45 +02:00
|
|
|
{
|
2020-01-13 14:07:22 +01:00
|
|
|
// All queue operations need to be locked, but nothing else in this loop
|
2022-08-24 18:35:45 +02:00
|
|
|
// can happen inside the crit.
|
|
|
|
|
CritScope cs(&crit_);
|
|
|
|
|
// Check for delayed messages that have been triggered and calculate the
|
|
|
|
|
// next trigger time.
|
|
|
|
|
while (!delayed_messages_.empty()) {
|
2022-09-16 17:26:10 +02:00
|
|
|
if (msCurrent < delayed_messages_.top().run_time_ms) {
|
2022-08-24 18:35:45 +02:00
|
|
|
cmsDelayNext =
|
2022-09-16 17:26:10 +02:00
|
|
|
TimeDiff(delayed_messages_.top().run_time_ms, msCurrent);
|
2020-01-13 14:07:22 +01:00
|
|
|
break;
|
|
|
|
|
}
|
2022-09-16 17:26:10 +02:00
|
|
|
messages_.push(std::move(delayed_messages_.top().functor));
|
2022-08-24 18:35:45 +02:00
|
|
|
delayed_messages_.pop();
|
|
|
|
|
}
|
|
|
|
|
// Pull a message off the message queue, if available.
|
|
|
|
|
if (!messages_.empty()) {
|
2022-09-16 17:26:10 +02:00
|
|
|
absl::AnyInvocable<void()&&> task = std::move(messages_.front());
|
|
|
|
|
messages_.pop();
|
|
|
|
|
return task;
|
2020-01-13 14:07:22 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (IsQuitting())
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
// Which is shorter, the delay wait or the asked wait?
|
|
|
|
|
|
|
|
|
|
int64_t cmsNext;
|
|
|
|
|
if (cmsWait == kForever) {
|
|
|
|
|
cmsNext = cmsDelayNext;
|
|
|
|
|
} else {
|
|
|
|
|
cmsNext = std::max<int64_t>(0, cmsTotal - cmsElapsed);
|
|
|
|
|
if ((cmsDelayNext != kForever) && (cmsDelayNext < cmsNext))
|
|
|
|
|
cmsNext = cmsDelayNext;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
// Wait and multiplex in the meantime
|
2022-08-25 11:40:13 +00:00
|
|
|
if (!ss_->Wait(cmsNext == kForever ? SocketServer::kForever
|
|
|
|
|
: webrtc::TimeDelta::Millis(cmsNext),
|
2022-09-16 17:26:10 +02:00
|
|
|
/*process_io=*/true))
|
|
|
|
|
return nullptr;
|
2020-01-13 14:07:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If the specified timeout expired, return
|
|
|
|
|
|
|
|
|
|
msCurrent = TimeMillis();
|
|
|
|
|
cmsElapsed = TimeDiff(msCurrent, msStart);
|
|
|
|
|
if (cmsWait != kForever) {
|
|
|
|
|
if (cmsElapsed >= cmsWait)
|
2022-09-16 17:26:10 +02:00
|
|
|
return nullptr;
|
2020-01-13 14:07:22 +01:00
|
|
|
}
|
|
|
|
|
}
|
2022-09-16 17:26:10 +02:00
|
|
|
return nullptr;
|
2020-01-13 14:07:22 +01:00
|
|
|
}
|
|
|
|
|
|
2022-09-16 17:26:10 +02:00
|
|
|
void Thread::PostTask(absl::AnyInvocable<void() &&> task) {
|
2020-01-13 14:07:22 +01:00
|
|
|
if (IsQuitting()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Keep thread safe
|
|
|
|
|
// Add the message to the end of the queue
|
|
|
|
|
// Signal for the multiplexer to return
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
CritScope cs(&crit_);
|
2022-09-16 17:26:10 +02:00
|
|
|
messages_.push(std::move(task));
|
2020-01-13 14:07:22 +01:00
|
|
|
}
|
|
|
|
|
WakeUpSocketServer();
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-16 17:26:10 +02:00
|
|
|
void Thread::PostDelayedHighPrecisionTask(absl::AnyInvocable<void() &&> task,
|
|
|
|
|
webrtc::TimeDelta delay) {
|
2020-01-13 14:07:22 +01:00
|
|
|
if (IsQuitting()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Keep thread safe
|
|
|
|
|
// Add to the priority queue. Gets sorted soonest first.
|
|
|
|
|
// Signal for the multiplexer to return.
|
|
|
|
|
|
2022-09-16 17:26:10 +02:00
|
|
|
int64_t delay_ms = delay.RoundUpTo(webrtc::TimeDelta::Millis(1)).ms<int>();
|
|
|
|
|
int64_t run_time_ms = TimeAfter(delay_ms);
|
2020-01-13 14:07:22 +01:00
|
|
|
{
|
|
|
|
|
CritScope cs(&crit_);
|
2022-09-16 17:26:10 +02:00
|
|
|
delayed_messages_.push({.delay_ms = delay_ms,
|
|
|
|
|
.run_time_ms = run_time_ms,
|
|
|
|
|
.message_number = delayed_next_num_,
|
|
|
|
|
.functor = std::move(task)});
|
2020-01-13 14:07:22 +01:00
|
|
|
// If this message queue processes 1 message every millisecond for 50 days,
|
|
|
|
|
// we will wrap this number. Even then, only messages with identical times
|
|
|
|
|
// will be misordered, and then only briefly. This is probably ok.
|
2020-01-17 14:46:08 +01:00
|
|
|
++delayed_next_num_;
|
|
|
|
|
RTC_DCHECK_NE(0, delayed_next_num_);
|
2020-01-13 14:07:22 +01:00
|
|
|
}
|
|
|
|
|
WakeUpSocketServer();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int Thread::GetDelay() {
|
|
|
|
|
CritScope cs(&crit_);
|
|
|
|
|
|
2020-01-17 14:46:08 +01:00
|
|
|
if (!messages_.empty())
|
2020-01-13 14:07:22 +01:00
|
|
|
return 0;
|
|
|
|
|
|
2020-01-17 14:46:08 +01:00
|
|
|
if (!delayed_messages_.empty()) {
|
2022-09-16 17:26:10 +02:00
|
|
|
int delay = TimeUntil(delayed_messages_.top().run_time_ms);
|
2020-01-13 14:07:22 +01:00
|
|
|
if (delay < 0)
|
|
|
|
|
delay = 0;
|
|
|
|
|
return delay;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return kForever;
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-16 17:26:10 +02:00
|
|
|
void Thread::Dispatch(absl::AnyInvocable<void() &&> task) {
|
|
|
|
|
TRACE_EVENT0("webrtc", "Thread::Dispatch");
|
2021-01-27 21:52:14 +00:00
|
|
|
RTC_DCHECK_RUN_ON(this);
|
2020-01-13 14:07:22 +01:00
|
|
|
int64_t start_time = TimeMillis();
|
2022-09-16 17:26:10 +02:00
|
|
|
std::move(task)();
|
2020-01-13 14:07:22 +01:00
|
|
|
int64_t end_time = TimeMillis();
|
|
|
|
|
int64_t diff = TimeDiff(end_time, start_time);
|
2021-01-27 21:52:14 +00:00
|
|
|
if (diff >= dispatch_warning_ms_) {
|
|
|
|
|
RTC_LOG(LS_INFO) << "Message to " << name() << " took " << diff
|
2022-09-16 17:26:10 +02:00
|
|
|
<< "ms to dispatch.";
|
2021-01-27 21:52:14 +00:00
|
|
|
// To avoid log spew, move the warning limit to only give warning
|
|
|
|
|
// for delays that are larger than the one observed.
|
|
|
|
|
dispatch_warning_ms_ = diff + 1;
|
2020-01-13 14:07:22 +01: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() {
|
2021-01-15 10:41:01 +01:00
|
|
|
return std::unique_ptr<Thread>(new Thread(CreateDefaultSocketServer()));
|
2016-04-28 01:32:48 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-17 15:47:49 +01:00
|
|
|
bool Thread::SetName(absl::string_view name, const void* obj) {
|
2017-12-04 15:18:23 +01:00
|
|
|
RTC_DCHECK(!IsRunning());
|
|
|
|
|
|
2022-03-17 15:47:49 +01:00
|
|
|
name_ = std::string(name);
|
2014-05-13 18:00:26 +00:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-27 21:52:14 +00:00
|
|
|
void Thread::SetDispatchWarningMs(int deadline) {
|
|
|
|
|
if (!IsCurrent()) {
|
2022-07-06 19:42:34 +02:00
|
|
|
PostTask([this, deadline]() { SetDispatchWarningMs(deadline); });
|
2021-01-27 21:52:14 +00:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
RTC_DCHECK_RUN_ON(this);
|
|
|
|
|
dispatch_warning_ms_ = deadline;
|
|
|
|
|
}
|
|
|
|
|
|
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, "
|
2020-01-14 12:11:31 +01:00
|
|
|
"but blocking calls have been disallowed";
|
2017-12-04 15:18:23 +01:00
|
|
|
}
|
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());
|
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
|
2014-05-13 18:00:26 +00:00
|
|
|
} // namespace rtc
|
|
|
|
|
|
|
|
|
|
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() {
|
2020-01-13 14:07:22 +01:00
|
|
|
Thread::Quit();
|
2014-05-13 18:00:26 +00:00
|
|
|
Join();
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-13 13:12:25 +02:00
|
|
|
void Thread::BlockingCall(rtc::FunctionView<void()> functor) {
|
|
|
|
|
TRACE_EVENT0("webrtc", "Thread::BlockingCall");
|
|
|
|
|
|
2020-01-17 13:10:54 +01:00
|
|
|
RTC_DCHECK(!IsQuitting());
|
2016-07-22 13:30:05 +02:00
|
|
|
if (IsQuitting())
|
2014-05-13 18:00:26 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (IsCurrent()) {
|
Add utility to count the number of blocking thread invokes.
This is useful to understand how often we block in certain parts of the
api and track improvements/regressions.
There are two macros, both are only active for RTC_DCHECK_IS_ON builds:
* RTC_LOG_THREAD_BLOCK_COUNT()
Example:
void MyClass::MyFunction() {
RTC_LOG_THREAD_BLOCK_COUNT();
thread_->Invoke<void>([this](){ DoStuff(); });
}
When executing this function during a test, the output could be:
(my_file.cc:2): Blocking MyFunction: total=1 (actual=1, would=0)
The words 'actual' and 'would' reflect whether an actual thread switch
was made, or if in the case of a test using the same thread for more
than one role (e.g. signaling, worker, network are all the same thread)
that an actual thread switch did not occur but it would have occurred
in the case of having dedicated threads. The 'total' count is the sum.
* RTC_DCHECK_BLOCK_COUNT_NO_MORE_THAN(x)
Example:
void MyClass::MyFunction() {
RTC_LOG_THREAD_BLOCK_COUNT();
thread_->Invoke<void>([this](){ DoStuff(); });
thread_->Invoke<void>([this](){ MoreStuff(); });
RTC_DCHECK_BLOCK_COUNT_NO_MORE_THAN(1);
}
When a function is known to have blocking calls and we want to not
regress from the currently known number of blocking calls, we can use
this macro to state that at a certain point in a function, below
where RTC_LOG_THREAD_BLOCK_COUNT() is called, there must have occurred
no more than |x| (total) blocking calls. If more occur, a DCHECK will
hit and print out what the actual number of calls was:
# Fatal error in: my_file.cc, line 5
# last system error: 60
# Check failed: blocked_call_count_printer.GetTotalBlockedCallCount() <= 1 (2 vs. 1)
Bug: webrtc:12649
Change-Id: Ibac4f85f00b89680601dba54a651eac95a0f45d3
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/213782
Commit-Queue: Tommi <tommi@webrtc.org>
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#33632}
2021-04-07 10:08:28 +02:00
|
|
|
#if RTC_DCHECK_IS_ON
|
2021-05-25 11:17:07 +02:00
|
|
|
RTC_DCHECK(this->IsInvokeToThreadAllowed(this));
|
Add utility to count the number of blocking thread invokes.
This is useful to understand how often we block in certain parts of the
api and track improvements/regressions.
There are two macros, both are only active for RTC_DCHECK_IS_ON builds:
* RTC_LOG_THREAD_BLOCK_COUNT()
Example:
void MyClass::MyFunction() {
RTC_LOG_THREAD_BLOCK_COUNT();
thread_->Invoke<void>([this](){ DoStuff(); });
}
When executing this function during a test, the output could be:
(my_file.cc:2): Blocking MyFunction: total=1 (actual=1, would=0)
The words 'actual' and 'would' reflect whether an actual thread switch
was made, or if in the case of a test using the same thread for more
than one role (e.g. signaling, worker, network are all the same thread)
that an actual thread switch did not occur but it would have occurred
in the case of having dedicated threads. The 'total' count is the sum.
* RTC_DCHECK_BLOCK_COUNT_NO_MORE_THAN(x)
Example:
void MyClass::MyFunction() {
RTC_LOG_THREAD_BLOCK_COUNT();
thread_->Invoke<void>([this](){ DoStuff(); });
thread_->Invoke<void>([this](){ MoreStuff(); });
RTC_DCHECK_BLOCK_COUNT_NO_MORE_THAN(1);
}
When a function is known to have blocking calls and we want to not
regress from the currently known number of blocking calls, we can use
this macro to state that at a certain point in a function, below
where RTC_LOG_THREAD_BLOCK_COUNT() is called, there must have occurred
no more than |x| (total) blocking calls. If more occur, a DCHECK will
hit and print out what the actual number of calls was:
# Fatal error in: my_file.cc, line 5
# last system error: 60
# Check failed: blocked_call_count_printer.GetTotalBlockedCallCount() <= 1 (2 vs. 1)
Bug: webrtc:12649
Change-Id: Ibac4f85f00b89680601dba54a651eac95a0f45d3
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/213782
Commit-Queue: Tommi <tommi@webrtc.org>
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#33632}
2021-04-07 10:08:28 +02:00
|
|
|
RTC_DCHECK_RUN_ON(this);
|
|
|
|
|
could_be_blocking_call_count_++;
|
|
|
|
|
#endif
|
2022-09-13 13:12:25 +02:00
|
|
|
functor();
|
2014-05-13 18:00:26 +00:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-24 17:14:05 +00:00
|
|
|
AssertBlockingIsAllowedOnCurrentThread();
|
|
|
|
|
|
2014-05-13 18:00:26 +00:00
|
|
|
Thread* current_thread = Thread::Current();
|
2020-09-04 16:33:25 +02:00
|
|
|
|
2020-03-03 10:48:05 +01:00
|
|
|
#if RTC_DCHECK_IS_ON
|
2020-09-04 16:33:25 +02:00
|
|
|
if (current_thread) {
|
Add utility to count the number of blocking thread invokes.
This is useful to understand how often we block in certain parts of the
api and track improvements/regressions.
There are two macros, both are only active for RTC_DCHECK_IS_ON builds:
* RTC_LOG_THREAD_BLOCK_COUNT()
Example:
void MyClass::MyFunction() {
RTC_LOG_THREAD_BLOCK_COUNT();
thread_->Invoke<void>([this](){ DoStuff(); });
}
When executing this function during a test, the output could be:
(my_file.cc:2): Blocking MyFunction: total=1 (actual=1, would=0)
The words 'actual' and 'would' reflect whether an actual thread switch
was made, or if in the case of a test using the same thread for more
than one role (e.g. signaling, worker, network are all the same thread)
that an actual thread switch did not occur but it would have occurred
in the case of having dedicated threads. The 'total' count is the sum.
* RTC_DCHECK_BLOCK_COUNT_NO_MORE_THAN(x)
Example:
void MyClass::MyFunction() {
RTC_LOG_THREAD_BLOCK_COUNT();
thread_->Invoke<void>([this](){ DoStuff(); });
thread_->Invoke<void>([this](){ MoreStuff(); });
RTC_DCHECK_BLOCK_COUNT_NO_MORE_THAN(1);
}
When a function is known to have blocking calls and we want to not
regress from the currently known number of blocking calls, we can use
this macro to state that at a certain point in a function, below
where RTC_LOG_THREAD_BLOCK_COUNT() is called, there must have occurred
no more than |x| (total) blocking calls. If more occur, a DCHECK will
hit and print out what the actual number of calls was:
# Fatal error in: my_file.cc, line 5
# last system error: 60
# Check failed: blocked_call_count_printer.GetTotalBlockedCallCount() <= 1 (2 vs. 1)
Bug: webrtc:12649
Change-Id: Ibac4f85f00b89680601dba54a651eac95a0f45d3
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/213782
Commit-Queue: Tommi <tommi@webrtc.org>
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#33632}
2021-04-07 10:08:28 +02:00
|
|
|
RTC_DCHECK_RUN_ON(current_thread);
|
|
|
|
|
current_thread->blocking_call_count_++;
|
2020-09-04 16:33:25 +02:00
|
|
|
RTC_DCHECK(current_thread->IsInvokeToThreadAllowed(this));
|
|
|
|
|
ThreadManager::Instance()->RegisterSendAndCheckForCycles(current_thread,
|
|
|
|
|
this);
|
|
|
|
|
}
|
2020-03-03 10:48:05 +01:00
|
|
|
#endif
|
2020-09-04 16:33:25 +02:00
|
|
|
|
|
|
|
|
// Perhaps down the line we can get rid of this workaround and always require
|
2022-09-13 13:12:25 +02:00
|
|
|
// current_thread to be valid when BlockingCall() is called.
|
2020-09-04 16:33:25 +02:00
|
|
|
std::unique_ptr<rtc::Event> done_event;
|
|
|
|
|
if (!current_thread)
|
|
|
|
|
done_event.reset(new rtc::Event());
|
|
|
|
|
|
2014-05-13 18:00:26 +00:00
|
|
|
bool ready = false;
|
2022-07-06 19:42:34 +02:00
|
|
|
absl::Cleanup cleanup = [this, &ready, current_thread,
|
|
|
|
|
done = done_event.get()] {
|
|
|
|
|
if (current_thread) {
|
|
|
|
|
CritScope cs(&crit_);
|
|
|
|
|
ready = true;
|
|
|
|
|
current_thread->socketserver()->WakeUp();
|
|
|
|
|
} else {
|
|
|
|
|
done->Set();
|
|
|
|
|
}
|
|
|
|
|
};
|
2022-09-13 13:12:25 +02:00
|
|
|
PostTask([functor, cleanup = std::move(cleanup)] { functor(); });
|
2020-09-04 16:33:25 +02:00
|
|
|
if (current_thread) {
|
|
|
|
|
bool waited = false;
|
2014-05-13 18:00:26 +00:00
|
|
|
crit_.Enter();
|
2020-09-04 16:33:25 +02:00
|
|
|
while (!ready) {
|
|
|
|
|
crit_.Leave();
|
2022-08-25 11:40:13 +00:00
|
|
|
current_thread->socketserver()->Wait(SocketServer::kForever, false);
|
2020-09-04 16:33:25 +02:00
|
|
|
waited = true;
|
|
|
|
|
crit_.Enter();
|
|
|
|
|
}
|
|
|
|
|
crit_.Leave();
|
|
|
|
|
|
|
|
|
|
// Our Wait loop above may have consumed some WakeUp events for this
|
|
|
|
|
// Thread, 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();
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
done_event->Wait(rtc::Event::kForever);
|
2014-05-13 18:00:26 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-15 10:11:56 +02:00
|
|
|
// Called by the ThreadManager when being set as the current thread.
|
|
|
|
|
void Thread::EnsureIsCurrentTaskQueue() {
|
|
|
|
|
task_queue_registration_ =
|
|
|
|
|
std::make_unique<TaskQueueBase::CurrentTaskQueueSetter>(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Called by the ThreadManager when being set as the current thread.
|
|
|
|
|
void Thread::ClearCurrentTaskQueue() {
|
|
|
|
|
task_queue_registration_.reset();
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-03 12:09:26 +02:00
|
|
|
void Thread::AllowInvokesToThread(Thread* thread) {
|
2021-07-30 13:57:25 +02:00
|
|
|
#if (!defined(NDEBUG) || RTC_DCHECK_IS_ON)
|
2020-07-03 12:09:26 +02:00
|
|
|
if (!IsCurrent()) {
|
2022-07-18 17:04:56 +02:00
|
|
|
PostTask([thread, this]() { AllowInvokesToThread(thread); });
|
2020-07-03 12:09:26 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
RTC_DCHECK_RUN_ON(this);
|
|
|
|
|
allowed_threads_.push_back(thread);
|
|
|
|
|
invoke_policy_enabled_ = true;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Thread::DisallowAllInvokes() {
|
2021-07-30 13:57:25 +02:00
|
|
|
#if (!defined(NDEBUG) || RTC_DCHECK_IS_ON)
|
2020-07-03 12:09:26 +02:00
|
|
|
if (!IsCurrent()) {
|
2022-07-18 17:04:56 +02:00
|
|
|
PostTask([this]() { DisallowAllInvokes(); });
|
2020-07-03 12:09:26 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
RTC_DCHECK_RUN_ON(this);
|
|
|
|
|
allowed_threads_.clear();
|
|
|
|
|
invoke_policy_enabled_ = true;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
Add utility to count the number of blocking thread invokes.
This is useful to understand how often we block in certain parts of the
api and track improvements/regressions.
There are two macros, both are only active for RTC_DCHECK_IS_ON builds:
* RTC_LOG_THREAD_BLOCK_COUNT()
Example:
void MyClass::MyFunction() {
RTC_LOG_THREAD_BLOCK_COUNT();
thread_->Invoke<void>([this](){ DoStuff(); });
}
When executing this function during a test, the output could be:
(my_file.cc:2): Blocking MyFunction: total=1 (actual=1, would=0)
The words 'actual' and 'would' reflect whether an actual thread switch
was made, or if in the case of a test using the same thread for more
than one role (e.g. signaling, worker, network are all the same thread)
that an actual thread switch did not occur but it would have occurred
in the case of having dedicated threads. The 'total' count is the sum.
* RTC_DCHECK_BLOCK_COUNT_NO_MORE_THAN(x)
Example:
void MyClass::MyFunction() {
RTC_LOG_THREAD_BLOCK_COUNT();
thread_->Invoke<void>([this](){ DoStuff(); });
thread_->Invoke<void>([this](){ MoreStuff(); });
RTC_DCHECK_BLOCK_COUNT_NO_MORE_THAN(1);
}
When a function is known to have blocking calls and we want to not
regress from the currently known number of blocking calls, we can use
this macro to state that at a certain point in a function, below
where RTC_LOG_THREAD_BLOCK_COUNT() is called, there must have occurred
no more than |x| (total) blocking calls. If more occur, a DCHECK will
hit and print out what the actual number of calls was:
# Fatal error in: my_file.cc, line 5
# last system error: 60
# Check failed: blocked_call_count_printer.GetTotalBlockedCallCount() <= 1 (2 vs. 1)
Bug: webrtc:12649
Change-Id: Ibac4f85f00b89680601dba54a651eac95a0f45d3
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/213782
Commit-Queue: Tommi <tommi@webrtc.org>
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#33632}
2021-04-07 10:08:28 +02:00
|
|
|
#if RTC_DCHECK_IS_ON
|
|
|
|
|
uint32_t Thread::GetBlockingCallCount() const {
|
|
|
|
|
RTC_DCHECK_RUN_ON(this);
|
|
|
|
|
return blocking_call_count_;
|
|
|
|
|
}
|
|
|
|
|
uint32_t Thread::GetCouldBeBlockingCallCount() const {
|
|
|
|
|
RTC_DCHECK_RUN_ON(this);
|
|
|
|
|
return could_be_blocking_call_count_;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2020-07-03 12:09:26 +02:00
|
|
|
// Returns true if no policies added or if there is at least one policy
|
2021-07-26 16:03:14 +02:00
|
|
|
// that permits invocation to `target` thread.
|
2020-07-03 12:09:26 +02:00
|
|
|
bool Thread::IsInvokeToThreadAllowed(rtc::Thread* target) {
|
2021-07-30 13:57:25 +02:00
|
|
|
#if (!defined(NDEBUG) || RTC_DCHECK_IS_ON)
|
2020-07-03 12:09:26 +02:00
|
|
|
RTC_DCHECK_RUN_ON(this);
|
|
|
|
|
if (!invoke_policy_enabled_) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
for (const auto* thread : allowed_threads_) {
|
|
|
|
|
if (thread == target) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
#else
|
|
|
|
|
return true;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-22 15:52:40 +01:00
|
|
|
void Thread::Delete() {
|
|
|
|
|
Stop();
|
|
|
|
|
delete this;
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-06 19:42:34 +02:00
|
|
|
void Thread::PostDelayedTask(absl::AnyInvocable<void() &&> task,
|
|
|
|
|
webrtc::TimeDelta delay) {
|
|
|
|
|
// This implementation does not support low precision yet.
|
|
|
|
|
PostDelayedHighPrecisionTask(std::move(task), delay);
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-06 08:42:44 +02:00
|
|
|
bool Thread::IsProcessingMessagesForTesting() {
|
2020-01-13 14:07:22 +01:00
|
|
|
return (owned_ || IsCurrent()) && !IsQuitting();
|
2018-09-06 08:42:44 +02:00
|
|
|
}
|
|
|
|
|
|
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
|
2022-09-16 17:26:10 +02:00
|
|
|
absl::AnyInvocable<void()&&> task = Get(cmsNext);
|
|
|
|
|
if (!task)
|
2017-02-22 00:42:11 -08:00
|
|
|
return !IsQuitting();
|
2022-09-16 17:26:10 +02:00
|
|
|
Dispatch(std::move(task));
|
2017-02-22 00:42:11 -08:00
|
|
|
|
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-02 15:20:33 -08:00
|
|
|
AutoThread::AutoThread()
|
2021-01-15 10:41:01 +01:00
|
|
|
: Thread(CreateDefaultSocketServer(), /*do_init=*/false) {
|
2014-05-13 18:00:26 +00:00
|
|
|
if (!ThreadManager::Instance()->CurrentThread()) {
|
2020-01-13 14:07:22 +01:00
|
|
|
// DoInit registers with ThreadManager. Do that only if we intend to
|
2019-06-12 11:30:59 +02:00
|
|
|
// 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_) {
|
2020-01-13 14:07:22 +01:00
|
|
|
ThreadManager::Remove(old_thread_);
|
2017-05-08 05:25:41 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AutoSocketServerThread::~AutoSocketServerThread() {
|
|
|
|
|
RTC_DCHECK(ThreadManager::Instance()->CurrentThread() == this);
|
2017-10-19 10:17:12 -07:00
|
|
|
// Stop and destroy the thread before clearing it as the current thread.
|
2020-01-13 14:07:22 +01:00
|
|
|
// Sometimes there are messages left in the Thread that will be
|
2017-10-19 10:17:12 -07:00
|
|
|
// 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_) {
|
2020-01-13 14:07:22 +01:00
|
|
|
ThreadManager::Add(old_thread_);
|
2017-05-08 05:25:41 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-13 18:00:26 +00:00
|
|
|
} // namespace rtc
|