Flutter macOS Embedder
FlutterThreadSynchronizer.mm
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
6 
7 #import <QuartzCore/QuartzCore.h>
8 
9 #include <mutex>
10 #include <unordered_map>
11 #include <vector>
12 
13 #import "flutter/fml/logging.h"
14 #import "flutter/fml/synchronization/waitable_event.h"
15 
17  dispatch_queue_t _mainQueue;
18  std::mutex _mutex;
20  std::unordered_map<int64_t, CGSize> _contentSizes;
21  std::vector<dispatch_block_t> _scheduledBlocks;
22 
24 
25  // Used to block [beginResize:].
26  std::condition_variable _condBlockBeginResize;
27 }
28 
29 /**
30  * Returns true if all existing views have a non-zero size.
31  *
32  * If there are no views, still returns true.
33  */
34 - (BOOL)allViewsHaveFrame;
35 
36 /**
37  * Returns true if there are any views that have a non-zero size.
38  *
39  * If there are no views, returns false.
40  */
41 - (BOOL)someViewsHaveFrame;
42 
43 @end
44 
45 @implementation FlutterThreadSynchronizer
46 
47 - (instancetype)init {
48  return [self initWithMainQueue:dispatch_get_main_queue()];
49 }
50 
51 - (instancetype)initWithMainQueue:(dispatch_queue_t)queue {
52  self = [super init];
53  if (self != nil) {
54  _mainQueue = queue;
55  }
56  return self;
57 }
58 
59 - (BOOL)allViewsHaveFrame {
60  for (auto const& [viewId, contentSize] : _contentSizes) {
61  if (CGSizeEqualToSize(contentSize, CGSizeZero)) {
62  return NO;
63  }
64  }
65  return YES;
66 }
67 
68 - (BOOL)someViewsHaveFrame {
69  for (auto const& [viewId, contentSize] : _contentSizes) {
70  if (!CGSizeEqualToSize(contentSize, CGSizeZero)) {
71  return YES;
72  }
73  }
74  return NO;
75 }
76 
77 - (void)drain {
78  dispatch_assert_queue(_mainQueue);
79 
80  [CATransaction begin];
81  [CATransaction setDisableActions:YES];
82  for (dispatch_block_t block : _scheduledBlocks) {
83  block();
84  }
85  [CATransaction commit];
86  _scheduledBlocks.clear();
87 }
88 
90  std::unique_lock<std::mutex> lock(_mutex);
91 
92  _beginResizeWaiting = YES;
93 
94  while (![self someViewsHaveFrame] && !_shuttingDown) {
95  _condBlockBeginResize.wait(lock);
96  [self drain];
97  }
98 
99  _beginResizeWaiting = NO;
100 }
101 
102 - (void)beginResizeForView:(int64_t)viewId
103  size:(CGSize)size
104  notify:(nonnull dispatch_block_t)notify {
105  dispatch_assert_queue(_mainQueue);
106  std::unique_lock<std::mutex> lock(_mutex);
107 
108  if (![self allViewsHaveFrame] || _shuttingDown) {
109  // No blocking until framework produces at least one frame
110  notify();
111  return;
112  }
113 
114  [self drain];
115 
116  notify();
117 
118  _contentSizes[viewId] = CGSizeMake(-1, -1);
119 
120  _beginResizeWaiting = YES;
121 
122  while (true) {
123  if (_shuttingDown) {
124  break;
125  }
126  const CGSize& contentSize = _contentSizes[viewId];
127  if (CGSizeEqualToSize(contentSize, size) || CGSizeEqualToSize(contentSize, CGSizeZero)) {
128  break;
129  }
130  _condBlockBeginResize.wait(lock);
131  [self drain];
132  }
133 
134  _beginResizeWaiting = NO;
135 }
136 
137 - (void)performCommitForView:(int64_t)viewId
138  size:(CGSize)size
139  notify:(nonnull dispatch_block_t)notify {
140  dispatch_assert_queue_not(_mainQueue);
141  fml::AutoResetWaitableEvent event;
142  {
143  std::unique_lock<std::mutex> lock(_mutex);
144  if (_shuttingDown) {
145  // Engine is shutting down, main thread may be blocked by the engine
146  // waiting for raster thread to finish.
147  return;
148  }
149  fml::AutoResetWaitableEvent& e = event;
150  _scheduledBlocks.push_back(^{
151  notify();
152  _contentSizes[viewId] = size;
153  e.Signal();
154  });
155  if (_beginResizeWaiting) {
156  _condBlockBeginResize.notify_all();
157  } else {
158  dispatch_async(_mainQueue, ^{
159  std::unique_lock<std::mutex> lock(_mutex);
160  [self drain];
161  });
162  }
163  }
164  event.Wait();
165 }
166 
167 - (void)registerView:(int64_t)viewId {
168  dispatch_assert_queue(_mainQueue);
169  std::unique_lock<std::mutex> lock(_mutex);
170  _contentSizes[viewId] = CGSizeZero;
171 }
172 
173 - (void)deregisterView:(int64_t)viewId {
174  dispatch_assert_queue(_mainQueue);
175  std::unique_lock<std::mutex> lock(_mutex);
176  _contentSizes.erase(viewId);
177 }
178 
179 - (void)shutdown {
180  dispatch_assert_queue(_mainQueue);
181  std::unique_lock<std::mutex> lock(_mutex);
182  _shuttingDown = YES;
183  _condBlockBeginResize.notify_all();
184  [self drain];
185 }
186 
188  std::unique_lock<std::mutex> lock(_mutex);
189  return _beginResizeWaiting;
190 }
191 
192 @end
FlutterThreadSynchronizer()::_scheduledBlocks
std::vector< dispatch_block_t > _scheduledBlocks
Definition: FlutterThreadSynchronizer.mm:21
FlutterThreadSynchronizer()::_shuttingDown
BOOL _shuttingDown
Definition: FlutterThreadSynchronizer.mm:19
-[FlutterThreadSynchronizer init]
nullable instancetype init()
Definition: FlutterThreadSynchronizer.mm:47
-[FlutterThreadSynchronizer(TestUtils) isWaitingWhenMutexIsAvailable]
BOOL isWaitingWhenMutexIsAvailable()
-[FlutterThreadSynchronizer initWithMainQueue:]
nullable instancetype initWithMainQueue:(nonnull dispatch_queue_t queue)
FlutterThreadSynchronizer()::_beginResizeWaiting
BOOL _beginResizeWaiting
Definition: FlutterThreadSynchronizer.mm:23
FlutterThreadSynchronizer()::_mutex
std::mutex _mutex
Definition: FlutterThreadSynchronizer.mm:18
FlutterThreadSynchronizer()::_mainQueue
dispatch_queue_t _mainQueue
Definition: FlutterThreadSynchronizer.mm:17
FlutterThreadSynchronizer
Definition: FlutterThreadSynchronizer.h:13
FlutterThreadSynchronizer()::_condBlockBeginResize
std::condition_variable _condBlockBeginResize
Definition: FlutterThreadSynchronizer.mm:26
FlutterThreadSynchronizer()::_contentSizes
std::unordered_map< int64_t, CGSize > _contentSizes
Definition: FlutterThreadSynchronizer.mm:20
FlutterThreadSynchronizer.h
-[FlutterThreadSynchronizer(TestUtils) blockUntilFrameAvailable]
void blockUntilFrameAvailable()
-[FlutterThreadSynchronizer shutdown]
void shutdown()
Definition: FlutterThreadSynchronizer.mm:179