mlock() - Unix,Linux系統呼叫
廣告
名稱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參見
廣告
|