Add RTX API to report stack usage

Add the function osThreadGetInfo to allow various Thread information
to be queried.  This includes stack size and maximum stack usage among
other things.

Note - for Cortex-A devices the worst case stack usage is not
available.
pull/2642/head
Russ Butler 2016-09-07 00:39:22 -05:00 committed by Russ Butler
parent ad24b7d982
commit c319296692
7 changed files with 195 additions and 0 deletions

View File

@ -224,6 +224,16 @@ typedef enum {
osTimerPeriodic = 1 ///< repeating timer
} os_timer_type;
typedef enum {
osThreadInfoState,
osThreadInfoStackSize,
osThreadInfoStackMax,
osThreadInfoEntry,
osThreadInfoArg,
osThreadInfo_reserved = 0x7FFFFFFF ///< prevent from enum down-size compiler optimization.
} osThreadInfo;
/// Entry point of a thread.
/// \note MUST REMAIN UNCHANGED: \b os_pthread shall be consistent in every CMSIS-RTOS.
typedef void (*os_pthread) (void const *argument);
@ -451,6 +461,13 @@ osPriority osThreadGetPriority (osThreadId thread_id);
uint8_t osThreadGetState (osThreadId thread_id);
#endif
/// Get into from an active thread.
/// \param[in] thread_id thread ID obtained by \ref osThreadCreate or \ref osThreadGetId.
/// \param[in] info information to read.
/// \return current state of the thread function.
/// \return requested info that includes the status code.
os_InRegs osEvent osThreadGetInfo(osThreadId thread_id, osThreadInfo info);
// ==== Generic Wait Functions ====
/// Wait for Timeout (Time Delay).

View File

