mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 20:31:14 +00:00
fs: implement AccessLog, enable for File operations
This commit is contained in:
parent
3fe7700e5c
commit
c6a0d88a76
36 changed files with 1930 additions and 362 deletions
|
@ -19,7 +19,7 @@ export ATMOSPHERE_DEFINES := -DATMOSPHERE
|
|||
export ATMOSPHERE_SETTINGS := -fPIE -g
|
||||
export ATMOSPHERE_CFLAGS := -Wall -ffunction-sections -fdata-sections -fno-strict-aliasing -fwrapv \
|
||||
-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_ASFLAGS :=
|
||||
|
|
|
@ -16,7 +16,13 @@
|
|||
|
||||
#pragma once
|
||||
#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_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_idirectory.hpp>
|
||||
#include <stratosphere/fs/fsa/fs_ifilesystem.hpp>
|
||||
|
@ -54,3 +60,4 @@
|
|||
#include <stratosphere/fs/fs_sd_card.hpp>
|
||||
#include <stratosphere/fs/fs_signed_system_partition.hpp>
|
||||
#include <stratosphere/fs/fs_system_data.hpp>
|
||||
#include <stratosphere/fs/impl/fs_access_log_impl.hpp>
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
|
@ -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);
|
||||
|
||||
}
|
|
@ -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);
|
||||
|
||||
}
|
|
@ -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__)
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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); \
|
||||
} \
|
||||
} \
|
||||
})
|
|
@ -35,7 +35,8 @@
|
|||
#include <stratosphere/os/os_system_event.hpp>
|
||||
#include <stratosphere/os/os_interrupt_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_message_queue.hpp>
|
||||
#include <stratosphere/os/os_waitable.hpp>
|
||||
|
|
|
@ -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; }
|
||||
};
|
||||
|
||||
}
|
|
@ -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);
|
||||
|
||||
}
|
|
@ -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; }
|
||||
};
|
||||
|
||||
}
|
|
@ -57,6 +57,12 @@ namespace ams::os {
|
|||
size_t stack_size;
|
||||
ThreadFunction function;
|
||||
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::InternalConditionVariableStorage cv_thread;
|
||||
|
||||
|
|
|
@ -17,9 +17,15 @@
|
|||
#pragma once
|
||||
#include <stratosphere/sf/sf_common.hpp>
|
||||
|
||||
namespace ams::sf {
|
||||
namespace ams::os {
|
||||
|
||||
u8 GetFsInlineContext();
|
||||
u8 SetFsInlineContext(u8 ctx);
|
||||
struct ThreadType;
|
||||
|
||||
}
|
||||
|
||||
namespace ams::sf {
|
||||
|
||||
u8 GetFsInlineContext(os::ThreadType *thread);
|
||||
u8 SetFsInlineContext(os::ThreadType *thread, u8 ctx);
|
||||
|
||||
}
|
||||
|
|
528
libraries/libstratosphere/source/fs/fs_access_log.cpp
Normal file
528
libraries/libstratosphere/source/fs/fs_access_log.cpp
Normal 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);
|
||||
}
|
||||
|
||||
}
|
74
libraries/libstratosphere/source/fs/fs_context.cpp
Normal file
74
libraries/libstratosphere/source/fs/fs_context.cpp
Normal 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));
|
||||
}
|
||||
|
||||
}
|
160
libraries/libstratosphere/source/fs/fs_priority.cpp
Normal file
160
libraries/libstratosphere/source/fs/fs_priority.cpp
Normal 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)));
|
||||
}
|
||||
|
||||
}
|
69
libraries/libstratosphere/source/fs/fs_result_utils.cpp
Normal file
69
libraries/libstratosphere/source/fs/fs_result_utils.cpp
Normal 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. */
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -32,7 +32,7 @@ namespace ams::fs::impl {
|
|||
Result Read(s64 *out_count, DirectoryEntry *out_entries, s64 max_entries);
|
||||
Result GetEntryCount(s64 *out);
|
||||
|
||||
FileSystemAccessor &GetParent() const { return this->parent; }
|
||||
FileSystemAccessor *GetParent() const { return std::addressof(this->parent); }
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -71,7 +71,7 @@ namespace ams::fs::impl {
|
|||
void SetPathBasedFileDataCacheAttachable(bool en) { this->path_cache_attachable = 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 IsPathBasedFileDataCacheAttachable() const { return this->path_cache_attachable; }
|
||||
|
||||
|
|
|
@ -29,8 +29,8 @@ namespace ams::fs {
|
|||
|
||||
Result ReadFile(FileHandle handle, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) {
|
||||
size_t read_size;
|
||||
R_TRY(ReadFile(std::addressof(read_size), handle, offset, buffer, size, option));
|
||||
R_UNLESS(read_size == size, fs::ResultOutOfRange());
|
||||
AMS_FS_R_TRY(ReadFile(std::addressof(read_size), handle, offset, buffer, size, option));
|
||||
AMS_FS_R_UNLESS(read_size == size, fs::ResultOutOfRange());
|
||||
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) {
|
||||
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) {
|
||||
|
@ -47,19 +48,23 @@ namespace ams::fs {
|
|||
}
|
||||
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
|
@ -67,11 +72,12 @@ namespace ams::fs {
|
|||
}
|
||||
|
||||
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) {
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
AutoBuffer meta;
|
||||
{
|
||||
/* TODO: fs::ScopedAutoAbortDisabler aad; */
|
||||
fs::ScopedAutoAbortDisabler aad;
|
||||
R_TRY(ReadContentMetaPath(std::addressof(meta), path.str));
|
||||
}
|
||||
|
||||
|
|
|
@ -1000,7 +1000,7 @@ namespace ams::ncm {
|
|||
Result InstallTaskBase::GetInstallContentMetaDataFromPath(AutoBuffer *out, const Path &path, const InstallContentInfo &content_info, std::optional<u32> source_version) {
|
||||
AutoBuffer meta;
|
||||
{
|
||||
/* TODO: fs::ScopedAutoAbortDisabler aad; */
|
||||
fs::ScopedAutoAbortDisabler aad;
|
||||
R_TRY(ReadContentMetaPath(std::addressof(meta), path.str));
|
||||
}
|
||||
|
||||
|
|
|
@ -41,6 +41,9 @@ namespace ams::os::impl {
|
|||
thread->name_buffer[0] = '\x00';
|
||||
thread->name_pointer = thread->name_buffer;
|
||||
|
||||
/* Set internal tls variables. */
|
||||
thread->atomic_sf_inline_context = 0;
|
||||
|
||||
/* Mark initialized. */
|
||||
thread->state = ThreadType::State_Initialized;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -21,47 +21,74 @@ namespace ams::sf {
|
|||
|
||||
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. */
|
||||
::fsSetPriority(static_cast<::FsPriority>(::ams::sf::GetFsInlineContext()));
|
||||
::fsSetPriority(static_cast<::FsPriority>(::ams::sf::GetFsInlineContext(thread)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
InlineContext SetInlineContext(InlineContext ctx) {
|
||||
ON_SCOPE_EXIT { OnSetInlineContext(); };
|
||||
static_assert(sizeof(ctx) <= sizeof(g_inline_context));
|
||||
/* Get current thread. */
|
||||
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;
|
||||
std::memcpy(std::addressof(old_ctx), std::addressof(g_inline_context), sizeof(old_ctx));
|
||||
std::memcpy(std::addressof(g_inline_context), std::addressof(ctx), sizeof(ctx));
|
||||
std::memcpy(std::addressof(old_ctx), std::addressof(old_context_value), sizeof(old_ctx));
|
||||
return old_ctx;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
u8 GetFsInlineContext() {
|
||||
u8 ctx;
|
||||
std::memcpy(std::addressof(ctx), std::addressof(cmif::g_inline_context), sizeof(ctx));
|
||||
return ctx;
|
||||
}
|
||||
namespace {
|
||||
|
||||
u8 SetFsInlineContext(u8 ctx) {
|
||||
ON_SCOPE_EXIT { cmif::OnSetInlineContext(); };
|
||||
static_assert(sizeof(ctx) <= sizeof(cmif::g_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;
|
||||
ALWAYS_INLINE std::atomic<u8> *GetAtomicFsInlineContext(os::ThreadType *thread) {
|
||||
static_assert(sizeof(thread->atomic_sf_inline_context) >= sizeof(std::atomic<u8>));
|
||||
return reinterpret_cast<std::atomic<u8> *>(std::addressof(thread->atomic_sf_inline_context));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -40,6 +40,9 @@
|
|||
|
||||
#define BITSIZEOF(x) (sizeof(x) * CHAR_BIT)
|
||||
|
||||
#define STRINGIZE(x) STRINGIZE_IMPL(x)
|
||||
#define STRINGIZE_IMPL(x) #x
|
||||
|
||||
#ifdef __COUNTER__
|
||||
#define ANONYMOUS_VARIABLE(pref) CONCATENATE(pref, __COUNTER__)
|
||||
#else
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <cstring>
|
||||
#include <climits>
|
||||
#include <cctype>
|
||||
#include <cinttypes>
|
||||
|
||||
/* C++ headers. */
|
||||
#include <type_traits>
|
||||
|
|
|
@ -21,6 +21,7 @@ namespace ams::fs {
|
|||
|
||||
R_DEFINE_NAMESPACE_RESULT_MODULE(2);
|
||||
|
||||
R_DEFINE_ERROR_RANGE(HandledByAllProcess, 0, 999);
|
||||
R_DEFINE_ERROR_RESULT(PathNotFound, 1);
|
||||
R_DEFINE_ERROR_RESULT(PathAlreadyExists, 2);
|
||||
|
||||
|
@ -39,6 +40,7 @@ namespace ams::fs {
|
|||
|
||||
R_DEFINE_ERROR_RESULT(MountNameAlreadyExists, 60);
|
||||
|
||||
R_DEFINE_ERROR_RANGE(HandledBySystemProcess, 1000, 2999);
|
||||
R_DEFINE_ERROR_RESULT(PartitionNotFound, 1001);
|
||||
R_DEFINE_ERROR_RESULT(TargetNotFound, 1002);
|
||||
|
||||
|
@ -116,6 +118,7 @@ namespace ams::fs {
|
|||
R_DEFINE_ERROR_RESULT(AllocationFailureInAllocateShared, 3423);
|
||||
R_DEFINE_ERROR_RESULT(AllocationFailurePooledBufferNotEnoughSize, 3424);
|
||||
|
||||
R_DEFINE_ERROR_RANGE(Internal, 3000, 7999);
|
||||
R_DEFINE_ERROR_RANGE(MmcAccessFailed, 3500, 3999);
|
||||
|
||||
R_DEFINE_ERROR_RANGE(DataCorrupted, 4000, 4999);
|
||||
|
|
|
@ -86,6 +86,9 @@ void __appInit(void) {
|
|||
spl::InitializeForFs();
|
||||
});
|
||||
|
||||
/* Disable auto-abort in fs operations. */
|
||||
fs::SetEnabledAutoAbort(false);
|
||||
|
||||
/* Initialize fssystem library. */
|
||||
fssystem::InitializeForFileSystemProxy();
|
||||
|
||||
|
|
|
@ -142,6 +142,9 @@ namespace {
|
|||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
/* Disable auto-abort in fs operations. */
|
||||
fs::SetEnabledAutoAbort(false);
|
||||
|
||||
/* Set thread name. */
|
||||
os::SetThreadNamePointer(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_NAME(fatal, Main));
|
||||
AMS_ASSERT(os::GetThreadPriority(os::GetCurrentThread()) == AMS_GET_SYSTEM_THREAD_PRIORITY(fatal, Main));
|
||||
|
|
|
@ -115,6 +115,9 @@ namespace {
|
|||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
/* Disable auto-abort in fs operations. */
|
||||
fs::SetEnabledAutoAbort(false);
|
||||
|
||||
/* Set thread name. */
|
||||
os::SetThreadNamePointer(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_NAME(ldr, Main));
|
||||
AMS_ASSERT(os::GetThreadPriority(os::GetCurrentThread()) == AMS_GET_SYSTEM_THREAD_PRIORITY(ldr, Main));
|
||||
|
|
|
@ -262,6 +262,9 @@ namespace {
|
|||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
/* Disable auto-abort in fs operations. */
|
||||
fs::SetEnabledAutoAbort(false);
|
||||
|
||||
/* Set thread name. */
|
||||
os::SetThreadNamePointer(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_NAME(ncm, MainWaitThreads));
|
||||
AMS_ASSERT(os::GetThreadPriority(os::GetCurrentThread()) == AMS_GET_SYSTEM_THREAD_PRIORITY(ncm, MainWaitThreads));
|
||||
|
|
|
@ -145,6 +145,9 @@ void __appExit(void) {
|
|||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
/* Disable auto-abort in fs operations. */
|
||||
fs::SetEnabledAutoAbort(false);
|
||||
|
||||
/* Set thread name. */
|
||||
os::SetThreadNamePointer(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_NAME(pgl, Main));
|
||||
AMS_ASSERT(os::GetThreadPriority(os::GetCurrentThread()) == AMS_GET_SYSTEM_THREAD_PRIORITY(pgl, Main));
|
||||
|
|
Loading…
Reference in a new issue