tmf: Make StateValueType and TimeRange exceptions into runtime ones
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.core / src / org / eclipse / linuxtools / tmf / core / statesystem / AbstractTmfStateProvider.java
CommitLineData
79e0a1df 1/*******************************************************************************
61759503 2 * Copyright (c) 2012, 2013 Ericsson
79e0a1df
AM
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 * Alexandre Montplaisir - Initial API and implementation
11 *******************************************************************************/
12
13package org.eclipse.linuxtools.tmf.core.statesystem;
14
15import java.util.concurrent.ArrayBlockingQueue;
16import java.util.concurrent.BlockingQueue;
17
6cfa0200 18import org.eclipse.linuxtools.tmf.core.ctfadaptor.CtfTmfEventFactory;
79e0a1df 19import org.eclipse.linuxtools.tmf.core.event.ITmfEvent;
1b9d3765 20import org.eclipse.linuxtools.tmf.core.event.TmfEvent;
79e0a1df 21import org.eclipse.linuxtools.tmf.core.exceptions.TimeRangeException;
3bd46eef 22import org.eclipse.linuxtools.tmf.core.timestamp.ITmfTimestamp;
1b9d3765 23import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimestamp;
79e0a1df
AM
24import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace;
25
26
27/**
28 * Instead of using IStateChangeInput directly, one can extend this class, which
29 * defines a lot of the common functions of the state change input plugin.
30 *
31 * It will handle the state-system-processing in a separate thread, which is
32 * normally not a bad idea for traces of some size.
33 *
34 * processEvent() is replaced with eventHandle(), so that all the multi-thread
35 * logic is abstracted away.
36 *
37 * @author Alexandre Montplaisir
38 * @since 2.0
39 */
0fe46f2a 40public abstract class AbstractTmfStateProvider implements ITmfStateProvider {
79e0a1df
AM
41
42 private static final int DEFAULT_EVENTS_QUEUE_SIZE = 10000;
43
79e0a1df 44 private final ITmfTrace trace;
79044a66
AM
45 private final Class<? extends ITmfEvent> eventType;
46 private final BlockingQueue<ITmfEvent> eventsQueue;
79e0a1df
AM
47 private final Thread eventHandlerThread;
48
49 private boolean ssAssigned;
79e0a1df
AM
50 private ITmfEvent currentEvent;
51
6f4e8ec0 52 /** State system in which to insert the state changes */
339d27b4 53 protected ITmfStateSystemBuilder ss = null;
6f4e8ec0 54
79e0a1df
AM
55 /**
56 * Instantiate a new state provider plugin.
57 *
58 * @param trace
59 * The LTTng 2.0 kernel trace directory
79044a66
AM
60 * @param eventType
61 * The specific class for the event type that will be used within
62 * the subclass
71f2da63
AM
63 * @param id
64 * Name given to this state change input. Only used internally.
79e0a1df 65 */
0fe46f2a 66 public AbstractTmfStateProvider(ITmfTrace trace,
71f2da63 67 Class<? extends ITmfEvent> eventType, String id) {
79e0a1df 68 this.trace = trace;
79044a66 69 this.eventType = eventType;
a4524c1b 70 eventsQueue = new ArrayBlockingQueue<>(DEFAULT_EVENTS_QUEUE_SIZE);
79044a66 71 ssAssigned = false;
71f2da63
AM
72
73 String id2 = (id == null ? "Unamed" : id); //$NON-NLS-1$
74 eventHandlerThread = new Thread(new EventProcessor(), id2 + " Event Handler"); //$NON-NLS-1$
79e0a1df
AM
75 }
76
77 @Override
78 public ITmfTrace getTrace() {
79 return trace;
80 }
81
82 @Override
83 public long getStartTime() {
faa38350 84 return trace.getStartTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
79e0a1df
AM
85 }
86
87 @Override
f1f86dfb 88 public void assignTargetStateSystem(ITmfStateSystemBuilder ssb) {
79e0a1df
AM
89 ss = ssb;
90 ssAssigned = true;
91 eventHandlerThread.start();
92 }
93
7e634be6
AM
94 @Override
95 public ITmfStateSystem getAssignedStateSystem() {
96 return ss;
97 }
98
79e0a1df
AM
99 @Override
100 public void dispose() {
101 /* Insert a null event in the queue to stop the event handler's thread. */
102 try {
6cfa0200 103 eventsQueue.put(CtfTmfEventFactory.getNullEvent());
79e0a1df
AM
104 eventHandlerThread.join();
105 } catch (InterruptedException e) {
106 e.printStackTrace();
107 }
108 ssAssigned = false;
109 ss = null;
110 }
111
112 @Override
79044a66
AM
113 public final Class<? extends ITmfEvent> getExpectedEventType() {
114 return eventType;
115 }
116
117 @Override
118 public final void processEvent(ITmfEvent event) {
79e0a1df
AM
119 /* Make sure the target state system has been assigned */
120 if (!ssAssigned) {
121 System.err.println("Cannot process event without a target state system"); //$NON-NLS-1$
122 return;
123 }
124
125 /* Insert the event we're received into the events queue */
126 ITmfEvent curEvent = event;
127 try {
128 eventsQueue.put(curEvent);
129 } catch (InterruptedException e) {
130 e.printStackTrace();
131 }
132 }
133
1b9d3765
AM
134 /**
135 * Block the caller until the events queue is empty.
136 */
137 public void waitForEmptyQueue() {
138 /*
139 * We will first insert a dummy event that is guaranteed to not modify
140 * the state. That way, when that event leaves the queue, we will know
141 * for sure that the state system processed the preceding real event.
142 */
ef8dd5af 143 TmfEvent ev = new EmptyEvent();
1b9d3765
AM
144
145 try {
146 eventsQueue.put(ev);
147 while (!eventsQueue.isEmpty()) {
6f04e06c 148 Thread.sleep(100);
1b9d3765
AM
149 }
150 } catch (InterruptedException e) {
151 e.printStackTrace();
152 }
153 }
154
ef8dd5af
AM
155 // ------------------------------------------------------------------------
156 // Inner classes
157 // ------------------------------------------------------------------------
158
159 /**
160 * Empty event that should be totally ignored by the event handler. It can
161 * by used for synchronisation purposes.
162 */
163 private class EmptyEvent extends TmfEvent {
164 public EmptyEvent() {
165 super(null, new TmfTimestamp(0), null, null, null, null);
166 }
167 }
168
79e0a1df
AM
169 /**
170 * This is the runner class for the second thread, which will take the
171 * events from the queue and pass them through the state system.
172 */
173 private class EventProcessor implements Runnable {
174
175 @Override
176 public void run() {
177 if (ss == null) {
178 System.err.println("Cannot run event manager without assigning a target state system first!"); //$NON-NLS-1$
179 return;
180 }
181 ITmfEvent event;
182
183 try {
184 event = eventsQueue.take();
185 while (event.getTimestamp().getValue() != -1) {
ef8dd5af
AM
186 if (event instanceof EmptyEvent) {
187 /* Synchronization event, should be ignored */
188 event = eventsQueue.take();
189 continue;
190 }
191
79e0a1df 192 currentEvent = event;
79044a66
AM
193
194 /* Make sure this is an event the sub-class can process */
1b9d3765 195 if (eventType.isInstance(event) && event.getType() != null) {
79044a66
AM
196 eventHandle(event);
197 }
79e0a1df
AM
198 event = eventsQueue.take();
199 }
200 /* We've received the last event, clean up */
201 closeStateSystem();
79e0a1df
AM
202 } catch (InterruptedException e) {
203 /* We've been interrupted abnormally */
204 System.out.println("Event handler interrupted!"); //$NON-NLS-1$
205 e.printStackTrace();
206 }
207 }
208
209 private void closeStateSystem() {
210 /* Close the History system, if there is one */
211 if (currentEvent == null) {
212 return;
213 }
214 try {
faa38350 215 ss.closeHistory(currentEvent.getTimestamp().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue());
79e0a1df
AM
216 } catch (TimeRangeException e) {
217 /*
218 * Since we're using currentEvent.getTimestamp, this shouldn't
219 * cause any problem
220 */
221 e.printStackTrace();
222 }
223 }
224 }
225
226 // ------------------------------------------------------------------------
227 // Abstract methods
228 // ------------------------------------------------------------------------
229
79e0a1df
AM
230 /**
231 * Handle the given event and send the appropriate state transitions into
232 * the the state system.
233 *
234 * This is basically the same thing as IStateChangeInput.processEvent(),
235 * except here processEvent() and eventHandle() are run in two different
236 * threads (and the AbstractStateChangeInput takes care of processEvent()
237 * already).
238 *
239 * @param event
240 * The event to process. If you need a specific event type, you
241 * should check for its instance right at the beginning.
242 */
243 protected abstract void eventHandle(ITmfEvent event);
244}
This page took 0.068873 seconds and 5 git commands to generate.