加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > Linux > 正文

如何在Linux中为内存映射文件提供扩展写入功能?

发布时间:2020-12-14 01:13:59 所属栏目:Linux 来源:网络整理
导读:我正在努力将一些代码从AIX移植到 Linux.部分代码使用 shmat() system call创建新文件.当在可写模式下与SHM_MAP一起使用时,可以将文件扩展到其原始长度之外(在我的情况下为零): When a file is mapped onto a segment,the file is referenced by accessing
我正在努力将一些代码从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的地址空间块,“页面”通常是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;
}

由于团队可能会再次使用相同的作业,因此我无法公开全部使用.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读