Commit | Line | Data |
---|---|---|
951d134a | 1 | /******************************************************************************* |
96b353c5 | 2 | * Copyright (c) 2009, 2010, 2012 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 |
951d134a FC |
12 | *******************************************************************************/ |
13 | ||
8fd82db5 | 14 | package org.eclipse.linuxtools.internal.tmf.core.request; |
8c8bf09f | 15 | |
96b353c5 FC |
16 | import java.util.Queue; |
17 | import java.util.concurrent.ArrayBlockingQueue; | |
8c8bf09f | 18 | import java.util.concurrent.Executor; |
54d55ced | 19 | import java.util.concurrent.ExecutorService; |
8c8bf09f | 20 | import java.util.concurrent.Executors; |
9b635e61 | 21 | |
5500a7f0 | 22 | import org.eclipse.linuxtools.internal.tmf.core.TmfCoreTracer; |
96b353c5 | 23 | import org.eclipse.linuxtools.internal.tmf.core.component.TmfEventThread; |
5419a136 | 24 | import org.eclipse.linuxtools.tmf.core.request.ITmfDataRequest.ExecutionType; |
8c8bf09f | 25 | |
951d134a | 26 | /** |
2fb2eb37 | 27 | * A simple, straightforward request executor. |
9b749023 | 28 | * |
8fd82db5 | 29 | * @author Francois Chouinard |
96b353c5 | 30 | * @version 1.1 |
951d134a | 31 | */ |
8c8bf09f ASL |
32 | public class TmfRequestExecutor implements Executor { |
33 | ||
96b353c5 FC |
34 | // ------------------------------------------------------------------------ |
35 | // Attributes | |
36 | // ------------------------------------------------------------------------ | |
37 | ||
38 | // The request executor | |
39 | private final ExecutorService fExecutor = Executors.newFixedThreadPool(2); | |
7a88aecf | 40 | private final String fExecutorName; |
96b353c5 FC |
41 | |
42 | // The request queues | |
43 | private final Queue<TmfEventThread> fHighPriorityTasks = new ArrayBlockingQueue<TmfEventThread>(100); | |
5419a136 | 44 | private final Queue<TmfEventThread> fLowPriorityTasks = new ArrayBlockingQueue<TmfEventThread>(100); |
96b353c5 FC |
45 | |
46 | // The tasks | |
47 | private TmfEventThread fActiveTask; | |
48 | private TmfEventThread fSuspendedTask; | |
fc6ccf6f | 49 | |
9b749023 AM |
50 | // ------------------------------------------------------------------------ |
51 | // Constructors | |
52 | // ------------------------------------------------------------------------ | |
53 | ||
54 | /** | |
55 | * Default constructor | |
56 | */ | |
57 | public TmfRequestExecutor() { | |
96b353c5 FC |
58 | String canonicalName = fExecutor.getClass().getCanonicalName(); |
59 | fExecutorName = canonicalName.substring(canonicalName.lastIndexOf('.') + 1); | |
60 | if (TmfCoreTracer.isComponentTraced()) { | |
61 | TmfCoreTracer.trace(fExecutor + " created"); //$NON-NLS-1$ | |
62 | } | |
9b749023 AM |
63 | } |
64 | ||
65 | /** | |
66 | * Standard constructor | |
67 | * | |
68 | * @param executor The executor service to use | |
69 | */ | |
96b353c5 | 70 | @Deprecated |
9b749023 | 71 | public TmfRequestExecutor(ExecutorService executor) { |
96b353c5 | 72 | this(); |
9b749023 | 73 | } |
54d55ced | 74 | |
96b353c5 FC |
75 | // ------------------------------------------------------------------------ |
76 | // Getters | |
77 | // ------------------------------------------------------------------------ | |
78 | ||
5c00c0b7 FC |
79 | /** |
80 | * @return the number of pending requests | |
81 | */ | |
96b353c5 | 82 | @Deprecated |
1087f2b9 | 83 | public synchronized int getNbPendingRequests() { |
5419a136 | 84 | return fHighPriorityTasks.size() + fLowPriorityTasks.size(); |
5c00c0b7 | 85 | } |
9b749023 | 86 | |
5c00c0b7 FC |
87 | /** |
88 | * @return the shutdown state (i.e. if it is accepting new requests) | |
89 | */ | |
db1ea19b | 90 | public synchronized boolean isShutdown() { |
5c00c0b7 FC |
91 | return fExecutor.isShutdown(); |
92 | } | |
9b749023 | 93 | |
5c00c0b7 FC |
94 | /** |
95 | * @return the termination state | |
96 | */ | |
1087f2b9 | 97 | public synchronized boolean isTerminated() { |
5c00c0b7 FC |
98 | return fExecutor.isTerminated(); |
99 | } | |
9b749023 | 100 | |
96b353c5 FC |
101 | // ------------------------------------------------------------------------ |
102 | // Operations | |
103 | // ------------------------------------------------------------------------ | |
9b749023 | 104 | |
2fb2eb37 FC |
105 | /* (non-Javadoc) |
106 | * @see java.util.concurrent.Executor#execute(java.lang.Runnable) | |
107 | */ | |
d4011df2 | 108 | @Override |
96b353c5 FC |
109 | public synchronized void execute(final Runnable command) { |
110 | ||
111 | // We are expecting MyEventThread:s | |
112 | if (!(command instanceof TmfEventThread)) { | |
113 | // TODO: Log an error | |
114 | return; | |
115 | } | |
116 | ||
117 | // Wrap the thread in a MyThread | |
118 | TmfEventThread thread = (TmfEventThread) command; | |
119 | TmfEventThread wrapper = new TmfEventThread(thread) { | |
475743b7 | 120 | @Override |
96b353c5 FC |
121 | public void run() { |
122 | try { | |
123 | command.run(); | |
124 | } finally { | |
125 | scheduleNext(); | |
126 | } | |
475743b7 | 127 | } |
96b353c5 FC |
128 | }; |
129 | ||
130 | // Add the thread to the appropriate queue | |
5419a136 AM |
131 | ExecutionType priority = thread.getExecType(); |
132 | (priority == ExecutionType.FOREGROUND ? fHighPriorityTasks : fLowPriorityTasks).offer(wrapper); | |
96b353c5 FC |
133 | |
134 | // Schedule or preempt as appropriate | |
135 | if (fActiveTask == null) { | |
136 | scheduleNext(); | |
5419a136 | 137 | } else if (priority == ExecutionType.FOREGROUND && priority != fActiveTask.getExecType()) { |
96b353c5 FC |
138 | fActiveTask.getThread().suspend(); |
139 | fSuspendedTask = fActiveTask; | |
140 | scheduleNext(); | |
141 | } | |
8c8bf09f ASL |
142 | } |
143 | ||
2fb2eb37 FC |
144 | /** |
145 | * Executes the next pending request, if applicable. | |
146 | */ | |
8c8bf09f | 147 | protected synchronized void scheduleNext() { |
96b353c5 FC |
148 | if (!isShutdown()) { |
149 | if ((fActiveTask = fHighPriorityTasks.poll()) != null) { | |
150 | fExecutor.execute(fActiveTask); | |
151 | } else if (fSuspendedTask != null) { | |
152 | fActiveTask = fSuspendedTask; | |
153 | fSuspendedTask = null; | |
154 | fActiveTask.getThread().resume(); | |
5419a136 | 155 | } else if ((fActiveTask = fLowPriorityTasks.poll()) != null) { |
96b353c5 FC |
156 | fExecutor.execute(fActiveTask); |
157 | } | |
158 | } | |
8c8bf09f ASL |
159 | } |
160 | ||
96b353c5 FC |
161 | /** |
162 | * Stops the executor | |
163 | */ | |
164 | public synchronized void stop() { | |
165 | if (fActiveTask != null) { | |
166 | fActiveTask.cancel(); | |
167 | } | |
168 | ||
169 | while ((fActiveTask = fHighPriorityTasks.poll()) != null) { | |
170 | fActiveTask.cancel(); | |
171 | } | |
172 | ||
173 | fExecutor.shutdown(); | |
174 | if (TmfCoreTracer.isComponentTraced()) { | |
175 | TmfCoreTracer.trace(fExecutor + " terminated"); //$NON-NLS-1$ | |
176 | } | |
177 | } | |
178 | ||
5c00c0b7 FC |
179 | // ------------------------------------------------------------------------ |
180 | // Object | |
181 | // ------------------------------------------------------------------------ | |
182 | ||
183 | @Override | |
3b38ea61 | 184 | @SuppressWarnings("nls") |
5c00c0b7 | 185 | public String toString() { |
7a88aecf | 186 | return "[TmfRequestExecutor(" + fExecutorName + ")]"; |
8c8bf09f ASL |
187 | } |
188 | ||
189 | } |