forked from Imagelibrary/rtems
stackchk: Add rtems_stack_checker_iterate()
This commit is contained in:
@@ -90,6 +90,81 @@ void rtems_stack_checker_report_usage_with_plugin(
|
||||
const rtems_printer *printer
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief This structure contains the stack information provided by the stack
|
||||
* checker for a stack.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief This member contains the object identifier associated with the
|
||||
* object using the stack.
|
||||
*
|
||||
* For interrupt stacks, the object identifier is the processor index.
|
||||
*/
|
||||
rtems_id id;
|
||||
|
||||
/**
|
||||
* @brief This member provides the object name associated with the
|
||||
* object using the stack.
|
||||
*
|
||||
* For interrupt stacks, the object name is "Interrupt Stack".
|
||||
*/
|
||||
const char *name;
|
||||
|
||||
/**
|
||||
* @brief This member provides the begin address of the stack area.
|
||||
*/
|
||||
const void *begin;
|
||||
|
||||
/**
|
||||
* @brief This member contains the size in byes of the stack area.
|
||||
*/
|
||||
uintptr_t size;
|
||||
|
||||
/**
|
||||
* @brief This member provides the current stack pointer of the stack.
|
||||
*
|
||||
* If the current stack pointer is not available, then the value is set to
|
||||
* NULL.
|
||||
*/
|
||||
const void *current;
|
||||
|
||||
/**
|
||||
* @brief This member contains the size in byes of the used stack area.
|
||||
*
|
||||
* If the stack checker is not initialized, then the value is set to
|
||||
* UINTPTR_MAX.
|
||||
*/
|
||||
uintptr_t used;
|
||||
} rtems_stack_checker_info;
|
||||
|
||||
/**
|
||||
* @brief Visitor routines invoked by rtems_stack_checker_iterate() shall have
|
||||
* this type.
|
||||
*
|
||||
* @param info is the stack information.
|
||||
*
|
||||
* @param arg is the argument passed to rtems_stack_checker_iterate().
|
||||
*/
|
||||
typedef void ( *rtems_stack_checker_visitor )(
|
||||
const rtems_stack_checker_info *info,
|
||||
void *arg
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Iterates over all stacks used by the system and invokes the visitor
|
||||
* routine for each stack.
|
||||
*
|
||||
* This method prints a stack usage report for the curently executing
|
||||
* task.
|
||||
*
|
||||
* @param visitor is the visitor routine invoked for each stack.
|
||||
*
|
||||
* @param arg is the argument passed to each visitor routine invocation during
|
||||
* the iteration.
|
||||
*/
|
||||
void rtems_stack_checker_iterate( rtems_stack_checker_visitor visit, void *arg );
|
||||
|
||||
/*************************************************************
|
||||
*************************************************************
|
||||
** Prototyped only so the user extension can be installed **
|
||||
|
||||
@@ -413,125 +413,135 @@ static inline void *Stack_check_Find_high_water_mark(
|
||||
return (void *) base;
|
||||
#endif
|
||||
|
||||
return (void *)0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool Stack_check_Dump_stack_usage(
|
||||
const Stack_Control *stack,
|
||||
const void *current,
|
||||
const char *name,
|
||||
uint32_t id,
|
||||
const rtems_printer *printer
|
||||
static void Stack_check_Visit_stack(
|
||||
const Stack_Control *stack,
|
||||
const void *current,
|
||||
const char *name,
|
||||
rtems_id id,
|
||||
rtems_stack_checker_visitor visit,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
uint32_t size;
|
||||
uint32_t used;
|
||||
void *low;
|
||||
void *high_water_mark;
|
||||
rtems_stack_checker_info info;
|
||||
|
||||
/* This is likely to occur if the stack checker is not actually enabled */
|
||||
if ( stack->area == NULL ) {
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
low = Stack_check_Usable_stack_start(stack);
|
||||
size = Stack_check_Usable_stack_size(stack);
|
||||
info.id = id;
|
||||
info.name = name;
|
||||
info.current = current;
|
||||
info.begin = Stack_check_Usable_stack_start( stack );
|
||||
info.size = Stack_check_Usable_stack_size( stack );
|
||||
|
||||
high_water_mark = Stack_check_Find_high_water_mark(low, size);
|
||||
if ( Stack_check_Initialized ) {
|
||||
void *high_water_mark;
|
||||
|
||||
if ( high_water_mark )
|
||||
used = Stack_check_Calculate_used( low, size, high_water_mark );
|
||||
else
|
||||
used = 0;
|
||||
high_water_mark =
|
||||
Stack_check_Find_high_water_mark( info.begin, info.size );
|
||||
|
||||
rtems_printf(
|
||||
printer,
|
||||
"0x%08" PRIx32 " %-21s 0x%08" PRIxPTR " 0x%08" PRIxPTR " 0x%08" PRIxPTR " %6" PRId32 " ",
|
||||
id,
|
||||
name,
|
||||
(uintptr_t) stack->area,
|
||||
(uintptr_t) stack->area + (uintptr_t) stack->size - 1,
|
||||
(uintptr_t) current,
|
||||
size
|
||||
);
|
||||
|
||||
if (Stack_check_Initialized) {
|
||||
rtems_printf( printer, "%6" PRId32 "\n", used );
|
||||
if ( high_water_mark != NULL ) {
|
||||
info.used =
|
||||
Stack_check_Calculate_used( info.begin, info.size, high_water_mark );
|
||||
} else {
|
||||
info.used = 0;
|
||||
}
|
||||
} else {
|
||||
rtems_printf( printer, "N/A\n" );
|
||||
info.used = UINTPTR_MAX;
|
||||
}
|
||||
|
||||
return false;
|
||||
( *visit )( &info, arg );
|
||||
}
|
||||
|
||||
static bool Stack_check_Dump_threads_usage(
|
||||
typedef struct {
|
||||
rtems_stack_checker_visitor visit;
|
||||
void *arg;
|
||||
} Stack_check_Visitor;
|
||||
|
||||
static bool Stack_check_Visit_thread(
|
||||
Thread_Control *the_thread,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
Stack_check_Visitor *visitor;
|
||||
char name[ 22 ];
|
||||
const rtems_printer *printer;
|
||||
uintptr_t sp = _CPU_Context_Get_SP( &the_thread->Registers );
|
||||
|
||||
printer = arg;
|
||||
visitor = arg;
|
||||
_Thread_Get_name( the_thread, name, sizeof( name ) );
|
||||
Stack_check_Dump_stack_usage(
|
||||
Stack_check_Visit_stack(
|
||||
&the_thread->Start.Initial_stack,
|
||||
(void *) sp,
|
||||
name,
|
||||
the_thread->Object.id,
|
||||
printer
|
||||
visitor->visit,
|
||||
visitor->arg
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
static void Stack_check_Dump_interrupt_stack_usage(
|
||||
const Stack_Control *stack,
|
||||
uint32_t id,
|
||||
const rtems_printer *printer
|
||||
static void Stack_check_Visit_interrupt_stack(
|
||||
const Stack_Control *stack,
|
||||
uint32_t id,
|
||||
rtems_stack_checker_visitor visit,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
Stack_check_Dump_stack_usage(
|
||||
Stack_check_Visit_stack(
|
||||
stack,
|
||||
NULL,
|
||||
"Interrupt Stack",
|
||||
id,
|
||||
printer
|
||||
visit,
|
||||
arg
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* rtems_stack_checker_report_usage
|
||||
*/
|
||||
static void Stack_check_Print_info(
|
||||
const rtems_stack_checker_info *info,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
const rtems_printer *printer;
|
||||
|
||||
printer = arg;
|
||||
|
||||
rtems_printf(
|
||||
printer,
|
||||
"0x%08" PRIx32 " %-21s 0x%08" PRIxPTR " 0x%08" PRIxPTR " 0x%08" PRIxPTR " %6" PRIuPTR " ",
|
||||
info->id,
|
||||
info->name,
|
||||
(uintptr_t) info->begin,
|
||||
(uintptr_t) info->begin + info->size - 1,
|
||||
(uintptr_t) info->current,
|
||||
info->size
|
||||
);
|
||||
|
||||
if ( info->used != UINTPTR_MAX ) {
|
||||
rtems_printf( printer, "%6" PRIuPTR "\n", info->used );
|
||||
} else {
|
||||
rtems_printf( printer, "N/A\n" );
|
||||
}
|
||||
}
|
||||
|
||||
void rtems_stack_checker_report_usage_with_plugin(
|
||||
const rtems_printer* printer
|
||||
)
|
||||
{
|
||||
uint32_t cpu_max;
|
||||
uint32_t cpu_index;
|
||||
|
||||
rtems_printf(
|
||||
printer,
|
||||
" STACK USAGE BY THREAD\n"
|
||||
"ID NAME LOW HIGH CURRENT AVAIL USED\n"
|
||||
);
|
||||
|
||||
/* iterate over all threads and dump the usage */
|
||||
rtems_task_iterate(
|
||||
Stack_check_Dump_threads_usage,
|
||||
rtems_stack_checker_iterate(
|
||||
Stack_check_Print_info,
|
||||
RTEMS_DECONST( rtems_printer *, printer )
|
||||
);
|
||||
|
||||
cpu_max = rtems_scheduler_get_processor_maximum();
|
||||
|
||||
for ( cpu_index = 0; cpu_index < cpu_max; ++cpu_index ) {
|
||||
Stack_check_Dump_interrupt_stack_usage(
|
||||
&Stack_check_Interrupt_stack[ cpu_index ],
|
||||
cpu_index,
|
||||
printer
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void rtems_stack_checker_report_usage( void )
|
||||
@@ -541,6 +551,28 @@ void rtems_stack_checker_report_usage( void )
|
||||
rtems_stack_checker_report_usage_with_plugin( &printer );
|
||||
}
|
||||
|
||||
void rtems_stack_checker_iterate( rtems_stack_checker_visitor visit, void *arg )
|
||||
{
|
||||
Stack_check_Visitor visitor;
|
||||
uint32_t cpu_max;
|
||||
uint32_t cpu_index;
|
||||
|
||||
visitor.visit = visit;
|
||||
visitor.arg = arg;
|
||||
rtems_task_iterate( Stack_check_Visit_thread, &visitor );
|
||||
|
||||
cpu_max = rtems_scheduler_get_processor_maximum();
|
||||
|
||||
for ( cpu_index = 0; cpu_index < cpu_max; ++cpu_index ) {
|
||||
Stack_check_Visit_interrupt_stack(
|
||||
&Stack_check_Interrupt_stack[ cpu_index ],
|
||||
cpu_index,
|
||||
visit,
|
||||
arg
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
static void Stack_check_Prepare_interrupt_stacks( void )
|
||||
{
|
||||
Stack_Control stack;
|
||||
|
||||
Reference in New Issue
Block a user