diff options
-rw-r--r-- | README.md | 2 | ||||
-rw-r--r-- | src/audio_core/renderer/adsp/audio_renderer.cpp | 8 | ||||
-rw-r--r-- | src/audio_core/renderer/adsp/audio_renderer.h | 4 | ||||
-rw-r--r-- | src/audio_core/sink/sink_stream.cpp | 5 | ||||
-rw-r--r-- | src/audio_core/sink/sink_stream.h | 5 | ||||
-rw-r--r-- | src/common/host_memory.cpp | 22 | ||||
-rw-r--r-- | src/core/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/core/file_sys/patch_manager.cpp | 5 | ||||
-rw-r--r-- | src/core/file_sys/romfs.cpp | 3 | ||||
-rw-r--r-- | src/core/file_sys/vfs_cached.cpp | 63 | ||||
-rw-r--r-- | src/core/file_sys/vfs_cached.h | 31 | ||||
-rw-r--r-- | src/core/file_sys/vfs_vector.cpp | 19 | ||||
-rw-r--r-- | src/core/file_sys/vfs_vector.h | 4 | ||||
-rw-r--r-- | src/core/hle/service/filesystem/fsp_srv.cpp | 20 |
14 files changed, 148 insertions, 45 deletions
@@ -13,7 +13,7 @@ SPDX-License-Identifier: GPL-2.0-or-later <h4 align="center"><b>yuzu</b> is the world's most popular, open-source, Nintendo Switch emulator — started by the creators of <a href="https://citra-emu.org" target="_blank">Citra</a>. <br> -It is written in C++ with portability in mind, and we actively maintain builds for Windows and Linux. +It is written in C++ with portability in mind, and we actively maintain builds for Windows, Linux and Android. </h4> <p align="center"> diff --git a/src/audio_core/renderer/adsp/audio_renderer.cpp b/src/audio_core/renderer/adsp/audio_renderer.cpp index 1cbeed302..8bc39f9f9 100644 --- a/src/audio_core/renderer/adsp/audio_renderer.cpp +++ b/src/audio_core/renderer/adsp/audio_renderer.cpp @@ -105,7 +105,7 @@ void AudioRenderer::Start(AudioRenderer_Mailbox* mailbox_) { } mailbox = mailbox_; - thread = std::thread(&AudioRenderer::ThreadFunc, this); + thread = std::jthread([this](std::stop_token stop_token) { ThreadFunc(stop_token); }); running = true; } @@ -131,7 +131,7 @@ void AudioRenderer::CreateSinkStreams() { } } -void AudioRenderer::ThreadFunc() { +void AudioRenderer::ThreadFunc(std::stop_token stop_token) { static constexpr char name[]{"AudioRenderer"}; MicroProfileOnThreadCreate(name); Common::SetCurrentThreadName(name); @@ -146,7 +146,7 @@ void AudioRenderer::ThreadFunc() { constexpr u64 max_process_time{2'304'000ULL}; - while (true) { + while (!stop_token.stop_requested()) { auto message{mailbox->ADSPWaitMessage()}; switch (message) { case RenderMessage::AudioRenderer_Shutdown: @@ -194,7 +194,7 @@ void AudioRenderer::ThreadFunc() { max_time = std::min(command_buffer.time_limit, max_time); command_list_processor.SetProcessTimeMax(max_time); - streams[index]->WaitFreeSpace(); + streams[index]->WaitFreeSpace(stop_token); // Process the command list { diff --git a/src/audio_core/renderer/adsp/audio_renderer.h b/src/audio_core/renderer/adsp/audio_renderer.h index 85ce6a269..88e558183 100644 --- a/src/audio_core/renderer/adsp/audio_renderer.h +++ b/src/audio_core/renderer/adsp/audio_renderer.h @@ -177,7 +177,7 @@ private: /** * Main AudioRenderer thread, responsible for processing the command lists. */ - void ThreadFunc(); + void ThreadFunc(std::stop_token stop_token); /** * Creates the streams which will receive the processed samples. @@ -187,7 +187,7 @@ private: /// Core system Core::System& system; /// Main thread - std::thread thread{}; + std::jthread thread{}; /// The current state std::atomic<bool> running{}; /// The active mailbox diff --git a/src/audio_core/sink/sink_stream.cpp b/src/audio_core/sink/sink_stream.cpp index b408fca89..5d58b950c 100644 --- a/src/audio_core/sink/sink_stream.cpp +++ b/src/audio_core/sink/sink_stream.cpp @@ -269,14 +269,15 @@ u64 SinkStream::GetExpectedPlayedSampleCount() { return std::min<u64>(exp_played_sample_count, max_played_sample_count) + TargetSampleCount * 3; } -void SinkStream::WaitFreeSpace() { +void SinkStream::WaitFreeSpace(std::stop_token stop_token) { std::unique_lock lk{release_mutex}; release_cv.wait_for(lk, std::chrono::milliseconds(5), [this]() { return queued_buffers < max_queue_size; }); #ifndef ANDROID // This wait can cause a problematic shutdown hang on Android. if (queued_buffers > max_queue_size + 3) { - release_cv.wait(lk, [this]() { return queued_buffers < max_queue_size; }); + Common::CondvarWait(release_cv, lk, stop_token, + [this] { return queued_buffers < max_queue_size; }); } #endif } diff --git a/src/audio_core/sink/sink_stream.h b/src/audio_core/sink/sink_stream.h index 21b5b40a1..41cbadc9c 100644 --- a/src/audio_core/sink/sink_stream.h +++ b/src/audio_core/sink/sink_stream.h @@ -13,6 +13,7 @@ #include "audio_core/common/common.h" #include "common/common_types.h" +#include "common/polyfill_thread.h" #include "common/reader_writer_queue.h" #include "common/ring_buffer.h" #include "common/thread.h" @@ -210,7 +211,7 @@ public: /** * Waits for free space in the sample ring buffer */ - void WaitFreeSpace(); + void WaitFreeSpace(std::stop_token stop_token); protected: /// Core system @@ -252,7 +253,7 @@ private: /// Set via IAudioDevice service calls f32 device_volume{1.0f}; /// Signalled when ring buffer entries are consumed - std::condition_variable release_cv; + std::condition_variable_any release_cv; std::mutex release_mutex; }; diff --git a/src/common/host_memory.cpp b/src/common/host_memory.cpp index 703ddb4a4..ba22595e0 100644 --- a/src/common/host_memory.cpp +++ b/src/common/host_memory.cpp @@ -18,6 +18,7 @@ #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif +#include <boost/icl/interval_set.hpp> #include <fcntl.h> #include <sys/mman.h> #include <unistd.h> @@ -423,6 +424,7 @@ public: madvise(virtual_base, virtual_size, MADV_HUGEPAGE); #endif + placeholders.add({0, virtual_size}); good = true; } @@ -431,6 +433,10 @@ public: } void Map(size_t virtual_offset, size_t host_offset, size_t length) { + { + std::scoped_lock lock{placeholder_mutex}; + placeholders.subtract({virtual_offset, virtual_offset + length}); + } void* ret = mmap(virtual_base + virtual_offset, length, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, fd, host_offset); @@ -441,6 +447,19 @@ public: // The method name is wrong. We're still talking about the virtual range. // We don't want to unmap, we want to reserve this memory. + { + std::scoped_lock lock{placeholder_mutex}; + auto it = placeholders.find({virtual_offset - 1, virtual_offset + length + 1}); + + if (it != placeholders.end()) { + size_t prev_upper = virtual_offset + length; + virtual_offset = std::min(virtual_offset, it->lower()); + length = std::max(it->upper(), prev_upper) - virtual_offset; + } + + placeholders.add({virtual_offset, virtual_offset + length}); + } + void* ret = mmap(virtual_base + virtual_offset, length, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0); ASSERT_MSG(ret != MAP_FAILED, "mmap failed: {}", strerror(errno)); @@ -484,6 +503,9 @@ private: } int fd{-1}; // memfd file descriptor, -1 is the error value of memfd_create + + boost::icl::interval_set<size_t> placeholders; ///< Mapped placeholders + std::mutex placeholder_mutex; ///< Mutex for placeholders }; #else // ^^^ Linux ^^^ vvv Generic vvv diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 157858c82..99602699a 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -106,6 +106,8 @@ add_library(core STATIC file_sys/system_archive/time_zone_binary.h file_sys/vfs.cpp file_sys/vfs.h + file_sys/vfs_cached.cpp + file_sys/vfs_cached.h file_sys/vfs_concat.cpp file_sys/vfs_concat.h file_sys/vfs_layered.cpp diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp index 4c80e13a9..f786f2add 100644 --- a/src/core/file_sys/patch_manager.cpp +++ b/src/core/file_sys/patch_manager.cpp @@ -21,6 +21,7 @@ #include "core/file_sys/patch_manager.h" #include "core/file_sys/registered_cache.h" #include "core/file_sys/romfs.h" +#include "core/file_sys/vfs_cached.h" #include "core/file_sys/vfs_layered.h" #include "core/file_sys/vfs_vector.h" #include "core/hle/service/filesystem/filesystem.h" @@ -380,11 +381,11 @@ static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType t auto romfs_dir = FindSubdirectoryCaseless(subdir, "romfs"); if (romfs_dir != nullptr) - layers.push_back(std::move(romfs_dir)); + layers.push_back(std::make_shared<CachedVfsDirectory>(romfs_dir)); auto ext_dir = FindSubdirectoryCaseless(subdir, "romfs_ext"); if (ext_dir != nullptr) - layers_ext.push_back(std::move(ext_dir)); + layers_ext.push_back(std::make_shared<CachedVfsDirectory>(ext_dir)); } // When there are no layers to apply, return early as there is no need to rebuild the RomFS diff --git a/src/core/file_sys/romfs.cpp b/src/core/file_sys/romfs.cpp index fb5683a6b..614da2130 100644 --- a/src/core/file_sys/romfs.cpp +++ b/src/core/file_sys/romfs.cpp @@ -9,6 +9,7 @@ #include "core/file_sys/fsmitm_romfsbuild.h" #include "core/file_sys/romfs.h" #include "core/file_sys/vfs.h" +#include "core/file_sys/vfs_cached.h" #include "core/file_sys/vfs_concat.h" #include "core/file_sys/vfs_offset.h" #include "core/file_sys/vfs_vector.h" @@ -132,7 +133,7 @@ VirtualDir ExtractRomFS(VirtualFile file, RomFSExtractionType type) { out = out->GetSubdirectories().front(); } - return out; + return std::make_shared<CachedVfsDirectory>(out); } VirtualFile CreateRomFS(VirtualDir dir, VirtualDir ext) { diff --git a/src/core/file_sys/vfs_cached.cpp b/src/core/file_sys/vfs_cached.cpp new file mode 100644 index 000000000..c3154ee81 --- /dev/null +++ b/src/core/file_sys/vfs_cached.cpp @@ -0,0 +1,63 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/file_sys/vfs_cached.h" +#include "core/file_sys/vfs_types.h" + +namespace FileSys { + +CachedVfsDirectory::CachedVfsDirectory(VirtualDir& source_dir) + : name(source_dir->GetName()), parent(source_dir->GetParentDirectory()) { + for (auto& dir : source_dir->GetSubdirectories()) { + dirs.emplace(dir->GetName(), std::make_shared<CachedVfsDirectory>(dir)); + } + for (auto& file : source_dir->GetFiles()) { + files.emplace(file->GetName(), file); + } +} + +CachedVfsDirectory::~CachedVfsDirectory() = default; + +VirtualFile CachedVfsDirectory::GetFile(std::string_view file_name) const { + auto it = files.find(file_name); + if (it != files.end()) { + return it->second; + } + + return nullptr; +} + +VirtualDir CachedVfsDirectory::GetSubdirectory(std::string_view dir_name) const { + auto it = dirs.find(dir_name); + if (it != dirs.end()) { + return it->second; + } + + return nullptr; +} + +std::vector<VirtualFile> CachedVfsDirectory::GetFiles() const { + std::vector<VirtualFile> out; + for (auto& [file_name, file] : files) { + out.push_back(file); + } + return out; +} + +std::vector<VirtualDir> CachedVfsDirectory::GetSubdirectories() const { + std::vector<VirtualDir> out; + for (auto& [dir_name, dir] : dirs) { + out.push_back(dir); + } + return out; +} + +std::string CachedVfsDirectory::GetName() const { + return name; +} + +VirtualDir CachedVfsDirectory::GetParentDirectory() const { + return parent; +} + +} // namespace FileSys diff --git a/src/core/file_sys/vfs_cached.h b/src/core/file_sys/vfs_cached.h new file mode 100644 index 000000000..113acac12 --- /dev/null +++ b/src/core/file_sys/vfs_cached.h @@ -0,0 +1,31 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <string_view> +#include <vector> +#include "core/file_sys/vfs.h" + +namespace FileSys { + +class CachedVfsDirectory : public ReadOnlyVfsDirectory { +public: + CachedVfsDirectory(VirtualDir& source_directory); + + ~CachedVfsDirectory() override; + VirtualFile GetFile(std::string_view file_name) const override; + VirtualDir GetSubdirectory(std::string_view dir_name) const override; + std::vector<VirtualFile> GetFiles() const override; + std::vector<VirtualDir> GetSubdirectories() const override; + std::string GetName() const override; + VirtualDir GetParentDirectory() const override; + +private: + std::string name; + VirtualDir parent; + std::map<std::string, VirtualDir, std::less<>> dirs; + std::map<std::string, VirtualFile, std::less<>> files; +}; + +} // namespace FileSys diff --git a/src/core/file_sys/vfs_vector.cpp b/src/core/file_sys/vfs_vector.cpp index af1df4c51..251d9d7c9 100644 --- a/src/core/file_sys/vfs_vector.cpp +++ b/src/core/file_sys/vfs_vector.cpp @@ -67,23 +67,6 @@ VectorVfsDirectory::VectorVfsDirectory(std::vector<VirtualFile> files_, VectorVfsDirectory::~VectorVfsDirectory() = default; -VirtualFile VectorVfsDirectory::GetFile(std::string_view file_name) const { - if (!optimized_file_index_built) { - optimized_file_index.clear(); - for (size_t i = 0; i < files.size(); i++) { - optimized_file_index.emplace(files[i]->GetName(), i); - } - optimized_file_index_built = true; - } - - const auto it = optimized_file_index.find(file_name); - if (it != optimized_file_index.end()) { - return files[it->second]; - } - - return nullptr; -} - std::vector<VirtualFile> VectorVfsDirectory::GetFiles() const { return files; } @@ -124,7 +107,6 @@ bool VectorVfsDirectory::DeleteSubdirectory(std::string_view subdir_name) { } bool VectorVfsDirectory::DeleteFile(std::string_view file_name) { - optimized_file_index_built = false; return FindAndRemoveVectorElement(files, file_name); } @@ -142,7 +124,6 @@ VirtualFile VectorVfsDirectory::CreateFile(std::string_view file_name) { } void VectorVfsDirectory::AddFile(VirtualFile file) { - optimized_file_index_built = false; files.push_back(std::move(file)); } diff --git a/src/core/file_sys/vfs_vector.h b/src/core/file_sys/vfs_vector.h index c9955755b..bfedb6e42 100644 --- a/src/core/file_sys/vfs_vector.h +++ b/src/core/file_sys/vfs_vector.h @@ -105,7 +105,6 @@ public: VirtualDir parent = nullptr); ~VectorVfsDirectory() override; - VirtualFile GetFile(std::string_view file_name) const override; std::vector<VirtualFile> GetFiles() const override; std::vector<VirtualDir> GetSubdirectories() const override; bool IsWritable() const override; @@ -127,9 +126,6 @@ private: VirtualDir parent; std::string name; - - mutable std::map<std::string, size_t, std::less<>> optimized_file_index; - mutable bool optimized_file_index_built{}; }; } // namespace FileSys diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp index f73a864c3..427dbc8b3 100644 --- a/src/core/hle/service/filesystem/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp_srv.cpp @@ -968,16 +968,20 @@ void FSP_SRV::ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(HLERequ void FSP_SRV::OpenDataStorageByCurrentProcess(HLERequestContext& ctx) { LOG_DEBUG(Service_FS, "called"); - auto current_romfs = fsc.OpenRomFSCurrentProcess(); - if (current_romfs.Failed()) { - // TODO (bunnei): Find the right error code to use here - LOG_CRITICAL(Service_FS, "no file system interface available!"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultUnknown); - return; + if (!romfs) { + auto current_romfs = fsc.OpenRomFSCurrentProcess(); + if (current_romfs.Failed()) { + // TODO (bunnei): Find the right error code to use here + LOG_CRITICAL(Service_FS, "no file system interface available!"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultUnknown); + return; + } + + romfs = current_romfs.Unwrap(); } - auto storage = std::make_shared<IStorage>(system, std::move(current_romfs.Unwrap())); + auto storage = std::make_shared<IStorage>(system, romfs); IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); |