T.E.D.
T.E.D.

Reputation: 44804

Defining routines for use with volatile and non-volatile objects

I find myself wanting to write a routine that will operate on both volatile and non-volatile memory blocks. Something along the lines of:

void byte_swap (unsigned * block_start, size_t amount) {
    for (unsigned * lp = block_start; lp < block_start + amount; lp++) {
        *lp = htonl(*lp);
    }
    memcpy (block_start, some_other_address, amount);
}

(Not my real code, but an example).

The problem I have is that if I try to use a pointer to a volatile memory area, the compiler complains about losing the volatile qualifier. I could cast away volatile, but it seems like that might make the routine itself unsafe if it tries to cache the changes (or previous reads), would it not?

The other option would be to make the routine itself take unsigned volatile *, but that would require me to convert all the non-volatile callers to volatile pointers.

I suppose a third option would be to make two exact duplicates of the routine, differing only in whether the volatile keyword appears. That sucks.

Is there a Right Way to handle this, and if so what is it?

As a mostly related question, are predefined routines (specifically memcpy) safe to use with volatile pointers? What bad things could happen to me if I did? It seems kinda silly to have to reroll any memory-related library routine myself simply because it doesn't use volatile void pointers.

Upvotes: 1

Views: 1184

Answers (2)

doron
doron

Reputation: 28902

You only need to use volatile when you are dealing with memory mapped IO, that is where successive reads or writes to the same memory address can and should return different values. If you are writing to what amounts to simply shared memory, a simple formal handover mechanism which allocates access the either the CPU or the hardware device (such as a DMA controller) should suffice.

Also be aware that performing operations on non-cached memory or, even worse, a memory mapped device will be really slow. You may well be far better off copying to normal uncached memory before performing any byte swapping operations. When copying large amounts of data to memory mapped IO, DMA can safe you a large number of CPU cycles.

volatile tends to act as a barrier to compiler optimization and should be avoided where necessary.

Upvotes: 2

CB Bailey
CB Bailey

Reputation: 792557

Although the code might be pessimistic for non-volatile objects (although given your function, probably not in this case) you should be able to code for volatile unsigned* and pass in unsigned*. Just like const you can add a volatile qualifier without an explicit (and potentially dangerous) cast.

You shouldn't have to change all your pointers to volatile, your non-volatile callers can stay as they are.

Although memcpy isn't defined to use volatile memory, because of its nature (it reads memory from one place once and writes it once somewhere else) the class of problematic optimizations that volatile inhibits don't apply. You're likely to be able to cast away volatile and use memcpy without any issues (other than those you already have with volatile areas of memory).

Upvotes: 1

Related Questions