blob: 1acdfbd6016d877472c34a20ae7e0c1c812238b0 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2017 École Polytechnique de Montréal
*
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License 2.0 which
* accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/
package org.eclipse.tracecompass.analysis.os.linux.core.model;
import org.eclipse.tracecompass.analysis.os.linux.core.kernel.LinuxValues;
import org.eclipse.tracecompass.internal.analysis.os.linux.core.kernel.StateValues;
import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue;
import org.eclipse.tracecompass.statesystem.core.statevalue.TmfStateValue;
/**
* A list of status a thread can be in
*
* @author Geneviève Bastien
* @author Francis Giraldeau
* @since 2.4
*/
public enum ProcessStatus {
/** Unknown process status */
UNKNOWN(StateValues.PROCESS_STATUS_UNKNOWN_VALUE),
/** Waiting for a fork */
WAIT_FORK(StateValues.PROCESS_STATUS_WAIT_FORK_VALUE),
/** Waiting for the CPU */
WAIT_CPU(StateValues.PROCESS_STATUS_WAIT_FOR_CPU_VALUE),
/**
* The thread has exited, but is not dead yet
*
* @since 2.3
*/
EXIT(StateValues.PROCESS_STATUS_UNKNOWN_VALUE),
/** The thread is a zombie thread */
ZOMBIE(StateValues.PROCESS_STATUS_UNKNOWN_VALUE),
/** The thread is blocked */
WAIT_BLOCKED(StateValues.PROCESS_STATUS_WAIT_BLOCKED_VALUE),
/** The thread is running */
RUN(StateValues.PROCESS_STATUS_RUN_USERMODE_VALUE),
/** The thread is dead or hasn't started yet */
NOT_ALIVE(TmfStateValue.nullValue()),
/** The thread is running in system call */
RUN_SYTEMCALL(StateValues.PROCESS_STATUS_RUN_SYSCALL_VALUE),
/** The thread is running but interrupted */
INTERRUPTED(StateValues.PROCESS_STATUS_INTERRUPTED_VALUE),
/** Waiting for an unknown reason */
WAIT_UNKNOWN(StateValues.PROCESS_STATUS_WAIT_UNKNOWN_VALUE);
private final ITmfStateValue fValue;
private ProcessStatus(ITmfStateValue value) {
fValue = value;
}
/**
* Get the state value that represents this status, to use to store the status
* to the state system
*
* @return The state value corresponding to this process status
*/
public ITmfStateValue getStateValue() {
return fValue;
}
/**
* Get the ProcessStatus associated with a long value
*
* @param status
* The long value corresponding to a status
* @return The {@link ProcessStatus} enum value
*/
public static ProcessStatus getStatusFromStatedump(long status) {
switch (Long.valueOf(status).intValue()) {
case LinuxValues.STATEDUMP_PROCESS_STATUS_UNNAMED:
return UNKNOWN;
case LinuxValues.STATEDUMP_PROCESS_STATUS_WAIT_FORK:
return WAIT_FORK;
case LinuxValues.STATEDUMP_PROCESS_STATUS_WAIT_CPU:
return WAIT_CPU;
case LinuxValues.STATEDUMP_PROCESS_STATUS_EXIT:
return EXIT;
case LinuxValues.STATEDUMP_PROCESS_STATUS_ZOMBIE:
return ZOMBIE;
case LinuxValues.STATEDUMP_PROCESS_STATUS_WAIT:
/*
* We have no information on what the process is waiting on (unlike a
* sched_switch for example), so we will use the WAIT_UNKNOWN state instead of
* the "normal" WAIT_BLOCKED state.
*/
return WAIT_UNKNOWN;
case LinuxValues.STATEDUMP_PROCESS_STATUS_RUN:
return RUN;
case LinuxValues.STATEDUMP_PROCESS_STATUS_DEAD:
return NOT_ALIVE;
default:
return UNKNOWN;
}
}
/**
* Get the ProcessStatus associated with a state value
*
* @param sv
* state value
* @return The {@link ProcessStatus} enum value
*/
static public ProcessStatus getStatusFromStateValue(ITmfStateValue sv) {
for (ProcessStatus e : ProcessStatus.values()) {
if (e.getStateValue().equals(sv)) {
return e;
}
}
return UNKNOWN;
}
private static boolean isDead(int state) {
return (state & LinuxValues.TASK_DEAD) != 0;
}
private static boolean isWaiting(int state) {
return (state & (LinuxValues.TASK_INTERRUPTIBLE | LinuxValues.TASK_UNINTERRUPTIBLE)) != 0;
}
private static boolean isRunning(int state) {
// special case, this means ALL STATES ARE 0
// this is effectively an anti-state
return state == 0;
}
/**
* Get the ProcessStatus from the value of the state in the kernel
*
* @param prevState the prev state
* @return The {@link ProcessStatus} enum value
*/
public static ProcessStatus getStatusFromKernelState(Long prevState) {
/*
* Empirical observations and look into the linux code have
* shown that the TASK_STATE_MAX flag is used internally and
* |'ed with other states, most often the running state, so it
* is ignored from the prevState value.
*
* Since Linux 4.1, the TASK_NOLOAD state was created and
* TASK_STATE_MAX is now 2048. We use TASK_NOLOAD as the new max
* because it does not modify the displayed state value.
*/
int state = (int) (prevState & (LinuxValues.TASK_NOLOAD - 1));
if (isRunning(state)) {
return WAIT_CPU;
} else if (isWaiting(state)) {
return WAIT_BLOCKED;
} else if (isDead(state)) {
return NOT_ALIVE;
} else {
return WAIT_UNKNOWN;
}
}
}