// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include "common/assert.h" #include "common/native_clock.h" #include "common/singleton.h" #include "debug_state.h" #include "libraries/kernel/event_queues.h" #include "libraries/kernel/time_management.h" #include "libraries/system/msgdialog.h" using namespace DebugStateType; DebugStateImpl& DebugState = *Common::Singleton::Instance(); static ThreadID ThisThreadID() { #ifdef _WIN32 return GetCurrentThreadId(); #else return pthread_self(); #endif } static void PauseThread(ThreadID id) { #ifdef _WIN32 auto handle = OpenThread(THREAD_SUSPEND_RESUME, FALSE, id); SuspendThread(handle); CloseHandle(handle); #else pthread_kill(id, SIGUSR1); #endif } static void ResumeThread(ThreadID id) { #ifdef _WIN32 auto handle = OpenThread(THREAD_SUSPEND_RESUME, FALSE, id); ResumeThread(handle); CloseHandle(handle); #else pthread_kill(id, SIGUSR1); #endif } void DebugStateImpl::AddCurrentThreadToGuestList() { std::lock_guard lock{guest_threads_mutex}; const ThreadID id = ThisThreadID(); guest_threads.push_back(id); } void DebugStateImpl::RemoveCurrentThreadFromGuestList() { std::lock_guard lock{guest_threads_mutex}; const ThreadID id = ThisThreadID(); std::erase_if(guest_threads, [&](const ThreadID& v) { return v == id; }); } void DebugStateImpl::PauseGuestThreads() { using namespace Libraries::MsgDialog; std::unique_lock lock{guest_threads_mutex}; if (is_guest_threads_paused) { return; } if (ShouldPauseInSubmit()) { waiting_submit_pause = false; should_show_frame_dump = true; } bool self_guest = false; ThreadID self_id = ThisThreadID(); for (const auto& id : guest_threads) { if (id == self_id) { self_guest = true; } else { PauseThread(id); } } pause_time = Libraries::Kernel::Dev::GetClock()->GetUptime(); is_guest_threads_paused = true; lock.unlock(); if (self_guest) { PauseThread(self_id); } } void DebugStateImpl::ResumeGuestThreads() { std::lock_guard lock{guest_threads_mutex}; if (!is_guest_threads_paused) { return; } u64 delta_time = Libraries::Kernel::Dev::GetClock()->GetUptime() - pause_time; Libraries::Kernel::Dev::GetInitialPtc() += delta_time; for (const auto& id : guest_threads) { ResumeThread(id); } is_guest_threads_paused = false; } void DebugStateImpl::RequestFrameDump(s32 count) { gnm_frame_dump_request_count = count; frame_dump_list.clear(); frame_dump_list.resize(count); waiting_submit_pause = true; }