Add RTX API to enumerate running threads

Add the functions osThreadsEnumStart, osThreadEnumNext and
osThreadEnumFree to allow enumeration of running threads. Protect
thread creation, thread exit and thread termination with a mutex
so threads are not created or destroyed while an enumeration is
ongoing.
pull/2642/head
Russ Butler 2016-09-07 00:37:56 -05:00 committed by Russ Butler
parent e9d0fbd178
commit ad24b7d982
4 changed files with 154 additions and 6 deletions

View File

@ -160,6 +160,7 @@ used throughout the whole project.
#define osFeature_Semaphore 65535 ///< maximum count for \ref osSemaphoreCreate function
#define osFeature_Wait 0 ///< osWait function: 1=available, 0=not available
#define osFeature_SysTick 1 ///< osKernelSysTick functions: 1=available, 0=not available
#define osFeature_ThreadEnum 1 ///< Thread enumeration available
#if defined (__CC_ARM)
#define os_InRegs __value_in_regs // Compiler specific: force struct in registers
@ -261,6 +262,8 @@ typedef struct os_messageQ_cb *osMessageQId;
/// \note CAN BE CHANGED: \b os_mailQ_cb is implementation specific in every CMSIS-RTOS.
typedef struct os_mailQ_cb *osMailQId;
/// Thread enumeration ID identifies the enumeration (pointer to a thread enumeration control block).
typedef uint32_t *osThreadEnumId;
/// Thread Definition structure contains startup information of a thread.
/// \note CAN BE CHANGED: \b os_thread_def is implementation specific in every CMSIS-RTOS.
@ -823,6 +826,26 @@ osStatus osMailFree (osMailQId queue_id, void *mail);
#endif // Mail Queues available
// ==== Thread Enumeration Functions ====
#if (defined (osFeature_ThreadEnum) && (osFeature_ThreadEnum != 0)) // Thread enumeration available
/// Start a thread enumeration.
/// \return an enumeration ID or NULL on error.
osThreadEnumId osThreadsEnumStart(void);
/// Get the next task ID in the enumeration.
/// \return a thread ID or NULL on if the end of the enumeration has been reached.
osThreadId osThreadEnumNext(osThreadEnumId enum_id);
/// Free the enumeration structure.
/// \param[in] enum_id pointer to the enumeration ID that was obtained with \ref osThreadsEnumStart.
/// \return status code that indicates the execution status of the function.
osStatus osThreadEnumFree(osThreadEnumId enum_id);
#endif // Thread Enumeration available
// ==== RTX Extensions ====
/// os_suspend: http://www.keil.com/support/man/docs/rlarm/rlarm_os_suspend.htm

View File

