8.17. Memory-Mapped FilesMac OS X provides the mmap() system call for mapping files, character devices, and POSIX shared memory descriptors into the caller's address space. Moreover, anonymous memory can be mapped by setting MAP_ANON in the flags argument to mmap(). void * mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset); When mmap() is used to map a regular file or anonymous memory, the mapping is backed by an on-disk object as follows.
Let us discuss the implementation of mmap() by looking at the sequence of operations that take place when a program maps a regular file. First, the program must acquire a file descriptor for the file in question. Figure 848 shows the relevant activity that occurs because of the open() system call. In this case, a preexisting regular file residing on an HFS Plus volume is being opened for the first time. Figure 848. Setting up the vnode pager during the open() system call![]() The vnode structure (struct vnode [bsd/sys/vnode_internal.h]) corresponding to a regular file contains a pointer to a UBC information structure (struct ubc_info [bsd/sys/ubc_internal.h]). The ubc_info structure contains a pointer to the pagerin this case, the vnode pager, as represented by a vnode_pager structure (struct vnode_pager [osfmk/vm/bsd_vm.c]). Figure 849 shows how these structures are connected when the vnode is created. Figure 849. Setting up of the vnode pager for a newly created vnode![]() Suppose a user program calls mmap() to map the file descriptor obtained in Figure 848. Figure 850 shows the ensuing kernel activity. mmap() calls mach_vm_map() [osfmk/vm/vm_user.c], which, in our case of a regular file, will call vm_object_enter() [osfmk/vm/vm_object.c]. Since no VM object will be associated with the given pager yet, vm_object_enter() will create a new VM object. Moreover, it will initialize the pager, which includes allocating a control port and passing it as an argument to memory_object_init(). Finally, the call to vm_map_enter() [osfmk/vm/vm_map.c] will result in a virtual address range being allocated in the task's virtual address space. Figure 850. Kernel processing of the mmap() system call![]() When the program attempts to access an address of the mapped memory for reading, it will cause page-in activity if the corresponding page is not resident yet (to begin with, no pages will be resident). Since the program mapped the file with PROT_READ | PROT_WRITE as the protection value and MAP_SHARED specified in the flags, it will also eventually cause page-out activity if it modifies the mapped memory. Figures 851 and 852 show an overview of the steps involved in a page-in operation, with the latter showing details of paging in from a vnode. Figures 853 and 854 show the analogous overview for a page-out operation. Figure 851. An overview of a page-in operation![]() Figure 852. Paging in from a vnode![]() Figure 853. An overview of a page-out operation![]() Figure 854. Paging out to a vnode![]() |