Memory Mapped I/O
Reference: Chapter 12.9 and 14.9, Advanced Programming in the UNIX Environment, by W. Richard Stevens.

Memory mapped operations are useful because they are more efficient than the alternative and also save on file descriptors.

Consider the case of a file opened for reading by two processes. If the processes use read calls, then on a typical machine, the file is read from disk into a buffer cache. Then two in memory copy operations are required, one for each process to copy the data into the address space of each process. There will be three copies of the data in memory.

If the two processes use memory mapping instead, then the mapping is made, but no copying is done. Instead when one or the other process requires the data, a page fault occurs and at that time a single copy is obtained off disk, which can be used by either process. Equally significant is that access to the data is through user functions, not through system calls (read/write) which are much slower.

Memory mapping is used for dynamic libraries. On a Solaris system, trussing almost any program will show numerous mmap( ) calls. Use strace instead of truss on Linux systems. Shared memory is a related idea; it is used as a form of interprocess communication; the system calls used are shmget( ), shmctl( ), shmat( ), and shmdt( ) but should be used by careful experienced programmers only.

The basic idea of memory mapping is to map a byte range of a file to a range of process addresses. The system calls used are mmap( ), munmap( ), mprotect( ) and a number of calls in the memcpy family, which are described below. On BSD systems bcopy( ) is used. See BSD porting notes. For a good example of the use of mmap and memcpy to copy a file, check page 412, Chapter 12.9 of the reference.

Note that read and write are atomic, but memory ops are not. Any change made by one process is immediately seen by any other. Also no file locking is possible.

mmap - map pages of memory

#include <sys/mman.h>
addr = void *mmap(void *addr /* Specify NULL */,
size_t len, int prot, int flags, int fd, off_t off /* 0 for start of file */);
where The return value addr is the memory address, which subsequent code will need to use. Thus file range [off, off + len) maps to process address space [addr, addr + len) unless MAP_FAILED (-1) is returned through addr.

Closing the file descriptor does not remove the mapping as mmap increments the reference count to the file; instead use munmap or terminate the process.

munmap - unmap pages of memory

munmap(void *addr, size_t len);
removes the mappings for pages in the range.

mprotect - set protection of memory mapping

mprotect(void *addr, size_t len, int prot);
This function changes protection for pages in the range to prot.

msync - synchronize memory with physical storage

msync(void *addr, size_t len, int flags);
Write modified copies of pages in range to hardware.

memccpy, memchr, memcmp, memcpy, memmove, memset - memory operations from <string.h>

void *memccpy(void *dest, const void *src, int c, size_t n);
void *memchr(const void *s, int c, size_t n);
int   memcmp(const void *s1, const void *s2, size_t n);
void *memcpy(void *dest, const void *src, size_t n);
void *memmove(void *dest, const void *src, size_t n);
void *memset(void *s, int c, size_t n);
c is interpreted as an unsigned char throughout.
memccpy copies no more than n bytes from memory area src into memory area dest, stopping after the first c is found. It returns a pointer to the byte after the copy of c in dest, or NULL if c was not found in the first n bytes of src.
memchr returns a pointer to the first occurrence of c in the first n bytes of memory area s or NULL if c does not occur.
memcmp compares the first n bytes of memory areas s1 and s2. It returns an integer less than, equal to, or greater than 0, according as s1 is lexicographically less than, equal to, or greater than s2.
memcpy and memmove copy n bytes from memory area src to dest, and return dest. For memcpy memory areas may not overlap. Use memmove if memory areas overlap.
memset fills the first n bytes in memory area s to the value of c and returns s.

Last update: 2000 December 29