fs: implement AccessLog, enable for File operations

This commit is contained in:
Michael Scire 2020-06-29 23:19:33 -07:00
parent 3fe7700e5c
commit c6a0d88a76
36 changed files with 1930 additions and 362 deletions

View file

@ -19,7 +19,7 @@ export ATMOSPHERE_DEFINES := -DATMOSPHERE
export ATMOSPHERE_SETTINGS := -fPIE -g export ATMOSPHERE_SETTINGS := -fPIE -g
export ATMOSPHERE_CFLAGS := -Wall -ffunction-sections -fdata-sections -fno-strict-aliasing -fwrapv \ export ATMOSPHERE_CFLAGS := -Wall -ffunction-sections -fdata-sections -fno-strict-aliasing -fwrapv \
-fno-asynchronous-unwind-tables -fno-unwind-tables -fno-stack-protector \ -fno-asynchronous-unwind-tables -fno-unwind-tables -fno-stack-protector \
-Wno-format-truncation -Wno-format-truncation -Wno-format-zero-length
export ATMOSPHERE_CXXFLAGS := -fno-rtti -fno-exceptions -std=gnu++20 export ATMOSPHERE_CXXFLAGS := -fno-rtti -fno-exceptions -std=gnu++20
export ATMOSPHERE_ASFLAGS := export ATMOSPHERE_ASFLAGS :=

View file

@ -16,7 +16,13 @@
#pragma once #pragma once
#include <stratosphere/fs/fs_common.hpp> #include <stratosphere/fs/fs_common.hpp>
#include <stratosphere/fs/impl/fs_result_utils.hpp>
#include <stratosphere/fs/fs_context.hpp>
#include <stratosphere/fs/fs_result_config.hpp>
#include <stratosphere/fs/fs_storage_type.hpp> #include <stratosphere/fs/fs_storage_type.hpp>
#include <stratosphere/fs/fs_priority.hpp>
#include <stratosphere/fs/impl/fs_priority_utils.hpp>
#include <stratosphere/fs/fs_access_log.hpp>
#include <stratosphere/fs/fsa/fs_ifile.hpp> #include <stratosphere/fs/fsa/fs_ifile.hpp>
#include <stratosphere/fs/fsa/fs_idirectory.hpp> #include <stratosphere/fs/fsa/fs_idirectory.hpp>
#include <stratosphere/fs/fsa/fs_ifilesystem.hpp> #include <stratosphere/fs/fsa/fs_ifilesystem.hpp>
@ -54,3 +60,4 @@
#include <stratosphere/fs/fs_sd_card.hpp> #include <stratosphere/fs/fs_sd_card.hpp>
#include <stratosphere/fs/fs_signed_system_partition.hpp> #include <stratosphere/fs/fs_signed_system_partition.hpp>
#include <stratosphere/fs/fs_system_data.hpp> #include <stratosphere/fs/fs_system_data.hpp>
#include <stratosphere/fs/impl/fs_access_log_impl.hpp>

View file

@ -0,0 +1,33 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
namespace ams::fs {
enum AccessLogMode : u32 {
AccessLogMode_None = 0,
AccessLogMode_Log = 1,
AccessLogMode_SdCard = 2,
};
Result GetGlobalAccessLogMode(u32 *out);
Result SetGlobalAccessLogMode(u32 mode);
void SetLocalAccessLog(bool enabled);
void SetLocalSystemAccessLogForDebug(bool enabled);
}

View file

@ -0,0 +1,68 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
namespace ams::fs {
enum class AbortSpecifier {
Default,
Abort,
Return,
};
using ResultHandler = AbortSpecifier (*)(Result);
class FsContext {
private:
ResultHandler handler;
public:
constexpr explicit FsContext(ResultHandler h) : handler(h) { /* ... */ }
constexpr void SetHandler(ResultHandler h) { this->handler = h; }
constexpr AbortSpecifier HandleResult(Result result) const { return this->handler(result); }
};
void SetDefaultFsContextResultHandler(const ResultHandler handler);
const FsContext *GetCurrentThreadFsContext();
void SetCurrentThreadFsContext(const FsContext *context);
class ScopedFsContext {
private:
const FsContext * const prev_context;
public:
ALWAYS_INLINE ScopedFsContext(const FsContext &ctx) : prev_context(GetCurrentThreadFsContext()) {
SetCurrentThreadFsContext(std::addressof(ctx));
}
ALWAYS_INLINE ~ScopedFsContext() {
SetCurrentThreadFsContext(this->prev_context);
}
};
class ScopedAutoAbortDisabler {
private:
const FsContext * const prev_context;
public:
ScopedAutoAbortDisabler();
ALWAYS_INLINE ~ScopedAutoAbortDisabler() {
SetCurrentThreadFsContext(this->prev_context);
}
};
}

View file

@ -0,0 +1,44 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
namespace ams::fs {
enum Priority {
Priority_Realtime = 0,
Priority_Normal = 1,
Priority_Low = 2,
};
enum PriorityRaw {
PriorityRaw_Realtime = 0,
PriorityRaw_Normal = 1,
PriorityRaw_Low = 2,
PriorityRaw_Background = 3,
};
Priority GetPriorityOnCurrentThread();
Priority GetPriority(os::ThreadType *thread);
PriorityRaw GetPriorityRawOnCurrentThread();
PriorityRaw GetPriorityRaw(os::ThreadType *thread);
void SetPriorityOnCurrentThread(Priority prio);
void SetPriority(os::ThreadType *thread, Priority prio);
void SetPriorityRawOnCurrentThread(PriorityRaw prio);
void SetPriorityRaw(os::ThreadType *thread, PriorityRaw prio);
}

View file

@ -0,0 +1,24 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
namespace ams::fs {
void SetEnabledAutoAbort(bool enabled);
void SetResultHandledByApplication(bool application);
}

View file

