出于并发/并行 GC 的目的,我对 mprotect 系统调用提供的内存顺序保证(即 mprotect 多线程的行为或 mprotect 的内存模型)感兴趣。我的问题是(假设没有编译器重新排序或有足够的编译器障碍)
如果线程 1 由于线程 2 上的 mprotect 触发了地址上的段错误,我是否可以确定在段错误的信号处理程序中的线程 1 中观察到系统调用之前,所有事情都发生在线程 2 上?如果在对线程 1 执行加载之前在信号处理程序中放置了一个完整的内存屏障怎么办?
如果线程 1 对由线程 2 设置为 PROT_NONE 的地址进行易失性加载并且没有触发段错误,那么这是否足够发生在两者之间的关系之前。或者换句话说,如果两个线程都这样做(
*ga
开始为0
,p
是一个页面对齐的地址以只读方式开始)// thread 1 *ga = 1; *(volatile int*)p; // no segfault happens // thread 2 mprotect(p, 4096, PROT_NONE); // Or replace 4096 by the real userspace-visible page size a = *ga;
是否可以保证
a
在线程 2 上会出现1
?(假设在线程 1 上没有观察到段错误并且没有其他代码修改*ga
)
我最感兴趣的是 Linux 行为,尤其是 x86(_64)、arm/aarch64 和 ppc,尽管欢迎访问有关其他 archs/OS 的信息(对于 Windows,将 mprotect 替换为 VirtualProtect 或其他任何名称......)。到目前为止,我在 x64 和 aarch64 Linux 上的测试表明没有违反这些规定,尽管我不确定我的测试是否是结论性的,或者是否可以长期依赖这种行为。
一些搜索表明,mprotect
可能会在删除权限时使用映射的地址对所有线程发出 TLB 击落,这可能会提供此处所述的保证(或者换句话说,提供此保证似乎是此类操作的目标),尽管我不清楚如果内核代码的未来优化可能会破坏这个保证。
参考LKML 帖子,我一周前问过这个问题,但还没有回复......
编辑:澄清问题。我知道 tlb 击落应该提供我正在寻找的保证,但我想知道是否可以依赖这种行为。换句话说,内核发出此类请求的原因是什么,因为如果不是为了提供某种排序保证,就不需要它。