- Rename "nodefer" to "immediate" (gets rid of double negative in "nodefer: false").
- Immediate close means that anything pending will be discarded.
- Plumb immediate all the way down to the handle watcher close call.
- When an EventStream is closed because no one is listening for events, close immediately.
- Don't call Dart_NewSendPort with ILLEGAL_PORT in sky embedder.
- Bump DEPS to include fixes for Dart_NewSendPort and profiler signal handler executing after shared object is unloaded.
- Fixes https://github.com/domokit/mojo/issues/79

R=zra@google.com

Review URL: https://codereview.chromium.org/1060193002
diff --git a/DEPS b/DEPS
index 8d8e9b2..602e9c0 100644
--- a/DEPS
+++ b/DEPS
@@ -25,7 +25,7 @@
   'v8_revision': '230d131d173ab2d60291d303177bc04ec3f6e519',
   'angle_revision': 'bdd419f9f5b006e913606e7363125942c8ae06bc',
   'buildtools_revision': '3b302fef93f7cc58d9b8168466905237484b2772',
-  'dart_revision': '44854',
+  'dart_revision': '44944',
   'pdfium_revision': 'b0115665b0f33971f1b7077740d51e155583cec0',
   'boringssl_revision': '642f1498d056dbba3e50ed5a232ab2f482626dec',
   'lss_revision': 'e079768b7e3a94dcbe7d338496c0c3bde7151b6e',
diff --git a/mojo/dart/test/validation_test.dart b/mojo/dart/test/validation_test.dart
index e747a4a..d4ab222 100644
--- a/mojo/dart/test/validation_test.dart
+++ b/mojo/dart/test/validation_test.dart
@@ -37,7 +37,7 @@
   method10(Map<String, int> param0) => _complete();
   method11(StructG param0) => _complete();
 
-  Future close({bool nodefer: false}) => _stub.close(nodefer: nodefer);
+  Future close({bool immediate: false}) => _stub.close(immediate: immediate);
 }
 
 parser.ValidationParseResult readAndParseTest(String test) {
@@ -65,7 +65,7 @@
     assert(e is MojoCodecError);
     // TODO(zra): Make the error messages conform?
     // assert(e == expected);
-    conformanceImpl.close(nodefer: true);
+    conformanceImpl.close(immediate: true);
     pipe.endpoints[0].handle.close();
     handles.forEach((h) => h.close());
   });
diff --git a/mojo/public/dart/src/application.dart b/mojo/public/dart/src/application.dart
index 03d0843..f6ee473 100644
--- a/mojo/public/dart/src/application.dart
+++ b/mojo/public/dart/src/application.dart
@@ -41,9 +41,11 @@
   @override
   void requestQuit() => _application._requestQuitAndClose();
 
-  Future close({bool nodefer: false}) {
-    if (shell != null) shell.close();
-    return _stub.close();
+  Future close({bool immediate: false}) {
+    if (shell != null) {
+      shell.close(immediate: immediate);
+    }
+    return _stub.close(immediate: immediate);
   }
 }
 
@@ -104,11 +106,11 @@
     });
   }
 
-  Future close() {
+  Future close({bool immediate: false}) {
     assert(_applicationImpl != null);
-    _applicationConnections.forEach((c) => c.close());
+    _applicationConnections.forEach((c) => c.close(immediate: immediate));
     _applicationConnections.clear();
-    return _applicationImpl.close();
+    return _applicationImpl.close(immediate: immediate);
   }
 
   // This method closes all the application connections. Used during apptesting.
diff --git a/mojo/public/dart/src/application_connection.dart b/mojo/public/dart/src/application_connection.dart
index 8c354ea..2e80fc1 100644
--- a/mojo/public/dart/src/application_connection.dart
+++ b/mojo/public/dart/src/application_connection.dart
@@ -21,7 +21,7 @@
     _stub.onError = f;
   }
 
-  Future close({bool nodefer: false}) => _stub.close(nodefer: nodefer);
+  Future close({bool immediate: false}) => _stub.close(immediate: immediate);
 
   void connectToService(
       String interfaceName, core.MojoMessagePipeEndpoint pipe) {
@@ -101,7 +101,7 @@
     });
   }
 
