Index: mojo/bindings/java/src/org/chromium/mojo/bindings/ExecutorFactory.java |
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 0000000000000000000000000000000000000000..0bb269b7d3328b4d9523bafcf5444ca4bce12ef7 |
--- /dev/null |
+++ b/mojo/bindings/java/src/org/chromium/mojo/bindings/ExecutorFactory.java |
@@ -0,0 +1,146 @@ |
+// 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.Collections; |
+import java.util.List; |
+import java.util.concurrent.Executor; |
+ |
+/** |
+ * A factory that allows to access executors that will execute everything on the thread they are |
+ * obtained from. |
+ */ |
+class ExecutorFactory { |
+ /** |
+ * A static buffer used to notify the executor threads. |
+ */ |
+ private static final ByteBuffer NOTIFY_BUFFER = ByteBuffer.allocateDirect(1); |
+ |
+ /** |
+ * Implementation of the executor. The executor owned a pair of {@link MessagePipeHandle}. It |
+ * waits asynchronously on one handle on the thread it will execute commands. When it receives a |
+ * command to execute, it queues it on a queue, and write a message on the other handle. |
+ * Whenever a message is received on the first handle, the executor dequeue on action and runs |
+ * it. |
+ */ |
+ private static class PipedExecutor implements Executor, Callback { |
+ |
+ /** |
+ * The handle to write to. |
+ */ |
+ private final MessagePipeHandle mWriteHandle; |
+ /** |
+ * The handle to read from. |
+ */ |
+ private final MessagePipeHandle mReadHandle; |
+ /** |
+ * The list of actions left to be run. |
+ */ |
+ private final List<Runnable> mPendingActions; |
+ private final AsyncWaiter mWaiter; |
+ |
+ /** |
+ * Constructor. |
+ */ |
+ public PipedExecutor(Core core) { |
+ mWaiter = core.getDefaultAsyncWaiter(); |
+ Pair<MessagePipeHandle, MessagePipeHandle> handles = core.createMessagePipe(); |
+ mReadHandle = handles.first; |
+ mWriteHandle = handles.second; |
+ mPendingActions = Collections.synchronizedList(new ArrayList<Runnable>()); |
+ if (mWaiter != null) { |
+ asyncWait(); |
+ } |
+ } |
+ |
+ /** |
+ * Wait for the next command to arrive. |
+ */ |
+ 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) { |
+ Runnable toRun = mPendingActions.remove(0); |
+ toRun.run(); |
+ ReadMessageResult readMessageResult = mReadHandle.readMessage(NOTIFY_BUFFER, 0, |
+ MessagePipeHandle.ReadFlags.NONE); |
+ if (readMessageResult.getMojoResult() == MojoResult.OK) { |
+ asyncWait(); |
+ } else { |
+ close(); |
+ } |
+ } else { |
+ close(); |
+ } |
+ } |
+ |
+ /** |
+ * Close the handles. Should only be called on the executor thread. |
+ */ |
+ void close() { |
+ mPendingActions.clear(); |
+ mReadHandle.close(); |
+ synchronized (mWriteHandle) { |
+ mWriteHandle.close(); |
+ } |
+ } |
+ |
+ /** |
+ * @see Callback#onError(MojoException) |
+ */ |
+ @Override |
+ public void onError(MojoException exception) { |
+ close(); |
+ } |
+ |
+ /** |
+ * @see Executor#execute(Runnable) |
+ */ |
+ @Override |
+ public void execute(Runnable command) { |
+ mPendingActions.add(command); |
+ // Accessing the write handle must be protected, because its internal value will change |
+ // when it is closed. |
+ synchronized (mWriteHandle) { |
+ 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; |
+ } |
+} |