@ -479,6 +479,9 @@ extern osMessageQId osMessageQId_osTimerMessageQ;
extern U32 IRQNestLevel; /* Indicates whether inside an ISR, and the depth of nesting. 0 = not in ISR. */
// Thread creation and destruction mutex
osMutexDef(osThreadMutex);
osMutexId osMutexId_osThreadMutex;
// ==== Helper Functions ====
@ -596,6 +599,8 @@ osStatus svcKernelInitialize (void) {
// Create OS Timers resources (Message Queue & Thread)
osMessageQId_osTimerMessageQ = svcMessageCreate (&os_messageQ_def_osTimerMessageQ, NULL);
osThreadId_osTimerThread = svcThreadCreate(&os_thread_def_osTimerThread, NULL);
// Initialize thread mutex
osMutexId_osThreadMutex = osMutexCreate(osMutex(osThreadMutex));
}
sysThreadError(osOK);
@ -856,7 +861,12 @@ osThreadId osThreadCreate (const osThreadDef_t *thread_def, void *argument) {
// Privileged and not running
return svcThreadCreate(thread_def, argument);
} else {
return __svcThreadCreate(thread_def, argument);
osThreadId id;
osMutexWait(osMutexId_osThreadMutex, osWaitForever);
// Thread mutex must be held when a thread is created or terminated
id = __svcThreadCreate(thread_def, argument);
osMutexRelease(osMutexId_osThreadMutex);
return id;
}
}
@ -868,8 +878,13 @@ osThreadId osThreadGetId (void) {
/// Terminate execution of a thread and remove it from ActiveThreads
osStatus osThreadTerminate (osThreadId thread_id) {
osStatus status;
if (__exceptional_mode()) return osErrorISR; // Not allowed in ISR
return __svcThreadTerminate(thread_id);
osMutexWait(osMutexId_osThreadMutex, osWaitForever);
// Thread mutex must be held when a thread is created or terminated
status = __svcThreadTerminate(thread_id);
osMutexRelease(osMutexId_osThreadMutex);
return status;
}
/// Pass control to next thread that is in state READY
@ -893,6 +908,10 @@ osPriority osThreadGetPriority (osThreadId thread_id) {
/// INTERNAL - Not Public
/// Auto Terminate Thread on exit (used implicitly when thread exists)
__NO_RETURN void osThreadExit (void) {
// Thread mutex must be held when a thread is created or terminated
// Note - the mutex will be released automatically by the os when
// the thread is terminated
osMutexWait(osMutexId_osThreadMutex, osWaitForever);
__svcThreadTerminate(__svcThreadGetId());
for (;;); // Should never come here
}
@ -911,6 +930,38 @@ uint8_t osThreadGetState (osThreadId thread_id) {
}
#endif
osThreadEnumId osThreadsEnumStart() {
static uint32_t thread_enum_index;
osMutexWait(osMutexId_osThreadMutex, osWaitForever);
thread_enum_index = 0;
return &thread_enum_index;
}
osThreadId osThreadEnumNext(osThreadEnumId enum_id) {
uint32_t i;
osThreadId id = NULL;
uint32_t *index = (uint32_t*)enum_id;
for (i = *index; i < os_maxtaskrun; i++) {
if (os_active_TCB[i] != NULL) {
id = (osThreadId)os_active_TCB[i];
break;
}
}
if (i == os_maxtaskrun) {
// Include the idle task at the end of the enumeration
id = &os_idle_TCB;
}
*index = i + 1;
return id;
}
osStatus osThreadEnumFree(osThreadEnumId enum_id) {
uint32_t *index = (uint32_t*)enum_id;
*index = 0;
osMutexRelease(osMutexId_osThreadMutex);
return osOK;
}
// ==== Generic Wait Functions ====
// Generic Wait Service Calls declarations

View File

@ -99,6 +99,7 @@
#define osFeature_Semaphore 65535 ///< Maximum count for \ref osSemaphoreCreate function
#define osFeature_Wait 0 ///< osWait not available
#define osFeature_SysTick 1 ///< osKernelSysTick functions available
#define osFeature_ThreadEnum 1 ///< Thread enumeration available
#if defined (__CC_ARM)
#define os_InRegs __value_in_regs // Compiler specific: force struct in registers
@ -188,6 +189,8 @@ typedef struct os_messageQ_cb *osMessageQId;
/// Mail ID identifies the mail queue (pointer to a mail queue control block).
typedef struct os_mailQ_cb *osMailQId;
/// Thread enumeration ID identifies the enumeration (pointer to a thread enumeration control block).
typedef uint32_t *osThreadEnumId;
/// Thread Definition structure contains startup information of a thread.
typedef struct os_thread_def {
@ -680,6 +683,26 @@ osStatus osMailFree (osMailQId queue_id, void *mail);
#endif // Mail Queues available
// ==== Thread Enumeration Functions ====
#if (defined (osFeature_ThreadEnum) && (osFeature_ThreadEnum != 0)) // Thread enumeration available
/// Start a thread enumeration.
/// \return an enumeration ID or NULL on error.
osThreadEnumId osThreadsEnumStart(void);
/// Get the next task ID in the enumeration.
/// \return a thread ID or NULL on if the end of the enumeration has been reached.
osThreadId osThreadEnumNext(osThreadEnumId enum_id);
/// Free the enumeration structure.
/// \param[in] enum_id pointer to the enumeration ID that was obtained with \ref osThreadsEnumStart.
/// \return status code that indicates the execution status of the function.
osStatus osThreadEnumFree(osThreadEnumId enum_id);
#endif // Thread Enumeration available
// ==== RTX Extensions ====
/// Suspend the RTX task scheduler.

View File

@ -392,6 +392,9 @@ extern osThreadId osThreadId_osTimerThread;
extern const osMessageQDef_t os_messageQ_def_osTimerMessageQ;
extern osMessageQId osMessageQId_osTimerMessageQ;
// Thread creation and destruction mutex
osMutexDef(osThreadMutex);
osMutexId osMutexId_osThreadMutex;
// ==== Helper Functions ====
@ -490,6 +493,8 @@ osStatus svcKernelInitialize (void) {
// Create OS Timers resources (Message Queue & Thread)
osMessageQId_osTimerMessageQ = svcMessageCreate (&os_messageQ_def_osTimerMessageQ, NULL);
osThreadId_osTimerThread = svcThreadCreate(&os_thread_def_osTimerThread, NULL, NULL);
// Initialize thread mutex
osMutexId_osThreadMutex = osMutexCreate(osMutex(osThreadMutex));
}
sysThreadError(osOK);
@ -806,7 +811,12 @@ osThreadId osThreadContextCreate (const osThreadDef_t *thread_def, void *argumen
// Privileged and not running
return svcThreadCreate(thread_def, argument, context);
} else {
return __svcThreadCreate(thread_def, argument, context);
osThreadId id;
osMutexWait(osMutexId_osThreadMutex, osWaitForever);
// Thread mutex must be held when a thread is created or terminated
id = __svcThreadCreate(thread_def, argument, context);
osMutexRelease(osMutexId_osThreadMutex);
return id;
}
}
@ -820,10 +830,15 @@ osThreadId osThreadGetId (void) {
/// Terminate execution of a thread and remove it from ActiveThreads
osStatus osThreadTerminate (osThreadId thread_id) {
osStatus status;
if (__get_IPSR() != 0U) {
return osErrorISR; // Not allowed in ISR
}
return __svcThreadTerminate(thread_id);
osMutexWait(osMutexId_osThreadMutex, osWaitForever);
// Thread mutex must be held when a thread is created or terminated
status = __svcThreadTerminate(thread_id);
osMutexRelease(osMutexId_osThreadMutex);
return status;
}
/// Pass control to next thread that is in state READY
@ -852,8 +867,12 @@ osPriority osThreadGetPriority (osThreadId thread_id) {
/// INTERNAL - Not Public
/// Auto Terminate Thread on exit (used implicitly when thread exists)
__NO_RETURN void osThreadExit (void) {
__svcThreadTerminate(__svcThreadGetId());
__NO_RETURN void osThreadExit (void) {
// Thread mutex must be held when a thread is created or terminated
// Note - the mutex will be released automatically by the os when
// the thread is terminated
osMutexWait(osMutexId_osThreadMutex, osWaitForever);
__svcThreadTerminate(__svcThreadGetId());
for (;;); // Should never come here
}
@ -871,6 +890,38 @@ uint8_t osThreadGetState (osThreadId thread_id) {
}
#endif
osThreadEnumId osThreadsEnumStart() {
static uint32_t thread_enum_index;
osMutexWait(osMutexId_osThreadMutex, osWaitForever);
thread_enum_index = 0;
return &thread_enum_index;
}
osThreadId osThreadEnumNext(osThreadEnumId enum_id) {
uint32_t i;
osThreadId id = NULL;
uint32_t *index = (uint32_t*)enum_id;
for (i = *index; i < os_maxtaskrun; i++) {
if (os_active_TCB[i] != NULL) {
id = (osThreadId)os_active_TCB[i];
break;
}
}
if (i == os_maxtaskrun) {
// Include the idle task at the end of the enumeration
id = &os_idle_TCB;
}
*index = i + 1;
return id;
}
osStatus osThreadEnumFree(osThreadEnumId enum_id) {
uint32_t *index = (uint32_t*)enum_id;
*index = 0;
osMutexRelease(osMutexId_osThreadMutex);
return osOK;
}
// ==== Generic Wait Functions ====
// Generic Wait Service Calls declarations