mirror of https://github.com/ARMmbed/mbed-os.git
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
parent
ad24b7d982
commit
c319296692
|
|
@ -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).
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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).
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
Loading…
Reference in New Issue