@ -0,0 +1,153 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
#include <stratosphere/fs/fs_access_log.hpp>
#include <stratosphere/fs/fs_directory.hpp>
#include <stratosphere/fs/fs_file.hpp>
#include <stratosphere/fs/fs_priority.hpp>
#include <stratosphere/os/os_tick.hpp>
namespace ams::fs::impl {
enum AccessLogTarget : u32 {
AccessLogTarget_None = (0 << 0),
AccessLogTarget_Application = (1 << 0),
AccessLogTarget_System = (1 << 1),
};
struct IdentifyAccessLogHandle {
void *handle;
public:
static constexpr IdentifyAccessLogHandle MakeHandle(void *h) {
return IdentifyAccessLogHandle{h};
}
};
bool IsEnabledAccessLog(u32 target);
bool IsEnabledAccessLog();
bool IsEnabledHandleAccessLog(fs::FileHandle handle);
bool IsEnabledHandleAccessLog(fs::DirectoryHandle handle);
bool IsEnabledHandleAccessLog(fs::impl::IdentifyAccessLogHandle handle);
bool IsEnabledHandleAccessLog(const void *handle);
bool IsEnabledFileSystemAccessorAccessLog(const char *mount_name);
void EnableFileSystemAccessorAccessLog(const char *mount_name);
using AccessLogPrinterCallback = int (*)(char *buffer, size_t buffer_size);
void RegisterStartAccessLogPrinterCallback(AccessLogPrinterCallback callback);
void OutputAccessLog(Result result, os::Tick start, os::Tick end, const char *name, fs::FileHandle handle, const char *fmt, ...) __attribute__((format (printf, 6, 7)));
void OutputAccessLog(Result result, os::Tick start, os::Tick end, const char *name, fs::DirectoryHandle handle, const char *fmt, ...) __attribute__((format (printf, 6, 7)));
void OutputAccessLog(Result result, os::Tick start, os::Tick end, const char *name, fs::impl::IdentifyAccessLogHandle handle, const char *fmt, ...) __attribute__((format (printf, 6, 7)));
void OutputAccessLog(Result result, os::Tick start, os::Tick end, const char *name, const void *handle, const char *fmt, ...) __attribute__((format (printf, 6, 7)));
void OutputAccessLog(Result result, fs::Priority priority, os::Tick start, os::Tick end, const char *name, const void *handle, const char *fmt, ...) __attribute__((format (printf, 7, 8)));
void OutputAccessLog(Result result, fs::PriorityRaw priority_raw, os::Tick start, os::Tick end, const char *name, const void *handle, const char *fmt, ...) __attribute__((format (printf, 7, 8)));
void OutputAccessLogToOnlySdCard(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
void OutputAccessLogUnlessResultSuccess(Result result, os::Tick start, os::Tick end, const char *name, fs::FileHandle handle, const char *fmt, ...) __attribute__((format (printf, 6, 7)));
void OutputAccessLogUnlessResultSuccess(Result result, os::Tick start, os::Tick end, const char *name, fs::DirectoryHandle handle, const char *fmt, ...) __attribute__((format (printf, 6, 7)));
void OutputAccessLogUnlessResultSuccess(Result result, os::Tick start, os::Tick end, const char *name, const void *handle, const char *fmt, ...) __attribute__((format (printf, 6, 7)));
class IdString {
private:
char buffer[0x20];
private:
const char *ToValueString(int id);
public:
template<typename T>
const char *ToString(T id);
};
}
/* Access log components. */
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_SIZE ", size: %" PRId64 ""
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_OFFSET_AND_SIZE ", offset: %" PRId64 ", size: %zu"
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_THREAD_ID ", thread_id: %" PRIu64 ""
/* Access log formats. */
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_NONE ""
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_WRITE_FILE_WITH_NO_OPTION AMS_FS_IMPL_ACCESS_LOG_FORMAT_OFFSET_AND_SIZE
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_WRITE_FILE_WITH_FLUSH_OPTION AMS_FS_IMPL_ACCESS_LOG_FORMAT_WRITE_FILE_WITH_NO_OPTION ", write_option: Flush"
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_WRITE_FILE(__OPTION__) ((__OPTION__).HasFlushFlag() ? AMS_FS_IMPL_ACCESS_LOG_FORMAT_WRITE_FILE_WITH_FLUSH_OPTION : AMS_FS_IMPL_ACCESS_LOG_FORMAT_WRITE_FILE_WITH_NO_OPTION)
/* Access log invocation lambdas. */
#define AMS_FS_IMPL_ACCESS_LOG_IMPL(__EXPR__, __HANDLE__, __ENABLED__, __NAME__, ...) \
[&](const char *name) { \
if (!(__ENABLED__)) { \
return (__EXPR__); \
} else { \
const ::ams::os::Tick start = ::ams::os::GetSystemTick(); \
const auto result = (__EXPR__); \
const ::ams::os::Tick end = ::ams::os::GetSystemTick(); \
::ams::fs::impl::OutputAccessLog(result, start, end, name, __HANDLE__, __VA_ARGS__); \
return result; \
} \
}(__NAME__)
#define AMS_FS_IMPL_ACCESS_LOG_WITH_PRIORITY_IMPL(__EXPR__, __PRIORITY__, __HANDLE__, __ENABLED__, __NAME__, ...) \
[&](const char *name) { \
if (!(__ENABLED__)) { \
return (__EXPR__); \
} else { \
const ::ams::os::Tick start = ::ams::os::GetSystemTick(); \
const auto result = (__EXPR__); \
const ::ams::os::Tick end = ::ams::os::GetSystemTick(); \
::ams::fs::impl::OutputAccessLog(result, __PRIORITY__, start, end, name, __HANDLE__, __VA_ARGS__); \
return result; \
} \
}(__NAME__)
#define AMS_FS_IMPL_ACCESS_LOG_EXPLICIT_IMPL(__RESULT__, __START__, __END__, __HANDLE__, __ENABLED__, __NAME__, ...) \
[&](const char *name) { \
if (!(__ENABLED__)) { \
return __RESULT__; \
} else { \
::ams::fs::impl::OutputAccessLog(__RESULT__, __START__, __END__, name, __HANDLE__, __VA_ARGS__); \
return __RESULT__; \
} \
}(__NAME__)
#define AMS_FS_IMPL_ACCESS_LOG_UNLESS_R_SUCCEEDED_IMPL(__EXPR__, __ENABLED__, __NAME__, ...) \
[&](const char *name) { \
if (!(__ENABLED__)) { \
return (__EXPR__); \
} else { \
const ::ams::os::Tick start = ::ams::os::GetSystemTick(); \
const auto result = (__EXPR__); \
const ::ams::os::Tick end = ::ams::os::GetSystemTick(); \
::ams::fs::impl::OutputAccessLogUnlessResultSuccess(result, start, end, name, nullptr, __VA_ARGS__); \
return result; \
} \
}(__NAME__)
/* Access log api. */
#define AMS_FS_IMPL_ACCESS_LOG(__EXPR__, __HANDLE__, ...) \
AMS_FS_IMPL_ACCESS_LOG_IMPL((__EXPR__), __HANDLE__, ::ams::fs::impl::IsEnabledAccessLog() && ::ams::fs::impl::IsEnabledHandleAccessLog(__HANDLE__), AMS_CURRENT_FUNCTION_NAME, __VA_ARGS__)
#define AMS_FS_IMPL_ACCESS_LOG_WITH_NAME(__EXPR__, __HANDLE__, __NAME__, ...) \
AMS_FS_IMPL_ACCESS_LOG_IMPL((__EXPR__), __HANDLE__, ::ams::fs::impl::IsEnabledAccessLog() && ::ams::fs::impl::IsEnabledHandleAccessLog(__HANDLE__), __NAME__, __VA_ARGS__)
#define AMS_FS_IMPL_ACCESS_LOG_EXPLICIT(__RESULT__, __START__, __END__, __HANDLE__, __NAME__, ...) \
AMS_FS_IMPL_ACCESS_LOG_EXPLICIT_IMPL((__RESULT__), __START__, __END__, __HANDLE__, ::ams::fs::impl::IsEnabledAccessLog() && ::ams::fs::impl::IsEnabledHandleAccessLog(__HANDLE__), __NAME__, __VA_ARGS__)
#define AMS_FS_IMPL_ACCESS_LOG_UNLESS_R_SUCCEEDED(__EXPR__, ...) \
AMS_FS_IMPL_ACCESS_LOG_UNLESS_R_SUCCEEDED_IMPL((__EXPR__), ::ams::fs::impl::IsEnabledAccessLog(), AMS_CURRENT_FUNCTION_NAME, __VA_ARGS__)

View file

@ -0,0 +1,46 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stratosphere/fs/fs_common.hpp>
#include <stratosphere/sf/sf_fs_inline_context.hpp>
namespace ams::fs::impl {
constexpr inline u8 TlsIoPriorityMask = 0x7;
constexpr inline u8 TlsIoRecursiveCallMask = 0x8;
struct TlsIoValueForInheritance {
u8 _tls_value;
};
inline void SetCurrentRequestRecursive() {
os::ThreadType * const cur_thread = os::GetCurrentThread();
sf::SetFsInlineContext(cur_thread, TlsIoRecursiveCallMask | sf::GetFsInlineContext(cur_thread));
}
inline bool IsCurrentRequestRecursive() {
return (sf::GetFsInlineContext(os::GetCurrentThread()) & TlsIoRecursiveCallMask) != 0;
}
inline TlsIoValueForInheritance GetTlsIoValueForInheritance() {
return TlsIoValueForInheritance { sf::GetFsInlineContext(os::GetCurrentThread()) };
}
inline void SetTlsIoValueForInheritance(TlsIoValueForInheritance tls_io) {
sf::SetFsInlineContext(os::GetCurrentThread(), tls_io._tls_value);
}
}

View file

@ -0,0 +1,68 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stratosphere/fs/fs_common.hpp>
#include <stratosphere/fs/fs_priority.hpp>
#include <stratosphere/fs/impl/fs_fs_inline_context_utils.hpp>
namespace ams::fs::impl {
enum TlsIoPriority : u8 {
TlsIoPriority_Normal = 0,
TlsIoPriority_Realtime = 1,
TlsIoPriority_Low = 2,
TlsIoPriority_Background = 3,
};
/* Ensure that TlsIo priority matches libnx priority. */
static_assert(TlsIoPriority_Normal == static_cast<TlsIoPriority>(::FsPriority_Normal));
static_assert(TlsIoPriority_Realtime == static_cast<TlsIoPriority>(::FsPriority_Realtime));
static_assert(TlsIoPriority_Low == static_cast<TlsIoPriority>(::FsPriority_Low));
static_assert(TlsIoPriority_Background == static_cast<TlsIoPriority>(::FsPriority_Background));
constexpr inline Result ConvertFsPriorityToTlsIoPriority(u8 *out, PriorityRaw priority) {
AMS_ASSERT(out != nullptr);
switch (priority) {
case PriorityRaw_Normal: *out = TlsIoPriority_Normal;
case PriorityRaw_Realtime: *out = TlsIoPriority_Realtime;
case PriorityRaw_Low: *out = TlsIoPriority_Low;
case PriorityRaw_Background: *out = TlsIoPriority_Background;
default: return fs::ResultInvalidArgument();
}
return ResultSuccess();
}
constexpr inline Result ConvertTlsIoPriorityToFsPriority(PriorityRaw *out, u8 tls_io) {
AMS_ASSERT(out != nullptr);
switch (static_cast<TlsIoPriority>(tls_io)) {
case TlsIoPriority_Normal: *out = PriorityRaw_Normal;
case TlsIoPriority_Realtime: *out = PriorityRaw_Realtime;
case TlsIoPriority_Low: *out = PriorityRaw_Low;
case TlsIoPriority_Background: *out = PriorityRaw_Background;
default: return fs::ResultInvalidArgument();
}
return ResultSuccess();
}
inline u8 GetTlsIoPriority(os::ThreadType *thread) {
return sf::GetFsInlineContext(thread) & TlsIoPriorityMask;
}
}

View file

@ -0,0 +1,77 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
namespace ams::fs::impl {
bool IsAbortNeeded(Result result);
void LogErrorMessage(Result result, const char *function);
}
#define AMS_FS_R_CHECK_ABORT_IMPL(__RESULT__, __FORCE__) \
({ \
if (::ams::fs::impl::IsAbortNeeded(__RESULT__) || (__FORCE__)) { \
::ams::fs::impl::LogErrorMessage(__RESULT__, AMS_CURRENT_FUNCTION_NAME); \
R_ABORT_UNLESS(__RESULT__); \
} \
})
#define AMS_FS_R_TRY(__RESULT__) \
({ \
const ::ams::Result __tmp_fs_result = (__RESULT__); \
AMS_FS_R_CHECK_ABORT_IMPL(__tmp_fs_result, false); \
R_TRY(__tmp_fs_result); \
})
#define AMS_FS_R_ABORT_UNLESS(__RESULT__) \
({ \
const ::ams::Result __tmp_fs_result = (__RESULT__); \
AMS_FS_R_CHECK_ABORT_IMPL(__tmp_fs_result, true); \
})
#define AMS_FS_R_THROW(__RESULT__) \
({ \
const ::ams::Result __tmp_fs_result = (__RESULT__); \
AMS_FS_R_CHECK_ABORT_IMPL(__tmp_fs_result, false); \
return __tmp_fs_result; \
})
#define AMS_FS_R_UNLESS(__EXPR__, __RESULT__) \
({ \
if (!(__EXPR__)) { \
AMS_FS_R_THROW((__RESULT__)); \
} \
})
#define AMS_FS_R_TRY_CATCH(__EXPR__) R_TRY_CATCH(__EXPR__)
#define AMS_FS_R_CATCH(...) R_CATCH(__VA_ARGS__)
#define AMS_FS_R_END_TRY_CATCH \
else if (R_FAILED(R_CURRENT_RESULT)) { \
AMS_FS_R_THROW(R_CURRENT_RESULT); \
} \
} \
})
#define AMS_FS_R_END_TRY_CATCH_WITH_ABORT_UNLESS \
else { \
AMS_FS_R_ABORT_UNLESS(R_CURRENT_RESULT); \
} \
} \
})