@ -713,6 +713,7 @@ SVC_1_1(svcThreadTerminate, osStatus, osThreadId, RET
SVC_0_1(svcThreadYield, osStatus, RET_osStatus)
SVC_2_1(svcThreadSetPriority, osStatus, osThreadId, osPriority, RET_osStatus)
SVC_1_1(svcThreadGetPriority, osPriority, osThreadId, RET_osPriority)
SVC_2_3(svcThreadGetInfo, os_InRegs osEvent, osThreadId, osThreadInfo, RET_osEvent)
// Thread Service Calls
@ -851,6 +852,80 @@ osPriority svcThreadGetPriority (osThreadId thread_id) {
return (osPriority)(ptcb->prio - 1 + osPriorityIdle);
}
/// Get info from an active thread
os_InRegs osEvent_type svcThreadGetInfo (osThreadId thread_id, osThreadInfo info) {
P_TCB ptcb;
osEvent ret;
ret.status = osOK;
ptcb = rt_tid2ptcb(thread_id); // Get TCB pointer
if (ptcb == NULL) {
ret.status = osErrorValue;
#if defined (__GNUC__) && defined (__ARM_PCS_VFP)
osEvent_ret_status;
return;
#else
return osEvent_ret_status;
#endif
}
if (osThreadInfoStackSize == info) {
uint32_t size;
size = ptcb->priv_stack;
if (0 == size) {
// This is an OS task - always a fixed size
size = os_stackinfo & 0x3FFFF;
}
ret.value.v = size;
#if defined (__GNUC__) && defined (__ARM_PCS_VFP)
osEvent_ret_value;
return;
#else
return osEvent_ret_value;
#endif
}
if (osThreadInfoStackMax == info) {
// Cortex-A RTX does not have stack init so
// the maximum stack usage cannot be obtained.
ret.status = osErrorResource;
#if defined (__GNUC__) && defined (__ARM_PCS_VFP)
osEvent_ret_status;
return;
#else
return osEvent_ret_status;
#endif
}
if (osThreadInfoEntry == info) {
ret.value.p = (void*)ptcb->ptask;
#if defined (__GNUC__) && defined (__ARM_PCS_VFP)
osEvent_ret_value;
return;
#else
return osEvent_ret_value;
#endif
}
if (osThreadInfoArg == info) {
ret.value.p = (void*)ptcb->argv;
#if defined (__GNUC__) && defined (__ARM_PCS_VFP)
osEvent_ret_value;
return;
#else
return osEvent_ret_value;
#endif
}
// Unsupported option so return error
ret.status = osErrorParameter;
#if defined (__GNUC__) && defined (__ARM_PCS_VFP)
osEvent_ret_status;
return;
#else
return osEvent_ret_status;
#endif
}
// Thread Public API
@ -930,6 +1005,16 @@ uint8_t osThreadGetState (osThreadId thread_id) {
}
#endif
/// Get the requested info from the specified active thread
os_InRegs osEvent osThreadGetInfo(osThreadId thread_id, osThreadInfo info) {
osEvent ret;
if (__exceptional_mode()) {
ret.status = osErrorISR;
return ret; // Not allowed in ISR
}
return __svcThreadGetInfo(thread_id, info);
}
osThreadEnumId osThreadsEnumStart() {
static uint32_t thread_enum_index;
osMutexWait(osMutexId_osThreadMutex, osWaitForever);

View File

@ -85,6 +85,7 @@ typedef struct OS_TCB {
/* Task entry point used for uVision debugger */
FUNCP ptask; /* Task entry address */
void *argv; /* Task argument */
} *P_TCB;
#define TCB_TID 3 /* 'task id' offset */
#define TCB_STACKF 37 /* 'stack_frame' offset */

View File

@ -160,6 +160,16 @@ typedef enum {
osTimerPeriodic = 1 ///< repeating timer
} os_timer_type;
typedef enum {
osThreadInfoState,
osThreadInfoStackSize,
osThreadInfoStackMax,
osThreadInfoEntry,
osThreadInfoArg,
osThreadInfo_reserved = 0x7FFFFFFF ///< prevent from enum down-size compiler optimization.
} osThreadInfo;
/// Entry point of a thread.
typedef void (*os_pthread) (void const *argument);
@ -361,6 +371,13 @@ osPriority osThreadGetPriority (osThreadId thread_id);
uint8_t osThreadGetState (osThreadId thread_id);
#endif
/// Get into from an active thread.
/// \param[in] thread_id thread ID obtained by \ref osThreadCreate or \ref osThreadGetId.
/// \param[in] info information to read.
/// \return current state of the thread function.
/// \return requested info that includes the status code.
os_InRegs osEvent osThreadGetInfo(osThreadId thread_id, osThreadInfo info);
// ==== Generic Wait Functions ====
/// Wait for Timeout (Time Delay).

View File

@ -637,6 +637,7 @@ SVC_1_1(svcThreadTerminate, osStatus, osThreadId, RET
SVC_0_1(svcThreadYield, osStatus, RET_osStatus)
SVC_2_1(svcThreadSetPriority, osStatus, osThreadId, osPriority, RET_osStatus)
SVC_1_1(svcThreadGetPriority, osPriority, osThreadId, RET_osPriority)
SVC_2_3(svcThreadGetInfo, os_InRegs osEvent, osThreadId, osThreadInfo, RET_osEvent)
// Thread Service Calls
@ -796,6 +797,67 @@ osPriority svcThreadGetPriority (osThreadId thread_id) {
return (osPriority)(ptcb->prio - 1 + osPriorityIdle);
}
/// Get info from an active thread
os_InRegs osEvent_type svcThreadGetInfo (osThreadId thread_id, osThreadInfo info) {
P_TCB ptcb;
osEvent ret;
ret.status = osOK;
ptcb = rt_tid2ptcb(thread_id); // Get TCB pointer
if (ptcb == NULL) {
ret.status = osErrorValue;
return osEvent_ret_status;
}
if (osThreadInfoStackSize == info) {
uint32_t size;
size = ptcb->priv_stack;
if (0 == size) {
// This is an OS task - always a fixed size
size = os_stackinfo & 0x3FFFF;
}
ret.value.v = size;
return osEvent_ret_value;
}
if (osThreadInfoStackMax == info) {
uint32_t i;
uint32_t *stack_ptr;
uint32_t stack_size;
if (!(os_stackinfo & (1 << 28))) {
// Stack init must be turned on for max stack usage
ret.status = osErrorResource;
return osEvent_ret_status;
}
stack_ptr = (uint32_t*)ptcb->stack;
stack_size = ptcb->priv_stack;
if (0 == stack_size) {
// This is an OS task - always a fixed size
stack_size = os_stackinfo & 0x3FFFF;
}
for (i = 1; i <stack_size / 4; i++) {
if (stack_ptr[i] != MAGIC_PATTERN) {
break;
}
}
ret.value.v = stack_size - i * 4;
return osEvent_ret_value;
}
if (osThreadInfoEntry == info) {
ret.value.p = (void*)ptcb->ptask;
return osEvent_ret_value;
}
if (osThreadInfoArg == info) {
ret.value.p = (void*)ptcb->argv;
return osEvent_ret_value;
}
// Unsupported option so return error
ret.status = osErrorParameter;
return osEvent_ret_status;
}
// Thread Public API
@ -890,6 +952,17 @@ uint8_t osThreadGetState (osThreadId thread_id) {
}
#endif
/// Get the requested info from the specified active thread
os_InRegs osEvent osThreadGetInfo(osThreadId thread_id, osThreadInfo info) {
osEvent ret;
if (__get_IPSR() != 0U) { // Not allowed in ISR
ret.status = osErrorISR;
return ret;
}
return __svcThreadGetInfo(thread_id, info);
}
osThreadEnumId osThreadsEnumStart() {
static uint32_t thread_enum_index;
osMutexWait(osMutexId_osThreadMutex, osWaitForever);

View File

@ -247,6 +247,7 @@ OS_TID rt_tsk_create (FUNCP task, U32 prio_stksz, void *stk, void *argv) {
task_context->task_id = (U8)i;
/* Pass parameter 'argv' to 'rt_init_context' */
task_context->msg = argv;
task_context->argv = argv;
/* For 'size == 0' system allocates the user stack from the memory pool. */
rt_init_context (task_context, (U8)(prio_stksz & 0xFFU), task);

View File

@ -79,6 +79,7 @@ typedef struct OS_TCB {
/* Task entry point used for uVision debugger */
FUNCP ptask; /* Task entry address */
void *argv; /* Task argument */
void *context; /* Pointer to thread context */
} *P_TCB;
#define TCB_STACKF 37 /* 'stack_frame' offset */