Skip to content

Commit ad24b7d

Browse files
committed
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.
1 parent e9d0fbd commit ad24b7d

File tree

4 files changed

+154
-6
lines changed

4 files changed

+154
-6
lines changed

rtos/rtx/TARGET_CORTEX_A/cmsis_os.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ used throughout the whole project.
160160
#define osFeature_Semaphore 65535 ///< maximum count for \ref osSemaphoreCreate function
161161
#define osFeature_Wait 0 ///< osWait function: 1=available, 0=not available
162162
#define osFeature_SysTick 1 ///< osKernelSysTick functions: 1=available, 0=not available
163+
#define osFeature_ThreadEnum 1 ///< Thread enumeration available
163164

164165
#if defined (__CC_ARM)
165166
#define os_InRegs __value_in_regs // Compiler specific: force struct in registers
@@ -261,6 +262,8 @@ typedef struct os_messageQ_cb *osMessageQId;
261262
/// \note CAN BE CHANGED: \b os_mailQ_cb is implementation specific in every CMSIS-RTOS.
262263
typedef struct os_mailQ_cb *osMailQId;
263264

265+
/// Thread enumeration ID identifies the enumeration (pointer to a thread enumeration control block).
266+
typedef uint32_t *osThreadEnumId;
264267

265268
/// Thread Definition structure contains startup information of a thread.
266269
/// \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);
823826
#endif // Mail Queues available
824827

825828

829+
// ==== Thread Enumeration Functions ====
830+
831+
#if (defined (osFeature_ThreadEnum) && (osFeature_ThreadEnum != 0)) // Thread enumeration available
832+
833+
/// Start a thread enumeration.
834+
/// \return an enumeration ID or NULL on error.
835+
osThreadEnumId osThreadsEnumStart(void);
836+
837+
/// Get the next task ID in the enumeration.
838+
/// \return a thread ID or NULL on if the end of the enumeration has been reached.
839+
osThreadId osThreadEnumNext(osThreadEnumId enum_id);
840+
841+
/// Free the enumeration structure.
842+
/// \param[in] enum_id pointer to the enumeration ID that was obtained with \ref osThreadsEnumStart.
843+
/// \return status code that indicates the execution status of the function.
844+
osStatus osThreadEnumFree(osThreadEnumId enum_id);
845+
846+
#endif // Thread Enumeration available
847+
848+
826849
// ==== RTX Extensions ====
827850

828851
/// os_suspend: http://www.keil.com/support/man/docs/rlarm/rlarm_os_suspend.htm

rtos/rtx/TARGET_CORTEX_A/rt_CMSIS.c

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,9 @@ extern osMessageQId osMessageQId_osTimerMessageQ;
479479

480480
extern U32 IRQNestLevel; /* Indicates whether inside an ISR, and the depth of nesting. 0 = not in ISR. */
481481

482+
// Thread creation and destruction mutex
483+
osMutexDef(osThreadMutex);
484+
osMutexId osMutexId_osThreadMutex;
482485

483486
// ==== Helper Functions ====
484487

@@ -596,6 +599,8 @@ osStatus svcKernelInitialize (void) {
596599
// Create OS Timers resources (Message Queue & Thread)
597600
osMessageQId_osTimerMessageQ = svcMessageCreate (&os_messageQ_def_osTimerMessageQ, NULL);
598601
osThreadId_osTimerThread = svcThreadCreate(&os_thread_def_osTimerThread, NULL);
602+
// Initialize thread mutex
603+
osMutexId_osThreadMutex = osMutexCreate(osMutex(osThreadMutex));
599604
}
600605

601606
sysThreadError(osOK);
@@ -856,7 +861,12 @@ osThreadId osThreadCreate (const osThreadDef_t *thread_def, void *argument) {
856861
// Privileged and not running
857862
return svcThreadCreate(thread_def, argument);
858863
} else {
859-
return __svcThreadCreate(thread_def, argument);
864+
osThreadId id;
865+
osMutexWait(osMutexId_osThreadMutex, osWaitForever);
866+
// Thread mutex must be held when a thread is created or terminated
867+
id = __svcThreadCreate(thread_def, argument);
868+
osMutexRelease(osMutexId_osThreadMutex);
869+
return id;
860870
}
861871
}
862872

