为了实现并发/并行GC,我对mprotect系统调用提供的内存顺序保证感兴趣(即在多线程或mprotect的内存模型中的行为)。我的问题是(假设没有编译器重新排序或具有足够的编译器障碍):
If thread 1 triggers a segfault on an address due to a mprotect on thread 2, can I be sure that everything happens on thread 2 before the syscall can be observed in thread 1 in the signal handler of the segfault? What if a full memory barrier is placed in the signal handler before performing load on thread1?
If thread 1 does an volatile load on an address that is set to PROT_NONE by thread 2 and didn't trigger a segfault, is this enough of a happens before relation between the two. Or in another word, if the two threads do (
*ga
starts as0
,p
is a page aligned address started readonly)// 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;
is there a guarantee that
a
on thread 2 will be1
? (assuming no segfault observed on thread 1 and no other code modifies*ga
)
我主要关心Linux的行为,特别是在x86(_64),arm/aarch64和ppc上的行为,尽管其他架构/操作系统的信息也很受欢迎(对于Windows,请使用VirtualProtect或类似方法替换mprotect...)。到目前为止,在x64和aarch64 Linux上的测试表明没有违规行为,但我不确定我的测试是否具有决定性,或者这种行为在长期内是否可靠。
一些搜索表明,当权限被移除时,mprotect
可能会对所有映射地址的线程发出TLB shootdown,这可能提供了此处所述的保证(或者换句话说,提供此保证似乎是此操作的目标),但我不清楚内核代码的未来优化是否会破坏此保证。
参考LKML帖子,我在一周前提出了这个问题,但还没有得到回复...
编辑:关于问题的澄清。我知道TLB shootdown应该提供我正在寻找的保证,但我想知道是否可以依赖这种行为。换句话说,为什么内核会发出这样的请求,因为如果不提供某种排序保证,则不需要这样做。
PROT_NONE
到PROT_READ
)或不允许(PROT_READ
到PROT_NONE
)访问。在Linux中,前者情况下省略了TLB刷新,因此同时运行的线程可能会在不同时间看到更改。在后一种情况下,进行TLB刷新,因此线程应该同时观察到更改(在TLB刷新时刻)--尽管我不确定是否存在TLB刷新在不同CPU(包!)上是非同时的硬件。 - Nominal Animal