函数page_allocate
有效。它确实将地址返回到具有指定对齐的映射页面。但是,使用64k和1024k的连续呼叫永远不会连续。为什么呢?
这里包含一个示例程序。使用gcc -Wall -g mmap.c -o mmap
进行编译。
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#define _GNU_SOURCE /* MAP_ANONYMOUS */
#include <sys/mman.h>
#include <unistd.h> /* sysconf */
static size_t sys_page_size = 0;
void
page_init(void)
{
int sc;
if(!sys_page_size)
{
sc = sysconf(_SC_PAGESIZE);
if(sc == -1)
{
sys_page_size = 0x0000000000001000; /* Default to 4Kb */
}
else
{
sys_page_size = sc;
}
}
}
void *
page_allocate(size_t request,
size_t alignment)
{
size_t size;
size_t slop;
void *addr;
/* Round up to page size multiple.
*/
request = (request + (sys_page_size - 1)) & ~(sys_page_size -1);
alignment = (alignment + (sys_page_size - 1)) & ~(sys_page_size -1);
size = request + alignment;
/* Maybe we get lucky.
*/
addr = mmap(NULL,
request,
PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_ANONYMOUS,
-1,
0);
if(!((uintptr_t)addr & (alignment - 1)))
{
return addr;
}
munmap(addr, request);
addr = mmap(NULL,
size,
PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_ANONYMOUS,
-1,
0);
slop = (uintptr_t)addr & (request - 1);
#define POINTER_OFFSET(addr, offset) ((void *)((uintptr_t)(addr) + (offset)))
if(slop)
{
munmap(addr, request - slop);
munmap(POINTER_OFFSET(addr, size - slop), slop);
addr = POINTER_OFFSET(addr, request - slop);
}
else
{
munmap(POINTER_OFFSET(addr, request), request);
}
return addr;
}
int
main(int argc,
char **argv)
{
size_t size;
void *cmp = NULL;
void *ptr[16];
int i;
page_init();
if(argc == 2)
{
size = strtol(argv[1], NULL, 16);
}
else
{
size = 0x00001000;
}
for(i = 0;
i < 16;
i ++)
{
ptr[i] = page_allocate(size, size);
}
for(i = 0;
i < 16;
i ++)
{
printf("%2i: %p-%p %s\n",
i,
ptr[i],
(void *)((uintptr_t)ptr[i] + size - 1),
(llabs(ptr[i] - cmp) == size) ? "contiguous" : "");
cmp = ptr[i];
}
return 1;
}
答案 0 :(得分:1)
您永远不应期望mmap
自己提供连续的地址,但您可以尝试通过请求一个地址来获取它们,这将使新映射与地址一样长范围是免费的,并且省略MAP_FIXED
以便所请求的地址仅用作提示(使用MAP_FIXED
,它将替换已存在的地址,这绝对是不是强烈的>你想要的。)
我怀疑你看到mmap
为某些调用返回连续映射的原因,但不是全部,是内核试图平衡制作新VM区域的成本与希望拥有地址无法预测(ASLR)。