@@ -868,8 +878,13 @@ osThreadId osThreadGetId (void) {
868878

869879
/// Terminate execution of a thread and remove it from ActiveThreads
870880
osStatus osThreadTerminate (osThreadId thread_id) {
881+
osStatus status;
871882
if (__exceptional_mode()) return osErrorISR; // Not allowed in ISR
872-
return __svcThreadTerminate(thread_id);
883+
osMutexWait(osMutexId_osThreadMutex, osWaitForever);
884+
// Thread mutex must be held when a thread is created or terminated
885+
status = __svcThreadTerminate(thread_id);
886+
osMutexRelease(osMutexId_osThreadMutex);
887+
return status;
873888
}
874889

875890
/// Pass control to next thread that is in state READY
@@ -893,6 +908,10 @@ osPriority osThreadGetPriority (osThreadId thread_id) {
893908
/// INTERNAL - Not Public
894909
/// Auto Terminate Thread on exit (used implicitly when thread exists)
895910
__NO_RETURN void osThreadExit (void) {
911+
// Thread mutex must be held when a thread is created or terminated
912+
// Note - the mutex will be released automatically by the os when
913+
// the thread is terminated
914+
osMutexWait(osMutexId_osThreadMutex, osWaitForever);
896915
__svcThreadTerminate(__svcThreadGetId());
897916
for (;;); // Should never come here
898917
}
@@ -911,6 +930,38 @@ uint8_t osThreadGetState (osThreadId thread_id) {
911930
}
912931
#endif
913932

933+
osThreadEnumId osThreadsEnumStart() {
934+
static uint32_t thread_enum_index;
935+
osMutexWait(osMutexId_osThreadMutex, osWaitForever);
936+
thread_enum_index = 0;
937+
return &thread_enum_index;
938+
}
939+
940+
osThreadId osThreadEnumNext(osThreadEnumId enum_id) {
941+
uint32_t i;
942+
osThreadId id = NULL;
943+
uint32_t *index = (uint32_t*)enum_id;
944+
for (i = *index; i < os_maxtaskrun; i++) {
945+
if (os_active_TCB[i] != NULL) {
946+
id = (osThreadId)os_active_TCB[i];
947+
break;
948+
}
949+
}
950+
if (i == os_maxtaskrun) {
951+
// Include the idle task at the end of the enumeration
952+
id = &os_idle_TCB;
953+
}
954+
*index = i + 1;
955+
return id;
956+
}
957+
958+
osStatus osThreadEnumFree(osThreadEnumId enum_id) {
959+
uint32_t *index = (uint32_t*)enum_id;
960+
*index = 0;
961+
osMutexRelease(osMutexId_osThreadMutex);
962+
return osOK;
963+
}
964+
914965
// ==== Generic Wait Functions ====
915966

916967
// Generic Wait Service Calls declarations

rtos/rtx/TARGET_CORTEX_M/cmsis_os.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@
9999
#define osFeature_Semaphore 65535 ///< Maximum count for \ref osSemaphoreCreate function
100100
#define osFeature_Wait 0 ///< osWait not available
101101
#define osFeature_SysTick 1 ///< osKernelSysTick functions available
102+
#define osFeature_ThreadEnum 1 ///< Thread enumeration available
102103

103104
#if defined (__CC_ARM)
104105
#define os_InRegs __value_in_regs // Compiler specific: force struct in registers
@@ -188,6 +189,8 @@ typedef struct os_messageQ_cb *osMessageQId;
188189
/// Mail ID identifies the mail queue (pointer to a mail queue control block).
189190
typedef struct os_mailQ_cb *osMailQId;
190191

192+
/// Thread enumeration ID identifies the enumeration (pointer to a thread enumeration control block).
193+
typedef uint32_t *osThreadEnumId;
191194

192195
/// Thread Definition structure contains startup information of a thread.
193196
typedef struct os_thread_def {
@@ -680,6 +683,26 @@ osStatus osMailFree (osMailQId queue_id, void *mail);
680683
#endif // Mail Queues available
681684

682685

686+
// ==== Thread Enumeration Functions ====
687+
688+
#if (defined (osFeature_ThreadEnum) && (osFeature_ThreadEnum != 0)) // Thread enumeration available
689+
690+
/// Start a thread enumeration.
691+
/// \return an enumeration ID or NULL on error.
692+
osThreadEnumId osThreadsEnumStart(void);
693+
694+
/// Get the next task ID in the enumeration.
695+
/// \return a thread ID or NULL on if the end of the enumeration has been reached.
696+
osThreadId osThreadEnumNext(osThreadEnumId enum_id);
697+
698+
/// Free the enumeration structure.
699+
/// \param[in] enum_id pointer to the enumeration ID that was obtained with \ref osThreadsEnumStart.
700+
/// \return status code that indicates the execution status of the function.
701+
osStatus osThreadEnumFree(osThreadEnumId enum_id);
702+
703+
#endif // Thread Enumeration available
704+
705+
683706
// ==== RTX Extensions ====
684707

685708
/// Suspend the RTX task scheduler.

rtos/rtx/TARGET_CORTEX_M/rt_CMSIS.c

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,9 @@ extern osThreadId osThreadId_osTimerThread;
392392
extern const osMessageQDef_t os_messageQ_def_osTimerMessageQ;
393393
extern osMessageQId osMessageQId_osTimerMessageQ;
394394

395+
// Thread creation and destruction mutex
396+
osMutexDef(osThreadMutex);
397+
osMutexId osMutexId_osThreadMutex;
395398

396399
// ==== Helper Functions ====
397400

@@ -490,6 +493,8 @@ osStatus svcKernelInitialize (void) {
490493
// Create OS Timers resources (Message Queue & Thread)
491494
osMessageQId_osTimerMessageQ = svcMessageCreate (&os_messageQ_def_osTimerMessageQ, NULL);
492495
osThreadId_osTimerThread = svcThreadCreate(&os_thread_def_osTimerThread, NULL, NULL);
496+
// Initialize thread mutex
497+
osMutexId_osThreadMutex = osMutexCreate(osMutex(osThreadMutex));
493498
}
494499

495500
sysThreadError(osOK);
@@ -806,7 +811,12 @@ osThreadId osThreadContextCreate (const osThreadDef_t *thread_def, void *argumen
806811
// Privileged and not running
807812
return svcThreadCreate(thread_def, argument, context);
808813
} else {
809-
return __svcThreadCreate(thread_def, argument, context);
814+
osThreadId id;
815+
osMutexWait(osMutexId_osThreadMutex, osWaitForever);
816+
// Thread mutex must be held when a thread is created or terminated
817+
id = __svcThreadCreate(thread_def, argument, context);
818+
osMutexRelease(osMutexId_osThreadMutex);
819+
return id;
810820
}
811821
}
812822

@@ -820,10 +830,15 @@ osThreadId osThreadGetId (void) {
820830

821831
/// Terminate execution of a thread and remove it from ActiveThreads
822832
osStatus osThreadTerminate (osThreadId thread_id) {
833+
osStatus status;
823834
if (__get_IPSR() != 0U) {
824835
return osErrorISR; // Not allowed in ISR
825836
}
826-
return __svcThreadTerminate(thread_id);
837+
osMutexWait(osMutexId_osThreadMutex, osWaitForever);
838+
// Thread mutex must be held when a thread is created or terminated
839+
status = __svcThreadTerminate(thread_id);
840+
osMutexRelease(osMutexId_osThreadMutex);
841+
return status;
827842
}
828843

829844
/// Pass control to next thread that is in state READY
@@ -852,8 +867,12 @@ osPriority osThreadGetPriority (osThreadId thread_id) {
852867

853868
/// INTERNAL - Not Public
854869
/// Auto Terminate Thread on exit (used implicitly when thread exists)
855-
__NO_RETURN void osThreadExit (void) {
856-
__svcThreadTerminate(__svcThreadGetId());
870+
__NO_RETURN void osThreadExit (void) {
871+
// Thread mutex must be held when a thread is created or terminated
872+
// Note - the mutex will be released automatically by the os when
873+
// the thread is terminated
874+
osMutexWait(osMutexId_osThreadMutex, osWaitForever);
875+
__svcThreadTerminate(__svcThreadGetId());
857876
for (;;); // Should never come here
858877
}
859878

@@ -871,6 +890,38 @@ uint8_t osThreadGetState (osThreadId thread_id) {
871890
}
872891
#endif
873892

893+
osThreadEnumId osThreadsEnumStart() {
894+
static uint32_t thread_enum_index;
895+
osMutexWait(osMutexId_osThreadMutex, osWaitForever);
896+
thread_enum_index = 0;
897+
return &thread_enum_index;
898+
}
899+
900+
osThreadId osThreadEnumNext(osThreadEnumId enum_id) {
901+
uint32_t i;
902+
osThreadId id = NULL;
903+
uint32_t *index = (uint32_t*)enum_id;
904+
for (i = *index; i < os_maxtaskrun; i++) {
905+
if (os_active_TCB[i] != NULL) {
906+
id = (osThreadId)os_active_TCB[i];
907+
break;
908+
}
909+
}
910+
if (i == os_maxtaskrun) {
911+
// Include the idle task at the end of the enumeration
912+
id = &os_idle_TCB;
913+
}
914+
*index = i + 1;
915+
return id;
916+
}
917+
918+
osStatus osThreadEnumFree(osThreadEnumId enum_id) {
919+
uint32_t *index = (uint32_t*)enum_id;
920+
*index = 0;
921+
osMutexRelease(osMutexId_osThreadMutex);
922+
return osOK;
923+
}
924+
874925
// ==== Generic Wait Functions ====
875926

876927
// Generic Wait Service Calls declarations

0 commit comments

Comments
 (0)