View file

@ -35,7 +35,8 @@
#include <stratosphere/os/os_system_event.hpp> #include <stratosphere/os/os_system_event.hpp>
#include <stratosphere/os/os_interrupt_event.hpp> #include <stratosphere/os/os_interrupt_event.hpp>
#include <stratosphere/os/os_timer_event.hpp> #include <stratosphere/os/os_timer_event.hpp>
#include <stratosphere/os/os_thread_local_storage_api.hpp> #include <stratosphere/os/os_thread_local_storage.hpp>
#include <stratosphere/os/os_sdk_thread_local_storage.hpp>
#include <stratosphere/os/os_thread.hpp> #include <stratosphere/os/os_thread.hpp>
#include <stratosphere/os/os_message_queue.hpp> #include <stratosphere/os/os_message_queue.hpp>
#include <stratosphere/os/os_waitable.hpp> #include <stratosphere/os/os_waitable.hpp>

View file

@ -0,0 +1,47 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stratosphere/os/os_thread_local_storage.hpp>
#include <stratosphere/os/os_sdk_thread_local_storage_api.hpp>
namespace ams::os {
class SdkThreadLocalStorage {
NON_COPYABLE(SdkThreadLocalStorage);
NON_MOVEABLE(SdkThreadLocalStorage);
private:
TlsSlot tls_slot;
public:
SdkThreadLocalStorage() {
R_ABORT_UNLESS(os::SdkAllocateTlsSlot(std::addressof(this->tls_slot), nullptr));
}
explicit SdkThreadLocalStorage(TlsDestructor destructor) {
R_ABORT_UNLESS(os::SdkAllocateTlsSlot(std::addressof(this->tls_slot), destructor));
}
~SdkThreadLocalStorage() {
os::FreeTlsSlot(this->tls_slot);
}
uintptr_t GetValue() const { return os::GetTlsValue(this->tls_slot); }
void SetValue(uintptr_t value) { return os::SetTlsValue(this->tls_slot, value); }
TlsSlot GetTlsSlot() const { return this->tls_slot; }
};
}

View file

@ -0,0 +1,26 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stratosphere/os/os_common_types.hpp>
#include <stratosphere/os/os_memory_common.hpp>
#include <stratosphere/os/os_thread_local_storage_common.hpp>
namespace ams::os {
Result SdkAllocateTlsSlot(TlsSlot *out, TlsDestructor destructor);
}

View file

@ -0,0 +1,47 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stratosphere/os/os_thread_local_storage_common.hpp>
#include <stratosphere/os/os_thread_local_storage_api.hpp>
namespace ams::os {
class ThreadLocalStorage {
NON_COPYABLE(ThreadLocalStorage);
NON_MOVEABLE(ThreadLocalStorage);
private:
TlsSlot tls_slot;
public:
ThreadLocalStorage() {
R_ABORT_UNLESS(os::AllocateTlsSlot(std::addressof(this->tls_slot), nullptr));
}
explicit ThreadLocalStorage(TlsDestructor destructor) {
R_ABORT_UNLESS(os::AllocateTlsSlot(std::addressof(this->tls_slot), destructor));
}
~ThreadLocalStorage() {
os::FreeTlsSlot(this->tls_slot);
}
uintptr_t GetValue() const { return os::GetTlsValue(this->tls_slot); }
void SetValue(uintptr_t value) { return os::SetTlsValue(this->tls_slot, value); }
TlsSlot GetTlsSlot() const { return this->tls_slot; }
};
}

View file

