1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
// Licensed under the Apache License, Version 2.0 or the MIT License.
// SPDX-License-Identifier: Apache-2.0 OR MIT
// Copyright Tock Contributors 2022.
//! Mechanism for inspecting the status of the kernel.
//!
//! In particular this provides functions for getting the status of processes
//! on the board. It potentially could be expanded to other kernel state.
//!
//! To restrict access on what can use this module, even though it is public (in
//! a Rust sense) so it is visible outside of this crate, the introspection
//! functions require the caller have the correct capability to call the
//! functions. This prevents arbitrary capsules from being able to use this
//! module, and only capsules that the board author has explicitly passed the
//! correct capabilities to can use it.
use core::cell::Cell;
use crate::capabilities::ProcessManagementCapability;
use crate::kernel::Kernel;
use crate::process;
use crate::process::ProcessId;
use crate::utilities::cells::NumericCellExt;
/// This struct provides the inspection functions.
pub struct KernelInfo {
kernel: &'static Kernel,
}
impl KernelInfo {
pub fn new(kernel: &'static Kernel) -> KernelInfo {
KernelInfo { kernel }
}
/// Returns how many processes have been loaded on this platform. This is
/// functionally equivalent to how many of the process slots have been used
/// on the board. This does not consider what state the process is in, as
/// long as it has been loaded.
pub fn number_loaded_processes(&self, _capability: &dyn ProcessManagementCapability) -> usize {
let count: Cell<usize> = Cell::new(0);
self.kernel.process_each(|_| count.increment());
count.get()
}
/// Returns how many processes are considered to be active. This includes
/// processes in the `Running` and `Yield` states. This does not include
/// processes which have faulted, or processes which the kernel is no longer
/// scheduling because they have faulted too frequently or for some other
/// reason.
pub fn number_active_processes(&self, _capability: &dyn ProcessManagementCapability) -> usize {
let count: Cell<usize> = Cell::new(0);
self.kernel
.process_each(|process| match process.get_state() {
process::State::Running => count.increment(),
process::State::Yielded => count.increment(),
_ => {}
});
count.get()
}
/// Returns how many processes are considered to be inactive. This includes
/// processes in the `Fault` state and processes which the kernel is not
/// scheduling for any reason.
pub fn number_inactive_processes(
&self,
_capability: &dyn ProcessManagementCapability,
) -> usize {
let count: Cell<usize> = Cell::new(0);
self.kernel
.process_each(|process| match process.get_state() {
process::State::Running => {}
process::State::Yielded => {}
_ => count.increment(),
});
count.get()
}
/// Get the name of the process.
pub fn process_name(
&self,
app: ProcessId,
_capability: &dyn ProcessManagementCapability,
) -> &'static str {
self.kernel
.process_map_or("unknown", app, |process| process.get_process_name())
}
/// Returns the number of syscalls the app has called.
pub fn number_app_syscalls(
&self,
app: ProcessId,
_capability: &dyn ProcessManagementCapability,
) -> usize {
self.kernel
.process_map_or(0, app, |process| process.debug_syscall_count())
}
/// Returns the number of dropped upcalls the app has experience.
/// Upcalls can be dropped if the queue for the app is full when a capsule
/// tries to schedule a upcall.
pub fn number_app_dropped_upcalls(
&self,
app: ProcessId,
_capability: &dyn ProcessManagementCapability,
) -> usize {
self.kernel
.process_map_or(0, app, |process| process.debug_dropped_upcall_count())
}
/// Returns the number of time this app has been restarted.
pub fn number_app_restarts(
&self,
app: ProcessId,
_capability: &dyn ProcessManagementCapability,
) -> usize {
self.kernel
.process_map_or(0, app, |process| process.get_restart_count())
}
/// Returns the number of time this app has exceeded its timeslice.
pub fn number_app_timeslice_expirations(
&self,
app: ProcessId,
_capability: &dyn ProcessManagementCapability,
) -> usize {
self.kernel
.process_map_or(0, app, |process| process.debug_timeslice_expiration_count())
}
/// Returns a tuple of the (the number of grants in the grant region this
/// app has allocated, total number of grants that exist in the system).
pub fn number_app_grant_uses(
&self,
app: ProcessId,
_capability: &dyn ProcessManagementCapability,
) -> (usize, usize) {
// Just need to get the number, this has already been finalized, but it
// doesn't hurt to call this again.
let number_of_grants = self.kernel.get_grant_count_and_finalize();
let used = self.kernel.process_map_or(0, app, |process| {
// Have process tell us the number of allocated grants. If this
// process isn't valid then we can't count the grants and all we can
// do is return 0.
process.grant_allocated_count().unwrap_or(0)
});
(used, number_of_grants)
}
/// Returns the total number of times all processes have exceeded
/// their timeslices.
pub fn timeslice_expirations(&self, _capability: &dyn ProcessManagementCapability) -> usize {
let count: Cell<usize> = Cell::new(0);
self.kernel.process_each(|proc| {
count.add(proc.debug_timeslice_expiration_count());
});
count.get()
}
}