This repository was archived by the owner on Feb 25, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 6k
Add synchronization mechanism to avoid deadlock caused by thread merging #30314
Closed
Closed
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,9 +13,12 @@ | |
| #include "flutter/fml/message_loop.h" | ||
| #include "flutter/fml/message_loop_impl.h" | ||
| #include "flutter/fml/message_loop_task_queues.h" | ||
| #include "flutter/fml/synchronization/waitable_event.h" | ||
|
|
||
| namespace fml { | ||
|
|
||
| std::mutex g_thread_merging_lock; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can't have global locks when working with non-singleton instances. |
||
|
|
||
| TaskRunner::TaskRunner(fml::RefPtr<MessageLoopImpl> loop) | ||
| : loop_(std::move(loop)) {} | ||
|
|
||
|
|
@@ -62,4 +65,19 @@ void TaskRunner::RunNowOrPostTask(fml::RefPtr<fml::TaskRunner> runner, | |
| } | ||
| } | ||
|
|
||
| void TaskRunner::RunNowOrPostTaskSync(fml::RefPtr<fml::TaskRunner> runner, | ||
| const fml::closure& task) { | ||
| FML_DCHECK(runner); | ||
| std::scoped_lock lock(g_thread_merging_lock); | ||
| if (runner->RunsTasksOnCurrentThread()) { | ||
| task(); | ||
| } else { | ||
| fml::AutoResetWaitableEvent latch; | ||
| runner->PostTask([&] { | ||
| task(); | ||
| latch.Signal(); | ||
| }); | ||
| latch.Wait(); | ||
| } | ||
| } | ||
| } // namespace fml | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,6 +16,10 @@ namespace fml { | |
|
|
||
| class MessageLoopImpl; | ||
|
|
||
| /// To avoid data races between the platform thread posting sync tasks to the | ||
| /// raster thread and the raster thread merging. | ||
| extern std::mutex g_thread_merging_lock; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When adding a mutex, I would ask myself what the critical section is. From the documentation, it is not clear what that is. |
||
|
|
||
| /// An interface over the ability to schedule tasks on a \p TaskRunner. | ||
| class BasicTaskRunner { | ||
| public: | ||
|
|
@@ -62,6 +66,11 @@ class TaskRunner : public fml::RefCountedThreadSafe<TaskRunner>, | |
| static void RunNowOrPostTask(fml::RefPtr<fml::TaskRunner> runner, | ||
| const fml::closure& task); | ||
|
|
||
| /// Similar to |RunNowOrPostTask|, but it needs to mutex with thread | ||
| /// merging operation and post the \p tast synchronously. | ||
| static void RunNowOrPostTaskSync(fml::RefPtr<fml::TaskRunner> runner, | ||
| const fml::closure& task); | ||
|
|
||
| protected: | ||
| explicit TaskRunner(fml::RefPtr<MessageLoopImpl> loop); | ||
|
|
||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@iskakaushik @cyanglaz - do we want to specialize this to the PlatformThread?
Do we not also need to flush any raster tasks?
Should we just be flushing both queues first?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry about the delay. I just cycled back to this today.
We actually cannot flush raster tasks before thread merging. Here's why:
Let's say we have 2 tasks in the raster task queue waiting to be executed. Frame 1 and Frame 2.
Each task represents a frame that will be drawn on the screen. (For example, a scroll animation or a new page transition animation)
Now frame 1 gave us the signal that a thread merge needs to happen (there is a platform view appearing in frame 1).
What we do today is that we drop frame 1 after pre-roll (that's when we know a platform view is in the layer_tree), create a new copy of frame 1, merge the thread, run frame 1 and frame 2 on platform thread.
So we cannot just flush frame 1 and frame 2 on the raster thread because they have to be run on the platform thread. Even when frame 2 doesn't need to run on platform thread (like how the example in the issue is), we still need to run frame 1 on the platform thread.