Index: mojo/public/dart/src/handle.dart |
diff --git a/mojo/public/dart/src/handle.dart b/mojo/public/dart/src/handle.dart |
index a612553d40b638ac7449f68b15c6f4a04b428fd9..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]); |
@@ -48,8 +67,25 @@ class MojoHandle { |
} |
} |
+ 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; |
} |
} |