Skip to content

Commit 6878549

Browse files
committed
Cleanup thread suspension code
Previously I was using the osThreadSuspend() and osThreadResume() APIs to freeze and thaw the application threads during debug halt. I code reviewed the RTX implementation of osThreadResume() and noticed that it incorrectly resumed previously waiting threads to the ready state. The code now suspends the application threads by lowering their priority to osPriorityIdle and then elevating the priority of the idle thread to osPriorityIdle+1 so the idle thread runs instead of an application thread if a debugger related thread blocks. I would have liked to use priority level 0 for the application threads which would have placed them below the idle thread but the osThreadSetPriority() API returns an error for this. I now run the mriMain() thread at osPriorityISR while it is suspending and resuming application threads as it is the highest priority level accepted by the osThreadSetPriority(). Always resume all threads when leaving debug halt mode, even when single stepping. Previously it only thawed the single stepping thread but that didn't match the GDB remote stub specification for stop mode debugging.
1 parent da8ed66 commit 6878549

File tree

1 file changed

+44
-19
lines changed

1 file changed

+44
-19
lines changed

libraries/ThreadDebug/src/ThreadDebug.cpp

Lines changed: 44 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ extern "C"
4848
// Typically these will be threads used by the communication stack to communicate with GDB or other important system
4949
// threads.
5050
static const char* g_threadNamesToIgnore[] = {
51-
"rtx_idle"
5251
};
5352

5453

