[mojo-bindings] Use Watcher API for JS bindings
BUG=592183
Review URL: https://codereview.chromium.org/1777673003
Cr-Commit-Position: refs/heads/master@{#380092}
CrOS-Libchrome-Original-Commit: b98777bcf33f467bba92cff7de951f0b3fd13b32
diff --git a/mojo/edk/js/support.cc b/mojo/edk/js/support.cc
index 66d84a0..404cb9b 100644
--- a/mojo/edk/js/support.cc
+++ b/mojo/edk/js/support.cc
@@ -26,14 +26,26 @@
gin::Handle<HandleWrapper> handle,
MojoHandleSignals signals,
v8::Handle<v8::Function> callback) {
- return WaitingCallback::Create(args.isolate(), callback, handle, signals)
- .get();
+ return WaitingCallback::Create(
+ args.isolate(), callback, handle, signals, true /* one_shot */).get();
}
void CancelWait(WaitingCallback* waiting_callback) {
waiting_callback->Cancel();
}
+WaitingCallback* Watch(const gin::Arguments& args,
+ gin::Handle<HandleWrapper> handle,
+ MojoHandleSignals signals,
+ v8::Handle<v8::Function> callback) {
+ return WaitingCallback::Create(
+ args.isolate(), callback, handle, signals, false /* one_shot */).get();
+}
+
+void CancelWatch(WaitingCallback* waiting_callback) {
+ waiting_callback->Cancel();
+}
+
gin::WrapperInfo g_wrapper_info = { gin::kEmbedderNativeGin };
} // namespace
@@ -47,8 +59,11 @@
if (templ.IsEmpty()) {
templ = gin::ObjectTemplateBuilder(isolate)
+ // TODO(rockot): Remove asyncWait and cancelWait.
.SetMethod("asyncWait", AsyncWait)
.SetMethod("cancelWait", CancelWait)
+ .SetMethod("watch", Watch)
+ .SetMethod("cancelWatch", CancelWatch)
.Build();
data->SetObjectTemplate(&g_wrapper_info, templ);
diff --git a/mojo/edk/js/waiting_callback.cc b/mojo/edk/js/waiting_callback.cc
index af34d87..4ba2c61 100644
--- a/mojo/edk/js/waiting_callback.cc
+++ b/mojo/edk/js/waiting_callback.cc
@@ -28,31 +28,32 @@
v8::Isolate* isolate,
v8::Handle<v8::Function> callback,
gin::Handle<HandleWrapper> handle_wrapper,
- MojoHandleSignals signals) {
+ MojoHandleSignals signals,
+ bool one_shot) {
gin::Handle<WaitingCallback> waiting_callback = gin::CreateHandle(
- isolate, new WaitingCallback(isolate, callback, handle_wrapper));
-
- waiting_callback->handle_watcher_.Start(
- handle_wrapper->get(), signals, MOJO_DEADLINE_INDEFINITE,
+ isolate, new WaitingCallback(isolate, callback, one_shot));
+ MojoResult result = waiting_callback->watcher_.Start(
+ handle_wrapper->get(), signals,
base::Bind(&WaitingCallback::OnHandleReady,
base::Unretained(waiting_callback.get())));
+
+ // The signals may already be unsatisfiable.
+ if (result == MOJO_RESULT_FAILED_PRECONDITION)
+ waiting_callback->OnHandleReady(MOJO_RESULT_FAILED_PRECONDITION);
+
return waiting_callback;
}
void WaitingCallback::Cancel() {
- if (!handle_watcher_.is_watching())
- return;
-
- RemoveHandleCloseObserver();
- handle_watcher_.Stop();
+ if (watcher_.IsWatching())
+ watcher_.Cancel();
}
WaitingCallback::WaitingCallback(v8::Isolate* isolate,
v8::Handle<v8::Function> callback,
- gin::Handle<HandleWrapper> handle_wrapper)
- : handle_wrapper_(handle_wrapper.get()),
+ bool one_shot)
+ : one_shot_(one_shot),
weak_factory_(this) {
- handle_wrapper_->AddCloseObserver(this);
v8::Handle<v8::Context> context = isolate->GetCurrentContext();
runner_ = gin::PerContextData::From(context)->runner()->GetWeakPtr();
GetWrapper(isolate)
@@ -64,20 +65,7 @@
Cancel();
}
-void WaitingCallback::RemoveHandleCloseObserver() {
- handle_wrapper_->RemoveCloseObserver(this);
- handle_wrapper_ = nullptr;
-}
-
void WaitingCallback::OnHandleReady(MojoResult result) {
- RemoveHandleCloseObserver();
- CallCallback(result);
-}
-
-void WaitingCallback::CallCallback(MojoResult result) {
- DCHECK(!handle_watcher_.is_watching());
- DCHECK(!handle_wrapper_);
-
if (!runner_)
return;
@@ -94,18 +82,11 @@
v8::Handle<v8::Value> args[] = { gin::ConvertToV8(isolate, result) };
runner_->Call(callback, runner_->global(), 1, args);
-}
-void WaitingCallback::OnWillCloseHandle() {
- handle_watcher_.Stop();
-
- // This may be called from GC, so we can't execute Javascript now, call
- // RemoveHandleCloseObserver explicitly, and CallCallback asynchronously.
- RemoveHandleCloseObserver();
- base::MessageLoop::current()->PostTask(
- FROM_HERE,
- base::Bind(&WaitingCallback::CallCallback, weak_factory_.GetWeakPtr(),
- MOJO_RESULT_INVALID_ARGUMENT));
+ if (one_shot_ || result == MOJO_RESULT_CANCELLED) {
+ runner_.reset();
+ Cancel();
+ }
}
} // namespace js
diff --git a/mojo/edk/js/waiting_callback.h b/mojo/edk/js/waiting_callback.h
index f2554bc..1195a98 100644
--- a/mojo/edk/js/waiting_callback.h
+++ b/mojo/edk/js/waiting_callback.h
@@ -11,25 +11,28 @@
#include "gin/runner.h"
#include "gin/wrappable.h"
#include "mojo/edk/js/handle.h"
-#include "mojo/edk/js/handle_close_observer.h"
-#include "mojo/message_pump/handle_watcher.h"
#include "mojo/public/cpp/system/core.h"
+#include "mojo/public/cpp/system/watcher.h"
namespace mojo {
namespace edk {
namespace js {
-class WaitingCallback : public gin::Wrappable<WaitingCallback>,
- public HandleCloseObserver {
+class WaitingCallback : public gin::Wrappable<WaitingCallback> {
public:
static gin::WrapperInfo kWrapperInfo;
// Creates a new WaitingCallback.
+ //
+ // If |one_shot| is true, the callback will only ever be called at most once.
+ // If false, the callback may be called any number of times until the
+ // WaitingCallback is explicitly cancelled.
static gin::Handle<WaitingCallback> Create(
v8::Isolate* isolate,
v8::Handle<v8::Function> callback,
gin::Handle<HandleWrapper> handle_wrapper,
- MojoHandleSignals signals);
+ MojoHandleSignals signals,
+ bool one_shot);
// Cancels the callback. Does nothing if a callback is not pending. This is
// implicitly invoked from the destructor but can be explicitly invoked as
@@ -39,24 +42,19 @@
private:
WaitingCallback(v8::Isolate* isolate,
v8::Handle<v8::Function> callback,
- gin::Handle<HandleWrapper> handle_wrapper);
+ bool one_shot);
~WaitingCallback() override;
- // Callback from common::HandleWatcher.
+ // Callback from the Watcher.
void OnHandleReady(MojoResult result);
- // Invoked by the HandleWrapper if the handle is closed while this wait is
- // still in progress.
- void OnWillCloseHandle() override;
-
- void RemoveHandleCloseObserver();
- void CallCallback(MojoResult result);
+ // Indicates whether this is a one-shot callback or not. If so, it uses the
+ // deprecated HandleWatcher to wait for signals; otherwise it uses the new
+ // system Watcher API.
+ const bool one_shot_;
base::WeakPtr<gin::Runner> runner_;
-
- common::HandleWatcher handle_watcher_;
-
- HandleWrapper* handle_wrapper_;
+ Watcher watcher_;
base::WeakPtrFactory<WaitingCallback> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(WaitingCallback);
diff --git a/mojo/public/js/connector.js b/mojo/public/js/connector.js
index e672b54..674f36b 100644
--- a/mojo/public/js/connector.js
+++ b/mojo/public/js/connector.js
@@ -16,17 +16,20 @@
this.dropWrites_ = false;
this.error_ = false;
this.incomingReceiver_ = null;
- this.readWaitCookie_ = null;
+ this.readWatcher_ = null;
this.errorHandler_ = null;
- if (handle)
- this.waitToReadMore_();
+ if (handle) {
+ this.readWatcher_ = support.watch(handle,
+ core.HANDLE_SIGNAL_READABLE,
+ this.readMore_.bind(this));
+ }
}
Connector.prototype.close = function() {
- if (this.readWaitCookie_) {
- support.cancelWait(this.readWaitCookie_);
- this.readWaitCookie_ = null;
+ if (this.readWatcher_) {
+ support.cancelWatch(this.readWatcher_);
+ this.readWatcher_ = null;
}
if (this.handle_ != null) {
core.close(this.handle_);
@@ -79,22 +82,14 @@
return this.error_;
};
- Connector.prototype.waitToReadMore_ = function() {
- this.readWaitCookie_ = support.asyncWait(this.handle_,
- core.HANDLE_SIGNAL_READABLE,
- this.readMore_.bind(this));
- };
-
Connector.prototype.readMore_ = function(result) {
for (;;) {
var read = core.readMessage(this.handle_,
core.READ_MESSAGE_FLAG_NONE);
if (this.handle_ == null) // The connector has been closed.
return;
- if (read.result == core.RESULT_SHOULD_WAIT) {
- this.waitToReadMore_();
+ if (read.result == core.RESULT_SHOULD_WAIT)
return;
- }
if (read.result != core.RESULT_OK) {
this.error_ = true;
if (this.errorHandler_)
@@ -118,9 +113,6 @@
TestConnector.prototype = Object.create(Connector.prototype);
- TestConnector.prototype.waitToReadMore_ = function() {
- }
-
TestConnector.prototype.waitForNextMessage = function() {
var wait = core.wait(this.handle_, core.HANDLE_SIGNAL_READABLE,
core.DEADLINE_INDEFINITE);
diff --git a/mojo/public/js/support.js b/mojo/public/js/support.js
index 025da6c..7e27504 100644
--- a/mojo/public/js/support.js
+++ b/mojo/public/js/support.js
@@ -9,22 +9,45 @@
while (1);
-/*
+/* @deprecated Please use watch()/cancelWatch() instead of
+ * asyncWait()/cancelWait().
+ *
* Waits on the given handle until the state indicated by |signals| is
* satisfied.
*
* @param {MojoHandle} handle The handle to wait on.
* @param {MojoHandleSignals} signals Specifies the condition to wait for.
* @param {function (mojoResult)} callback Called with the result the wait is
- * complete. See MojoWait for possible result codes.
+ * complete. See MojoWait for possible result codes.
*
* @return {MojoWaitId} A waitId that can be passed to cancelWait to cancel the
- * wait.
+ * wait.
*/
function asyncWait(handle, signals, callback) { [native code] }
-/*
+/* @deprecated Please use watch()/cancelWatch() instead of
+ * asyncWait()/cancelWait().
+ *
* Cancels the asyncWait operation specified by the given |waitId|.
+ *
* @param {MojoWaitId} waitId The waitId returned by asyncWait.
*/
function cancelWait(waitId) { [native code] }
+
+/* Begins watching a handle for |signals| to be satisfied or unsatisfiable.
+ *
+ * @param {MojoHandle} handle The handle to watch.
+ * @param {MojoHandleSignals} signals The signals to watch.
+ * @param {function (mojoResult)} calback Called with a result any time
+ * the watched signals become satisfied or unsatisfiable.
+ *
+ * @param {MojoWatchId} watchId An opaque identifier that identifies this
+ * watch.
+ */
+function watch(handle, signals, callback) { [native code] }
+
+/* Cancels a handle watch initiated by watch().
+ *
+ * @param {MojoWatchId} watchId The watch identifier returned by watch().
+ */
+function cancelWatch(watchId) { [native code] }