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.

RTOS/TI-RTOS: TSK_setPri problem

Part Number: TI-RTOS
Other Parts Discussed in Thread: SYSBIOS

Tool/software: TI-RTOS

I have ported existing project from DSP/BIOS into SYS/BIOS and I experience triggering of assert in stackchecking in Task_schedule() in Task.c module. Problem is that newTask handle is invalid pointer. Pointer value is one from 'ti_sysbios_knl_Task_Module_State_0_readyQ__A' but it is not address of any task in system.

After examining situation I found out that I can get round the problem if I dont use Task_setPri() function. Project is running stable without using Task_setPri function. (does not meet our timing requirements though)

I also tried to understand Task_schedule() method and placed the following procedure at the end:

static void taskTest()
{
    // todo
    UInt32 curSet;
    void * readyQ;
    void *curQ;
    void *maxQ;
    UInt maxbit;
    UInt ptrSize;
    UInt handleSize;
    int i;

     for (i = 0; i < 7; ++i) {
            if (Task_module->curSet & (1 << i)) {
                curSet = Task_module->curSet;
                readyQ = Task_module->readyQ;
                maxbit = Intrinsics_maxbit(Task_module->curSet);
                maxQ = (Queue_Handle)((UInt8 *)(Task_module->readyQ) + (UInt)(i*(2*sizeof(Ptr))));
                curQ = Task_module->curQ;
                Assert_isTrue(!Queue_empty(maxQ), Task_A_badTimeout);
            }
    }

}



This new additional assert is triggered before assert for stacks.

System configuration:
CPU: 28377S
Compiler: 6.2.6
SYS/BIOS: v6.42.03.35
CGT: 3.30.6.67