-  Future close({bool nodefer: false}) {
+  Future close({bool immediate: false}) {
     var rspCloseFuture;
     var lspCloseFuture;
     if (remoteServiceProvider != null) {
@@ -111,7 +111,7 @@
       rspCloseFuture = new Future.value(null);
     }
     if (_localServiceProvider != null) {
-      lspCloseFuture = _localServiceProvider.close(nodefer: nodefer);
+      lspCloseFuture = _localServiceProvider.close(immediate: immediate);
       _localServiceProvider = null;
     } else {
       lspCloseFuture = new Future.value(null);
diff --git a/mojo/public/dart/src/event_stream.dart b/mojo/public/dart/src/event_stream.dart
index 712d025..febfc9d 100644
--- a/mojo/public/dart/src/event_stream.dart
+++ b/mojo/public/dart/src/event_stream.dart
@@ -37,10 +37,10 @@
     }
   }
 
-  Future close() {
+  Future close({bool immediate: false}) {
     if (_handle != null) {
       if (_isListening) {
-        return _handleWatcherClose();
+        return _handleWatcherClose(immediate: immediate);
       } else {
         _localClose();
         return new Future.value(null);
@@ -92,10 +92,10 @@
   void enableWriteEvents() => enableSignals(MojoHandleSignals.WRITABLE);
   void enableAllEvents() => enableSignals(MojoHandleSignals.READWRITE);
 
-  Future _handleWatcherClose() {
+  Future _handleWatcherClose({bool immediate: false}) {
     assert(_handle != null);
     assert(MojoHandle._removeUnclosedHandle(_handle));
-    return MojoHandleWatcher.close(_handle.h, wait: true).then((r) {
+    return MojoHandleWatcher.close(_handle.h, wait: !immediate).then((r) {
       if (_receivePort != null) {
         _receivePort.close();
         _receivePort = null;
@@ -116,7 +116,8 @@
 
   void _onSubscriptionStateChange() {
     if (!_controller.hasListener) {
-      close();
+      // No one is listening, close it immediately.
+      close(immediate: true);
     }
   }
 
@@ -210,9 +211,9 @@
       }
       _isInHandler = false;
       if (signalsReceived.isPeerClosed) {
-        // nodefer is true here because there is no need to wait to close until
-        // outstanding messages are sent. The other side is gone.
-        close(nodefer: true).then((_) {
+        // immediate is true here because there is no need to wait to close
+        // until outstanding messages are sent. The other side is gone.
+        close(immediate: true).then((_) {
           if (onError != null) {
             onError();
           }
@@ -222,13 +223,13 @@
     return subscription;
   }
 
-  Future close({bool nodefer: false}) {
+  Future close({bool immediate: false}) {
     var result;
     _isOpen = false;
     _endpoint = null;
     subscription = null;
     if (_eventStream != null) {
-      result = _eventStream.close().then((_) {
+      result = _eventStream.close(immediate: immediate).then((_) {
         _eventStream = null;
       });
     }
diff --git a/mojo/public/dart/src/proxy.dart b/mojo/public/dart/src/proxy.dart
index a84ca3e..863e734 100644
--- a/mojo/public/dart/src/proxy.dart
+++ b/mojo/public/dart/src/proxy.dart
@@ -47,12 +47,12 @@
   }
 
   @override
-  Future close({bool nodefer: false}) {
+  Future close({bool immediate: false}) {
     for (var completer in _completerMap.values) {
       completer.completeError(new ProxyCloseException('Proxy closed'));
     }
     _completerMap.clear();
-    return super.close(nodefer: nodefer);
+    return super.close(immediate: immediate);
   }
 
   void sendMessage(Struct message, int name) {
diff --git a/mojo/public/dart/src/stub.dart b/mojo/public/dart/src/stub.dart
index 9008f55..c932584 100644
--- a/mojo/public/dart/src/stub.dart
+++ b/mojo/public/dart/src/stub.dart
@@ -52,9 +52,11 @@
             // This was the final response future for which we needed to send
             // a response. It is safe to close.
             super.close().then((_) {
-              _isClosing = false;
-              _closeCompleter.complete(null);
-              _closeCompleter = null;
+              if (_isClosing) {
+                _isClosing = false;
+                _closeCompleter.complete(null);
+                _closeCompleter = null;
+              }
             });
           }
         }
@@ -63,9 +65,11 @@
       // We are closing, there is no response to send for this message, and
       // there are no outstanding response futures. Do the close now.
       super.close().then((_) {
-        _isClosing = false;
-        _closeCompleter.complete(null);
-        _closeCompleter = null;
+        if (_isClosing) {
+          _isClosing = false;
+          _closeCompleter.complete(null);
+          _closeCompleter = null;
+        }
       });
     }
   }
@@ -74,13 +78,13 @@
     throw 'Unexpected write signal in client.';
   }
 
-  // NB: |nodefer| should only be true when calling close() while handling an
+  // NB: |immediate| should only be true when calling close() while handling an
   // exception thrown from handleRead(), e.g. when we receive a malformed
   // message, or when we have received the PEER_CLOSED event.
   @override
-  Future close({bool nodefer: false}) {
+  Future close({bool immediate: false}) {
     if (isOpen &&
-        !nodefer &&
+        !immediate &&
         (isInHandler || (_outstandingResponseFutures > 0))) {
       // Either close() is being called from within handleRead() or
       // handleWrite(), or close() is being called while there are outstanding
@@ -90,7 +94,7 @@
       _closeCompleter = new Completer();
       return _closeCompleter.future;
     } else {
-      return super.close(nodefer: nodefer).then((_) {
+      return super.close(immediate: immediate).then((_) {
         if (_isClosing) {
           _isClosing = false;
           _closeCompleter.complete(null);
diff --git a/mojo/public/tools/bindings/generators/dart_templates/interface_definition.tmpl b/mojo/public/tools/bindings/generators/dart_templates/interface_definition.tmpl
index 30463b2..99e2ab3 100644
--- a/mojo/public/tools/bindings/generators/dart_templates/interface_definition.tmpl
+++ b/mojo/public/tools/bindings/generators/dart_templates/interface_definition.tmpl
@@ -158,7 +158,7 @@
       core.MojoMessagePipeEndpoint endpoint) =>
       new {{interface|name}}Proxy.fromEndpoint(endpoint);
 
-  Future close({bool nodefer: false}) => impl.close(nodefer: nodefer);
+  Future close({bool immediate: false}) => impl.close(immediate: immediate);
 
   String toString() {
     return "{{interface|name}}Proxy($impl)";
diff --git a/sky/engine/bindings/mojo_natives.cc b/sky/engine/bindings/mojo_natives.cc
index 25faf76..c67f71a 100644
--- a/sky/engine/bindings/mojo_natives.cc
+++ b/sky/engine/bindings/mojo_natives.cc
@@ -716,7 +716,7 @@
   CHECK_INTEGER_ARGUMENT(arguments, 1, &client_handle, InvalidArgument);
 
   Dart_Handle send_port_handle = Dart_GetNativeArgument(arguments, 2);
-  Dart_Port send_port_id = 0;
+  Dart_Port send_port_id = ILLEGAL_PORT;
   if (!Dart_IsNull(send_port_handle)) {
     Dart_Handle result = Dart_SendPortGetId(send_port_handle, &send_port_id);
     if (Dart_IsError(result)) {
@@ -755,7 +755,9 @@
 
   Dart_Handle list = Dart_NewList(3);
   Dart_ListSetAt(list, 0, Dart_NewInteger(cd.handle));
-  Dart_ListSetAt(list, 1, Dart_NewSendPort(cd.port));
+  if (cd.port != ILLEGAL_PORT) {
+    Dart_ListSetAt(list, 1, Dart_NewSendPort(cd.port));
+  }
   Dart_ListSetAt(list, 2, Dart_NewInteger(cd.data));
   Dart_SetReturnValue(arguments, list);
 }