I've been playing around with copy-on-write buffers on Linux and the following example seems to work as intended:
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#define SIZE 4096
#define SHM_NAME "foobar"
int main(void)
{
int fd = shm_open(SHM_NAME, O_RDWR | O_CREAT, 0666);
int r = ftruncate(fd, SIZE);
char *buf1 = mmap(NULL, SIZE, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0);
strcpy(buf1, "Original buffer");
char *buf2 = mmap(NULL, SIZE, PROT_READ | PROT_WRITE,
MAP_PRIVATE, fd, 0);
// At this point buf2 is aliased to buf1
// Now modifying buf2 should trigger copy-on-write)...
strcpy(buf2, "Modified buffer");
// buf1 and buf2 are now two separate buffers
strcpy(buf1, "Modified original buffer");
// clean up
r = munmap(buf2, SIZE);
printf("munmap(buf2): %i\n", r);
r = munmap(buf1, SIZE);
printf("munmap(buf1): %i\n", r);
r = shm_unlink(SHM_NAME);
printf("shm_unlink: %i\n", r);
return EXIT_SUCCESS;
}
However under OS X (10.10) the second mmap
call returns MAP_FAILED
, with errno
= 22 (EINVAL
). The OS X man page for mmap
seems to suggest that this should work (it even mentions copy-on-write in the description of the MAP_PRIVATE
flag), and I've experimented with various different flags for the calls to mmap
, but nothing seems to work. Any ideas ?
It appears that using shm_open
with MAP_SHARED
and MAP_PRIVATE
does something undesirable with the file descriptor. Using open
is a possible workaround:
int fd = open(SHM_NAME, O_RDWR | O_CREAT, 0666);
...
Result:
munmap(buf2): 0
munmap(buf1): 0
shm_unlink: -1
Using shm_open
with MAP_SHARED
and MAP_PRIVATE
results in an Invalid file descriptor
, although using it with MAP_SHARED
and MAP_SHARED
for example does not. It's unclear to me whether this is a bug, or by design - the behavior does not seem correct though.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With