原文:http://www.ophonesdn.com/forum/thread-6260-8-1.html
pmem与ashmem都通过mmap实现共享,区别是Pmem的共享区域是一段连续的物理内存,而Ashmem的共享区域在虚拟空间是连续的,物理内存却不一定连续
A、PMEM的实现
Pmem的源代码在drivers/misc/pmem.c中,Pmem驱动依赖于linux的misc device和platform driver框架,一个系统可以有多个Pmem,默认的是最多10个。Pmem暴露4组操作,分别是platform driver的probe和remove操作; misc device的fops接口和vm_ops操作。模块初始化时会注册一个platform driver,在之后probe时,创建misc设备文件,分配内存,完成初始化工作。
Pmem通过pmem_info,pmem_data,pmem_region三个结构体维护分配的共享内存,其中pmem_info代表一个Pmem设备分配的内存块,pmem_data代表该内存块的一个子块,pmem_region则把每个子块分成多个区域。 pmem_data是分配的基本单位,即每次应用层要分配一块Pmem内存,就会有一个pmem_data来表示这个被分配的内存块,实际上在open的时候,并不是open一个pmem_info表示的整个Pmem内存块,而是创建一个pmem_data以备使用。一个应用可以通过ioctl来分配pmem_data中的一个区域,并可以把它map到进程空间;并不一定每次都要分配和map整个pmem_data内存块
B、用户接口
一个进程首先打开Pmem设备,通过ioctl(PMEM_ALLOCATE)分配内存,它mmap这段内存到自己的进程空间后,该进程成为master进程。其他进程可以重新打开这个pmem设
备,通过调用ioctl(PMEM_CONNECT)将自己的pmem_data与master进程的pmem_data建立连接关系,这个进程就成为client进程。Client进程可以通过mmap将master Pmem中的一段或全部重新映射到自己的进程空间,这样就实现了共享Pmem内存。如果是GPU或DSP则可以通过ioctl(PMEM_GET_PHYS)获取物理地址进行操作。
3. 在应用程序中的使用:
1)
Pmem 例子:
sp<MemoryHeapBase> master_workspace = new MemoryHeapBase(pmem_adsp, Coda_WorkSpace_Size);
//new 一个 base
memeoryHeapBase ,构造函数中做了 2 件事情 , 一个是 open “/dev/pmem_adsp” 设备, 第二是调用 mapfd (内部即 mmap )来得到共享内存区域
if (master_workspace->heapID() < 0) {
LOGD("Error creating workspace heap");
Status = UNKNOWN_ERROR;
}
master_workspace->setDevice(pmem); // 如果 pmem_adsp device 出错, 就是用 pmem device
mHeapPmem_workspace = new MemoryHeapPmem(master_workspace, 0);
// new 一个 Pmem , MemoryHeapPmem , (构造函数中调用 init ,设定了 Base,device ,size 等)
mHeapPmem_workspace->slap();
master_workspace.clear();
if (ioctl(mHeapPmem_workspace->heapID(), PMEM_GET_PHYS, ®ion) >= 0)// 得到物理地址
{
pys_address = (unsigned int)region.offset;
WORK_SPACE_PMEM_PHY_ADDRESS = pys_address;
WORK_SPACE_PMEM_VIR_ADDRESS = mHeapPmem_workspace->base(); // 得到虚拟地址
}
else
{
pys_address = 0xFFFFFFFF;
LOGE("Error: WORKSPACE PMEM_GET_PHYS FAILED");
return UNKNOWN_ERROR;
}
2)
Ashmem 例子:
sp<MemoryHeapBase> heap = new MemoryHeapBase(frameSize * kBufferCount);
if (heap->heapID() < 0) {
LOGE("Error creating frame buffer heap");
return false;
}
// 没有指定 device , 就是用的 ashmem . 构造函数中做了 2 件事情 , 一个是 ashmem_create_region , 第二是调用 mapfd (内部即 mmap )来得到共享内存区域
第一步通过调用 ashmem_create_region 函数,这个函数完成这几件事:
1 ) fd = open("/dev/ashmem", O_RDWR);
2 ) ioctl(fd, ASHMEM_SET_NAME, region_name); // 这一步可选
3 ) ioctl(fd, ASHMEM_SET_SIZE, region_size);
第二步,应用程序一般会调用 mmap 来把 ashmem 分配的空间映射到进程空间:
mapAddr = mmap(NULL, pHdr->mapLength, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
4. 如何将PMEM编入内核