tmf : Use of Activator.logError() instead of System.err.println()
[deliverable/tracecompass.git] / tmf / org.eclipse.tracecompass.tmf.core / src / org / eclipse / tracecompass / tmf / core / statesystem / AbstractTmfStateProvider.java
CommitLineData
79e0a1df 1/*******************************************************************************
ed902a2b 2 * Copyright (c) 2012, 2015 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
2bdf0193 13package org.eclipse.tracecompass.tmf.core.statesystem;
79e0a1df 14
e2bcc8a5
AM
15import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
16
e2bcc8a5 17import org.eclipse.jdt.annotation.NonNull;
d0c7e4ba 18import org.eclipse.jdt.annotation.Nullable;
423cf6a4 19import org.eclipse.tracecompass.common.core.collect.BufferedBlockingQueue;
1ff5d16c 20import org.eclipse.tracecompass.internal.tmf.core.Activator;
e894a508
AM
21import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
22import org.eclipse.tracecompass.statesystem.core.ITmfStateSystemBuilder;
2bdf0193
AM
23import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
24import org.eclipse.tracecompass.tmf.core.event.TmfEvent;
25import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp;
0c7471fb 26import org.eclipse.tracecompass.tmf.core.trace.ITmfContext;
2bdf0193 27import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
79e0a1df 28
79e0a1df
AM
29/**
30 * Instead of using IStateChangeInput directly, one can extend this class, which
31 * defines a lot of the common functions of the state change input plugin.
32 *
33 * It will handle the state-system-processing in a separate thread, which is
34 * normally not a bad idea for traces of some size.
35 *
36 * processEvent() is replaced with eventHandle(), so that all the multi-thread
37 * logic is abstracted away.
38 *
39 * @author Alexandre Montplaisir
79e0a1df 40 */
0fe46f2a 41public abstract class AbstractTmfStateProvider implements ITmfStateProvider {
79e0a1df 42
423cf6a4
MK
43 private static final int DEFAULT_EVENTS_QUEUE_SIZE = 127;
44 private static final int DEFAULT_EVENTS_CHUNK_SIZE = 127;
79e0a1df 45
086cd39c 46 private final ITmfTrace fTrace;
423cf6a4 47 private final BufferedBlockingQueue<ITmfEvent> fEventsQueue;
086cd39c 48 private final Thread fEventHandlerThread;
79e0a1df 49
086cd39c 50 private boolean fStateSystemAssigned;
79e0a1df 51
6f4e8ec0 52 /** State system in which to insert the state changes */
086cd39c 53 private @Nullable ITmfStateSystemBuilder fSS = 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
71f2da63
AM
60 * @param id
61 * Name given to this state change input. Only used internally.
79e0a1df 62 */
e2bcc8a5 63 public AbstractTmfStateProvider(ITmfTrace trace, String id) {
086cd39c 64 fTrace = trace;
423cf6a4 65 fEventsQueue = new BufferedBlockingQueue<>(DEFAULT_EVENTS_QUEUE_SIZE, DEFAULT_EVENTS_CHUNK_SIZE);
086cd39c 66 fStateSystemAssigned = false;
71f2da63 67
086cd39c 68 fEventHandlerThread = new Thread(new EventProcessor(), id + " Event Handler"); //$NON-NLS-1$
d0c7e4ba
AM
69 }
70
71 /**
72 * Get the state system builder of this provider (to insert states in).
73 *
74 * @return The state system object to be filled
75 */
76 protected @Nullable ITmfStateSystemBuilder getStateSystemBuilder() {
086cd39c 77 return fSS;
79e0a1df
AM
78 }
79
80 @Override
81 public ITmfTrace getTrace() {
086cd39c 82 return fTrace;
79e0a1df
AM
83 }
84
85 @Override
86 public long getStartTime() {
086cd39c 87 return fTrace.getStartTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
79e0a1df
AM
88 }
89
90 @Override
f1f86dfb 91 public void assignTargetStateSystem(ITmfStateSystemBuilder ssb) {
086cd39c
MK
92 fSS = ssb;
93 fStateSystemAssigned = true;
94 fEventHandlerThread.start();
79e0a1df
AM
95 }
96
7e634be6 97 @Override
d0c7e4ba 98 public @Nullable ITmfStateSystem getAssignedStateSystem() {
086cd39c 99 return fSS;
7e634be6
AM
100 }
101
79e0a1df
AM
102 @Override
103 public void dispose() {
104 /* Insert a null event in the queue to stop the event handler's thread. */
105 try {
086cd39c 106 fEventsQueue.put(END_EVENT);
423cf6a4 107 fEventsQueue.flushInputBuffer();
086cd39c 108 fEventHandlerThread.join();
79e0a1df
AM
109 } catch (InterruptedException e) {
110 e.printStackTrace();
111 }
086cd39c
MK
112 fStateSystemAssigned = false;
113 fSS = null;
79e0a1df
AM
114 }
115
79044a66
AM
116 @Override
117 public final void processEvent(ITmfEvent event) {
79e0a1df 118 /* Make sure the target state system has been assigned */
086cd39c 119 if (!fStateSystemAssigned) {
1ff5d16c 120 Activator.logError("Cannot process event without a target state system"); //$NON-NLS-1$
79e0a1df
AM
121 return;
122 }
123
124 /* Insert the event we're received into the events queue */
125 ITmfEvent curEvent = event;
423cf6a4 126 fEventsQueue.put(curEvent);
79e0a1df
AM
127 }
128
1b9d3765
AM
129 /**
130 * Block the caller until the events queue is empty.
131 */
132 public void waitForEmptyQueue() {
133 /*
134 * We will first insert a dummy event that is guaranteed to not modify
135 * the state. That way, when that event leaves the queue, we will know
136 * for sure that the state system processed the preceding real event.
137 */
1b9d3765 138 try {
086cd39c 139 fEventsQueue.put(EMPTY_QUEUE_EVENT);
423cf6a4 140 fEventsQueue.flushInputBuffer();
086cd39c 141 while (!fEventsQueue.isEmpty()) {
6f04e06c 142 Thread.sleep(100);
1b9d3765
AM
143 }
144 } catch (InterruptedException e) {
145 e.printStackTrace();
146 }
147 }
148
ef8dd5af 149 // ------------------------------------------------------------------------
aca5f650 150 // Special event types
ef8dd5af
AM
151 // ------------------------------------------------------------------------
152
aca5f650 153 /** Fake event indicating the build is over, and the provider should close */
0c7471fb
AM
154 private static class EndEvent extends TmfEvent {
155 public EndEvent() {
e1de2fd4 156 super(null, ITmfContext.UNKNOWN_RANK, null, null, null);
0c7471fb
AM
157 }
158 }
159
aca5f650 160 /** Fake event indicating we want to clear the current queue */
0c7471fb
AM
161 private static class EmptyQueueEvent extends TmfEvent {
162 public EmptyQueueEvent() {
e1de2fd4 163 super(null, ITmfContext.UNKNOWN_RANK, null, null, null);
0c7471fb
AM
164 }
165 }
aca5f650
MK
166
167 private static final EndEvent END_EVENT = new EndEvent();
168 private static final EmptyQueueEvent EMPTY_QUEUE_EVENT = new EmptyQueueEvent();
169
170 // ------------------------------------------------------------------------
171 // Inner classes
172 // ------------------------------------------------------------------------
ef8dd5af 173
79e0a1df
AM
174 /**
175 * This is the runner class for the second thread, which will take the
176 * events from the queue and pass them through the state system.
177 */
178 private class EventProcessor implements Runnable {
179
d0c7e4ba 180 private @Nullable ITmfEvent currentEvent;
e8b7cc14 181
79e0a1df
AM
182 @Override
183 public void run() {
086cd39c 184 if (!fStateSystemAssigned) {
1ff5d16c 185 Activator.logError("Cannot run event manager without assigning a target state system first!"); //$NON-NLS-1$
79e0a1df
AM
186 return;
187 }
79e0a1df 188
423cf6a4
MK
189
190 /*
191 * We never insert null in the queue. Cannot be checked at
192 * compile-time until Java 8 annotations...
193 */
194 @NonNull ITmfEvent event = checkNotNull(fEventsQueue.take());
195 /* This is a singleton, we want to do != instead of !x.equals */
196 while (event != END_EVENT) {
197 if (event == EMPTY_QUEUE_EVENT) {
198 /* Synchronization event, should be ignored */
e2bcc8a5 199 event = checkNotNull(fEventsQueue.take());
423cf6a4 200 continue;
79e0a1df 201 }
423cf6a4
MK
202 currentEvent = event;
203 eventHandle(event);
204 event = checkNotNull(fEventsQueue.take());
79e0a1df 205 }
423cf6a4
MK
206 /* We've received the last event, clean up */
207 closeStateSystem();
79e0a1df
AM
208 }
209
210 private void closeStateSystem() {
d0c7e4ba
AM
211 ITmfEvent event = currentEvent;
212 final long endTime = (event == null) ? 0 :
213 event.getTimestamp().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
214
086cd39c
MK
215 if (fSS != null) {
216 fSS.closeHistory(endTime);
d0c7e4ba 217 }
79e0a1df
AM
218 }
219 }
220
221 // ------------------------------------------------------------------------
222 // Abstract methods
223 // ------------------------------------------------------------------------
224
79e0a1df
AM
225 /**
226 * Handle the given event and send the appropriate state transitions into
227 * the the state system.
228 *
229 * This is basically the same thing as IStateChangeInput.processEvent(),
230 * except here processEvent() and eventHandle() are run in two different
231 * threads (and the AbstractStateChangeInput takes care of processEvent()
232 * already).
233 *
234 * @param event
235 * The event to process. If you need a specific event type, you
236 * should check for its instance right at the beginning.
237 */
238 protected abstract void eventHandle(ITmfEvent event);
086cd39c 239
79e0a1df 240}
This page took 0.0986 seconds and 5 git commands to generate.