[try Beta version]
Not logged in

 
Using of voltile qualifier

Feb 28, 2025 at 2:47pm
Hi,
Where should i use volatile keyword in cpp?

I wrote a code in cpp which communicating with a memory mapped IO (MMIO) - specifically a IP core with base address and physical memory size - for Linux target. I am working on Xilinx platform (consists of processor and fpga)

So I understand that because I'm accessing MMIO, the compiler can optimize things away so I sohuld use volatile.

I'm confused about where should I add this volatile. Here is my relevant code section:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
struct SITAL_DEVICE_INTERNAL {
	SITAL_DEVICE_HANDLE hDevice;
	U16BIT* virtBarAddr;
	int DeviceNum;
	SITAL_DEVICE_INTERNAL() : hDevice((SITAL_DEVICE_HANDLE)(long)-1), Bars(0), memOffset(0)  {
//		::memset(UniqueDeviceName, 0, sizeof(UniqueDeviceName));
		::memset(DeviceID, 0, sizeof(DeviceID));
	}
};
 // Map the BRM physical address into user space getting a virtual address for it using mmap function
if ((pDevice->fd = open("/dev/mem", O_RDWR | O_SYNC)) != -1)
	{
	pDevice->virtBarAddr = (U16BIT *)mmap(NULL, addrSpace, PROT_READ|PROT_WRITE, MAP_SHARED, pDevice->fd, base_addr);
	}


After I mapped the physical memory to virual using mmap, here I perform read from the MMIO:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int ReadMemoryBar(DEVICE_HANDLE device, int bar, int offset, void* data, unsigned int size)

{
	DEVICE_INTERNAL* dev = static_cast<DEVICE_INTERNAL*>(device);
	U16BIT * p = (U16BIT*)data;
	U16BIT * readerBar = dev->virtBarAddr; 
	U16BIT * add;
	add = readerBar + offset / 2;
	for (unsigned long i = 0; i < (size / 2); i++)   // from bytes to words 16 bit
	{
		*p = *add;          //((*(U16BIT*)(add)));
		p++;
		add++;
	}
	return ok;
}



If i add volatile to a pointer like this:
 
volatile pDevice->virtBarAddr = (volatile U16BIT *)mmap(NULL, addrSpace, PROT_READ|PROT_WRITE, MAP_SHARED, pDevice->fd, base_addr);


Does it tell the compiler that all of the region pointed to by the pointer [addrSpace] is volatile?

Or should i add volatile when read from the MMIO:

volatile U16BIT * readerBar = dev->virtBarAddr;
Last edited on Feb 28, 2025 at 3:04pm
Feb 28, 2025 at 5:01pm
first thing to do is make sure you need it. Volatile was heavily deprecated in c++20, and old info on when and where to use it may be misleading for the current state of the language. Second thing is that this is a keyword that you want to avoid as much as possible, as it forces the compiler to do slow things and if used where not needed, it just adds a useless performance hit.

While I am not sure about your case, the one place where I have had to use it (things did not work without) was when dealing with actual (not virtual) external hardware devices, such that the c++ code needed to get an updated value from it and could not use what it got last time (like a gps position) from a cache. I have never felt compelled to use it for a memory mapped file if no other program is also modifying that same file at the same time (I have not had it come up as a possibility to deal with that case).

as best as I follow your code, which is probably not 100%, what could change is the value you read from the pointer, not the pointer itself (?). So the thing pointed to is the volatile entity, right?

It looks like you are on the right track, but I can't tell if your target is able to change state externally with your c++ program unaware of it. If so then you do need the keyword, and the where.. is the data that can change externally. Just take care that its not the address (pointer) that can change but its underlying variable/value/register.
Last edited on Feb 28, 2025 at 5:08pm
Feb 28, 2025 at 11:25pm
Uncle GPT puts it very well:


In C++, the volatile keyword is a type qualifier that informs the compiler that a variable's value might be modified by external factors beyond the control of the current program's execution. These external factors can include hardware interactions, other threads, or signal handlers. The volatile keyword essentially instructs the compiler to avoid optimizations that assume the variable's value remains constant between accesses.
When a variable is declared as volatile, the compiler will:

Disable caching:
The compiler will not store the variable's value in registers, ensuring that each read operation fetches the most up-to-date value from memory.
Prevent reordering:
The compiler will not reorder memory accesses to volatile variables, preserving the intended sequence of operations.
Avoid optimization:
The compiler will not optimize away reads or writes to volatile variables, even if they appear redundant.

The volatile keyword is typically used in the following scenarios:

Memory-mapped hardware:
When interacting with hardware devices through memory-mapped registers, volatile ensures that the program correctly reads and writes to these registers.
Shared memory:
In multi-threaded applications, volatile can be used to ensure that changes made to shared variables by one thread are visible to other threads. However, for more robust thread synchronization, consider using mechanisms like mutexes or atomic operations.
Signal handlers:
When a signal handler modifies a variable, volatile ensures that the main program observes the changes.


(volatile U16BIT *) Declares the storage for the U16BIT is volatile.
(U16BIT * volalite) Declares that the pointer is volatile.


Last edited on Feb 28, 2025 at 11:33pm
Mar 1, 2025 at 6:06pm
ElusiveTau wrote:
In multi-threaded applications, volatile can be used to ensure that changes made to shared variables by one thread are visible to other threads.


Is volatile useful with C and C++ threads?
https://isvolatileusefulwiththreads.com/cxx/
Registered users can post here. Sign in or register to post.