@@ -88,6 +87,17 @@ static const char* g_threadNamesToIgnore[] = {
8887

8988

9089

90+
// Structure used to store a 'suspended' thread's original priority settings (current and base) so that they can be
91+
// later restored.
92+
struct ThreadPriority
93+
{
94+
int8_t priority;
95+
int8_t basePriority;
96+
};
97+
98+
99+
100+
91101
// Globals that describe the ThreadDebug singleton.
92102
static DebugCommInterface* g_pComm;
93103
static bool g_breakInSetup;
@@ -98,15 +108,17 @@ static volatile osThreadId_t g_haltedThreadId;
98108
// The list of threads which were suspended upon entry into the debugger. These are the threads that will be resumed
99109
// upon exit from the debugger.
100110
static osThreadId_t g_suspendedThreads[MAXIMUM_ACTIVE_THREADS];
101-
// The state of each thread before being suspended.
102-
static uint8_t g_threadStates[MAXIMUM_ACTIVE_THREADS];
111+
// The priorities (current and base) of each thread modified to suspend application threads when halting in debugger.
112+
static ThreadPriority g_threadPriorities[MAXIMUM_ACTIVE_THREADS];
103113
// The number of active threads that were placed in g_suspendedThreads. Some of those entries may be NULL if they were
104114
// important enough to not be suspended.
105115
static uint32_t g_threadCount;
106116
// The current index into the g_suspendedThreads array being returned from Platform_RtosGetFirstThread.
107117
static uint32_t g_threadIndex;
108118
// Buffer to be used for storing extra thread info.
109119
static char g_threadExtraInfo[64];
120+
// The ID of the rtx_idle thread to be skipped when providing list of threads to GDB.
121+
static osThreadId_t g_idleThread;
110122

111123
// This flag is set to a non-zero value if the DebugMon handler is to re-enable DWT watchpoints and FPB breakpoints
112124
// after being disabled by the HardFault handler when a debug event is encounted in handler mode.
@@ -185,6 +197,7 @@ static void wakeMriMainToDebugCurrentThread();
185197
static void stopSingleStepping();
186198
static void recordAndSwitchFaultHandlersToDebugger();
187199
static void skipNullThreadIds();
200+
static bool isNullOrIdleThread(osThreadId_t threadId);
188201
static const char* getThreadStateName(uint8_t threadState);
189202
static bool isDebugThreadActive();
190203
static void setFaultDetectedFlag();
@@ -236,7 +249,7 @@ static __NO_RETURN void mriMain(void *pv)
236249
{
237250
// Run the code which suspends, resumes, etc the other threads at highest priority so that it doesn't context
238251
// switch to one of the other threads. Switch to normal priority when running mriDebugException() though.
239-
osThreadSetPriority(osThreadGetId(), osPriorityRealtime7);
252+
osThreadSetPriority(osThreadGetId(), osPriorityISR);
240253

241254
while (1) {
242255
int waitResult = osThreadFlagsWait(MRI_THREAD_DEBUG_EVENT_FLAG, osFlagsWaitAny, osWaitForever);
@@ -250,32 +263,42 @@ static __NO_RETURN void mriMain(void *pv)
250263

251264
osThreadSetPriority(osThreadGetId(), osPriorityNormal);
252265
mriDebugException(&mriCortexMState.context);
253-
osThreadSetPriority(osThreadGetId(), osPriorityRealtime7);
266+
osThreadSetPriority(osThreadGetId(), osPriorityISR);
254267

255268
if (Platform_IsSingleStepping()) {
256269
mriThreadSingleStepThreadId = g_haltedThreadId;
257270
switchRtxHandlersToDebugStubsForSingleStepping();
258-
osThreadResume(mriThreadSingleStepThreadId);
259-
} else {
260-
resumeApplicationThreads();
261271
}
272+
resumeApplicationThreads();
262273
g_haltedThreadId = 0;
263274
}
264275
}
265276

266277
static void suspendAllApplicationThreads()
267278
{
279+
// Suspend application threads by setting their priorities to the lowest setting, osPriorityIdle.
280+
// Bump rtx_idle thread up one priority level so that it will run instead of the 'suspended' application threads if
281+
// the debug related threads go idle.
282+
g_idleThread = 0;
268283
g_threadCount = osThreadGetCount();
269284
ASSERT ( g_threadCount <= ARRAY_SIZE(g_suspendedThreads) );
270285
osThreadEnumerate(g_suspendedThreads, ARRAY_SIZE(g_suspendedThreads));
271286
for (uint32_t i = 0 ; i < g_threadCount ; i++) {
272287
osThreadId_t thread = g_suspendedThreads[i];
288+
osPriority_t newPriority = osPriorityIdle;
289+
const char* pThreadName = osThreadGetName(thread);
290+
if (strcmp(pThreadName, "rtx_idle") == 0) {
291+
newPriority = (osPriority_t)(osPriorityIdle + 1);
292+
g_idleThread = thread;
293+
}
294+
273295
if (isThreadToIgnore(thread)) {
274296
g_suspendedThreads[i] = 0;
275297
} else {
276298
osRtxThread_t* pThread = (osRtxThread_t*)thread;
277-
g_threadStates[i] = pThread->state;
278-
osThreadSuspend(thread);
299+
g_threadPriorities[i].basePriority = pThread->priority_base;
300+
g_threadPriorities[i].priority = pThread->priority;
301+
osThreadSetPriority(thread, newPriority);
279302
}
280303
}
281304
}
@@ -301,7 +324,9 @@ static void resumeApplicationThreads()
301324
for (uint32_t i = 0 ; i < g_threadCount ; i++) {
302325
osThreadId_t thread = g_suspendedThreads[i];
303326
if (thread != 0) {
304-
osThreadResume(thread);
327+
osThreadSetPriority(thread, (osPriority_t)g_threadPriorities[i].priority);
328+
osRtxThread_t* pThread = (osRtxThread_t*)thread;
329+
pThread->priority_base = g_threadPriorities[i].basePriority;
305330
}
306331
}
307332
}
@@ -549,20 +574,20 @@ uint32_t Platform_RtosGetNextThreadId(void)
549574

550575
static void skipNullThreadIds()
551576
{
552-
while (g_threadIndex < g_threadCount && g_suspendedThreads[g_threadIndex] == 0)
577+
while (g_threadIndex < g_threadCount && isNullOrIdleThread(g_suspendedThreads[g_threadIndex]))
553578
g_threadIndex++;
554579
}
555580

581+
static bool isNullOrIdleThread(osThreadId_t threadId)
582+
{
583+
return threadId == 0 || threadId == g_idleThread;
584+
}
585+
556586
const char* Platform_RtosGetExtraThreadInfo(uint32_t threadId)
557587
{
558-
const char* pState = "";
559588
const char* pThreadName = osThreadGetName((osThreadId)threadId);
560-
for (uint32_t i = 0 ; i < g_threadCount ; i++) {
561-
if ((uint32_t)g_suspendedThreads[i] == threadId) {
562-
pState = getThreadStateName(g_threadStates[i]);
563-
break;
564-
}
565-
}
589+
osRtxThread_t* pThread = (osRtxThread_t*)threadId;
590+
const char* pState = getThreadStateName(pThread->state);
566591
snprintf(g_threadExtraInfo, sizeof(g_threadExtraInfo), "\"%s\" %s", pThreadName ? pThreadName : "", pState);
567592
return g_threadExtraInfo;
568593
}

0 commit comments

Comments
 (0)