diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/file_sys/vfs_real.cpp | 55 | ||||
| -rw-r--r-- | src/core/file_sys/vfs_real.h | 15 |
2 files changed, 45 insertions, 25 deletions
diff --git a/src/core/file_sys/vfs_real.cpp b/src/core/file_sys/vfs_real.cpp index fcc81a664..b0515ec05 100644 --- a/src/core/file_sys/vfs_real.cpp +++ b/src/core/file_sys/vfs_real.cpp | |||
| @@ -76,6 +76,7 @@ VfsEntryType RealVfsFilesystem::GetEntryType(std::string_view path_) const { | |||
| 76 | VirtualFile RealVfsFilesystem::OpenFileFromEntry(std::string_view path_, std::optional<u64> size, | 76 | VirtualFile RealVfsFilesystem::OpenFileFromEntry(std::string_view path_, std::optional<u64> size, |
| 77 | Mode perms) { | 77 | Mode perms) { |
| 78 | const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault); | 78 | const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault); |
| 79 | std::scoped_lock lk{list_lock}; | ||
| 79 | 80 | ||
| 80 | if (auto it = cache.find(path); it != cache.end()) { | 81 | if (auto it = cache.find(path); it != cache.end()) { |
| 81 | if (auto file = it->second.lock(); file) { | 82 | if (auto file = it->second.lock(); file) { |
| @@ -88,7 +89,7 @@ VirtualFile RealVfsFilesystem::OpenFileFromEntry(std::string_view path_, std::op | |||
| 88 | } | 89 | } |
| 89 | 90 | ||
| 90 | auto reference = std::make_unique<FileReference>(); | 91 | auto reference = std::make_unique<FileReference>(); |
| 91 | this->InsertReferenceIntoList(*reference); | 92 | this->InsertReferenceIntoListLocked(*reference); |
| 92 | 93 | ||
| 93 | auto file = std::shared_ptr<RealVfsFile>( | 94 | auto file = std::shared_ptr<RealVfsFile>( |
| 94 | new RealVfsFile(*this, std::move(reference), path, perms, size)); | 95 | new RealVfsFile(*this, std::move(reference), path, perms, size)); |
| @@ -103,7 +104,10 @@ VirtualFile RealVfsFilesystem::OpenFile(std::string_view path_, Mode perms) { | |||
| 103 | 104 | ||
| 104 | VirtualFile RealVfsFilesystem::CreateFile(std::string_view path_, Mode perms) { | 105 | VirtualFile RealVfsFilesystem::CreateFile(std::string_view path_, Mode perms) { |
| 105 | const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault); | 106 | const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault); |
| 106 | cache.erase(path); | 107 | { |
| 108 | std::scoped_lock lk{list_lock}; | ||
| 109 | cache.erase(path); | ||
| 110 | } | ||
| 107 | 111 | ||
| 108 | // Current usages of CreateFile expect to delete the contents of an existing file. | 112 | // Current usages of CreateFile expect to delete the contents of an existing file. |
| 109 | if (FS::IsFile(path)) { | 113 | if (FS::IsFile(path)) { |
| @@ -133,8 +137,11 @@ VirtualFile RealVfsFilesystem::CopyFile(std::string_view old_path_, std::string_ | |||
| 133 | VirtualFile RealVfsFilesystem::MoveFile(std::string_view old_path_, std::string_view new_path_) { | 137 | VirtualFile RealVfsFilesystem::MoveFile(std::string_view old_path_, std::string_view new_path_) { |
| 134 | const auto old_path = FS::SanitizePath(old_path_, FS::DirectorySeparator::PlatformDefault); | 138 | const auto old_path = FS::SanitizePath(old_path_, FS::DirectorySeparator::PlatformDefault); |
| 135 | const auto new_path = FS::SanitizePath(new_path_, FS::DirectorySeparator::PlatformDefault); | 139 | const auto new_path = FS::SanitizePath(new_path_, FS::DirectorySeparator::PlatformDefault); |
| 136 | cache.erase(old_path); | 140 | { |
| 137 | cache.erase(new_path); | 141 | std::scoped_lock lk{list_lock}; |
| 142 | cache.erase(old_path); | ||
| 143 | cache.erase(new_path); | ||
| 144 | } | ||
| 138 | if (!FS::RenameFile(old_path, new_path)) { | 145 | if (!FS::RenameFile(old_path, new_path)) { |
| 139 | return nullptr; | 146 | return nullptr; |
| 140 | } | 147 | } |
| @@ -143,7 +150,10 @@ VirtualFile RealVfsFilesystem::MoveFile(std::string_view old_path_, std::string_ | |||
| 143 | 150 | ||
| 144 | bool RealVfsFilesystem::DeleteFile(std::string_view path_) { | 151 | bool RealVfsFilesystem::DeleteFile(std::string_view path_) { |
| 145 | const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault); | 152 | const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault); |
| 146 | cache.erase(path); | 153 | { |
| 154 | std::scoped_lock lk{list_lock}; | ||
| 155 | cache.erase(path); | ||
| 156 | } | ||
| 147 | return FS::RemoveFile(path); | 157 | return FS::RemoveFile(path); |
| 148 | } | 158 | } |
| 149 | 159 | ||
| @@ -182,14 +192,17 @@ bool RealVfsFilesystem::DeleteDirectory(std::string_view path_) { | |||
| 182 | return FS::RemoveDirRecursively(path); | 192 | return FS::RemoveDirRecursively(path); |
| 183 | } | 193 | } |
| 184 | 194 | ||
| 185 | void RealVfsFilesystem::RefreshReference(const std::string& path, Mode perms, | 195 | std::unique_lock<std::mutex> RealVfsFilesystem::RefreshReference(const std::string& path, |
| 186 | FileReference& reference) { | 196 | Mode perms, |
| 197 | FileReference& reference) { | ||
| 198 | std::unique_lock lk{list_lock}; | ||
| 199 | |||
| 187 | // Temporarily remove from list. | 200 | // Temporarily remove from list. |
| 188 | this->RemoveReferenceFromList(reference); | 201 | this->RemoveReferenceFromListLocked(reference); |
| 189 | 202 | ||
| 190 | // Restore file if needed. | 203 | // Restore file if needed. |
| 191 | if (!reference.file) { | 204 | if (!reference.file) { |
| 192 | this->EvictSingleReference(); | 205 | this->EvictSingleReferenceLocked(); |
| 193 | 206 | ||
| 194 | reference.file = | 207 | reference.file = |
| 195 | FS::FileOpen(path, ModeFlagsToFileAccessMode(perms), FS::FileType::BinaryFile); | 208 | FS::FileOpen(path, ModeFlagsToFileAccessMode(perms), FS::FileType::BinaryFile); |
| @@ -199,12 +212,16 @@ void RealVfsFilesystem::RefreshReference(const std::string& path, Mode perms, | |||
| 199 | } | 212 | } |
| 200 | 213 | ||
| 201 | // Reinsert into list. | 214 | // Reinsert into list. |
| 202 | this->InsertReferenceIntoList(reference); | 215 | this->InsertReferenceIntoListLocked(reference); |
| 216 | |||
| 217 | return lk; | ||
| 203 | } | 218 | } |
| 204 | 219 | ||
| 205 | void RealVfsFilesystem::DropReference(std::unique_ptr<FileReference>&& reference) { | 220 | void RealVfsFilesystem::DropReference(std::unique_ptr<FileReference>&& reference) { |
| 221 | std::scoped_lock lk{list_lock}; | ||
| 222 | |||
| 206 | // Remove from list. | 223 | // Remove from list. |
| 207 | this->RemoveReferenceFromList(*reference); | 224 | this->RemoveReferenceFromListLocked(*reference); |
| 208 | 225 | ||
| 209 | // Close the file. | 226 | // Close the file. |
| 210 | if (reference->file) { | 227 | if (reference->file) { |
| @@ -213,14 +230,14 @@ void RealVfsFilesystem::DropReference(std::unique_ptr<FileReference>&& reference | |||
| 213 | } | 230 | } |
| 214 | } | 231 | } |
| 215 | 232 | ||
| 216 | void RealVfsFilesystem::EvictSingleReference() { | 233 | void RealVfsFilesystem::EvictSingleReferenceLocked() { |
| 217 | if (num_open_files < MaxOpenFiles || open_references.empty()) { | 234 | if (num_open_files < MaxOpenFiles || open_references.empty()) { |
| 218 | return; | 235 | return; |
| 219 | } | 236 | } |
| 220 | 237 | ||
| 221 | // Get and remove from list. | 238 | // Get and remove from list. |
| 222 | auto& reference = open_references.back(); | 239 | auto& reference = open_references.back(); |
| 223 | this->RemoveReferenceFromList(reference); | 240 | this->RemoveReferenceFromListLocked(reference); |
| 224 | 241 | ||
| 225 | // Close the file. | 242 | // Close the file. |
| 226 | if (reference.file) { | 243 | if (reference.file) { |
| @@ -229,10 +246,10 @@ void RealVfsFilesystem::EvictSingleReference() { | |||
| 229 | } | 246 | } |
| 230 | 247 | ||
| 231 | // Reinsert into closed list. | 248 | // Reinsert into closed list. |
| 232 | this->InsertReferenceIntoList(reference); | 249 | this->InsertReferenceIntoListLocked(reference); |
| 233 | } | 250 | } |
| 234 | 251 | ||
| 235 | void RealVfsFilesystem::InsertReferenceIntoList(FileReference& reference) { | 252 | void RealVfsFilesystem::InsertReferenceIntoListLocked(FileReference& reference) { |
| 236 | if (reference.file) { | 253 | if (reference.file) { |
| 237 | open_references.push_front(reference); | 254 | open_references.push_front(reference); |
| 238 | } else { | 255 | } else { |
| @@ -240,7 +257,7 @@ void RealVfsFilesystem::InsertReferenceIntoList(FileReference& reference) { | |||
| 240 | } | 257 | } |
| 241 | } | 258 | } |
| 242 | 259 | ||
| 243 | void RealVfsFilesystem::RemoveReferenceFromList(FileReference& reference) { | 260 | void RealVfsFilesystem::RemoveReferenceFromListLocked(FileReference& reference) { |
| 244 | if (reference.file) { | 261 | if (reference.file) { |
| 245 | open_references.erase(open_references.iterator_to(reference)); | 262 | open_references.erase(open_references.iterator_to(reference)); |
| 246 | } else { | 263 | } else { |
| @@ -271,7 +288,7 @@ std::size_t RealVfsFile::GetSize() const { | |||
| 271 | 288 | ||
| 272 | bool RealVfsFile::Resize(std::size_t new_size) { | 289 | bool RealVfsFile::Resize(std::size_t new_size) { |
| 273 | size.reset(); | 290 | size.reset(); |
| 274 | base.RefreshReference(path, perms, *reference); | 291 | auto lk = base.RefreshReference(path, perms, *reference); |
| 275 | return reference->file ? reference->file->SetSize(new_size) : false; | 292 | return reference->file ? reference->file->SetSize(new_size) : false; |
| 276 | } | 293 | } |
| 277 | 294 | ||
| @@ -288,7 +305,7 @@ bool RealVfsFile::IsReadable() const { | |||
| 288 | } | 305 | } |
| 289 | 306 | ||
| 290 | std::size_t RealVfsFile::Read(u8* data, std::size_t length, std::size_t offset) const { | 307 | std::size_t RealVfsFile::Read(u8* data, std::size_t length, std::size_t offset) const { |
| 291 | base.RefreshReference(path, perms, *reference); | 308 | auto lk = base.RefreshReference(path, perms, *reference); |
| 292 | if (!reference->file || !reference->file->Seek(static_cast<s64>(offset))) { | 309 | if (!reference->file || !reference->file->Seek(static_cast<s64>(offset))) { |
| 293 | return 0; | 310 | return 0; |
| 294 | } | 311 | } |
| @@ -297,7 +314,7 @@ std::size_t RealVfsFile::Read(u8* data, std::size_t length, std::size_t offset) | |||
| 297 | 314 | ||
| 298 | std::size_t RealVfsFile::Write(const u8* data, std::size_t length, std::size_t offset) { | 315 | std::size_t RealVfsFile::Write(const u8* data, std::size_t length, std::size_t offset) { |
| 299 | size.reset(); | 316 | size.reset(); |
| 300 | base.RefreshReference(path, perms, *reference); | 317 | auto lk = base.RefreshReference(path, perms, *reference); |
| 301 | if (!reference->file || !reference->file->Seek(static_cast<s64>(offset))) { | 318 | if (!reference->file || !reference->file->Seek(static_cast<s64>(offset))) { |
| 302 | return 0; | 319 | return 0; |
| 303 | } | 320 | } |
diff --git a/src/core/file_sys/vfs_real.h b/src/core/file_sys/vfs_real.h index 67f4c4422..26ea7df62 100644 --- a/src/core/file_sys/vfs_real.h +++ b/src/core/file_sys/vfs_real.h | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | #pragma once | 4 | #pragma once |
| 5 | 5 | ||
| 6 | #include <map> | 6 | #include <map> |
| 7 | #include <mutex> | ||
| 7 | #include <optional> | 8 | #include <optional> |
| 8 | #include <string_view> | 9 | #include <string_view> |
| 9 | #include "common/intrusive_list.h" | 10 | #include "common/intrusive_list.h" |
| @@ -48,22 +49,24 @@ private: | |||
| 48 | std::map<std::string, std::weak_ptr<VfsFile>, std::less<>> cache; | 49 | std::map<std::string, std::weak_ptr<VfsFile>, std::less<>> cache; |
| 49 | ReferenceListType open_references; | 50 | ReferenceListType open_references; |
| 50 | ReferenceListType closed_references; | 51 | ReferenceListType closed_references; |
| 52 | std::mutex list_lock; | ||
| 51 | size_t num_open_files{}; | 53 | size_t num_open_files{}; |
| 52 | 54 | ||
| 53 | private: | 55 | private: |
| 54 | friend class RealVfsFile; | 56 | friend class RealVfsFile; |
| 55 | void RefreshReference(const std::string& path, Mode perms, FileReference& reference); | 57 | std::unique_lock<std::mutex> RefreshReference(const std::string& path, Mode perms, |
| 58 | FileReference& reference); | ||
| 56 | void DropReference(std::unique_ptr<FileReference>&& reference); | 59 | void DropReference(std::unique_ptr<FileReference>&& reference); |
| 57 | void EvictSingleReference(); | ||
| 58 | |||
| 59 | private: | ||
| 60 | void InsertReferenceIntoList(FileReference& reference); | ||
| 61 | void RemoveReferenceFromList(FileReference& reference); | ||
| 62 | 60 | ||
| 63 | private: | 61 | private: |
| 64 | friend class RealVfsDirectory; | 62 | friend class RealVfsDirectory; |
| 65 | VirtualFile OpenFileFromEntry(std::string_view path, std::optional<u64> size, | 63 | VirtualFile OpenFileFromEntry(std::string_view path, std::optional<u64> size, |
| 66 | Mode perms = Mode::Read); | 64 | Mode perms = Mode::Read); |
| 65 | |||
| 66 | private: | ||
| 67 | void EvictSingleReferenceLocked(); | ||
| 68 | void InsertReferenceIntoListLocked(FileReference& reference); | ||
| 69 | void RemoveReferenceFromListLocked(FileReference& reference); | ||
| 67 | }; | 70 | }; |
| 68 | 71 | ||
| 69 | // An implementation of VfsFile that represents a file on the user's computer. | 72 | // An implementation of VfsFile that represents a file on the user's computer. |