歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> 關於Linux >> Linux中mmap與munmap函數系統調用

Linux中mmap與munmap函數系統調用

日期:2017/3/3 16:27:01   编辑:關於Linux

內存映射函數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

Copyright © Linux教程網 All Rights Reserved