1

I'm programming an application for an embedded device. We are using an RTOS that supports multi threading. The device is supposed to mimic an older project that was programmed in plain C (without threads).

The original project uses a stack and START / END functions at the beginning and end of each function that can be called throughout runtime. Each time START is called a constant number (identifying the function) will be put on the stack - END will remove it from the stack and check if the top is equal to the called function. If it is different something really bad has happened and the device will recover/reset.

This feature is great for debugging purposes as it fully displays how functions are called. It would be very lovely to have such a feature in the multi-threaded version.

I implemented START and END as a class in C++ using constructor and destructor which makes the handling fairly easy. Running this single-threaded works like a charm. Anything multithreaded will destroy the stack as the scheduler switches context and writing to one stack would not make sense.

The most basic solution in my mind would be having one START/END stack for each thread -> Problem each function has to know which threads it runs on. Is there a better solution to this problem?

  • 4
    hint: thread local storage – ratchet freak Aug 28 '14 at 8:49
  • great idea, unfortunately our compiler does not support C++11 :( – clambake Aug 28 '14 at 9:33
  • EDIT: It does not support C++11 but seems to support TLS. I'm having a deeper look. – clambake Aug 28 '14 at 9:34
  • 1
    Are the START/END numbers stored on the function call stack (the one that also holds the parameters & return addresses) or in a separate data structure with stack semantics? – Bart van Ingen Schenau Aug 28 '14 at 11:34
  • 1
    TLS has been around as long as threads, at least 20 years. Your compiler probably has a way, if you talk to it nicely. – david.pfx Aug 28 '14 at 14:33
1

(Please note that in the comments above, the OP mentioned the "stack" we're talking about isn't the call stack, it's a separate, dedicated stack for the purpose of call tracking)

We've already covered the concept of Thread Local Storage (TLS) in the comments above. If that's available and you want to use it, great.

Another approach is slightly more "roll your own", but I've used it with success. For now I'm assuming we're only talking about task-level function call tracking, although this method can be extended to ISRs too.

Most RTOSes provide the opportunity to run user-defined callout functions, or "hooks", at specific points, like entering & exiting ISRs, context switching into and out of a task, the timer tick, etc. For example, FreeRTOS provides a large set of [Trace Macros] (http://www.freertos.org/rtos-trace-macros.html) that let you instrument & trace your code (see traceTASK_SUSPEND(xTask) and traceTASK_RESUME(xTask), for example.)

Let's keep this simple. I hate globals, they are a source bugs, break good encapsulation, etc. That said, you could have a global variable:

FUNC_CALL_STK   *stack_ptr;

or whatever. Each time you switch into a task (using the RTOS' built in hook function), "stack_ptr" is set to the current task's "trace stack" position. Each time you switch out of the task (again, via RTOS hook), you store stack_ptr into the task's private stack pointer. Each task has its own private tracing stack & pointer into the current position.

Another alternative, which avoids using OS-supplied hook functions (I tend to favor this approach):

Each task would still have its own tracing stack & pointer, but this could be implemented as a lookup table of "stack pointers" (perhaps indexed by task ID or whatever), and just use those directly from task context to push & pop. Each task's tracing stack & stack pointer would be initialized at task init, before entering the task's "infinite loop". So for example, your START function would do something like:

PushCurrentFuncIdentifier(FuncId, GetCurrentTaskID());

GetCurrentTaskID() is an OS API that would return an integer which uniquely identifies the currently-running task (every RTOS has such an API). No matter if/when a context switch occurs, this should be thread-safe.

BTW, using your C++ class, the CTOR could save off the Task ID (TID) as a private member, and then the DTOR could use the cached TID instead of having to call the RTOS API again.

| improve this answer | |
  • 1
    the second approach is exactly what I was thinking of :). – clambake Sep 2 '14 at 6:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.