




已阅读5页,还剩6页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第28章文件与I/O8.mmapmmap可以把磁盘文件的一部分直接映射到内存,这样文件中的位置直接就有对应的内存地址,对文件的读写可以直接用指针来做而不需要read/write函数。#include void *mmap(void *addr, size_t len, int prot, int flag, int filedes, off_t off); int munmap(void *addr, size_t len);该函数各参数的作用图示如下:图28.4.mmap函数如果addr参数为NULL,内核会自己在进程地址空间中选择合适的地址建立映射。如果addr不是NULL,则给内核一个提示,应该从什么地址开始映射,内核会选择addr之上的某个合适的地址开始映射。建立映射后,真正的映射首地址通过返回值可以得到。len参数是需要映射的那一部分文件的长度。off参数是从文件的什么位置开始映射,必须是页大小的整数倍(在32位体系统结构上通常是4K)。filedes是代表该文件的描述符。prot参数有四种取值: PROT_EXEC表示映射的这一段可执行,例如映射共享库 PROT_READ表示映射的这一段可读 PROT_WRITE表示映射的这一段可写 PROT_NONE表示映射的这一段不可访问flag参数有很多种取值,这里只讲两种,其它取值可查看mmap(2) MAP_SHARED多个进程对同一个文件的映射是共享的,一个进程对映射的内存做了修改,另一个进程也会看到这种变化。 MAP_PRIVATE多个进程对同一个文件的映射不是共享的,一个进程对映射的内存做了修改,另一个进程并不会看到这种变化,也不会真的写到文件中去。如果mmap成功则返回映射首地址,如果出错则返回常数MAP_FAILED。当进程终止时,该进程的映射内存会自动解除,也可以调用munmap解除映射。munmap成功返回0,出错返回-1。下面做一个简单的实验。$ vi hello(编辑该文件的内容为“hello”)$ od -tx1 -tc hello 0000000 68 65 6c 6c 6f 0a h e l l o n0000006现在用如下程序操作这个文件(注意,把fd关掉并不影响该文件已建立的映射,仍然可以对文件进行读写)。#include #include #include int main(void)int *p;int fd = open(hello, O_RDWR);if (fd 0) perror(open hello);exit(1);p = mmap(NULL, 6, PROT_WRITE, MAP_SHARED, fd, 0);if (p = MAP_FAILED) perror(mmap);exit(1);close(fd);p0 = 0x30313233;munmap(p, 6);return 0;然后再查看这个文件的内容:$ od -tx1 -tc hello 0000000 33 32 31 30 6f 0a 3 2 1 0 o n 0000006请读者自己分析一下实验结果。mmap函数的底层也是一个系统调用,在执行程序时经常要用到这个系统调用来映射共享库到该进程的地址空间。例如一个很简单的hello world程序:#include int main(void)printf(hello worldn);return 0;用strace命令执行该程序,跟踪该程序执行过程中用到的所有系统调用的参数及返回值:$ strace ./a.out execve(./a.out, ./a.out, /* 38 vars */) = 0brk(0) = 0x804a000access(/etc/ld.so.nohwcap, F_OK) = -1 ENOENT (No such file or directory)mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7fca000access(/etc/ld.so.preload, R_OK) = -1 ENOENT (No such file or directory)open(/etc/ld.so.cache, O_RDONLY) = 3fstat64(3, st_mode=S_IFREG|0644, st_size=63628, .) = 0mmap2(NULL, 63628, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7fba000close(3) = 0access(/etc/ld.so.nohwcap, F_OK) = -1 ENOENT (No such file or directory)open(/lib/tls/i686/cmov/libc.so.6, O_RDONLY) = 3read(3, 177ELF11100000000030301000260a1., 512) = 512fstat64(3, st_mode=S_IFREG|0644, st_size=1339816, .) = 0mmap2(NULL, 1349136, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb7e70000mmap2(0xb7fb4000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x143) = 0xb7fb4000mmap2(0xb7fb7000, 9744, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb7fb7000close(3) = 0mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7e6f000set_thread_area(entry_number:-1 - 6, base_addr:0xb7e6f6b0, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1) = 0mprotect(0xb7fb4000, 4096, PROT_READ) = 0munmap(0xb7fba000, 63628) = 0fstat64(1, st_mode=S_IFCHR|0620, st_rdev=makedev(136, 1), .) = 0mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7fc9000write(1, hello worldn, 12hello world) = 12exit_group(0) = ?Process 8572 detached可以看到,执行这个程序要映射共享库/lib/tls/i686/cmov/libc.so.6到进程地址空间。也可以看到,printf函数的底层确实是调用write。 8.mmapmmap可以把磁盘文件的一部分直接映射到内存,这样文件中的位置直接就有对应的内存地址,对文件的读写可以直接用指针来做而不需要read/write函数。#include void *mmap(void *addr, size_t len, int prot, int flag, int filedes, off_t off); int munmap(void *addr, size_t len);该函数各参数的作用图示如下:图28.4.mmap函数如果addr参数为NULL,内核会自己在进程地址空间中选择合适的地址建立映射。如果addr不是NULL,则给内核一个提示,应该从什么地址开始映射,内核会选择addr之上的某个合适的地址开始映射。建立映射后,真正的映射首地址通过返回值可以得到。len参数是需要映射的那一部分文件的长度。off参数是从文件的什么位置开始映射,必须是页大小的整数倍(在32位体系统结构上通常是4K)。filedes是代表该文件的描述符。prot参数有四种取值: PROT_EXEC表示映射的这一段可执行,例如映射共享库 PROT_READ表示映射的这一段可读 PROT_WRITE表示映射的这一段可写 PROT_NONE表示映射的这一段不可访问flag参数有很多种取值,这里只讲两种,其它取值可查看mmap(2) MAP_SHARED多个进程对同一个文件的映射是共享的,一个进程对映射的内存做了修改,另一个进程也会看到这种变化。 MAP_PRIVATE多个进程对同一个文件的映射不是共享的,一个进程对映射的内存做了修改,另一个进程并不会看到这种变化,也不会真的写到文件中去。如果mmap成功则返回映射首地址,如果出错则返回常数MAP_FAILED。当进程终止时,该进程的映射内存会自动解除,也可以调用munmap解除映射。munmap成功返回0,出错返回-1。下面做一个简单的实验。$ vi hello(编辑该文件的内容为“hello”)$ od -tx1 -tc hello 0000000 68 65 6c 6c 6f 0a h e l l o n0000006现在用如下程序操作这个文件(注意,把fd关掉并不影响该文件已建立的映射,仍然可以对文件进行读写)。#include #include #include int main(void)int *p;int fd = open(hello, O_RDWR);if (fd 0) perror(open hello);exit(1);p = mmap(NULL, 6, PROT_WRITE, MAP_SHARED, fd, 0);if (p = MAP_FAILED) perror(mmap);exit(1);close(fd);p0 = 0x30313233;munmap(p, 6);return 0;然后再查看这个文件的内容:$ od -tx1 -tc hello 0000000 33 32 31 30 6f 0a 3 2 1 0 o n 0000006请读者自己分析一下实验结果。mmap函数的底层也是一个系统调用,在执行程序时经常要用到这个系统调用来映射共享库到该进程的地址空间。例如一个很简单的hello world程序:#include int main(void)printf(hello worldn);return 0;用strace命令执行该程序,跟踪该程序执行过程中用到的所有系统调用的参数及返回值:$ strace ./a.out execve(./a.out, ./a.out, /* 38 vars */) = 0brk(0) = 0x804a000access(/etc/ld.so.nohwcap, F_OK) = -1 ENOENT (No such file or directory)mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7fca000access(/etc/ld.so.preload, R_OK) = -1 ENOENT (No such file or directory)open(/etc/ld.so.cache, O_RDONLY) = 3fstat64(3, st_mode=S_IFREG|0644, st_size=63628, .) = 0mmap2(NULL, 63628, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7fba000close(3) = 0access(/etc/ld.so.nohwcap, F_OK) = -1 ENOENT (No such file or directory)open(/lib/tls/i686/cmov/libc.so.6, O_RDONLY) = 3read(3, 177ELF11100000000030301000260a1., 512) = 512fstat64(3, st_mode=S_IFREG|0644, st_size=1339816, .) = 0mmap2(NULL, 1349136, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb7e70000mmap2(0xb7fb4000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x143) = 0xb7fb4000mmap2(0xb7fb7000, 9744, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb7fb7000close(3) = 0mmap2(NULL, 4
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
评论
0/150
提交评论