mirror of
				https://git.suyu.dev/suyu/suyu.git
				synced 2025-11-04 12:34:39 +08:00 
			
		
		
		
	Qt: Restructured to remove unnecessary shutdown event and various cleanups.
This commit is contained in:
		
							parent
							
								
									3dd2688785
								
							
						
					
					
						commit
						e4ea133717
					
				@ -28,9 +28,8 @@
 | 
			
		||||
#define COPYRIGHT       "Copyright (C) 2013-2014 Citra Team"
 | 
			
		||||
 | 
			
		||||
EmuThread::EmuThread(GRenderWindow* render_window) :
 | 
			
		||||
    exec_cpu_step(false), cpu_running(false), stop_run(false), render_window(render_window) {
 | 
			
		||||
    exec_step(false), running(false), stop_run(false), render_window(render_window) {
 | 
			
		||||
 | 
			
		||||
    shutdown_event.Reset();
 | 
			
		||||
    connect(this, SIGNAL(started()), render_window, SLOT(moveContext()));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -42,20 +41,20 @@ void EmuThread::run() {
 | 
			
		||||
    // next execution step
 | 
			
		||||
    bool was_active = false;
 | 
			
		||||
    while (!stop_run) {
 | 
			
		||||
        if (cpu_running) {
 | 
			
		||||
        if (running) {
 | 
			
		||||
            if (!was_active)
 | 
			
		||||
                emit DebugModeLeft();
 | 
			
		||||
 | 
			
		||||
            Core::RunLoop();
 | 
			
		||||
 | 
			
		||||
            was_active = cpu_running || exec_cpu_step;
 | 
			
		||||
            was_active = running || exec_step;
 | 
			
		||||
            if (!was_active)
 | 
			
		||||
                emit DebugModeEntered();
 | 
			
		||||
        } else if (exec_cpu_step) {
 | 
			
		||||
        } else if (exec_step) {
 | 
			
		||||
            if (!was_active)
 | 
			
		||||
                emit DebugModeLeft();
 | 
			
		||||
 | 
			
		||||
            exec_cpu_step = false;
 | 
			
		||||
            exec_step = false;
 | 
			
		||||
            Core::SingleStep();
 | 
			
		||||
            emit DebugModeEntered();
 | 
			
		||||
            yieldCurrentThread();
 | 
			
		||||
@ -65,40 +64,8 @@ void EmuThread::run() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    render_window->moveContext();
 | 
			
		||||
 | 
			
		||||
    shutdown_event.Set();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void EmuThread::Stop() {
 | 
			
		||||
    if (!isRunning()) {
 | 
			
		||||
        LOG_WARNING(Frontend, "EmuThread::Stop called while emu thread wasn't running, returning...");
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    stop_run = true;
 | 
			
		||||
 | 
			
		||||
    // Release emu threads from any breakpoints, so that this doesn't hang forever.
 | 
			
		||||
    Pica::g_debug_context->ClearBreakpoints();
 | 
			
		||||
 | 
			
		||||
    //core::g_state = core::SYS_DIE;
 | 
			
		||||
 | 
			
		||||
    // TODO: Waiting here is just a bad workaround for retarded shutdown logic.
 | 
			
		||||
    wait(1000);
 | 
			
		||||
    if (isRunning()) {
 | 
			
		||||
        LOG_WARNING(Frontend, "EmuThread still running, terminating...");
 | 
			
		||||
        quit();
 | 
			
		||||
 | 
			
		||||
        // TODO: Waiting 50 seconds can be necessary if the logging subsystem has a lot of spam
 | 
			
		||||
        // queued... This should be fixed.
 | 
			
		||||
        wait(50000);
 | 
			
		||||
        if (isRunning()) {
 | 
			
		||||
            LOG_CRITICAL(Frontend, "EmuThread STILL running, something is wrong here...");
 | 
			
		||||
            terminate();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    LOG_INFO(Frontend, "EmuThread stopped");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// This class overrides paintEvent and resizeEvent to prevent the GUI thread from stealing GL context.
 | 
			
		||||
// The corresponding functionality is handled in EmuThread instead
 | 
			
		||||
class GGLWidgetInternal : public QGLWidget
 | 
			
		||||
 | 
			
		||||
@ -25,66 +25,46 @@ public:
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Start emulation (on new thread)
 | 
			
		||||
     *
 | 
			
		||||
     * @warning Only call when not running!
 | 
			
		||||
     */
 | 
			
		||||
    void run() override;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Allow the CPU to process a single instruction (if cpu is not running)
 | 
			
		||||
     *
 | 
			
		||||
     * Steps the emulation thread by a single CPU instruction (if the CPU is not already running)
 | 
			
		||||
     * @note This function is thread-safe
 | 
			
		||||
     */
 | 
			
		||||
    void ExecStep() { exec_cpu_step = true; }
 | 
			
		||||
    void ExecStep() { exec_step = true; }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets whether the CPU is running 
 | 
			
		||||
     *
 | 
			
		||||
     * Sets whether the emulation thread is running or not
 | 
			
		||||
     * @param running Boolean value, set the emulation thread to running if true
 | 
			
		||||
     * @note This function is thread-safe
 | 
			
		||||
     */
 | 
			
		||||
    void SetCpuRunning(bool running) { cpu_running = running; }
 | 
			
		||||
    void SetRunning(bool running) { this->running = running; }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Allow the CPU to continue processing instructions without interruption
 | 
			
		||||
     *
 | 
			
		||||
     * Check if the emulation thread is running or not
 | 
			
		||||
     * @return True if the emulation thread is running, otherwise false
 | 
			
		||||
     * @note This function is thread-safe
 | 
			
		||||
     */
 | 
			
		||||
    bool IsCpuRunning() { return cpu_running; }
 | 
			
		||||
 | 
			
		||||
    bool IsRunning() { return running; }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Shutdown (permantently stops) the CPU
 | 
			
		||||
     * Shutdown (permanently stops) the emulation thread
 | 
			
		||||
     */
 | 
			
		||||
    void ShutdownCpu() { stop_run = true; };
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Waits for the CPU shutdown to complete
 | 
			
		||||
     */
 | 
			
		||||
    void WaitForCpuShutdown() { shutdown_event.Wait(); }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
public slots:
 | 
			
		||||
    /**
 | 
			
		||||
     * Stop emulation and wait for the thread to finish.
 | 
			
		||||
     *
 | 
			
		||||
     * @details: This function will wait a second for the thread to finish; if it hasn't finished until then, we'll terminate() it and wait another second, hoping that it will be terminated by then.
 | 
			
		||||
     * @note: This function is thread-safe.
 | 
			
		||||
     */
 | 
			
		||||
    void Stop();
 | 
			
		||||
    void Shutdown() { stop_run = true; };
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    friend class GMainWindow;
 | 
			
		||||
 | 
			
		||||
    EmuThread(GRenderWindow* render_window);
 | 
			
		||||
 | 
			
		||||
    bool exec_cpu_step;
 | 
			
		||||
    bool cpu_running;
 | 
			
		||||
    bool exec_step;
 | 
			
		||||
    bool running;
 | 
			
		||||
    std::atomic<bool> stop_run;
 | 
			
		||||
 | 
			
		||||
    GRenderWindow* render_window;
 | 
			
		||||
 | 
			
		||||
    Common::Event shutdown_event;
 | 
			
		||||
 | 
			
		||||
signals:
 | 
			
		||||
    /**
 | 
			
		||||
     * Emitted when the CPU has halted execution
 | 
			
		||||
 | 
			
		||||
@ -201,7 +201,7 @@ void DisassemblerWidget::Init()
 | 
			
		||||
 | 
			
		||||
void DisassemblerWidget::OnContinue()
 | 
			
		||||
{
 | 
			
		||||
    main_window.GetEmuThread()->SetCpuRunning(true);
 | 
			
		||||
    main_window.GetEmuThread()->SetRunning(true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DisassemblerWidget::OnStep()
 | 
			
		||||
@ -211,13 +211,13 @@ void DisassemblerWidget::OnStep()
 | 
			
		||||
 | 
			
		||||
void DisassemblerWidget::OnStepInto()
 | 
			
		||||
{
 | 
			
		||||
    main_window.GetEmuThread()->SetCpuRunning(false);
 | 
			
		||||
    main_window.GetEmuThread()->SetRunning(false);
 | 
			
		||||
    main_window.GetEmuThread()->ExecStep();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DisassemblerWidget::OnPause()
 | 
			
		||||
{
 | 
			
		||||
    main_window.GetEmuThread()->SetCpuRunning(false);
 | 
			
		||||
    main_window.GetEmuThread()->SetRunning(false);
 | 
			
		||||
 | 
			
		||||
    // TODO: By now, the CPU might not have actually stopped...
 | 
			
		||||
    if (Core::g_app_core) {
 | 
			
		||||
@ -227,7 +227,7 @@ void DisassemblerWidget::OnPause()
 | 
			
		||||
 | 
			
		||||
void DisassemblerWidget::OnToggleStartStop()
 | 
			
		||||
{
 | 
			
		||||
    main_window.GetEmuThread()->SetCpuRunning(!main_window.GetEmuThread()->IsCpuRunning());
 | 
			
		||||
    main_window.GetEmuThread()->SetRunning(!main_window.GetEmuThread()->IsRunning());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DisassemblerWidget::OnDebugModeEntered()
 | 
			
		||||
@ -235,7 +235,7 @@ void DisassemblerWidget::OnDebugModeEntered()
 | 
			
		||||
    ARMword next_instr = Core::g_app_core->GetPC();
 | 
			
		||||
 | 
			
		||||
    if (model->GetBreakPoints().IsAddressBreakPoint(next_instr))
 | 
			
		||||
        main_window.GetEmuThread()->SetCpuRunning(false);
 | 
			
		||||
        main_window.GetEmuThread()->SetRunning(false);
 | 
			
		||||
 | 
			
		||||
    model->SetNextInstruction(next_instr);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -199,10 +199,6 @@ void GMainWindow::OnDisplayTitleBars(bool show)
 | 
			
		||||
void GMainWindow::BootGame(std::string filename) {
 | 
			
		||||
    LOG_INFO(Frontend, "Citra starting...\n");
 | 
			
		||||
 | 
			
		||||
    // Shutdown previous session if the emu thread is still active...
 | 
			
		||||
    if (emu_thread != nullptr)
 | 
			
		||||
        ShutdownGame();
 | 
			
		||||
 | 
			
		||||
    System::Init(render_window);
 | 
			
		||||
 | 
			
		||||
    // Load a game or die...
 | 
			
		||||
@ -222,29 +218,36 @@ void GMainWindow::BootGame(std::string filename) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GMainWindow::ShutdownGame() {
 | 
			
		||||
    emu_thread->SetCpuRunning(false);
 | 
			
		||||
 | 
			
		||||
    emu_thread->ShutdownCpu();
 | 
			
		||||
    emu_thread->WaitForCpuShutdown();
 | 
			
		||||
    emu_thread->Stop();
 | 
			
		||||
 | 
			
		||||
    // Shutdown the emulation thread and wait for it to complete
 | 
			
		||||
    emu_thread->SetRunning(false);
 | 
			
		||||
    emu_thread->Shutdown();
 | 
			
		||||
    emu_thread->wait();
 | 
			
		||||
    delete emu_thread;
 | 
			
		||||
    emu_thread = nullptr;
 | 
			
		||||
 | 
			
		||||
    // Release emu threads from any breakpoints
 | 
			
		||||
    Pica::g_debug_context->ClearBreakpoints();
 | 
			
		||||
 | 
			
		||||
    // Shutdown the core emulation
 | 
			
		||||
    System::Shutdown();
 | 
			
		||||
 | 
			
		||||
    // Update the GUI
 | 
			
		||||
    ui.action_Start->setEnabled(true);
 | 
			
		||||
    ui.action_Pause->setEnabled(false);
 | 
			
		||||
    ui.action_Stop->setEnabled(false);
 | 
			
		||||
 | 
			
		||||
    render_window->hide();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GMainWindow::OnMenuLoadFile()
 | 
			
		||||
{
 | 
			
		||||
    QString filename = QFileDialog::getOpenFileName(this, tr("Load File"), QString(), tr("3DS executable (*.3ds *.3dsx *.elf *.axf *.bin *.cci *.cxi)"));
 | 
			
		||||
    if (filename.size())
 | 
			
		||||
       BootGame(filename.toLatin1().data());
 | 
			
		||||
    if (filename.size()) {
 | 
			
		||||
        // Shutdown previous session if the emu thread is still active...
 | 
			
		||||
        if (emu_thread != nullptr)
 | 
			
		||||
            ShutdownGame();
 | 
			
		||||
 | 
			
		||||
        BootGame(filename.toLatin1().data());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GMainWindow::OnMenuLoadSymbolMap() {
 | 
			
		||||
@ -255,7 +258,7 @@ void GMainWindow::OnMenuLoadSymbolMap() {
 | 
			
		||||
 | 
			
		||||
void GMainWindow::OnStartGame()
 | 
			
		||||
{
 | 
			
		||||
    emu_thread->SetCpuRunning(true);
 | 
			
		||||
    emu_thread->SetRunning(true);
 | 
			
		||||
 | 
			
		||||
    ui.action_Start->setEnabled(false);
 | 
			
		||||
    ui.action_Pause->setEnabled(true);
 | 
			
		||||
@ -264,7 +267,7 @@ void GMainWindow::OnStartGame()
 | 
			
		||||
 | 
			
		||||
void GMainWindow::OnPauseGame()
 | 
			
		||||
{
 | 
			
		||||
    emu_thread->SetCpuRunning(false);
 | 
			
		||||
    emu_thread->SetRunning(false);
 | 
			
		||||
 | 
			
		||||
    ui.action_Start->setEnabled(true);
 | 
			
		||||
    ui.action_Pause->setEnabled(false);
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user