mmap和munmap函数

来源:互联网 发布:看美剧的网站知乎 编辑:程序博客网 时间:2024/05/20 07:50

原:http://blog.sina.com.cn/s/blog_605f5b4f0100znqs.html

 

 

mmap munmap是一对操作命令,就像mallocfree命令一样


Mmap and munmap: map or unmap files or devices into memory(操作的内存页Page)


mmap操作提供了一种机制,让用户程序直接访问设备内存,这种机制,相比较在用户空间和内核空间互相拷贝数据,效率更高。在要求高性能的应用中比较常用。mmap映射内存必须是页面大小的整数倍,面向流的设备不能进行mmapmmap的实现和硬件有关。


munmap执行相反的操作,删除特定地址区域的对象映射,基于文件的映射,在mmapmunmap执行过程的任何时刻,被映射文件的st_atime可能被更新。如果st_atime字段在前述的情况下没有得到更新,首次对映射区的第一个页索引时会更新该字段的值。用PROT_WRITE 和 MAP_SHARED标志建立起来的文件映射其st_ctime 和 st_mtime,在对映射区写入之后但在msync()通过MS_SYNC 和 MS_ASYNC两个标志调用之前会被更新


#include <sys/mman.h>


void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);


int munmap(void *addr, size_t length);


 

mmap() creates new mapping in the virtual address space of the calling process.  The starting address for the new mapping is specified in addr Thlength argument specifies the length of the mapping.


If addr is NULL, then the kernel chooses the address at which to create the       mapping; this is the most portable method of creating new mapping.  If addr is not NULL, then the kernel takes it as hint about where to place the mapping; on Linux, the mapping will be created at nearby page boundary.  The address of the new mapping is returned as the result of the call.


The contents of file mapping (as opposed to an anonymous mapping; see MAP_ANONYMOUS below), are initialized using length bytes starting at offset  offset in the file (or other object) referred to by the file descriptor fd.

       

offset must be multiple of the page size as returned by sysconf(_SC_PAGE_SIZE).


The prot argument describes the desired memory protection of the mapping (and      must not conflict with the open mode of the file).  It is either PROT_NONE or the bitwise OR of one or more of the following flags:

PROT_EXEC  Pages may be executed.       

PROT_READ  Pages may be read.       

PROT_WRITE Pages may be written.     

 PROT_NONE  Pages may not be accessed.


The flags argument determines whether updates to the mapping are visible to other processes mapping the same region, and whether updates are carried through to the underlying file. This behavior is determined by including exactly one of the following values in flags:

MAP_SHARED Share this mapping.  

Updates to the mapping are visible to otherprocesses that map this fileand are carried through to the underlying file.  The file may not actually be updated until msync(2) or munmap() is called.


MAP_PRIVATE   Create private copy-on-Write mapping. Updates to the mapping are not visible to other processes mapping the same file, and are not carried through to the underlying file.  It is unspecified whether changes made to the file after the mmap() call are visible in the mapped region.


In addition, zero or more of the following values can be ORed in flags:


MAP_ANONYMOUS

The mapping is not backed by any file; its contents are initialized to zero. The fd and offset arguments are ignored; however, some implementations require fd to be -1 if MAP_ANONYMOUS (or MAP_ANONis specified, and portable applications should ensure this.  The use of MAP_ANONYMOUS in conjunction with MAP_SHARED is only supported on Linux since kernel 2.4.


MAP_FIXED

Don't interpret addr as hint: place the mapping at exactly that address.  addr must be multiple of the page size. If the memory region specified by addr and len overlaps pages of any existing mapping(s), then the overlapped part of the existing mapping(s) will be discarded. If the specified address cannot be used, mmap() will fail. Because requiring fixed address for mapping is less portable, the use of this option is discouraged.


MAP_HUGETLB (since Linux 2.6.32)

Allocate the mapping using "huge pages."  See the kernel source file Documentation/vm/hugetlbpage.txt  for further information.


MAP_NORESERVE

Do not reserve swap space for this mapping.  When swap space is reserved, one has the guarantee that it is possible to modify the mapping.  When swap space is not reserved one might get SIGSEGV upon a write if no physical memory is available. See also the discussion of the file /proc/sys/vm/overcommit_memory in proc(5)In kernels before2.6, this flag only had effect for private writable mappings.


MAP_POPULATE (since Linux 2.5.46)

Populate (prefault) page tables for mapping. For file mapping, this causes read-ahead on the file.  Later accesses to the mapping will not be blocked by page faults.  MAP_POPULATE is only supported for private mappings since Linux 2.6.23.


 

Memory mapped by mmap() is preserved across fork(2)with the same attributes.(猜想一定和进程创建fork的Copy On Write机制 有关联,说不定使用的就是MAP_PRIVATE



 file is mapped in multiples of the page size.  For file that is not a multiple of the page size, the remaining memory is zeroed when mapped, and writes to that region are not written out to the file. The effect of changing the size of the underlying file of mapping on the pages that correspond to added or removed regions of the file is unspecified.


Munmap()       

The munmap() system call deletes the mappings for the specified address range,      and causes further references to addresses within the range to generate invalid memory references. The region is also automatically unmapped when the process is terminated.  On the other hand, closing the file descriptor does not unmap the region.


The address addr must be multiple of the page size.  All pages containing a part of the indicated range are unmapped, and subsequent references to these pages will generate SIGSEGV It is not an error if the indicated range does not contain any mapped pages.


EXAMPLE:

The following program prints part of the file specified in its first command-line argument to standard output. The range of bytes to be printed is specified via offset and length values in the second and third command-line arguments.  The program creates memory mapping of the required pages of the file and then uses write(2) to output the desired bytes.

       #include <sys/mman.h>

       #include <sys/stat.h>

       #include <fcntl.h>

       #include <stdio.h>

       #include <stdlib.h>

       #include <unistd.h>

       #define handle_error(msg) \

           do perror(msg); exit(EXIT_FAILURE); while (0)

       int  main(int argc, char *argv[])

       {

           char *addr;

           int fd;

           struct stat sb;

           off_t offset, pa_offset;

           size_t length;

           ssize_t s;

           if (argc || argc 4) {

               fprintf(stderr, "%s file offset [length]\n", argv[0]);

               exit(EXIT_FAILURE);

           }

           fd open(argv[1], O_RDONLY);//第二个参数为文件名

           if (fd == -1)

               handle_error("open");

           if (fstat(fd, &sb) == -1)           

              handle_error("fstat");

          offset atoi(argv[2]);//第三个参数为偏移量 atoi将一个字符串变成一个int

           pa_offset offset ~(sysconf(_SC_PAGE_SIZE) 1);

               

 

           if (offset >= sb.st_size) {

               fprintf(stderr, "offset is past end of file\n");

               exit(EXIT_FAILURE);

           }

           if (argc == 4) {

               length atoi(argv[3]);//第四个参数时映射内存大小

               if (offset length sb.st_size)

                   length sb.st_size offset;

                       

           else    

               length sb.st_size offset;

           }

           addr mmap(NULL, length offset pa_offset, PROT_READ,

                       MAP_PRIVATEfd, pa_offset);

           if (addr == MAP_FAILED)

               handle_error("mmap");

          write(STDOUT_FILENO, addr offset pa_offset, length);

           if (s != length) {

               if (s == -1)

                   handle_error("write");

               fprintf(stderr, "partial write");

               exit(EXIT_FAILURE);

           }

           exit(EXIT_SUCCESS);

       }

 

0 0
原创粉丝点击