Commit | Line | Data |
---|---|---|
951d134a | 1 | /******************************************************************************* |
be4a197a | 2 | * Copyright (c) 2009, 2014 Ericsson |
9b749023 | 3 | * |
951d134a FC |
4 | * All rights reserved. This program and the accompanying materials are |
5 | * made available under the terms of the Eclipse Public License v1.0 which | |
6 | * accompanies this distribution, and is available at | |
7 | * http://www.eclipse.org/legal/epl-v10.html | |
9b749023 | 8 | * |
951d134a FC |
9 | * Contributors: |
10 | * Francois Chouinard - Initial API and implementation | |
96b353c5 | 11 | * Francois Chouinard - Added support for pre-emption |
306586b1 | 12 | * Simon Delisle - Added scheduler for requests |
951d134a FC |
13 | *******************************************************************************/ |
14 | ||
2bdf0193 | 15 | package org.eclipse.tracecompass.internal.tmf.core.request; |
8c8bf09f | 16 | |
b30ff01f MAL |
17 | import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull; |
18 | ||
96b353c5 | 19 | import java.util.Queue; |
306586b1 SD |
20 | import java.util.Timer; |
21 | import java.util.TimerTask; | |
96b353c5 | 22 | import java.util.concurrent.ArrayBlockingQueue; |
8c8bf09f | 23 | import java.util.concurrent.Executor; |
54d55ced | 24 | import java.util.concurrent.ExecutorService; |
8c8bf09f | 25 | import java.util.concurrent.Executors; |
9b635e61 | 26 | |
2bdf0193 AM |
27 | import org.eclipse.tracecompass.internal.tmf.core.TmfCoreTracer; |
28 | import org.eclipse.tracecompass.internal.tmf.core.component.TmfEventThread; | |
29 | import org.eclipse.tracecompass.tmf.core.request.ITmfEventRequest.ExecutionType; | |
8c8bf09f | 30 | |
951d134a | 31 | /** |
306586b1 SD |
32 | * The request scheduler works with 5 slots with a specific time. It has 4 slots |
33 | * for foreground requests and 1 slot for background requests, and it passes | |
34 | * through all the slots (foreground first and background after). | |
35 | * | |
36 | * Example: if we have one foreground and one background request, the foreground | |
37 | * request will be executed four times more often than the background request. | |
9b749023 | 38 | * |
8fd82db5 | 39 | * @author Francois Chouinard |
306586b1 | 40 | * @author Simon Delisle |
96b353c5 | 41 | * @version 1.1 |
951d134a | 42 | */ |
8c8bf09f ASL |
43 | public class TmfRequestExecutor implements Executor { |
44 | ||
306586b1 SD |
45 | // ------------------------------------------------------------------------ |
46 | // Constants | |
47 | // ------------------------------------------------------------------------ | |
48 | ||
49 | private static final long REQUEST_TIME = 100; | |
50 | private static final int FOREGROUND_SLOT = 4; | |
51 | ||
96b353c5 FC |
52 | // ------------------------------------------------------------------------ |
53 | // Attributes | |
54 | // ------------------------------------------------------------------------ | |
55 | ||
56 | // The request executor | |
306586b1 | 57 | private final ExecutorService fExecutor = Executors.newCachedThreadPool(); |
11252342 | 58 | private final String fExecutorName; |
96b353c5 | 59 | |
11252342 | 60 | // The request queues |
e1627b18 AM |
61 | private final Queue<TmfEventThread> fForegroundTasks = new ArrayBlockingQueue<>(10); |
62 | private final Queue<TmfEventThread> fBackgroundTasks = new ArrayBlockingQueue<>(10); | |
96b353c5 | 63 | |
11252342 AM |
64 | // The tasks |
65 | private TmfEventThread fActiveTask; | |
306586b1 | 66 | |
661b21a1 | 67 | private Timer fTimer; |
306586b1 SD |
68 | private TimerTask fTimerTask; |
69 | ||
70 | private int fForegroundCycle = 0; | |
fc6ccf6f | 71 | |
9b749023 AM |
72 | // ------------------------------------------------------------------------ |
73 | // Constructors | |
74 | // ------------------------------------------------------------------------ | |
75 | ||
76 | /** | |
77 | * Default constructor | |
78 | */ | |
79 | public TmfRequestExecutor() { | |
b30ff01f MAL |
80 | // We know the canonical name is not null because we use ExecutorService only |
81 | String canonicalName = checkNotNull(fExecutor.getClass().getCanonicalName()); | |
96b353c5 FC |
82 | fExecutorName = canonicalName.substring(canonicalName.lastIndexOf('.') + 1); |
83 | if (TmfCoreTracer.isComponentTraced()) { | |
84 | TmfCoreTracer.trace(fExecutor + " created"); //$NON-NLS-1$ | |
85 | } | |
9b749023 AM |
86 | } |
87 | ||
96b353c5 FC |
88 | // ------------------------------------------------------------------------ |
89 | // Getters | |
90 | // ------------------------------------------------------------------------ | |
91 | ||
11252342 AM |
92 | /** |
93 | * @return the shutdown state (i.e. if it is accepting new requests) | |
94 | */ | |
e1627b18 | 95 | public boolean isShutdown() { |
11252342 AM |
96 | return fExecutor.isShutdown(); |
97 | } | |
98 | ||
99 | /** | |
100 | * @return the termination state | |
101 | */ | |
e1627b18 | 102 | public boolean isTerminated() { |
11252342 AM |
103 | return fExecutor.isTerminated(); |
104 | } | |
9b749023 | 105 | |
96b353c5 FC |
106 | // ------------------------------------------------------------------------ |
107 | // Operations | |
108 | // ------------------------------------------------------------------------ | |
9b749023 | 109 | |
661b21a1 PT |
110 | /** |
111 | * Initialize the executor | |
112 | */ | |
113 | public void init() { | |
114 | if (fTimer != null) { | |
115 | return; | |
116 | } | |
117 | // Initialize the timer for the schedSwitch | |
118 | fTimerTask = new SchedSwitch(); | |
119 | fTimer = new Timer(true); | |
120 | fTimer.schedule(fTimerTask, 0, REQUEST_TIME); | |
121 | } | |
122 | ||
11252342 AM |
123 | @Override |
124 | public synchronized void execute(final Runnable command) { | |
96b353c5 FC |
125 | |
126 | // We are expecting MyEventThread:s | |
127 | if (!(command instanceof TmfEventThread)) { | |
128 | // TODO: Log an error | |
129 | return; | |
130 | } | |
131 | ||
132 | // Wrap the thread in a MyThread | |
133 | TmfEventThread thread = (TmfEventThread) command; | |
134 | TmfEventThread wrapper = new TmfEventThread(thread) { | |
475743b7 | 135 | @Override |
96b353c5 FC |
136 | public void run() { |
137 | try { | |
138 | command.run(); | |
139 | } finally { | |
140 | scheduleNext(); | |
141 | } | |
475743b7 | 142 | } |
96b353c5 FC |
143 | }; |
144 | ||
145 | // Add the thread to the appropriate queue | |
5419a136 | 146 | ExecutionType priority = thread.getExecType(); |
96b353c5 | 147 | |
306586b1 | 148 | if (priority == ExecutionType.FOREGROUND) { |
e1627b18 AM |
149 | if (!fForegroundTasks.offer(wrapper)) { |
150 | wrapper.cancel(); | |
151 | } | |
306586b1 | 152 | } else { |
e1627b18 AM |
153 | if (!fBackgroundTasks.offer(wrapper)) { |
154 | wrapper.cancel(); | |
155 | } | |
306586b1 SD |
156 | } |
157 | } | |
158 | ||
159 | /** | |
160 | * Timer task to trigger scheduleNext() | |
161 | */ | |
162 | private class SchedSwitch extends TimerTask { | |
163 | ||
164 | SchedSwitch() { | |
165 | } | |
166 | ||
167 | @Override | |
168 | public void run() { | |
96b353c5 FC |
169 | scheduleNext(); |
170 | } | |
11252342 AM |
171 | } |
172 | ||
173 | /** | |
174 | * Executes the next pending request, if applicable. | |
175 | */ | |
176 | protected synchronized void scheduleNext() { | |
177 | if (!isShutdown()) { | |
306586b1 SD |
178 | if (fActiveTask == null) { |
179 | schedule(); | |
180 | } else if (fActiveTask.getExecType() == ExecutionType.FOREGROUND) { | |
181 | if (fActiveTask.getThread().isCompleted()) { | |
6dcda2b7 | 182 | fActiveTask = null; |
306586b1 SD |
183 | schedule(); |
184 | } else { | |
185 | if (hasTasks()) { | |
186 | fActiveTask.getThread().suspend(); | |
e1627b18 AM |
187 | if (!fForegroundTasks.offer(fActiveTask)) { |
188 | fActiveTask.cancel(); | |
189 | fActiveTask = null; | |
190 | } | |
306586b1 SD |
191 | schedule(); |
192 | } | |
193 | } | |
194 | ||
195 | } else if (fActiveTask.getExecType() == ExecutionType.BACKGROUND) { | |
196 | if (fActiveTask.getThread().isCompleted()) { | |
6dcda2b7 | 197 | fActiveTask = null; |
306586b1 SD |
198 | schedule(); |
199 | } else { | |
200 | if (hasTasks()) { | |
201 | fActiveTask.getThread().suspend(); | |
e1627b18 AM |
202 | if (!fBackgroundTasks.offer(fActiveTask)) { |
203 | fActiveTask.cancel(); | |
204 | fActiveTask = null; | |
205 | } | |
306586b1 SD |
206 | schedule(); |
207 | } | |
208 | } | |
11252342 AM |
209 | } |
210 | } | |
211 | } | |
8c8bf09f | 212 | |
96b353c5 FC |
213 | /** |
214 | * Stops the executor | |
215 | */ | |
216 | public synchronized void stop() { | |
661b21a1 PT |
217 | if (fTimerTask != null) { |
218 | fTimerTask.cancel(); | |
219 | } | |
220 | ||
221 | if (fTimer != null) { | |
222 | fTimer.cancel(); | |
223 | } | |
b67f3f7c | 224 | |
96b353c5 FC |
225 | if (fActiveTask != null) { |
226 | fActiveTask.cancel(); | |
227 | } | |
228 | ||
306586b1 SD |
229 | while ((fActiveTask = fForegroundTasks.poll()) != null) { |
230 | fActiveTask.cancel(); | |
231 | } | |
232 | while ((fActiveTask = fBackgroundTasks.poll()) != null) { | |
96b353c5 FC |
233 | fActiveTask.cancel(); |
234 | } | |
235 | ||
236 | fExecutor.shutdown(); | |
237 | if (TmfCoreTracer.isComponentTraced()) { | |
238 | TmfCoreTracer.trace(fExecutor + " terminated"); //$NON-NLS-1$ | |
239 | } | |
240 | } | |
241 | ||
306586b1 SD |
242 | // ------------------------------------------------------------------------ |
243 | // Helper methods | |
244 | // ------------------------------------------------------------------------ | |
245 | ||
246 | /** | |
247 | * Determine which type of request (foreground or background) we schedule | |
248 | * next | |
249 | */ | |
250 | private void schedule() { | |
251 | if (!fForegroundTasks.isEmpty()) { | |
252 | scheduleNextForeground(); | |
253 | } else { | |
254 | scheduleNextBackground(); | |
255 | } | |
256 | } | |
257 | ||
258 | /** | |
259 | * Schedule the next foreground request | |
260 | */ | |
261 | private void scheduleNextForeground() { | |
262 | if (fForegroundCycle < FOREGROUND_SLOT || fBackgroundTasks.isEmpty()) { | |
263 | ++fForegroundCycle; | |
264 | fActiveTask = fForegroundTasks.poll(); | |
265 | executefActiveTask(); | |
266 | } else { | |
267 | fActiveTask = null; | |
268 | scheduleNextBackground(); | |
269 | } | |
270 | } | |
271 | ||
272 | /** | |
273 | * Schedule the next background request | |
274 | */ | |
275 | private void scheduleNextBackground() { | |
276 | fForegroundCycle = 0; | |
277 | if (!fBackgroundTasks.isEmpty()) { | |
278 | fActiveTask = fBackgroundTasks.poll(); | |
279 | executefActiveTask(); | |
280 | } | |
281 | } | |
282 | ||
283 | /** | |
284 | * Execute or resume the active task | |
285 | */ | |
286 | private void executefActiveTask() { | |
287 | if (fActiveTask.getThread().isPaused()) { | |
288 | fActiveTask.getThread().resume(); | |
289 | } else { | |
290 | fExecutor.execute(fActiveTask); | |
291 | } | |
292 | } | |
293 | ||
294 | /** | |
295 | * Check if the scheduler has tasks | |
296 | */ | |
297 | private boolean hasTasks() { | |
298 | return !(fForegroundTasks.isEmpty() && fBackgroundTasks.isEmpty()); | |
299 | } | |
300 | ||
11252342 AM |
301 | // ------------------------------------------------------------------------ |
302 | // Object | |
303 | // ------------------------------------------------------------------------ | |
5c00c0b7 | 304 | |
11252342 | 305 | @Override |
3b38ea61 | 306 | @SuppressWarnings("nls") |
11252342 AM |
307 | public String toString() { |
308 | return "[TmfRequestExecutor(" + fExecutorName + ")]"; | |
309 | } | |
8c8bf09f ASL |
310 | |
311 | } |