More JVM Signal tricks - Thread control via mprotect
09 Nov 2015In my last post, I mentioned the JVM uses intentionally uses SIGSEGVS in other interesting ways. In this post I’ll give an overview of one of those other ways, synchronization for GC pauses.
If you ever look at generated assembly from Hotspot, you will find methods ending with very odd-looking tests like this:
At first glance, this doesn’t seem to serve any real purpose right before the return. Rather than doing any useful work, its just a way of trying to read from 0x7fce84071000
, the designated polling page. Modifying access to this page lets the JVM stop threads cleanly - in places where the state of the world is well-known.
We can make the world stop
To stop the world, the JVM calls SafepointSynchronize::begin
in safepoint.cpp, which calls os::make_polling_page_unreadable
, the linux implementation of which calls mprotect
on the page with PROT_NONE
(no access allowed)
When our compiled code hit those tests, they’ll now segfault. Again looking back at Hotspot’s linux x86 signal handler, in os_linux_86.cpp
This case is handled via SharedRuntime::get_poll_stub
, which returns the address of the handler, a wrapper around SafepointSynchronize::handle_polling_page_exception
.
In Action
To see this in action, heres a quick demo. We start a 3 threads doing a bunch of (non object allocating) busy work, and then then manually issue a gc from the main thread after waiting long enough to be fairly confident they have been compiled.
Again, we can run this via strace
strace -f -o outfile java GC
and clearly see this in action - an mprotect
preventing reads & writes is issued on the page starting at 0x7fce84071000
, which all 3 processes quickly segfault trying to read from.
23172 mprotect(0x7fce84071000, 4096, PROT_NONE) = 0
23182 --- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_ACCERR, si_addr=0x7fce84071000} ---
23180 --- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_ACCERR, si_addr=0x7fce84071000} ---
23181 --- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_ACCERR, si_addr=0x7fce84071000} ---
Nifty eh?
(Shameless plug: If you are, like me, crazy enough to find this sort of stuff interesting, follow me on twitter.