| Index: mojo/public/dart/src/handle.dart
|
| diff --git a/mojo/public/dart/src/handle.dart b/mojo/public/dart/src/handle.dart
|
| index 298ed1df090afe8122a388ee3c5703e39f6d44bd..6b99ed87aa79e929fe865fe076f3c51d8ba7881e 100644
|
| --- a/mojo/public/dart/src/handle.dart
|
| +++ b/mojo/public/dart/src/handle.dart
|
| @@ -13,20 +13,39 @@ class _MojoHandleNatives {
|
| int deadline) native "MojoHandle_WaitMany";
|
| }
|
|
|
| +class _HandleCreationRecord {
|
| + final MojoHandle handle;
|
| + final StackTrace stack;
|
| + _HandleCreationRecord(this.handle, this.stack);
|
| +}
|
| +
|
| class MojoHandle {
|
| static const int INVALID = 0;
|
| static const int DEADLINE_INDEFINITE = -1;
|
|
|
| - int h;
|
| + int _h;
|
| + int get h => _h;
|
| +
|
| + MojoHandle(this._h) {
|
| + assert(_addUnclosedHandle(this));
|
| + }
|
| +
|
| + MojoHandle._internal(this._h);
|
|
|
| - MojoHandle(this.h);
|
| + MojoHandle.invalid() : this._internal(INVALID);
|
|
|
| MojoResult close() {
|
| - int result = _MojoHandleNatives.close(h);
|
| - h = INVALID;
|
| + assert(_removeUnclosedHandle(this));
|
| + int result = _MojoHandleNatives.close(_h);
|
| + _h = INVALID;
|
| return new MojoResult(result);
|
| }
|
|
|
| + MojoHandle pass() {
|
| + assert(_removeUnclosedHandle(this));
|
| + return this;
|
| + }
|
| +
|
| MojoWaitResult wait(int signals, int deadline) {
|
| List result = _MojoHandleNatives.wait(h, signals, deadline);
|
| return new MojoWaitResult(new MojoResult(result[0]), result[1]);
|
| @@ -44,12 +63,29 @@ class MojoHandle {
|
| return false;
|
| default:
|
| // Should be unreachable.
|
| - throw "Unexpected result $res for wait on $h";
|
| + throw "Unexpected result $mwr for wait on $h";
|
| }
|
| }
|
|
|
| + void _set(int value) {
|
| + _h = value;
|
| + }
|
| +
|
| bool get readyRead => _ready(MojoHandleSignals.PEER_CLOSED_READABLE);
|
| bool get readyWrite => _ready(MojoHandleSignals.WRITABLE);
|
| + bool get isValid => (_h != INVALID);
|
| +
|
| + String toString() {
|
| + if (!isValid) {
|
| + return "MojoHandle(INVALID)";
|
| + }
|
| + var mwr = wait(MojoHandleSignals.kAll, 0);
|
| + return "MojoHandle(h: $h, status: $mwr)";
|
| + }
|
| +
|
| + bool operator ==(MojoHandle other) {
|
| + return _h == other._h;
|
| + }
|
|
|
| static MojoWaitManyResult waitMany(
|
| List<int> handles, List<int> signals, int deadline) {
|
| @@ -62,17 +98,38 @@ class MojoHandle {
|
| return new MojoResult(_MojoHandleNatives.register(eventStream));
|
| }
|
|
|
| - bool get isValid => (h != INVALID);
|
| + static HashMap<int, _HandleCreationRecord> _unclosedHandles = new HashMap();
|
|
|
| - String toString() {
|
| - if (!isValid) {
|
| - return "MojoHandle(INVALID)";
|
| + // _addUnclosedHandle(), _removeUnclosedHandle(), and dumpLeakedHandles()
|
| + // should only be used inside of assert() statements.
|
| + static bool _addUnclosedHandle(MojoHandle handle) {
|
| + var stack;
|
| + try {
|
| + assert(false);
|
| + } catch (_, s) {
|
| + stack = s;
|
| }
|
| - var mwr = wait(MojoHandleSignals.kAll, 0);
|
| - return "MojoHandle(h: $h, status: $mwr)";
|
| +
|
| + var handleCreate = new _HandleCreationRecord(handle, stack);
|
| + _unclosedHandles[handle.h] = handleCreate;
|
| + return true;
|
| }
|
|
|
| - bool operator ==(MojoHandle other) {
|
| - return h == other.h;
|
| + static bool _removeUnclosedHandle(MojoHandle handle) {
|
| + _unclosedHandles.remove(handle._h);
|
| + return true;
|
| + }
|
| +
|
| + static bool reportLeakedHandles() {
|
| + var noleaks = true;
|
| + for (var handle in MojoHandle._unclosedHandles.keys) {
|
| + var handleCreation = MojoHandle._unclosedHandles[handle];
|
| + if (handleCreation != null) {
|
| + print("HANDLE LEAK: handle: $handle, created at:");
|
| + print("${handleCreation.stack}");
|
| + noleaks = false;
|
| + }
|
| + }
|
| + return noleaks;
|
| }
|
| }
|
|
|