#include <stdint.h>
//volatile
uint32_t spinvar = 1;
uint32_t mtx;
void lock(uint32_t* l)
{
*l = 1;
}
void unlock(uint32_t* l)
{
*l = 0;
}
void spin()
{
uint32_t local;
for (;;)
{
lock(&mtx);
local = spinvar;
unlock(&mtx);
if (!local)
break;
}
}
without the volatile:
spin:
pushl %ebp
movl spinvar, %eax
movl %esp, %ebp
testl %eax, %eax
je .L7
.L10:
jmp .L10
.L7:
movl $0, mtx
popl %ebp
ret
so the compiler did something like
local = spinvar;
if (local)
for (;;);
(notice the dead lock/unlock inlined code elimination).
With the volatile, the code is correct:
spin:
pushl %ebp
movl %esp, %ebp
.p2align 4,,7
.L7:
movl spinvar, %eax
testl %eax, %eax
jne .L7
movl $0, mtx
popl %ebp
ret
So think about all you inlined spinlocks, mutexes and so on.
And if you do
void lock(volatile uint32_t* l)
...
void unlock(volatile uint32_t* l)
...
the code is even better:
spin:
pushl %ebp
movl %esp, %ebp
.p2align 4,,7
.L7:
movl $1, mtx <=========
movl spinvar, %eax
movl $0, mtx <=========
testl %eax, %eax
jne .L7
popl %ebp
ret
So volatile just means 'dont trust this does not change even you don't see
why'.