This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Scheduler tries to run a task which does not exist

Other Parts Discussed in Thread: TMS320F28069, SYSBIOS

I am using SYS/BIOS on a TMS320F28069 for a complex motor control application. It consists of several tasks, SWIs, HWIs and one "low latency" ISR.

The tasks are waiting on semaphores for most of the time, until the semaphore receives a post by either a SWI or HWI.

After adding another task to the application to service the I2C bus, and a SWI to periodically trigger this task, the application would experience what CCS is reporting as a stack overflow in a thread which does not exist. Debugging showed that the address which is reported as the task experiencing the stack overflow is actually the address of 

_ti_sysbios_knl_Task_Module_State_0_readyQ__A[9]

It seems that the scheduler determines that a thread with priority 9 (10?) is ready to run, however there is no thread with this priority in the application. As there is no such thread, the element in the ready queue points to itself, resulting in the scheduler feeding completely wrong information to the function which checks for stack overflows.

Two more observations:

There is another task in the application which is called every tick (via sem_post from SWI). If I change this task's SWI clock period from 1 to 2, the problem seems to go away.

When I change the period for the I2C task's SWI from 2000 ticks to 3000 ticks, the problem seems to go away.

The workload of the tasks in question has no influence on the problem (I removed all workload and it didn't change anything).

What I need to know is the exact moment when the scheduler makes the wrong decision about what thread has to be executed next, so I can trace what is happening in my application.

Additional information:

CCS 5.2.1.00018 

SYS/BIOS 6.33.04.39

XDCTOOLS 3.23.03.53

Compiler TI v6.1.0

Any help would be greatly appreciated!

Thanks

Torben Frenzel

  • Torben,

    I'm immediately suspicious of the "low latency" ISR you mention.

    Low latency ISRs must not post Swis or Semaphores since by definition they do not honor any critical section protection and will thus corrupt the SYS/BIOS kernel data structures. This usually leads to fatal task scheduling behavior.

    Alan

  • Alan,

    The ISR doesn't use any SYS/BIOS APIs. However, I tried disabling it and the scheduling problem went away. I guess there might be some interaction between the ISR and the scheduler, but I still can not pinpoint the exact moment that leads to the scheduler trying to run a non-existing task.

    Regards,

    Torben

  • Does the ISR call rand(), printf(), System_printf()?

    These APIs have Semaphore-based thread protecting lock/unlock calls within them.

    Alan

  • It does not. In fact, it doesn't use any APIs at all, except macros from the motor control library. 

    I tried minimizing the impact the ISR has on program flow by immediately acknowledging the interrupt and returning, and again, the problem went away.

    My current hypothesis is that the ISR somehow corrupts a memory address or a processor register, leading to the scheduler operating on wrong values. Is it possible for an ISR which has been registered with Hwi_plug() to interrupt the scheduler?

  • Torben,

    Can you provide more detail about how you are setting up the low latency ISR?

    Are you configuring the Hwi.zeroLatencyIERMask such that you ISR is never disabled?

    Or are you simply using Hwi_plug() to plug the vector table with your ISR function?

    And in either case, are you using the 'interrupt' key word when you define your ISR function?

    If not, what register context save/restore mechanism are you using to preserve the background thread's context while your ISR is running?

    Alan

  • I am simply using Hwi_plug(). The Hwi.zeroLatencyIERMask is not configured, it doesn't show in the .cfg source and in the GUI it is set to 0x0. I do use the 'interrupt' keyword, which is why I didn't take any other measures to save/restore the processor context.

  • Hmm. I would expect the 'interrupt' keyword to do a proper job of preserving the processor state.

    Does your ISR call any assembly code that may not follow the C register usage conventions shown in section 7.2 of the compiler user's manual?:

        http://www.ti.com/lit/ug/spru514e/spru514e.pdf

    Alan

  • You can use the CCS register view and strategically placed breakpoints to help confirm whether the ISR function is properly restoring the register state.

    Set a breakpoint at the first instruction of your ISR and another at the 'iret' instruction which you should find at the end of the function.

    When execution stops at the entry to your ISR, open the register view and then run to the second breakpoint.

    At this point, apart from the PC, SP, and a few bits in ST0/ST1, there should be NO REGISTER CONTENTS SHOWN IN RED (ie indicating they are different than they were upon entry to the ISR).

    Alan

  • The biggest problem I have with debugging this is that every little change has the potential to make the problem go away. However, I don't just want it to vanish, I need to understand what happens so it I can make sure it doesn't happen under other circumstances.

    I had a look at the registers at the beginning and the end of my ISR, and they don't seem to change. However, the ISR is called every 50us whereas the "stack overflow" occurs only after a few seconds, the I can't keep stepping through breakpoints until then. Especially as I have to enable the HW BP at the beginning of the ISR, run to it, disable it, enable the HW BP at the end, run to it, and repeat. If I use a SW BP, the problem doesn't show up (I ran it with the SW BP disabled but in the code and it worked fine). And even if I did step the 1000 or so times from one BP to the other, I can't be sure I will catch the problem.

    Right now I need to know one thing: is it possible for an ISR to preempt the scheduler? Part of the routine deciding which thread to run next is written in assembler (_ti_sysbios_family_c28_IntrinsicsSupport_maxbit__E) and uses the ACC.AL register for passing it's result. Could the ISR change this register, because it doesn't seem to be saved on the stack (is that even possible?).

    If the ISR cannot preempt the scheduler, I think I need to investigate other possibilities.

    Thanks,

    Torben

  • Torben,

    Yes it can. But since you are not running the ISR in the "Zero Latency" mode, the ISR can only pre-empt the scheduler in non-critical sections of the scheduler code (ie in places where interrupts are purposely NOT globally disabled).

    Is there any chance you are simply blowing the ISR stack with nested interrupts? What size of ISR (Hwi) stack have you configured? Can/does your 50us interrupt nest itself if it gets delayed for any reason?

    Alan

  • Alan,

    the HWI stack is not the issue. I placed a HW watchpoint at the top of the stack and it was never hit.

    However, while debugging I activated asserts in the SYS/BIOS library and was made aware of the fact that I called Semaphore_pend() from SWI context, which apparently isn't allowed.

    I need this semaphore to protect a shared object, so I rewrote the code to move the _pend() call to task context. The application has been running for a while now without problems.

    Now I'm wondering: could this call to Semaphore_pend() have been the cause of the problem all along? Or is it just coincidence, like a SW breakpoint upsetting the program flow in such a way that the problem doesn't show...

    Torben

  • Calling Semaphore_pend() from within ANY ISR thread, even those managed by SYS/BIOS, is usually fatal.

    It will result in the task that was interrupted by the ISR to be blocked and not returned to.

    When called from a non-SYS/BIOS-managed ISR, it may cause an immediate context switch into a task thread, while corrupting the interrupted task's stack in the process.

    Alan

  • Alan,

    thank you very much for your support. I am still not 100% sure what happened, but the problem occurred first after I made the changes including the illegal call to Semaphore_pend() and the program has been running for 24+ hours after removing it, so I am certain that it was the cause.

    Thanks

    Torben Frenzel

  • Dear Alan

    My customer got issues on SYS/BIOS driver when interrupt between different tasks so they decided to use non-SYS/BIOS-managed ISR.

    Is there anything I should be careful if I use non-SYS/BIOS-managed ISR under TI RTOS?

    Is there any document or information can share with me?

    Thanks for your support.

  • Please open a new thread for this new question.

    An ISR not managed by SYS/BIOS should not invoke ANY SYS/BIOS APIs.

    Otherwise unpredictable and most likely catastrophic things will occur.

    Alan