xTaskCreate and memory storing pvParameters

mikej42 wrote on Thursday, February 14, 2008:

Is there a mechanism for a new task to copy data pointed to by *pvParameters to be saved by the new task before the calling task (the one that calls xTaskCreate) erases the memory?
So a structure is created on a local stack,
xTaskCreate called, and returns
When can the function release the stack memory - when has the new task taken its copy of the data?
Do I need an interlock, a flag in the structure that is cleared by the new task when it has its copy, or another signalling method?

Any suggestions or help gratefully received

Regards

Mike Newsome

davedoors wrote on Thursday, February 14, 2008:

If I get your question right, you have task A that creates task B, and task B wants some to copy some stack (that is not static) data from task A but does not know if the data is still valid or not as task A may have gone away and done something else. pvParameters being used to point to the data.

You can achieve this by having task A create task B at a priority higher than task A. This way you are guaranteed that task B will run before task A even exits the xTaskCreate() function. Once task B has got the data it requires it can set its own priority to its real wanted value.

jon_newcomb wrote on Thursday, February 14, 2008:

I had a situation where trimming task priorities resulted in a NULL pointer reference, which scared me slightly.
Also the code to start the new task was a function call used by lots of tasks of differing priorities.

The way I got round this was to use pvPortMalloc() and let the newly generated task free the memory using vPortFree().

WHAT DOES THE CODE DO?
Its a one shot timer. It fires off a new tasks that waits for the specified period of time, posts a message to a queue and then destroys itself.

HOW?
I allocate memory for a ‘param_*’ struct and stuff it with local variables from calling task
A new task is started and receives a pointer to the struct. The struct is cast to access data. Once used it can be freed.

CONCLUSION
It did strike me as a safe way, but rather long winded.
Has anyone else solved this problem in a less round about way?

CODE…
typedef struct prt_param_oneshottimer_t
{
   portTickType timerperiod;
   uint32_t event;
   uint32_t data;
}param_oneshottimer_t;

int
TaskStart_OneShotTimer (portTickType timerperiod, uint32_t event, uint32_t data)
{
   int retval = PASS;
   param_oneshottimer_t *param_oneshottimer;
   // Allocate storage for the timer variables. Pointer to this is
   // passed to the task and used by the task created
   param_oneshottimer = ( param_oneshottimer_t * )
      pvPortMalloc( sizeof( param_oneshottimer_t ) );
   // Assign passed arguments to the task
   param_oneshottimer->timerperiod = timerperiod;
   param_oneshottimer->event = event;
   param_oneshottimer->data = data;
   // Pass arguments to the task that starts the timer
   if (xTaskCreate
       (Task_OneShotTimer, "OneShotTimer", TASKSTACK_TIMER,
        (void *)param_oneshottimer, (tskIDLE_PRIORITY + 3),
        (xTaskHandle *) NULL) != PASS)
   {
      retval = FAIL;
   }
   return (retval);
}

static
portTASK_FUNCTION (Task_OneShotTimer, pvParameters)
{
   // Cast data passed to task
   param_oneshottimer_t *prt_param_oneshottimer;
   prt_param_oneshottimer = (param_oneshottimer_t *) pvParameters;
   // Wait for the specified period of time
   vTaskDelay(prt_param_oneshottimer->timerperiod);
   // We have waited the required amount of time. Post the required
   // message to the queue
   MessageQueueSendData(prt_param_oneshottimer->event,
    prt_param_oneshottimer->data, "oneshottimer");
   // Deallocate memory used
   vPortFree( (void *)prt_param_oneshottimer );
   // Now delete the task
   vTaskDelete (NULL);
}

mikej42 wrote on Thursday, February 14, 2008:

Hi Dave
You have the question right! Thanks for an answer.

I quite like the look of Jons solution, although as he says it is a bit long winded.

Regards

Mike Newsome