I have implemented a watchdog system, to overview my task and everything seems to work.
I can detect if a task is staying running over its time limits, and also trace the task who has the issue.
But for debug purposes i would like to know where in the code a given task is held up, and under what circumstance’s the task is held.
Theoretically, at least for an AMP/single-core system, when the watchdog task is active, it could peek into the stack frame of any task and see where it was running, and the stack trace back for how it got there. For a SMP system, since the task might still be running that doesn’t quite work, but you could modify the system to looking into the stack and retrieve the curr3nt PC address on a scheduler call, and then send a yield to the core it is running on and get that address, or force an analysis task to be scheduled on that core and see what it was doing.
For more than the current PC at the point it was suspended, the ability is largely theoretical, as it requires the knowledge and processing of the stack frames that the compiler build, and back linking through them, and likely processing that through a link map.
This is what a debugger does when it provides the stack trace back, so it gives you an idea of the complexity.
I have implemented a similar watchdog in my application. There is a simple solution to your problem : metadata.
When you update your watchdog, you must have some kind of function call which takes as an argument the expiry time after watch the watchdog even is triggered.
Replace this integer by a struct containing one or more extra fields with metadata, that you set in your task code prior to updating your watchdog timer. You can even use the macro __LINE__ as your metadata to know which line of code was the last WDT update.
Here’s some pseudo-code (incomplete, doesn’t handle rollovers, just to demonstrate the concept of carrying your metadata)
struct watchdog_entry
{
int expiry;
int metadata;
};
void updateWDT( int timeout, int metadata )
{
struct watchdog_entry * entry = findWDTEntryForCurrentTask();
entry->expiry = xTaskGetTickCount() + timeout;
entry->metadata = metadata;
}
void WDT_TASK()
{
struct watchdog_entry * entry;
while(1)
{
entry = NULL;
while ( NULL != (entry = getNextWDTEntry(entry)) )
{
if ( xTaskGetTickCount() > entry->expiry )
{
/* entry->metadata contains the location information */
}
}
}
}
void TASK_BEING_MONITORED()
{
int metadata = 0;
while(1)
{
metadata = 1;
updateWDT( 100, metadata );
/* some blocking calls 1 */
metadata = 2;
updateWDT( 100, metadata );
/* some blocking calls 2 */
}
}