lttng: Don't update the status of dead processes
[deliverable/tracecompass.git] / org.eclipse.linuxtools.lttng2.kernel.core / src / org / eclipse / linuxtools / internal / lttng2 / kernel / core / stateprovider / CtfKernelHandler.java
1 /*******************************************************************************
2 * Copyright (c) 2012 Ericsson
3 * Copyright (c) 2010, 2011 École Polytechnique de Montréal
4 * Copyright (c) 2010, 2011 Alexandre Montplaisir <alexandre.montplaisir@gmail.com>
5 *
6 * All rights reserved. This program and the accompanying materials are
7 * made available under the terms of the Eclipse Public License v1.0 which
8 * accompanies this distribution, and is available at
9 * http://www.eclipse.org/legal/epl-v10.html
10 *
11 *******************************************************************************/
12
13 package org.eclipse.linuxtools.internal.lttng2.kernel.core.stateprovider;
14
15 import java.util.HashMap;
16 import java.util.Vector;
17 import java.util.concurrent.BlockingQueue;
18
19 import org.eclipse.linuxtools.lttng2.kernel.core.trace.Attributes;
20 import org.eclipse.linuxtools.lttng2.kernel.core.trace.LttngStrings;
21 import org.eclipse.linuxtools.tmf.core.ctfadaptor.CtfTmfEvent;
22 import org.eclipse.linuxtools.tmf.core.event.ITmfEventField;
23 import org.eclipse.linuxtools.tmf.core.exceptions.AttributeNotFoundException;
24 import org.eclipse.linuxtools.tmf.core.exceptions.StateValueTypeException;
25 import org.eclipse.linuxtools.tmf.core.exceptions.TimeRangeException;
26 import org.eclipse.linuxtools.tmf.core.statesystem.IStateSystemBuilder;
27 import org.eclipse.linuxtools.tmf.core.statevalue.ITmfStateValue;
28 import org.eclipse.linuxtools.tmf.core.statevalue.TmfStateValue;
29
30 /**
31 * This is the reference "state provider" for LTTng 2.0 kernel traces.
32 *
33 * @author alexmont
34 *
35 */
36 class CtfKernelHandler implements Runnable {
37
38 private final BlockingQueue<CtfTmfEvent> inQueue;
39 private IStateSystemBuilder ss;
40
41 private CtfTmfEvent currentEvent;
42
43 /*
44 * We can keep handles to some Attribute Nodes so these don't need to be
45 * re-found (re-hashed Strings etc.) every new event
46 */
47 Vector<Integer> currentCPUNodes;
48 Vector<Integer> currentThreadNodes;
49
50 /* Event names HashMap. TODO: This can be discarded once we move to Java 7 */
51 private final HashMap<String, Integer> knownEventNames;
52
53 /* Common locations in the attribute tree */
54 private int cpusNode = -1;
55 private int threadsNode = -1;
56 private int irqsNode = -1;
57 private int softIrqsNode = -1;
58
59 CtfKernelHandler(BlockingQueue<CtfTmfEvent> eventsQueue) {
60 assert (eventsQueue != null);
61 this.inQueue = eventsQueue;
62 currentCPUNodes = new Vector<Integer>();
63 currentThreadNodes = new Vector<Integer>();
64
65 knownEventNames = fillEventNames();
66 }
67
68 void assignStateSystem(IStateSystemBuilder targetSS) {
69 this.ss = targetSS;
70 }
71
72 @Override
73 public void run() {
74 if (ss == null) {
75 System.err.println("Cannot run event manager without assigning a target state system first!"); //$NON-NLS-1$
76 return;
77 }
78 CtfTmfEvent event;
79 setupCommonLocations();
80
81 try {
82 event = inQueue.take();
83 while (event.getTimestampValue() != -1) {
84 processEvent(event);
85 event = inQueue.take();
86 }
87 /* We've received the last event, clean up */
88 closeStateSystem();
89 return;
90 } catch (InterruptedException e) {
91 /* We've been interrupted abnormally */
92 System.out.println("Event handler interrupted!"); //$NON-NLS-1$
93 e.printStackTrace();
94 }
95 }
96
97 private void closeStateSystem() {
98 /* Close the History system, if there is one */
99 try {
100 ss.closeHistory(currentEvent.getTimestamp().getValue());
101 } catch (TimeRangeException e) {
102 /*
103 * Since we're using currentEvent.getTimestamp, this shouldn't
104 * cause any problem
105 */
106 e.printStackTrace();
107 }
108 }
109
110 private void processEvent(CtfTmfEvent event) {
111 currentEvent = event;
112 ITmfEventField content = event.getContent();
113 String eventName = event.getEventName();
114
115 long ts = event.getTimestamp().getValue();
116 int quark;
117 ITmfStateValue value;
118 Integer eventCpu = event.getCPU();
119 Integer currentCPUNode, currentThreadNode, tidNode;
120
121 /* Adjust the current nodes Vectors if we see a new CPU in an event */
122 if (eventCpu >= currentCPUNodes.size()) {
123 /* We need to add this node to the vector */
124 for (Integer i = currentCPUNodes.size(); i < eventCpu + 1; i++) {
125 quark = ss.getQuarkRelativeAndAdd(cpusNode, i.toString());
126 currentCPUNodes.add(quark);
127
128 quark = ss.getQuarkRelativeAndAdd(threadsNode, Attributes.UNKNOWN);
129 currentThreadNodes.add(quark);
130 }
131 }
132
133 currentCPUNode = currentCPUNodes.get(eventCpu);
134 currentThreadNode = currentThreadNodes.get(eventCpu);
135 assert (currentCPUNode != null);
136 assert (currentThreadNode != null);
137
138 try {
139 /*
140 * Feed event to the history system if it's known to cause a state
141 * transition.
142 */
143 switch (getEventIndex(eventName)) {
144
145 case 1: // "exit_syscall":
146 /* Fields: int64 ret */
147 {
148 /* Clear the current system call on the process */
149 quark = ss.getQuarkRelativeAndAdd(currentThreadNode, Attributes.SYSTEM_CALL);
150 value = TmfStateValue.nullValue();
151 ss.modifyAttribute(ts, value, quark);
152
153 /* Put the process' status back to user mode */
154 quark = ss.getQuarkRelativeAndAdd(currentThreadNode, Attributes.STATUS);
155 value = TmfStateValue.newValueInt(Attributes.STATUS_RUN_USERMODE);
156 ss.modifyAttribute(ts, value, quark);
157 }
158 break;
159
160 case 2: // "irq_handler_entry":
161 /* Fields: int32 irq, string name */
162 {
163 Integer irqId = ((Long) content.getField(LttngStrings.IRQ).getValue()).intValue();
164
165 /* Mark this IRQ as active in the resource tree.
166 * The state value = the CPU on which this IRQ is sitting */
167 quark = ss.getQuarkRelativeAndAdd(irqsNode, irqId.toString());
168 value = TmfStateValue.newValueInt(event.getCPU());
169 ss.modifyAttribute(ts, value, quark);
170
171 /* Change the status of the running process to interrupted */
172 quark = ss.getQuarkRelativeAndAdd(currentThreadNode, Attributes.STATUS);
173 value = TmfStateValue.newValueInt(Attributes.STATUS_INTERRUPTED);
174 ss.modifyAttribute(ts, value, quark);
175 }
176 break;
177
178 case 3: // "irq_handler_exit":
179 /* Fields: int32 irq, int32 ret */
180 {
181 Integer irqId = ((Long) content.getField(LttngStrings.IRQ).getValue()).intValue();
182
183 /* Put this IRQ back to inactive in the resource tree */
184 quark = ss.getQuarkRelativeAndAdd(irqsNode, irqId.toString());
185 value = TmfStateValue.nullValue();
186 ss.modifyAttribute(ts, value, quark);
187
188 /* Set the previous process back to running */
189 setProcessToRunning(ts, currentThreadNode);
190 }
191 break;
192
193 case 4: // "softirq_entry":
194 /* Fields: int32 vec */
195 {
196 Integer softIrqId = ((Long) content.getField(LttngStrings.VEC).getValue()).intValue();
197
198 /* Mark this SoftIRQ as active in the resource tree.
199 * The state value = the CPU on which this SoftIRQ is processed */
200 quark = ss.getQuarkRelativeAndAdd(softIrqsNode, softIrqId.toString());
201 value = TmfStateValue.newValueInt(event.getCPU());
202 ss.modifyAttribute(ts, value, quark);
203
204 /* Change the status of the running process to interrupted */
205 quark = ss.getQuarkRelativeAndAdd(currentThreadNode, Attributes.STATUS);
206 value = TmfStateValue.newValueInt(Attributes.STATUS_INTERRUPTED);
207 ss.modifyAttribute(ts, value, quark);
208 }
209 break;
210
211 case 5: // "softirq_exit":
212 /* Fields: int32 vec */
213 {
214 Integer softIrqId = ((Long) content.getField(LttngStrings.VEC).getValue()).intValue();
215
216 /* Put this SoftIRQ back to inactive (= -1) in the resource tree */
217 quark = ss.getQuarkRelativeAndAdd(softIrqsNode, softIrqId.toString());
218 value = TmfStateValue.nullValue();
219 ss.modifyAttribute(ts, value, quark);
220
221 /* Set the previous process back to running */
222 setProcessToRunning(ts, currentThreadNode);
223 }
224 break;
225
226 case 6: // "softirq_raise":
227 /* Fields: int32 vec */
228 {
229 Integer softIrqId = ((Long) content.getField(LttngStrings.VEC).getValue()).intValue();
230
231 /* Mark this SoftIRQ as *raised* in the resource tree.
232 * State value = -2 */
233 quark = ss.getQuarkRelativeAndAdd(softIrqsNode, softIrqId.toString());
234 value = TmfStateValue.newValueInt(Attributes.SOFT_IRQ_RAISED);
235 ss.modifyAttribute(ts, value, quark);
236 }
237 break;
238
239 case 7: // "sched_switch":
240 /*
241 * Fields: string prev_comm, int32 prev_tid, int32 prev_prio, int64 prev_state,
242 * string next_comm, int32 next_tid, int32 next_prio
243 */
244 {
245 Integer prevTid = ((Long) content.getField(LttngStrings.PREV_TID).getValue()).intValue();
246 //Long prevState = (Long) content.getField(LttngStrings.PREV_STATE).getValue();
247
248 String nextProcessName = (String) content.getField(LttngStrings.NEXT_COMM).getValue();
249 Integer nextTid = ((Long) content.getField(LttngStrings.NEXT_TID).getValue()).intValue();
250
251 /* Update the currentThreadNodes pointer */
252 Integer newCurrentThreadNode = ss.getQuarkRelativeAndAdd(threadsNode, nextTid.toString());
253 currentThreadNodes.set(eventCpu, newCurrentThreadNode);
254
255 /*
256 * Set the status of the process that got scheduled out, but
257 * only in the case where that process is currently active.
258 */
259 Integer formerThreadNode = ss.getQuarkRelativeAndAdd(threadsNode, prevTid.toString());
260 quark = ss.getQuarkRelativeAndAdd(formerThreadNode, Attributes.EXEC_NAME);
261 value = ss.queryOngoingState(quark);
262 if (!value.isNull()) {
263 quark = ss.getQuarkRelativeAndAdd(formerThreadNode, Attributes.STATUS);
264 value = TmfStateValue.newValueInt(Attributes.STATUS_WAIT);
265 ss.modifyAttribute(ts, value, quark);
266 }
267
268 /* Set the status of the new scheduled process */
269 setProcessToRunning(ts, newCurrentThreadNode);
270
271 /* Set the exec name of the new process */
272 quark = ss.getQuarkRelativeAndAdd(newCurrentThreadNode, Attributes.EXEC_NAME);
273 value = TmfStateValue.newValueString(nextProcessName);
274 ss.modifyAttribute(ts, value, quark);
275
276 /*
277 * Check if we need to set the syscall state and the PPID of
278 * the new process (in case we haven't seen this process before)
279 */
280 quark = ss.getQuarkRelativeAndAdd(newCurrentThreadNode, Attributes.SYSTEM_CALL);
281 if (quark == ss.getNbAttributes()) { /* Did we just add this attribute? */
282 value = TmfStateValue.nullValue();
283 ss.modifyAttribute(ts, value, quark);
284 }
285 quark = ss.getQuarkRelativeAndAdd(newCurrentThreadNode, Attributes.PPID);
286 if (quark == ss.getNbAttributes()) {
287 value = TmfStateValue.nullValue();
288 ss.modifyAttribute(ts, value, quark);
289 }
290
291 /* Set the current scheduled process on the relevant CPU */
292 quark = ss.getQuarkRelativeAndAdd(currentCPUNode, Attributes.CURRENT_THREAD);
293 value = TmfStateValue.newValueInt(nextTid);
294 ss.modifyAttribute(ts, value, quark);
295 }
296 break;
297
298 case 8: // "sched_process_fork":
299 /* Fields: string parent_comm, int32 parent_tid,
300 * string child_comm, int32 child_tid */
301 {
302 // String parentProcessName = (String)
303 // event.getFieldValue("parent_comm");
304 String childProcessName;
305 childProcessName = (String) content.getField(LttngStrings.CHILD_COMM).getValue();
306 // assert ( parentProcessName.equals(childProcessName) );
307
308 Integer parentTid = ((Long) content.getField(LttngStrings.PARENT_TID).getValue()).intValue();
309 Integer childTid = ((Long) content.getField(LttngStrings.CHILD_TID).getValue()).intValue();
310
311 tidNode = ss.getQuarkRelativeAndAdd(threadsNode, childTid.toString());
312
313 /* Assign the PPID to the new process */
314 quark = ss.getQuarkRelativeAndAdd(tidNode, Attributes.PPID);
315 value = TmfStateValue.newValueInt(parentTid);
316 ss.modifyAttribute(ts, value, quark);
317
318 /* Set the new process' exec_name */
319 quark = ss.getQuarkRelativeAndAdd(tidNode, Attributes.EXEC_NAME);
320 value = TmfStateValue.newValueString(childProcessName);
321 ss.modifyAttribute(ts, value, quark);
322
323 /* Set the new process' status */
324 quark = ss.getQuarkRelativeAndAdd(tidNode, Attributes.STATUS);
325 value = TmfStateValue.newValueInt(Attributes.STATUS_WAIT);
326 ss.modifyAttribute(ts, value, quark);
327
328 /* Set the process' syscall state */
329 quark = ss.getQuarkRelativeAndAdd(tidNode, Attributes.SYSTEM_CALL);
330 value = TmfStateValue.nullValue();
331 ss.modifyAttribute(ts, value, quark);
332 }
333 break;
334
335 case 9: // "sched_process_exit":
336 /* Fields: string comm, int32 tid, int32 prio */
337 {
338 String processName = (String) content.getField(LttngStrings.COMM).getValue();
339 Integer tid = ((Long) content.getField(LttngStrings.TID).getValue()).intValue();
340
341 /* Update the process' name, if we don't have it */
342 quark = ss.getQuarkRelativeAndAdd(threadsNode, tid.toString(), Attributes.EXEC_NAME);
343 value = TmfStateValue.newValueString(processName);
344 ss.updateOngoingState(value, quark);
345
346 /*
347 * Remove the process and all its sub-attributes from the
348 * current state
349 */
350 quark = ss.getQuarkRelativeAndAdd(threadsNode, tid.toString());
351 ss.removeAttribute(ts, quark);
352 }
353 break;
354
355 case 10: // "sched_process_free":
356 /* Fields: string comm, int32 tid, int32 prio */
357 break;
358
359 // FIXME In CTF it's as "syscall_exec". Will have to be adapted.
360 // case LTT_EVENT_EXEC:
361 // filename = new String((byte[]) event.getField(0));
362 //
363 // /* Change the Exec_name of the process */
364 // quark = ss.getQuarkRelativePath(true, currentThreadNode,
365 // "Exec_name");
366 // ss.modifyAttribute(ts, filename, quark);
367 // break;
368
369 default:
370 /* Other event types not covered by the main switch */
371 {
372 if (eventName.startsWith(LttngStrings.SYSCALL_PREFIX)
373 || eventName.startsWith(LttngStrings.COMPAT_SYSCALL_PREFIX)) {
374 /*
375 * This is a replacement for the old sys_enter event. Now
376 * syscall names are listed into the event type
377 */
378
379 /* Assign the new system call to the process */
380 quark = ss.getQuarkRelativeAndAdd(currentThreadNode, Attributes.SYSTEM_CALL);
381 value = TmfStateValue.newValueString(eventName);
382 ss.modifyAttribute(ts, value, quark);
383
384 /* Put the process in system call mode */
385 quark = ss.getQuarkRelativeAndAdd(currentThreadNode, Attributes.STATUS);
386 value = TmfStateValue.newValueInt(Attributes.STATUS_RUN_SYSCALL);
387 ss.modifyAttribute(ts, value, quark);
388 }
389 }
390 break;
391 } // End of big switch
392
393 /*
394 * Statistics
395 */
396
397 /* Number of events of each type, globally */
398 // quark = ss.getQuarkAbsoluteAndAdd(Attributes.STATISTICS,
399 // Attributes.EVENT_TYPES, eventName);
400 // ss.incrementAttribute(ts, quark);
401
402 /* Number of events per CPU */
403 // quark = ss.getQuarkRelativeAndAdd(currentCPUNode,
404 // Attributes.STATISTICS, Attributes.EVENT_TYPES, eventName);
405 // ss.incrementAttribute(ts, quark);
406
407 /* Number of events per process */
408 // quark = ss.getQuarkRelativeAndAdd(currentThreadNode,
409 // Attributes.STATISTICS, Attributes.EVENT_TYPES, eventName);
410 // ss.incrementAttribute(ts, quark);
411
412 } catch (AttributeNotFoundException ae) {
413 /*
414 * This would indicate a problem with the logic of the manager here,
415 * so it shouldn't happen.
416 */
417 ae.printStackTrace();
418
419 } catch (TimeRangeException tre) {
420 /*
421 * This would happen if the events in the trace aren't ordered
422 * chronologically, which should never be the case ...
423 */
424 System.err.println("TimeRangeExcpetion caught in the state system's event manager."); //$NON-NLS-1$
425 System.err.println("Are the events in the trace correctly ordered?"); //$NON-NLS-1$
426 tre.printStackTrace();
427
428 } catch (StateValueTypeException sve) {
429 /*
430 * This would happen if we were trying to push/pop attributes not of
431 * type integer. Which, once again, should never happen.
432 */
433 sve.printStackTrace();
434 }
435 }
436
437 private void setupCommonLocations() {
438 cpusNode = ss.getQuarkAbsoluteAndAdd(Attributes.CPUS);
439 threadsNode = ss.getQuarkAbsoluteAndAdd(Attributes.THREADS);
440 irqsNode = ss.getQuarkAbsoluteAndAdd(Attributes.RESOURCES, Attributes.IRQS);
441 softIrqsNode = ss.getQuarkAbsoluteAndAdd(Attributes.RESOURCES, Attributes.SOFT_IRQS);
442 }
443
444 private static HashMap<String, Integer> fillEventNames() {
445 /*
446 * TODO Replace with straight strings in the switch/case once we move to
447 * Java 7
448 */
449 HashMap<String, Integer> map = new HashMap<String, Integer>();
450
451 map.put(LttngStrings.EXIT_SYSCALL, 1);
452 map.put(LttngStrings.IRQ_HANDLER_ENTRY, 2);
453 map.put(LttngStrings.IRQ_HANDLER_EXIT, 3);
454 map.put(LttngStrings.SOFTIRQ_ENTRY, 4);
455 map.put(LttngStrings.SOFTIRQ_EXIT, 5);
456 map.put(LttngStrings.SOFTIRQ_RAISE, 6);
457 map.put(LttngStrings.SCHED_SWITCH, 7);
458 map.put(LttngStrings.SCHED_PROCESS_FORK, 8);
459 map.put(LttngStrings.SCHED_PROCESS_EXIT, 9);
460 map.put(LttngStrings.SCHED_PROCESS_FREE, 10);
461
462 return map;
463 }
464
465 private int getEventIndex(String eventName) {
466 Integer ret = knownEventNames.get(eventName);
467 return (ret != null) ? ret : -1;
468 }
469
470 /**
471 * When we want to set a process back to a "running" state, first check
472 * its current System_call attribute. If there is a system call active, we
473 * put the process back in the syscall state. If not, we put it back in
474 * user mode state.
475 */
476 private void setProcessToRunning(long ts, int currentThreadNode)
477 throws AttributeNotFoundException, TimeRangeException,
478 StateValueTypeException {
479 int quark;
480 ITmfStateValue value;
481
482 quark = ss.getQuarkRelativeAndAdd(currentThreadNode, Attributes.SYSTEM_CALL);
483 if (ss.queryOngoingState(quark).isNull()) {
484 /* We were in user mode before the interruption */
485 value = TmfStateValue.newValueInt(Attributes.STATUS_RUN_USERMODE);
486 } else {
487 /* We were previously in kernel mode */
488 value = TmfStateValue.newValueInt(Attributes.STATUS_RUN_SYSCALL);
489 }
490 quark = ss.getQuarkRelativeAndAdd(currentThreadNode, Attributes.STATUS);
491 ss.modifyAttribute(ts, value, quark);
492 }
493 }
This page took 0.042483 seconds and 6 git commands to generate.