1. 保护权限
mmap函数的prot参数可指定内存映射区的保护权限,例如指定PROT_READ和PROT_EXEC,在调用open打开文件就应该指定O_RDONLY或者O_RDWR。如果指定了PROT_WRITE,打开的文件应该使用O_WRONLY或者O_RDWR。
由于一些硬件架构提供的内存保护粒度有所不同,情况也会变的复杂:
1. 一般打开文件指定O_RDWR标记就已经满足基本的使用了。
2. 如果prot参数只指定了PROT_WRITE,且open以O_WRONLY标记打开文件,内存映射的保护权限和打开文件的权限理论上是兼容的,但是调用mmap却会失败,设置errno为EACCES错误。因为一些硬件架构上PROT_WRITE隐含了PROT_READ,这意味着系统分页可写也可读,但这与O_WRONLY标记实际上是不兼容的。
例如下面这一段代码:
//以O_WRONLY权限打开文件
int fd = open("test.txt", O_WRONLY, 0644);
if (fd < 0){
perror("open error");
}
//拓展文件大小4096
lseek(fd , 4096, SEEK_SET);
write(fd , "0" , 1);
//指向文件开头
lseek(fd , 0 , SEEK_SET);
//创建共享映射区,指定PROT_WRITE权限
addr =(char *)mmap(NULL , 4096 , PROT_WRITE , MAP_SHARED , fd , 0);
if (addr == MAP_FAILED){
perror("mmap err: ");
//进一步判断是否为EACCES错误
if(errno == EACCES){
puts("EACCES error");
exit(-1);
}
}
程序执行结果:
3. 以O_RDONLY标记打开一个文件,mmap调用指定了MAP_PRIVATE创建私有内存映射,因为MAP_PRIVATE映射上的修改操作不会反映到打开的文件中,所以prot参数可以指定任意的组合权限。
对于一个MAP_SHARED映射来说,在MAP_SHARED映射上的修改操作会反映到打开的文件中,唯一与O_RDONLY标记兼容的内存保护权限就是PROT_READ|PROT_EXEC。
2. 映射区域同步——msync
一般,为确保映射区的数据写入物理磁盘上的文件中,在调用munmap解除映射前需要调用msync函数。前面我们没有调用msync函数依然能在文件中看到写入的数据,这是因为内核会自动将MAP_SHARED映射区的内容同步到打开的文件中,但内核并不保证何时同步数据。
通过调用msync函数可以让应用程序显式的控制文件与内存映射中的数据同步。
#include <sys/mman.h>
int msync(void *addr, size_t length, int flags);
返回值:成功返回0,失败返回-1并设置errno
addr:需要同步的内存映射区起始地址
length:需要同步的数据大小
flags:设置同步数据的方式(MS_SYNC,MS_ASYNC,MS_INVALIDATE)