| 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 _MojoHandleNatives { | 7 class _MojoHandleNatives { |
| 8 static int register(MojoHandle handle) native "MojoHandle_Register"; | 8 static int register(MojoEventStream eventStream) native "MojoHandle_Register"; |
| 9 static int close(int handle) native "MojoHandle_Close"; | 9 static int close(int handle) native "MojoHandle_Close"; |
| 10 static List wait(int handle, int signals, int deadline) | 10 static List wait(int handle, int signals, int deadline) |
| 11 native "MojoHandle_Wait"; | 11 native "MojoHandle_Wait"; |
| 12 static List waitMany( | 12 static List waitMany( |
| 13 List<int> handles, List<int> signals, int deadline) | 13 List<int> handles, List<int> signals, int deadline) |
| 14 native "MojoHandle_WaitMany"; | 14 native "MojoHandle_WaitMany"; |
| 15 } | 15 } |
| 16 | 16 |
| 17 | 17 |
| 18 class RawMojoHandle { | 18 class MojoHandle { |
| 19 static const int INVALID = 0; | 19 static const int INVALID = 0; |
| 20 static const int DEADLINE_INDEFINITE = -1; | 20 static const int DEADLINE_INDEFINITE = -1; |
| 21 | 21 |
| 22 int h; | 22 int h; |
| 23 | 23 |
| 24 RawMojoHandle(this.h); | 24 MojoHandle(this.h); |
| 25 | 25 |
| 26 MojoResult close() { | 26 MojoResult close() { |
| 27 int result = _MojoHandleNatives.close(h); | 27 int result = _MojoHandleNatives.close(h); |
| 28 h = INVALID; | 28 h = INVALID; |
| 29 return new MojoResult(result); | 29 return new MojoResult(result); |
| 30 } | 30 } |
| 31 | 31 |
| 32 MojoWaitResult wait(int signals, int deadline) { | 32 MojoWaitResult wait(int signals, int deadline) { |
| 33 List result = _MojoHandleNatives.wait(h, signals, deadline); | 33 List result = _MojoHandleNatives.wait(h, signals, deadline); |
| 34 return new MojoWaitResult(new MojoResult(result[0]), result[1]); | 34 return new MojoWaitResult(new MojoResult(result[0]), result[1]); |
| 35 } | 35 } |
| 36 | 36 |
| 37 bool _ready(int signal) { | 37 bool _ready(MojoHandleSignals signal) { |
| 38 MojoWaitResult res = wait(signal, 0); | 38 MojoWaitResult mwr = wait(signal.value, 0); |
| 39 switch (res.result) { | 39 switch (mwr.result) { |
| 40 case MojoResult.OK: | 40 case MojoResult.OK: |
| 41 return true; | 41 return true; |
| 42 case MojoResult.DEADLINE_EXCEEDED: | 42 case MojoResult.DEADLINE_EXCEEDED: |
| 43 case MojoResult.CANCELLED: | 43 case MojoResult.CANCELLED: |
| 44 case MojoResult.INVALID_ARGUMENT: | 44 case MojoResult.INVALID_ARGUMENT: |
| 45 case MojoResult.FAILED_PRECONDITION: | 45 case MojoResult.FAILED_PRECONDITION: |
| 46 return false; | 46 return false; |
| 47 default: | 47 default: |
| 48 // Should be unreachable. | 48 // Should be unreachable. |
| 49 throw new Exception("Unreachable"); | 49 throw "Unexpected result $res for wait on $h"; |
| 50 } | 50 } |
| 51 } | 51 } |
| 52 | 52 |
| 53 bool readyRead() => _ready(MojoHandleSignals.READABLE); | 53 bool get readyRead => _ready(MojoHandleSignals.READABLE); |
| 54 bool readyWrite() => _ready(MojoHandleSignals.WRITABLE); | 54 bool get readyWrite => _ready(MojoHandleSignals.WRITABLE); |
| 55 | 55 |
| 56 static MojoWaitManyResult waitMany(List<int> handles, | 56 static MojoWaitManyResult waitMany( |
| 57 List<int> signals, | 57 List<int> handles, List<int> signals, int deadline) { |
| 58 int deadline) { | 58 List result = _MojoHandleNatives.waitMany(handles, signals, deadline); |
| 59 List result = _MojoHandleNatives.waitMany( | |
| 60 handles, signals, deadline); | |
| 61 | |
| 62 return new MojoWaitManyResult( | 59 return new MojoWaitManyResult( |
| 63 new MojoResult(result[0]), result[1], result[2]); | 60 new MojoResult(result[0]), result[1], result[2]); |
| 64 } | 61 } |
| 65 | 62 |
| 66 static MojoResult register(MojoHandle handle) { | 63 static MojoResult register(MojoEventStream eventStream) { |
| 67 return new MojoResult(_MojoHandleNatives.register(handle)); | 64 return new MojoResult(_MojoHandleNatives.register(eventStream)); |
| 68 } | 65 } |
| 69 | 66 |
| 70 bool get isValid => (h != INVALID); | 67 bool get isValid => (h != INVALID); |
| 71 | 68 |
| 72 String toString() => "$h"; | 69 String toString() => "$h"; |
| 73 | 70 |
| 74 bool operator ==(RawMojoHandle other) { | 71 bool operator ==(MojoHandle other) { |
| 75 return h == other.h; | 72 return h == other.h; |
| 76 } | 73 } |
| 77 } | 74 } |
| 78 | 75 |
| 79 | 76 |
| 80 class MojoHandle extends Stream<int> { | 77 class MojoEventStream extends Stream<int> { |
| 81 // The underlying Mojo handle. | 78 // The underlying Mojo handle. |
| 82 RawMojoHandle _handle; | 79 MojoHandle _handle; |
| 83 | 80 |
| 84 // Providing our own stream controller allows us to take custom actions when | 81 // Providing our own stream controller allows us to take custom actions when |
| 85 // listeners pause/resume/etc. their StreamSubscription. | 82 // listeners pause/resume/etc. their StreamSubscription. |
| 86 StreamController _controller; | 83 StreamController _controller; |
| 87 | 84 |
| 88 // The send port that we give to the handle watcher to notify us of handle | 85 // The send port that we give to the handle watcher to notify us of handle |
| 89 // events. | 86 // events. |
| 90 SendPort _sendPort; | 87 SendPort _sendPort; |
| 91 | 88 |
| 92 // The receive port on which we listen and receive events from the handle | 89 // The receive port on which we listen and receive events from the handle |
| 93 // watcher. | 90 // watcher. |
| 94 ReceivePort _receivePort; | 91 ReceivePort _receivePort; |
| 95 | 92 |
| 96 // The signals on this handle that we're interested in. | 93 // The signals on this handle that we're interested in. |
| 97 int _signals; | 94 MojoHandleSignals _signals; |
| 98 | 95 |
| 99 // Whether the handle has been added to the handle watcher. | 96 // Whether listen has been called. |
| 100 bool _eventHandlerAdded; | 97 bool _isListening; |
| 101 | 98 |
| 102 MojoHandle(this._handle) : | 99 MojoEventStream(MojoHandle handle, |
| 103 _signals = MojoHandleSignals.READABLE, | 100 [MojoHandleSignals signals = MojoHandleSignals.READABLE]) : |
| 104 _eventHandlerAdded = false { | 101 _handle = handle, |
| 105 MojoResult result = RawMojoHandle.register(this); | 102 _signals = signals, |
| 103 _isListening = false { |
| 104 MojoResult result = MojoHandle.register(this); |
| 106 if (!result.isOk) { | 105 if (!result.isOk) { |
| 107 throw new Exception("Failed to register the MojoHandle"); | 106 throw "Failed to register the MojoHandle: $result."; |
| 108 } | 107 } |
| 109 } | 108 } |
| 110 | 109 |
| 111 void close() { | 110 void close() { |
| 112 if (_eventHandlerAdded) { | 111 if (_handle != null) { |
| 113 MojoHandleWatcher.close(_handle); | 112 MojoHandleWatcher.close(_handle); |
| 114 _eventHandlerAdded = false; | 113 _handle = null; |
| 115 } else { | |
| 116 // If we're not in the handle watcher, then close the handle manually. | |
| 117 _handle.close(); | |
| 118 } | 114 } |
| 119 if (_receivePort != null) { | 115 if (_receivePort != null) { |
| 120 _receivePort.close(); | 116 _receivePort.close(); |
| 117 _receivePort = null; |
| 121 } | 118 } |
| 122 } | 119 } |
| 123 | 120 |
| 124 // We wrap the callback provided by clients in listen() with some code to | 121 StreamSubscription<List<int>> listen( |
| 125 // handle adding and removing the handle to/from the handle watcher. Because | 122 void onData(List event), |
| 126 // the handle watcher removes this handle whenever it receives an event, | |
| 127 // we have to re-add it when the callback is finished. | |
| 128 Function _onDataClosure(origOnData) { | |
| 129 return ((int event) { | |
| 130 // The handle watcher removes this handle from its set on an event. | |
| 131 _eventHandlerAdded = false; | |
| 132 origOnData(event); | |
| 133 | |
| 134 // The callback could have closed the handle. If so, don't add it back to | |
| 135 // the MojoHandleWatcher. | |
| 136 if (_handle.isValid) { | |
| 137 assert(!_eventHandlerAdded); | |
| 138 var res = MojoHandleWatcher.add(_handle, _sendPort, _signals); | |
| 139 if (!res.isOk) { | |
| 140 throw new Exception("Failed to re-add handle: $res"); | |
| 141 } | |
| 142 _eventHandlerAdded = true; | |
| 143 } | |
| 144 }); | |
| 145 } | |
| 146 | |
| 147 StreamSubscription<int> listen( | |
| 148 void onData(int event), | |
| 149 {Function onError, void onDone(), bool cancelOnError}) { | 123 {Function onError, void onDone(), bool cancelOnError}) { |
| 124 if (_isListening) { |
| 125 throw "Listen has already been called: $_handle."; |
| 126 } |
| 150 _receivePort = new ReceivePort(); | 127 _receivePort = new ReceivePort(); |
| 151 _sendPort = _receivePort.sendPort; | 128 _sendPort = _receivePort.sendPort; |
| 152 _controller = new StreamController(sync: true, | 129 _controller = new StreamController(sync: true, |
| 153 onListen: _onSubscriptionStateChange, | 130 onListen: _onSubscriptionStateChange, |
| 154 onCancel: _onSubscriptionStateChange, | 131 onCancel: _onSubscriptionStateChange, |
| 155 onPause: _onPauseStateChange, | 132 onPause: _onPauseStateChange, |
| 156 onResume: _onPauseStateChange); | 133 onResume: _onPauseStateChange); |
| 157 _controller.addStream(_receivePort); | 134 _controller.addStream(_receivePort); |
| 158 | 135 |
| 159 assert(!_eventHandlerAdded); | 136 if (_signals != MojoHandleSignals.NONE) { |
| 160 var res = MojoHandleWatcher.add(_handle, _sendPort, _signals); | 137 var res = MojoHandleWatcher.add(_handle, _sendPort, _signals.value); |
| 161 if (!res.isOk) { | 138 if (!res.isOk) { |
| 162 throw new Exception("MojoHandleWatcher add failed: $res"); | 139 throw "MojoHandleWatcher add failed: $res"; |
| 140 } |
| 163 } | 141 } |
| 164 _eventHandlerAdded = true; | |
| 165 | 142 |
| 143 _isListening = true; |
| 166 return _controller.stream.listen( | 144 return _controller.stream.listen( |
| 167 _onDataClosure(onData), | 145 onData, |
| 168 onError: onError, | 146 onError: onError, |
| 169 onDone: onDone, | 147 onDone: onDone, |
| 170 cancelOnError: cancelOnError); | 148 cancelOnError: cancelOnError); |
| 171 } | 149 } |
| 172 | 150 |
| 173 bool writeEnabled() => MojoHandleSignals.isWritable(_signals); | 151 void enableSignals(MojoHandleSignals signals) { |
| 174 | 152 _signals = signals; |
| 175 void toggleWriteEvents() { | 153 if (_isListening) { |
| 176 _signals = MojoHandleSignals.toggleWrite(_signals); | 154 var res = MojoHandleWatcher.add(_handle, _sendPort, signals.value); |
| 177 if (_eventHandlerAdded) { | |
| 178 var res = MojoHandleWatcher.toggleWrite(_handle); | |
| 179 if (!res.isOk) { | 155 if (!res.isOk) { |
| 180 throw new Exception("MojoHandleWatcher failed to toggle write: $res"); | 156 throw "MojoHandleWatcher add failed: $res"; |
| 181 } | 157 } |
| 182 } | 158 } |
| 183 } | 159 } |
| 184 | 160 |
| 185 void enableWriteEvents() { | 161 void enableReadEvents() => enableSignals(MojoHandleSignals.READABLE); |
| 186 assert(!writeEnabled()); | 162 void enableWriteEvents() => enableSignals(MojoHandleSignals.WRITABLE); |
| 187 toggleWriteEvents(); | 163 void enableAllEvents() => enableSignals(MojoHandleSignals.READWRITE); |
| 188 } | |
| 189 | |
| 190 void disableWriteEvents() { | |
| 191 assert(writeEnabled()); | |
| 192 toggleWriteEvents(); | |
| 193 } | |
| 194 | 164 |
| 195 void _onSubscriptionStateChange() { | 165 void _onSubscriptionStateChange() { |
| 196 if (!_controller.hasListener) { | 166 if (!_controller.hasListener) { |
| 197 close(); | 167 close(); |
| 198 } | 168 } |
| 199 } | 169 } |
| 200 | 170 |
| 201 void _onPauseStateChange() { | 171 void _onPauseStateChange() { |
| 202 if (_controller.isPaused) { | 172 if (_controller.isPaused) { |
| 203 if (_eventHandlerAdded) { | 173 var res = MojoHandleWatcher.remove(_handle); |
| 204 var res = MojoHandleWatcher.remove(_handle); | 174 if (!res.isOk) { |
| 205 if (!res.isOk) { | 175 throw "MojoHandleWatcher add failed: $res"; |
| 206 throw new Exception("MojoHandleWatcher add failed: $res"); | |
| 207 } | |
| 208 _eventHandlerAdded = false; | |
| 209 } | 176 } |
| 210 } else { | 177 } else { |
| 211 if (!_eventHandlerAdded) { | 178 var res = MojoHandleWatcher.add(_handle, _sendPort, _signals.value); |
| 212 var res = MojoHandleWatcher.add(_handle, _sendPort, _signals); | 179 if (!res.isOk) { |
| 213 if (!res.isOk) { | 180 throw "MojoHandleWatcher add failed: $res"; |
| 214 throw new Exception("MojoHandleWatcher add failed: $res"); | |
| 215 } | |
| 216 _eventHandlerAdded = true; | |
| 217 } | 181 } |
| 218 } | 182 } |
| 219 } | 183 } |
| 220 | 184 |
| 185 bool get readyRead => _handle.readyRead; |
| 186 bool get readyWrite => _handle.readyWrite; |
| 187 |
| 221 String toString() => "$_handle"; | 188 String toString() => "$_handle"; |
| 222 } | 189 } |
| OLD | NEW |