Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make message loop task entry containers thread safe #11367

Merged
merged 10 commits into from Aug 23, 2019

Conversation

iskakaushik
Copy link
Contributor

@iskakaushik iskakaushik commented Aug 22, 2019

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.

1. Make as many methods as possible const.
2. Migrate all the queue members to a struct, and have a map.
3. Guard all the const methods with a read lock and everything else with
a write lock.
@iskakaushik
Copy link
Contributor Author

This addresses flutter/flutter#38778

@iskakaushik iskakaushik changed the title Make MessageLoopTaskQueues thread safe Make message loop task entry containers thread safe Aug 22, 2019
task_queue_->GetTasksToRunNow(queue_id_, type, invocations);

for (const auto& invocation : invocations) {
invocation();
task_queue_->NotifyObservers(queue_id_);
std::vector<fml::closure> observers;
task_queue_->GetObserversToNotify(queue_id_, observers);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let just make this return a vector.

@@ -30,6 +31,20 @@ class TaskQueueId {
size_t value_ = kUnmerged;
};

static const TaskQueueId _kUnmerged = TaskQueueId(TaskQueueId::kUnmerged);

class TaskQueueEntry {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doxygen comment block for this.

TaskQueueId owner_of;
TaskQueueId subsumed_by;

TaskQueueEntry();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Disallow copy and assign here.

Wakeable* wakeable;
TaskObservers task_observers;
DelayedTaskQueue delayed_tasks;
TaskQueueId owner_of;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comments here saying these are mutually exclusive and optional.

Wakeable* wakeable;
TaskObservers task_observers;
DelayedTaskQueue delayed_tasks;
TaskQueueId owner_of;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comments here saying these are mutually exclusive and optional.

MergedQueuesRunner merged_tasks = MergedQueuesRunner(*this, queue_id);
merged_tasks.InvokeMerged(
[&](TaskQueueId queue_id) { delayed_tasks_[queue_id] = {}; });
std::scoped_lock queue_lock(GetMutex(queue_id));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DCHECK here to make sure queue ID is part of the entries.

size_t MessageLoopTaskQueues::GetNumPendingTasks(TaskQueueId queue_id) const {
std::scoped_lock queue_lock(GetMutex(queue_id));

if (queue_entries_.at(queue_id).subsumed_by != _kUnmerged) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Get the iterator once and stash it in a variable.

// delayed_tasks locks
std::mutex& t1 = GetMutex(primary, MutexType::kTasks);
std::mutex& t2 = GetMutex(secondary, MutexType::kTasks);
if (queue_entries_.at(queue_id).subsumed_by != _kUnmerged) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto about getting the iterator once.

if (owner == subsumed) {
return true;
}

if (owner_to_subsumed_[owner] == subsumed) {
std::mutex& owner_lock = GetMutex(owner);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ivar should probably be named mutex instead of lock. Also, auto& would be fine too.

@iskakaushik iskakaushik merged commit 632a37b into flutter:master Aug 23, 2019
@iskakaushik iskakaushik deleted the rw-lock branch August 23, 2019 06:27
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Aug 23, 2019
engine-flutter-autoroll added a commit to flutter/flutter that referenced this pull request Aug 23, 2019
git@github.com:flutter/engine.git/compare/975a8aa5752e...1e828b2

git log 975a8aa..1e828b2 --no-merges --oneline
2019-08-23 iska.kaushik@gmail.com Ios simulator unittests seem to not consider the full compilation unit (flutter/engine#11413)
2019-08-23 iska.kaushik@gmail.com Make message loop task entry containers thread safe (flutter/engine#11367)

The AutoRoll server is located here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+/master/autoroll/README.md

If the roll is causing failures, please contact the current sheriff (liyuqian@google.com), and stop
the roller if necessary.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
3 participants