Mac OS X Internals: A Systems Approach

8.17. Memory-Mapped Files

Mac 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.

  • Anonymous memory is always backed by swap space.

  • A regular file's mapping is backed by the file itself if MAP_SHARED was specified in the flags argument to mmap(). This means that any modifications made to the mapping are written to the original file when the corresponding pages are evicted.

  • A regular file's mapping is backed by swap space if MAP_PRIVATE was specified in the flags argument. This means that any modifications made to the mapping are private.

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

Категории