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:
bunnei 2020-12-28 18:23:42 -08:00
parent c7a06908ae
commit 7d77a3f88f
7 changed files with 41 additions and 40 deletions

View file

@ -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);

View file

@ -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;

View file

@ -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:

View file

@ -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,
[this]() {
const auto guard = LockService();
system_event.writable->Signal();
},
instance_number); 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");

View file

@ -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);
}); });

View file

@ -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};

View file

@ -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;
}; };
/** /**