There’s a couple of overlapping questions here. I hope I can answer them, if not necessarily the right order.
Reads are used rather than writes because reads don’t incur cross-CPU cache invalidations. If threads were writing to a page, then cache invalidation traffic would be sent between CPUs, and also interact with the outgoing memory bus to no effect. With the reads, you’re essentially just validating that read against a permissions bit in the TLB, and while you’re pulling in a cache line, it’s in a shared state so doesn’t affect other CPUs. The second reason why an ‘if’ conditional is not used is to avoid the jump. A speculating CPU can of course continue executing past the ‘if’ condition in order to make further progress, but may limit how far the CPU can speculate ahead. In fact, if you had the ‘if’ condition in place, you wouldn’t need a trap at all - you could just jump to the place where the trap handler does its work. The protect a single page works because in normal flow, a read is effectively a free no-op to which the CPU can keep executing and doesn’t pollute any of the branch prediction, outgoing memory bandwidth or cross-CPU cache invalidations. Note that the single-page approach is the one chosen by OpenJDK/Hotspot; other JVMs have the ability to stop on a per-thread basis rather than globally bringing everything to a halt. Alex Sent from my iPhone 📱 > On 18 May 2020, at 05:27, Steven Stewart-Gallus > <[email protected]> wrote: > > Hi > As I understand it most VMs poll for safepoints by using memory management > tricks to page fault polling threads. A page is set aside to read from and > whenever a safepoint is desired the page is set to be unreadable. > > But can't a number of other hardware traps be used instead > https://wiki.osdev.org/Exceptions ? > > Not sure if a conditional jump to a trapping debug instruction would be slow > or not. > > Also why not read from a pointer to a page instead of reading directly? That > way only a an atomic write to a pointer is needed instead of a whole memory > protection syscall. > > Also an atomicly written boolean flag is only one of many possible types of > branches. > You could have an indirect call or possibly jump and just overwrite a > function pointer to install your handler for example. > > The standard way of doing things seems pretty sensible but it's just I've > never actually seen a concrete comparison. > > Basically in pseudocode why > > void poll() { > page[0]; > } > void trap() { > mprotect(page, 0); > } > > over > > void poll() { > page[0]; > } > void trap() { > page = 0; > } > > or > > void poll() { > 1 / bit; > } > void trap() { > bit = 0; > } > > And why > > void poll() { > if (flag) dostuff(); > } > > over > > void poll() { > f(); > } > void trap() { > f = handler; > } > > Or > > void poll() { > if (flag) __builtin_trao(); > } > > Probably makes sense to do safepoint polls the standard way but I've never > seen a detailed comparison exactly why. > > -- > You received this message because you are subscribed to the Google Groups > "mechanical-sympathy" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to [email protected]. > To view this discussion on the web, visit > https://groups.google.com/d/msgid/mechanical-sympathy/5a36e38d-3811-4663-a7d5-b9ac4897404d%40googlegroups.com. -- You received this message because you are subscribed to the Google Groups "mechanical-sympathy" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To view this discussion on the web, visit https://groups.google.com/d/msgid/mechanical-sympathy/BBFDFC0B-5E9D-49A0-9DF6-E4853905BC66%40gmail.com.
