Kaushik Iska 0d8da99a35 Make message loop task entry containers thread safe (flutter/engine#11367)
The core underlying issue is that vector push_back could re-allocate and cause us to segfault. I have switched the backing queues to a map per @jason-simmons suggestion in flutter/flutter#38778.

I've also added a test to capture the aforementioned bug. I've run internal tests several times to validate that this is fixed.

General threading note for this class is that only the following operations take a write lock on the meta mutex:

1. Create
2. Dispose

The rest of the operations take read lock on the meta mutex and acquire finer grained locks for the duration of the operation. We can not grab read lock for the entire duration of NotifyObservers for example because observer can in-turn create other queues -- Which we should not block.

Additional changes:

1. Make as many methods as possible const. Unlocked methods are all const.
2. Migrate all the queue members to a struct, and have a map.
3. Get rid of the un-used Swap functionality.
2019-08-22 23:27:25 -07:00

85 lines
2.1 KiB
C++

// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/fml/message_loop.h"
#include <utility>
#include "flutter/fml/memory/ref_counted.h"
#include "flutter/fml/memory/ref_ptr.h"
#include "flutter/fml/message_loop_impl.h"
#include "flutter/fml/task_runner.h"
#include "flutter/fml/thread_local.h"
namespace fml {
FML_THREAD_LOCAL ThreadLocalUniquePtr<MessageLoop> tls_message_loop;
MessageLoop& MessageLoop::GetCurrent() {
auto* loop = tls_message_loop.get();
FML_CHECK(loop != nullptr)
<< "MessageLoop::EnsureInitializedForCurrentThread was not called on "
"this thread prior to message loop use.";
return *loop;
}
void MessageLoop::EnsureInitializedForCurrentThread() {
if (tls_message_loop.get() != nullptr) {
// Already initialized.
return;
}
tls_message_loop.reset(new MessageLoop());
}
bool MessageLoop::IsInitializedForCurrentThread() {
return tls_message_loop.get() != nullptr;
}
MessageLoop::MessageLoop()
: loop_(MessageLoopImpl::Create()),
task_runner_(fml::MakeRefCounted<fml::TaskRunner>(loop_)) {
FML_CHECK(loop_);
FML_CHECK(task_runner_);
}
MessageLoop::~MessageLoop() = default;
void MessageLoop::Run() {
loop_->DoRun();
}
void MessageLoop::Terminate() {
loop_->DoTerminate();
}
fml::RefPtr<fml::TaskRunner> MessageLoop::GetTaskRunner() const {
return task_runner_;
}
fml::RefPtr<MessageLoopImpl> MessageLoop::GetLoopImpl() const {
return loop_;
}
void MessageLoop::AddTaskObserver(intptr_t key, fml::closure callback) {
loop_->AddTaskObserver(key, callback);
}
void MessageLoop::RemoveTaskObserver(intptr_t key) {
loop_->RemoveTaskObserver(key);
}
void MessageLoop::RunExpiredTasksNow() {
loop_->RunExpiredTasksNow();
}
TaskQueueId MessageLoop::GetCurrentTaskQueueId() {
auto* loop = tls_message_loop.get();
FML_CHECK(loop != nullptr)
<< "MessageLoop::EnsureInitializedForCurrentThread was not called on "
"this thread prior to message loop use.";
return loop->GetLoopImpl()->GetTaskQueueId();
}
} // namespace fml