|
|
caddr_t mmap(caddr_t addr, size_t len, int prot, int flags, int fd, off_t off);mmap establishes a mapping between a process's address space and an object in the system's virtual memory. All other system functions that contribute to the definition of an address space are built from mmap, the system's most fundamental function for defining the contents of an address space. The format of an mmap call is:
paddr = mmap(addr, len, prot, flags, fd, off);mmap establishes a mapping from the process's address space at an address paddr for len bytes to the object specified by fd at offset off for len bytes. A successful call to mmap returns paddr as its result, which is an implementation-dependent function of the parameter addr and the setting of the MAP_FIXED bit of flags, as described below. The address range [paddr, paddr + len) must be valid for the address space of the process and the range [off, off + len) must be valid for the virtual memory object. (The notation [start, end) denotes the interval from start to end, including start but excluding end.)
The parameter prot determines whether read, execute, write or some combination of accesses are permitted to the pages being mapped. To deny all access, set prot to PROT_NONE. Otherwise, specify permissions by an OR of PROT_READ, PROT_EXECUTE, and PROT_WRITE.
A write access must fail if PROT_WRITE has not been set, though the behavior of the write can be influenced by setting MAP_PRIVATE in the flags parameter, which provides other information about the handling of mapped pages, as described below:
On the other hand, if MAP_PRIVATE is specified, an initial write reference to a page in the mapped area will create a copy of that page and redirect the initial and successive write references to that copy. This operation is sometimes referred to as copy-on-write and occurs invisibly to the process causing the store. Only pages actually modified have copies made in this manner. MAP_PRIVATE mappings are used by system functions such as exec(2) when mapping files containing programs for execution. This permits operations by programs such as debuggers to modify the ``text'' (code) of the program without affecting the file from which the program is obtained.
The mapping type is retained across a fork.
Similarly, if a program accesses an address in a manner inconsistently
with how it has been mapped (for instance, by attempting a store operation
into a mapping that was established with only
PROT_READ
access), then a
SIGSEGV
signal will
result.
SIGSEGV
signals will also result on any attempt to reference an address not defined
by any mapping.
In general, if a program makes a reference to an address that is inconsistent with the mapping (or lack of a mapping) established at that address, the system will respond with a SIGSEGV violation. However, if a program makes a reference to an address consistent with how the address is mapped, but that address does not evaluate at the time of the access to allocated storage in the object being mapped, then the system will respond with a SIGBUS violation. In this manner a program (or user) can distinguish between whether it is the mapping or the object that is inconsistent with the access, and take appropriate remedial action.
Using mmap to access system memory objects can simplify programs in a variety of ways. Keeping in mind that mmap can really be viewed as just a means to access memory objects, it is possible to program using mmap in many cases where you might program with read or write. However, it is important to realize that mmap can only be used to gain access to memory objects -- those objects that can be thought of as randomly accessible storage. Thus, terminals and network connections cannot be accessed with mmap because they are not ``memory.'' Magnetic tapes, even though they are memory devices, can not be accessed with mmap because storage locations on the tape can only be addressed sequentially. Some examples of situations which can be thought of as candidates for use of mmap over more traditional methods of file access include:
Mapping /dev/zero gives the calling program a block of zero-filled virtual memory of the size specified in the call to mmap. /dev/zero is a special device, that responds to read as an infinite source of bytes with the value 0, but when mapped creates an unnamed object to back the mapped region of memory. The following code fragment demonstrates a use of this to create a block of scratch storage in a program, at an address of the system's choosing.
/* * Function to allocate a block of zeroed storage. Parameter * is the number of bytes desired. The storage is mapped as * MAP_SHARED, so that if a fork occurs, the child process * will be able to access and modify the storage. If we wished * to cause the child's modifications (as well as those by the * parent) to be invisible to the ancestry of processes, we * would use MAP_PRIVATE. */ caddr_t get_zero_storage(int len); { int fd; caddr_t result;As written, this function permits a hierarchy of processes to use the area of allocated storage as a region of communication (for implicit interprocess communication purposes). Later in this section we will describe a set of system facilities that provide a similar function packaged for accomplishing the same purpose without requiring that the processes be in a parent-child hierarchy.if ((fd = open("/dev/zero", O_RDWR)) == -1) return ((caddr_t)-1); result = mmap(0, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); (void) close(fd); return (result); }
In some cases, devices or files are only useful if accessed via mapping. An example of this is frame buffer devices used to support bit-mapped displays, where display management algorithms function best if they can operate randomly on the addresses of the display directly.
Finally, it is important to remember that mappings can be operated upon at the granularity of a single page. Even though a mapping operation may define multiple pages of an address space, there is no restriction that subsequent operations on those addresses must operate on the same number of pages. For instance, an mmap operation defining ten pages of an address space may be followed by subsequent munmap (see below) operations that remove every other page from the address space, leaving five mapped pages each followed by an unmapped page. Those unmapped pages may subsequently be mapped to different locations in the same or different objects, or the whole range of pages (or any partition, superset, or subset of the pages) used in other mmap or other memory management operations. Further, it must be noted that any mapping operation that operates on more than a single page can ``partially succeed'' in that some parts of the address range can be affected even though the call returns a failure. Thus, an mmap operation that replaces another mapping, if it fails, may have deleted the previous mapping and failed to replace it. Similarly, other operations (unless specifically stated otherwise) may process some pages in the range successfully before operating on a page where the operation fails.
Not all device drivers support memory mapping. mmap fails if you try to map a device that does not support mapping.