Weird task switch after non-ISR call to xQueueReceive()

martin72216 wrote on Wednesday, October 30, 2013:

Hi I’m porting a small project from embOS to FreeRTOS. I’m running FreeRTOS on an STM32F207IG (STM3220G-EVAL) and I’m encountering some odd behavior with a semaphore I’m using to synchronize tasks. Task 1 (SPCRootTask) puts a command into Task 2’s (RedpineTask) command queue. Task 1 also increments a counting semaphore to signal that there is something to do. (The additional semaphore exists because there are more events that shall wake Task 2 besides a command.) The command contains another semaphore that is signalled by Task 2 as soon as command execution is finished. Task 1 waits for this semaphore. This is done to implement a synchronous interface for the services offered by Task 2.

Below you see Eclipse Debug output for the function that eventually calls “take()” on the command semaphore.

marTouchWireless Debug [GDB Hardware Debugging]	
    GDB Hardware Debugger (30.10.13 16:51) (Suspended)	
            Thread [1] (Suspended)	
                5 RedpineTask::queryFirmwareVersion() RedpineTask.cpp:761 0x080120b8	
                4 RedpineTask::redpineStartup() RedpineTask.cpp:2914 0x0801424e
                3 SPCRootTask::run() SPCRootTask.cpp:143 0x08014e0c	
                2 taskFunc() IRunnable.cpp:19 0x0800c81e	
                1 <symbol is not available> 0x00000000	
    arm-none-eabi-gdb (30.10.13 16:51)	

This call stack would be totally fine for Task 1 but according to pcGetTaskName() this is actually the call stack of Task 2.

This is the function I’m looking at in the debugger. Although it’s a method of the RedpineTask class it is meant to be called by other tasks (the sychronous interface i talked about). “PC->” marks the program counter…

SINT32 RedpineTask::queryFirmwareVersion(UINT8* pui8FwVersion) {
    ComQueryFirmwareVersion _command(this);
    deliverCommand(&_command); //puts command to queue, queue was empty before

    xTaskHandle curTask = xTaskGetCurrentTaskHandle(); //<--OOPS to show the effect
    signed char* task = pcTaskGetTaskName(curTask); //to show the effect
    _command.waitCompletion();//<--PC of debug window

    _command.getFirmwareVersion(pui8FwVersion); //i never get here due to the resulting deadlock
    return _command.getRetval();

When Task 1 calls the function above the command is delivered and the semaphore tells Task 2 to wake up. Task 2 wakes up and checks if there are any commands in the queue. It takes the command from the queue in a function collectCommand() similar to deliverDommand() which just puts the pointer passed to it into a defined byte order. As soon as this function returns I get thrown to the place marked with “OOPS”. Actually I get thrown to the next instruction right after “deliverCommand”. The debugger tells me that I’m executing in the context of SPCRootTask. However, looking at the string named task I see that the current task is “RedpineTask” (Task 2) which never calls “queryFirmwareVersion()”.

I hope this is some known issue that can be quickly resolved. I also want to add that I have been through all CM3 specifics and I think that my settings (full interrupt preemption, Kernel Prio 0xF0, Syscall Prio = API call Prio = 0xB0) should all be correct. I’m currently not using any interrupts besides the ones the portPackage enabled.



So it seems that a non-trivial mixup is happening somewhere

rtel wrote on Wednesday, October 30, 2013:

Wow - there is a lot to comprehend here. A few simple questions first:

  1. You say it deadlocks - but am I right in thinking it does not crash?

  2. Do you have stack overflow protection on?

  3. Are you generating task specific call stacks? If so, how? By default GDB will normally only show you the call stack of the currently executing task. [point of interest].

  4. Are you using the latest FreeRTOS version with configASSERT() defined? [some additional assert points were put in recently]


martin72216 wrote on Wednesday, October 30, 2013:

Hi Richard,

  1. Correct, no crash… Task 1 and Task 2 are both blocked so the Idle task is the only one running. This is because Task 2 is trying to take from the command semaphore, the one it should actually give;-) I know… a lot to understand. Here is a few lines of code that give you the other half of the picture.

    while (true) {
    // Wait for something to happen.

     // If there is a pending command we cannot service a further command. So
     // only if there is no further command we collect a new command from the
     // mailbox and execute it.
     if (!isCommandPending()) {
         if ((IRedpineCommand*) NULL != (_pRedpineCommand = collectCommand())) {
             SINT32 _si32Ret((SINT32) COMM_ERR_OK);
             pendingCommand = _pRedpineCommand;
             // if we have an error executing the command we immediately destroy the
             // command; handleResponse() discards unexpected commands, so this is no
             // problem.
             if (0 != (_si32Ret = pendingCommand->execute())) {
                 pendingCommand = (IRedpineCommand*) NULL;

  2. No stack overflow protection is in place however the code already ran on embOS using the same libc and the stacks are dimensioned with a 50% security margin

  3. No the call stacks are not task specific. I only have one Task callback (taskFunc()) which all task implementations use. They pass a this pointer as argument when creating the task. taskFunc() then calls the virtual run() method of the IRunnable() base class for all tasks. This is like the first hit when googling “FreeRTOS and C++”.

  4. I’m running FreeRTOS V7.5.2 which i downloaded about 6 weeks ago.

Thanks for taking interest.


martin72216 wrote on Wednesday, October 30, 2013:

I updated to the latest version and enabled stack overflow checking. The problem persists.

martin72216 wrote on Wednesday, October 30, 2013:

Nevermind, i mixed up the arguments for size and count when initializing the message queue, so the memcpy() in the queue messed up my stack… another 3 hrs worthlessly spent :wink:

rtel wrote on Wednesday, October 30, 2013:

Its a well known attribute of embedded system programming that the jobs you think are going to be hard take a few hours, and the jobs you think are going to take a few minutes take a few days.

Glad you got your problem fixed.