mirror of
https://github.com/Lime3DS/Lime3DS.git
synced 2026-06-01 20:45:00 -06:00
core: Refactor thread unschedule and add debug frontend unschedule (#2145)
This commit is contained in:
parent
ab6896a2ca
commit
b186b04995
@ -879,6 +879,8 @@ void GMainWindow::InitializeHotkeys() {
|
||||
link_action_shortcut(ui->action_Debug_Pause, QStringLiteral("Debug Pause"));
|
||||
link_action_shortcut(ui->action_Debug_Resume, QStringLiteral("Debug Resume"));
|
||||
link_action_shortcut(ui->action_Debug_Step, QStringLiteral("Debug Step"), false, true);
|
||||
link_action_shortcut(ui->action_Debug_Unschedule_All, QStringLiteral("Debug Unschedule All"));
|
||||
link_action_shortcut(ui->action_Debug_Schedule_All, QStringLiteral("Debug Schedule All"));
|
||||
link_action_shortcut(ui->action_Screen_Layout_Swap_Screens, QStringLiteral("Swap Screens"));
|
||||
link_action_shortcut(ui->action_Screen_Layout_Upright_Screens,
|
||||
QStringLiteral("Rotate Screens Upright"));
|
||||
@ -1209,6 +1211,10 @@ void GMainWindow::ConnectMenuEvents() {
|
||||
emu_thread->ExecStep();
|
||||
}
|
||||
});
|
||||
connect_menu(ui->action_Debug_Unschedule_All,
|
||||
[this] { system.DebugUnscheduleAllThreadsFromFrontend(true); });
|
||||
connect_menu(ui->action_Debug_Schedule_All,
|
||||
[this] { system.DebugUnscheduleAllThreadsFromFrontend(false); });
|
||||
|
||||
// Tools
|
||||
connect_menu(ui->action_Compress_ROM_File, &GMainWindow::OnCompressFile);
|
||||
|
||||
@ -57,15 +57,17 @@ const std::array<std::array<int, 5>, Settings::NativeAnalog::NumAnalogs> QtConfi
|
||||
// This must be in alphabetical order according to action name as it must have the same order as
|
||||
// UISetting::values.shortcuts, which is alphabetically ordered.
|
||||
// clang-format off
|
||||
const std::array<UISettings::Shortcut, 41> QtConfig::default_hotkeys {{
|
||||
const std::array<UISettings::Shortcut, 43> QtConfig::default_hotkeys {{
|
||||
{QStringLiteral("Advance Frame"), QStringLiteral("Main Window"), {QStringLiteral(""), Qt::ApplicationShortcut}},
|
||||
{QStringLiteral("Audio Mute/Unmute"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+M"), Qt::WindowShortcut}},
|
||||
{QStringLiteral("Audio Volume Down"), QStringLiteral("Main Window"), {QStringLiteral(""), Qt::WindowShortcut}},
|
||||
{QStringLiteral("Audio Volume Up"), QStringLiteral("Main Window"), {QStringLiteral(""), Qt::WindowShortcut}},
|
||||
{QStringLiteral("Capture Screenshot"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+P"), Qt::WidgetWithChildrenShortcut}},
|
||||
{QStringLiteral("Debug Pause"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+F4"),Qt::WidgetWithChildrenShortcut}},
|
||||
{QStringLiteral("Debug Resume"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+F5"),Qt::WidgetWithChildrenShortcut}},
|
||||
{QStringLiteral("Debug Step"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+F6"),Qt::WidgetWithChildrenShortcut}},
|
||||
{QStringLiteral("Debug Pause"), QStringLiteral("Main Window"), {QStringLiteral(""), Qt::WidgetWithChildrenShortcut}},
|
||||
{QStringLiteral("Debug Resume"), QStringLiteral("Main Window"), {QStringLiteral(""), Qt::WidgetWithChildrenShortcut}},
|
||||
{QStringLiteral("Debug Step"), QStringLiteral("Main Window"), {QStringLiteral(""), Qt::WidgetWithChildrenShortcut}},
|
||||
{QStringLiteral("Debug Unschedule All"), QStringLiteral("Main Window"), {QStringLiteral(""), Qt::WidgetWithChildrenShortcut}},
|
||||
{QStringLiteral("Debug Schedule All"), QStringLiteral("Main Window"), {QStringLiteral(""), Qt::WidgetWithChildrenShortcut}},
|
||||
{QStringLiteral("Continue/Pause Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F4"), Qt::WindowShortcut}},
|
||||
{QStringLiteral("Decrease 3D Factor"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+-"), Qt::ApplicationShortcut}},
|
||||
{QStringLiteral("Decrease Speed Limit"), QStringLiteral("Main Window"), {QStringLiteral("-"), Qt::ApplicationShortcut}},
|
||||
|
||||
@ -26,7 +26,7 @@ public:
|
||||
|
||||
static const std::array<int, Settings::NativeButton::NumButtons> default_buttons;
|
||||
static const std::array<std::array<int, 5>, Settings::NativeAnalog::NumAnalogs> default_analogs;
|
||||
static const std::array<UISettings::Shortcut, 41> default_hotkeys;
|
||||
static const std::array<UISettings::Shortcut, 43> default_hotkeys;
|
||||
|
||||
private:
|
||||
void Initialize(const std::string& config_name);
|
||||
|
||||
@ -213,6 +213,9 @@
|
||||
<addaction name="action_Debug_Pause"/>
|
||||
<addaction name="action_Debug_Resume"/>
|
||||
<addaction name="action_Debug_Step"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="action_Debug_Unschedule_All"/>
|
||||
<addaction name="action_Debug_Schedule_All"/>
|
||||
</widget>
|
||||
<addaction name="menu_Debug"/>
|
||||
<addaction name="separator"/>
|
||||
@ -487,6 +490,22 @@
|
||||
<string>Debug Step</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_Debug_Unschedule_All">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Debug Unschedule All</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_Debug_Schedule_All">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Debug Schedule All</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_Dump_Video">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
|
||||
@ -833,6 +833,19 @@ bool System::IsInitialSetup() {
|
||||
return app_loader && app_loader->DoingInitialSetup();
|
||||
}
|
||||
|
||||
void System::DebugUnscheduleAllThreadsFromFrontend(bool unschedule) {
|
||||
if (!is_powered_on)
|
||||
return;
|
||||
|
||||
for (auto proc : kernel->GetProcessList()) {
|
||||
if (unschedule) {
|
||||
proc->SetUnscheduleMode(Kernel::UnscheduleMode::FRONTEND);
|
||||
} else {
|
||||
proc->ClearUnscheduleMode(Kernel::UnscheduleMode::FRONTEND);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
void System::serialize(Archive& ar, const unsigned int file_version) {
|
||||
|
||||
|
||||
@ -419,6 +419,8 @@ public:
|
||||
debug_next_process = false;
|
||||
}
|
||||
|
||||
void DebugUnscheduleAllThreadsFromFrontend(bool unschedule);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Initialize the emulated system.
|
||||
|
||||
@ -877,7 +877,7 @@ static void HandleGetStopReason() {
|
||||
for (const auto& process : process_list) {
|
||||
if (process->codeset->program_id == program_id) {
|
||||
current_process = process.get();
|
||||
current_process->SetDebugBreak(true);
|
||||
current_process->SetUnscheduleMode(Kernel::UnscheduleMode::GDB);
|
||||
is_running = false;
|
||||
if (SetThread(0)) {
|
||||
SendStopReply(current_thread, 0);
|
||||
@ -900,7 +900,7 @@ static void BreakImpl(int signal) {
|
||||
"and memory exceptions. Disable CPU JIT for more accuracy.");
|
||||
}
|
||||
|
||||
current_process->SetDebugBreak(true);
|
||||
current_process->SetUnscheduleMode(Kernel::UnscheduleMode::GDB);
|
||||
is_running = false;
|
||||
|
||||
latest_signal = signal;
|
||||
@ -1248,7 +1248,7 @@ static void Continue() {
|
||||
continue_list.push_back(thread_id);
|
||||
}
|
||||
|
||||
current_process->SetDebugBreak(false, continue_list);
|
||||
current_process->ClearUnscheduleMode(Kernel::UnscheduleMode::GDB, continue_list);
|
||||
is_running = true;
|
||||
|
||||
ClearAllInstructionCache();
|
||||
@ -1414,7 +1414,7 @@ void HandleVCommand() {
|
||||
SendReply("E02");
|
||||
} else {
|
||||
current_process = process.get();
|
||||
current_process->SetDebugBreak(true);
|
||||
current_process->SetUnscheduleMode(Kernel::UnscheduleMode::GDB);
|
||||
is_running = false;
|
||||
if (SetThread(0)) {
|
||||
SendStopReply(current_thread, 0);
|
||||
@ -1456,7 +1456,7 @@ void HandleVCommand() {
|
||||
HexToInt(reinterpret_cast<const u8*>(threads[i].c_str()), threads[i].size()));
|
||||
}
|
||||
|
||||
current_process->SetDebugBreak(false, thread_ids);
|
||||
current_process->ClearUnscheduleMode(Kernel::UnscheduleMode::GDB, thread_ids);
|
||||
is_running = true;
|
||||
}
|
||||
} else {
|
||||
|
||||
@ -270,7 +270,7 @@ void Process::Run(s32 main_thread_priority, u32 stack_size) {
|
||||
#ifdef ENABLE_GDBSTUB
|
||||
if (GDBStub::IsServerEnabled()) {
|
||||
LOG_INFO(Loader, "Pausing process {} at start", process_id);
|
||||
SetDebugBreak(true);
|
||||
SetUnscheduleMode(Kernel::UnscheduleMode::GDB);
|
||||
}
|
||||
#endif
|
||||
Core::System::GetInstance().ClearDebugNextProcessFlag();
|
||||
@ -624,7 +624,8 @@ std::vector<std::shared_ptr<Kernel::Thread>> Kernel::Process::GetThreadList() {
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Kernel::Process::SetDebugBreak(bool debug_break, std::vector<u32> thread_ids) {
|
||||
void Kernel::Process::ChangeUnscheduleMode(UnscheduleMode mode, std::vector<u32> thread_ids,
|
||||
bool set) {
|
||||
auto thread_list = GetThreadList();
|
||||
bool needs_reschedule = false;
|
||||
for (auto& t : thread_list) {
|
||||
@ -636,7 +637,7 @@ void Kernel::Process::SetDebugBreak(bool debug_break, std::vector<u32> thread_id
|
||||
}
|
||||
}
|
||||
|
||||
needs_reschedule |= t->SetDebugBreak(debug_break);
|
||||
needs_reschedule |= (set ? t->SetUnscheduleMode(mode) : t->ClearUnscheduleMode(mode));
|
||||
}
|
||||
|
||||
if (needs_reschedule) {
|
||||
|
||||
@ -13,6 +13,7 @@
|
||||
#include <boost/container/static_vector.hpp>
|
||||
#include <boost/serialization/export.hpp>
|
||||
#include "common/bit_field.h"
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/kernel/handle_table.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
@ -51,6 +52,13 @@ union ProcessFlags {
|
||||
BitField<12, 1, u16> loaded_high; ///< Application loaded high (not at 0x00100000).
|
||||
};
|
||||
|
||||
enum class UnscheduleMode : u32 {
|
||||
SVC = (1 << 0),
|
||||
GDB = (1 << 1),
|
||||
FRONTEND = (1 << 2),
|
||||
};
|
||||
DECLARE_ENUM_FLAG_OPERATORS(UnscheduleMode);
|
||||
|
||||
enum class ProcessStatus { Created, Running, Exited };
|
||||
|
||||
class ResourceLimit;
|
||||
@ -228,9 +236,15 @@ public:
|
||||
|
||||
std::vector<std::shared_ptr<Kernel::Thread>> GetThreadList();
|
||||
|
||||
void SetDebugBreak(bool debug_break, std::vector<u32> thread_ids = {});
|
||||
void SetUnscheduleMode(UnscheduleMode mode, std::vector<u32> thread_ids = {}) {
|
||||
ChangeUnscheduleMode(mode, thread_ids, true);
|
||||
}
|
||||
void ClearUnscheduleMode(UnscheduleMode mode, std::vector<u32> thread_ids = {}) {
|
||||
ChangeUnscheduleMode(mode, thread_ids, false);
|
||||
}
|
||||
|
||||
private:
|
||||
void ChangeUnscheduleMode(UnscheduleMode mode, std::vector<u32> thread_ids, bool set);
|
||||
void FreeAllMemory();
|
||||
|
||||
KernelSystem& kernel;
|
||||
|
||||
@ -2191,7 +2191,11 @@ Result SVC::ControlProcess(Handle process_handle, u32 process_OP, u32 varg2, u32
|
||||
kernel.GetCurrentThreadManager().GetCurrentThread()->thread_id) {
|
||||
continue;
|
||||
}
|
||||
thread.get()->can_schedule = !varg2;
|
||||
if (varg2) {
|
||||
thread->SetUnscheduleMode(Kernel::UnscheduleMode::SVC);
|
||||
} else {
|
||||
thread->ClearUnscheduleMode(Kernel::UnscheduleMode::SVC);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ResultSuccess;
|
||||
|
||||
@ -80,7 +80,7 @@ void Thread::serialize(Archive& ar, const unsigned int file_version) {
|
||||
}
|
||||
}
|
||||
ar & wakeup_callback;
|
||||
ar & debug_break;
|
||||
ar & unschedule_mode;
|
||||
}
|
||||
SERIALIZE_IMPL(Thread)
|
||||
|
||||
@ -545,12 +545,20 @@ VAddr Thread::GetCommandBufferAddress() const {
|
||||
return GetTLSAddress() + command_header_offset;
|
||||
}
|
||||
|
||||
bool Thread::SetDebugBreak(bool _debug_break) {
|
||||
if (debug_break == _debug_break) {
|
||||
return false;
|
||||
}
|
||||
debug_break = _debug_break;
|
||||
return true;
|
||||
bool Thread::SetUnscheduleMode(UnscheduleMode mode) {
|
||||
UnscheduleMode old = unschedule_mode;
|
||||
|
||||
unschedule_mode |= mode;
|
||||
|
||||
return unschedule_mode != old;
|
||||
}
|
||||
|
||||
bool Thread::ClearUnscheduleMode(UnscheduleMode mode) {
|
||||
UnscheduleMode old = unschedule_mode;
|
||||
|
||||
unschedule_mode &= ~mode;
|
||||
|
||||
return unschedule_mode != old;
|
||||
}
|
||||
|
||||
CpuLimiter::~CpuLimiter() {}
|
||||
|
||||
@ -21,6 +21,7 @@
|
||||
#include "core/arm/arm_interface.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
#include "core/hle/kernel/resource_limit.h"
|
||||
#include "core/hle/kernel/wait_object.h"
|
||||
#include "core/hle/result.h"
|
||||
@ -28,7 +29,6 @@
|
||||
namespace Kernel {
|
||||
|
||||
class Mutex;
|
||||
class Process;
|
||||
|
||||
enum ThreadPriority : u32 {
|
||||
ThreadPrioHighest = 0, ///< Highest thread priority
|
||||
@ -366,19 +366,16 @@ public:
|
||||
}
|
||||
|
||||
bool CanSchedule() {
|
||||
// TODO(PabloMK7): This may not be the proper way
|
||||
// threads are marked as non-schedulable when they
|
||||
// are in debug break. Figure out and fix.
|
||||
return can_schedule && !debug_break;
|
||||
return static_cast<u32>(unschedule_mode) == 0;
|
||||
}
|
||||
|
||||
bool SetDebugBreak(bool debug_break);
|
||||
bool SetUnscheduleMode(UnscheduleMode mode);
|
||||
bool ClearUnscheduleMode(UnscheduleMode mode);
|
||||
|
||||
Core::ARM_Interface::ThreadContext context{};
|
||||
|
||||
u32 thread_id;
|
||||
|
||||
bool can_schedule{true};
|
||||
ThreadStatus status;
|
||||
VAddr entry_point;
|
||||
VAddr stack_top;
|
||||
@ -419,7 +416,10 @@ public:
|
||||
|
||||
private:
|
||||
ThreadManager& thread_manager;
|
||||
bool debug_break{};
|
||||
|
||||
// Does not represent how real HW works, instead it mimics behaviour
|
||||
// taking into account how our scheduler works.
|
||||
UnscheduleMode unschedule_mode{};
|
||||
|
||||
friend class boost::serialization::access;
|
||||
template <class Archive>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user