@ -57,6 +57,12 @@ namespace ams::os {
size_t stack_size; size_t stack_size;
ThreadFunction function; ThreadFunction function;
void *argument; void *argument;
/* NOTE: Here, Nintendo stores the TLS array. This is handled by libnx in our case. */
/* However, we need to access certain values in other threads' TLS (Nintendo uses a hardcoded layout for SDK tls members...) */
/* These members are tls slot holders in sdk code, but just normal thread type members under our scheme. */
uintptr_t atomic_sf_inline_context;
mutable impl::InternalCriticalSectionStorage cs_thread; mutable impl::InternalCriticalSectionStorage cs_thread;
mutable impl::InternalConditionVariableStorage cv_thread; mutable impl::InternalConditionVariableStorage cv_thread;

View file

@ -17,9 +17,15 @@
#pragma once #pragma once
#include <stratosphere/sf/sf_common.hpp> #include <stratosphere/sf/sf_common.hpp>
namespace ams::sf { namespace ams::os {
u8 GetFsInlineContext(); struct ThreadType;
u8 SetFsInlineContext(u8 ctx);
}
namespace ams::sf {
u8 GetFsInlineContext(os::ThreadType *thread);
u8 SetFsInlineContext(os::ThreadType *thread, u8 ctx);
} }

View file

@ -0,0 +1,528 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stratosphere.hpp>
#include "fsa/fs_user_mount_table.hpp"
#include "fsa/fs_directory_accessor.hpp"
#include "fsa/fs_file_accessor.hpp"
#include "fsa/fs_filesystem_accessor.hpp"
#define AMS_FS_IMPL_ACCESS_LOG_AMS_API_VERSION "ams_version: " STRINGIZE(ATMOSPHERE_RELEASE_VERSION_MAJOR) "." STRINGIZE(ATMOSPHERE_RELEASE_VERSION_MINOR) "." STRINGIZE(ATMOSPHERE_RELEASE_VERSION_MICRO)
/* TODO: Other boards? */
#define AMS_FS_IMPL_ACCESS_LOG_SPEC "spec: NX"
namespace ams::fs {
/* Forward declare priority getter. */
fs::PriorityRaw GetPriorityRawOnCurrentThreadInternal();
namespace {
constinit u32 g_global_access_log_mode = fs::AccessLogMode_None;
constinit u32 g_local_access_log_target = fs::impl::AccessLogTarget_None;
constinit std::atomic_bool g_access_log_initialized = false;
constinit os::SdkMutex g_access_log_initialization_mutex;
void SetLocalAccessLogImpl(bool enabled) {
if (enabled) {
g_local_access_log_target |= fs::impl::AccessLogTarget_Application;
} else {
g_local_access_log_target &= ~fs::impl::AccessLogTarget_Application;
}
}
}
Result GetGlobalAccessLogMode(u32 *out) {
/* Use libnx bindings. */
return ::fsGetGlobalAccessLogMode(out);
}
Result SetGlobalAccessLogMode(u32 mode) {
/* Use libnx bindings. */
return ::fsSetGlobalAccessLogMode(mode);
}
void SetLocalAccessLog(bool enabled) {
SetLocalAccessLogImpl(enabled);
}
void SetLocalApplicationAccessLog(bool enabled) {
SetLocalAccessLogImpl(enabled);
}
void SetLocalSystemAccessLogForDebug(bool enabled) {
#if defined(AMS_BUILD_FOR_DEBUGGING)
if (enabled) {
g_local_access_log_target |= (fs::impl::AccessLogTarget_Application | fs::impl::AccessLogTarget_System);
} else {
g_local_access_log_target &= ~(fs::impl::AccessLogTarget_Application | fs::impl::AccessLogTarget_System);
}
#endif
}
}
namespace ams::fs::impl {
const char *IdString::ToValueString(int id) {
const int len = std::snprintf(this->buffer, sizeof(this->buffer), "%d", id);
AMS_ASSERT(static_cast<size_t>(len) < sizeof(this->buffer));
return this->buffer;
}
template<> const char *IdString::ToString<fs::Priority>(fs::Priority id) {
switch (id) {
case fs::Priority_Realtime: return "Realtime";
case fs::Priority_Normal: return "Normal";
case fs::Priority_Low: return "Low";
default: return ToValueString(static_cast<int>(id));
}
}
template<> const char *IdString::ToString<fs::PriorityRaw>(fs::PriorityRaw id) {
switch (id) {
case fs::PriorityRaw_Realtime: return "Realtime";
case fs::PriorityRaw_Normal: return "Normal";
case fs::PriorityRaw_Low: return "Low";
case fs::PriorityRaw_Background: return "Realtime";
default: return ToValueString(static_cast<int>(id));
}
}
template<> const char *IdString::ToString<fs::ContentStorageId>(fs::ContentStorageId id) {
switch (id) {
case fs::ContentStorageId::User: return "User";
case fs::ContentStorageId::System: return "System";
case fs::ContentStorageId::SdCard: return "SdCard";
default: return ToValueString(static_cast<int>(id));
}
}
template<> const char *IdString::ToString<fs::SaveDataSpaceId>(fs::SaveDataSpaceId id) {
switch (id) {
case fs::SaveDataSpaceId::System: return "System";
case fs::SaveDataSpaceId::User: return "User";
case fs::SaveDataSpaceId::SdSystem: return "SdSystem";
case fs::SaveDataSpaceId::ProperSystem: return "ProperSystem";
default: return ToValueString(static_cast<int>(id));
}
}
template<> const char *IdString::ToString<fs::ContentType>(fs::ContentType id) {
switch (id) {
case fs::ContentType_Meta: return "Meta";
case fs::ContentType_Control: return "Control";
case fs::ContentType_Manual: return "Manual";
case fs::ContentType_Logo: return "Logo";
case fs::ContentType_Data: return "Data";
default: return ToValueString(static_cast<int>(id));
}
}
template<> const char *IdString::ToString<fs::BisPartitionId>(fs::BisPartitionId id) {
switch (id) {
case fs::BisPartitionId::BootPartition1Root: return "BootPartition1Root";
case fs::BisPartitionId::BootPartition2Root: return "BootPartition2Root";
case fs::BisPartitionId::UserDataRoot: return "UserDataRoot";
case fs::BisPartitionId::BootConfigAndPackage2Part1: return "BootConfigAndPackage2Part1";
case fs::BisPartitionId::BootConfigAndPackage2Part2: return "BootConfigAndPackage2Part2";
case fs::BisPartitionId::BootConfigAndPackage2Part3: return "BootConfigAndPackage2Part3";
case fs::BisPartitionId::BootConfigAndPackage2Part4: return "BootConfigAndPackage2Part4";
case fs::BisPartitionId::BootConfigAndPackage2Part5: return "BootConfigAndPackage2Part5";
case fs::BisPartitionId::BootConfigAndPackage2Part6: return "BootConfigAndPackage2Part6";
case fs::BisPartitionId::CalibrationBinary: return "CalibrationBinary";
case fs::BisPartitionId::CalibrationFile: return "CalibrationFile";
case fs::BisPartitionId::SafeMode: return "SafeMode";
case fs::BisPartitionId::User: return "User";
case fs::BisPartitionId::System: return "System";
case fs::BisPartitionId::SystemProperEncryption: return "SystemProperEncryption";
case fs::BisPartitionId::SystemProperPartition: return "SystemProperPartition";
default: return ToValueString(static_cast<int>(id));
}
}
namespace {
class AccessLogPrinterCallbackManager {
private:
AccessLogPrinterCallback callback;
public:
constexpr AccessLogPrinterCallbackManager() : callback(nullptr) { /* ... */ }
constexpr bool IsRegisteredCallback() const { return this->callback != nullptr; }
constexpr void RegisterCallback(AccessLogPrinterCallback c) {
AMS_ASSERT(this->callback == nullptr);
this->callback = c;
}
constexpr int InvokeCallback(char *buf, size_t size) const {
AMS_ASSERT(this->callback != nullptr);
return this->callback(buf, size);
}
};
constinit AccessLogPrinterCallbackManager g_access_log_manager_printer_callback_manager;
ALWAYS_INLINE AccessLogPrinterCallbackManager &GetStartAccessLogPrinterCallbackManager() {
return g_access_log_manager_printer_callback_manager;
}
const char *GetPriorityRawName() {
return fs::impl::IdString().ToString(fs::GetPriorityRawOnCurrentThreadInternal());
}
Result OutputAccessLogToSdCardImpl(const char *log, size_t size) {
/* Use libnx bindings. */
return ::fsOutputAccessLogToSdCard(log, size);
}
void OutputAccessLogToSdCard(const char *format, std::va_list vl) {
if ((g_global_access_log_mode & AccessLogMode_SdCard) != 0) {
/* Create a buffer to hold the log's input string. */
int log_buffer_size = 1_KB;
auto log_buffer = fs::impl::MakeUnique<char[]>(log_buffer_size);
while (true) {
if (log_buffer == nullptr) {
return;
}
const auto size = std::vsnprintf(log_buffer.get(), log_buffer_size, format, vl);
if (size < log_buffer_size) {
break;
}
log_buffer_size = size + 1;
log_buffer = fs::impl::MakeUnique<char[]>(log_buffer_size);
}
/* Output. */
OutputAccessLogToSdCardImpl(log_buffer.get(), log_buffer_size - 1);
}
}
void OutputAccessLogImpl(const char *log, size_t size) {
if ((g_global_access_log_mode & AccessLogMode_Log) != 0) {
/* TODO: Support logging. */
} else if ((g_global_access_log_mode & AccessLogMode_SdCard) != 0) {
OutputAccessLogToSdCardImpl(log, size - 1);
}
}
void OutputAccessLog(Result result, const char *priority, os::Tick start, os::Tick end, const char *name, const void *handle, const char *format, std::va_list vl) {
/* Create a buffer to hold the log's input string. */
int str_buffer_size = 1_KB;
auto str_buffer = fs::impl::MakeUnique<char[]>(str_buffer_size);
while (true) {
if (str_buffer == nullptr) {
return;
}
const auto size = std::vsnprintf(str_buffer.get(), str_buffer_size, format, vl);
if (size < str_buffer_size) {
break;
}
str_buffer_size = size + 1;
str_buffer = fs::impl::MakeUnique<char[]>(str_buffer_size);
}
/* Create a buffer to hold the log. */
int log_buffer_size = 0;
decltype(str_buffer) log_buffer;
{
/* Declare format string. */
constexpr const char FormatString[] = "FS_ACCESS { "
"start: %9" PRId64 ", "
"end: %9" PRId64 ", "
"result: 0x%08" PRIX32 ", "
"handle: 0x%p, "
"priority: %s, "
"function: \"%s\""
"%s"
" }\n";
/* Convert the timing to ms. */
const s64 start_ms = start.ToTimeSpan().GetMilliSeconds();
const s64 end_ms = end.ToTimeSpan().GetMilliSeconds();
/* Print the log. */
int try_size = std::max<int>(str_buffer_size + sizeof(FormatString) + 0x100, 1_KB);
while (true) {
log_buffer = fs::impl::MakeUnique<char[]>(try_size);
if (log_buffer == nullptr) {
return;
}
log_buffer_size = 1 + std::snprintf(log_buffer.get(), try_size, FormatString, start_ms, end_ms, result.GetValue(), handle, priority, name, str_buffer.get());
if (log_buffer_size <= try_size) {
break;
}
try_size = log_buffer_size;
}
}
OutputAccessLogImpl(log_buffer.get(), log_buffer_size);
}
void GetProgramIndexFortAccessLog(u32 *out_index, u32 *out_count) {
if (hos::GetVersion() >= hos::Version_7_0_0) {
/* Use libnx bindings if available. */
R_ABORT_UNLESS(::fsGetProgramIndexForAccessLog(out_index, out_count));
} else {
/* Use hardcoded defaults. */
*out_index = 0;
*out_count = 0;
}
}
void OutputAccessLogStart() {
/* Get the program index. */
u32 program_index = 0, program_count = 0;
GetProgramIndexFortAccessLog(std::addressof(program_index), std::addressof(program_count));
/* Print the log buffer. */
if (program_count < 2) {
constexpr const char StartLog[] = "FS_ACCESS: { "
AMS_FS_IMPL_ACCESS_LOG_AMS_API_VERSION ", "
AMS_FS_IMPL_ACCESS_LOG_SPEC
" }\n";
OutputAccessLogImpl(StartLog, sizeof(StartLog));
} else {
constexpr const char StartLog[] = "FS_ACCESS: { "
AMS_FS_IMPL_ACCESS_LOG_AMS_API_VERSION ", "
AMS_FS_IMPL_ACCESS_LOG_SPEC ", "
"program_index: %d"
" }\n";
char log_buffer[0x80];
const int len = 1 + std::snprintf(log_buffer, sizeof(log_buffer), StartLog, static_cast<int>(program_index));
if (static_cast<size_t>(len) <= sizeof(log_buffer)) {
OutputAccessLogImpl(log_buffer, len);
}
}
}
[[maybe_unused]] void OutputAccessLogStartForSystem() {
constexpr const char StartLog[] = "FS_ACCESS: { "
AMS_FS_IMPL_ACCESS_LOG_AMS_API_VERSION ", "
AMS_FS_IMPL_ACCESS_LOG_SPEC ", "
"for_system: true"
" }\n";
OutputAccessLogImpl(StartLog, sizeof(StartLog));
}
void OutputAccessLogStartGeneratedByCallback() {
/* Get the manager. */
const auto &manager = GetStartAccessLogPrinterCallbackManager();
if (manager.IsRegisteredCallback()) {
/* Invoke the callback. */
char log_buffer[0x80];
const int len = 1 + manager.InvokeCallback(log_buffer, sizeof(log_buffer));
/* Print, if we fit. */
if (static_cast<size_t>(len) <= sizeof(log_buffer)) {
OutputAccessLogImpl(log_buffer, len);
}
}
}
}
bool IsEnabledAccessLog(u32 target) {
/* If we don't need to log to the target, return false. */
if ((g_local_access_log_target & target) == 0) {
return false;
}
/* Ensure we've initialized. */
if (!g_access_log_initialized) {
std::scoped_lock lk(g_access_log_initialization_mutex);
if (!g_access_log_initialized) {
#if defined (AMS_BUILD_FOR_DEBUGGING)
if ((g_local_access_log_target & fs::impl::AccessLogTarget_System) != 0)
{
g_global_access_log_mode = AccessLogMode_Log;
OutputAccessLogStartForSystem();
OutputAccessLogStartGeneratedByCallback();
}
else
#endif
{
AMS_FS_R_ABORT_UNLESS(GetGlobalAccessLogMode(std::addressof(g_global_access_log_mode)));
if (g_global_access_log_mode != AccessLogMode_None) {
OutputAccessLogStart();
OutputAccessLogStartGeneratedByCallback();
}
}
g_access_log_initialized = true;
}
}
return g_global_access_log_mode != AccessLogMode_None;
}
bool IsEnabledAccessLog() {
return IsEnabledAccessLog(fs::impl::AccessLogTarget_Application | fs::impl::AccessLogTarget_System);
}
void RegisterStartAccessLogPrinterCallback(AccessLogPrinterCallback callback) {
GetStartAccessLogPrinterCallbackManager().RegisterCallback(callback);
}
void OutputAccessLog(Result result, fs::Priority priority, os::Tick start, os::Tick end, const char *name, const void *handle, const char *fmt, ...) {
std::va_list vl;
va_start(vl, fmt);
OutputAccessLog(result, fs::impl::IdString().ToString(priority), start, end, name, handle, fmt, vl);
va_end(vl);
}
void OutputAccessLog(Result result, fs::PriorityRaw priority_raw, os::Tick start, os::Tick end, const char *name, const void *handle, const char *fmt, ...){
std::va_list vl;
va_start(vl, fmt);
OutputAccessLog(result, fs::impl::IdString().ToString(priority_raw), start, end, name, handle, fmt, vl);
va_end(vl);
}
void OutputAccessLog(Result result, os::Tick start, os::Tick end, const char *name, fs::FileHandle handle, const char *fmt, ...) {
std::va_list vl;
va_start(vl, fmt);
OutputAccessLog(result, GetPriorityRawName(), start, end, name, handle.handle, fmt, vl);
va_end(vl);
}
void OutputAccessLog(Result result, os::Tick start, os::Tick end, const char *name, fs::DirectoryHandle handle, const char *fmt, ...) {
std::va_list vl;
va_start(vl, fmt);
OutputAccessLog(result, GetPriorityRawName(), start, end, name, handle.handle, fmt, vl);
va_end(vl);
}
void OutputAccessLog(Result result, os::Tick start, os::Tick end, const char *name, fs::impl::IdentifyAccessLogHandle handle, const char *fmt, ...) {
std::va_list vl;
va_start(vl, fmt);
OutputAccessLog(result, GetPriorityRawName(), start, end, name, handle.handle, fmt, vl);
va_end(vl);
}
void OutputAccessLog(Result result, os::Tick start, os::Tick end, const char *name, const void *handle, const char *fmt, ...) {
std::va_list vl;
va_start(vl, fmt);
OutputAccessLog(result, GetPriorityRawName(), start, end, name, handle, fmt, vl);
va_end(vl);
}
void OutputAccessLogToOnlySdCard(const char *fmt, ...) {
std::va_list vl;
va_start(vl, fmt);
OutputAccessLogToSdCard(fmt, vl);
va_end(vl);
}
void OutputAccessLogUnlessResultSuccess(Result result, os::Tick start, os::Tick end, const char *name, fs::FileHandle handle, const char *fmt, ...) {
if (R_FAILED(result)) {
std::va_list vl;
va_start(vl, fmt);
OutputAccessLog(result, GetPriorityRawName(), start, end, name, handle.handle, fmt, vl);
va_end(vl);
}
}
void OutputAccessLogUnlessResultSuccess(Result result, os::Tick start, os::Tick end, const char *name, fs::DirectoryHandle handle, const char *fmt, ...) {
if (R_FAILED(result)) {
std::va_list vl;
va_start(vl, fmt);
OutputAccessLog(result, GetPriorityRawName(), start, end, name, handle.handle, fmt, vl);
va_end(vl);
}
}
void OutputAccessLogUnlessResultSuccess(Result result, os::Tick start, os::Tick end, const char *name, const void *handle, const char *fmt, ...) {
if (R_FAILED(result)) {
std::va_list vl;
va_start(vl, fmt);
OutputAccessLog(result, GetPriorityRawName(), start, end, name, handle, fmt, vl);
va_end(vl);
}
}
bool IsEnabledHandleAccessLog(fs::FileHandle handle) {
/* Get the file accessor. */
impl::FileAccessor *accessor = reinterpret_cast<impl::FileAccessor *>(handle.handle);
if (accessor == nullptr) {
return true;
}
/* Check the parent. */
if (auto *parent = accessor->GetParent(); parent != nullptr) {
return parent->IsEnabledAccessLog();
} else {
return false;
}
}
bool IsEnabledHandleAccessLog(fs::DirectoryHandle handle) {
/* Get the file accessor. */
impl::DirectoryAccessor *accessor = reinterpret_cast<impl::DirectoryAccessor *>(handle.handle);
if (accessor == nullptr) {
return true;
}
/* Check the parent. */
if (auto *parent = accessor->GetParent(); parent != nullptr) {
return parent->IsEnabledAccessLog();
} else {
return false;
}
}
bool IsEnabledHandleAccessLog(fs::impl::IdentifyAccessLogHandle handle) {
return true;
}
bool IsEnabledHandleAccessLog(const void *handle) {
if (handle == nullptr) {
return true;
}
/* We should never receive non-null here. */
AMS_ASSERT(handle == nullptr);
return false;
}
bool IsEnabledFileSystemAccessorAccessLog(const char *mount_name) {
/* Get the accessor. */
impl::FileSystemAccessor *accessor;
if (R_FAILED(impl::Find(std::addressof(accessor), mount_name))) {
return true;
}
return accessor->IsEnabledAccessLog();
}
void EnableFileSystemAccessorAccessLog(const char *mount_name) {
/* Get the accessor. */
impl::FileSystemAccessor *accessor;
AMS_FS_R_ABORT_UNLESS(impl::Find(std::addressof(accessor), mount_name));
accessor->SetAccessLogEnabled(true);
}
}

View file

@ -0,0 +1,74 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stratosphere.hpp>
namespace ams::fs {
namespace {
constinit bool g_auto_abort_enabled = true;
/* NOTE: This generates a global constructor. */
os::SdkThreadLocalStorage g_context_tls;
}
void SetEnabledAutoAbort(bool enabled) {
g_auto_abort_enabled = enabled;
}
AbortSpecifier DefaultResultHandler(Result result) {
if (g_auto_abort_enabled) {
return AbortSpecifier::Default;
} else {
return AbortSpecifier::Return;
}
}
AbortSpecifier AlwaysReturnResultHandler(Result result) {
return AbortSpecifier::Return;
}
constinit FsContext g_default_context(DefaultResultHandler);
constinit FsContext g_always_return_context(AlwaysReturnResultHandler);
void SetDefaultFsContextResultHandler(const ResultHandler handler) {
if (handler == nullptr) {
g_default_context.SetHandler(DefaultResultHandler);
} else {
g_default_context.SetHandler(handler);
}
}
const FsContext *GetCurrentThreadFsContext() {
const FsContext *context = reinterpret_cast<const FsContext *>(g_context_tls.GetValue());
if (context == nullptr) {
context = std::addressof(g_default_context);
}
return context;
}
void SetCurrentThreadFsContext(const FsContext *context) {
g_context_tls.SetValue(reinterpret_cast<uintptr_t>(context));
}
ScopedAutoAbortDisabler::ScopedAutoAbortDisabler() : prev_context(GetCurrentThreadFsContext()) {
SetCurrentThreadFsContext(std::addressof(g_always_return_context));
}
}

View file

@ -0,0 +1,160 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stratosphere.hpp>
namespace ams::fs {
namespace {
constexpr bool IsValidPriority(fs::Priority priority) {
return priority == Priority_Low || priority == Priority_Normal || priority == Priority_Realtime;
}
constexpr bool IsValidPriorityRaw(fs::PriorityRaw priority_raw) {
return priority_raw == PriorityRaw_Background || priority_raw == PriorityRaw_Low || priority_raw == PriorityRaw_Normal || priority_raw == PriorityRaw_Realtime;
}
fs::PriorityRaw ConvertPriorityToPriorityRaw(fs::Priority priority) {
AMS_ASSERT(IsValidPriority(priority));
switch (priority) {
case Priority_Low: return PriorityRaw_Low;
case Priority_Normal: return PriorityRaw_Normal;
case Priority_Realtime: return PriorityRaw_Realtime;
AMS_UNREACHABLE_DEFAULT_CASE();
}
}
fs::Priority ConvertPriorityRawToPriority(fs::PriorityRaw priority_raw) {
AMS_ASSERT(IsValidPriorityRaw(priority_raw));
switch (priority_raw) {
case PriorityRaw_Background: return Priority_Low;
case PriorityRaw_Low: return Priority_Low;
case PriorityRaw_Normal: return Priority_Normal;
case PriorityRaw_Realtime: return Priority_Realtime;
AMS_UNREACHABLE_DEFAULT_CASE();
}
}
void UpdateTlsIoPriority(os::ThreadType *thread, u8 tls_io) {
sf::SetFsInlineContext(thread, (tls_io & impl::TlsIoPriorityMask) | (sf::GetFsInlineContext(thread) & ~impl::TlsIoPriorityMask));
}
Result GetPriorityRawImpl(fs::PriorityRaw *out, os::ThreadType *thread) {
/* Validate arguments. */
R_UNLESS(thread != nullptr, fs::ResultNullptrArgument());
/* Get the raw priority. */
PriorityRaw priority_raw;
R_TRY(impl::ConvertTlsIoPriorityToFsPriority(std::addressof(priority_raw), impl::GetTlsIoPriority(thread)));
/* Set output. */
*out = priority_raw;
return ResultSuccess();
}
Result GetPriorityImpl(fs::Priority *out, os::ThreadType *thread) {
/* Validate arguments. */
R_UNLESS(thread != nullptr, fs::ResultNullptrArgument());
/* Get the raw priority. */
PriorityRaw priority_raw;
R_TRY(impl::ConvertTlsIoPriorityToFsPriority(std::addressof(priority_raw), impl::GetTlsIoPriority(thread)));
/* Set output. */
*out = ConvertPriorityRawToPriority(priority_raw);
return ResultSuccess();
}
Result SetPriorityRawImpl(os::ThreadType *thread, fs::PriorityRaw priority_raw) {
/* Validate arguments. */
R_UNLESS(thread != nullptr, fs::ResultNullptrArgument());
R_UNLESS(IsValidPriorityRaw(priority_raw), fs::ResultInvalidArgument());
/* Convert to tls io. */
u8 tls_io;
R_TRY(impl::ConvertFsPriorityToTlsIoPriority(std::addressof(tls_io), priority_raw));
/* Update the priority. */
UpdateTlsIoPriority(thread, tls_io);
return ResultSuccess();
}
Result SetPriorityImpl(os::ThreadType *thread, fs::Priority priority) {
/* Validate arguments. */
R_UNLESS(thread != nullptr, fs::ResultNullptrArgument());
R_UNLESS(IsValidPriority(priority), fs::ResultInvalidArgument());
/* Convert to tls io. */
u8 tls_io;
R_TRY(impl::ConvertFsPriorityToTlsIoPriority(std::addressof(tls_io), ConvertPriorityToPriorityRaw(priority)));
/* Update the priority. */
UpdateTlsIoPriority(thread, tls_io);
return ResultSuccess();
}
}
Priority GetPriorityOnCurrentThread() {
fs::Priority priority;
AMS_FS_R_ABORT_UNLESS(AMS_FS_IMPL_ACCESS_LOG(GetPriorityImpl(std::addressof(priority), os::GetCurrentThread()), nullptr, AMS_FS_IMPL_ACCESS_LOG_FORMAT_NONE));
return priority;
}
Priority GetPriority(os::ThreadType *thread) {
fs::Priority priority;
AMS_FS_R_ABORT_UNLESS(AMS_FS_IMPL_ACCESS_LOG(GetPriorityImpl(std::addressof(priority), thread), nullptr, AMS_FS_IMPL_ACCESS_LOG_FORMAT_THREAD_ID, thread != nullptr ? os::GetThreadId(thread) : static_cast<os::ThreadId>(0)));
return priority;
}
PriorityRaw GetPriorityRawOnCurrentThread() {
fs::PriorityRaw priority_raw;
AMS_FS_R_ABORT_UNLESS(AMS_FS_IMPL_ACCESS_LOG(GetPriorityRawImpl(std::addressof(priority_raw), os::GetCurrentThread()), nullptr, AMS_FS_IMPL_ACCESS_LOG_FORMAT_NONE));
return priority_raw;
}
PriorityRaw GetPriorityRawOnCurrentThreadInternal() {
fs::PriorityRaw priority_raw;
AMS_FS_R_ABORT_UNLESS(GetPriorityRawImpl(std::addressof(priority_raw), os::GetCurrentThread()));
return priority_raw;
}
PriorityRaw GetPriorityRaw(os::ThreadType *thread) {
fs::PriorityRaw priority_raw;
AMS_FS_R_ABORT_UNLESS(AMS_FS_IMPL_ACCESS_LOG(GetPriorityRawImpl(std::addressof(priority_raw), thread), nullptr, AMS_FS_IMPL_ACCESS_LOG_FORMAT_THREAD_ID, thread != nullptr ? os::GetThreadId(thread) : static_cast<os::ThreadId>(0)));
return priority_raw;
}
void SetPriorityOnCurrentThread(Priority priority) {
AMS_FS_R_ABORT_UNLESS(AMS_FS_IMPL_ACCESS_LOG(SetPriorityImpl(os::GetCurrentThread(), priority), nullptr, AMS_FS_IMPL_ACCESS_LOG_FORMAT_NONE));
}
void SetPriority(os::ThreadType *thread, Priority priority) {
AMS_FS_R_ABORT_UNLESS(AMS_FS_IMPL_ACCESS_LOG(SetPriorityImpl(os::GetCurrentThread(), priority), nullptr, AMS_FS_IMPL_ACCESS_LOG_FORMAT_THREAD_ID, thread != nullptr ? os::GetThreadId(thread) : static_cast<os::ThreadId>(0)));
}
void SetPriorityRawOnCurrentThread(PriorityRaw priority_raw) {
AMS_FS_R_ABORT_UNLESS(AMS_FS_IMPL_ACCESS_LOG(SetPriorityRawImpl(os::GetCurrentThread(), priority_raw), nullptr, AMS_FS_IMPL_ACCESS_LOG_FORMAT_NONE));
}
void SetPriorityRaw(os::ThreadType *thread, PriorityRaw priority_raw) {
AMS_FS_R_ABORT_UNLESS(AMS_FS_IMPL_ACCESS_LOG(SetPriorityRawImpl(os::GetCurrentThread(), priority_raw), nullptr, AMS_FS_IMPL_ACCESS_LOG_FORMAT_THREAD_ID, thread != nullptr ? os::GetThreadId(thread) : static_cast<os::ThreadId>(0)));
}
}

View file

@ -0,0 +1,69 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stratosphere.hpp>
namespace ams::fs {
namespace {
constinit bool g_handled_by_application = false;
}
void SetResultHandledByApplication(bool application) {
g_handled_by_application = application;
}
namespace impl {
bool IsAbortNeeded(Result result) {
/* If the result succeeded, we never need to abort. */
if (R_SUCCEEDED(result)) {
return false;
}
/* Get the abort specifier from current context. */
switch (GetCurrentThreadFsContext()->HandleResult(result)) {
case AbortSpecifier::Default:
if (g_handled_by_application) {
return !fs::ResultHandledByAllProcess::Includes(result);
} else {
return !(fs::ResultHandledByAllProcess::Includes(result) || fs::ResultHandledBySystemProcess::Includes(result));
}
case AbortSpecifier::Abort:
return true;
case AbortSpecifier::Return:
return false;
AMS_UNREACHABLE_DEFAULT_CASE();
}
}
void LogResultErrorMessage(Result result) {
/* TODO: log specific results */
}
void LogErrorMessage(Result result, const char *function) {
/* If the result succeeded, there's nothing to log. */
if (R_SUCCEEDED(result)) {
return;
}
/* TODO: Actually log stuff. */
}
}
}

View file

@ -32,7 +32,7 @@ namespace ams::fs::impl {
Result Read(s64 *out_count, DirectoryEntry *out_entries, s64 max_entries); Result Read(s64 *out_count, DirectoryEntry *out_entries, s64 max_entries);
Result GetEntryCount(s64 *out); Result GetEntryCount(s64 *out);
FileSystemAccessor &GetParent() const { return this->parent; } FileSystemAccessor *GetParent() const { return std::addressof(this->parent); }
}; };
} }

