core: De-globalize HLE lock (#7212)

This commit is contained in:
GPUCode 2023-11-29 00:15:27 +02:00 committed by GitHub
parent 83b329f6e1
commit 6ec079ede8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 66 additions and 92 deletions

View file

@ -37,8 +37,9 @@ void DspInterface::EnableStretching(bool enable) {
}
void DspInterface::OutputFrame(StereoFrame16 frame) {
if (!sink)
if (!sink) {
return;
}
fifo.Push(frame.data(), frame.size());
@ -49,8 +50,9 @@ void DspInterface::OutputFrame(StereoFrame16 frame) {
}
void DspInterface::OutputSample(std::array<s16, 2> sample) {
if (!sink)
if (!sink) {
return;
}
fifo.Push(&sample, 1);

View file

@ -13,7 +13,6 @@
#include "common/thread.h"
#include "core/core.h"
#include "core/core_timing.h"
#include "core/hle/lock.h"
#include "core/hle/service/dsp/dsp_dsp.h"
namespace AudioCore {
@ -411,17 +410,15 @@ std::array<u8, Memory::DSP_RAM_SIZE>& DspLle::GetDspMemory() {
void DspLle::SetInterruptHandler(
std::function<void(Service::DSP::InterruptType type, DspPipe pipe)> handler) {
impl->teakra.SetRecvDataHandler(0, [this, handler]() {
if (!impl->loaded)
if (!impl->loaded) {
return;
std::lock_guard lock(HLE::g_hle_lock);
}
handler(Service::DSP::InterruptType::Zero, static_cast<DspPipe>(0));
});
impl->teakra.SetRecvDataHandler(1, [this, handler]() {
if (!impl->loaded)
if (!impl->loaded) {
return;
std::lock_guard lock(HLE::g_hle_lock);
}
handler(Service::DSP::InterruptType::One, static_cast<DspPipe>(0));
});
@ -450,7 +447,6 @@ void DspLle::SetInterruptHandler(
impl->ReadPipe(static_cast<u8>(pipe),
impl->GetPipeReadableSize(static_cast<u8>(pipe)));
} else {
std::lock_guard lock(HLE::g_hle_lock);
handler(Service::DSP::InterruptType::Pipe, static_cast<DspPipe>(pipe));
}
}

View file

@ -2118,6 +2118,7 @@ void GMainWindow::OnLoadAmiibo() {
return;
}
std::scoped_lock lock{system.Kernel().GetHLELock()};
if (nfc->IsTagActive()) {
QMessageBox::warning(this, tr("Error opening amiibo data file"),
tr("A tag is already in use."));
@ -2148,6 +2149,7 @@ void GMainWindow::LoadAmiibo(const QString& filename) {
return;
}
std::scoped_lock lock{system.Kernel().GetHLELock()};
if (!nfc->LoadAmiibo(filename.toStdString())) {
QMessageBox::warning(this, tr("Error opening amiibo data file"),
tr("Unable to open amiibo file \"%1\" for reading.").arg(filename));
@ -2164,6 +2166,7 @@ void GMainWindow::OnRemoveAmiibo() {
return;
}
std::scoped_lock lock{system.Kernel().GetHLELock()};
nfc->RemoveAmiibo();
ui->action_Remove_Amiibo->setEnabled(false);
}

View file

@ -182,8 +182,6 @@ add_library(citra_core STATIC
hle/kernel/vm_manager.h
hle/kernel/wait_object.cpp
hle/kernel/wait_object.h
hle/lock.cpp
hle/lock.h
hle/mii.h
hle/mii.cpp
hle/result.h

View file

@ -104,7 +104,7 @@ System::ResultStatus System::RunLoop(bool tight_loop) {
Signal signal{Signal::None};
u32 param{};
{
std::lock_guard lock{signal_mutex};
std::scoped_lock lock{signal_mutex};
if (current_signal != Signal::None) {
signal = current_signal;
param = signal_param;
@ -242,7 +242,7 @@ System::ResultStatus System::RunLoop(bool tight_loop) {
}
bool System::SendSignal(System::Signal signal, u32 param) {
std::lock_guard lock{signal_mutex};
std::scoped_lock lock{signal_mutex};
if (current_signal != signal && current_signal != Signal::None) {
LOG_ERROR(Core, "Unable to {} as {} is ongoing", signal, current_signal);
return false;

View file

@ -64,7 +64,7 @@ void FFmpegStream::WritePacket(AVPacket* packet) {
FFmpeg::av_packet_rescale_ts(packet, codec_context->time_base, stream->time_base);
packet->stream_index = stream->index;
{
std::lock_guard lock{*format_context_mutex};
std::scoped_lock lock{*format_context_mutex};
FFmpeg::av_interleaved_write_frame(format_context, packet);
}
}
@ -727,7 +727,7 @@ void FFmpegMuxer::FlushAudio() {
}
void FFmpegMuxer::WriteTrailer() {
std::lock_guard lock{format_context_mutex};
std::scoped_lock lock{format_context_mutex};
FFmpeg::av_interleaved_write_frame(format_context.get(), nullptr);
FFmpeg::av_write_trailer(format_context.get());
}

View file

@ -35,7 +35,7 @@ private:
explicit Device(std::weak_ptr<TouchState>&& touch_state) : touch_state(touch_state) {}
std::tuple<float, float, bool> GetStatus() const override {
if (auto state = touch_state.lock()) {
std::lock_guard guard{state->mutex};
std::scoped_lock guard{state->mutex};
return std::make_tuple(state->touch_x, state->touch_y, state->touch_pressed);
}
return std::make_tuple(0.0f, 0.0f, false);
@ -132,7 +132,7 @@ bool EmuWindow::TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y) {
framebuffer_x -=
(framebuffer_layout.width / 2) - (framebuffer_layout.cardboard.user_x_shift * 2);
}
std::lock_guard guard(touch_state->mutex);
std::scoped_lock guard(touch_state->mutex);
if (Settings::values.render_3d.GetValue() == Settings::StereoRenderOption::SideBySide) {
touch_state->touch_x =
static_cast<float>(framebuffer_x - framebuffer_layout.bottom_screen.left / 2) /
@ -157,7 +157,7 @@ bool EmuWindow::TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y) {
}
void EmuWindow::TouchReleased() {
std::lock_guard guard{touch_state->mutex};
std::scoped_lock guard{touch_state->mutex};
touch_state->touch_pressed = false;
touch_state->touch_x = 0;
touch_state->touch_y = 0;

View file

@ -8,6 +8,7 @@
#include <atomic>
#include <functional>
#include <memory>
#include <mutex>
#include <span>
#include <string>
#include <unordered_map>
@ -322,6 +323,10 @@ public:
return n3ds_hw_caps;
}
std::recursive_mutex& GetHLELock() {
return hle_lock;
}
/// Map of named ports managed by the kernel, which can be retrieved using the ConnectToPort
std::unordered_map<std::string, std::shared_ptr<ClientPort>> named_ports;
@ -370,6 +375,15 @@ private:
MemoryMode memory_mode;
New3dsHwCapabilities n3ds_hw_caps;
/*
* Synchronizes access to the internal HLE kernel structures, it is acquired when a guest
* application thread performs a syscall. It should be acquired by any host threads that read or
* modify the HLE kernel state. Note: Any operation that directly or indirectly reads from or
* writes to the emulated memory is not protected by this mutex, and should be avoided in any
* threads other than the CPU thread.
*/
std::recursive_mutex hle_lock;
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive& ar, const unsigned int file_version);

View file

@ -36,7 +36,6 @@
#include "core/hle/kernel/timer.h"
#include "core/hle/kernel/vm_manager.h"
#include "core/hle/kernel/wait_object.h"
#include "core/hle/lock.h"
#include "core/hle/result.h"
#include "core/hle/service/plgldr/plgldr.h"
@ -2300,8 +2299,8 @@ MICROPROFILE_DEFINE(Kernel_SVC, "Kernel", "SVC", MP_RGB(70, 200, 70));
void SVC::CallSVC(u32 immediate) {
MICROPROFILE_SCOPE(Kernel_SVC);
// Lock the global kernel mutex when we enter the kernel HLE.
std::lock_guard lock{HLE::g_hle_lock};
// Lock the kernel mutex when we enter the kernel HLE.
std::scoped_lock lock{kernel.GetHLELock()};
DEBUG_ASSERT_MSG(kernel.GetCurrentProcess()->status == ProcessStatus::Running,
"Running threads from exiting processes is unimplemented");

View file

@ -1,9 +0,0 @@
// Copyright 2017 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "core/hle/lock.h"
namespace HLE {
std::recursive_mutex g_hle_lock;
} // namespace HLE

View file

@ -1,18 +0,0 @@
// Copyright 2017 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <mutex>
namespace HLE {
/*
* Synchronizes access to the internal HLE kernel structures, it is acquired when a guest
* application thread performs a syscall. It should be acquired by any host threads that read or
* modify the HLE kernel state. Note: Any operation that directly or indirectly reads from or writes
* to the emulated memory is not protected by this mutex, and should be avoided in any threads other
* than the CPU thread.
*/
extern std::recursive_mutex g_hle_lock;
} // namespace HLE

View file

@ -395,7 +395,8 @@ DSP_DSP::DSP_DSP(Core::System& system)
semaphore_event->SetHLENotifier(
[this]() { this->system.DSP().SetSemaphore(preset_semaphore); });
system.DSP().SetInterruptHandler([dsp_ref = this](InterruptType type, DspPipe pipe) {
system.DSP().SetInterruptHandler([dsp_ref = this, &system](InterruptType type, DspPipe pipe) {
std::scoped_lock lock{system.Kernel().GetHLELock()};
if (dsp_ref) {
dsp_ref->SignalInterrupt(type, pipe);
}

View file

@ -5,8 +5,6 @@
#include "common/archives.h"
#include "core/core.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/event.h"
#include "core/hle/lock.h"
#include "core/hle/service/nfc/nfc.h"
#include "core/hle/service/nfc/nfc_m.h"
#include "core/hle/service/nfc/nfc_u.h"
@ -680,26 +678,21 @@ std::shared_ptr<Module> Module::Interface::GetModule() const {
}
bool Module::Interface::IsSearchingForAmiibos() {
std::lock_guard lock(HLE::g_hle_lock);
const auto state = nfc->device->GetCurrentState();
return state == DeviceState::SearchingForTag;
}
bool Module::Interface::IsTagActive() {
std::lock_guard lock(HLE::g_hle_lock);
const auto state = nfc->device->GetCurrentState();
return state == DeviceState::TagFound || state == DeviceState::TagMounted ||
state == DeviceState::TagPartiallyMounted;
}
bool Module::Interface::LoadAmiibo(const std::string& fullpath) {
std::lock_guard lock(HLE::g_hle_lock);
return nfc->device->LoadAmiibo(fullpath);
}
void Module::Interface::RemoveAmiibo() {
std::lock_guard lock(HLE::g_hle_lock);
nfc->device->UnloadAmiibo();
}

View file

@ -4,12 +4,10 @@
#pragma once
#include <atomic>
#include <memory>
#include <boost/serialization/binary_object.hpp>
#include "common/common_types.h"
#include "core/hle/service/nfc/nfc_device.h"
#include "core/hle/service/nfc/nfc_types.h"
#include "core/hle/service/service.h"
namespace Core {

View file

@ -16,7 +16,6 @@
#include "core/hle/kernel/event.h"
#include "core/hle/kernel/shared_memory.h"
#include "core/hle/kernel/shared_page.h"
#include "core/hle/lock.h"
#include "core/hle/result.h"
#include "core/hle/service/nwm/nwm_uds.h"
#include "core/hle/service/nwm/uds_beacon.h"
@ -56,7 +55,7 @@ constexpr u16 BroadcastNetworkNodeId = 0xFFFF;
constexpr u16 HostDestNodeId = 1;
std::list<Network::WifiPacket> NWM_UDS::GetReceivedBeacons(const MacAddress& sender) {
std::lock_guard lock(beacon_mutex);
std::scoped_lock lock(beacon_mutex);
if (sender != Network::BroadcastMac) {
std::list<Network::WifiPacket> filtered_list;
const auto beacon = std::find_if(received_beacons.begin(), received_beacons.end(),
@ -123,7 +122,7 @@ void NWM_UDS::BroadcastNodeMap() {
}
void NWM_UDS::HandleNodeMapPacket(const Network::WifiPacket& packet) {
std::lock_guard lock(connection_status_mutex);
std::scoped_lock lock(connection_status_mutex);
if (connection_status.status == NetworkStatus::ConnectedAsHost) {
LOG_DEBUG(Service_NWM, "Ignored NodeMapPacket since connection_status is host");
return;
@ -145,7 +144,7 @@ void NWM_UDS::HandleNodeMapPacket(const Network::WifiPacket& packet) {
}
void NWM_UDS::HandleBeaconFrame(const Network::WifiPacket& packet) {
std::lock_guard lock(beacon_mutex);
std::scoped_lock lock(beacon_mutex);
const auto unique_beacon =
std::find_if(received_beacons.begin(), received_beacons.end(),
[&packet](const Network::WifiPacket& new_packet) {
@ -169,7 +168,7 @@ void NWM_UDS::HandleAssociationResponseFrame(const Network::WifiPacket& packet)
ASSERT_MSG(std::get<AssocStatus>(assoc_result) == AssocStatus::Successful,
"Could not join network");
{
std::lock_guard lock(connection_status_mutex);
std::scoped_lock lock(connection_status_mutex);
if (connection_status.status != NetworkStatus::Connecting) {
LOG_DEBUG(Service_NWM,
"Ignored AssociationResponseFrame because connection status is {}",
@ -191,9 +190,7 @@ void NWM_UDS::HandleAssociationResponseFrame(const Network::WifiPacket& packet)
}
void NWM_UDS::HandleEAPoLPacket(const Network::WifiPacket& packet) {
std::unique_lock hle_lock(HLE::g_hle_lock, std::defer_lock);
std::unique_lock lock(connection_status_mutex, std::defer_lock);
std::lock(hle_lock, lock);
std::scoped_lock lock{connection_status_mutex, system.Kernel().GetHLELock()};
if (GetEAPoLFrameType(packet.data) == EAPoLStartMagic) {
if (connection_status.status != NetworkStatus::ConnectedAsHost) {
@ -323,10 +320,8 @@ void NWM_UDS::HandleEAPoLPacket(const Network::WifiPacket& packet) {
}
void NWM_UDS::HandleSecureDataPacket(const Network::WifiPacket& packet) {
auto secure_data = ParseSecureDataHeader(packet.data);
std::unique_lock hle_lock(HLE::g_hle_lock, std::defer_lock);
std::unique_lock lock(connection_status_mutex, std::defer_lock);
std::lock(hle_lock, lock);
const auto secure_data = ParseSecureDataHeader(packet.data);
std::scoped_lock lock{connection_status_mutex, system.Kernel().GetHLELock()};
if (connection_status.status != NetworkStatus::ConnectedAsHost &&
connection_status.status != NetworkStatus::ConnectedAsClient) {
@ -381,7 +376,7 @@ void NWM_UDS::HandleSecureDataPacket(const Network::WifiPacket& packet) {
// Add the received packet to the data queue.
channel_info->second.received_packets.emplace_back(packet.data);
// Signal the data event. We can do this directly because we locked g_hle_lock
// Signal the data event. We can do this directly because we locked hle_lock
channel_info->second.event->Signal();
}
@ -389,7 +384,7 @@ void NWM_UDS::StartConnectionSequence(const MacAddress& server) {
using Network::WifiPacket;
WifiPacket auth_request;
{
std::lock_guard lock(connection_status_mutex);
std::scoped_lock lock(connection_status_mutex);
connection_status.status = NetworkStatus::Connecting;
// TODO(Subv): Handle timeout.
@ -409,7 +404,7 @@ void NWM_UDS::SendAssociationResponseFrame(const MacAddress& address) {
WifiPacket assoc_response;
{
std::lock_guard lock(connection_status_mutex);
std::scoped_lock lock(connection_status_mutex);
if (connection_status.status != NetworkStatus::ConnectedAsHost) {
LOG_ERROR(Service_NWM, "Connection sequence aborted, because connection status is {}",
static_cast<u32>(connection_status.status));
@ -435,7 +430,7 @@ void NWM_UDS::HandleAuthenticationFrame(const Network::WifiPacket& packet) {
using Network::WifiPacket;
WifiPacket auth_request;
{
std::lock_guard lock(connection_status_mutex);
std::scoped_lock lock(connection_status_mutex);
if (connection_status.status != NetworkStatus::ConnectedAsHost) {
LOG_ERROR(Service_NWM,
"Connection sequence aborted, because connection status is {}",
@ -469,9 +464,8 @@ void NWM_UDS::HandleAuthenticationFrame(const Network::WifiPacket& packet) {
void NWM_UDS::HandleDeauthenticationFrame(const Network::WifiPacket& packet) {
LOG_DEBUG(Service_NWM, "called");
std::unique_lock hle_lock(HLE::g_hle_lock, std::defer_lock);
std::unique_lock lock(connection_status_mutex, std::defer_lock);
std::lock(hle_lock, lock);
std::scoped_lock lock{connection_status_mutex, system.Kernel().GetHLELock()};
if (connection_status.status != NetworkStatus::ConnectedAsHost) {
LOG_ERROR(Service_NWM, "Got deauthentication frame but we are not the host");
return;
@ -662,7 +656,7 @@ ResultVal<std::shared_ptr<Kernel::Event>> NWM_UDS::Initialize(
ASSERT_MSG(recv_buffer_memory->GetSize() == sharedmem_size, "Invalid shared memory size.");
{
std::lock_guard lock(connection_status_mutex);
std::scoped_lock lock(connection_status_mutex);
// Reset the connection status, it contains all zeros after initialization,
// except for the actual status value.
@ -715,7 +709,7 @@ void NWM_UDS::GetConnectionStatus(Kernel::HLERequestContext& ctx) {
rb.Push(RESULT_SUCCESS);
{
std::lock_guard lock(connection_status_mutex);
std::scoped_lock lock(connection_status_mutex);
rb.PushRaw(connection_status);
// Reset the bitmask of changed nodes after each call to this
@ -740,7 +734,7 @@ void NWM_UDS::GetNodeInformation(Kernel::HLERequestContext& ctx) {
}
{
std::lock_guard lock(connection_status_mutex);
std::scoped_lock lock(connection_status_mutex);
auto itr = std::find_if(node_info.begin(), node_info.end(),
[network_node_id](const NodeInfo& node) {
return node.network_node_id == network_node_id;
@ -799,7 +793,7 @@ void NWM_UDS::Bind(Kernel::HLERequestContext& ctx) {
// Create a new event for this bind node.
auto event = system.Kernel().CreateEvent(Kernel::ResetType::OneShot,
"NWM::BindNodeEvent" + std::to_string(bind_node_id));
std::lock_guard lock(connection_status_mutex);
std::scoped_lock lock(connection_status_mutex);
ASSERT(channel_data.find(data_channel) == channel_data.end());
// TODO(B3N30): Support more than one bind node per channel.
@ -821,7 +815,7 @@ void NWM_UDS::Unbind(Kernel::HLERequestContext& ctx) {
return;
}
std::lock_guard lock(connection_status_mutex);
std::scoped_lock lock(connection_status_mutex);
auto itr =
std::find_if(channel_data.begin(), channel_data.end(), [bind_node_id](const auto& data) {
@ -848,7 +842,7 @@ ResultCode NWM_UDS::BeginHostingNetwork(std::span<const u8> network_info_buffer,
// TODO(Subv): Store the passphrase and verify it when attempting a connection.
{
std::lock_guard lock(connection_status_mutex);
std::scoped_lock lock(connection_status_mutex);
network_info = {};
std::memcpy(&network_info, network_info_buffer.data(), network_info_buffer.size());
@ -961,7 +955,7 @@ void NWM_UDS::EjectClient(Kernel::HLERequestContext& ctx) {
return;
}
std::lock_guard lock(connection_status_mutex);
std::scoped_lock lock(connection_status_mutex);
if (connection_status.status != NetworkStatus::ConnectedAsHost) {
// Only the host can kick people.
rb.Push(ResultCode(ErrorDescription::NotAuthorized, ErrorModule::UDS,
@ -1012,7 +1006,7 @@ void NWM_UDS::DestroyNetwork(Kernel::HLERequestContext& ctx) {
system.CoreTiming().UnscheduleEvent(beacon_broadcast_event, 0);
// Only a host can destroy
std::lock_guard lock(connection_status_mutex);
std::scoped_lock lock(connection_status_mutex);
if (connection_status.status != NetworkStatus::ConnectedAsHost) {
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(ResultCode(ErrCodes::WrongStatus, ErrorModule::UDS, ErrorSummary::InvalidState,
@ -1050,7 +1044,7 @@ void NWM_UDS::DisconnectNetwork(Kernel::HLERequestContext& ctx) {
using Network::WifiPacket;
WifiPacket deauth;
{
std::lock_guard lock(connection_status_mutex);
std::scoped_lock lock(connection_status_mutex);
if (connection_status.status == NetworkStatus::ConnectedAsHost) {
// A real 3ds makes strange things here. We do the same
u16_le tmp_node_id = connection_status.network_node_id;
@ -1104,7 +1098,7 @@ void NWM_UDS::SendTo(Kernel::HLERequestContext& ctx) {
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
std::lock_guard lock(connection_status_mutex);
std::scoped_lock lock(connection_status_mutex);
if (connection_status.status != NetworkStatus::ConnectedAsClient &&
connection_status.status != NetworkStatus::ConnectedAsHost) {
rb.Push(ResultCode(ErrorDescription::NotAuthorized, ErrorModule::UDS,
@ -1176,7 +1170,7 @@ void NWM_UDS::PullPacket(Kernel::HLERequestContext& ctx) {
// This size is hard coded into the uds module. We don't know the meaning yet.
u32 buff_size = std::min<u32>(max_out_buff_size_aligned, 0x172) << 2;
std::lock_guard lock(connection_status_mutex);
std::scoped_lock lock(connection_status_mutex);
if (connection_status.status != NetworkStatus::ConnectedAsHost &&
connection_status.status != NetworkStatus::ConnectedAsClient &&
connection_status.status != NetworkStatus::ConnectedAsSpectator) {
@ -1239,7 +1233,7 @@ void NWM_UDS::GetChannel(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx);
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
std::lock_guard lock(connection_status_mutex);
std::scoped_lock lock(connection_status_mutex);
bool is_connected = connection_status.status != NetworkStatus::NotConnected;
u8 channel = is_connected ? network_channel : 0;

View file

@ -20,7 +20,6 @@
#include "core/hle/kernel/semaphore.h"
#include "core/hle/kernel/server_port.h"
#include "core/hle/kernel/server_session.h"
#include "core/hle/lock.h"
#include "core/hle/service/sm/sm.h"
#include "core/hle/service/sm/srv.h"

View file

@ -21,6 +21,9 @@ TEST_CASE("DSP LLE vs HLE", "[audio_core][hle]") {
Memory::MemorySystem lle_memory{system};
Core::Timing lle_core_timing(1, 100);
Kernel::KernelSystem lle_kernel(
lle_memory, lle_core_timing, [] {}, Kernel::MemoryMode::Prod, 1,
Kernel::New3dsHwCapabilities{false, false, Kernel::New3dsMemoryMode::Legacy});
AudioCore::DspHle hle(system, hle_memory, hle_core_timing);
AudioCore::DspLle lle(system, lle_memory, lle_core_timing, true);

View file

@ -11,6 +11,7 @@
#include "common/file_util.h"
#include "core/core.h"
#include "core/core_timing.h"
#include "core/hle/kernel/kernel.h"
#include "core/memory.h"
TEST_CASE("DSP LLE Sanity", "[audio_core][lle]") {