-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Description
Right now, to check if for interrupts:
- we load the interrupts pointer from the vmctx
- we dereference it to get the maybe-interrupted value
- we compare that against the interrupt-has-been-requested value
- and finally we conditionally trap when the comparison returned true.
There is no fast/slow path split here. Interrupts happen rarely, but we always perform those four steps.
By using virtual memory tricks, we can create a fast path for the common case when no interrupts are requested. We reserve a page of memory as the "interrupt page" and point to it from the vmctx. This replaces the current interrupt pointer on the vmctx. When interrupts are not requested, this page is readable. When an interrupt is requested, remove the readable bit via mprotect, and wait.
Now, all that our loop headers do is:
- load the pointer to the interrupts page from the vmctx
- (attempt to) read the first byte from the interrupts page
When the interrupts page is readable and an interrupt is not requested, we just have those two loads as our fast path.
When the interrupts page is not readable because an interrupt is requested, a signal is generated, so our signal handler needs to recognize+handle this case.
IIRC, essentially this same trick is used in some JVMs for synchronizing at safepoints for stop-the-world GC phases (e.g. root marking).
The one open question is how to detect stack overflows with this setup, since our interrupt handling and stack overflow code is very intertwined. Not totally sure here.
+cc @alexcrichton