forked from suyu/suyu
hle: service: Acquire and release a lock on requests.
- This makes it such that we can safely access service members from CoreTiming thread.
This commit is contained in:
parent
c7a06908ae
commit
7d77a3f88f
7 changed files with 41 additions and 40 deletions
|
@ -11,7 +11,6 @@
|
||||||
#include "audio_core/info_updater.h"
|
#include "audio_core/info_updater.h"
|
||||||
#include "audio_core/voice_context.h"
|
#include "audio_core/voice_context.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "core/hle/kernel/writable_event.h"
|
|
||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
#include "core/settings.h"
|
#include "core/settings.h"
|
||||||
|
|
||||||
|
@ -71,10 +70,9 @@ namespace {
|
||||||
namespace AudioCore {
|
namespace AudioCore {
|
||||||
AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory::Memory& memory_,
|
AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory::Memory& memory_,
|
||||||
AudioCommon::AudioRendererParameter params,
|
AudioCommon::AudioRendererParameter params,
|
||||||
std::shared_ptr<Kernel::WritableEvent> buffer_event_,
|
Stream::ReleaseCallback&& release_callback,
|
||||||
std::size_t instance_number)
|
std::size_t instance_number)
|
||||||
: worker_params{params}, buffer_event{buffer_event_},
|
: worker_params{params}, memory_pool_info(params.effect_count + params.voice_count * 4),
|
||||||
memory_pool_info(params.effect_count + params.voice_count * 4),
|
|
||||||
voice_context(params.voice_count), effect_context(params.effect_count), mix_context(),
|
voice_context(params.voice_count), effect_context(params.effect_count), mix_context(),
|
||||||
sink_context(params.sink_count), splitter_context(),
|
sink_context(params.sink_count), splitter_context(),
|
||||||
voices(params.voice_count), memory{memory_},
|
voices(params.voice_count), memory{memory_},
|
||||||
|
@ -85,10 +83,9 @@ AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory
|
||||||
params.num_splitter_send_channels);
|
params.num_splitter_send_channels);
|
||||||
mix_context.Initialize(behavior_info, params.submix_count + 1, params.effect_count);
|
mix_context.Initialize(behavior_info, params.submix_count + 1, params.effect_count);
|
||||||
audio_out = std::make_unique<AudioCore::AudioOut>();
|
audio_out = std::make_unique<AudioCore::AudioOut>();
|
||||||
stream =
|
stream = audio_out->OpenStream(
|
||||||
audio_out->OpenStream(core_timing, params.sample_rate, AudioCommon::STREAM_NUM_CHANNELS,
|
core_timing, params.sample_rate, AudioCommon::STREAM_NUM_CHANNELS,
|
||||||
fmt::format("AudioRenderer-Instance{}", instance_number),
|
fmt::format("AudioRenderer-Instance{}", instance_number), std::move(release_callback));
|
||||||
[=]() { buffer_event_->Signal(); });
|
|
||||||
audio_out->StartStream(stream);
|
audio_out->StartStream(stream);
|
||||||
|
|
||||||
QueueMixedBuffer(0);
|
QueueMixedBuffer(0);
|
||||||
|
|
|
@ -27,10 +27,6 @@ namespace Core::Timing {
|
||||||
class CoreTiming;
|
class CoreTiming;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Kernel {
|
|
||||||
class WritableEvent;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace Core::Memory {
|
namespace Core::Memory {
|
||||||
class Memory;
|
class Memory;
|
||||||
}
|
}
|
||||||
|
@ -44,8 +40,7 @@ class AudioRenderer {
|
||||||
public:
|
public:
|
||||||
AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory::Memory& memory_,
|
AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory::Memory& memory_,
|
||||||
AudioCommon::AudioRendererParameter params,
|
AudioCommon::AudioRendererParameter params,
|
||||||
std::shared_ptr<Kernel::WritableEvent> buffer_event_,
|
Stream::ReleaseCallback&& release_callback, std::size_t instance_number);
|
||||||
std::size_t instance_number);
|
|
||||||
~AudioRenderer();
|
~AudioRenderer();
|
||||||
|
|
||||||
[[nodiscard]] ResultCode UpdateAudioRenderer(const std::vector<u8>& input_params,
|
[[nodiscard]] ResultCode UpdateAudioRenderer(const std::vector<u8>& input_params,
|
||||||
|
@ -61,7 +56,6 @@ private:
|
||||||
BehaviorInfo behavior_info{};
|
BehaviorInfo behavior_info{};
|
||||||
|
|
||||||
AudioCommon::AudioRendererParameter worker_params;
|
AudioCommon::AudioRendererParameter worker_params;
|
||||||
std::shared_ptr<Kernel::WritableEvent> buffer_event;
|
|
||||||
std::vector<ServerMemoryPoolInfo> memory_pool_info;
|
std::vector<ServerMemoryPoolInfo> memory_pool_info;
|
||||||
VoiceContext voice_context;
|
VoiceContext voice_context;
|
||||||
EffectContext effect_context;
|
EffectContext effect_context;
|
||||||
|
|
|
@ -70,8 +70,10 @@ public:
|
||||||
Kernel::WritableEvent::CreateEventPair(system.Kernel(), "IAudioOutBufferReleased");
|
Kernel::WritableEvent::CreateEventPair(system.Kernel(), "IAudioOutBufferReleased");
|
||||||
|
|
||||||
stream = audio_core.OpenStream(system.CoreTiming(), audio_params.sample_rate,
|
stream = audio_core.OpenStream(system.CoreTiming(), audio_params.sample_rate,
|
||||||
audio_params.channel_count, std::move(unique_name),
|
audio_params.channel_count, std::move(unique_name), [this] {
|
||||||
[this] { buffer_event.writable->Signal(); });
|
const auto guard = LockService();
|
||||||
|
buffer_event.writable->Signal();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -49,16 +49,16 @@ public:
|
||||||
|
|
||||||
system_event =
|
system_event =
|
||||||
Kernel::WritableEvent::CreateEventPair(system.Kernel(), "IAudioRenderer:SystemEvent");
|
Kernel::WritableEvent::CreateEventPair(system.Kernel(), "IAudioRenderer:SystemEvent");
|
||||||
renderer = std::make_unique<AudioCore::AudioRenderer>(system.CoreTiming(), system.Memory(),
|
renderer = std::make_unique<AudioCore::AudioRenderer>(
|
||||||
audren_params, system_event.writable,
|
system.CoreTiming(), system.Memory(), audren_params,
|
||||||
instance_number);
|
[this]() {
|
||||||
|
const auto guard = LockService();
|
||||||
|
system_event.writable->Signal();
|
||||||
|
},
|
||||||
|
instance_number);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void UpdateAudioCallback() {
|
|
||||||
system_event.writable->Signal();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GetSampleRate(Kernel::HLERequestContext& ctx) {
|
void GetSampleRate(Kernel::HLERequestContext& ctx) {
|
||||||
LOG_DEBUG(Service_Audio, "called");
|
LOG_DEBUG(Service_Audio, "called");
|
||||||
|
|
||||||
|
|
|
@ -78,11 +78,13 @@ IAppletResource::IAppletResource(Core::System& system_)
|
||||||
pad_update_event = Core::Timing::CreateEvent(
|
pad_update_event = Core::Timing::CreateEvent(
|
||||||
"HID::UpdatePadCallback",
|
"HID::UpdatePadCallback",
|
||||||
[this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
|
[this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
|
||||||
|
const auto guard = LockService();
|
||||||
UpdateControllers(user_data, ns_late);
|
UpdateControllers(user_data, ns_late);
|
||||||
});
|
});
|
||||||
motion_update_event = Core::Timing::CreateEvent(
|
motion_update_event = Core::Timing::CreateEvent(
|
||||||
"HID::MotionPadCallback",
|
"HID::MotionPadCallback",
|
||||||
[this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
|
[this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
|
||||||
|
const auto guard = LockService();
|
||||||
UpdateMotion(user_data, ns_late);
|
UpdateMotion(user_data, ns_late);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -95,9 +95,14 @@ ServiceFrameworkBase::ServiceFrameworkBase(Core::System& system_, const char* se
|
||||||
: system{system_}, service_name{service_name_}, max_sessions{max_sessions_},
|
: system{system_}, service_name{service_name_}, max_sessions{max_sessions_},
|
||||||
handler_invoker{handler_invoker_} {}
|
handler_invoker{handler_invoker_} {}
|
||||||
|
|
||||||
ServiceFrameworkBase::~ServiceFrameworkBase() = default;
|
ServiceFrameworkBase::~ServiceFrameworkBase() {
|
||||||
|
// Wait for other threads to release access before destroying
|
||||||
|
const auto guard = LockService();
|
||||||
|
}
|
||||||
|
|
||||||
void ServiceFrameworkBase::InstallAsService(SM::ServiceManager& service_manager) {
|
void ServiceFrameworkBase::InstallAsService(SM::ServiceManager& service_manager) {
|
||||||
|
const auto guard = LockService();
|
||||||
|
|
||||||
ASSERT(!port_installed);
|
ASSERT(!port_installed);
|
||||||
|
|
||||||
auto port = service_manager.RegisterService(service_name, max_sessions).Unwrap();
|
auto port = service_manager.RegisterService(service_name, max_sessions).Unwrap();
|
||||||
|
@ -106,6 +111,8 @@ void ServiceFrameworkBase::InstallAsService(SM::ServiceManager& service_manager)
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServiceFrameworkBase::InstallAsNamedPort(Kernel::KernelCore& kernel) {
|
void ServiceFrameworkBase::InstallAsNamedPort(Kernel::KernelCore& kernel) {
|
||||||
|
const auto guard = LockService();
|
||||||
|
|
||||||
ASSERT(!port_installed);
|
ASSERT(!port_installed);
|
||||||
|
|
||||||
auto [server_port, client_port] =
|
auto [server_port, client_port] =
|
||||||
|
@ -115,17 +122,6 @@ void ServiceFrameworkBase::InstallAsNamedPort(Kernel::KernelCore& kernel) {
|
||||||
port_installed = true;
|
port_installed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Kernel::ClientPort> ServiceFrameworkBase::CreatePort(Kernel::KernelCore& kernel) {
|
|
||||||
ASSERT(!port_installed);
|
|
||||||
|
|
||||||
auto [server_port, client_port] =
|
|
||||||
Kernel::ServerPort::CreatePortPair(kernel, max_sessions, service_name);
|
|
||||||
auto port = MakeResult(std::move(server_port)).Unwrap();
|
|
||||||
port->SetHleHandler(shared_from_this());
|
|
||||||
port_installed = true;
|
|
||||||
return client_port;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServiceFrameworkBase::RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n) {
|
void ServiceFrameworkBase::RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n) {
|
||||||
handlers.reserve(handlers.size() + n);
|
handlers.reserve(handlers.size() + n);
|
||||||
for (std::size_t i = 0; i < n; ++i) {
|
for (std::size_t i = 0; i < n; ++i) {
|
||||||
|
@ -164,6 +160,8 @@ void ServiceFrameworkBase::InvokeRequest(Kernel::HLERequestContext& ctx) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& context) {
|
ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& context) {
|
||||||
|
const auto guard = LockService();
|
||||||
|
|
||||||
switch (context.GetCommandType()) {
|
switch (context.GetCommandType()) {
|
||||||
case IPC::CommandType::Close: {
|
case IPC::CommandType::Close: {
|
||||||
IPC::ResponseBuilder rb{context, 2};
|
IPC::ResponseBuilder rb{context, 2};
|
||||||
|
|
|
@ -5,9 +5,11 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
#include <mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <boost/container/flat_map.hpp>
|
#include <boost/container/flat_map.hpp>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
#include "common/spin_lock.h"
|
||||||
#include "core/hle/kernel/hle_ipc.h"
|
#include "core/hle/kernel/hle_ipc.h"
|
||||||
#include "core/hle/kernel/object.h"
|
#include "core/hle/kernel/object.h"
|
||||||
|
|
||||||
|
@ -68,11 +70,9 @@ public:
|
||||||
void InstallAsService(SM::ServiceManager& service_manager);
|
void InstallAsService(SM::ServiceManager& service_manager);
|
||||||
/// Creates a port pair and registers it on the kernel's global port registry.
|
/// Creates a port pair and registers it on the kernel's global port registry.
|
||||||
void InstallAsNamedPort(Kernel::KernelCore& kernel);
|
void InstallAsNamedPort(Kernel::KernelCore& kernel);
|
||||||
/// Creates and returns an unregistered port for the service.
|
/// Invokes a service request routine.
|
||||||
std::shared_ptr<Kernel::ClientPort> CreatePort(Kernel::KernelCore& kernel);
|
|
||||||
|
|
||||||
void InvokeRequest(Kernel::HLERequestContext& ctx);
|
void InvokeRequest(Kernel::HLERequestContext& ctx);
|
||||||
|
/// Handles a synchronization request for the service.
|
||||||
ResultCode HandleSyncRequest(Kernel::HLERequestContext& context) override;
|
ResultCode HandleSyncRequest(Kernel::HLERequestContext& context) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -80,6 +80,11 @@ protected:
|
||||||
template <typename Self>
|
template <typename Self>
|
||||||
using HandlerFnP = void (Self::*)(Kernel::HLERequestContext&);
|
using HandlerFnP = void (Self::*)(Kernel::HLERequestContext&);
|
||||||
|
|
||||||
|
/// Used to gain exclusive access to the service members, e.g. from CoreTiming thread.
|
||||||
|
[[nodiscard]] std::scoped_lock<Common::SpinLock> LockService() {
|
||||||
|
return std::scoped_lock{lock_service};
|
||||||
|
}
|
||||||
|
|
||||||
/// System context that the service operates under.
|
/// System context that the service operates under.
|
||||||
Core::System& system;
|
Core::System& system;
|
||||||
|
|
||||||
|
@ -115,6 +120,9 @@ private:
|
||||||
/// Function used to safely up-cast pointers to the derived class before invoking a handler.
|
/// Function used to safely up-cast pointers to the derived class before invoking a handler.
|
||||||
InvokerFn* handler_invoker;
|
InvokerFn* handler_invoker;
|
||||||
boost::container::flat_map<u32, FunctionInfoBase> handlers;
|
boost::container::flat_map<u32, FunctionInfoBase> handlers;
|
||||||
|
|
||||||
|
/// Used to gain exclusive access to the service members, e.g. from CoreTiming thread.
|
||||||
|
Common::SpinLock lock_service;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in a new issue