mlock() - Unix、Linux 系统调用
Tutorials Point


  Unix 初学者指南
  Unix Shell 编程
  高级 Unix
  Unix 有用参考
  Unix 有用资源
  精选阅读

版权所有 © 2014 tutorialspoint



  首页     参考     讨论论坛     关于 TP  

mlock() - Unix、Linux 系统调用


previous next AddThis Social Bookmark Button

广告

名称

mlock、munlock、mlockall、munlockall - 锁定和解锁内存

语法

#include <sys/mman.h> 

int mlock(const void *addr, size_t len);

int munlock(const void *addr, size_t len);

int mlockall(int flags);

int munlockall(void);

描述

mlock() 和 mlockall() 分别将调用进程的虚拟地址空间的一部分或全部锁定到 RAM 中,防止该内存被换出到交换区。munlock() 和 munlockall() 执行相反的操作,分别解锁调用进程的虚拟地址空间的一部分或全部,以便在内核内存管理器需要时,指定虚拟地址范围内的页面可以再次被换出。内存锁定和解锁以整个页面的单位执行。

mlock() 和 munlock()

mlock() 锁定从addr开始,持续len字节的地址范围内的页面。当调用成功返回时,所有包含指定地址范围一部分的页面都保证驻留在 RAM 中;这些页面保证会保留在 RAM 中,直到以后解锁。

munlock() 解锁从addr开始,持续len字节的地址范围内的页面。在此调用之后,所有包含指定内存范围一部分的页面都可以由内核再次移动到外部交换空间。

mlockall() 和 munlockall()

mlockall() 锁定映射到调用进程地址空间的所有页面。这包括代码、数据和堆栈段的页面,以及共享库、用户空间内核数据、共享内存和内存映射文件。当调用成功返回时,所有映射的页面都保证驻留在 RAM 中;这些页面保证会保留在 RAM 中,直到以后解锁。

flags 参数是以下一个或多个常量的按位或结果

标签描述
MCL_CURRENT 锁定当前映射到进程地址空间的所有页面。
MCL_FUTURE 锁定将来将映射到进程地址空间的所有页面。例如,这些可能是不断增长的堆和栈所需的新页面,以及新的内存映射文件或共享内存区域。
如果已指定MCL_FUTURE,则以后的系统调用(例如,mmap(2)、sbrk(2)、malloc(3))可能会失败,如果会导致锁定的字节数超过允许的最大值(见下文)。在相同的情况下,堆栈增长也可能失败:内核将拒绝堆栈扩展并向进程发送SIGSEGV信号。

munlockall() 解锁映射到调用进程地址空间的所有页面。

备注

内存锁定有两个主要应用:实时算法和高安全性数据处理。实时应用程序需要确定性计时,并且与调度一样,分页是导致程序执行延迟意外的主要原因之一。实时应用程序通常也会使用sched_setscheduler(2)切换到实时调度程序。加密安全软件通常将密码或密钥等关键字节作为数据结构处理。由于分页,这些机密可能会被传输到持久交换存储介质上,在那里它们可能在安全软件已擦除 RAM 中的机密并终止后很长时间内仍可供敌人访问。(但请注意,笔记本电脑和某些台式电脑上的挂起模式会将系统 RAM 的副本保存到磁盘上,而无论内存锁如何。)

正在使用mlockall() 来防止页面错误延迟的实时进程应该在进入时间关键部分之前预留足够锁定的堆栈页面,以便函数调用不会导致任何页面错误。这可以通过调用分配足够大的自动变量(数组)并写入该数组占用的内存来实现,以便访问这些堆栈页面。这样,将为堆栈映射足够的页面,并可以将其锁定到 RAM 中。虚拟写入确保在关键部分不会发生复制时写入页面错误。

内存锁不会被通过fork(2)创建的子进程继承,并且会在execve(2)期间或进程终止时自动删除(解锁)。

如果通过munmap(2)取消映射地址范围,则该地址范围上的内存锁会自动删除。

内存锁不会堆叠,即,已通过调用mlock() 或mlockall() 多次锁定的页面将通过对相应范围调用munlock() 或通过munlockall() 解锁。映射到多个位置或由多个进程映射的页面只要至少在一个位置或至少一个进程中被锁定,就会保持锁定在 RAM 中。

Linux 备注

在 Linux 下,mlock() 和munlock() 会自动将addr向下舍入到最接近的页面边界。但是,POSIX.1-2001 允许实现要求addr与页面对齐,因此可移植的应用程序应确保这一点。

限制和权限

在 Linux 2.6.8 及更早版本中,进程必须具有特权(CAP_IPC_LOCK)才能锁定内存,并且RLIMIT_MEMLOCK软资源限制定义了进程可以锁定的内存量限制。

从 Linux 2.6.9 开始,对特权进程可以锁定的内存量没有限制,并且RLIMIT_MEMLOCK软资源限制改为定义非特权进程可以锁定的内存量限制。

返回值

如果成功,这些系统调用将返回 0。如果出错,则返回 -1,errno 被相应地设置,并且不会对进程地址空间中的任何锁进行更改。

错误

标签描述
ENOMEM (Linux 2.6.9 及更高版本)调用方具有非零RLIMIT_MEMLOCK软资源限制,但尝试锁定的内存超过了允许的限制。如果进程具有特权(CAP_IPC_LOCK),则不会强制执行此限制。
ENOMEM (Linux 2.4 及更早版本)调用进程尝试锁定的内存超过 RAM 的一半。
EPERM (Linux 2.6.9 及更高版本)调用方没有特权(CAP_IPC_LOCK),并且其RLIMIT_MEMLOCK软资源限制为 0。
EPERM (Linux 2.6.8 及更早版本)调用进程没有足够的权限来调用munlockall()。在 Linux 下,需要CAP_IPC_LOCK功能。
对于mlock() 和munlock()
EINVAL len 为负。
EINVAL (Linux 上不适用)addr 不是页面大小的倍数。
ENOMEM 指定地址范围的一部分与进程地址空间中映射的页面不对应。
对于mlockall()
EINVAL 指定了未知的flags
对于munlockall()
EPERM (Linux 2.6.8 及更早版本)调用方没有特权(CAP_IPC_LOCK)。

错误

在 2.4 系列 Linux 内核(直至 2.4.17 包括在内)中,一个错误导致mlockall() MCL_FUTURE 标志在fork(2) 过程中被继承。这在内核 2.4.18 中得到了纠正。

从内核 2.6.9 开始,如果特权进程调用mlockall(MCL_FUTURE) 并在以后放弃特权(例如,通过将其有效 UID 设置为非零值来丢失CAP_IPC_LOCK功能),则如果遇到RLIMIT_MEMLOCK资源限制,后续的内存分配(例如,mmap(2)、brk(2))将失败。

可用性

在提供mlock() 和munlock() 的 POSIX 系统上,_POSIX_MEMLOCK_RANGE 在<unistd.h>中定义,并且页面的字节数可以通过<limits.h>中的常量PAGESIZE(如果定义)或通过调用sysconf(_SC_PAGESIZE)来确定。

在提供mlockall() 和munlockall() 的 POSIX 系统上,_POSIX_MEMLOCK 在<unistd.h>中定义为大于 0 的值。(另请参阅sysconf(3)。)

符合标准

POSIX.1-2001、SVr4

另请参阅



previous next Printer Friendly

广告


  

广告



广告