OLD | NEW |
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 27 matching lines...) Expand all Loading... |
38 // be notified about a handle ready for writing is made the opposite. | 38 // be notified about a handle ready for writing is made the opposite. |
39 // | 39 // |
40 // close(handle) - Notifies the HandleWatcherIsolate that a handle it is | 40 // close(handle) - Notifies the HandleWatcherIsolate that a handle it is |
41 // watching should be removed from its set and closed. | 41 // watching should be removed from its set and closed. |
42 class MojoHandleWatcher { | 42 class MojoHandleWatcher { |
43 // Control commands. | 43 // Control commands. |
44 static const int ADD = 0; | 44 static const int ADD = 0; |
45 static const int REMOVE = 1; | 45 static const int REMOVE = 1; |
46 static const int TOGGLE_WRITE = 2; | 46 static const int TOGGLE_WRITE = 2; |
47 static const int CLOSE = 3; | 47 static const int CLOSE = 3; |
48 static const int SHUTDOWN = 4; | 48 static const int TIMER = 4; |
| 49 static const int SHUTDOWN = 5; |
49 | 50 |
50 static int _encodeCommand(int cmd, [int signals = 0]) => | 51 static int _encodeCommand(int cmd, [int signals = 0]) => |
51 (cmd << 2) | (signals & MojoHandleSignals.READWRITE); | 52 (cmd << 2) | (signals & MojoHandleSignals.READWRITE); |
52 static int _decodeCommand(int cmd) => cmd >> 2; | 53 static int _decodeCommand(int cmd) => cmd >> 2; |
53 | 54 |
54 // The Mojo handle over which control messages are sent. | 55 // The Mojo handle over which control messages are sent. |
55 int _controlHandle; | 56 int _controlHandle; |
56 | 57 |
57 // Whether the handle watcher should shut down. | 58 // Whether the handle watcher should shut down. |
58 bool _shutdown; | 59 bool _shutdown; |
59 | 60 |
60 // The list of handles being watched. | 61 // The list of handles being watched. |
61 List<int> _handles; | 62 List<int> _handles; |
62 int _handleCount; | 63 int _handleCount; |
63 | 64 |
64 // A port for each handle on which to send events back to the isolate that | 65 // A port for each handle on which to send events back to the isolate that |
65 // owns the handle. | 66 // owns the handle. |
66 List<SendPort> _ports; | 67 List<SendPort> _ports; |
67 | 68 |
68 // The signals that we care about for each handle. | 69 // The signals that we care about for each handle. |
69 List<int> _signals; | 70 List<int> _signals; |
70 | 71 |
71 // A mapping from Mojo handles to their indices in _handles. | 72 // A mapping from Mojo handles to their indices in _handles. |
72 Map<int, int> _handleIndices; | 73 Map<int, int> _handleIndices; |
73 | 74 |
74 // Since we are not storing wrapped handles, a dummy handle for when we need | 75 // Since we are not storing wrapped handles, a dummy handle for when we need |
75 // a RawMojoHandle. | 76 // a RawMojoHandle. |
76 RawMojoHandle _tempHandle; | 77 RawMojoHandle _tempHandle; |
77 | 78 |
| 79 // Priority queue of timers registered with the watcher. |
| 80 TimerQueue _timerQueue; |
| 81 |
78 MojoHandleWatcher(this._controlHandle) : | 82 MojoHandleWatcher(this._controlHandle) : |
79 _shutdown = false, | 83 _shutdown = false, |
80 _handles = new List<int>(), | 84 _handles = new List<int>(), |
81 _ports = new List<SendPort>(), | 85 _ports = new List<SendPort>(), |
82 _signals = new List<int>(), | 86 _signals = new List<int>(), |
83 _handleIndices = new Map<int, int>(), | 87 _handleIndices = new Map<int, int>(), |
84 _handleCount = 1, | 88 _handleCount = 1, |
85 _tempHandle = new RawMojoHandle(RawMojoHandle.INVALID) { | 89 _tempHandle = new RawMojoHandle(RawMojoHandle.INVALID), |
| 90 _timerQueue = new TimerQueue() { |
86 // Setup control handle. | 91 // Setup control handle. |
87 _handles.add(_controlHandle); | 92 _handles.add(_controlHandle); |
88 _ports.add(null); // There is no port for the control handle. | 93 _ports.add(null); // There is no port for the control handle. |
89 _signals.add(MojoHandleSignals.READABLE); | 94 _signals.add(MojoHandleSignals.READABLE); |
90 _handleIndices[_controlHandle] = 0; | 95 _handleIndices[_controlHandle] = 0; |
91 } | 96 } |
92 | 97 |
93 static void _handleWatcherIsolate(MojoHandleWatcher watcher) { | 98 static void _handleWatcherIsolate(int consumerHandle) { |
| 99 MojoHandleWatcher watcher = new MojoHandleWatcher(consumerHandle); |
94 while (!watcher._shutdown) { | 100 while (!watcher._shutdown) { |
| 101 int deadline = watcher._processTimerDeadlines(); |
95 int res = RawMojoHandle.waitMany(watcher._handles, | 102 int res = RawMojoHandle.waitMany(watcher._handles, |
96 watcher._signals, | 103 watcher._signals, |
97 RawMojoHandle.DEADLINE_INDEFINITE); | 104 deadline); |
98 if (res == 0) { | 105 if (res == 0) { |
99 watcher._handleControlMessage(); | 106 watcher._handleControlMessage(); |
100 } else if (res > 0) { | 107 } else if (res > 0) { |
101 int handle = watcher._handles[res]; | 108 int handle = watcher._handles[res]; |
102 // Route event. | 109 // Route event. |
103 watcher._routeEvent(res); | 110 watcher._routeEvent(res); |
104 // Remove the handle from the list. | 111 // Remove the handle from the list. |
105 watcher._removeHandle(handle); | 112 watcher._removeHandle(handle); |
106 } else { | 113 } else if (res != MojoResult.kDeadlineExceeded) { |
107 // Some handle was closed, but not by us. | 114 // Some handle was closed, but not by us. |
108 // We have to go through the list and find it. | 115 // We have to go through the list and find it. |
109 watcher._pruneClosedHandles(); | 116 watcher._pruneClosedHandles(); |
110 } | 117 } |
111 } | 118 } |
112 } | 119 } |
113 | 120 |
114 void _routeEvent(int idx) { | 121 void _routeEvent(int idx) { |
115 int client_handle = _handles[idx]; | 122 int client_handle = _handles[idx]; |
116 int signals = _signals[idx]; | 123 int signals = _signals[idx]; |
117 SendPort port = _ports[idx]; | 124 SendPort port = _ports[idx]; |
118 | 125 |
119 _tempHandle.h = client_handle; | 126 _tempHandle.h = client_handle; |
120 bool readyWrite = | 127 bool readyWrite = |
121 MojoHandleSignals.isWritable(signals) && _tempHandle.readyWrite(); | 128 MojoHandleSignals.isWritable(signals) && _tempHandle.readyWrite(); |
122 bool readyRead = | 129 bool readyRead = |
123 MojoHandleSignals.isReadable(signals) && _tempHandle.readyRead(); | 130 MojoHandleSignals.isReadable(signals) && _tempHandle.readyRead(); |
124 if (readyRead && readyWrite) { | 131 if (readyRead && readyWrite) { |
125 port.send(MojoHandleSignals.READWRITE); | 132 port.send(MojoHandleSignals.READWRITE); |
126 } else if (readyWrite) { | 133 } else if (readyWrite) { |
127 port.send(MojoHandleSignals.WRITABLE); | 134 port.send(MojoHandleSignals.WRITABLE); |
128 } else if (readyRead) { | 135 } else if (readyRead) { |
129 port.send(MojoHandleSignals.READABLE); | 136 port.send(MojoHandleSignals.READABLE); |
130 } | 137 } |
131 _tempHandle.h = RawMojoHandle.INVALID; | 138 _tempHandle.h = RawMojoHandle.INVALID; |
132 } | 139 } |
133 | 140 |
134 void _handleControlMessage() { | 141 void _handleControlMessage() { |
135 List result = _MojoHandleWatcherNatives.recvControlData(_controlHandle); | 142 List result = _MojoHandleWatcherNatives.recvControlData(_controlHandle); |
136 // result[0] = mojo handle if any | 143 // result[0] = mojo handle if any, or a timer deadline in milliseconds. |
137 // result[1] = SendPort if any | 144 // result[1] = SendPort if any. |
138 // result[2] = command << 2 | WRITABLE | READABLE | 145 // result[2] = command << 2 | WRITABLE | READABLE |
139 | 146 |
140 int signals = result[2] & MojoHandleSignals.READWRITE; | 147 int signals = result[2] & MojoHandleSignals.READWRITE; |
141 int command = _decodeCommand(result[2]); | 148 int command = _decodeCommand(result[2]); |
142 switch (command) { | 149 switch (command) { |
143 case ADD: | 150 case ADD: |
144 _addHandle(result[0], result[1], signals); | 151 _addHandle(result[0], result[1], signals); |
145 break; | 152 break; |
146 case REMOVE: | 153 case REMOVE: |
147 _removeHandle(result[0]); | 154 _removeHandle(result[0]); |
148 break; | 155 break; |
149 case TOGGLE_WRITE: | 156 case TOGGLE_WRITE: |
150 _toggleWrite(result[0]); | 157 _toggleWrite(result[0]); |
151 break; | 158 break; |
152 case CLOSE: | 159 case CLOSE: |
153 _close(result[0]); | 160 _close(result[0]); |
154 break; | 161 break; |
| 162 case TIMER: |
| 163 _timer(result[1], result[0]); |
| 164 break; |
155 case SHUTDOWN: | 165 case SHUTDOWN: |
156 _shutdownHandleWatcher(); | 166 _shutdownHandleWatcher(); |
157 break; | 167 break; |
158 default: | 168 default: |
159 throw new Exception("Invalid Command: $command"); | 169 throw new Exception("Invalid Command: $command"); |
160 break; | 170 break; |
161 } | 171 } |
162 } | 172 } |
163 | 173 |
164 void _addHandle(int mojoHandle, SendPort port, int signals) { | 174 void _addHandle(int mojoHandle, SendPort port, int signals) { |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
210 _tempHandle.close(); | 220 _tempHandle.close(); |
211 _tempHandle.h = RawMojoHandle.INVALID; | 221 _tempHandle.h = RawMojoHandle.INVALID; |
212 if (pruning) { | 222 if (pruning) { |
213 // If this handle is being pruned, notify the application isolate | 223 // If this handle is being pruned, notify the application isolate |
214 // by sending MojoHandleSignals.NONE. | 224 // by sending MojoHandleSignals.NONE. |
215 _ports[idx].send(MojoHandleSignals.NONE); | 225 _ports[idx].send(MojoHandleSignals.NONE); |
216 } | 226 } |
217 _removeHandle(mojoHandle); | 227 _removeHandle(mojoHandle); |
218 } | 228 } |
219 | 229 |
| 230 // Returns the next timer deadline in units of microseconds from 'now'. |
| 231 int _processTimerDeadlines() { |
| 232 int now = (new DateTime.now()).millisecondsSinceEpoch; |
| 233 while (_timerQueue.hasTimer && (now >= _timerQueue.currentTimeout)) { |
| 234 _timerQueue.currentPort.send(null); |
| 235 _timerQueue.removeCurrent(); |
| 236 now = (new DateTime.now()).millisecondsSinceEpoch; |
| 237 } |
| 238 return _timerQueue.hasTimer ? (_timerQueue.currentTimeout - now) * 1000 |
| 239 : RawMojoHandle.DEADLINE_INDEFINITE; |
| 240 } |
| 241 |
| 242 void _timer(SendPort port, int deadline) { |
| 243 _timerQueue.updateTimer(port, deadline); |
| 244 } |
| 245 |
220 void _toggleWrite(int mojoHandle) { | 246 void _toggleWrite(int mojoHandle) { |
221 int idx = _handleIndices[mojoHandle]; | 247 int idx = _handleIndices[mojoHandle]; |
222 if (idx == null) { | 248 if (idx == null) { |
223 throw new Exception( | 249 throw new Exception( |
224 "Toggle write on a non-existent handle: $mojoHandle."); | 250 "Toggle write on a non-existent handle: $mojoHandle."); |
225 } | 251 } |
226 if (idx == 0) { | 252 if (idx == 0) { |
227 throw new Exception("The control handle (idx = 0) cannot be toggled."); | 253 throw new Exception("The control handle (idx = 0) cannot be toggled."); |
228 } | 254 } |
229 _signals[idx] = MojoHandleSignals.toggleWrite(_signals[idx]); | 255 _signals[idx] = MojoHandleSignals.toggleWrite(_signals[idx]); |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
267 controlHandle, rawHandle, port, data); | 293 controlHandle, rawHandle, port, data); |
268 return new MojoResult(result); | 294 return new MojoResult(result); |
269 } | 295 } |
270 | 296 |
271 static Future<Isolate> Start() { | 297 static Future<Isolate> Start() { |
272 // Make a control message pipe, | 298 // Make a control message pipe, |
273 MojoMessagePipe pipe = new MojoMessagePipe(); | 299 MojoMessagePipe pipe = new MojoMessagePipe(); |
274 int consumerHandle = pipe.endpoints[0].handle.h; | 300 int consumerHandle = pipe.endpoints[0].handle.h; |
275 int producerHandle = pipe.endpoints[1].handle.h; | 301 int producerHandle = pipe.endpoints[1].handle.h; |
276 | 302 |
277 // Make a MojoHandleWatcher with one end. | |
278 MojoHandleWatcher watcher = new MojoHandleWatcher(consumerHandle); | |
279 | |
280 // Call setControlHandle with the other end. | 303 // Call setControlHandle with the other end. |
281 _MojoHandleWatcherNatives.setControlHandle(producerHandle); | 304 _MojoHandleWatcherNatives.setControlHandle(producerHandle); |
282 | 305 |
283 // Spawn the handle watcher isolate with the MojoHandleWatcher, | 306 // Spawn the handle watcher isolate with the MojoHandleWatcher, |
284 return Isolate.spawn(_handleWatcherIsolate, watcher); | 307 return Isolate.spawn(_handleWatcherIsolate, consumerHandle); |
285 } | 308 } |
286 | 309 |
287 static void Stop() { | 310 static void Stop() { |
288 // Send the shutdown command. | 311 // Send the shutdown command. |
289 _sendControlData(null, null, _encodeCommand(SHUTDOWN)); | 312 _sendControlData(null, null, _encodeCommand(SHUTDOWN)); |
290 | 313 |
291 // Close the control handle. | 314 // Close the control handle. |
292 int controlHandle = _MojoHandleWatcherNatives.getControlHandle(); | 315 int controlHandle = _MojoHandleWatcherNatives.getControlHandle(); |
293 var handle = new RawMojoHandle(controlHandle); | 316 var handle = new RawMojoHandle(controlHandle); |
294 handle.close(); | 317 handle.close(); |
| 318 |
| 319 // Invalidate the control handle. |
| 320 _MojoHandleWatcherNatives.setControlHandle(RawMojoHandle.INVALID); |
295 } | 321 } |
296 | 322 |
297 static MojoResult close(RawMojoHandle mojoHandle) { | 323 static MojoResult close(RawMojoHandle mojoHandle) { |
298 return _sendControlData(mojoHandle, null, _encodeCommand(CLOSE)); | 324 return _sendControlData(mojoHandle, null, _encodeCommand(CLOSE)); |
299 } | 325 } |
300 | 326 |
301 static MojoResult toggleWrite(RawMojoHandle mojoHandle) { | 327 static MojoResult toggleWrite(RawMojoHandle mojoHandle) { |
302 return _sendControlData(mojoHandle, null, _encodeCommand(TOGGLE_WRITE)); | 328 return _sendControlData(mojoHandle, null, _encodeCommand(TOGGLE_WRITE)); |
303 } | 329 } |
304 | 330 |
305 static MojoResult add(RawMojoHandle mojoHandle, SendPort port, int signals) { | 331 static MojoResult add(RawMojoHandle mojoHandle, SendPort port, int signals) { |
306 return _sendControlData(mojoHandle, port, _encodeCommand(ADD, signals)); | 332 return _sendControlData(mojoHandle, port, _encodeCommand(ADD, signals)); |
307 } | 333 } |
308 | 334 |
309 static MojoResult remove(RawMojoHandle mojoHandle) { | 335 static MojoResult remove(RawMojoHandle mojoHandle) { |
310 return _sendControlData(mojoHandle, null, _encodeCommand(REMOVE)); | 336 return _sendControlData(mojoHandle, null, _encodeCommand(REMOVE)); |
311 } | 337 } |
| 338 |
| 339 static MojoResult timer(SendPort port, int deadline) { |
| 340 // The deadline will be unwrapped before sending to the handle watcher. |
| 341 return _sendControlData( |
| 342 new RawMojoHandle(deadline), port, _encodeCommand(TIMER)); |
| 343 } |
312 } | 344 } |
OLD | NEW |