Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(131)

Side by Side Diff: mojo/public/dart/src/handle_watcher.dart

Issue 800523004: Dart: Simplifies the handle watcher. Various cleanups and bugfixes. (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 part of core; 5 part of core;
6 6
7 class _MojoHandleWatcherNatives { 7 class _MojoHandleWatcherNatives {
8 static int sendControlData( 8 static int sendControlData(
9 int controlHandle, int mojoHandle, SendPort port, int data) 9 int controlHandle, int mojoHandle, SendPort port, int data)
10 native "MojoHandleWatcher_SendControlData"; 10 native "MojoHandleWatcher_SendControlData";
(...skipping 15 matching lines...) Expand all
26 // 26 //
27 // add(handle, port, signals) - Instructs the MojoHandleWatcher isolate to add 27 // add(handle, port, signals) - Instructs the MojoHandleWatcher isolate to add
28 // 'handle' to the set of handles it watches, and to notify the calling 28 // 'handle' to the set of handles it watches, and to notify the calling
29 // isolate only for the events specified by 'signals' using the send port 29 // isolate only for the events specified by 'signals' using the send port
30 // 'port' 30 // 'port'
31 // 31 //
32 // remove(handle) - Instructs the MojoHandleWatcher isolate to remove 'handle' 32 // remove(handle) - Instructs the MojoHandleWatcher isolate to remove 'handle'
33 // from the set of handles it watches. This allows the application isolate 33 // from the set of handles it watches. This allows the application isolate
34 // to, e.g., pause the stream of events. 34 // to, e.g., pause the stream of events.
35 // 35 //
36 // toggleWrite(handle) - Modifies the set of signals that an application isolate
37 // wishes to be notified about. Whether the application isolate should be
38 // be notified about a handle ready for writing is made the opposite.
39 //
40 // close(handle) - Notifies the HandleWatcherIsolate that a handle it is 36 // close(handle) - Notifies the HandleWatcherIsolate that a handle it is
41 // watching should be removed from its set and closed. 37 // watching should be removed from its set and closed.
42 class MojoHandleWatcher { 38 class MojoHandleWatcher {
43 // Control commands. 39 // Control commands.
44 static const int ADD = 0; 40 static const int ADD = 0;
45 static const int REMOVE = 1; 41 static const int REMOVE = 1;
46 static const int TOGGLE_WRITE = 2; 42 static const int CLOSE = 2;
47 static const int CLOSE = 3; 43 static const int TIMER = 3;
48 static const int TIMER = 4; 44 static const int SHUTDOWN = 4;
49 static const int SHUTDOWN = 5;
50 45
51 static int _encodeCommand(int cmd, [int signals = 0]) => 46 static int _encodeCommand(int cmd, [int signals = 0]) =>
52 (cmd << 2) | (signals & MojoHandleSignals.READWRITE); 47 (cmd << 2) | (signals & MojoHandleSignals.kReadWrite);
53 static int _decodeCommand(int cmd) => cmd >> 2; 48 static int _decodeCommand(int cmd) => cmd >> 2;
54 49
55 // The Mojo handle over which control messages are sent. 50 // The Mojo handle over which control messages are sent.
56 int _controlHandle; 51 int _controlHandle;
57 52
58 // Whether the handle watcher should shut down. 53 // Whether the handle watcher should shut down.
59 bool _shutdown; 54 bool _shutdown;
60 55
61 // The list of handles being watched. 56 // The list of handles being watched.
62 List<int> _handles; 57 List<int> _handles;
(...skipping 21 matching lines...) Expand all
84 _handles = new List<int>(), 79 _handles = new List<int>(),
85 _ports = new List<SendPort>(), 80 _ports = new List<SendPort>(),
86 _signals = new List<int>(), 81 _signals = new List<int>(),
87 _handleIndices = new Map<int, int>(), 82 _handleIndices = new Map<int, int>(),
88 _handleCount = 1, 83 _handleCount = 1,
89 _tempHandle = new RawMojoHandle(RawMojoHandle.INVALID), 84 _tempHandle = new RawMojoHandle(RawMojoHandle.INVALID),
90 _timerQueue = new TimerQueue() { 85 _timerQueue = new TimerQueue() {
91 // Setup control handle. 86 // Setup control handle.
92 _handles.add(_controlHandle); 87 _handles.add(_controlHandle);
93 _ports.add(null); // There is no port for the control handle. 88 _ports.add(null); // There is no port for the control handle.
94 _signals.add(MojoHandleSignals.READABLE); 89 _signals.add(MojoHandleSignals.kReadable);
95 _handleIndices[_controlHandle] = 0; 90 _handleIndices[_controlHandle] = 0;
96 } 91 }
97 92
98 static void _handleWatcherIsolate(int consumerHandle) { 93 static void _handleWatcherIsolate(int consumerHandle) {
99 MojoHandleWatcher watcher = new MojoHandleWatcher(consumerHandle); 94 MojoHandleWatcher watcher = new MojoHandleWatcher(consumerHandle);
100 while (!watcher._shutdown) { 95 while (!watcher._shutdown) {
101 int deadline = watcher._processTimerDeadlines(); 96 int deadline = watcher._processTimerDeadlines();
102 int res = RawMojoHandle.waitMany(watcher._handles, 97 int res = RawMojoHandle.waitMany(watcher._handles,
103 watcher._signals, 98 watcher._signals,
104 deadline); 99 deadline);
105 if (res == 0) { 100 if (res == 0) {
106 watcher._handleControlMessage(); 101 watcher._handleControlMessage();
107 } else if (res > 0) { 102 } else if (res > 0) {
108 int handle = watcher._handles[res]; 103 int handle = watcher._handles[res];
109 // Route event. 104 // Route event.
110 watcher._routeEvent(res); 105 watcher._routeEvent(res);
111 // Remove the handle from the list. 106 // Remove the handle from the list.
112 watcher._removeHandle(handle); 107 watcher._removeHandle(handle);
113 } else if (res != MojoResult.kDeadlineExceeded) { 108 } else if (res != MojoResult.kDeadlineExceeded) {
109 var result = new MojoResult(res);
114 // Some handle was closed, but not by us. 110 // Some handle was closed, but not by us.
115 // We have to go through the list and find it. 111 // We have to go through the list and find it.
116 watcher._pruneClosedHandles(); 112 watcher._pruneClosedHandles();
117 } 113 }
118 } 114 }
119 } 115 }
120 116
121 void _routeEvent(int idx) { 117 void _routeEvent(int idx) {
122 int client_handle = _handles[idx]; 118 int client_handle = _handles[idx];
123 int signals = _signals[idx]; 119 var signals = new MojoHandleSignals(_signals[idx]);
124 SendPort port = _ports[idx]; 120 SendPort port = _ports[idx];
125 121
126 _tempHandle.h = client_handle; 122 _tempHandle.h = client_handle;
127 bool readyWrite = 123 bool readyWrite = signals.isWritable && _tempHandle.readyWrite;
128 MojoHandleSignals.isWritable(signals) && _tempHandle.readyWrite(); 124 bool readyRead = signals.isReadable && _tempHandle.readyRead;
129 bool readyRead =
130 MojoHandleSignals.isReadable(signals) && _tempHandle.readyRead();
131 if (readyRead && readyWrite) {
132 port.send(MojoHandleSignals.READWRITE);
133 } else if (readyWrite) {
134 port.send(MojoHandleSignals.WRITABLE);
135 } else if (readyRead) {
136 port.send(MojoHandleSignals.READABLE);
137 }
138 _tempHandle.h = RawMojoHandle.INVALID; 125 _tempHandle.h = RawMojoHandle.INVALID;
126
127 var event = MojoHandleSignals.NONE;
128 event += readyRead ? MojoHandleSignals.READABLE : MojoHandleSignals.NONE;
129 event += readyWrite ? MojoHandleSignals.WRITABLE : MojoHandleSignals.NONE;
130 port.send([signals.value, event.value]);
139 } 131 }
140 132
141 void _handleControlMessage() { 133 void _handleControlMessage() {
142 List result = _MojoHandleWatcherNatives.recvControlData(_controlHandle); 134 List result = _MojoHandleWatcherNatives.recvControlData(_controlHandle);
143 // result[0] = mojo handle if any, or a timer deadline in milliseconds. 135 // result[0] = mojo handle if any, or a timer deadline in milliseconds.
144 // result[1] = SendPort if any. 136 // result[1] = SendPort if any.
145 // result[2] = command << 2 | WRITABLE | READABLE 137 // result[2] = command << 2 | WRITABLE | READABLE
146 138
147 int signals = result[2] & MojoHandleSignals.READWRITE; 139 var signals = new MojoHandleSignals(
140 result[2] & MojoHandleSignals.kReadWrite);
148 int command = _decodeCommand(result[2]); 141 int command = _decodeCommand(result[2]);
149 switch (command) { 142 switch (command) {
150 case ADD: 143 case ADD:
151 _addHandle(result[0], result[1], signals); 144 _addHandle(result[0], result[1], signals);
152 break; 145 break;
153 case REMOVE: 146 case REMOVE:
154 _removeHandle(result[0]); 147 _removeHandle(result[0]);
155 break; 148 break;
156 case TOGGLE_WRITE:
157 _toggleWrite(result[0]);
158 break;
159 case CLOSE: 149 case CLOSE:
160 _close(result[0]); 150 _close(result[0]);
161 break; 151 break;
162 case TIMER: 152 case TIMER:
163 _timer(result[1], result[0]); 153 _timer(result[1], result[0]);
164 break; 154 break;
165 case SHUTDOWN: 155 case SHUTDOWN:
166 _shutdownHandleWatcher(); 156 _shutdownHandleWatcher(result[1]);
167 break; 157 break;
168 default: 158 default:
169 throw new Exception("Invalid Command: $command"); 159 throw "Invalid Command: $command";
170 break; 160 break;
171 } 161 }
172 } 162 }
173 163
174 void _addHandle(int mojoHandle, SendPort port, int signals) { 164 void _addHandle(int mojoHandle, SendPort port, MojoHandleSignals signals) {
175 _handles.add(mojoHandle); 165 int idx = _handleIndices[mojoHandle];
176 _ports.add(port); 166 if (idx == null) {
177 _signals.add(signals & MojoHandleSignals.READWRITE); 167 _handles.add(mojoHandle);
178 _handleIndices[mojoHandle] = _handleCount; 168 _ports.add(port);
179 _handleCount++; 169 _signals.add(signals.value);
170 _handleIndices[mojoHandle] = _handleCount;
171 _handleCount++;
172 } else {
173 assert(_ports[idx] == port);
174 assert(_handles[idx] == mojoHandle);
175 _signals[idx] |= signals.value;
176 }
180 } 177 }
181 178
182 void _removeHandle(int mojoHandle) { 179 void _removeHandle(int mojoHandle) {
183 int idx = _handleIndices[mojoHandle]; 180 int idx = _handleIndices[mojoHandle];
184 if (idx == null) { 181 if (idx == null) {
185 throw new Exception("Remove on a non-existent handle: idx = $idx."); 182 throw "Remove on a non-existent handle: idx = $idx.";
186 } 183 }
187 if (idx == 0) { 184 if (idx == 0) {
188 throw new Exception("The control handle (idx = 0) cannot be removed."); 185 throw "The control handle (idx = 0) cannot be removed.";
189 } 186 }
190 // We don't use List.removeAt so that we know how to fix-up _handleIndices. 187 // We don't use List.removeAt so that we know how to fix-up _handleIndices.
191 if (idx == _handleCount - 1) { 188 if (idx == _handleCount - 1) {
192 int handle = _handles[idx]; 189 int handle = _handles[idx];
193 _handleIndices[handle] = null; 190 _handleIndices[handle] = null;
194 _handles.removeLast(); 191 _handles.removeLast();
195 _signals.removeLast(); 192 _signals.removeLast();
196 _ports.removeLast(); 193 _ports.removeLast();
197 _handleCount--; 194 _handleCount--;
198 } else { 195 } else {
199 int last = _handleCount - 1; 196 int last = _handleCount - 1;
197 _handleIndices[_handles[idx]] = null;
200 _handles[idx] = _handles[last]; 198 _handles[idx] = _handles[last];
201 _signals[idx] = _signals[last]; 199 _signals[idx] = _signals[last];
202 _ports[idx] = _ports[last]; 200 _ports[idx] = _ports[last];
203 _handles.removeLast(); 201 _handles.removeLast();
204 _signals.removeLast(); 202 _signals.removeLast();
205 _ports.removeLast(); 203 _ports.removeLast();
206 _handleIndices[_handles[idx]] = idx; 204 _handleIndices[_handles[idx]] = idx;
207 _handleCount--; 205 _handleCount--;
208 } 206 }
209 } 207 }
210 208
211 void _close(int mojoHandle, {bool pruning : false}) { 209 void _close(int mojoHandle, {bool pruning : false}) {
212 int idx = _handleIndices[mojoHandle]; 210 int idx = _handleIndices[mojoHandle];
213 if (idx == null) { 211 if (idx == null) {
214 throw new Exception("Close on a non-existent handle: idx = $idx."); 212 // A client may request to close a handle that has already been closed on
213 // the other side and pruned, but before receiving notification from the
214 // handle watcher.
215 return;
215 } 216 }
216 if (idx == 0) { 217 if (idx == 0) {
217 throw new Exception("The control handle (idx = 0) cannot be closed."); 218 throw "The control handle (idx = 0) cannot be closed.";
218 } 219 }
219 _tempHandle.h = _handles[idx]; 220 _tempHandle.h = _handles[idx];
220 _tempHandle.close(); 221 _tempHandle.close();
221 _tempHandle.h = RawMojoHandle.INVALID; 222 _tempHandle.h = RawMojoHandle.INVALID;
222 if (pruning) { 223 if (pruning) {
223 // If this handle is being pruned, notify the application isolate 224 // If this handle is being pruned, notify the application isolate
224 // by sending MojoHandleSignals.NONE. 225 // by sending MojoHandleSignals.PEER_CLOSED.
225 _ports[idx].send(MojoHandleSignals.NONE); 226 _ports[idx].send([_signals[idx], MojoHandleSignals.kPeerClosed]);
226 } 227 }
227 _removeHandle(mojoHandle); 228 _removeHandle(mojoHandle);
228 } 229 }
229 230
230 // Returns the next timer deadline in units of microseconds from 'now'. 231 // Returns the next timer deadline in units of microseconds from 'now'.
231 int _processTimerDeadlines() { 232 int _processTimerDeadlines() {
232 int now = (new DateTime.now()).millisecondsSinceEpoch; 233 int now = (new DateTime.now()).millisecondsSinceEpoch;
233 while (_timerQueue.hasTimer && (now >= _timerQueue.currentTimeout)) { 234 while (_timerQueue.hasTimer && (now >= _timerQueue.currentTimeout)) {
234 _timerQueue.currentPort.send(null); 235 _timerQueue.currentPort.send(null);
235 _timerQueue.removeCurrent(); 236 _timerQueue.removeCurrent();
236 now = (new DateTime.now()).millisecondsSinceEpoch; 237 now = (new DateTime.now()).millisecondsSinceEpoch;
237 } 238 }
238 return _timerQueue.hasTimer ? (_timerQueue.currentTimeout - now) * 1000 239 return _timerQueue.hasTimer ? (_timerQueue.currentTimeout - now) * 1000
239 : RawMojoHandle.DEADLINE_INDEFINITE; 240 : RawMojoHandle.DEADLINE_INDEFINITE;
240 } 241 }
241 242
242 void _timer(SendPort port, int deadline) { 243 void _timer(SendPort port, int deadline) {
243 _timerQueue.updateTimer(port, deadline); 244 _timerQueue.updateTimer(port, deadline);
244 } 245 }
245 246
246 void _toggleWrite(int mojoHandle) {
247 int idx = _handleIndices[mojoHandle];
248 if (idx == null) {
249 throw new Exception(
250 "Toggle write on a non-existent handle: $mojoHandle.");
251 }
252 if (idx == 0) {
253 throw new Exception("The control handle (idx = 0) cannot be toggled.");
254 }
255 _signals[idx] = MojoHandleSignals.toggleWrite(_signals[idx]);
256 }
257
258 void _pruneClosedHandles() { 247 void _pruneClosedHandles() {
259 List<int> closed = new List(); 248 List<int> closed = new List();
260 for (var h in _handles) { 249 for (var h in _handles) {
261 _tempHandle.h = h; 250 _tempHandle.h = h;
262 MojoResult res = _tempHandle.wait(MojoHandleSignals.READWRITE, 0); 251 MojoResult res = _tempHandle.wait(MojoHandleSignals.kReadWrite, 0);
263 if ((!res.isOk) && (!res.isDeadlineExceeded)) { 252 if ((!res.isOk) && (!res.isDeadlineExceeded)) {
264 closed.add(h); 253 closed.add(h);
265 } 254 }
266 _tempHandle.h = RawMojoHandle.INVALID; 255 _tempHandle.h = RawMojoHandle.INVALID;
267 } 256 }
268 for (var h in closed) { 257 for (var h in closed) {
269 _close(h, pruning: true); 258 _close(h, pruning: true);
270 } 259 }
271 } 260 }
272 261
273 void _shutdownHandleWatcher() { 262 void _shutdownHandleWatcher(SendPort shutdownSendPort) {
274 _shutdown = true; 263 _shutdown = true;
275 _tempHandle.h = _controlHandle; 264 _tempHandle.h = _controlHandle;
276 _tempHandle.close(); 265 _tempHandle.close();
277 _tempHandle.h = RawMojoHandle.INVALID; 266 _tempHandle.h = RawMojoHandle.INVALID;
267 shutdownSendPort.send(null);
278 } 268 }
279 269
280 static MojoResult _sendControlData(RawMojoHandle mojoHandle, 270 static MojoResult _sendControlData(RawMojoHandle mojoHandle,
281 SendPort port, 271 SendPort port,
282 int data) { 272 int data) {
283 int controlHandle = _MojoHandleWatcherNatives.getControlHandle(); 273 int controlHandle = _MojoHandleWatcherNatives.getControlHandle();
284 if (controlHandle == RawMojoHandle.INVALID) { 274 if (controlHandle == RawMojoHandle.INVALID) {
285 throw new Exception("Found invalid control handle"); 275 return MojoResult.FAILED_PRECONDITION;
286 } 276 }
287 277
288 int rawHandle = RawMojoHandle.INVALID; 278 int rawHandle = RawMojoHandle.INVALID;
289 if (mojoHandle != null) { 279 if (mojoHandle != null) {
290 rawHandle = mojoHandle.h; 280 rawHandle = mojoHandle.h;
291 } 281 }
292 var result = _MojoHandleWatcherNatives.sendControlData( 282 var result = _MojoHandleWatcherNatives.sendControlData(
293 controlHandle, rawHandle, port, data); 283 controlHandle, rawHandle, port, data);
294 return new MojoResult(result); 284 return new MojoResult(result);
295 } 285 }
296 286
297 static Future<Isolate> Start() { 287 static Future<Isolate> Start() {
298 // Make a control message pipe, 288 // Make a control message pipe,
299 MojoMessagePipe pipe = new MojoMessagePipe(); 289 MojoMessagePipe pipe = new MojoMessagePipe();
300 int consumerHandle = pipe.endpoints[0].handle.h; 290 int consumerHandle = pipe.endpoints[0].handle.h;
301 int producerHandle = pipe.endpoints[1].handle.h; 291 int producerHandle = pipe.endpoints[1].handle.h;
302 292
303 // Call setControlHandle with the other end. 293 // Call setControlHandle with the other end.
294 assert(producerHandle != RawMojoHandle.INVALID);
304 _MojoHandleWatcherNatives.setControlHandle(producerHandle); 295 _MojoHandleWatcherNatives.setControlHandle(producerHandle);
305 296
306 // Spawn the handle watcher isolate with the MojoHandleWatcher, 297 // Spawn the handle watcher isolate with the MojoHandleWatcher,
307 return Isolate.spawn(_handleWatcherIsolate, consumerHandle); 298 return Isolate.spawn(_handleWatcherIsolate, consumerHandle);
308 } 299 }
309 300
310 static void Stop() { 301 static void Stop() {
302 // Create a port for notification that the handle watcher has shutdown.
303 var shutdownReceivePort = new ReceivePort();
304 var shutdownSendPort = shutdownReceivePort.sendPort;
305
311 // Send the shutdown command. 306 // Send the shutdown command.
312 _sendControlData(null, null, _encodeCommand(SHUTDOWN)); 307 _sendControlData(null, shutdownSendPort, _encodeCommand(SHUTDOWN));
313 308
314 // Close the control handle. 309 // Close the control handle.
315 int controlHandle = _MojoHandleWatcherNatives.getControlHandle(); 310 int controlHandle = _MojoHandleWatcherNatives.getControlHandle();
316 var handle = new RawMojoHandle(controlHandle); 311 var handle = new RawMojoHandle(controlHandle);
317 handle.close(); 312 handle.close();
318 313
319 // Invalidate the control handle. 314 // Invalidate the control handle.
320 _MojoHandleWatcherNatives.setControlHandle(RawMojoHandle.INVALID); 315 _MojoHandleWatcherNatives.setControlHandle(RawMojoHandle.INVALID);
316
317 // Wait for the handle watcher isolate to exit.
318 shutdownReceivePort.first.then((_) {
319 shutdownReceivePort.close();
320 });
321 } 321 }
322 322
323 static MojoResult close(RawMojoHandle mojoHandle) { 323 static MojoResult close(RawMojoHandle mojoHandle) {
324 return _sendControlData(mojoHandle, null, _encodeCommand(CLOSE)); 324 return _sendControlData(mojoHandle, null, _encodeCommand(CLOSE));
325 } 325 }
326 326
327 static MojoResult toggleWrite(RawMojoHandle mojoHandle) {
328 return _sendControlData(mojoHandle, null, _encodeCommand(TOGGLE_WRITE));
329 }
330
331 static MojoResult add(RawMojoHandle mojoHandle, SendPort port, int signals) { 327 static MojoResult add(RawMojoHandle mojoHandle, SendPort port, int signals) {
332 return _sendControlData(mojoHandle, port, _encodeCommand(ADD, signals)); 328 return _sendControlData(mojoHandle, port, _encodeCommand(ADD, signals));
333 } 329 }
334 330
335 static MojoResult remove(RawMojoHandle mojoHandle) { 331 static MojoResult remove(RawMojoHandle mojoHandle) {
336 return _sendControlData(mojoHandle, null, _encodeCommand(REMOVE)); 332 return _sendControlData(mojoHandle, null, _encodeCommand(REMOVE));
337 } 333 }
338 334
339 static MojoResult timer(SendPort port, int deadline) { 335 static MojoResult timer(SendPort port, int deadline) {
340 // The deadline will be unwrapped before sending to the handle watcher. 336 // The deadline will be unwrapped before sending to the handle watcher.
341 return _sendControlData( 337 return _sendControlData(
342 new RawMojoHandle(deadline), port, _encodeCommand(TIMER)); 338 new RawMojoHandle(deadline), port, _encodeCommand(TIMER));
343 } 339 }
344 } 340 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698