David Daney wrote:
> Kevin D. Kissell wrote:
>> But it *could* be a trap or system call instruction, or a load/store
>> that would provoke a TLB exception. In the usual cases, however, as
>> I believe David was alluding, either the exception will ultimately
>> unwind to return to execute the magic alignment trap, or the thread
>> will exit, and could free the emulation slot as part of general cleanup.
>> But there's a case that isn't handled in this model, and that's the
>> case of an exception (or interrupt that falls in the 2-instruction
>> window) resulting in a signal that is caught and dispatched, and
>> where either the signal handler does a longjmp and restarts FP
>> computation, or where the signal handler itself contains a FP branch
>> with yet another delay slot to be emulated. One *could* get alarm
>> signal before the original delay slot instruction is executed, so
>> recycling the same vdso cache line would be premature. It's hard to
>> get away from something distinctly stack-like if one wants to cover
>> these cases.
> System calls we don't have to handle, they will eventually return to
> the break instruction following the delay slot instruction and be
> handled by the normal processing.
> I am thinking that all other exceptions will result in one of three
> 1) They will work like system calls and return to the 'break'.
> 2) The thread will exit.
> 3) They result in a signal being sent to the thread. We can handle it
> in force_signal(). In this case we would adjust the eip to point at
> the original location of the instruction and clean things up. If the
> signal handler tries to restart the instruction, the FP emulator will
> re-run the emulation.
That's presumably OK if we *know* that the delay slot instruction has
*not* executed prior to the signal being taken. But if it has, it may
have had side-effects, i.e. imagine if it's an "ADD.S f4, f4, f6". We
can't re-run the emulation without generating erroneous processor
state. What do we do if, between the ADD.S and the
BREAK-that-replaces-my-old-alignment-trap, a timer interrupt comes in,
causing a SIGALRM which is caught and which executes another FP branch?
When I first wrote the delay slot handling code, I dreamed of disabling
interrupts during the delay slot instruction emulation - I think I even
coded it that way at one point - but it's fundamentally uncool to go off
into user mode with interrupts off.
I really think that once the delay slot emulation machinery has been put
into motion, that fact needs to become a part of the thread state.
Currently, it's encoded, in a sense, in the stack pointer and the stack
contents. If we no longer stack it, and use a more static instruction
buffer as a trampoline, then I think it needs to be tagged as part of
the kernel's thread state.
That knowledge might be used in various ways. I still think it would
work to check that state and cause any signals to that thread need to be
deferred until it has processed the BREAK instruction to restore the
pre-emulation instruction flow. Once the state has been restored from
the dsemul record, the signal can be dispatched rather than returning
directly to the branch target. I don't like putting another check into
the context restore code, though.
A cruftier, but less inefficient-in-the-expected-case approach would be
a variant on what you suggest above. Signal dispatch could check the
EPC, and *if* EPC shows that the delay slot exception hasn't yet
executed, it could roll back the EPC to re-execute the FP branch after
the signal. If the delay slot instruction *has* executed, but not the
following BREAK, the signal dispatch code could preemptively do the
dsemulret cleanup and restore the pre-emulation stack and post-emulation
EPC before doing the signal dispatch.