summaryrefslogtreecommitdiffstats
path: root/mojo/bindings
diff options
context:
space:
mode:
authorqsr@chromium.org <qsr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-07-08 20:59:02 +0000
committerqsr@chromium.org <qsr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-07-08 20:59:02 +0000
commitb856433e86b51eeb230c727095af5108dad61e86 (patch)
tree1943561f806d9a257b1fa99a86548073c83d3ed0 /mojo/bindings
parentd027020080801b97d742aab193f87f8352216251 (diff)
downloadchromium_src-b856433e86b51eeb230c727095af5108dad61e86.zip
chromium_src-b856433e86b51eeb230c727095af5108dad61e86.tar.gz
chromium_src-b856433e86b51eeb230c727095af5108dad61e86.tar.bz2
Adding an ExecutorFactory for the bindings.
This will allow to call back the thread owning a connector from the finalization thread. This API is private to the bindings code. R=rmcilroy@chromium.org Review URL: https://codereview.chromium.org/368923004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@281821 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'mojo/bindings')
-rw-r--r--mojo/bindings/java/src/org/chromium/mojo/bindings/ExecutorFactory.java183
1 files changed, 183 insertions, 0 deletions
diff --git a/mojo/bindings/java/src/org/chromium/mojo/bindings/ExecutorFactory.java b/mojo/bindings/java/src/org/chromium/mojo/bindings/ExecutorFactory.java
new file mode 100644
index 0000000..c153bc9
--- /dev/null
+++ b/mojo/bindings/java/src/org/chromium/mojo/bindings/ExecutorFactory.java
@@ -0,0 +1,183 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.mojo.bindings;
+
+import org.chromium.mojo.system.AsyncWaiter;
+import org.chromium.mojo.system.AsyncWaiter.Callback;
+import org.chromium.mojo.system.Core;
+import org.chromium.mojo.system.MessagePipeHandle;
+import org.chromium.mojo.system.MessagePipeHandle.ReadMessageResult;
+import org.chromium.mojo.system.MojoException;
+import org.chromium.mojo.system.MojoResult;
+import org.chromium.mojo.system.Pair;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Executor;
+
+/**
+ * A factory which provides per-thread executors, which enable execution on the thread from which
+ * they were obtained.
+ */
+class ExecutorFactory {
+
+ /**
+ * A null buffer which is used to send messages without any data on the PipedExecutor's
+ * signaling handles.
+ */
+ private static final ByteBuffer NOTIFY_BUFFER = null;
+
+ /**
+ * Implementation of the executor which uses a pair of {@link MessagePipeHandle} for signaling.
+ * The executor will wait asynchronously on one end of a {@link MessagePipeHandle} on the thread
+ * on which it was created. Other threads can call execute with a {@link Runnable}, and the
+ * executor will queue the {@link Runnable} and write a message on the other end of the handle.
+ * This will wake up the executor which is waiting on the handle, which will then dequeue the
+ * {@link Runnable} and execute it on the original thread.
+ */
+ private static class PipedExecutor implements Executor, Callback {
+
+ /**
+ * The handle which is written to. Access to this object must be protected with |mLock|.
+ */
+ private final MessagePipeHandle mWriteHandle;
+ /**
+ * The handle which is read from.
+ */
+ private final MessagePipeHandle mReadHandle;
+ /**
+ * The list of actions left to be run. Access to this object must be protected with |mLock|.
+ */
+ private final List<Runnable> mPendingActions;
+ /**
+ * Lock protecting access to |mWriteHandle| and |mPendingActions|.
+ */
+ private final Object mLock;
+ /**
+ * The {@link AsyncWaiter} to get notified of new message availability on |mReadHandle|.
+ */
+ private final AsyncWaiter mWaiter;
+
+ /**
+ * Constructor.
+ */
+ public PipedExecutor(Core core) {
+ mWaiter = core.getDefaultAsyncWaiter();
+ assert mWaiter != null;
+ mLock = new Object();
+ Pair<MessagePipeHandle, MessagePipeHandle> handles = core.createMessagePipe();
+ mReadHandle = handles.first;
+ mWriteHandle = handles.second;
+ mPendingActions = new ArrayList<Runnable>();
+ asyncWait();
+ }
+
+ /**
+ * Asynchronously wait for the next command to arrive. This should only be called on the
+ * executor thread.
+ */
+ private void asyncWait() {
+ mWaiter.asyncWait(mReadHandle, Core.WaitFlags.READABLE, Core.DEADLINE_INFINITE,
+ this);
+ }
+
+ /**
+ * @see Callback#onResult(int)
+ */
+ @Override
+ public void onResult(int result) {
+ if (result == MojoResult.OK && readNotifyBufferMessage()) {
+ runNextAction();
+ } else {
+ close();
+ }
+ }
+
+ /**
+ * @see Callback#onError(MojoException)
+ */
+ @Override
+ public void onError(MojoException exception) {
+ close();
+ }
+
+ /**
+ * Close the handles. Should only be called on the executor thread.
+ */
+ private void close() {
+ synchronized (mLock) {
+ mWriteHandle.close();
+ mPendingActions.clear();
+ }
+ mReadHandle.close();
+ }
+
+ /**
+ * Read the next message on |mReadHandle|, and return |true| if successful, |false|
+ * otherwise.
+ */
+ private boolean readNotifyBufferMessage() {
+ try {
+ ReadMessageResult readMessageResult = mReadHandle.readMessage(NOTIFY_BUFFER, 0,
+ MessagePipeHandle.ReadFlags.NONE);
+ if (readMessageResult.getMojoResult() == MojoResult.OK) {
+ asyncWait();
+ return true;
+ }
+ } catch (MojoException e) {
+ // Will be closed by the fall back at the end of this method.
+ }
+ return false;
+ }
+
+ /**
+ * Run the next action in the |mPendingActions| queue.
+ */
+ private void runNextAction() {
+ Runnable toRun = null;
+ synchronized (mWriteHandle) {
+ toRun = mPendingActions.remove(0);
+ }
+ toRun.run();
+ }
+
+ /**
+ * Execute the given |command| in the executor thread. This can be called on any thread.
+ *
+ * @see Executor#execute(Runnable)
+ */
+ @Override
+ public void execute(Runnable command) {
+ // Accessing the write handle must be protected by the lock, because it can be closed
+ // from the executor's thread.
+ synchronized (mLock) {
+ if (!mWriteHandle.isValid()) {
+ throw new IllegalStateException(
+ "Trying to execute an action on a closed executor.");
+ }
+ mPendingActions.add(command);
+ mWriteHandle.writeMessage(NOTIFY_BUFFER, null, MessagePipeHandle.WriteFlags.NONE);
+ }
+ }
+ }
+
+ /**
+ * Keep one executor per executor thread.
+ */
+ private static final ThreadLocal<Executor> EXECUTORS = new ThreadLocal<Executor>();
+
+ /**
+ * Returns an {@link Executor} that will run all of its actions in the current thread.
+ */
+ public static Executor getExecutorForCurrentThread(Core core) {
+ Executor executor = EXECUTORS.get();
+ if (executor == null) {
+ executor = new PipedExecutor(core);
+ EXECUTORS.set(executor);
+ }
+ return executor;
+ }
+}