我正致力于将一些代码从 AIX 移植到 Linux。部分代码使用 shmat()
system call创建新文件。当在可写模式下与 SHM_MAP
一起使用时,可以将文件扩展到超过其原始长度(在我的例子中为零):
When a file is mapped onto a segment, the file is referenced by accessing the segment. The memory paging system automatically takes care of the physical I/O. References beyond the end of the file cause the file to be extended in page-sized increments. The file cannot be extended beyond the next segment boundary.
(AIX 中的“段”是 256 MB 的地址空间 block ,而“页”通常是 4 KB。)
我喜欢在 Linux 上做的事情如下:
- 保留一大块地址空间(不必大到 256 MB,这些文件不是那么大)
- 设置页面保护位,以便在第一次访问之前未被触及的页面时生成段错误
- 在出现页面错误时,清除“导致页面错误”位并为该页面分配已提交的内存,允许导致页面错误的写入(或读取)继续进行
- 关闭共享内存区域后,将修改后的页面写入文件
我知道我可以在 Windows 上使用 VirtualProtect 执行此操作函数、PAGE_GUARD
内存保护位和 structured exception handler . Linux 上相应的方法是什么?是否有更好的方法在 Linux 上实现这种写时扩展功能?
我已经考虑过:
- 使用
mmap()
一些固定的大尺寸,但我无法判断应用程序代码写入了多少文件 - 分配一个较大的匿名共享内存区域,但我还是不知道该区域有多少已被写入
mmap()
本身似乎没有提供任何工具来扩展支持文件的长度
当然,我希望只对应用程序代码进行最少的更改。
最佳答案
这与我曾经做过的作业非常相似。基本上我有一个“页面”列表和一个“框架”列表,以及相关信息。使用 SIGSEGV
我会捕获错误并根据需要更改内存保护位。我将包含您可能会觉得有用的部分。
创建映射。最初它没有权限。
int w_create_mapping(size_t size, void **addr)
{
*addr = mmap(NULL,
size * w_get_page_size(),
PROT_NONE,
MAP_ANONYMOUS | MAP_PRIVATE,
-1,
0
);
if (*addr == MAP_FAILED) {
perror("mmap");
return FALSE;
}
return TRUE;
}
安装信号处理器
int w_set_exception_handler(w_exception_handler_t handler)
{
static struct sigaction sa;
sa.sa_sigaction = handler;
sigemptyset(&sa.sa_mask);
sigaddset(&sa.sa_mask, SIGSEGV);
sa.sa_flags = SA_SIGINFO;
if (sigaction(SIGSEGV, &sa, &previous_action) < 0)
return FALSE;
return TRUE;
}
异常处理程序
static void fault_handler(int signum, siginfo_t *info, void *context)
{
void *address; /* the address that faulted */
/* Memory location which caused fault */
address = info->si_addr;
if (FALSE == page_fault(address)) {
_exit(1);
}
}
加强保护
int w_protect_mapping(void *addr, size_t num_pages, w_prot_t protection)
{
int prot;
switch (protection) {
case PROTECTION_NONE:
prot = PROT_NONE;
break;
case PROTECTION_READ:
prot = PROT_READ;
break;
case PROTECTION_WRITE:
prot = PROT_READ | PROT_WRITE;
break;
}
if (mprotect(addr, num_pages * w_get_page_size(), prot) < 0)
return FALSE;
return TRUE;
}
我不能公开提供所有内容,因为团队可能会再次使用相同的作业。
关于linux - 如何在 Linux 中为内存映射文件提供写时扩展功能?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6935988/