出于并发/并行GC的目的我对mprotect syscall提供的内存顺序保证感兴趣(即具有多个线程的mprotect的行为或mprotect的内存模型(。我的问题是(假设没有编译器重新排序或具有足够的编译器屏障(
-
如果线程1触发了由于在线程2,我可以确定一切都发生在线程2上可以在线程1中观察到Syscall的信号处理程序segfault?如果在信号中放置完整的内存屏障怎么办在Thread1上执行负载之前的处理程序?
-
如果线程1在设置为的地址上进行挥发性负载prot_none by thread 2,没有触发segfault,这已经足够了在两者之间的关系之前发生。或另一个单词,如果两个线程do(
*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;
是否可以保证线程2上的
a
将是1
?(假设没有在线程1上观察到的segfault,没有其他代码修改*ga
(
我对Linux行为非常感兴趣,尤其是对X86(_64(,ARM/AARCH64和PPC虽然有关其他拱门/OS的信息欢迎来到(对于Windows,用VirtualProtect替换MPROTECT或任何称为...(。到目前为止,我对X64和AARCH64 Linux的测试建议不违反这些,尽管我不确定我的测试是否是结论性的,或者从长远来看是否可以依靠这种行为。
一些搜索表明,mprotect
可能会在所有线程上发出TLB射击,并在删除权限时映射地址,这可能提供此处所述的保证(或者用另一个单词,前提此保证似乎是此类操作的目标(我尚不清楚内核代码的未来优化是否可能打破此guarentee。
ref lkml帖子我一周前询问了这一点,但还没有回复...
编辑:有关问题的澄清。我知道TLB射击应该提供我想要的保证,但我想知道是否可以依靠这种行为。从另一个单词中,内核发出此类请求的原因是什么,因为如果不提供某种订购保证,则不需要。
所以我在这里发布了一天的机械同情组,并从吉尔·特内(Gil Tene(得到答案。在他的允许下,这是我对他的答案的摘要。完整线程可在此处可用,以防万一我不包括的东西不清楚。
对于一个人可以期望的整体行为。
(如" OS不遇到的操作系统(是令人惊讶的(:
呼叫mprotect((是针对呼叫之前和之后发生的负载和商店的完全排序的。这往往是在CPU和OS级别上实现的,因为Mprotect是一个系统调用,涉及一个陷阱,进而涉及完全排序。[在奇怪的无环 - 过渡 - 实施(例如内核执行等(中,保护呼叫可能是责任模拟此订购假设的责任]。
呼叫mprotect不会在该过程中的保护请求在语义上无处不在。如果mprotect((调用设置一个会导致故障的保护,则需要在此mprotect((调用之后发生的任何线程上进行故障。同样,如果mprotect((调用设置一个防止故障的保护
这本质上意味着其他线程上受影响页面上的内存操作与呼叫mprotect
的线程同步。更具体地说,可以保证原始问题中提到的两个案例中的两个。即。
-
如果观察到由于mprotect调用而导致的一个线程中的一个线程上的一个负载,则此故障发生在mprotect((呼叫之后,因此可以在Mprotect之前观察所有内存操作,因此可以观察到所有内存操作。
-
如果观察到受影响页面中一个线程上的一个负载并不是错误的错误,请列出mprotect调用,负载发生在mprotect呼叫和mprotect呼叫之前,以及在加载后的任何代码,并将能够观察到负载之前发生的任何内存操作。
也有人指出,传递性可能行不通,即,一个线程上的故障负载可能不会在另一线程上的非故障负载之后进行。这可能(有效地(是由TLB冲洗的非原子性引起的,导致不同的线程/CPU观察不同时间的访问权限的变化。