MIPS体系架构下的shmat()函数注意事项 和 SHMLBA

     

        最近在进行criu zdtm单项测试 ./test/zdtm.py run -t zdtm/transition/ipc 时,测试失败。分析ipc.c用例发现,ipc测试实例功能是父进程创建了2个子进程,并通过信号量和子进程共享一个内存空间并进行数据交互。测试失败点在criu restore过程中,子进程对共享内存的虚拟地址映射无法对应上criu dump之前的地址,定位到criu 调用函数newaddr = shmat(shm,oldaddr,0)时,返回的地址newaddr不等于oldaddr所致。

       为了排查问题,我写了一个小测试实例,核心代码如下:

/* 创建一个共享内存对象并返回共享内存标识符 */
shm = shmget(key, shmem_size, 0777 | IPC_CREAT | IPC_EXCL); 

/* 把共享内存区对象映射到调用进程的地址空间 */
mem = shmat(shm, NULL, 0); 

printf("line(%s): mem=%p\n",__LINE__,mem);

/*把共享内存区对象映射到调用进程的固定地址空间 */
mem = shmat(shm, mem, SHM_RND | SHM_REMAP); 

printf("line(%s): mem=%p\n",__LINE__,mem);

key和shmem_size可以随便生成和指定,通常shmem_size为当前系统页大小PAGE_SIZE的整数倍即可。上述代码某一次执行结果如下:

line(128):  mem=0xfff5e9c000
line(133):  mem=0xfff5e80000

         可以看到使用第一次使用shmat(shm,NULL,0)映射出来的虚拟地址为0xfff5e9c000,这个地址是PAGE_SIZE的整数倍(当前系统PAGE_SIZE为16K)。第二次使用shmat(shm, mem, SHM_RND | SHM_REMAP),这里mem为0xfff5e9c000,映射出来的虚拟地址为0xfff5e80000,而不是我所期望的0xfff5e9c000。而且这个地址0xfff5e80000是SHMLBA的整数倍,SHMLBA定义在内核代码arch/mips/include/asm/shmparam.h里。

           SHMLBA是什么?这就引出一个知识点,CPU 高速缓存cache的组织方式:VIVT(Virtual Index Virtual Tag) 、VIPT(Virtual Index Physical Tag)、PIPT(Physical Index Physical Tag)。这3种方式可以参考https://blog.csdn.net/hx_op/article/details/89244618

            使用VIVT和VIPT组织方式的cache都存在高速缓存别名的问题。就是如果两个不同的cache line索引指向同一个物理内存地址,那么改变别名中的一个就可能导致命中失败或者全部从写。为了克服此问题,内核中在对进程间共享内存的使用SHMLBA(4个页大小)对齐的页渲染方式。目前MIPS和ARMv6 体系架构中,对一级高速缓存都是使用VIPT方式,所以都要求4个页大小的对齐方式。

shmat对应的sys_shmat系统调用在内核中对请求有固定地址映射时的处理方式就是:如果体系架构使用VIPT方式,那么就要求SHMLBA对齐,代码如下:

long do_shmat(int shmid, char __user *shmaddr, int shmflg,
	      ulong *raddr, unsigned long shmlba)
{
       ...
	if (addr) {
		if (addr & (shmlba - 1)) {
			if (shmflg & SHM_RND) {
				addr &= ~(shmlba - 1);  /* round down */

				/*
				 * Ensure that the round-down is non-nil
				 * when remapping. This can happen for
				 * cases when addr < shmlba.
				 */
				if (!addr && (shmflg & SHM_REMAP))
					goto out;
			} else
#ifndef __ARCH_FORCE_SHMLBA
				if (addr & ~PAGE_MASK)
#endif
					goto out;
		}

		flags |= MAP_FIXED;

在MIPS中SHMLBA的定义在内核代码arch/mips/include/asm/shmparam.h里,具体如下:

#define __ARCH_FORCE_SHMLBA	1
#define SHMLBA 0x40000	/* attach addr a multiple of this */

         由此可知,上面0xfff5e9c000不是0x40000的整数倍,即非0x40000对齐。所以shmat(shm,0xfff5e9c000, SHM_RND | SHM_REMAP)返回地址不是0xfff5e9c000。内核会在进程堆区重新找一块同大小的区域,且此区域的起始地址为0x40000对齐,并把此起始地址返回,此处为0xfff5e80000。

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

海棠花败

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值