OLD | NEW |
| (Empty) |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 package org.chromium.mojo.bindings; | |
6 | |
7 import org.chromium.mojo.system.AsyncWaiter; | |
8 import org.chromium.mojo.system.AsyncWaiter.Callback; | |
9 import org.chromium.mojo.system.Core; | |
10 import org.chromium.mojo.system.MessagePipeHandle; | |
11 import org.chromium.mojo.system.MessagePipeHandle.ReadMessageResult; | |
12 import org.chromium.mojo.system.MojoException; | |
13 import org.chromium.mojo.system.MojoResult; | |
14 import org.chromium.mojo.system.Pair; | |
15 import org.chromium.mojo.system.ResultAnd; | |
16 | |
17 import java.nio.ByteBuffer; | |
18 import java.util.ArrayList; | |
19 import java.util.List; | |
20 import java.util.concurrent.Executor; | |
21 | |
22 /** | |
23 * A factory which provides per-thread executors, which enable execution on the
thread from which | |
24 * they were obtained. | |
25 */ | |
26 class ExecutorFactory { | |
27 | |
28 /** | |
29 * A null buffer which is used to send messages without any data on the Pipe
dExecutor's | |
30 * signaling handles. | |
31 */ | |
32 private static final ByteBuffer NOTIFY_BUFFER = null; | |
33 | |
34 /** | |
35 * Implementation of the executor which uses a pair of {@link MessagePipeHan
dle} for signaling. | |
36 * The executor will wait asynchronously on one end of a {@link MessagePipeH
andle} on the thread | |
37 * on which it was created. Other threads can call execute with a {@link Run
nable}, and the | |
38 * executor will queue the {@link Runnable} and write a message on the other
end of the handle. | |
39 * This will wake up the executor which is waiting on the handle, which will
then dequeue the | |
40 * {@link Runnable} and execute it on the original thread. | |
41 */ | |
42 private static class PipedExecutor implements Executor, Callback { | |
43 | |
44 /** | |
45 * The handle which is written to. Access to this object must be protect
ed with |mLock|. | |
46 */ | |
47 private final MessagePipeHandle mWriteHandle; | |
48 /** | |
49 * The handle which is read from. | |
50 */ | |
51 private final MessagePipeHandle mReadHandle; | |
52 /** | |
53 * The list of actions left to be run. Access to this object must be pro
tected with |mLock|. | |
54 */ | |
55 private final List<Runnable> mPendingActions; | |
56 /** | |
57 * Lock protecting access to |mWriteHandle| and |mPendingActions|. | |
58 */ | |
59 private final Object mLock; | |
60 /** | |
61 * The {@link AsyncWaiter} to get notified of new message availability o
n |mReadHandle|. | |
62 */ | |
63 private final AsyncWaiter mWaiter; | |
64 | |
65 /** | |
66 * Constructor. | |
67 */ | |
68 public PipedExecutor(Core core) { | |
69 mWaiter = core.getDefaultAsyncWaiter(); | |
70 assert mWaiter != null; | |
71 mLock = new Object(); | |
72 Pair<MessagePipeHandle, MessagePipeHandle> handles = core.createMess
agePipe( | |
73 new MessagePipeHandle.CreateOptions()); | |
74 mReadHandle = handles.first; | |
75 mWriteHandle = handles.second; | |
76 mPendingActions = new ArrayList<Runnable>(); | |
77 asyncWait(); | |
78 } | |
79 | |
80 /** | |
81 * Asynchronously wait for the next command to arrive. This should only
be called on the | |
82 * executor thread. | |
83 */ | |
84 private void asyncWait() { | |
85 mWaiter.asyncWait(mReadHandle, Core.HandleSignals.READABLE, Core.DEA
DLINE_INFINITE, | |
86 this); | |
87 } | |
88 | |
89 /** | |
90 * @see Callback#onResult(int) | |
91 */ | |
92 @Override | |
93 public void onResult(int result) { | |
94 if (result == MojoResult.OK && readNotifyBufferMessage()) { | |
95 runNextAction(); | |
96 } else { | |
97 close(); | |
98 } | |
99 } | |
100 | |
101 /** | |
102 * @see Callback#onError(MojoException) | |
103 */ | |
104 @Override | |
105 public void onError(MojoException exception) { | |
106 close(); | |
107 } | |
108 | |
109 /** | |
110 * Close the handles. Should only be called on the executor thread. | |
111 */ | |
112 private void close() { | |
113 synchronized (mLock) { | |
114 mWriteHandle.close(); | |
115 mPendingActions.clear(); | |
116 } | |
117 mReadHandle.close(); | |
118 } | |
119 | |
120 /** | |
121 * Read the next message on |mReadHandle|, and return |true| if successf
ul, |false| | |
122 * otherwise. | |
123 */ | |
124 private boolean readNotifyBufferMessage() { | |
125 try { | |
126 ResultAnd<ReadMessageResult> readMessageResult = | |
127 mReadHandle.readMessage(NOTIFY_BUFFER, 0, MessagePipeHan
dle.ReadFlags.NONE); | |
128 if (readMessageResult.getMojoResult() == MojoResult.OK) { | |
129 asyncWait(); | |
130 return true; | |
131 } | |
132 } catch (MojoException e) { | |
133 // Will be closed by the fall back at the end of this method. | |
134 } | |
135 return false; | |
136 } | |
137 | |
138 /** | |
139 * Run the next action in the |mPendingActions| queue. | |
140 */ | |
141 private void runNextAction() { | |
142 Runnable toRun = null; | |
143 synchronized (mLock) { | |
144 toRun = mPendingActions.remove(0); | |
145 } | |
146 toRun.run(); | |
147 } | |
148 | |
149 /** | |
150 * Execute the given |command| in the executor thread. This can be calle
d on any thread. | |
151 * | |
152 * @see Executor#execute(Runnable) | |
153 */ | |
154 @Override | |
155 public void execute(Runnable command) { | |
156 // Accessing the write handle must be protected by the lock, because
it can be closed | |
157 // from the executor's thread. | |
158 synchronized (mLock) { | |
159 if (!mWriteHandle.isValid()) { | |
160 throw new IllegalStateException( | |
161 "Trying to execute an action on a closed executor.")
; | |
162 } | |
163 mPendingActions.add(command); | |
164 mWriteHandle.writeMessage(NOTIFY_BUFFER, null, MessagePipeHandle
.WriteFlags.NONE); | |
165 } | |
166 } | |
167 } | |
168 | |
169 /** | |
170 * Keep one executor per executor thread. | |
171 */ | |
172 private static final ThreadLocal<Executor> EXECUTORS = new ThreadLocal<Execu
tor>(); | |
173 | |
174 /** | |
175 * Returns an {@link Executor} that will run all of its actions in the curre
nt thread. | |
176 */ | |
177 public static Executor getExecutorForCurrentThread(Core core) { | |
178 Executor executor = EXECUTORS.get(); | |
179 if (executor == null) { | |
180 executor = new PipedExecutor(core); | |
181 EXECUTORS.set(executor); | |
182 } | |
183 return executor; | |
184 } | |
185 } | |
OLD | NEW |