【Linux】存儲映射I/O—mmap

存儲映射I/O能將一個磁盤文件映射到存儲空間中的一個緩衝區上,於是可以用對緩衝區的讀寫代替對磁盤文件的讀寫,這樣就可以在不使用read和write的情況下執行I/O。爲了實現這種功能,應首先將一個給定的文件映射到一個存儲區域中,這由mmap函數實現。
注:子進程能夠通過fork繼承父進程的存儲映射區。

mmap函數

#include <sys/mman.h>
void *mmap(void *addr, size_t len, int prot, int flag, int fd, off_t off);
返回值:若成功,返回映射區的起始地址; 若出錯,返回MAP_FAILED

參數

  • addr

    用於指定映射存儲區的起始地址。通常將其設置爲0,表示由系統選擇該起始地址,並由函數返回。

  • fd
    指定要被映射文件的描述符。在文件映射到地址空間之前,必須先打開該文件。

  • len
    指定要映射的字節數。

  • off
    要映射字節在文件中的起始偏移量。

  • prot
    指定映射存儲區域的保護要求。如下圖所示

    prot 說明
    PROT_READ 映射區可讀
    PROT_WRITE 映射區可寫
    PROT_EXEC 映射區可執行
    PROT_NONE 映射區不可訪問

    可將proc參數指定爲PROT_NONE,也可以指定爲其他三項的任意組合的按位或。要注意,對於指定映射區域的保護要求不能超過文件open模式訪問權限。例如,文件是隻讀打開的,就不能對映射區指定PROT_WRITE。

  • flag
    下圖展示了一個存儲映射文件

    圖中“起始地址”是mmap的返回值,映射存儲區位於堆和棧之間(具體取決於實現)

    下面是flag參數可選的值,它們影響着映射存儲區的多種屬性:
    每種實現可能還有其它的一些標誌值,具體參見系統手冊。

    • MAP_FIXED
      返回值必須等於參數addr。這不利於可移植性,所以不推薦使用。如未指定此標誌,且addr不爲0,則系統只把addr作爲一個建議,但是不保證會使用該地址。

    • MAP_SHARED
      這一標誌描述了進程對映射區所進行的存儲操作的配置。該標誌指定存儲操作修改映射文件,也就是存儲操作相當於對該文件的write。
      注意:必須指定本標誌或下一個標誌(MAP_PRIVATE),但不能同時指定。

    • MAP_PRIVATE
      本標誌說明,對映射區的存儲操作導致該映射文件的一個私有副本。所有後來對該映射區的引用都是引用該副本。任何修改隻影響該副本,而不影響源文件。

    off和addr通常被要求是虛擬存儲頁長的整數倍,該長度可通過使用參數_SC_PAGE_SIZE的sysconf函數獲得。

相關信號

  • SIGSEGV
    只是進程試圖訪問對它不可用的存儲區。如果映射區指定爲只讀,那麼試圖向其中寫入數據就會產生該信號
  • SIGBUS

    如果映射區的某部分在訪問時已不存在,則產生該信號。

munmap函數

當進程終止時,會自動解除存儲映射區的映射,或者調用munmap函數也可以解除映射區。關閉被映射的文件描述符並不能解除映射區。munmap並不會使映射區的內容寫入到磁盤文件中,對於MAP_SHARED區的數據,會由內核在某個時刻將其寫入磁盤文件;而對於MAP_PRIVATE區的修改會被丟棄。

#include <sys/mman.h>
int munmap(void *addr, size_t len)
    //返回值:成功,返回0;出錯,返回-1

;

mprotect函數

調用該函數可以修改一個現有映射的權限。

#include <sys/mman.h>
int mprotect(void *addr, size_t len, int prot);
    //返回值:成功,返回0;出錯,返回-1

msync函數

將被修改的頁沖洗到被映射的文件中。

#include <sys/mman.h>
int msync(void *addr, size_t len, int flags);
    //返回值:成功,返回0;出錯,返回-1
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章