Initializing local variables

hermarcel wrote on Tuesday, June 25, 2013:

I must be overlooking something (again). I have several functions using local (= on the task’s stack) variables. What is the best way to initialise these at first use(where needed).

Without an RTOS, one would simply declare the variables-to-be-initialised-once as static, but this doesn’t work when multiple tasks are using the function re-entrantly.

I was thinking about setting some flags as TaskTag. But maybe there is a simpler way?

pcalton wrote on Tuesday, June 25, 2013:

If you have multiple tasks calling a function and you expect that function to operate using the data for the calling task then you need to give the function some method of finding the correct data to use.

There are many different ways to accomplish what I think you are asking about. Which method you use determines how the data should be initialized.

example: You could declare the data on the task stack and pass the function a reference to the data

void myFunc(uint32_t* pdata)
{
    uint32_t data_to_use = *pdata;
}

void myTask(void *pvParameters)
{
    uint32_t taskdata = 123;
    // alternatively pass in the initial value via pvParameters
    uint32_t taskdata2 = *((uint32_t*)pvParameters);
    while(1)
    {
        myFunc(&taskdata);
    }
}

hermarcel wrote on Tuesday, June 25, 2013:

Yes, but passing a pointer down to a subsubsubsub…subfunction is quite cumbersome.

richard_damon wrote on Wednesday, June 26, 2013:

One option to avoid having to pass it everywhere would be to use vTaskSetApplicationTaskTag to store the pointer to the data in the TCB and xTaskGetApplicationTaskTag to get the pointer later without needing to pass it everywhere. (remember you can use NULL as id of the current task).

hermarcel wrote on Wednesday, June 26, 2013:

Yes, I found that out already (see first post :wink: ), but was looking for an easier way to define some Task Local Storage. Perhaps a definable amount of stackspace with a volatile global pointer to it that is set at task switch. With proper warnings to access this storage only from the running task, not from any isr.

rtel wrote on Wednesday, June 26, 2013:

I’m not really sure what this thread is about.  If each task has its own stack variables then they can be initialised when they are declared, and each task has its own copy.

With regards to thread local storage, I was considering this just this morning in relation to another feature request (Newlib re-entrancy).  I’m not convinced of its usefulness yet though, so if you have a compelling use case for it let me know.

Regards.

hermarcel wrote on Wednesday, June 26, 2013:

But when you initialize a variable in that way in a common subsubsub-function (not the never-ending-task-function), the init takes place each time the function is entered. Normal alternative would be to declare the local variable as static to have it initialized just once. But once-per-task is a different matter.

rtel wrote on Wednesday, June 26, 2013:

Ok - understand.  You want a function scope variable that maintains its value between calls, but on a per task basis.

Regards.

hermarcel wrote on Wednesday, June 26, 2013:

Correct. Accessible from any point at any time. Tasklocal. With minimal overhead and no protection.

I can malloc() a block and put it’s pointer in TaskTag, but I was wondering if there is an easier way without having to call GetTaskTag each time this subsubsubfunction executes. It are high-use functions and I want to avoid the overhead involved with GetTaskTag.

rtel wrote on Wednesday, June 26, 2013:

Well the way thread local storage normally works, in systems like Windows and Unix, is to have three functions.  The first function assigns a key to a malloced block.  The second returns a pointer to the malloced block when you pass it the key.  The third frees the block and key.  So that is not really more efficient that using the TaskTag value anyway.

Regards.

hermarcel wrote on Wednesday, June 26, 2013:

Then TaskTag it is.

Thanks all! :slight_smile:

richard_damon wrote on Wednesday, June 26, 2013:

To get true “Task Local Storage”, would require a compiler that supports it, as it becomes a new storage type distinct from global/automatic, so is a language issue. This would typically be implemented with a method similar to the TaskTag where the pointer is part of the context that is saved for each task.

IF your compiler provides for it, there should be in the documentation, instructions for how to connect it up to your RTOS, which would then use the set/get task tag operations. This documentation will likely also provide instructions for other connections to make the library thread safe.

Without direct support for it, you can fake it by having those functions that need it set a pointer to a struct type from getTaskTag (where the struct defines those variables that are part of the Thread Local Storage).