Makes Thread::Send execute sent messages after pending posted messages.

Bug: webrtc:11255
Change-Id: I4b9036d22c9db3a5ec0e19fc5f2f5ac0d7e2289a
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/168058
Commit-Queue: Sebastian Jansson <srte@webrtc.org>
Reviewed-by: Karl Wiberg <kwiberg@webrtc.org>
Reviewed-by: Ali Tofigh <alito@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#30667}
This commit is contained in:
Sebastian Jansson
2020-03-03 10:48:05 +01:00
committed by Commit Bot
parent 3a087a839a
commit da7267a10f
4 changed files with 96 additions and 107 deletions

View File

@ -34,6 +34,7 @@
#include "rtc_base/critical_section.h"
#include "rtc_base/logging.h"
#include "rtc_base/null_socket_server.h"
#include "rtc_base/task_utils/to_queued_task.h"
#include "rtc_base/time_utils.h"
#include "rtc_base/trace_event.h"
@ -142,9 +143,44 @@ void ThreadManager::RemoveInternal(Thread* message_queue) {
if (iter != message_queues_.end()) {
message_queues_.erase(iter);
}
#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) {
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.
for (auto it = all_targets.begin(); it != all_targets.end(); ++it) {
const auto& targets = send_graph_[*it];
all_targets.insert(all_targets.end(), targets.begin(), targets.end());
}
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);
}
#endif
// static
void ThreadManager::Clear(MessageHandler* handler) {
return Instance()->ClearInternal(handler);
@ -404,9 +440,6 @@ bool Thread::Get(Message* pmsg, int cmsWait, bool process_io) {
int64_t msStart = TimeMillis();
int64_t msCurrent = msStart;
while (true) {
// Check for sent messages
ReceiveSendsFromThread(nullptr);
// Check for posted events
int64_t cmsDelayNext = kForever;
bool first_pass = true;
@ -836,7 +869,7 @@ void Thread::Send(const Location& posted_from,
msg.message_id = id;
msg.pdata = pdata;
if (IsCurrent()) {
phandler->OnMessage(&msg);
msg.phandler->OnMessage(&msg);
return;
}
@ -845,27 +878,23 @@ void Thread::Send(const Location& posted_from,
AutoThread thread;
Thread* current_thread = Thread::Current();
RTC_DCHECK(current_thread != nullptr); // AutoThread ensures this
#if RTC_DCHECK_IS_ON
ThreadManager::Instance()->RegisterSendAndCheckForCycles(current_thread,
this);
#endif
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();
PostTask(
webrtc::ToQueuedTask([msg]() mutable { msg.phandler->OnMessage(&msg); },
[this, &ready, current_thread] {
CritScope cs(&crit_);
ready = true;
current_thread->socketserver()->WakeUp();
}));
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();
@ -888,38 +917,6 @@ void Thread::Send(const Location& posted_from,
}
}
void Thread::ReceiveSendsFromThread(const Thread* source) {
// Receive a sent message. Cleanup scenarios:
// - thread sending exits: We don't allow this, since thread can exit
// only via Join, so Send must complete.
// - thread receiving exits: Wakeup/set ready in Thread::Clear()
// - object target cleared: Wakeup/set ready in Thread::Clear()
_SendMessage smsg;
crit_.Enter();
while (PopSendMessageFromThread(source, &smsg)) {
crit_.Leave();
Dispatch(&smsg.msg);
crit_.Enter();
*smsg.ready = true;
smsg.thread->socketserver()->WakeUp();
}
crit_.Leave();
}
bool Thread::PopSendMessageFromThread(const Thread* source, _SendMessage* msg) {
for (auto 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,
rtc::FunctionView<void()> functor) {
TRACE_EVENT2("webrtc", "Thread::Invoke", "src_file", posted_from.file_name(),
@ -981,26 +978,6 @@ 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.
for (auto iter = sendlist_.begin(); iter != sendlist_.end();) {
_SendMessage smsg = *iter;
if (smsg.msg.Match(phandler, id)) {
if (removed) {
removed->push_back(smsg.msg);
} else {
delete smsg.msg.pdata;
}
iter = sendlist_.erase(iter);
*smsg.ready = true;
smsg.thread->socketserver()->WakeUp();
continue;
}
++iter;
}
ClearInternal(phandler, id, removed);
}