So I have a piece of code that looks like the following:
uint8_t *buffer = <16 MB memory region>
uint32_t count = 1024;
uint32_t position = 0;
uint8_t *get_data() {
uint8_t *region = buffer + position * 16;
position += 1;
position %= count;
do {
__sync_synchronize();
} while (reigon[0] != 1);
return region;
}
The buffer in question is being written to by a hardware device. At some point (maybe before we started looping, maybe after we've started), the hardware will write to that location, as well as to the rest of the buffer.
I'm currently using __sync_synchronize to issue a memory barri开发者_JS百科er, because I would like to ensure that there is no way that the compiler would cause the rest of that memory region to be cached from any time before region[0] == 1
.
I'm aware that I could mark the entire buffer as volatile. However, I'd like to be able to return a non-volatile buffer from this function.
So, is there any way to do a __sync_synchronize
, but only have it target the range of memory that I specify. In this case the memory from [region, region + 1024)
?
As an aside, this code is living in userspace. The memory buffer is a pinned region of memory that I've allocated with a kernel module, mapped into userspace, and told a FPGA to eventually DMA to it. This is essentailly attempting to implement a polling mechanism on the FPGA finishing a DMA tranfer.
A region-limited memory fence would be a fairly unusual architectural feature. However, you only need the fence after the loop has terminated:
while (*(volatile uint8_t *)region != 1)
;
__sync_synchronize();
return region;
This should do the trick:
uint8_t *get_data() {
uint8_t *region = buffer + position * 16;
volatile uint8_t *volatile_region = region;
position += 1;
position %= count;
do {
} while (volatile_region[0] != 1);
return region;
}
精彩评论