An interrupt and a CPU exception are different things. UNIX treats them similarly because the PDP-11 did. An interrupt is something outside the CPU wanting to be serviced, like an I/O completion. An interrupt can be deferred during a critical section, which is what "preventing interrupts" does. Some machines direct interrupts to one of many CPUs, so whoever is free can handle I/O. Interrupts have priorities, queuing, and are handled like events on a queue.
A hardware exception is the CPU doing something that stops execution. Inaccessible memory - could be the need to page something in from disk, or a program error. The OS has to decide that. Floating point overflow. Divide by zero. An illegal instruction. The CPU can't continue. So exceptions cannot be deferred, even if in a critical section. The CPU that raised the exception must handle the exception; it can't be handled by another CPU.
UNIX/Linux signals are rarely used for I/O completions in user space, but that is supported. See "aio".[1] Apparently Oracle uses this.
You can see NMIs for examples of interrupts outside the CPU that can't be deferred like the distinction you're making.
Additionally software interrupts are an example of interrupts that come from user space and can't be deferred from user space's perspective, but must be handled before their instruction stream continues.
You can also see processors like slave DSPs who's exceptions are routed to other processors to be handled just like any other interrupt on that other core. The N64's RSP, and the Cell's SPEs are great examples of this.
You gave the example of AIO for peripheral interruption to user space like an interrupts, (which is used by more than just Oracle), but the classic example is SIGLARM as a corollary to a timer interrupt.
This is not a Unix/PDP-11 thing, but pretty much every hardware arch and every OS out there. I say this as someone who's ported a non Unix derived RTOS to MIPS, PowerPC, ARMv7A, ARMv7M, ARMv8-A64, X86_64 linux user mode, Microblaze, and SH4, and has written drivers for Linux, FreeBSD, Windows CE, Windows NT, and that aforementioned RTOS.
That's more of a support processor thing, where the special-purpose processor doesn't really do interrupts. GPU exceptions usually create interrupts in the controlling CPU, for example, rather than being handled within the GPU. (How the GPUs should talk to the CPUs is a whole subject in its own right.)
Timer interrupts are usually deferrable.
The Cell. Is it totally gone now? (If they'd had, say, 16MB/SPE instead of 256K, it might have been good for something.)
I would say that's out of date. GPU exceptions typically don't exist for most shader code (unmapped memory loads are just RAZ, division by zero is defined and doesn't trap, etc.). For the ones that do exist, they're typically handled on GPU these days for latency reasons, but that's just a config register to route it externally or not.'
> Timer interrupts are usually deferrable.
I didn't say they weren't. Just like SIGALRM can be masked.
> The Cell. Is it totally gone now? (If they'd had, say, 16MB/SPE instead of 256K, it might have been good for something.)
16MB would have never made sense. You're only supposed to keep the working set in memory, and 64x the amount of memory was never in the cards from a gate count perspective.
Also reminds me of this: https://news.ycombinator.com/item?id=4157777
Sounds like something from Neuromancer
Terrifying but fun!
Next C statement is pretty cute, though.
I mean, it's not wrong, but it is crazy.
What you really need to do is figure out which instruction was executing and increment RIP appropriately.
colleague: "Caller says she's getting an error 'No Resumé' ?!?" us: ... huh?..... it is a document management system, but still ... . time passes . . me: Oh! On Error No Resumé us: much hilarity. No Resumé indeed.
Beyond that there are sometimes very valid reasons for allowing segfaults to occur in certain conditions and catching/patching them. For instance in an emulator's dynamic recompiler you could optimize your generated code by assuming that most memory accesses target the emulated RAM region (generally a reasonable assuption). Then you map the RAM buffer in such a way that if it turns out that the emulated program was actually attempting to access an address outside of RAM a memory fault occurs, which you can then catch and recompile the offending code block with a slower but more comprehensive address decode.
Yeah yeah yeah but this ALSO fixes use-after-free bugs! Really an amazing little trick, I wonder why compilers don't just do it automatically.
ON ERROR RESUME NEXT