內存映射函數mmap, 負責把文件內容或者其他對象映射到進程的虛擬內存空間, 通過對這段內存的讀取和修改,來實現對文件的讀取和修改,而不需要再調用read,write等操作。文件或者其他對象被映射到多個頁上,如果文件的大小不是所有頁的大小之和,最後一個頁不被使用的空間將會清零。munmap執行相反的操作,刪除特定地址區域的對象映射。
用法:
void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset); int munmap(void *start, size_t length);
參數:
start:映射區的開始地址。
length:映射區的長度。
prot:期望的內存保護標志,不能與文件的打開模式沖突。是以下的某個值,可以通過or運算合理地組合在一起
PROT_EXEC //頁內容可以被執行 PROT_READ //頁內容可以被讀取 PROT_WRITE //頁可以被寫入 PROT_NONE //頁不可訪問
flags:指定映射對象的類型,映射選項和映射頁是否可以共享。它的值可以是一個或者多個以下位的組合體
MAP_FIXED //使用指定的映射起始地址,如果由start和len參數指定的內存區重疊於現存的映射空間,重疊部分將會被丟棄。如果指定的起始地址不可用,操作將會失敗。並且起始地址必須落在頁的邊界上。
MAP_SHARED //與其它所有映射這個對象的進程共享映射空間。對共享區的寫入,相當於輸出到文件。直到msync()或者munmap()被調用,文件實際上不會被更新。
MAP_PRIVATE //建立一個寫入時拷貝的私有映射。內存區域的寫入不會影響到原文件。這個標志和以上標志是互斥的,只能使用其中一個。
MAP_DENYWRITE //這個標志被忽略。
MAP_EXECUTABLE //同上
MAP_NORESERVE //不要為這個映射保留交換空間。當交換空間被保留,對映射區修改的可能會得到保證。當交換空間不被保留,同時內存不足,對映射區的修改會引起段違例信號。
MAP_LOCKED //鎖定映射區的頁面,從而防止頁面被交換出內存。
MAP_GROWSDOWN //用於堆棧,告訴內核VM系統,映射區可以向下擴展。
MAP_ANONYMOUS //匿名映射,映射區不與任何文件關聯。
MAP_ANON //MAP_ANONYMOUS的別稱,不再被使用。
MAP_FILE //兼容標志,被忽略。
MAP_32BIT //將映射區放在進程地址空間的低2GB,MAP_FIXED指定時會被忽略。當前這個標志只在x86-64平台上得到支持。
MAP_POPULATE //為文件映射通過預讀的方式准備好頁表。隨後對映射區的訪問不會被頁違例阻塞。
MAP_NONBLOCK //僅和MAP_POPULATE一起使用時才有意義。不執行預讀,只為已存在於內存中的頁面建立頁表入口。
fd:有效的文件描述詞。如果MAP_ANONYMOUS被設定,為了兼容問題,其值應為-1。
offset:被映射對象內容的起點。
返回值說明:
成功執行時,mmap()返回被映射區的指針。失敗時,mmap()返回MAP_FAILED[其值為(void *)-1]。
munmap(void *start, size_t length);
取消參數start所指向的映射內存,參數length表示欲取消的內存大小。
返回值:解除成功返回0,否則返回-1,錯誤原因存於errno中。
一個簡單的實例,實現對framebuffer的操作:
#include <stdio.h> #include <sys/mman.h> #include <string.h> #include <linux/fb.h> #include <sys/ioctl.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdlib.h> #ifndef true #define true 1 #endif #ifndef false #define false 0 #endif int FB_Init() { fb = open("/dev/fb0", O_RDWR); if(fb < 0) { fprintf(stderr, "Open Failed\n"); return false; } if(ioctl(fb, FBIOGET_FSCREENINFO, &f_info) < 0) { fprintf(stderr, "Get FSCREENINFO Failed\n"); return false; } if(ioctl(fb, FBIOGET_VSCREENINFO, &v_info) < 0) { fprintf(stderr, "Get VSCREENINFO Failed\n"); return false; } screen_size = v_info.xres * v_info.yres * (v_info.bits_per_pixel) / 8; fbuffer = mmap(0, screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fb, 0); if((int)fbuffer == -1) { fprintf(stderr, "Mmap error\n"); return false; } } int FB_Close() { munmap(fbuffer, screen_size); close(fb); return true; } int point(int x,int y, ColorType color) { int temp; void *currPoint; if(x < 0 || x >= v_info.width) return false; if(y < 0 || y >= v_info.height) return false; temp = (x + v_info.xoffset) * (v_info.bits_per_pixel/8) + (y + v_info.yoffset) * f_info.line_length; *((unsigned short *)(fbuffer + temp)) = color; return true; } int main(int argc, char *argv[]) { FB_Init(); point(100, 100, 0x19ff1d00); FB_Close(); return 0; }
編譯運行後就在我們的framebuffer上的坐標為(100, 100)的地方畫出一個點。
本文出自 “驿落黃昏” 博客,請務必保留此出處http://yiluohuanghun.blog.51cto.com/3407300/857476