Volatile variable are the meat of Locks in Kernel.
Volatile Variable :-Compiler does not optimizes the code around Volatile variables. Generally compiler stores the value of register in accumulator and every time reads from it. But when we declare a variable as volatile, the compiler reads every time from register not accumulator.
Declaring volatile tells compiler that variable can be changed by another thread without being any action taken by the code the compiler finds near by.
Its mostly used in :-
- memory mapped peripheral register.
- Interrupts.
- Multi-Threaded application.
Example:-
Without Volatile :-
UINT1 *ptr = (UNT1 *)0x1234
/* ptr is indicating 8 bit status register at address 0x1234 */
while (*ptr)
//Do something
Here it will infinitely loop. As compiler will cache the ptr and it won’t fetch it again. Compiler will delete any instruction writen below while(..)
Ptr can be modified by other code but it won’t consider reading from register
With Volatile:-Each time compiler will read from the register at address 0x1234. In case someone has changed the while() loop will break and below code will be executed.
In multi Threaded Programming, we use volatile variable for a global variable. It might happen we create too much volatile variable so best is to create identity that uses volatile variable and use that identity to secure the access for global variable. That identity is called Lock.
Atomic Variable :-
typedef struct {
int counters;
}atomic_t;
For reading, writing, read and write APIs are typecasting it to Volatile -
static inline int atomic_read(constatomic_t *v)
{
return(*(volatile int*)&(v)->counter);
}
static inline void atomic_add(int i, atomic_t *v)
{
asm volatile(LOCK_PREFIX”addl %1,%0"
:”+m”(v->counter)
:”ir”(i));
}
We can see that the atomic variable is implemented via volatile. So each time we read or write to atomic variable it’s going through the volatile operations.
Files in linux for atomic variable :-
include/asm-generic/atomic.h
include/linux/types.h