mmap msync munmap close

来源:互联网 发布:知乎在国外开中餐厅 编辑:程序博客网 时间:2024/05/30 20:07


转自:http://blog.163.com/xychenbaihu@yeah/blog/static/132229655201082753446602/
open 打开文件后——>使用mmap建设文件映射;建立文件映射后,可以对映射到的空间进行操作。用msync同步到文件中。
问:close后对映射空间的操作能够同步到文件中吗?
答:可以,只要文件映射存在,就可以向你映射空间的内容写入文件,实现空间和文件的同步。
实例代码::
 
#include <stdio.h>   
#include <stdlib.h>   
#include <string.h>   
#include <unistd.h>   
#include <sys/mman.h>   
#include <sys/types.h>   
#include <fcntl.h>   

int  main( int  argc,  char  *argv[])  
{  
  int  fd;  
  char  *addr;  
  char  *str=  "Hello World" ;  
 fd = open( "./a" ,O_CREAT|O_RDWR|O_TRUNC,0666);  
  if (fd == -1)  
 {  
  perror( "open file fail:" );  
  exit(1);  
 }  
  if (ftruncate(fd,4096)==-1)  
 {  
  perror( "ftruncate fail:" );  
  close(fd);  
  exit(1);  
 }  
 addr =( char  *) mmap(NULL,4096,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);  
  if (addr == ( char  *)MAP_FAILED)  
 {  
  perror( "mmap fail:" );  
  exit(1);  
 }  
 memset(addr, ' ' ,4096);  
   
 memcpy(addr,str,strlen(str));                        //hello world  1   
 close(fd);  
 memcpy(addr+strlen(str),str,strlen(str));            //hello world  2   
 if (msync(addr,4096,MS_SYNC)==-1)  
 {  
  perror( "msync fail:" );  
  exit(1);  
 }  
  munmap(addr,4096);  
  return  0;  
 
 
========================================
另摘自: http://www.ppkao.com/linux/2011/36566.html
//下面的代码把文件1.ls中的内容通过mmap函数写入2.ls中,忽略出错处理
int fd=open("1.ls",O_RDONLY);
int fd2=open("2.ls",O_CREAT|O_RDWR|O_TRUNC,S_IRUSR|S_IWUSR);//必须设置读写权限,若只有写权限,会产生SIGSEGV信号
//mmap进行文件映射时必须先读取文件`
struct stat st;
fstat(fd,&st);
lseek(fd2,st.st_size-1,SEEK_SET);
write(fd2,"",1);        //必须的,如果不设置,当写入数据的时候会遇到文件结束符,产生SIGBUS信号
void *_src=mmap(NULL,st.st_size,PROT_READ,MAP_SHARED, fd,0);
void *_des=mmap(NULL,st.st_size,PROT_WRITE,MAP_SHARED,fd2,0);
close(fd);      //关闭文件后 依然可修改文件内容
close(fd2);

memcpy(_des,_src,st.st_size);

总结一下,可能产生的问题如下:
1.进行文件映射的描述符必须拥有读权限,否则会产生SIGSEGV信号
2.把内存内容写入映射文件时,必须确保被写文件当前位置到文件结尾的长度不小于所写内容长度,否则产生SIGBUS信号
3.关闭文件描述符并不能保证文件内容不被修改
4.munmap并不能使映射的内容写回磁盘
=======================================================================================
 
 
在编写设备驱动程序的时候,如果要想把设备内存映射到用户空间,那需要我们实现mmap,通过看ldd3上面的介绍,对实现mmap有了一点了解. 
书上介绍主要是利用 
int remap_pfn_range(struct vm_area_struct*vma,unsignedlong virt_addr,unsigned long pfn,unsignedlong size, pgprot_t prot) 函数或者 
int io_remap_page_range(struct vm_area_struct*vma,unsignedlong virt_addr,unsigned long phys_addr,unsignedlong size, pgprot_t prot)函数来实现,它们负责建立新的页表.这两个函数的区别是第一个函数是在参数pfn指向实际系统RAM的时候使用,而第二个函数是在 phys_addr指向I/O内存的时候使用.对于ARM平台来说,系统内存和端口应该是统一编址的,所以两个函数是等价的. 
还有另外一个函数就是nopage函数,是VMA结构体中可以填充的一个函数,在虚拟页没有所对应的物理页的时候,会调用此函数,来分配一个物理页给虚拟页. 
int remap_page_range(unsignedlong from,unsigned long phys_addr,unsignedlong size, pgprot_t prot) 

其中from是映射开始的虚拟地址。这个函数为虚拟地址空间from和from+size之间的范围构造页表; 
phys_addr是虚拟地址应该映射到的物理地址; 
size是被映射区域的大小; 
prot是保护标志。 
remap_page_range的处理过程是对from到form+size之间的每一个页面,查找它所在的页目录和页表(必要时建立页表),清除页表项旧的内容,重新填写它的物理地址与保护域。 
remap_page_range可以对多个连续的物理页面进行处理。<<Linux设备驱动程序>>指出, 
remap_page_range只能给予对保留的页和物理内存之上的物理地址的访问,当对非保留的页使用 
remap_page_range时,缺省的nopage处理控制映射被访问的虚地址处的零页。所以在分配内存后,就要对所分配的内存置保留位,它是通过函数mem_map_reserve实现的,它就是对相应物理页面置 
PG_reserved标志位。
remap_pfn_range 通过你的页帧号来建立页表, 并映射到用户空间!
一般情况是你的驱动分配一块内存,然后在驱动的mmap中使用这块内存的 物理地址转成页帧号, 再调用remap_pfn_range!
1, 假设你是通过kmalloc(),get_free_pages()等分配的,这种内存页是不能通过remap_pfn_range()映射出去的,要对 每个页面调用SetPageReserverd()标记为“保留”才可以,virt_to_phys()函数只是得到其物理地 址,remap_pfn_range()中的第三个参数是要求物理页便的“帧”号,即pfn,所以你的phys还要“>> PAGE_SHIFT”操作 
2,假设你是通过vmalloc分配得来的,同上,不同的是要用vmalloc_to_pfn 
3,用kmalloc,get_free_pages,vmalloc分配的物理内存页面最好还是不要用remap_pfn_page方法,建议使用VMA的nopage方法 
4,对于这样的设备内存,最好对调用pgprot_nocached(vma-> vm_page_prot)后传给remap_pfn_range,防止处理器缓存
以下是Camera mmap的一个例子:

  1.  * V4L interface- mmap function  
     * @param file        structure file *  
     * @param vma         structure vm_area_struct*  
     * @return status     0 Success, EINTR busy lock error, ENOBUFS remap_page error  
     */   
    static   int  mxc_mmap(struct  file*file,  struct  vm_area_struct*vma)  
    {  
    struct  video_device *dev = video_devdata(file);  
    unsigned  long  size;  
          int  res = 0;  
         cam_data *cam = video_get_drvdata(dev);  
         pr_err( "=============================camera mmap\n" );  
         pr_err( "In MVC:mxc_mmap\n" );  
         pr_err( "   pgoff=0x%lx, start=0x%lx, end=0x%lx\n" ,  
                vma->vm_pgoff, vma->vm_start, vma->vm_end);  
          /* make this _really_ smp-safe */   
          if  (down_interruptible(&cam->busy_lock))  
                      return  -EINTR;  
         size = vma->vm_end- vma->vm_start;  
         vma->vm_page_prot= pgprot_writecombine(vma->vm_page_prot);  
          if  (remap_pfn_range(vma, vma->vm_start,  
                         vma->vm_pgoff, size, vma->vm_page_prot)) {  
               pr_err( "ERROR: v4l2 capture: mxc_mmap: "   
                             "remap_pfn_range failed\n" );  
               res = -ENOBUFS;  
                goto  mxc_mmap_exit;  
         }  
         vma->vm_flags&=~VM_IO; /* using shared anonymous pages */   
         mxc_mmap_exit:  
         up(&cam->busy_lock);  
          return  res;  
    }
  2.  * V4L interface - mmap function  
     * @param file        structure file *  
     * @param vma         structure vm_area_struct *  
     * @return status     0 Success, EINTR busy lock error, ENOBUFS remap_page error  
     */
       
    static   int  mxc_mmap(struct  file*file,  struct  vm_area_struct*vma)  
    {  
    struct  video_device *dev = video_devdata(file);  
    unsigned  long  size;  
          int  res = 0;  
         cam_data *cam = video_get_drvdata(dev);  
         pr_err( "=============================camera mmap\n" );  
         pr_err( "In MVC:mxc_mmap\n" );  
         pr_err( "   pgoff=0x%lx, start=0x%lx, end=0x%lx\n" ,  
                vma->vm_pgoff, vma->vm_start, vma->vm_end);  
          /* make this _really_ smp-safe */   
          if  (down_interruptible(&cam->busy_lock))  
                      return  -EINTR;  
         size = vma->vm_end- vma->vm_start;  
         vma->vm_page_prot= pgprot_writecombine(vma->vm_page_prot);  
          if  (remap_pfn_range(vma, vma->vm_start,  
                         vma->vm_pgoff, size, vma->vm_page_prot)) {  
               pr_err( "ERROR: v4l2 capture: mxc_mmap: "   
                             "remap_pfn_range failed\n" );  
               res = -ENOBUFS;  
                goto  mxc_mmap_exit;  
         }  
         vma->vm_flags&=~VM_IO; /* using shared anonymous pages */   
         mxc_mmap_exit:  
         up(&cam->busy_lock);  
          return  res;  
    }
    /*!
     * V4L interface - mmap function
     * @param file        structure file *
     * @param vma         structure vm_area_struct *
     * @return status     0 Success, EINTR busy lock error, ENOBUFS remap_page error
     */

    static int mxc_mmap(struct file*file,struct vm_area_struct*vma)
    {
    struct video_device *dev = video_devdata(file);
    unsigned long size;
         int res = 0;
         cam_data *cam = video_get_drvdata(dev);
         pr_err("=============================camera mmap\n");
         pr_err("In MVC:mxc_mmap\n");
         pr_err("   pgoff=0x%lx, start=0x%lx, end=0x%lx\n",
                vma->vm_pgoff, vma->vm_start, vma->vm_end);
         /* make this _really_ smp-safe */
         if (down_interruptible(&cam->busy_lock))
                     return -EINTR;
         size = vma->vm_end- vma->vm_start;
         vma->vm_page_prot= pgprot_writecombine(vma->vm_page_prot);
         if (remap_pfn_range(vma, vma->vm_start,
                         vma->vm_pgoff, size, vma->vm_page_prot)) {
               pr_err("ERROR: v4l2 capture: mxc_mmap: "
                            "remap_pfn_range failed\n");
               res = -ENOBUFS;
               goto mxc_mmap_exit;
         }
         vma->vm_flags&=~VM_IO;/* using shared anonymous pages */
         mxc_mmap_exit:
         up(&cam->busy_lock);
         return res;
    }
    ========================================
    用户层调用:
    mmap (NULL, mCaptureBuffers[i].length,PROT_READ | PROT_WRITE, MAP_SHARED, fd_v4l, mCaptureBuffers[i].phy_offset);
    以下是抓取的Log:
     [   46.355719]=============================camera mmap
    [   46.360704] In MVC:mxc_mmap
    [   46.363635]    pgoff=0x93900, start=0x40c0f000, end=0x40cbf000
    [   46.459041]=============================camera mmap
    [   46.464109] In MVC:mxc_mmap
    [   46.466908]    pgoff=0x93a00, start=0x40dbf000, end=0x40e6f000
    [   46.569979]=============================camera mmap
    [   46.575116] In MVC:mxc_mmap
    [   46.577927]    pgoff=0x93b00, start=0x42692000, end=0x42742000
    [   46.631274]=============================camera mmap
    [   46.636332] In MVC:mxc_mmap
    [   46.639130]    pgoff=0x93c00, start=0x42842000, end=0x428f2000
    [   46.673606]=============================camera mmap
    [   46.678661] In MVC:mxc_mmap
    [   46.681459]    pgoff=0x93d00, start=0x429f2000, end=0x42aa2000
    拍照:
    [ 1072.567111]=============================camera mmap
    [ 1072.572256] In MVC:mxc_mmap
    [ 1072.575093]    pgoff=0x92c00, start=0x42692000, end=0x42952000
    [ 1072.591292]=============================camera mmap
    [ 1072.596321] In MVC:mxc_mmap
    [ 1072.599119]    pgoff=0x91000, start=0x42952000, end=0x42c12000
    [ 1072.612007]=============================camera mmap
    [ 1072.616990] In MVC:mxc_mmap
    [ 1072.619852]    pgoff=0x91400, start=0x42f25000, end=0x431e5000

    返回preview:
    [ 1074.351975]=============================camera mmap
    [ 1074.357060] In MVC:mxc_mmap
    [ 1074.359895]    pgoff=0x91700, start=0x40c0a000, end=0x40cba000
    [ 1074.369823]=============================camera mmap
    [ 1074.374837] In MVC:mxc_mmap
    [ 1074.377635]    pgoff=0x93900, start=0x40cc5000, end=0x40d75000
    [ 1074.385910]=============================camera mmap
    [ 1074.390883] In MVC:mxc_mmap
    [ 1074.393713]    pgoff=0x93e00, start=0x40d75000, end=0x40e25000
    [ 1074.402028]=============================camera mmap
    [ 1074.407004] In MVC:mxc_mmap
    [ 1074.409808]    pgoff=0x92b00, start=0x40e25000, end=0x40ed5000
    [ 1074.417813]=============================camera mmap
    [ 1074.422813] In MVC:mxc_mmap
    [ 1074.425610]    pgoff=0x91600, start=0x42692000, end=0x42742000
    切换到录像:
    [ 1148.276637]=============================camera mmap
    [ 1148.281664] In MVC:mxc_mmap
    [ 1148.284470]    pgoff=0x92b00, start=0x40e00000, end=0x40e98000
    [ 1148.293967]=============================camera mmap
    [ 1148.298943] In MVC:mxc_mmap
    [ 1148.301780]    pgoff=0x93900, start=0x42323000, end=0x423bb000
    [ 1148.311097]=============================camera mmap
    [ 1148.316121] In MVC:mxc_mmap
    [ 1148.318920]    pgoff=0x93e00, start=0x423bb000, end=0x42453000
    [ 1148.328422]=============================camera mmap
    [ 1148.333448] In MVC:mxc_mmap
    [ 1148.336246]    pgoff=0x93c00, start=0x42453000, end=0x424eb000
    [ 1148.346153]=============================camera mmap
    [ 1148.351130] In MVC:mxc_mmap
    [ 1148.353981]    pgoff=0x93d00, start=0x424eb000, end=0x42583000
    ==================================================================
原创粉丝点击