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

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

Issue 814543006: Move //mojo/{public, edk} underneath //third_party (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase 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
« no previous file with comments | « mojo/public/dart/src/handle.dart ('k') | mojo/public/dart/src/interface.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 part of core;
6
7 class _MojoHandleWatcherNatives {
8 static int sendControlData(
9 int controlHandle, int mojoHandle, SendPort port, int data)
10 native "MojoHandleWatcher_SendControlData";
11 static List recvControlData(int controlHandle)
12 native "MojoHandleWatcher_RecvControlData";
13 static int setControlHandle(int controlHandle)
14 native "MojoHandleWatcher_SetControlHandle";
15 static int getControlHandle()
16 native "MojoHandleWatcher_GetControlHandle";
17 }
18
19 // The MojoHandleWatcher sends a stream of events to application isolates that
20 // register Mojo handles with it. Application isolates make the following calls:
21 //
22 // Start() - Starts up the MojoHandleWatcher isolate. Should be called only once
23 // per VM process.
24 //
25 // Stop() - Causes the MojoHandleWatcher isolate to exit.
26 //
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
29 // isolate only for the events specified by 'signals' using the send port
30 // 'port'
31 //
32 // remove(handle) - Instructs the MojoHandleWatcher isolate to remove 'handle'
33 // from the set of handles it watches. This allows the application isolate
34 // to, e.g., pause the stream of events.
35 //
36 // close(handle) - Notifies the HandleWatcherIsolate that a handle it is
37 // watching should be removed from its set and closed.
38 class MojoHandleWatcher {
39 // Control commands.
40 static const int ADD = 0;
41 static const int REMOVE = 1;
42 static const int CLOSE = 2;
43 static const int TIMER = 3;
44 static const int SHUTDOWN = 4;
45
46 static int _encodeCommand(int cmd, [int signals = 0]) =>
47 (cmd << 2) | (signals & MojoHandleSignals.kReadWrite);
48 static int _decodeCommand(int cmd) => cmd >> 2;
49
50 // The Mojo handle over which control messages are sent.
51 int _controlHandle;
52
53 // Whether the handle watcher should shut down.
54 bool _shutdown;
55
56 // The list of handles being watched.
57 List<int> _handles;
58 int _handleCount;
59
60 // A port for each handle on which to send events back to the isolate that
61 // owns the handle.
62 List<SendPort> _ports;
63
64 // The signals that we care about for each handle.
65 List<int> _signals;
66
67 // A mapping from Mojo handles to their indices in _handles.
68 Map<int, int> _handleIndices;
69
70 // Since we are not storing wrapped handles, a dummy handle for when we need
71 // a MojoHandle.
72 MojoHandle _tempHandle;
73
74 // Priority queue of timers registered with the watcher.
75 TimerQueue _timerQueue;
76
77 MojoHandleWatcher(this._controlHandle) :
78 _shutdown = false,
79 _handles = new List<int>(),
80 _ports = new List<SendPort>(),
81 _signals = new List<int>(),
82 _handleIndices = new Map<int, int>(),
83 _handleCount = 1,
84 _tempHandle = new MojoHandle(MojoHandle.INVALID),
85 _timerQueue = new TimerQueue() {
86 // Setup control handle.
87 _handles.add(_controlHandle);
88 _ports.add(null); // There is no port for the control handle.
89 _signals.add(MojoHandleSignals.kReadable);
90 _handleIndices[_controlHandle] = 0;
91 }
92
93 static void _handleWatcherIsolate(int consumerHandle) {
94 MojoHandleWatcher watcher = new MojoHandleWatcher(consumerHandle);
95 while (!watcher._shutdown) {
96 int deadline = watcher._processTimerDeadlines();
97 MojoWaitManyResult mwmr = MojoHandle.waitMany(
98 watcher._handles, watcher._signals, deadline);
99 if (mwmr.result.isOk && mwmr.index == 0) {
100 watcher._handleControlMessage();
101 } else if (mwmr.result.isOk && (mwmr.index > 0)) {
102 int handle = watcher._handles[mwmr.index];
103 // Route event.
104 watcher._routeEvent(mwmr.index);
105 // Remove the handle from the list.
106 watcher._removeHandle(handle);
107 } else if (!mwmr.result.isDeadlineExceeded) {
108 // Some handle was closed, but not by us.
109 // Find it and close it on our side.
110 watcher._pruneClosedHandles(mwmr.states);
111 }
112 }
113 }
114
115 void _routeEvent(int idx) {
116 int client_handle = _handles[idx];
117 var signals = new MojoHandleSignals(_signals[idx]);
118 SendPort port = _ports[idx];
119
120 _tempHandle.h = client_handle;
121 bool readyWrite = signals.isWritable && _tempHandle.readyWrite;
122 bool readyRead = signals.isReadable && _tempHandle.readyRead;
123 _tempHandle.h = MojoHandle.INVALID;
124
125 var event = MojoHandleSignals.NONE;
126 event += readyRead ? MojoHandleSignals.READABLE : MojoHandleSignals.NONE;
127 event += readyWrite ? MojoHandleSignals.WRITABLE : MojoHandleSignals.NONE;
128 port.send([signals.value, event.value]);
129 }
130
131 void _handleControlMessage() {
132 List result = _MojoHandleWatcherNatives.recvControlData(_controlHandle);
133 // result[0] = mojo handle if any, or a timer deadline in milliseconds.
134 // result[1] = SendPort if any.
135 // result[2] = command << 2 | WRITABLE | READABLE
136
137 var signals = new MojoHandleSignals(
138 result[2] & MojoHandleSignals.kReadWrite);
139 int command = _decodeCommand(result[2]);
140 switch (command) {
141 case ADD:
142 _addHandle(result[0], result[1], signals);
143 break;
144 case REMOVE:
145 _removeHandle(result[0]);
146 break;
147 case CLOSE:
148 _close(result[0]);
149 break;
150 case TIMER:
151 _timer(result[1], result[0]);
152 break;
153 case SHUTDOWN:
154 _shutdownHandleWatcher(result[1]);
155 break;
156 default:
157 throw "Invalid Command: $command";
158 break;
159 }
160 }
161
162 void _addHandle(int mojoHandle, SendPort port, MojoHandleSignals signals) {
163 int idx = _handleIndices[mojoHandle];
164 if (idx == null) {
165 _handles.add(mojoHandle);
166 _ports.add(port);
167 _signals.add(signals.value);
168 _handleIndices[mojoHandle] = _handleCount;
169 _handleCount++;
170 } else {
171 assert(_ports[idx] == port);
172 assert(_handles[idx] == mojoHandle);
173 _signals[idx] |= signals.value;
174 }
175 }
176
177 void _removeHandle(int mojoHandle) {
178 int idx = _handleIndices[mojoHandle];
179 if (idx == null) {
180 throw "Remove on a non-existent handle: idx = $idx.";
181 }
182 if (idx == 0) {
183 throw "The control handle (idx = 0) cannot be removed.";
184 }
185 // We don't use List.removeAt so that we know how to fix-up _handleIndices.
186 if (idx == _handleCount - 1) {
187 int handle = _handles[idx];
188 _handleIndices[handle] = null;
189 _handles.removeLast();
190 _signals.removeLast();
191 _ports.removeLast();
192 _handleCount--;
193 } else {
194 int last = _handleCount - 1;
195 _handleIndices[_handles[idx]] = null;
196 _handles[idx] = _handles[last];
197 _signals[idx] = _signals[last];
198 _ports[idx] = _ports[last];
199 _handles.removeLast();
200 _signals.removeLast();
201 _ports.removeLast();
202 _handleIndices[_handles[idx]] = idx;
203 _handleCount--;
204 }
205 }
206
207 void _close(int mojoHandle, {bool pruning : false}) {
208 int idx = _handleIndices[mojoHandle];
209 if (idx == null) {
210 // A client may request to close a handle that has already been closed on
211 // the other side and pruned, but before receiving notification from the
212 // handle watcher.
213 return;
214 }
215 if (idx == 0) {
216 throw "The control handle (idx = 0) cannot be closed.";
217 }
218 _tempHandle.h = _handles[idx];
219 _tempHandle.close();
220 _tempHandle.h = MojoHandle.INVALID;
221 if (pruning) {
222 // If this handle is being pruned, notify the application isolate
223 // by sending MojoHandleSignals.PEER_CLOSED.
224 _ports[idx].send([_signals[idx], MojoHandleSignals.kPeerClosed]);
225 }
226 _removeHandle(mojoHandle);
227 }
228
229 // Returns the next timer deadline in units of microseconds from 'now'.
230 int _processTimerDeadlines() {
231 int now = (new DateTime.now()).millisecondsSinceEpoch;
232 while (_timerQueue.hasTimer && (now >= _timerQueue.currentTimeout)) {
233 _timerQueue.currentPort.send(null);
234 _timerQueue.removeCurrent();
235 now = (new DateTime.now()).millisecondsSinceEpoch;
236 }
237 return _timerQueue.hasTimer ? (_timerQueue.currentTimeout - now) * 1000
238 : MojoHandle.DEADLINE_INDEFINITE;
239 }
240
241 void _timer(SendPort port, int deadline) {
242 _timerQueue.updateTimer(port, deadline);
243 }
244
245 void _pruneClosedHandles(List<MojoHandleSignalsState> states) {
246 List<int> closed = new List();
247 for (var i = 0; i < _handles.length; i++) {
248 if (states != null) {
249 var signals = new MojoHandleSignals(states[i].satisfied_signals);
250 if (signals.isPeerClosed) {
251 closed.add(_handles[i]);
252 }
253 } else {
254 _tempHandle.h = _handles[i];
255 MojoWaitResult mwr = _tempHandle.wait(MojoHandleSignals.kReadWrite, 0);
256 if ((!mwr.result.isOk) && (!mwr.result.isDeadlineExceeded)) {
257 closed.add(_handles[i]);
258 }
259 _tempHandle.h = MojoHandle.INVALID;
260 }
261 }
262 for (var h in closed) {
263 _close(h, pruning: true);
264 }
265 // '_close' updated the '_handles' array, so at this point the '_handles'
266 // array and the caller's 'states' array are mismatched.
267 }
268
269 void _shutdownHandleWatcher(SendPort shutdownSendPort) {
270 _shutdown = true;
271 _tempHandle.h = _controlHandle;
272 _tempHandle.close();
273 _tempHandle.h = MojoHandle.INVALID;
274 shutdownSendPort.send(null);
275 }
276
277 static MojoResult _sendControlData(MojoHandle mojoHandle,
278 SendPort port,
279 int data) {
280 int controlHandle = _MojoHandleWatcherNatives.getControlHandle();
281 if (controlHandle == MojoHandle.INVALID) {
282 return MojoResult.FAILED_PRECONDITION;
283 }
284
285 int rawHandle = MojoHandle.INVALID;
286 if (mojoHandle != null) {
287 rawHandle = mojoHandle.h;
288 }
289 var result = _MojoHandleWatcherNatives.sendControlData(
290 controlHandle, rawHandle, port, data);
291 return new MojoResult(result);
292 }
293
294 static Future<Isolate> Start() {
295 // Make a control message pipe,
296 MojoMessagePipe pipe = new MojoMessagePipe();
297 int consumerHandle = pipe.endpoints[0].handle.h;
298 int producerHandle = pipe.endpoints[1].handle.h;
299
300 // Call setControlHandle with the other end.
301 assert(producerHandle != MojoHandle.INVALID);
302 _MojoHandleWatcherNatives.setControlHandle(producerHandle);
303
304 // Spawn the handle watcher isolate with the MojoHandleWatcher,
305 return Isolate.spawn(_handleWatcherIsolate, consumerHandle);
306 }
307
308 static void Stop() {
309 // Create a port for notification that the handle watcher has shutdown.
310 var shutdownReceivePort = new ReceivePort();
311 var shutdownSendPort = shutdownReceivePort.sendPort;
312
313 // Send the shutdown command.
314 _sendControlData(null, shutdownSendPort, _encodeCommand(SHUTDOWN));
315
316 // Close the control handle.
317 int controlHandle = _MojoHandleWatcherNatives.getControlHandle();
318 var handle = new MojoHandle(controlHandle);
319 handle.close();
320
321 // Invalidate the control handle.
322 _MojoHandleWatcherNatives.setControlHandle(MojoHandle.INVALID);
323
324 // Wait for the handle watcher isolate to exit.
325 shutdownReceivePort.first.then((_) {
326 shutdownReceivePort.close();
327 });
328 }
329
330 static MojoResult close(MojoHandle mojoHandle) {
331 return _sendControlData(mojoHandle, null, _encodeCommand(CLOSE));
332 }
333
334 static MojoResult add(MojoHandle mojoHandle, SendPort port, int signals) {
335 return _sendControlData(mojoHandle, port, _encodeCommand(ADD, signals));
336 }
337
338 static MojoResult remove(MojoHandle mojoHandle) {
339 return _sendControlData(mojoHandle, null, _encodeCommand(REMOVE));
340 }
341
342 static MojoResult timer(SendPort port, int deadline) {
343 // The deadline will be unwrapped before sending to the handle watcher.
344 return _sendControlData(
345 new MojoHandle(deadline), port, _encodeCommand(TIMER));
346 }
347 }
OLDNEW
« no previous file with comments | « mojo/public/dart/src/handle.dart ('k') | mojo/public/dart/src/interface.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698