6 ms·
The signal comes from a safe fetch, which is just a read that allows ignoring the fault as if it never happened. Such a signal is deliver synchronously, so the
by fweimer 3y ago
The signal comes from a safe fetch, which is just a read that allows ignoring the fault as if it never happened. Such a signal is deliver synchronously, so the usual restrictions for asynchronous signal handlers do not apply.
The code in question takes into account that the value read might be garbage. See the big comment here: https://github.com/openjdk/jdk/commit/29397d29baac3b29083b1b5d6b2cb06e456af0c3 https://github.com/openjdk/jdk/commit/29397d29baac3b29083b1b...
On current CPUs and operating systems, this is not an optimization, so the code was removed earlier this year: https://bugs.openjdk.org/browse/JDK-8320317 https://bugs.openjdk.org/browse/JDK-8320317
- arghwhat 3y agoThe "safe fetch" code relies on a signal handler (either here https://github.com/openjdk/jdk/blob/48717d63cc58f693f0917e61eafd672cd6af02ed/src/hotspot/os/posix/vmError_posix.cpp#L80 https://github.com/openjdk/jdk/blob/48717d63cc58f693f0917e61... or here https://github.com/openjdk/jdk/blob/3c70f26b2f3fa9bc143e2506af30f9b1daf20022/src/hotspot/os/posix/signals_posix.cpp#L557C5-L557C26 https://github.com/openjdk/jdk/blob/3c70f26b2f3fa9bc143e2506...), which is considered asynchronous delivery (i.e., delivered mid-execution, see `man 7 signal`) - which is why the `async-signal-safe` manpage simply states that it is functions that can safely be called within a signal handler. This is opposed to calling `sigwait` or similar to actively suspend and wait for a signal, which is not possible to do here. Granted, it may be that the stars align and their implementation works in practice, but that does not make it any less bizarre.
- quotemstr 3y agoIt's not "bizarre" at all. It's a direct translation of hardware CPU traps to userspace API. That's what signal handers are: virtualized interrupts! There's nothing wrong with using signals to achieve performance levels otherwise not possible.
- zozbot234 3y agoBut this also means that signal handlers are running in what's effectively a separate thread of execution - even in otherwise single-threaded code! So the things you're allowed to do safely in your signal handler are very limited, they boil down to atomically tweaking some lightweight data structure (or even just setting a flag) that the main code will look at later and behave accordingly.
- quotemstr 3y agoWhile it's true that async-signal-safe programming bears some similarities to multi-threaded programming, an interrupt really isn't the same as a thread. Also, there's a lot more you can do in a signal handler than just set a flag: you can longjmp or even make calls to regular functions. For example, one kind of program organization that used to be more common in Unix but that remains legal involves keeping signals masked all the time except around certain blocking system calls, e.g. ppoll, that atomically unblock signals and wait. In such a program, a signal can arrive only inside the blocking system call and so the handler can call regular functions without the usual strictures of asynchronous signal safety. (Consider responding to SIGWINCH, which tells you about changing terminal size.) Synchronous signals are also special in that they're, well, synchronous. That means that in the signal handler you can examine the target memory address or instruction pointer and take action specific to a given spot in your program --- e.g. longjmp to an error handler. All of this is useful, safe, and legal under POSIX. The main problems with POSIX signals are that, 1) as this thread underscores, most people don't understand them, and 2) signal handlers are process global and hard to share. (Consider if you're running two VMs in a process and each wants to use a SIGSEGV GC safe point trick.) (userfaultfd, sadly, requires more system calls than a synchronous signal handler to handle anomalous memory access.) We should be enhancing POSIX signals to make them easier to share, not casting aspersions on them.
- zozbot234 3y agoHow is this pattern any different from "keep interrupts disabled all the time except when the program is ready to yield()"? I'm not really seeing the inherent difference w/ the well-known pitfalls of multi-threaded programming. The defining characteristics of signals is that, like interrupts and multi-threaded execution, they can pre-empt your program at any time. (Synchronous signals as you describe them are indeed different, they look more like a "recoverable exceptions" system.)
- arghwhat 3y agoThis did not improve performance, it was just an unnecessary hack. The authors agree, as they removed it realizing it was not an optimization. UNIX signals are in no way or form direct translations of hardware CPU traps. The kernel handles hardware traps, which may or may not lead to UNIX signals. Heck, with userfaultfd, a different userspace process could be handling, or injecting, the fault! Not to mention VMs, where the the guest userspace is very far away from any real hardware traps. There are basically two classes of UNIX signals: Signals that indicate that you might need to take some action (SIGTERM, SIGALRM, SIGUSR1, ...), and signals that indicate that your process did something illegal (SIGILL, SIGSEGV, SIGFP, ...). There is a very, very limited number of cases where handling these errors make sense, and trying to be "clever" to make (faulty and ill-advised) performance optimizations is not one of them.
- quotemstr 3y agoPlease, knock it off with the value judgements. "Ill-advised" according to whom? You? Why should your opinion prevail? > This did not improve performance, it was just an unnecessary hack Well, the Android VM certainly uses a signal mechanism for safepoints and stack overflow checking, for a reason (https://android.googlesource.com/platform/art/+/master/runtime/fault_handler.cc#299 https://android.googlesource.com/platform/art/+/master/runti...) (both latency and code size), so don't sit there and tell me that the VM running the world's most popular OS is pessimizing itself pointlessly. > The kernel handles hardware traps, which may or may not lead to UNIX signals. Not all traps result in signals, and not all signals are traps. Nevertheless, the POSIX signals API is the means through which Unix OSes provide user programs the ability to interact with CPU traps. (Windows does the same thing, morally, with SEH and vectored exception handling --- https://learn.microsoft.com/en-us/windows/win32/debug/vectored-exception-handling https://learn.microsoft.com/en-us/windows/win32/debug/vector...). Any decent OS should provide applications with the tools they need to make full use of the underlying hardware. All these anti-signals people are just arguing that programs be bigger and slower, because they can't make full use of all the hardware features of the system, out of, ultimately, an aesthetic objection to signal handling.
- arghwhat 3y ago
- deleted 3y ago[deleted]