shared memory problem on ARM v5TE using threads
Russell King - ARM Linux
linux at arm.linux.org.uk
Tue Dec 15 12:14:40 EST 2009
On Tue, Dec 15, 2009 at 12:01:56PM +0100, christian pellegrin wrote:
> Thanks for your answers, unfortunately it turned out to be quite easy
> to write a program [0] that shows exactly what Russell described. :-(
Try this:
- create a 4K file
- create three programs:
1. repeatedly uses read() and write() to increment the first word of
this file
2. uses one shared mmap of this file to increment the 256th word (offset
1024)
3. uses two shared mmaps of this file, reading the 128th word from one
shared mmap, reads the 128th word from the other, increments the
first value and writes it to the 128th word in the second map,
printing the two values read. It also reads the first and 256th
word and prints the result
This should be an adequate test of most of the important scenarios: the
third program should show an increasing number for both locations.
If it doesn't, then the value is being cached somewhere. I suspect
what you'll find is that on Feroceon, the only values you will see
increment is the 128th value. The remainder will be static.
That means multiple shared mmaps on Feroceon are incoherent with:
1. file updates via read/write.
2. other shared mappings in other processes.
And because of (1) I expect that a read() followed by another read() of
the same file offset as being updated by (3) will not show updates - so
it should be both lost write()s and stale data on read()s (which will
mean PIO write-outs - eg swap out, file update - will be affected.)
> int main(int argc, char *argv[])
> {
> int fd, fd1;
> char *s1, *s2, *p;
> volatile char x;
As a note, you want s1, s2 and p to be volatile, otherwise the compiler
can cache the result.
> fd = open("prova", O_RDWR);
> assert(fd);
>
> fd1 = open("prova", O_RDWR);
> assert(fd1);
>
> p = mmap(NULL, 1024, PROT_WRITE|PROT_READ, MAP_PRIVATE,
> fd1, 0);
> assert((long) p != -1);
>
> x = *p;
>
> s1 = mmap(NULL, 1024, PROT_WRITE|PROT_READ, MAP_SHARED,
> fd, 0);
> assert((long) s1 != -1);
> s2 = mmap(NULL, 1024, PROT_WRITE|PROT_READ, MAP_SHARED,
> fd, 0);
> assert((long) s2 != -1);
>
> fprintf(stderr,"s1 %p s2 %p p %p\n", s1, s2, p);
> fprintf(stderr, "1: s1 %d s2 %d p %d\n", s1[0], s2[0], p[0]);
>
> s1[0] = 'a';
> s2[0] = 'b';
>
> msync(s1, 1024, MS_SYNC);
> msync(s2, 1024, MS_SYNC);
These msyncs should not be required for data via one shared mmap to be
visible via another mmap.
> assert(lseek(fd1, SEEK_SET, 0) == 0);
> assert(read(fd1, &x, 1) == 1);
> fprintf(stderr, "2: s1 %d s2 %d p %d x %d\n", s1[0], s2[0], p[0], x);
>
> return 0;
> }
More information about the linux-arm-kernel
mailing list