View file

@ -71,7 +71,7 @@ namespace ams::fs::impl {
void SetPathBasedFileDataCacheAttachable(bool en) { this->path_cache_attachable = en; } void SetPathBasedFileDataCacheAttachable(bool en) { this->path_cache_attachable = en; }
void SetMultiCommitSupported(bool en) { this->multi_commit_supported = en; } void SetMultiCommitSupported(bool en) { this->multi_commit_supported = en; }
bool IsAccessLogEnabled() const { return this->access_log_enabled; } bool IsEnabledAccessLog() const { return this->access_log_enabled; }
bool IsFileDataCacheAttachable() const { return this->data_cache_attachable; } bool IsFileDataCacheAttachable() const { return this->data_cache_attachable; }
bool IsPathBasedFileDataCacheAttachable() const { return this->path_cache_attachable; } bool IsPathBasedFileDataCacheAttachable() const { return this->path_cache_attachable; }

View file

@ -29,8 +29,8 @@ namespace ams::fs {
Result ReadFile(FileHandle handle, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) { Result ReadFile(FileHandle handle, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) {
size_t read_size; size_t read_size;
R_TRY(ReadFile(std::addressof(read_size), handle, offset, buffer, size, option)); AMS_FS_R_TRY(ReadFile(std::addressof(read_size), handle, offset, buffer, size, option));
R_UNLESS(read_size == size, fs::ResultOutOfRange()); AMS_FS_R_UNLESS(read_size == size, fs::ResultOutOfRange());
return ResultSuccess(); return ResultSuccess();
} }
@ -39,7 +39,8 @@ namespace ams::fs {
} }
Result ReadFile(size_t *out, FileHandle handle, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) { Result ReadFile(size_t *out, FileHandle handle, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) {
return Get(handle)->Read(out, offset, buffer, size, option); AMS_FS_R_TRY(Get(handle)->Read(out, offset, buffer, size, option));
return ResultSuccess();
} }
Result ReadFile(size_t *out, FileHandle handle, s64 offset, void *buffer, size_t size) { Result ReadFile(size_t *out, FileHandle handle, s64 offset, void *buffer, size_t size) {
@ -47,19 +48,23 @@ namespace ams::fs {
} }
Result GetFileSize(s64 *out, FileHandle handle) { Result GetFileSize(s64 *out, FileHandle handle) {
return Get(handle)->GetSize(out); AMS_FS_R_TRY(Get(handle)->GetSize(out));
return ResultSuccess();
} }
Result FlushFile(FileHandle handle) { Result FlushFile(FileHandle handle) {
return Get(handle)->Flush(); AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG(Get(handle)->Flush(), handle, AMS_FS_IMPL_ACCESS_LOG_FORMAT_NONE));
return ResultSuccess();
} }
Result WriteFile(FileHandle handle, s64 offset, const void *buffer, size_t size, const fs::WriteOption &option) { Result WriteFile(FileHandle handle, s64 offset, const void *buffer, size_t size, const fs::WriteOption &option) {
return Get(handle)->Write(offset, buffer, size, option); AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG(Get(handle)->Write(offset, buffer, size, option), handle, AMS_FS_IMPL_ACCESS_LOG_FORMAT_WRITE_FILE(option), offset, size));
return ResultSuccess();
} }
Result SetFileSize(FileHandle handle, s64 size) { Result SetFileSize(FileHandle handle, s64 size) {
return Get(handle)->SetSize(size); AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG(Get(handle)->SetSize(size), handle, AMS_FS_IMPL_ACCESS_LOG_FORMAT_SIZE, size));
return ResultSuccess();
} }
int GetFileOpenMode(FileHandle handle) { int GetFileOpenMode(FileHandle handle) {
@ -67,11 +72,12 @@ namespace ams::fs {
} }
void CloseFile(FileHandle handle) { void CloseFile(FileHandle handle) {
delete Get(handle); AMS_FS_IMPL_ACCESS_LOG((delete Get(handle), ResultSuccess()), handle, AMS_FS_IMPL_ACCESS_LOG_FORMAT_NONE);
} }
Result QueryRange(QueryRangeInfo *out, FileHandle handle, s64 offset, s64 size) { Result QueryRange(QueryRangeInfo *out, FileHandle handle, s64 offset, s64 size) {
return Get(handle)->OperateRange(out, sizeof(*out), OperationId::QueryRange, offset, size, nullptr, 0); AMS_FS_R_TRY(Get(handle)->OperateRange(out, sizeof(*out), OperationId::QueryRange, offset, size, nullptr, 0));
return ResultSuccess();
} }
} }