Please give some advice what I could check.

  • Lukas,

    Can you give the code snippet where you are calling Task_setPri and a little explanation of how it is being called (e.g. by what task, are interrupts disabled, etc.).

    Todd
  • I simplified the code and checked that problem is still present.

    Method sendRequest is called from task threads with priorities 2 (multiple), 3 (multiple), 4, 5. There are two additional tasks with priorities 1 and 6 in the system.

    int TEST_Class::sendRequest() {
    
        Task_Handle tskHle;
    
        tskHle = Task_self();
        int oldpri = Task_setPri(tskHle, m_tskPri);
        for (int i = 0; i < 30000; ++i) {volatile int tmp = i;}
        Task_setPri(tskHle, oldpri);
    
        return 0;
    
    }

    Where m_tskPri is set to 5 during initialization

    Interupts (HWI, SWI) are enabled when calling method sendRequest()

  • It looks fine. Did you use Tools->ROV->Task->Detailed to verify the priority did not change?

    What is the root problem you are avoiding by removing the Task_setPri? Is it the blown stack you mentioned? Can you try increase the stack size of the task that is getting the assert?

    Todd
  • >It looks fine. Did you use Tools->ROV->Task->Detailed to verify the priority did not change?

    I did not complain that priority did not change.

    >What is the root problem you are avoiding by removing the Task_setPri?

    System restart because of corrupted scheduler state.

    >Is it the blown stack you mentioned?

    I wrote that execution stops at assert that checks stack size because task pointer is invalid. I also checked stack memory of all tasks + system stack in memory window and they are ok.

    Can you validate function taskTest() that I understood behaviour of scheduler correctly?

  • Hi Lukas,

    Can you share your original application with Task_setPri() ? I can use it to repro the problem on my end.

    Best,
    Ashish
  • No. I can not share original application. Even if I would share it you would not be able to execute it because it depends on many external peripherals (SRAM, Flash disk, ..)

    I may try to create some example application though.

    And what about my additional assert. Did I understand scheduller correctly? It would help me to pinpoint location where I break scheduler.

  • Hi Lukas,

    It would be useful if you can create a cut down application that demonstrates the issue.

    Also, can you enable Task logging ? The Task logs may reveal something useful.

    >> And what about my additional assert. Did I understand scheduller correctly? It would help me to pinpoint location where I break scheduler.

    It looks like some of the kernel data structures are getting corrupted and causing the scheduler to malfunction.

    Best,

    Ashish

  • Hi,

       I have not been able to reproduce the behaviour with some minimalistic configuration yet. I tried to add asserts for different expressions.

    The most interesting one is checking Task_module->readyQ (aux1) if it contains valid data. After some execution time it returns some random big number (0x6F129A45) and my assert is triggered.

    I checked in CCS:

    • Task_module (aux) pointer contains value 0x001001C0. It is correct address of structure ti_sysbios_knl_Task_Module__state__V
    • readyQ in Task_module  contains value 0x100240. Probably correct.

    It is mystery for me how can variable aux1 contain different value than that is saved in Task_module structure.

    I had theory that there was some kind of glitch with external SRAM memory that is connected by EMIF and tried to read Task_module->readyQ twice and check them both. Theory was not confirmed becasue both variables contained same big random value.

    Could you give me some hints because it does not look like I have problem with SYS/BIOS but some problem with SRAM/EMIF.

  • Hi Lukas,

    Just to confirm, the aux1 value is consistent each time the check function is called until some Nth time when it is corrupted ? What check do you do on aux1 to ensure it is consistent ? Also, are you doing these checks in the Task switch hook function or inside a regular Task ?

    Best,
    Ashish
  • Yes, aux1 is consistent some N runs.

    I added checks into Sys/Bios Task.c. I just check that address is < 0x200000. I have data sections in Zone6 which has addresses 0x100000 - 0x200000

    Extended part in Tasks.c (look for todo):

    UInt Task_setPri(Task_Object *tsk, Int priority)
    {
        Int oldPri;
        UInt newMask, tskKey, hwiKey;
        Queue_Handle newQ;
        void *aux = NULL;
        void *aux1;
    
        Assert_isTrue((((priority == -1) || (priority > 0) ||
                      ((priority == 0 && Task_module->idleTask == NULL))) &&
                       (priority < (Int)Task_numPriorities)),
                       Task_A_badPriority);
    
        Log_write4(Task_LM_setPri, (UArg)tsk, (UArg)tsk->fxn,
                           (UArg)tsk->priority, (UArg)priority);
    
        tskKey = Task_disable();
        hwiKey = Hwi_disable();
    //    aux0 = Task_module->readyQ;
    /*    if (aux == NULL) {
            aux = Task_module;
        } else {
            Assert_isTrue(aux == Task_module, Task_A_badTimeout);
        }
    */
        aux = Task_module;
        oldPri = tsk->priority;
    
        if (oldPri == priority) {
            Hwi_restore(hwiKey);
            Task_restore(tskKey);
            return (oldPri);
        }
    
        if (priority < 0) {
            newMask = 0;
            newQ = Task_Module_State_inactiveQ();
        }
        else {
            // todo
            newMask = 1 << priority;
    
            aux1 = Task_module->readyQ;
            Assert_isTrue((unsigned long) aux1 < 0x200000, Task_A_badTimeout);
            newQ = (Queue_Handle)((UInt8 *)(Task_module->readyQ) +
                    (UInt)(priority*(2*sizeof(Ptr))));
    //        Assert_isTrue((unsigned long) newQ < 0x200000, Task_A_badTimeout);
        }
    
        if (tsk->mode == Task_Mode_READY) {
            Queue_remove((Queue_Elem *)tsk);
    
            /* if last task in readyQ, remove corresponding bit in curSet */
            if (Queue_empty(tsk->readyQ)) {
                Task_module->curSet &= ~tsk->mask;
            }
    
            if (Task_module->curTask == tsk) {
                Task_module->curQ = newQ;   /* force a Task_switch() */
                                            /* if no longer maxQ */
                /* Put current task at front of its new readyQ */
                Queue_insert(((Queue_Elem *)(newQ))->next, (Queue_Elem *)tsk);
                Assert_isTrue((unsigned long) newQ < 0x200000, Task_A_badTimeout);
            }
            else {
                /* place task at end of its readyQ */
                Queue_enqueue(newQ, (Queue_Elem *)tsk);
            }
    
            Task_module->curSet |= newMask;
        }
    
        tsk->priority = priority;
        tsk->mask = newMask;
        tsk->readyQ = newQ;
    
        if (priority < 0) {
            Task_module->curQ = NULL;   /* force a Task_switch() */
        }
    
        Task_module->workFlag = 1;
    	//taskTest();
    
        Hwi_restore(hwiKey);
        Task_restore(tskKey);
    
        return oldPri;
    }

  • New information:
    I checked in assembler and found that CPU DP register is used to access readyQ address and I found that CPU DP register is corrupted. It is notable that DP register contains same value as IER register. This is the case in every system breakdown that I induce. (Even if I change IER)

    This lead me to believe that there was something wrong on the stack. But I checked program disassemby by 'dis2000.exe' and there are no insturctions PUSH DP, PUSH DP:ST1, POP DP, POP DP:ST1.
    +
    I also checked that IER value is not equal to any value in: MOVW DP, #NUMBER

    How is it possible to change CPU DP register without above mentioned instructions?
  • Hi Lukas,

    That's a good find. A corrupted DP can cause the module state reads to be corrupted. Let's try to dig a little deeper to determine why is the DP corrupted.

    A couple of questions:
    - You mentioned the DP register value is same as IER. When you change the IER, does the DP change to the same value ?
    - I presume your application does not include any assembly that modifies the DP. Can you confirm ?
    - C28x auto saves several registers on the stack when an interrupt occurs and DP is one of them. If the stack somehow got corrupted, it is possible that the DP register is restored with an incorrect value. To confirm if an interrupt is in play, can you enable Task & Hwi logging ?

    Best,
    Ashish

  • > - You mentioned the DP register value is same as IER. When you change the IER, does the DP change to the same value ?

    Yes

    > - I presume your application does not include any assembly that modifies the DP. Can you confirm ?

    Confirm

    > To confirm if an interrupt is in play, can you enable Task & Hwi logging

    Will try later

    I have tried to move to newest compiler, sys/bios and xdctools and problem did not reappear. I will use this configuration for some days to validate if it solved the problem.

  • Well, some days have passed and problem did not happen again. I consider it closed.