mmap() - Unix,Linux 系统调用
广告
名称mmap、munmap - 将文件或设备映射或取消映射到内存语法
#include <sys/mman.h>
void *mmap(void *start, size_t length, int prot, int flags,
int fd, off_t offset);
int munmap(void *start, size_t length);
|
描述mmap() 函数请求将从文件(或其他对象)指定的文件描述符 fd 的偏移量 offset 开始的 length 字节映射到内存中,最好映射到地址 start。后一个地址只是一个提示,通常指定为 0。mmap() 返回对象实际映射到的位置。prot 参数描述所需的内存保护(并且不得与文件的打开模式冲突)。它要么是 PROT_NONE,要么是其他 PROT_* 标志的一个或多个的按位或。
标签 | 描述 |
PROT_EXEC | 页面可以执行。 |
PROT_READ | 页面可以读取。 |
PROT_WRITE | 页面可以写入。 |
PROT_NONE | 页面无法访问。 |
flags 参数指定映射对象的类型、映射选项以及对映射页面的副本所做的修改是特定于进程的还是与其他引用共享。它具有位
标签 | 描述 |
MAP_FIXED | 不要选择与指定地址不同的地址。如果由 start 和 len 指定的内存区域与任何现有映射的页面重叠,则现有映射的重叠部分将被丢弃。如果无法使用指定的地址,mmap() 将失败。如果指定了 MAP_FIXED,则 start 必须是页面大小的倍数。不鼓励使用此选项。 |
MAP_SHARED | 与映射此对象的所有其他进程共享此映射。存储到该区域等效于写入文件。在调用 msync(2) 或 munmap(2) 之前,文件可能不会实际更新。 |
MAP_PRIVATE | 创建一个私有的写时复制映射。存储到该区域不会影响原始文件。在 mmap() 调用之后对文件进行的更改是否在映射区域中可见尚不确定。 |
必须精确指定 MAP_SHARED 和 MAP_PRIVATE 中的一个。以上三个标志在 POSIX.1-2001 中进行了描述。Linux 还了解以下非标准标志
标签 | 描述 |
MAP_DENYWRITE | | 此标志被忽略。(很久以前,它表示尝试写入基础文件应以 ETXTBUSY 失败。但这会导致拒绝服务攻击。) |
MAP_EXECUTABLE | | 此标志被忽略。 |
MAP_NORESERVE | | 不要为此映射保留交换空间。当保留交换空间时,可以保证可以修改映射。如果没有物理内存可用,当没有保留交换空间时,写入时可能会得到 SIGSEGV。另请参见 proc(5) 中关于文件 /proc/sys/vm/overcommit_memory 的讨论。在 2.6 之前的内核中,此标志仅对私有可写映射有效。 |
MAP_LOCKED(自 Linux 2.5.37 起) | | 以 mlock() 的方式将映射区域的页面锁定到内存中。此标志在较旧的内核中被忽略。 |
MAP_GROWSDOWN | | 用于堆栈。指示内核 VM 系统映射应在内存中向下扩展。 |
MAP_ANONYMOUS | | 映射不受任何文件支持;fd 和 offset 参数被忽略。自内核 2.4 以来,仅在 Linux 上支持将此标志与 MAP_SHARED 结合使用。 |
MAP_ANON | | MAP_ANONYMOUS 的别名。已弃用。 |
MAP_FILE | | 兼容性标志。被忽略。 |
MAP_32BIT | | 将映射放入进程地址空间的前 2GB 中。设置 MAP_FIXED 时被忽略。此标志目前仅在 x86-64 上的 64 位程序中受支持。 |
MAP_POPULATE(自 Linux 2.5.46 起) | | 通过对文件执行预读来填充(预故障)文件映射的页表。以后对映射的访问不会因页面错误而被阻止。 |
MAP_NONBLOCK(自 Linux 2.5.46 起) | | 仅在与 MAP_POPULATE 结合使用时才有意义。不要执行预读:仅为 RAM 中已存在的页面创建页表条目。 |
某些系统记录了其他标志 MAP_AUTOGROW、MAP_AUTORESRV、MAP_COPY 和 MAP_LOCAL。
除非设置了 MAP_ANONYMOUS,否则 fd 应为有效的文件描述符。如果设置了 MAP_ANONYMOUS,则在 Linux 上会忽略 fd。但是,某些实现要求如果指定了 MAP_ANONYMOUS(或 MAP_ANON),则 fd 为 -1,并且可移植应用程序应确保这一点。
offset 应为 getpagesize(2) 返回的页面大小的倍数。 由 mmap() 映射的内存在 fork(2) 中保留,并具有相同的属性。 文件以页面大小的倍数映射。对于不是页面大小倍数的文件,在映射时剩余的内存将清零,并且对该区域的写入不会写入文件。在映射中对应于文件添加或删除区域的页面上更改基础文件的大小所产生的影响是不确定的。 munmap() 系统调用删除指定地址范围的映射,并导致对该范围内的地址的进一步引用生成无效的内存引用。当进程终止时,该区域也会自动取消映射。另一方面,关闭文件描述符不会取消映射该区域。 地址 start 必须是页面大小的倍数。包含指示范围的一部分的所有页面都将取消映射,并且随后对这些页面的引用将生成 SIGSEGV。如果指示的范围不包含任何映射的页面,则不会出错。 对于文件支持的映射,映射文件的 st_atime 字段可以在 mmap() 和相应的取消映射之间随时更新;如果尚未更新,则对映射页面的第一次引用将更新该字段。 使用 PROT_WRITE 和 MAP_SHARED 映射的文件的 st_ctime 和 st_mtime 字段将在写入映射区域后以及在随后的 msync()(带有 MS_SYNC 或 MS_ASYNC 标志)之前更新,如果发生这种情况。 返回值成功时,mmap() 返回指向映射区域的指针。发生错误时,将返回 MAP_FAILED(即 (void *) -1),并且 errno 将被相应地设置。成功时,munmap() 返回 0,失败时返回 -1,并且 errno 被设置(可能为 EINVAL)。备注PROT_READ 是否包含 PROT_EXEC 取决于体系结构。可移植程序如果打算在新的映射中执行代码,则应始终设置 PROT_EXEC。错误
标签 | 描述 |
EACCES | 文件描述符引用非常规文件。或者请求了 MAP_PRIVATE,但 fd 未打开以供读取。或者请求了 MAP_SHARED 并且设置了 PROT_WRITE,但 fd 未以读写 (O_RDWR) 模式打开。或者设置了 PROT_WRITE,但文件是追加模式。 |
EAGAIN | 文件已被锁定,或者锁定了太多内存(请参阅 setrlimit(2))。 |
EBADF |
fd 不是有效的文件描述符(并且未设置 MAP_ANONYMOUS)。 |
EINVAL | 我们不喜欢 start 或 length 或 offset。(例如,它们太大或未对齐到页面边界。) |
ENFILE | 已达到系统对打开文件总数的限制。 |
ENODEV | 指定文件的底层文件系统不支持内存映射。 |
ENOMEM | 没有可用的内存,或者进程的最大映射数将被超过。 |
EPERM | prot 参数请求 PROT_EXEC,但映射区域属于已安装为 no-exec 的文件系统上的文件。 |
ETXTBSY | |
设置了 MAP_DENYWRITE,但 fd 指定的对象已打开以供写入。 |
使用映射区域可能导致以下信号 |
SIGSEGV | | 尝试写入以只读方式映射的区域。 |
SIGBUS | 尝试访问缓冲区中不对应于文件的部分(例如,超出文件末尾,包括另一个进程已截断文件的情况)。 |
可用性在提供 mmap()、msync() 和 munmap() 的 POSIX 系统上,_POSIX_MAPPED_FILES 在 <unistd.h> 中定义为大于 0 的值。(另请参阅 sysconf(3)。)符合标准SVr4、4.4BSD、POSIX.1-2001。错误在 Linux 上,没有像 MAP_NORESERVE 下面建议的那样的保证。默认情况下,当系统内存不足时,任何进程都可能在任何时候被杀死。在 2.6.7 之前的内核中,MAP_POPULATE 标志仅在 prot 指定为 PROT_NONE 时才有效。 另请参阅
B.O. Gallmeister,POSIX.4,O’Reilly,第 128-129 页和 389-391 页。
广告
|