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