View file

@ -86,7 +86,7 @@ namespace ams::ncm {
Result ReadVariationContentMetaInfoList(s32 *out_count, std::unique_ptr<ContentMetaInfo[]> *out_meta_infos, const Path &path, FirmwareVariationId firmware_variation_id) { Result ReadVariationContentMetaInfoList(s32 *out_count, std::unique_ptr<ContentMetaInfo[]> *out_meta_infos, const Path &path, FirmwareVariationId firmware_variation_id) {
AutoBuffer meta; AutoBuffer meta;
{ {
/* TODO: fs::ScopedAutoAbortDisabler aad; */ fs::ScopedAutoAbortDisabler aad;
R_TRY(ReadContentMetaPath(std::addressof(meta), path.str)); R_TRY(ReadContentMetaPath(std::addressof(meta), path.str));
} }

View file

@ -1000,7 +1000,7 @@ namespace ams::ncm {
Result InstallTaskBase::GetInstallContentMetaDataFromPath(AutoBuffer *out, const Path &path, const InstallContentInfo &content_info, std::optional<u32> source_version) { Result InstallTaskBase::GetInstallContentMetaDataFromPath(AutoBuffer *out, const Path &path, const InstallContentInfo &content_info, std::optional<u32> source_version) {
AutoBuffer meta; AutoBuffer meta;
{ {
/* TODO: fs::ScopedAutoAbortDisabler aad; */ fs::ScopedAutoAbortDisabler aad;
R_TRY(ReadContentMetaPath(std::addressof(meta), path.str)); R_TRY(ReadContentMetaPath(std::addressof(meta), path.str));
} }

View file

@ -41,6 +41,9 @@ namespace ams::os::impl {
thread->name_buffer[0] = '\x00'; thread->name_buffer[0] = '\x00';
thread->name_pointer = thread->name_buffer; thread->name_pointer = thread->name_buffer;
/* Set internal tls variables. */
thread->atomic_sf_inline_context = 0;
/* Mark initialized. */ /* Mark initialized. */
thread->state = ThreadType::State_Initialized; thread->state = ThreadType::State_Initialized;
} }

View file

@ -0,0 +1,26 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stratosphere.hpp>
namespace ams::os {
/* TODO: Nintendo reserves half the TLS slots for SDK usage. */
/* We don't have that ability...how should this work? */
Result SdkAllocateTlsSlot(TlsSlot *out, TlsDestructor destructor) {
return os::AllocateTlsSlot(out, destructor);
}
}

View file

@ -21,47 +21,74 @@ namespace ams::sf {
namespace { namespace {
thread_local InlineContext g_inline_context; ALWAYS_INLINE std::atomic<uintptr_t> *GetAtomicSfInlineContext(os::ThreadType *thread) {
static_assert(sizeof(thread->atomic_sf_inline_context) >= sizeof(std::atomic<uintptr_t>));
return reinterpret_cast<std::atomic<uintptr_t> *>(std::addressof(thread->atomic_sf_inline_context));
}
ALWAYS_INLINE void OnSetInlineContext() { ALWAYS_INLINE std::atomic<uintptr_t> *GetAtomicSfInlineContext() {
return GetAtomicSfInlineContext(os::GetCurrentThread());
}
ALWAYS_INLINE void OnSetInlineContext(os::ThreadType *thread) {
/* Ensure that libnx receives the priority value. */ /* Ensure that libnx receives the priority value. */
::fsSetPriority(static_cast<::FsPriority>(::ams::sf::GetFsInlineContext())); ::fsSetPriority(static_cast<::FsPriority>(::ams::sf::GetFsInlineContext(thread)));
} }
} }
InlineContext GetInlineContext() { InlineContext GetInlineContext() {
/* Get current thread. */
os::ThreadType * const cur_thread = os::GetCurrentThread();
/* Get the context. */
uintptr_t thread_context = GetAtomicSfInlineContext()->load();
/* Copy it out. */
InlineContext ctx; InlineContext ctx;
std::memcpy(std::addressof(ctx), std::addressof(::ams::sf::cmif::g_inline_context), sizeof(ctx)); static_assert(sizeof(ctx) <= sizeof(thread_context));
std::memcpy(std::addressof(ctx), std::addressof(thread_context), sizeof(ctx));
return ctx; return ctx;
} }
InlineContext SetInlineContext(InlineContext ctx) { InlineContext SetInlineContext(InlineContext ctx) {
ON_SCOPE_EXIT { OnSetInlineContext(); }; /* Get current thread. */
static_assert(sizeof(ctx) <= sizeof(g_inline_context)); os::ThreadType * const cur_thread = os::GetCurrentThread();
ON_SCOPE_EXIT { OnSetInlineContext(cur_thread); };
/* Create the new context. */
static_assert(sizeof(ctx) <= sizeof(uintptr_t));
uintptr_t new_context_value = 0;
std::memcpy(std::addressof(new_context_value), std::addressof(ctx), sizeof(ctx));
/* Get the old context. */
uintptr_t old_context_value = GetAtomicSfInlineContext()->exchange(new_context_value);
/* Convert and copy it out. */
InlineContext old_ctx; InlineContext old_ctx;
std::memcpy(std::addressof(old_ctx), std::addressof(g_inline_context), sizeof(old_ctx)); std::memcpy(std::addressof(old_ctx), std::addressof(old_context_value), sizeof(old_ctx));
std::memcpy(std::addressof(g_inline_context), std::addressof(ctx), sizeof(ctx));
return old_ctx; return old_ctx;
} }
} }
u8 GetFsInlineContext() { namespace {
u8 ctx;
std::memcpy(std::addressof(ctx), std::addressof(cmif::g_inline_context), sizeof(ctx));
return ctx;
}
u8 SetFsInlineContext(u8 ctx) { ALWAYS_INLINE std::atomic<u8> *GetAtomicFsInlineContext(os::ThreadType *thread) {
ON_SCOPE_EXIT { cmif::OnSetInlineContext(); }; static_assert(sizeof(thread->atomic_sf_inline_context) >= sizeof(std::atomic<u8>));
static_assert(sizeof(ctx) <= sizeof(cmif::g_inline_context)); return reinterpret_cast<std::atomic<u8> *>(std::addressof(thread->atomic_sf_inline_context));
}
u8 old_ctx;
std::memcpy(std::addressof(old_ctx), std::addressof(cmif::g_inline_context), sizeof(old_ctx)); }
std::memcpy(std::addressof(cmif::g_inline_context), std::addressof(ctx), sizeof(ctx));
return old_ctx; u8 GetFsInlineContext(os::ThreadType *thread) {
return GetAtomicFsInlineContext(thread)->load();
}
u8 SetFsInlineContext(os::ThreadType *thread, u8 ctx) {
ON_SCOPE_EXIT { cmif::OnSetInlineContext(thread); };
return GetAtomicFsInlineContext(thread)->exchange(ctx);
} }
} }

View file

@ -40,6 +40,9 @@
#define BITSIZEOF(x) (sizeof(x) * CHAR_BIT) #define BITSIZEOF(x) (sizeof(x) * CHAR_BIT)
#define STRINGIZE(x) STRINGIZE_IMPL(x)
#define STRINGIZE_IMPL(x) #x
#ifdef __COUNTER__ #ifdef __COUNTER__
#define ANONYMOUS_VARIABLE(pref) CONCATENATE(pref, __COUNTER__) #define ANONYMOUS_VARIABLE(pref) CONCATENATE(pref, __COUNTER__)
#else #else

View file

@ -25,6 +25,7 @@
#include <cstring> #include <cstring>
#include <climits> #include <climits>
#include <cctype> #include <cctype>
#include <cinttypes>
/* C++ headers. */ /* C++ headers. */
#include <type_traits> #include <type_traits>

View file

@ -21,6 +21,7 @@ namespace ams::fs {
R_DEFINE_NAMESPACE_RESULT_MODULE(2); R_DEFINE_NAMESPACE_RESULT_MODULE(2);
R_DEFINE_ERROR_RANGE(HandledByAllProcess, 0, 999);
R_DEFINE_ERROR_RESULT(PathNotFound, 1); R_DEFINE_ERROR_RESULT(PathNotFound, 1);
R_DEFINE_ERROR_RESULT(PathAlreadyExists, 2); R_DEFINE_ERROR_RESULT(PathAlreadyExists, 2);
@ -39,6 +40,7 @@ namespace ams::fs {
R_DEFINE_ERROR_RESULT(MountNameAlreadyExists, 60); R_DEFINE_ERROR_RESULT(MountNameAlreadyExists, 60);
R_DEFINE_ERROR_RANGE(HandledBySystemProcess, 1000, 2999);
R_DEFINE_ERROR_RESULT(PartitionNotFound, 1001); R_DEFINE_ERROR_RESULT(PartitionNotFound, 1001);
R_DEFINE_ERROR_RESULT(TargetNotFound, 1002); R_DEFINE_ERROR_RESULT(TargetNotFound, 1002);
@ -116,6 +118,7 @@ namespace ams::fs {
R_DEFINE_ERROR_RESULT(AllocationFailureInAllocateShared, 3423); R_DEFINE_ERROR_RESULT(AllocationFailureInAllocateShared, 3423);
R_DEFINE_ERROR_RESULT(AllocationFailurePooledBufferNotEnoughSize, 3424); R_DEFINE_ERROR_RESULT(AllocationFailurePooledBufferNotEnoughSize, 3424);
R_DEFINE_ERROR_RANGE(Internal, 3000, 7999);
R_DEFINE_ERROR_RANGE(MmcAccessFailed, 3500, 3999); R_DEFINE_ERROR_RANGE(MmcAccessFailed, 3500, 3999);
R_DEFINE_ERROR_RANGE(DataCorrupted, 4000, 4999); R_DEFINE_ERROR_RANGE(DataCorrupted, 4000, 4999);

View file

@ -86,6 +86,9 @@ void __appInit(void) {
spl::InitializeForFs(); spl::InitializeForFs();
}); });
/* Disable auto-abort in fs operations. */
fs::SetEnabledAutoAbort(false);
/* Initialize fssystem library. */ /* Initialize fssystem library. */
fssystem::InitializeForFileSystemProxy(); fssystem::InitializeForFileSystemProxy();

View file

@ -142,6 +142,9 @@ namespace {
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
/* Disable auto-abort in fs operations. */
fs::SetEnabledAutoAbort(false);
/* Set thread name. */ /* Set thread name. */
os::SetThreadNamePointer(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_NAME(fatal, Main)); os::SetThreadNamePointer(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_NAME(fatal, Main));
AMS_ASSERT(os::GetThreadPriority(os::GetCurrentThread()) == AMS_GET_SYSTEM_THREAD_PRIORITY(fatal, Main)); AMS_ASSERT(os::GetThreadPriority(os::GetCurrentThread()) == AMS_GET_SYSTEM_THREAD_PRIORITY(fatal, Main));

View file

@ -115,6 +115,9 @@ namespace {
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
/* Disable auto-abort in fs operations. */
fs::SetEnabledAutoAbort(false);
/* Set thread name. */ /* Set thread name. */
os::SetThreadNamePointer(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_NAME(ldr, Main)); os::SetThreadNamePointer(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_NAME(ldr, Main));
AMS_ASSERT(os::GetThreadPriority(os::GetCurrentThread()) == AMS_GET_SYSTEM_THREAD_PRIORITY(ldr, Main)); AMS_ASSERT(os::GetThreadPriority(os::GetCurrentThread()) == AMS_GET_SYSTEM_THREAD_PRIORITY(ldr, Main));

View file

@ -262,6 +262,9 @@ namespace {
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
/* Disable auto-abort in fs operations. */
fs::SetEnabledAutoAbort(false);
/* Set thread name. */ /* Set thread name. */
os::SetThreadNamePointer(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_NAME(ncm, MainWaitThreads)); os::SetThreadNamePointer(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_NAME(ncm, MainWaitThreads));
AMS_ASSERT(os::GetThreadPriority(os::GetCurrentThread()) == AMS_GET_SYSTEM_THREAD_PRIORITY(ncm, MainWaitThreads)); AMS_ASSERT(os::GetThreadPriority(os::GetCurrentThread()) == AMS_GET_SYSTEM_THREAD_PRIORITY(ncm, MainWaitThreads));

View file

@ -145,6 +145,9 @@ void __appExit(void) {
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
/* Disable auto-abort in fs operations. */
fs::SetEnabledAutoAbort(false);
/* Set thread name. */ /* Set thread name. */
os::SetThreadNamePointer(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_NAME(pgl, Main)); os::SetThreadNamePointer(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_NAME(pgl, Main));
AMS_ASSERT(os::GetThreadPriority(os::GetCurrentThread()) == AMS_GET_SYSTEM_THREAD_PRIORITY(pgl, Main)); AMS_ASSERT(os::GetThreadPriority(os::GetCurrentThread()) == AMS_GET_SYSTEM_THREAD_PRIORITY(pgl, Main));