Attached another test program. I don't expect it to print any errors with any OS, but I'd like to confirm it for non-Linux SMP kernels.
(Except for OpenBSD, it doesn't work correctly in it anyway because it doesn't support mixing write()s and mmap())
/* gcc concurrency.c -o concurrency -Wall */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <unistd.h> #include <assert.h> #include <sys/stat.h> #include <sys/file.h> #include <sys/mman.h> #define MAX_PAGESIZE (8192) int main(int argc, char *argv[]) { char buf[MAX_PAGESIZE*2], ones[4] = { 1, 1, 1, 1 }; int fd, pagesize; int process_count = 5; void *mmap_base = NULL; size_t mmap_size = 0; struct stat st; int fixed; memset(buf, 0, sizeof(buf)); pagesize = getpagesize(); assert(pagesize <= MAX_PAGESIZE); buf[pagesize] = 'h'; if (fork() == 0) { printf("writing, page size = %d\n", pagesize); for (;;) { fd = open("foo2", O_RDWR | O_CREAT | O_TRUNC, 0600); if (fd == -1) { perror("open()"); return 1; } if (flock(fd, LOCK_EX) < 0) perror("flock()"); if (rename("foo2", "foo") < 0) perror("rename()"); usleep(rand() % 1000); pwrite(fd, buf, pagesize + 16, 0); //usleep(rand() % 1000); //fdatasync(fd); pwrite(fd, ones, 4, pagesize-4); if (flock(fd, LOCK_UN) < 0) perror("flock()"); close(fd); usleep(rand() % 1000); } } else { while (process_count-- > 1) { if (fork() == 0) break; } printf("%d: reading, page size = %d\n", process_count, pagesize); for (;; close(fd), usleep(rand() % 1000)) { fd = open("foo", O_RDWR, 0600); if (fd == -1) { perror("open()"); return 1; } if (fstat(fd, &st) < 0) perror("fstat()"); fixed = 0; again: if (st.st_size < pagesize) continue; if (mmap_base != NULL && mmap_base != MAP_FAILED) munmap(mmap_base, mmap_size); mmap_size = st.st_size; mmap_base = mmap(NULL, mmap_size, PROT_READ, MAP_SHARED, fd, 0); if (memcmp((char *)mmap_base + pagesize - 4, ones, 4) == 0) { if (mmap_size != pagesize+16) { if (mmap_size == pagesize && fstat(fd, &st) == 0 && st.st_size != pagesize) { fixed = 1; goto again; } printf("page size cut, mmap_size=%ld\n", mmap_size); } else if (((char *)mmap_base)[pagesize] != 'h') printf("broken data\n"); } } } return 0; }
signature.asc
Description: This is a digitally signed message part