1 /*******************************************************************************
2 * Copyright (c) 2009, 2014 Ericsson
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
10 * Francois Chouinard - Initial API and implementation
11 * Francois Chouinard - Added support for pre-emption
12 * Simon Delisle - Added scheduler for requests
13 *******************************************************************************/
15 package org
.eclipse
.linuxtools
.internal
.tmf
.core
.request
;
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
;
25 import org
.eclipse
.linuxtools
.internal
.tmf
.core
.TmfCoreTracer
;
26 import org
.eclipse
.linuxtools
.internal
.tmf
.core
.component
.TmfEventThread
;
27 import org
.eclipse
.linuxtools
.tmf
.core
.request
.ITmfEventRequest
.ExecutionType
;
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).
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.
37 * @author Francois Chouinard
38 * @author Simon Delisle
41 public class TmfRequestExecutor
implements Executor
{
43 // ------------------------------------------------------------------------
45 // ------------------------------------------------------------------------
47 private static final long REQUEST_TIME
= 100;
48 private static final int FOREGROUND_SLOT
= 4;
50 // ------------------------------------------------------------------------
52 // ------------------------------------------------------------------------
54 // The request executor
55 private final ExecutorService fExecutor
= Executors
.newCachedThreadPool();
56 private final String fExecutorName
;
59 private final Queue
<TmfEventThread
> fForegroundTasks
= new ArrayBlockingQueue
<>(10);
60 private final Queue
<TmfEventThread
> fBackgroundTasks
= new ArrayBlockingQueue
<>(10);
63 private TmfEventThread fActiveTask
;
66 private TimerTask fTimerTask
;
68 private int fForegroundCycle
= 0;
70 // ------------------------------------------------------------------------
72 // ------------------------------------------------------------------------
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$
85 // ------------------------------------------------------------------------
87 // ------------------------------------------------------------------------
90 * @return the shutdown state (i.e. if it is accepting new requests)
92 public boolean isShutdown() {
93 return fExecutor
.isShutdown();
97 * @return the termination state
99 public boolean isTerminated() {
100 return fExecutor
.isTerminated();
103 // ------------------------------------------------------------------------
105 // ------------------------------------------------------------------------
108 * Initialize the executor
111 if (fTimer
!= null) {
114 // Initialize the timer for the schedSwitch
115 fTimerTask
= new SchedSwitch();
116 fTimer
= new Timer(true);
117 fTimer
.schedule(fTimerTask
, 0, REQUEST_TIME
);
121 public synchronized void execute(final Runnable command
) {
123 // We are expecting MyEventThread:s
124 if (!(command
instanceof TmfEventThread
)) {
125 // TODO: Log an error
129 // Wrap the thread in a MyThread
130 TmfEventThread thread
= (TmfEventThread
) command
;
131 TmfEventThread wrapper
= new TmfEventThread(thread
) {
142 // Add the thread to the appropriate queue
143 ExecutionType priority
= thread
.getExecType();
145 if (priority
== ExecutionType
.FOREGROUND
) {
146 if (!fForegroundTasks
.offer(wrapper
)) {
150 if (!fBackgroundTasks
.offer(wrapper
)) {
157 * Timer task to trigger scheduleNext()
159 private class SchedSwitch
extends TimerTask
{
171 * Executes the next pending request, if applicable.
173 protected synchronized void scheduleNext() {
175 if (fActiveTask
== null) {
177 } else if (fActiveTask
.getExecType() == ExecutionType
.FOREGROUND
) {
178 if (fActiveTask
.getThread().isCompleted()) {
183 fActiveTask
.getThread().suspend();
184 if (!fForegroundTasks
.offer(fActiveTask
)) {
185 fActiveTask
.cancel();
192 } else if (fActiveTask
.getExecType() == ExecutionType
.BACKGROUND
) {
193 if (fActiveTask
.getThread().isCompleted()) {
198 fActiveTask
.getThread().suspend();
199 if (!fBackgroundTasks
.offer(fActiveTask
)) {
200 fActiveTask
.cancel();
213 public synchronized void stop() {
214 if (fTimerTask
!= null) {
218 if (fTimer
!= null) {
222 if (fActiveTask
!= null) {
223 fActiveTask
.cancel();
226 while ((fActiveTask
= fForegroundTasks
.poll()) != null) {
227 fActiveTask
.cancel();
229 while ((fActiveTask
= fBackgroundTasks
.poll()) != null) {
230 fActiveTask
.cancel();
233 fExecutor
.shutdown();
234 if (TmfCoreTracer
.isComponentTraced()) {
235 TmfCoreTracer
.trace(fExecutor
+ " terminated"); //$NON-NLS-1$
239 // ------------------------------------------------------------------------
241 // ------------------------------------------------------------------------
244 * Determine which type of request (foreground or background) we schedule
247 private void schedule() {
248 if (!fForegroundTasks
.isEmpty()) {
249 scheduleNextForeground();
251 scheduleNextBackground();
256 * Schedule the next foreground request
258 private void scheduleNextForeground() {
259 if (fForegroundCycle
< FOREGROUND_SLOT
|| fBackgroundTasks
.isEmpty()) {
261 fActiveTask
= fForegroundTasks
.poll();
262 executefActiveTask();
265 scheduleNextBackground();
270 * Schedule the next background request
272 private void scheduleNextBackground() {
273 fForegroundCycle
= 0;
274 if (!fBackgroundTasks
.isEmpty()) {
275 fActiveTask
= fBackgroundTasks
.poll();
276 executefActiveTask();
281 * Execute or resume the active task
283 private void executefActiveTask() {
284 if (fActiveTask
.getThread().isPaused()) {
285 fActiveTask
.getThread().resume();
287 fExecutor
.execute(fActiveTask
);
292 * Check if the scheduler has tasks
294 private boolean hasTasks() {
295 return !(fForegroundTasks
.isEmpty() && fBackgroundTasks
.isEmpty());
298 // ------------------------------------------------------------------------
300 // ------------------------------------------------------------------------
303 @SuppressWarnings("nls")
304 public String
toString() {
305 return "[TmfRequestExecutor(" + fExecutorName
+ ")]";