POSIX系统上的内存映射文件保持同步

时间:2010-11-11 07:32:50

标签: c posix mmap

为什么以下代码正常运行?

void continuous_mmap (void)
{
 struct stat buf;
 int fd = open("file_one", O_RDONLY), i;
 char *contents;

 fstat(fd, &buf);
 contents = mmap(NULL, buf.st_size, PROT_WRITE, MAP_PRIVATE, fd, 0);
 close (fd);
 mprotect(contents, buf.st_size, PROT_READ);
 for (i = 0; i < 15; i++) {
  printf ("%s\n", contents);
  sleep (1);
 }
 munmap(contents, buf.st_size);
}

首先,文件保持同步(编辑和保存文件外部自动打印更新的内容),即使附加到。如果没有segfaulting,我的代码如何能够超出我映射的字节数(初始文件大小)?是因为mmap总是将长度向上舍入到系统页面大小?如果是这样,这种行为一般可以依赖于POSIX系统(我在mmap手册页中找不到任何此类要求。)

其次,文本如何自动附加'0'?是因为非映射字节会自动归零吗?这种行为可以依赖吗?

3 个答案:

答案 0 :(得分:2)

是标准说

  

系统应始终零填充任何   对象末尾的部分页面。   此外,系统永远不会写   删除最后一个的任何修改部分   一个超出它的对象的页面   端。

  • 如果是,可以依赖此行为 在一般的POSIX系统上(我 找不到任何这样的要求 在mmap手册页中。)。
不,我不会这样做,并非所有实现都可以符合要求。我曾经看过至少一个相当破碎的实现。

您不应该使用mmap来电的此功能,但ftruncate可以根据您的需要延长文件。

答案 1 :(得分:1)

POSIX甚至不会要求一个非常重要的页面大小;理论上,实现可以具有1字节的“页面”大小。类似地,似乎没有指定从文件大小超过页面的其余部分读取零。我可以想象一些破坏的实现泄漏了在这里被截断的旧文件内容,但我认为这是一个重大的安全/隐私泄露,会使这种实现在现实世界中无关紧要。当然,他们可以用0xDEADBEEF填补空间,然后你就会失去运气。

即使您可以假设零填充(大多数实际操作系统可能就是这种情况),我会提醒您不要使用它。如果您的文件恰好是系统页面大小的两倍,会发生什么?突然间,您的代码在读取结束时崩溃,或者(可能更糟)从不相关的页面读取,这些页面恰好被映射到文件的映射旁边。这是一个非常非常讨厌的错误,你可能无法捕获,因为文本文件是系统页面大小的精确倍数的可能性非常低。

答案 2 :(得分:0)

您看到文件的外部更新的原因,即使它已映射MAP_PRIVATE,是因为您尚未写入映射,因此系统未向您提供该文件的私有副本页面呢。允许此行为,但不是必需的。

如果你的应用程序在循环之前修改了contents[0],它将看到外部变化。