mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-09-21 09:55:14 +00:00
@@ -272,6 +272,7 @@ void OpusDecoder::Main(std::stop_token stop_token) {
|
||||
void OpusDecoder::NotifyShutdown() {
|
||||
init_thread.request_stop();
|
||||
main_thread.request_stop();
|
||||
Send(Direction::DSP, Message::Shutdown);
|
||||
}
|
||||
|
||||
} // namespace AudioCore::ADSP::OpusDecoder
|
||||
|
||||
@@ -1242,8 +1242,7 @@ namespace Kernel {
|
||||
if (m_termination_requested.compare_exchange_strong(expected, true)) {
|
||||
// If the thread is in initialized state, just change state to terminated.
|
||||
if (this->GetState() == ThreadState::Initialized) {
|
||||
m_thread_state = ThreadState::Terminated;
|
||||
return ThreadState::Terminated;
|
||||
return m_thread_state = ThreadState::Terminated;
|
||||
}
|
||||
|
||||
// Register the terminating dpc.
|
||||
@@ -1277,7 +1276,6 @@ namespace Kernel {
|
||||
m_wait_queue->CancelWait(kernel, this, ResultTerminationRequested, true);
|
||||
}
|
||||
}
|
||||
|
||||
return this->GetState();
|
||||
}
|
||||
|
||||
|
||||
@@ -80,7 +80,10 @@ struct KernelCore::Impl {
|
||||
// so it will be statically given a TLS slot anyways.
|
||||
static inline thread_local ThreadLocalData tls_data = {};
|
||||
|
||||
explicit Impl(Core::System& system_, KernelCore& kernel_) : system{system_} {
|
||||
explicit Impl(Core::System& system_, KernelCore& kernel_)
|
||||
: worker_task_manager{kernel_}
|
||||
, system{system_}
|
||||
{
|
||||
tls_data.lock = true;
|
||||
}
|
||||
|
||||
@@ -1257,7 +1260,6 @@ void KernelCore::ShutdownCores() {
|
||||
for (auto& sm : impl->server_managers) {
|
||||
sm->NotifyShutdown();
|
||||
}
|
||||
|
||||
impl->TerminateAllProcesses();
|
||||
KScopedSchedulerLock lk{*this};
|
||||
for (auto* thread : impl->shutdown_threads)
|
||||
|
||||
@@ -26,24 +26,25 @@ EventObserver::EventObserver(Core::System& system, WindowSystem& window_system)
|
||||
m_window_system.SetEventObserver(this);
|
||||
m_wakeup_holder.SetUserData(static_cast<uintptr_t>(UserDataTag::WakeupEvent));
|
||||
m_wakeup_holder.LinkToMultiWait(std::addressof(m_multi_wait));
|
||||
m_thread = std::jthread([this](std::stop_token stop_token) {
|
||||
Common::SetCurrentThreadName("am:EventObserver");
|
||||
system.Kernel().RunOnGuestCoreProcess("am:EventObserver", [this]() {
|
||||
auto const stop_token = m_stop_source.get_token();
|
||||
while (!stop_token.stop_requested()) {
|
||||
auto* signaled_holder = this->WaitSignaled(stop_token);
|
||||
if (!signaled_holder)
|
||||
if (stop_token.stop_requested() || !signaled_holder)
|
||||
break;
|
||||
this->Process(signaled_holder);
|
||||
}
|
||||
m_process_cv.notify_one();
|
||||
});
|
||||
}
|
||||
|
||||
EventObserver::~EventObserver() {
|
||||
// Signal thread and wait for processing to finish.
|
||||
if (m_thread.joinable()) {
|
||||
// Signal thread and wait for processing to finish.
|
||||
m_thread.request_stop();
|
||||
m_wakeup_event.Signal(m_system.Kernel());
|
||||
m_thread.join();
|
||||
m_stop_source.request_stop();
|
||||
m_wakeup_event.Signal(m_system.Kernel());
|
||||
{
|
||||
std::unique_lock lk{m_process_mutex};
|
||||
m_process_cv.wait(lk);
|
||||
}
|
||||
|
||||
// Free remaining owned sessions.
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <condition_variable>
|
||||
#include <stop_token>
|
||||
#include "common/polyfill_thread.h"
|
||||
#include "common/thread.h"
|
||||
#include "core/hle/service/kernel_helpers.h"
|
||||
@@ -62,7 +64,9 @@ private:
|
||||
MultiWait m_deferred_wait_list;
|
||||
|
||||
// Processing thread.
|
||||
std::jthread m_thread{};
|
||||
std::stop_source m_stop_source{};
|
||||
std::mutex m_process_mutex;
|
||||
std::condition_variable m_process_cv{};
|
||||
};
|
||||
|
||||
} // namespace Service::AM
|
||||
|
||||
@@ -49,14 +49,15 @@ TimeWorker::TimeWorker(Core::System& system, StandardSteadyClockResource& steady
|
||||
}
|
||||
|
||||
TimeWorker::~TimeWorker() {
|
||||
// Wait for processing to stop
|
||||
m_stop_source.request_stop();
|
||||
m_local_clock_event->Signal(m_system.Kernel());
|
||||
m_network_clock_event->Signal(m_system.Kernel());
|
||||
m_ephemeral_clock_event->Signal(m_system.Kernel());
|
||||
|
||||
if (m_thread.joinable()) {
|
||||
m_thread.request_stop();
|
||||
m_event->Signal(m_system.Kernel());
|
||||
m_thread.join();
|
||||
m_event->Signal(m_system.Kernel());
|
||||
{
|
||||
std::unique_lock lk{m_process_mutex};
|
||||
m_process_cv.wait(lk);
|
||||
}
|
||||
|
||||
m_ctx.CloseEvent(m_event);
|
||||
@@ -125,9 +126,8 @@ void TimeWorker::Initialize(std::shared_ptr<Service::PSC::Time::StaticService> t
|
||||
}
|
||||
|
||||
void TimeWorker::StartThread() {
|
||||
m_thread = m_system.Kernel().RunOnHostCoreThread("TimeWorker", [this]() {
|
||||
auto const stop_token = m_thread.get_stop_token();
|
||||
Common::SetCurrentThreadPriority(Common::ThreadPriority::Low);
|
||||
m_system.Kernel().RunOnGuestCoreProcess("TimeWorker", [this]() {
|
||||
auto const stop_token = m_stop_source.get_token();
|
||||
while (!stop_token.stop_requested()) {
|
||||
enum class EventType : s32 {
|
||||
Exit = 0,
|
||||
@@ -140,9 +140,7 @@ void TimeWorker::StartThread() {
|
||||
UpdateFileTimestamp = 7,
|
||||
AutoCorrect = 8,
|
||||
};
|
||||
|
||||
s32 index{};
|
||||
|
||||
if (m_pm_state_change_handler.m_priority != 0) {
|
||||
// TODO: gIPmModuleService::GetEvent() 1
|
||||
index = WaitAny(
|
||||
@@ -282,6 +280,7 @@ void TimeWorker::StartThread() {
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
m_process_cv.notify_one();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <condition_variable>
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/service/glue/time/alarm_worker.h"
|
||||
@@ -39,13 +40,14 @@ public:
|
||||
template <typename T>
|
||||
T GetSettingsItemValue(const std::string& category, const std::string& name);
|
||||
|
||||
void ThreadFunc(std::stop_token stop_token);
|
||||
|
||||
Core::System& m_system;
|
||||
KernelHelpers::ServiceContext m_ctx;
|
||||
std::shared_ptr<Service::Set::ISystemSettingsServer> m_set_sys;
|
||||
|
||||
std::jthread m_thread;
|
||||
std::mutex m_process_mutex;
|
||||
std::condition_variable m_process_cv;
|
||||
std::stop_source m_stop_source;
|
||||
|
||||
Kernel::KEvent* m_event{};
|
||||
std::shared_ptr<Service::PSC::Time::ServiceManager> m_time_m;
|
||||
std::shared_ptr<Service::PSC::Time::StaticService> m_time_sm;
|
||||
|
||||
@@ -94,9 +94,6 @@ Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system
|
||||
{"ldn", &LDN::LoopProcess},
|
||||
{"nvservices", &Nvidia::LoopProcess},
|
||||
{"bsdsocket", &Sockets::LoopProcess},
|
||||
// TODO: glue is only required here as otherwise the dummythread doesn't close
|
||||
// TODO: rework sched so this isn't needed
|
||||
{"glue", &Glue::LoopProcess},
|
||||
})
|
||||
kernel.RunOnHostCoreProcess(std::string(e.first), [&system, f = e.second] { f(system); }).detach();
|
||||
kernel.RunOnHostCoreProcess("vi", [&, token] { VI::LoopProcess(system, token); }).detach();
|
||||
@@ -155,6 +152,7 @@ Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system
|
||||
{"usb", &USB::LoopProcess},
|
||||
{"i2c", &I2C::LoopProcess},
|
||||
{"gpio", &GPIO::LoopProcess},
|
||||
{"glue", &Glue::LoopProcess},
|
||||
})
|
||||
kernel.RunOnGuestCoreProcess(std::string(e.first), [&system, f = e.second] { f(system); });
|
||||
}
|
||||
|
||||
@@ -30,13 +30,10 @@ Conductor::Conductor(Core::System& system, Container& container, DisplayList& di
|
||||
});
|
||||
|
||||
if (system.IsMulticore()) {
|
||||
m_event = Core::Timing::CreateEvent(
|
||||
"ScreenComposition",
|
||||
[this](s64 time,
|
||||
std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
|
||||
m_signal.Set();
|
||||
return std::chrono::nanoseconds(this->GetNextTicks());
|
||||
});
|
||||
m_event = Core::Timing::CreateEvent("ScreenComposition", [this](s64 time, std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
|
||||
m_signal.Set();
|
||||
return std::chrono::nanoseconds(this->GetNextTicks());
|
||||
});
|
||||
|
||||
system.CoreTiming().ScheduleLoopingEvent(FrameNs, FrameNs, m_event);
|
||||
m_thread = system.Kernel().RunOnHostCoreThread("VSyncThread", [this]() {
|
||||
@@ -52,13 +49,10 @@ Conductor::Conductor(Core::System& system, Container& container, DisplayList& di
|
||||
}
|
||||
});
|
||||
} else {
|
||||
m_event = Core::Timing::CreateEvent(
|
||||
"ScreenComposition",
|
||||
[this](s64 time,
|
||||
std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
|
||||
this->ProcessVsync();
|
||||
return std::chrono::nanoseconds(this->GetNextTicks());
|
||||
});
|
||||
m_event = Core::Timing::CreateEvent("ScreenComposition", [this](s64 time, std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
|
||||
this->ProcessVsync();
|
||||
return std::chrono::nanoseconds(this->GetNextTicks());
|
||||
});
|
||||
|
||||
system.CoreTiming().ScheduleLoopingEvent(FrameNs, FrameNs, m_event);
|
||||
}
|
||||
|
||||
@@ -232,10 +232,7 @@ DmntCheatVm::Callbacks::~Callbacks() = default;
|
||||
bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode& out) {
|
||||
// If we've ever seen a decode failure, return false.
|
||||
bool valid = decode_success;
|
||||
CheatVmOpcode opcode = {
|
||||
.begin_conditional_block = false,
|
||||
.opcode = {}
|
||||
};
|
||||
CheatVmOpcode opcode = {};
|
||||
SCOPE_EXIT {
|
||||
decode_success &= valid;
|
||||
if (valid) {
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: 2014 Citra Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <regex>
|
||||
#include <string>
|
||||
|
||||
#include "common/logging.h"
|
||||
#include "common/settings.h"
|
||||
#include "core/core.h"
|
||||
#include "core/cpu_manager.h"
|
||||
#include "core/file_sys/registered_cache.h"
|
||||
#include "core/file_sys/vfs/vfs_real.h"
|
||||
#include "core/hle/service/am/applet_manager.h"
|
||||
#include "core/hle/service/filesystem/filesystem.h"
|
||||
#include "core/loader/loader.h"
|
||||
#include "frontend_common/config.h"
|
||||
#include "input_common/main.h"
|
||||
#include "video_core/gpu.h"
|
||||
#include "video_core/renderer_base.h"
|
||||
#include "yuzu_cmd/emu_window/emu_window_sdl3.h"
|
||||
#include "yuzu_cmd/emu_window/emu_window_sdl3_null.h"
|
||||
#include "yuzu_cmd/emu_window/emu_window_sdl3_vk.h"
|
||||
|
||||
class EmuWindow_Headless : public Core::Frontend::EmuWindow {
|
||||
public:
|
||||
explicit EmuWindow_Headless() = default;
|
||||
~EmuWindow_Headless() = default;
|
||||
|
||||
bool IsShown() const override {
|
||||
return true;
|
||||
}
|
||||
void OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal_size) override {
|
||||
|
||||
}
|
||||
std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override {
|
||||
return std::make_unique<DummyContext>();
|
||||
}
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
struct {
|
||||
Core::System system{};
|
||||
EmuWindow_Headless emu_window{};
|
||||
} state = {};
|
||||
|
||||
Common::Log::Initialize();
|
||||
Common::Log::SetColorConsoleBackendEnabled(true);
|
||||
Common::Log::Start();
|
||||
|
||||
if (argc < 2) {
|
||||
LOG_CRITICAL(Frontend, "Usage: {} [ms-to-run] [file]", argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
std::chrono::milliseconds time_quanta = std::chrono::milliseconds{atoi(argv[1])};
|
||||
auto const time_end = std::chrono::steady_clock::now() + time_quanta;
|
||||
std::string filepath = argv[2];
|
||||
|
||||
// apply the log_filter setting
|
||||
// the logger was initialized before and doesn't pick up the filter on its own
|
||||
Common::Log::Filter filter;
|
||||
filter.ParseFilterString("*:Info");
|
||||
Common::Log::SetGlobalFilter(filter);
|
||||
|
||||
if (filepath.empty()) {
|
||||
LOG_CRITICAL(Frontend, "Failed to load ROM: No ROM specified");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
state.system.Initialize();
|
||||
|
||||
InputCommon::InputSubsystem input_subsystem{};
|
||||
|
||||
// Apply the command line arguments
|
||||
state.system.ApplySettings();
|
||||
Settings::values.renderer_backend.SetValue(Settings::RendererBackend::Null);
|
||||
|
||||
state.system.SetContentProvider(std::make_unique<FileSys::ContentProviderUnion>());
|
||||
state.system.SetFilesystem(std::make_shared<FileSys::RealVfsFilesystem>());
|
||||
state.system.GetFileSystemController().CreateFactories(*state.system.GetFilesystem());
|
||||
state.system.GetUserChannel().clear();
|
||||
|
||||
Service::AM::FrontendAppletParameters load_parameters{
|
||||
.applet_id = Service::AM::AppletId::Application,
|
||||
};
|
||||
if (auto const load_result = state.system.Load(state.emu_window, filepath, load_parameters); load_result != Core::SystemResultStatus::Success) {
|
||||
LOG_CRITICAL(Frontend, "load result = {}", u32(load_result));
|
||||
// shutdown
|
||||
void(state.system.Pause());
|
||||
state.system.DetachDebugger();
|
||||
state.system.ShutdownMainProcess();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
// Core is loaded, start the GPU (makes the GPU contexts current to this thread)
|
||||
state.system.GPU().Start();
|
||||
state.system.GetCpuManager().OnGpuReady();
|
||||
// don't do anything, SDL3 already exists for us :D
|
||||
state.system.RegisterExitCallback([] {});
|
||||
void(state.system.Run());
|
||||
if (state.system.DebuggerEnabled())
|
||||
state.system.InitializeDebugger();
|
||||
while (state.system.IsPoweredOn() && !state.system.GetExitRequested()) {
|
||||
auto const time_now = std::chrono::steady_clock::now();
|
||||
if (time_now > time_end)
|
||||
break;
|
||||
}
|
||||
// shutdown
|
||||
void(state.system.Pause());
|
||||
state.system.DetachDebugger();
|
||||
state.system.ShutdownMainProcess();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#define VMA_IMPLEMENTATION
|
||||
#include "video_core/vulkan_common/vma.h"
|
||||
Reference in New Issue
Block a user