在Linux的用户空间:假设我分配的3MiB连续存储ABC,其中A,B与C各1MiB.有没有办法以某种方式AC作为单个连续2MiB内存访问(一种用户空间MMU)?
背景:我的方案是用C模拟ASIC芯片.芯片有一个3MiB内存,芯片中的两个组件可以访问相同的内存硬件,但具有不同的地址映射.要在C中对其进行建模,一种方法可能是为两个组件复制3MiB内存,并在两个内存副本之间添加一些同步机制.另一种方式可能是只有一个3MiB内存副本,一个组件按原样访问内存,而另一个组件则添加一种包装器来进行地址转换.我只是想知道是否有更简洁的方法,避免内存重复和地址转换包装...
PS:根据Maxim的回答,我写了一个简单的测试程序,它只是起作用.看来我不应该MAP_ANONYMOUSE为我的目的使用旗帜.另外,根据mmap()手册,为了MAP_FIXED正常工作,对齐C应该是PAGE_SIZE目标平台上的多个(我的x86_64 Ubuntu).我粘贴下面的代码以防万一...
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#define SZ_A (64 * 1024) // A
#define SZ_B (204 * 1024) // B
#define SZ_C (4 * 1024) // C
#define SZ_ABC (272 * 1024) // ABC
#define SZ_AB (268 * 1024) // AB
#define SZ_AC (68 * 1024) // AC
const char shm_name[] = "/shm_name1";
unsigned char* p_abc = NULL;
unsigned char* p_ac = NULL;
#define MMAP_PROT (PROT_READ | PROT_WRITE)
#define USE_MAP_ANONYMOUSE 0
#if USE_MAP_ANONYMOUSE
#define MMAP_FLAG (MAP_SHARED | MAP_ANONYMOUS)
#define MMAP_FLAG_FIXED (MAP_SHARED | MAP_ANONYMOUS | MAP_FIXED)
#else
#define MMAP_FLAG (MAP_SHARED)
#define MMAP_FLAG_FIXED (MAP_SHARED | MAP_FIXED)
#endif
int main(void)
{
int fd = - 1;
void* p = NULL;
fd = shm_open(shm_name, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
if (fd == - 1) {
printf("shm_open() fail\n");
return - 1;
}
if (0 != ftruncate(fd, SZ_ABC)) {
printf("ftruncate() fail\n");
return - 1;
}
if (0 != shm_unlink(shm_name)) {
printf("shm_unlink() fail\n");
return - 1;
}
p_abc = (unsigned char*)mmap(NULL, SZ_ABC, MMAP_PROT, MMAP_FLAG, fd, 0);
if (p_abc == (unsigned char*) -1) {
printf("p_abc = mmap(NULL) fail\n");
p_abc = NULL;
goto EXIT;
}
p_ac = (unsigned char*)mmap(NULL, SZ_AC, MMAP_PROT, MMAP_FLAG, fd, 0);
if (p_ac == (unsigned char*) -1) {
printf("p_ac = mmap(NULL) fail\n");
p_ac = NULL;
goto EXIT;
}
p = mmap(p_ac + SZ_A, SZ_C, MMAP_PROT, MMAP_FLAG_FIXED, fd, SZ_AB);
if (p == MAP_FAILED || p != (void*)(p_ac + SZ_A)) {
printf("mmap(MAP_FIXED) fail\n");
p = NULL;
goto EXIT;
}
close(fd);
printf("mmap() ok:"
"\np_abc=0x%" PRIxPTR
"\n p_ac=0x%" PRIxPTR
"\n p=0x%" PRIxPTR "\n",
(uintptr_t)p_abc, (uintptr_t)p_ac, (uintptr_t)p);
// test
memset(p_abc, 0xab, SZ_AB);
memset(p_abc + SZ_AB, 0x0c, SZ_C);
// should be: ab, 0c
printf("sm4: %02x, %02x\n", p_ac[0], p_ac[SZ_A]);
memset(p_ac, 0x0c, SZ_AC);
// should be: 0c, 0c
printf("sm0: %02x, %02x\n", p_abc[0], p_abc[SZ_AB]);
EXIT:
if (p) munmap(p, SZ_C);
if (p_ac) munmap(p_ac, SZ_AC);
if (p_abc) munmap(p_abc, SZ_ABC);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
假设我分配的3MiB连续存储
ABC,其中A,B与C各1MiB.有没有办法以某种方式AC作为单个连续2MiB内存访问(一种用户空间MMU)?
您可以使用shm_open(并且可选地,立即shm_unlink)创建3MiB大小的内存映射文件.然后使用不同的偏移量和大小将该文件多次映射到进程地址空间.
需要注意的是,要AC连续映射,首先需要mmap2MiB的匿名内存来保留连续的地址空间块.然后它mmap的前半部分A和下半部分C使用MAP_FIXED标志.
伪代码:
// Create an anonymous shared memory file.
int fd = shm_open(filename);
shm_unlink(filename);
ftruncate(fd, 3MiB);
// Map A and C contiguously.
void* ac = mmap(NULL, 2MiB, ..., fd, 0MiB); // maps AB part of ABC.
mmap(ac + 1MiB, 1MiB, ... | MAP_FIXED, fd, 2MiB); // remaps C part over B part (B gets unmapped).
Run Code Online (Sandbox Code Playgroud)