mirror of
https://gitee.com/mirrors_PX4/PX4-Autopilot.git
synced 2026-10-16 21:53:34 +08:00
printload: use sched_lock to protect access to tcb
what could have gone wrong before? A scheduling switch during the printload could have led to a task exit, rendering the tcb invalid. After switching back, printload would access invalid memory. This keeps the sched_lock() section as small as possible, just grabbing the tcb variables we need.
This commit is contained in:
+148
-121
@@ -140,159 +140,186 @@ void print_load(uint64_t t, int fd, struct print_load_s *print_state)
|
||||
print_state->total_user_time = 0;
|
||||
|
||||
for (i = 0; i < CONFIG_MAX_TASKS; i++) {
|
||||
uint64_t interval_runtime;
|
||||
|
||||
if (system_load.tasks[i].valid) {
|
||||
switch (system_load.tasks[i].tcb->task_state) {
|
||||
case TSTATE_TASK_PENDING:
|
||||
case TSTATE_TASK_READYTORUN:
|
||||
case TSTATE_TASK_RUNNING:
|
||||
print_state->running_count++;
|
||||
break;
|
||||
sched_lock(); // need to lock the tcb access (but make it as short as possible)
|
||||
|
||||
case TSTATE_TASK_INVALID:
|
||||
case TSTATE_TASK_INACTIVE:
|
||||
case TSTATE_WAIT_SEM:
|
||||
#ifndef CONFIG_DISABLE_SIGNALS
|
||||
case TSTATE_WAIT_SIG:
|
||||
#endif
|
||||
#ifndef CONFIG_DISABLE_MQUEUE
|
||||
case TSTATE_WAIT_MQNOTEMPTY:
|
||||
case TSTATE_WAIT_MQNOTFULL:
|
||||
#endif
|
||||
#ifdef CONFIG_PAGING
|
||||
case TSTATE_WAIT_PAGEFILL:
|
||||
#endif
|
||||
print_state->blocked_count++;
|
||||
break;
|
||||
}
|
||||
if (!system_load.tasks[i].valid) {
|
||||
sched_unlock();
|
||||
continue;
|
||||
}
|
||||
|
||||
interval_runtime = (system_load.tasks[i].valid && print_state->last_times[i] > 0 &&
|
||||
uint64_t interval_runtime;
|
||||
unsigned tcb_pid = system_load.tasks[i].tcb->pid;
|
||||
size_t stack_size = system_load.tasks[i].tcb->adj_stack_size;
|
||||
ssize_t stack_free = 0;
|
||||
char tcb_name[CONFIG_TASK_NAME_SIZE];
|
||||
strncpy(tcb_name, system_load.tasks[i].tcb->name, CONFIG_TASK_NAME_SIZE);
|
||||
|
||||
#if CONFIG_ARCH_INTERRUPTSTACK > 3
|
||||
|
||||
if (system_load.tasks[i].tcb->pid == 0) {
|
||||
stack_size = (CONFIG_ARCH_INTERRUPTSTACK & ~3);
|
||||
stack_free = up_check_intstack_remain();
|
||||
|
||||
} else {
|
||||
#endif
|
||||
stack_free = up_check_tcbstack_remain(system_load.tasks[i].tcb);
|
||||
#if CONFIG_ARCH_INTERRUPTSTACK > 3
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
unsigned tcb_sched_priority = system_load.tasks[i].tcb->sched_priority;
|
||||
#if CONFIG_ARCH_BOARD_SIM || !defined(CONFIG_PRIORITY_INHERITANCE)
|
||||
#else
|
||||
unsigned tcb_base_priority = system_load.tasks[i].tcb->base_priority;
|
||||
#endif
|
||||
|
||||
#if CONFIG_RR_INTERVAL > 0
|
||||
unsigned tcb_timeslice = system_load.tasks[i].tcb->timeslice);
|
||||
#endif
|
||||
unsigned tcb_task_state = system_load.tasks[i].tcb->task_state;
|
||||
|
||||
|
||||
sched_unlock();
|
||||
|
||||
|
||||
switch (tcb_task_state) {
|
||||
// astyle formatting bug
|
||||
case TSTATE_TASK_PENDING:
|
||||
case TSTATE_TASK_READYTORUN:
|
||||
case TSTATE_TASK_RUNNING:
|
||||
print_state->running_count++;
|
||||
break;
|
||||
|
||||
case TSTATE_TASK_INVALID:
|
||||
case TSTATE_TASK_INACTIVE:
|
||||
case TSTATE_WAIT_SEM:
|
||||
#ifndef CONFIG_DISABLE_SIGNALS
|
||||
case TSTATE_WAIT_SIG:
|
||||
#endif
|
||||
#ifndef CONFIG_DISABLE_MQUEUE
|
||||
case TSTATE_WAIT_MQNOTEMPTY:
|
||||
case TSTATE_WAIT_MQNOTFULL:
|
||||
#endif
|
||||
#ifdef CONFIG_PAGING
|
||||
case TSTATE_WAIT_PAGEFILL:
|
||||
#endif
|
||||
print_state->blocked_count++;
|
||||
break;
|
||||
}
|
||||
|
||||
interval_runtime = (print_state->last_times[i] > 0 &&
|
||||
system_load.tasks[i].total_runtime > print_state->last_times[i])
|
||||
? (system_load.tasks[i].total_runtime - print_state->last_times[i]) / 1000
|
||||
: 0;
|
||||
|
||||
print_state->last_times[i] = system_load.tasks[i].total_runtime;
|
||||
|
||||
if (system_load.tasks[i].valid && (print_state->new_time > print_state->interval_start_time)) {
|
||||
print_state->curr_loads[i] = interval_runtime * print_state->interval_time_ms_inv;
|
||||
if (print_state->new_time > print_state->interval_start_time) {
|
||||
print_state->curr_loads[i] = interval_runtime * print_state->interval_time_ms_inv;
|
||||
|
||||
if (i > 0) {
|
||||
if (tcb_pid != 0) {
|
||||
print_state->total_user_time += interval_runtime;
|
||||
}
|
||||
|
||||
} else {
|
||||
print_state->curr_loads[i] = 0;
|
||||
}
|
||||
|
||||
|
||||
if (print_state->new_time <= print_state->interval_start_time) {
|
||||
continue; // not enough data yet
|
||||
}
|
||||
|
||||
for (i = 0; i < CONFIG_MAX_TASKS; i++) {
|
||||
if (system_load.tasks[i].valid && (print_state->new_time > print_state->interval_start_time)) {
|
||||
if (system_load.tasks[i].tcb->pid == 0) {
|
||||
float idle;
|
||||
float task_load;
|
||||
float sched_load;
|
||||
// print output
|
||||
|
||||
idle = print_state->curr_loads[0];
|
||||
task_load = (float)(print_state->total_user_time) * print_state->interval_time_ms_inv;
|
||||
if (tcb_pid == 0) {
|
||||
float idle;
|
||||
float task_load;
|
||||
float sched_load;
|
||||
|
||||
/* this can happen if one tasks total runtime was not computed
|
||||
correctly by the scheduler instrumentation TODO */
|
||||
if (task_load > (1.f - idle)) {
|
||||
task_load = (1.f - idle);
|
||||
}
|
||||
idle = print_state->curr_loads[i];
|
||||
task_load = (float)(print_state->total_user_time) * print_state->interval_time_ms_inv;
|
||||
|
||||
sched_load = 1.f - idle - task_load;
|
||||
|
||||
dprintf(fd, "%sProcesses: %d total, %d running, %d sleeping\n",
|
||||
clear_line,
|
||||
system_load.total_count,
|
||||
print_state->running_count,
|
||||
print_state->blocked_count);
|
||||
dprintf(fd, "%sCPU usage: %.2f%% tasks, %.2f%% sched, %.2f%% idle\n",
|
||||
clear_line,
|
||||
(double)(task_load * 100.f),
|
||||
(double)(sched_load * 100.f),
|
||||
(double)(idle * 100.f));
|
||||
#if defined(BOARD_DMA_ALLOC_POOL_SIZE)
|
||||
uint16_t dma_total;
|
||||
uint16_t dma_used;
|
||||
uint16_t dma_peak_used;
|
||||
|
||||
if (board_get_dma_usage(&dma_total, &dma_used, &dma_peak_used) >= 0) {
|
||||
dprintf(fd, "%sDMA Memory: %d total, %d used %d peak\n",
|
||||
clear_line,
|
||||
dma_total,
|
||||
dma_used,
|
||||
dma_peak_used);
|
||||
}
|
||||
|
||||
#endif
|
||||
dprintf(fd, "%sUptime: %.3fs total, %.3fs idle\n%s\n",
|
||||
clear_line,
|
||||
(double)curr_time_us / 1000000.d,
|
||||
(double)idle_time_us / 1000000.d,
|
||||
clear_line);
|
||||
/* header for task list */
|
||||
dprintf(fd, "%s%4s %*-s %8s %6s %11s %10s %-6s\n",
|
||||
clear_line,
|
||||
"PID",
|
||||
CONFIG_TASK_NAME_SIZE, "COMMAND",
|
||||
"CPU(ms)",
|
||||
"CPU(%)",
|
||||
"USED/STACK",
|
||||
"PRIO(BASE)",
|
||||
#if CONFIG_RR_INTERVAL > 0
|
||||
"TSLICE"
|
||||
#else
|
||||
"STATE"
|
||||
#endif
|
||||
);
|
||||
/* this can happen if one tasks total runtime was not computed
|
||||
correctly by the scheduler instrumentation TODO */
|
||||
if (task_load > (1.f - idle)) {
|
||||
task_load = (1.f - idle);
|
||||
}
|
||||
|
||||
size_t stack_size = system_load.tasks[i].tcb->adj_stack_size;
|
||||
ssize_t stack_free = 0;
|
||||
sched_load = 1.f - idle - task_load;
|
||||
|
||||
#if CONFIG_ARCH_INTERRUPTSTACK > 3
|
||||
|
||||
if (system_load.tasks[i].tcb->pid == 0) {
|
||||
stack_size = (CONFIG_ARCH_INTERRUPTSTACK & ~3);
|
||||
stack_free = up_check_intstack_remain();
|
||||
|
||||
} else {
|
||||
#endif
|
||||
stack_free = up_check_tcbstack_remain(system_load.tasks[i].tcb);
|
||||
#if CONFIG_ARCH_INTERRUPTSTACK > 3
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
dprintf(fd, "%s%4d %*-s %8lld %2d.%03d %5u/%5u %3u (%3u) ",
|
||||
dprintf(fd, "%sProcesses: %d total, %d running, %d sleeping\n",
|
||||
clear_line,
|
||||
system_load.tasks[i].tcb->pid,
|
||||
CONFIG_TASK_NAME_SIZE, system_load.tasks[i].tcb->name,
|
||||
(system_load.tasks[i].total_runtime / 1000),
|
||||
(int)(print_state->curr_loads[i] * 100.0f),
|
||||
(int)((print_state->curr_loads[i] * 100.0f - (int)(print_state->curr_loads[i] * 100.0f)) * 1000),
|
||||
stack_size - stack_free,
|
||||
stack_size,
|
||||
system_load.tasks[i].tcb->sched_priority,
|
||||
#if CONFIG_ARCH_BOARD_SIM || !defined(CONFIG_PRIORITY_INHERITANCE)
|
||||
0);
|
||||
system_load.total_count,
|
||||
print_state->running_count,
|
||||
print_state->blocked_count);
|
||||
dprintf(fd, "%sCPU usage: %.2f%% tasks, %.2f%% sched, %.2f%% idle\n",
|
||||
clear_line,
|
||||
(double)(task_load * 100.f),
|
||||
(double)(sched_load * 100.f),
|
||||
(double)(idle * 100.f));
|
||||
#if defined(BOARD_DMA_ALLOC_POOL_SIZE)
|
||||
uint16_t dma_total;
|
||||
uint16_t dma_used;
|
||||
uint16_t dma_peak_used;
|
||||
|
||||
if (board_get_dma_usage(&dma_total, &dma_used, &dma_peak_used) >= 0) {
|
||||
dprintf(fd, "%sDMA Memory: %d total, %d used %d peak\n",
|
||||
clear_line,
|
||||
dma_total,
|
||||
dma_used,
|
||||
dma_peak_used);
|
||||
}
|
||||
|
||||
#endif
|
||||
dprintf(fd, "%sUptime: %.3fs total, %.3fs idle\n%s\n",
|
||||
clear_line,
|
||||
(double)curr_time_us / 1000000.d,
|
||||
(double)idle_time_us / 1000000.d,
|
||||
clear_line);
|
||||
/* header for task list */
|
||||
dprintf(fd, "%s%4s %*-s %8s %6s %11s %10s %-6s\n",
|
||||
clear_line,
|
||||
"PID",
|
||||
CONFIG_TASK_NAME_SIZE, "COMMAND",
|
||||
"CPU(ms)",
|
||||
"CPU(%)",
|
||||
"USED/STACK",
|
||||
"PRIO(BASE)",
|
||||
#if CONFIG_RR_INTERVAL > 0
|
||||
"TSLICE"
|
||||
#else
|
||||
system_load.tasks[i].tcb->base_priority);
|
||||
"STATE"
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
dprintf(fd, "%s%4d %*-s %8lld %2d.%03d %5u/%5u %3u (%3u) ",
|
||||
clear_line,
|
||||
tcb_pid,
|
||||
CONFIG_TASK_NAME_SIZE, tcb_name,
|
||||
(system_load.tasks[i].total_runtime / 1000),
|
||||
(int)(print_state->curr_loads[i] * 100.0f),
|
||||
(int)((print_state->curr_loads[i] * 100.0f - (int)(print_state->curr_loads[i] * 100.0f)) * 1000),
|
||||
stack_size - stack_free,
|
||||
stack_size,
|
||||
tcb_sched_priority,
|
||||
#if CONFIG_ARCH_BOARD_SIM || !defined(CONFIG_PRIORITY_INHERITANCE)
|
||||
0);
|
||||
#else
|
||||
tcb_base_priority);
|
||||
#endif
|
||||
|
||||
#if CONFIG_RR_INTERVAL > 0
|
||||
/* print scheduling info with RR time slice */
|
||||
dprintf(fd, " %6d\n", system_load.tasks[i].tcb->timeslice);
|
||||
(void)tstate_name(TSTATE_TASK_INVALID); // Stop not used warning
|
||||
/* print scheduling info with RR time slice */
|
||||
dprintf(fd, " %6d\n", tcb_timeslice);
|
||||
(void)tstate_name(TSTATE_TASK_INVALID); // Stop not used warning
|
||||
#else
|
||||
// print task state instead
|
||||
dprintf(fd, " %-6s\n", tstate_name(system_load.tasks[i].tcb->task_state));
|
||||
// print task state instead
|
||||
dprintf(fd, " %-6s\n", tstate_name(tcb_task_state));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
print_state->interval_start_time = print_state->new_time;
|
||||
|
||||
Reference in New Issue
Block a user