Beispiel #1
0
void __KernelReturnFromInterrupt()
{
    DEBUG_LOG(CPU, "Left interrupt handler at %08x", currentMIPS->pc);

    // This is what we just ran.
    PendingInterrupt pend = pendingInterrupts.front();
    pendingInterrupts.pop_front();

    intrHandlers[pend.intr]->handleResult(pend);
    inInterrupt = false;

    // Restore context after running the interrupt.
    intState.restore();
    // All should now be back to normal, including PC.

    // Alright, let's see if there's any more interrupts queued...
    if (!__RunOnePendingInterrupt())
    {
        // Otherwise, we reschedule when dispatch was enabled, or switch back otherwise.
        if (__KernelIsDispatchEnabled())
            __KernelReSchedule("return from interrupt");
        else
            __KernelSwitchToThread(threadBeforeInterrupt, "return from interrupt");
    }
}
// Returns true if anything was executed.
bool __RunOnePendingInterrupt()
{
	bool needsThreadReturn = false;

	if (inInterrupt || !interruptsEnabled) {
		// Already in an interrupt! We'll keep going when it's done.
		return false;
	}
	// Can easily prioritize between different kinds of interrupts if necessary.
retry:
	if (!pendingInterrupts.empty()) {
		PendingInterrupt pend = pendingInterrupts.front();

		IntrHandler* handler = intrHandlers[pend.intr];
		if (handler == NULL) {
			WARN_LOG(SCEINTC, "Ignoring interrupt");
			pendingInterrupts.pop_front();
			goto retry;
		}

		// If we came from CoreTiming::Advance(), we might've come from a waiting thread's callback.
		// To avoid "injecting" return values into our saved state, we context switch here.
		SceUID savedThread = __KernelGetCurThread();
		if (__KernelSwitchOffThread("interrupt")) {
			threadBeforeInterrupt = savedThread;
			needsThreadReturn = true;
		}

		intState.save();
		inInterrupt = true;

		if (!handler->run(pend)) {
			pendingInterrupts.pop_front();
			inInterrupt = false;
			goto retry;
		}

		currentMIPS->r[MIPS_REG_RA] = __KernelInterruptReturnAddress();
		return true;
	} else {
		if (needsThreadReturn)
			__KernelSwitchToThread(threadBeforeInterrupt, "left interrupt");
		// DEBUG_LOG(SCEINTC, "No more interrupts!");
		return false;
	}
}