Is a context switch possible during a function call?

I have the idea that a context switch will not occur while a function call is being prepared.

Basically I have 2 global variables :-

int g_Temperature;
int g_Height; 

These are set by a “measurement” task, inside a critical section - since the 2 are dependent.

In another task (e.g. display) I would normally wrap copies of these values in critical section, before using them

void DisplayTask()
{
  taskENTER_CRTICAL();
  int LocalTemp = g_Temperature;
  int LocalHeight = g_Height;
  taskEXIT_CRTICAL();
  // Draw a nice picture
  AddBlob( LocalHeight, LocalTemp );
}

My question is, can I just do this :-

void DisplayTask()
{
  // Draw a nice picture
  AddBlob( g_Height, g_Temperature);
}

Or is it possible that a context switch can occur while the function call is being constructed on the stack, thus leading to a possible mismatch of my 2 variables ?

yes, that is possible. The scheduler has no concept of a task “being in a function.”

So, there is nothing special about putting a function call on the stack, as opposed to say local variables. This helps my understanding…

Many thanks !

Sorry, I do not understand that last statement. What exactly do you mean by “putting a function call on the stack, as opposed to say local variables?” First of all, function CALLS are never “put” anywhere, and then, local variables by definition ARE on “the stack.” Maybe the fact that each task is allocated a stack of its own has so far eluded you?

Look at it this way: A task that is running executes a sequence of machine instructions. That instruction sequence may contain branches to subroutines, returns from subroutines, accesses to local or global variables (which is the same as far as the CPU is concerned) or any other instruction supported by the CPU. The scheduler does not care. As soon as an event occurrs that invokes the scheduler (for example, during interrupt processing), the current processor status is saved (including, among other things, the task stack) to be restored later on, namely, once the task is rescheduled to pick up at the point right after suspension. Whichever logical context was active at task switch time is of no interest to the scheduler whatsoever.

:smiley: Sorry for my loose terminology ! I was referring to the various processor instructions which are generated by the compiler to implement a C function call - ending in setting the function address in the instruction register (in my mind, this is putting the function call somewhere :wink: ).

Of course what concerns me are the function arguments, which are put on the (task’s) stack.

As you say, the scheduler doesn’t care which instruction the processor is processing, so a context switch could occur between writing one argument on the stack and another (when the context is switched back, quite possibly after my other task has changed the pair of variables). So I do have to ensure my two variables remain atomic in some way.

Hi @timo12 welcome to the FreeRTOS Community. From your description, it looks like the 2 variables, g_Height and g_Temperature, are updated together and you want to ensure that old value of one variable and new value of another is not passed to the AddBlob function.

The above code block translates roughly to the following assembly on cortex-M:

LDR R0, =g_Height /* Read the g_Height value in R0 registed which is used to pass first parameter to AddBlob. */
LDR R1, =g_Temperature /* LRead the g_Temperature value in R1 register which is used to pass second parameter to AddBlob. */
BL AddBlob /* Call the function. */

A context switch can happen after the first instruction. If the variables g_Height and g_Temperature are updated before this task is scheduled again, R0 will contain the old value of g_Height and R1 will have the new value of g_Temperature. As a result, the function AddBlob will be called with old value of g_Height and new value of g_Temperature. Is this what you meant by “possible mismatch of my 2 variables”?

And for this case, since you are first reading into local variables which would mean that in addition to loading into registers you would also be pushing them onto the stack and all this would happen inside the critical section. A context switch can happen after the critical section is exited and g_Height and g_Temperature can change, but the local copies on the stack won’t change so when the DisplayTask is next scheduled, LocalTemp and LocalHeight would contain what was stored in them when the critical section was last executed.

2 Likes

Exactly :slight_smile:

Thanks for taking the time to spell it out…

2 Likes