xv6映射新共享内存页后进程无法正常结束问题求助
问题根源与解决方案
核心问题分析
你修改exec()让父子进程共享整个页目录的做法,违背了exec的原生语义——exec本应替换当前进程的完整地址空间。现在子进程执行exec("/bin/liSa")时,会直接在共享的页目录中修改映射,把父进程的代码段、数据段全部覆盖成liSa的镜像。父进程调用wait()返回后,执行流指向的printf和exit代码已经被破坏,自然触发陷阱无法执行。另外,子进程exit时会释放共享的页目录,父进程后续操作时页目录已失效,进一步加剧错误。
修复方案
方案1:放弃exec共享页目录,改用fork实现共享内存(推荐)
xv6原生fork已经实现写时复制(Copy-on-Write),父子进程默认共享物理页,只有当某一方执行写操作时才会复制页。如果需要显式共享特定内存区域,只需修改fork的页表映射逻辑,为目标页增加引用计数,避免写时复制即可,无需改动exec。
方案2:若坚持修改exec实现共享,需做以下调整
区分共享与私有内存区域
修改exec时,不要替换整个页目录,而是在父进程页目录的基础上,为子进程创建私有映射(如栈、进程私有数据段),仅共享指定区域(如代码段或自定义共享内存段),避免覆盖父进程的地址空间。添加引用计数机制
- 在
proc结构体中新增页目录引用计数字段:int pgdir_refcnt;,同时为共享页表项添加引用计数。 - 当
fork或exec触发页目录共享时,执行pgdir_refcnt++。 - 修改
exit函数:- 先清理进程私有资源(如私有栈、进程控制块等)。
- 对共享页目录执行
pgdir_refcnt--,仅当计数减至0时,才调用freewalk释放页表、kfree释放页目录;否则跳过资源释放,避免父进程的页目录被提前销毁。
- 在
修正exec的页表映射逻辑
exec加载新镜像时,仅修改子进程的私有区域映射,共享区域保持与父进程一致,同时更新对应页表项的引用计数,确保父子进程对共享页的操作互不干扰且资源不会被提前释放。
针对你的代码的临时验证
可以先注释掉exec的共享页目录修改,恢复exec原生逻辑,此时父进程wait()后应该能正常执行printf和exit,以此验证地址空间被覆盖是核心问题。
内容的提问来源于stack exchange,提问作者xyz
相关产品推荐
相关产品推荐

