C/C++ volatile variable accessed from another module

Viewed 94

I know and understand the purpose of volatile variables and optimisation in general (well, I think I do!). This question relates specifically to what happens if a variable is accessed outside the module it is declared in.

In the following scenario, if funcThatWaits was called inside bar.c, it could be optimised and not fetch the value of sTheVar each loop iteration.

However, when GetTheVar is called externally could the same optimisation apply or does the function call ensure sTheVar will always be read each loop iteration?

I am not suggesting this is good code or practice, but an example for the sake of the question.

bar.h

int GetTheVar(void);

bar.c

static /*volatile*/ int sTheVar;

int GetTheVar(void)
{
    return sTheVar;
}

static void someISROrFuncCalledFromAnotherThread(void)
{
    sTheVar = 1;
}

foo.c

#include "bar.h"

void funcThatWaits(void)
{
    while(GetTheVar() != 1) {}
}
2 Answers

when GetTheVar is called externally could the same optimisation apply or does the function call ensure sTheVar will always be read each loop iteration?

The same optimization may apply. For instance, if you are using LTO (Link-Time Optimization), then the compiler knows everything about GetTheVar and will likely decide funcThatWaits is an infinite loop (which, by the way, would be UB).

Function calls are not going to be optimized away since, for all the caller knows, the function being called could depend on some exogenous state.

I compiled the following three files using gcc:

foo.c

#include "bar.h"

void funcThatWaits(void) {
    while ( getVar() != 1 );
}

bar.c

#include "foo.h"

static int theVar;

int getTheVar(void) {
    return theVar;
}

void theFunc(void) {
    funcThatWaits();
}

test.c

#include "bar.h"

int main() {
    theFunc();

    return 0;
}

Compiling those three into a.out and running objdump -d a.out, the following comes out:

00000000000005fa <main>:
 5fa:   55                      push   %rbp
 5fb:   48 89 e5                mov    %rsp,%rbp
 5fe:   e8 25 00 00 00          callq  628 <theFunc>
 603:   b8 00 00 00 00          mov    $0x0,%eax
 608:   5d                      pop    %rbp
 609:   c3                      retq   

000000000000060a <funcThatWaits>:
 60a:   55                      push   %rbp
 60b:   48 89 e5                mov    %rsp,%rbp
 60e:   90                      nop
 60f:   e8 08 00 00 00          callq  61c <getTheVar>
 614:   83 f8 01                cmp    $0x1,%eax
 617:   75 f6                   jne    60f <funcThatWaits+0x5>
 619:   90                      nop
 61a:   5d                      pop    %rbp
 61b:   c3                      retq   

000000000000061c <getTheVar>:
 61c:   55                      push   %rbp
 61d:   48 89 e5                mov    %rsp,%rbp
 620:   8b 05 ee 09 20 00       mov    0x2009ee(%rip),%eax        # 201014 <theVar>
 626:   5d                      pop    %rbp
 627:   c3                      retq   

0000000000000628 <theFunc>:
 628:   55                      push   %rbp
 629:   48 89 e5                mov    %rsp,%rbp
 62c:   e8 d9 ff ff ff          callq  60a <funcThatWaits>
 631:   90                      nop
 632:   5d                      pop    %rbp
 633:   c3                      retq   
 634:   66 2e 0f 1f 84 00 00    nopw   %cs:0x0(%rax,%rax,1)
 63b:   00 00 00 
 63e:   66 90                   xchg   %ax,%ax
Related