vTaskSuspend strange behavior

Hi,

I noticed strange behavior when i suspend a task in the freeRtos.

Apparently the task is suspended when i suspend it, ie, not printing anything in my debug console.
When i resume the task, all the non-executed cycles run all at once (print on the screen all at once). It seems that the task continues to run behind the scenes, but without printing on my console.

TaskHandle_t ws_keep_alive_task_handler;  

void init_Ws_Keep_Alive_Task( uint32_t time_resolution )
{
    static uint32_t param;
    uint32_t* const my_Param = &param;
    param = time_resolution;   

    xTaskCreatePinnedToCore( ws_keep_alive_task, 
                             "ws_keep_alive_task", 
                             2048, 
                             my_Param, 
                             1,
                             &ws_keep_alive_task_handler,
                             PRO_CPU_NUM                         
                           );

    configASSERT( ws_keep_alive_task_handler ); 
 
    vTaskSuspend(ws_keep_alive_task_handler);  // Set task in Suspended state.
}


static void ws_keep_alive_task( void* pvParameters )
{
    uint32_t* taskTime = (uint32_t*) pvParameters;

    TickType_t xLastWakeTime;
    static TickType_t xFrequency;               
    xFrequency = pdMS_TO_TICKS( *taskTime );    

    // Initialise the xLastWakeTime variable with the current time.
    xLastWakeTime = xTaskGetTickCount ();

    printf("\n*taskTime: %u\n", *taskTime );
    printf("xFrequency: %u\n\n", xFrequency );

    static uint32_t counter = 0;

    for( ;; )    // runs every 1000 ms.
    { 
        // Wait for the next cycle.
        vTaskDelayUntil( &xLastWakeTime, xFrequency );


        printf("ENTREI!!!!!!:  %u\n", xLastWakeTime );

        counter++;

        printf("counter: %u\n", counter );
    }
}


void ws_set_keep_alive_task_state( bool state )
{
    if( state == false )
    {
        vTaskSuspend(ws_keep_alive_task_handler);    // Set task in Suspended state.
    }
    else
    {    
        vTaskResume(ws_keep_alive_task_handler);    // Set task in Ready state(Exit Suspended state).    
    }    
}


eTaskState ws_get_keep_alive_task_state()
{
    return eTaskGetState(ws_keep_alive_task_handler);
}

ws_set_keep_alive_task_state( true ); // vTaskResume

ws_set_keep_alive_task_state( false ); // vTaskSuspend

// wait some seconds(10, 20 or 30 seconds).

ws_set_keep_alive_task_state( true ); // vTaskResume
// print all (10, 20 or 30 seconds ) at once and after it continues printing normally every 1000 ms.

That is because you are using the vTaskDelayUntil() call - that calculates the time at which is should execute next, and if the calculated time is in the past it won’t block and just return immediately (it can’t block because its unblock time has already past). In that way it will keep executing until the time it calculates that it should next leave the blocked state is in the future - at which time it will enter the Blocked state to wait for the unblock time.

Hi,

Sorry.
I did not understand.
The task runs, but prints nothing, between vTaskSuspend and vTaskResume and after vTaskResume the task prints everything it did while it was suspended.
Very strange to me.

So, what should i do to have a periodic task that work correctly ?

Thank you.

Sounds like you want vTaskDelay() instead of vTaskDelayUntil(). The Until() function is based on a time to wake up. The basic delay function is based on a simple delay.

However, you should consider other methods of controlling the task’s behavior. For example, if the task is supposed to take some action once a minute but you suspend it for 20 minutes, what is it supposed to do once it resumes? Maybe the answer to that question should be in the task’s own logic along with the ability to suspend and resume itself by waiting for specific events.

Lets say a task is using vTaskDelayUntil to run every 100 ticks, and that the current tick time is 1000. Then the task will unblock at the following times:

1000
1100
1200
1300
1400
1500
1600

Now lets say the task is suspended at 1210, and resumed at 1520. The task has already calculated its next unblock time is 1300, but it doesn’t run until time 1520. Now, when it calls vTaskDelayUntil() and wants to unblock at 1300, seeing the time is already 1520 it won’t block at all as the time it wanted to unblock is already in the past. It then calculates its next unblock time as 1400 - but that too is in the past so again calling vTaskDelayUntil() does not cause the task to block. It calculates its next unblock time as 1500, but that too is in the past so it doesn’t block (so it has run several iterations now without blocking) - only when it calculates its next block time as 1600 is the unblock time in the future - so the task enters the blocked state.

1 Like

I understand now.

what i intend to do is a task that runs every 1 second for example.

I am coding a websocket server.

I am trying to do a task that manages the keep alive(ping pong) of connected clients.
So, if the list of connected clients have 0 clients i suspend the task and if the list of connected clients have more than 1 client i resume the task.

Every 1 second i iterate over a data structure to see if the clients still alive, if not, i close the client socket. At least this is the idea.

That doesn’t sound to need the ‘catch up’ feature of vTaskDelayUntil, but just needs a vTaskDelay.

An alternative to the supend/resume would be to have a semaphore. When a task is added to the list, it gives the semaphore, if the list has 0 clients, then that task tries to take the semaphore, causing it to block until the give happens. (After getting unblocked, it will need to check the list and reblock if it has 0 entries).

This avoids the race of “See that 0 Clients are on the list”, get interrupted by a task that adds a client and then resumes the task, and then the monitor task suspends itself when it gets cpu time next, as its last action was seeing 0 clients, and the resume got lost.

I will try vTaskDelay.

Can i explicitly block and unblock the task ?

The task that insert and delete clients from the list are the same, so i think that no have race condition.

And i am new with freeRtos. I never used a semaphore.

It is dangerous to suspend a task other than yourself, unless you KNOW exactly what it is doing at the moment, as if it happens to be using some guarded resource, you have locked up that resource. So just because you removed the last client, the task may still be doing something for that client and perhaps as control of some system resource. You BLOCK on a specific thing, like a semaphore, a queue, a task notification, etc. That is what I was suggesting, setup something like a semaphore, that the task can block on when it has no work to do, and when someone adds work they can give that resource to unblock the task. You could also use the direct to task notification system as that semaphore to be a bit more efficient, the semaphore, being more explicit is sometimes clearer to someone first learning these interactions.

1 Like

When i suspend a task, the task suspend immediately or does the task finish what it was doing and then suspend ?

Immediately. There is no way for FreeRTOS to delay when that happens.

Hi,

“vTaskDelay( xFrequency )” seens to solve the problem.

Thank’s all.

static void ws_keep_alive_task( void* pvParameters )
{
    uint32_t* taskTime = (uint32_t*) pvParameters;
    
    static TickType_t xFrequency;               
    xFrequency = pdMS_TO_TICKS( *taskTime );    // The macro pdMS_TO_TICKS() can be used to convert milliseconds into ticks. 

    printf("\n*taskTime: %u\n", *taskTime );
    printf("xFrequency: %u\n\n", xFrequency );

    static uint32_t counter = 0;

	for( ;; )    // run every xFrequency ms.
	{ 
        // Wait for the next cycle.  		
        vTaskDelay( xFrequency ); 

        printf("ENTREI!!!!!!:  %u\n", xTaskGetTickCount() );

        counter++;
        
        printf("counter: %u\n", counter );
    }
}