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/EK-TM4C1294XL: TI-RTOS's Scheduler

Part Number: EK-TM4C1294XL

Tool/software: TI-RTOS

After creating 3 tasks, Welder with priority 10, Feeder with priority 5, and Monitor with priority 1, the experiment result is as follows:

Running Welder Machine
Running Feeder
Running Stack Monitor
Running Welder Machine
Running Feeder
Running Stack Monitor
Running Welder Machine
Running Feeder
Running Stack Monitor
Running Welder Machine
Running Feeder
Running Stack Monitor
Running Welder Machine
Running Feeder
Running Stack Monitor
Running Welder Machine
Calling BIOS_exit from Feeder

Q1: Why does the scheduler look like a loop and each look it schedules the task by priorities?

Q2: As we know the scheduler should schedule the tasks by priorities.  Why after Feeder completion, it does not run Welder with priority 10, but run Stack Monitor?

Q3. I think it is relative to the scheduler's algorithm, how many schedule strategies or methods in TI-RTOS?  How for a programmer to choose one of them?

Thanks

  • Hi Neil,

    I would need to know what each task is doing to explain the behavior. Are you blocking on a semaphore or calling Task_sleep?

    I'm not sure what you are asking for #3.

    Todd

  • Thank you, Todd, my code is based on TI's mux example and here is the code:

    /* XDC module Headers */

    #include <xdc/std.h>
    #include <xdc/runtime/System.h>

    /* BIOS module Headers */
    #include <ti/sysbios/BIOS.h>
    #include <ti/sysbios/knl/Clock.h>
    #include <ti/sysbios/knl/Task.h>
    #include <ti/sysbios/knl/Semaphore.h>

    /* Example/Board Header files */
    #include "Board.h"

    #define WDTASKSTACKSIZE 2048
    #define FDTASKSTACKSIZE 1024
    #define MTTASKSTACKSIZE 512

    Void wdFxn(UArg arg0, UArg arg1); // Welder Machine
    Void fdFxn(UArg arg0, UArg arg1); // Wire Feeder
    Void mtFxn(UArg arg0, UArg arg1); // stack monitor

    Int resource = 0;
    Int finishCount = 0;
    UInt32 sleepTickCount;

    Task_Struct wdStruct, fdStruct, mtStruct;
    Char wdStack[WDTASKSTACKSIZE], fdStack[FDTASKSTACKSIZE], mtStack[MTTASKSTACKSIZE];
    Semaphore_Struct semStruct;
    Semaphore_Handle semHandle;

    Int main()
    {
    /* Construct BIOS objects */
    Task_Params taskParams;
    Semaphore_Params semParams;

    /* Call board init functions */
    Board_initGeneral();

    /* Construct writer/reader Task threads */
    Task_Params_init(&taskParams);
    taskParams.stackSize = WDTASKSTACKSIZE;
    taskParams.stack = &wdStack;
    taskParams.priority = 10;
    Task_construct(&wdStruct, (Task_FuncPtr)wdFxn, &taskParams, NULL);

    taskParams.stackSize = FDTASKSTACKSIZE;
    taskParams.stack = &fdStack;
    taskParams.priority = 5;
    Task_construct(&fdStruct, (Task_FuncPtr)fdFxn, &taskParams, NULL);

    taskParams.stackSize = MTTASKSTACKSIZE;
    taskParams.stack = &mtStack;
    taskParams.priority = 1;
    Task_construct(&mtStruct, (Task_FuncPtr)mtFxn, &taskParams, NULL);

    /* Construct a Semaphore object to be use as a resource lock, inital count 1 */
    Semaphore_Params_init(&semParams);
    Semaphore_construct(&semStruct, 1, &semParams);

    /* Obtain instance handle */
    semHandle = Semaphore_handle(&semStruct);

    /* We want to sleep for 10000 microseconds */
    sleepTickCount = 10000 / Clock_tickPeriod;

    BIOS_start(); /* Does not return */
    return(0);
    }

    /*
    * ======== task1Fxn ========
    */
    Void wdFxn(UArg arg0, UArg arg1)
    {
    UInt32 time;
    // Task_Stat statbuf; /* declare buffer */
    int t1Arr[] = {1, 2, 3};
    for (;;) {
    System_printf("Running Welder Machine\n");


    if (Semaphore_getCount(semHandle) == 0) {
    System_printf("Sem blocked in Welder\n");
    }

    /* Get access to resource */
    Semaphore_pend(semHandle, BIOS_WAIT_FOREVER);

    /* Do work by waiting for 2 system ticks to pass */
    time = Clock_getTicks();
    while (Clock_getTicks() <= (time + 1)) {
    ;
    }

    /* Do work on locked resource */
    resource += 1;
    /* Unlock resource */

    Semaphore_post(semHandle);

    Task_sleep(sleepTickCount);
    }
    }

    /*
    * ======== task2Fxn ========
    */
    Void fdFxn(UArg arg0, UArg arg1)
    {
    // Task_Stat statbuf; /* declare buffer */

    for (;;) {
    System_printf("Running Feeder\n");
    // Task_stat(&task1Struct, &statbuf); /* call func to get status */

    if (Semaphore_getCount(semHandle) == 0) {
    System_printf("Sem blocked in Feeder\n");
    }

    /* Get access to resource */
    Semaphore_pend(semHandle, BIOS_WAIT_FOREVER);

    /* Do work on locked resource */
    resource += 1;
    /* Unlock resource */

    Semaphore_post(semHandle);

    Task_sleep(sleepTickCount);

    finishCount++;
    if (finishCount == 5) {
    System_printf("Calling BIOS_exit from Feeder\n");
    BIOS_exit(0);
    }
    }
    }


    Void mtFxn(UArg arg0, UArg arg1)
    {
    UInt32 time;
    Task_Stat statbuf; /* declare buffer */

    for (;;) {
    System_printf("Running Stack Monitor \n");
    Task_stat(&wdStruct, &statbuf); /* call func to get status */
    System_printf("Wedler's stat priority = %d.\n", statbuf.priority);
    System_printf("Wdler's stat stackSize = %d.\n", statbuf.stackSize);
    System_printf("Welder's stat used = %d.\n", statbuf.used);

    Task_stat(&fdStruct, &statbuf); /* call func to get status */
    System_printf("Feeder's stat priority = %d.\n", statbuf.priority);
    System_printf("Feeder's stat stackSize = %d.\n", statbuf.stackSize);
    System_printf("Feeder's stat used = %d.\n", statbuf.used);

    Task_stat(Task_self(), &statbuf); /* call func to get status */

    System_printf("Monitor's stat priority = %d.\n", statbuf.priority);
    System_printf("Monitor's stat stackSize = %d.\n", statbuf.stackSize);
    System_printf("Monitor's stat used = %d.\n", statbuf.used);

    if (Semaphore_getCount(semHandle) == 0) {
    System_printf("Sem blocked in Monitor\n");
    }

    /* Get access to resource */
    Semaphore_pend(semHandle, BIOS_WAIT_FOREVER);

    /* Do work by waiting for 2 system ticks to pass */
    time = Clock_getTicks();
    while (Clock_getTicks() <= (time + 1)) {
    ;
    }

    /* Do work on locked resource */
    resource += 1;
    /* Unlock resource */

    Semaphore_post(semHandle);

    Task_sleep(sleepTickCount);
    }
    }

    For Q3, I mean which of the methods TI RTOS designed, for example:

    • First-Come, First-Served (FCFS) Scheduling.
    • Shortest-Job-Next (SJN) Scheduling.
    • Priority Scheduling.
    • Shortest Remaining Time.
    • Round Robin(RR) Scheduling.
    • Multiple-Level Queues Scheduling.

  • Neil,

    Based on the code above, the output is as expected for a multi-threaded application on a single threaded core.

    None of your task(s) block until Semaphore_pend() or Task_sleep().

    Additionally, you are sleeping at most 1 tick since you're comparing less than or equal to the previously read tick.

    If you were to obtain the semaphore and sleep(<long time>) you would notice your other task(s) blocked.

    Derrick

  • Thank you, Derrick, after increasing the sleepTickCount from 10000 to 10000000, unfortunately, nothing has been changed and it still looks like a loop and sequential by priority loop.

  • Neil,

    Changing the sleepTickCount will have no effect unless you obtain the semaphore and sleep (before posting).

    Semaphore_pend(semHandle, BIOS_WAIT_FOREVER);
    Task_sleep(sleepTickCount);
    Semaphore_post(semHandle);

    Derrick

  • Thank you for your teaching, and yes, the code is exact the same as you mentioned.  I guess the sleepTickCount should not be applied to every task because everybody sleeps the same time, the order remain the same without changing.  

  • Neil,

    I would use a unique sleep time for each task and observe the resulting behavior.

    In general, a context switch will not occur unless the scheduler is invoked.
    Some examples of APIs which invoke the scheduler are:

    • Task_sleep()
    • Semaphore_pend() / post()
    • Mailbox_pend() / post()
    • Task_yield()
    • ....etc

    Check out our SimpleLink(tm) Academy on RTOS Concepts.

    Derrick

  • Thank you, Derrick, for all the information.!