|
|
#include <sys/types.h> #include <sys/mman.h>void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t off);
void *mmap64(void *addr, size_t len, int prot, int flags, int fd, off64_t offset);
The format of the call is as follows:
pa = mmap(addr, len, prot, flags, fd, off);
mmap establishes a mapping between the process's address space at an address pa for len bytes and the file represented by the file descriptor fd at offset off for len bytes. The value of pa is an implementation-dependent function of the parameter addr and values of flags, further described below. A successful mmap call returns pa as its result.
The parameter
prot
determines whether read, write, execute,
or some combination of accesses are permitted to the
pages being mapped.
The protection options are defined in
sys/mman.h
as:
PROT_READ Page can be read.
PROT_WRITE Page can be written.
PROT_EXEC Page can be executed.
PROT_NONE Page can not be accessed.
Not all implementations literally provide all possible combinations. PROT_WRITE is often implemented as PROT_READ|PROT_WRITE and PROT_EXEC as PROT_READ|PROT_EXEC. However, no implementation will permit a write to succeed where PROT_WRITE has not been set. The behavior of PROT_WRITE can be influenced by setting MAP_PRIVATE in the flags parameter, described below.
The parameter flags provides other information about the handling of the mapped pages. The options are defined in sys/mman.h as:
MAP_SHARED Share changes.
MAP_PRIVATE Changes are private.
MAP_FIXED Interpret addr exactly.
MAP_ANONYMOUS Map /dev/zero without open or close.
MAP_SHARED and MAP_PRIVATE describe the disposition of write references to the file. If MAP_SHARED is specified, write references will change the file. If MAP_PRIVATE is specified, the initial write reference will create a private copy of the modified file page and redirect the mapping to the copy. Either MAP_SHARED or MAP_PRIVATE must be specified, but not both. The mapping type is retained across a fork(S).
Note that the private copy is not created until either the first write or the page is locked for write access (see memcntl(S)); until then, other users who have the file mapped MAP_SHARED can change the image of the file observed in the mapped page.
MAP_FIXED informs the system that the value of pa must be addr, exactly. The use of MAP_FIXED is discouraged, as it may prevent an implementation from making the most effective use of system resources.
The MAP_ANONYMOUS flag provides a mapping identical to that obtained by mapping /dev/zero. However, there is no need for the program to open and close a device.
When MAP_ANONYMOUS is specified fd must be set to ``-1''.
Using MAP_ANONYMOUS is faster than mapping /dev/zero, even after device /dev/zero is already open, due to the system's ability to completely bypass the device layer. Also see ``Usage'' and ``Standards Conformance'', below.
When MAP_FIXED is not set, the system uses addr in an implementation-defined manner to arrive at pa. The pa so chosen will be an area of the address space which the system deems suitable for a mapping of len bytes to the specified file. All implementations interpret an addr value of zero as granting the system complete freedom in selecting pa, subject to constraints described below. A non-zero value of addr is taken to be a suggestion of a process address near which the mapping should be placed. When the system selects a value for pa, it will never place a mapping at address 0, nor will it replace any extant mapping, nor map into areas considered part of the potential data or stack segments. pa will be aligned on a page boundary. When MAP_FIXED is specified, addr must be aligned on a page boundary.
off is the offset into the file to be mapped. off is constrained to be aligned on a page boundary.
The address range covered by [pa, pa + len) must be legitimate for the address space of a process. mmap cannot grow a file.
The mapping established by mmap replaces any previous mappings for the process's pages in the range [pa, pa + len).
In the case where off + len exceeds the length of the file, the system will zero-fill the mapping from the end of the file to the next page boundary. If the process modifies any portion of the mapped region beyond the end of the file, there is no guarantee that the system will write those changes out to the file; the results are file system dependent. References to pages in a mapped region which are beyond the page containing the end of a file will result in the delivery of a SIGBUS signal. SIGBUS signals may also be delivered on various file system conditions, including quota exceeded errors.
mmap adds an extra reference to the file associated with the file descriptor fd which is not removed by a subsequent close on that file descriptor. This reference is removed when the entire range is unmapped (explicitly or implicitly). A mapping is unmapped explicitly with munmap, or implicitly with exit(S), exec(S), or by an mmap MAP_FIXED to the same range.
In the following conditions, mmap and mmap64 fail and set errno to:
fd = open(...) lseek(fd, offset) read(fd, buf, len) /* use data in buf */
Here is a rewrite using mmap:
fd = open(...) address = mmap((void *) 0, len, (PROT_READ | PROT_WRITE), MAP_PRIVATE, fd, offset) /* use data at address */
The most straightforward way to get zero-filled space using mmap without MAP_ANONYMOUS is demonstrated by the following code fragment:
fd = open("/dev/zero", O_RDONLY); ptr = mmap(0, desired_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); close(fd);
This approach, while very reasonable in concept, is expensive in terms of system performance, particularly if multiple such calls to mmap are required by the application.
This is what MAP_ANONYMOUS addresses. The three lines of code above turn into a single system call:
ptr = mmap(0, desired_size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
MAP_ANONYMOUS causes mmap to ignore the file descriptor argument and act as if it had been given one referring to /dev/zero.
An application can take advantage of MAP_ANONYMOUS and still run on systems that do not implement it, by attempting first MAP_ANONYMOUS and, if this fails, then opening /dev/zero.