• mmap msync munmap close


           open 打开文件后——>使用mmap建设文件映射;建立文件映射后,可以对映射到的空间进行操作。用msync同步到文件中。
           问:close后对映射空间的操作能够同步到文件中吗?
           答:可以,只要文件映射存在,就可以向你映射空间的内容写入文件,实现空间和文件的同步。
    实例代码::
    1. #include <stdio.h>   
    2. #include <stdlib.h>   
    3. #include <string.h>   
    4. #include <unistd.h>   
    5. #include <sys/mman.h>   
    6. #include <sys/types.h>   
    7. #include <fcntl.h>   
    8. int main(int argc, char *argv[])  
    9. {  
    10.  int fd;  
    11.  char *addr;  
    12.  char *str = "Hello World";  
    13.  fd = open("./a",O_CREAT|O_RDWR|O_TRUNC,0666);  
    14.  if(fd == -1)  
    15.  {  
    16.   perror("open file fail:");  
    17.   exit(1);  
    18.  }  
    19.  if(ftruncate(fd,4096)==-1)  
    20.  {  
    21.   perror("ftruncate fail:");  
    22.   close(fd);  
    23.   exit(1);  
    24.  }  
    25.  addr =(char *) mmap(NULL,4096,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);  
    26.  if(addr == (char *)MAP_FAILED)  
    27.  {  
    28.   perror("mmap fail:");  
    29.   exit(1);  
    30.  }  
    31.  memset(addr,' ',4096);  
    32.    
    33.  memcpy(addr,str,strlen(str));                       //hello world  1   
    34.  close(fd);  
    35.  memcpy(addr+strlen(str),str,strlen(str));           //hello world  2   
    36.  if(msync(addr,4096,MS_SYNC)==-1)  
    37.  {  
    38.   perror("msync fail:");  
    39.   exit(1);  
    40.  }  
    41.       munmap(addr,4096);  
    42.  return 0;  
    43. }  
    ========================================

      //下面的代码把文件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, unsigned long virt_addr, unsigned long pfn, unsigned long size, pgprot_t prot) 函数或者 
    int io_remap_page_range(struct vm_area_struct *vma, unsigned long virt_addr, unsigned long phys_addr, unsigned long size, pgprot_t prot)函数来实现,它们负责建立新的页表.这两个函数的区别是第一个函数是在参数pfn指向实际系统RAM的时候使用,而第二个函数是在 phys_addr指向I/O内存的时候使用.对于ARM平台来说,系统内存和端口应该是统一编址的,所以两个函数是等价的. 
    还有另外一个函数就是nopage函数,是VMA结构体中可以填充的一个函数,在虚拟页没有所对应的物理页的时候,会调用此函数,来分配一个物理页给虚拟页. 
      int remap_page_range(unsigned long from, unsigned long phys_addr, unsigned long 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,防止处理器缓存 
    ==================================================================================
    系统调用过程(详见: ARM linux系统调用的实现原理)
    void*  mmap(void *, size_t, int, int, int, off_t);      //bionic/libc/unistd/mmap.c     (head file: bionic/libc/include/sys/mman.h) 
      |

    void*  __mmap2(void*, size_t, int, int, int, size_t);     // bionic/libc/arch-arm/syscalls/__mmap2.S   ( __NR_mmap2 = __NR_SYSCALL_BASE + 192 )

      |    ( arch/arm/kernel/calls.S )

    sys_mmap2         // ( arch/arm/kernel/entry-common.S )

      |

    sys_mmap_pgoff            //( mm/mmap.c )          SYSCALL_DEFINE6(mmap_pgoff, )

       |

    do_mmap_pgoff(file, addr, len, prot, flags, pgoff);   //   mm/mmap.c

    可能合并VMA
    否则新分配一个VMA
    然后
    error = file->f_op->mmap(file, vma);
    就调用了驱动里的mmap      
    这时候vma->vm_pgoff = pgoff    (这个pgoff就是map(offset, len , fd ,...)  中的 offset ,当然经过处理了,PAGE_SHIFT移来移去的)
    =============================================================
    以下是Camera mmap的一个例子:
    1. <SPAN style="FONT-SIZE: 13px">/*! 
    2.  * V4L interface - mmap function 
    3.  * @param file        structure file * 
    4.  * @param vma         structure vm_area_struct * 
    5.  * @return status     0 Success, EINTR busy lock error, ENOBUFS remap_page error 
    6.  */  
    7. static int mxc_mmap(struct file *file, struct vm_area_struct *vma)  
    8. {  
    9. struct video_device *dev = video_devdata(file);  
    10. unsigned long size;  
    11.      int res = 0;  
    12.      cam_data *cam = video_get_drvdata(dev);  
    13.      pr_err("=============================camera mmap\n");  
    14.      pr_err("In MVC:mxc_mmap\n");  
    15.      pr_err("   pgoff=0x%lx, start=0x%lx, end=0x%lx\n",  
    16.             vma->vm_pgoff, vma->vm_start, vma->vm_end);  
    17.      /* make this _really_ smp-safe */  
    18.      if (down_interruptible(&cam->busy_lock))  
    19.                  return -EINTR;  
    20.      size = vma->vm_end - vma->vm_start;  
    21.      vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);  
    22.      if (remap_pfn_range(vma, vma->vm_start,  
    23.                      vma->vm_pgoff, size, vma->vm_page_prot)) {  
    24.            pr_err("ERROR: v4l2 capture: mxc_mmap: "  
    25.                         "remap_pfn_range failed\n");  
    26.            res = -ENOBUFS;  
    27.            goto mxc_mmap_exit;  
    28.      }  
    29.      vma->vm_flags &= ~VM_IO;/* using shared anonymous pages */  
    30.      mxc_mmap_exit:  
    31.      up(&cam->busy_lock);  
    32.      return res;  
    33. }</SPAN>  
    ========================================
    用户层调用:
    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


    ==================================================================

  • 相关阅读:
    【转】 java中Class对象详解和类名.class, class.forName(), getClass()区别
    106. Construct Binary Tree from Inorder and Postorder Traversal
    105. Construct Binary Tree from Preorder and Inorder Traversal
    107. Binary Tree Level Order Traversal II
    109. Convert Sorted List to Binary Search Tree
    108. Convert Sorted Array to Binary Search Tree
    110. Balanced Binary Tree
    STL容器迭代器失效问题讨论
    113. Path Sum II
    112. Path Sum
  • 原文地址:https://www.cnblogs.com/hehehaha/p/6332946.html
Copyright © 2020-2023  润新知