| 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;
|
| + }
|
| +}
|
|
|