Commit | Line | Data |
---|---|---|
951d134a | 1 | /******************************************************************************* |
61759503 | 2 | * Copyright (c) 2009, 2013 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 | |
11252342 AM |
39 | private final ExecutorService fExecutor = Executors.newFixedThreadPool(2); |
40 | private final String fExecutorName; | |
96b353c5 | 41 | |
11252342 AM |
42 | // The request queues |
43 | private final Queue<TmfEventThread> fHighPriorityTasks = new ArrayBlockingQueue<TmfEventThread>(100); | |
44 | private final Queue<TmfEventThread> fLowPriorityTasks = new ArrayBlockingQueue<TmfEventThread>(100); | |
96b353c5 | 45 | |
11252342 AM |
46 | // The tasks |
47 | private TmfEventThread fActiveTask; | |
96b353c5 | 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 | * | |
11252342 AM |
68 | * @param executor |
69 | * The executor service to use | |
9b749023 | 70 | */ |
96b353c5 | 71 | @Deprecated |
9b749023 | 72 | public TmfRequestExecutor(ExecutorService executor) { |
96b353c5 | 73 | this(); |
9b749023 | 74 | } |
54d55ced | 75 | |
96b353c5 FC |
76 | // ------------------------------------------------------------------------ |
77 | // Getters | |
78 | // ------------------------------------------------------------------------ | |
79 | ||
11252342 AM |
80 | /** |
81 | * @return the number of pending requests | |
82 | */ | |
96b353c5 | 83 | @Deprecated |
11252342 AM |
84 | public synchronized int getNbPendingRequests() { |
85 | return fHighPriorityTasks.size() + fLowPriorityTasks.size(); | |
86 | } | |
87 | ||
88 | /** | |
89 | * @return the shutdown state (i.e. if it is accepting new requests) | |
90 | */ | |
91 | public synchronized boolean isShutdown() { | |
92 | return fExecutor.isShutdown(); | |
93 | } | |
94 | ||
95 | /** | |
96 | * @return the termination state | |
97 | */ | |
98 | public synchronized boolean isTerminated() { | |
99 | return fExecutor.isTerminated(); | |
100 | } | |
9b749023 | 101 | |
96b353c5 FC |
102 | // ------------------------------------------------------------------------ |
103 | // Operations | |
104 | // ------------------------------------------------------------------------ | |
9b749023 | 105 | |
11252342 AM |
106 | @Override |
107 | public synchronized void execute(final Runnable command) { | |
96b353c5 FC |
108 | |
109 | // We are expecting MyEventThread:s | |
110 | if (!(command instanceof TmfEventThread)) { | |
111 | // TODO: Log an error | |
112 | return; | |
113 | } | |
114 | ||
115 | // Wrap the thread in a MyThread | |
116 | TmfEventThread thread = (TmfEventThread) command; | |
117 | TmfEventThread wrapper = new TmfEventThread(thread) { | |
475743b7 | 118 | @Override |
96b353c5 FC |
119 | public void run() { |
120 | try { | |
121 | command.run(); | |
122 | } finally { | |
123 | scheduleNext(); | |
124 | } | |
475743b7 | 125 | } |
96b353c5 FC |
126 | }; |
127 | ||
128 | // Add the thread to the appropriate queue | |
5419a136 AM |
129 | ExecutionType priority = thread.getExecType(); |
130 | (priority == ExecutionType.FOREGROUND ? fHighPriorityTasks : fLowPriorityTasks).offer(wrapper); | |
96b353c5 FC |
131 | |
132 | // Schedule or preempt as appropriate | |
133 | if (fActiveTask == null) { | |
134 | scheduleNext(); | |
5419a136 | 135 | } else if (priority == ExecutionType.FOREGROUND && priority != fActiveTask.getExecType()) { |
96b353c5 FC |
136 | fActiveTask.getThread().suspend(); |
137 | fSuspendedTask = fActiveTask; | |
138 | scheduleNext(); | |
139 | } | |
11252342 AM |
140 | } |
141 | ||
142 | /** | |
143 | * Executes the next pending request, if applicable. | |
144 | */ | |
145 | protected synchronized void scheduleNext() { | |
146 | if (!isShutdown()) { | |
147 | if ((fActiveTask = fHighPriorityTasks.poll()) != null) { | |
148 | fExecutor.execute(fActiveTask); | |
149 | } else if (fSuspendedTask != null) { | |
150 | fActiveTask = fSuspendedTask; | |
151 | fSuspendedTask = null; | |
152 | fActiveTask.getThread().resume(); | |
153 | } else if ((fActiveTask = fLowPriorityTasks.poll()) != null) { | |
154 | fExecutor.execute(fActiveTask); | |
155 | } | |
156 | } | |
157 | } | |
8c8bf09f | 158 | |
96b353c5 FC |
159 | /** |
160 | * Stops the executor | |
161 | */ | |
162 | public synchronized void stop() { | |
163 | if (fActiveTask != null) { | |
164 | fActiveTask.cancel(); | |
165 | } | |
166 | ||
167 | while ((fActiveTask = fHighPriorityTasks.poll()) != null) { | |
168 | fActiveTask.cancel(); | |
169 | } | |
170 | ||
171 | fExecutor.shutdown(); | |
172 | if (TmfCoreTracer.isComponentTraced()) { | |
173 | TmfCoreTracer.trace(fExecutor + " terminated"); //$NON-NLS-1$ | |
174 | } | |
175 | } | |
176 | ||
11252342 AM |
177 | // ------------------------------------------------------------------------ |
178 | // Object | |
179 | // ------------------------------------------------------------------------ | |
5c00c0b7 | 180 | |
11252342 | 181 | @Override |
3b38ea61 | 182 | @SuppressWarnings("nls") |
11252342 AM |
183 | public String toString() { |
184 | return "[TmfRequestExecutor(" + fExecutorName + ")]"; | |
185 | } | |
8c8bf09f ASL |
186 | |
187 | } |