mirror of
https://github.com/AxioDL/logvisor.git
synced 2025-12-08 13:15:09 +00:00
Compare commits
9 Commits
8c2e711362
...
libbacktra
| Author | SHA1 | Date | |
|---|---|---|---|
| 22e14d760a | |||
| 81fb4e4c2d | |||
|
|
7f63cabaea | ||
| 41432143fd | |||
|
|
14ea54f8b5 | ||
|
|
d62b4ce26e | ||
|
|
27814c5276 | ||
|
|
f04a9777eb | ||
|
|
187c35f3c4 |
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -1,3 +1,6 @@
|
|||||||
[submodule "fmt"]
|
[submodule "fmt"]
|
||||||
path = fmt
|
path = fmt
|
||||||
url = https://github.com/fmtlib/fmt
|
url = https://github.com/fmtlib/fmt
|
||||||
|
[submodule "libbacktrace"]
|
||||||
|
path = libbacktrace
|
||||||
|
url = https://github.com/status-im/libbacktrace.git
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
|
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
|
||||||
cmake_minimum_required(VERSION 3.10 FATAL_ERROR) # because of c++17
|
cmake_minimum_required(VERSION 3.10 FATAL_ERROR) # because of c++17
|
||||||
project(nod VERSION 0.1)
|
project(nod VERSION 0.1)
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
if (NOT MSVC)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
include (CMakePackageConfigHelpers)
|
include (CMakePackageConfigHelpers)
|
||||||
@@ -13,11 +15,41 @@ add_library(logvisor
|
|||||||
lib/logvisor.cpp
|
lib/logvisor.cpp
|
||||||
include/logvisor/logvisor.hpp)
|
include/logvisor/logvisor.hpp)
|
||||||
|
|
||||||
target_link_libraries(logvisor PUBLIC ${CMAKE_DL_LIBS} fmt)
|
if(APPLE OR UNIX)
|
||||||
|
include(ExternalProject)
|
||||||
|
find_package(Git REQUIRED)
|
||||||
|
find_program(MAKE_EXE NAMES gmake make)
|
||||||
|
ExternalProject_Add(
|
||||||
|
project_libbacktrace
|
||||||
|
PREFIX ${PROJECT_BINARY_DIR}/libbacktrace
|
||||||
|
GIT_REPOSITORY https://github.com/status-im/libbacktrace.git
|
||||||
|
GIT_TAG 2e878a38dd7144c84b665019b1085ea38ebe56d1
|
||||||
|
CONFIGURE_COMMAND ${PROJECT_BINARY_DIR}/libbacktrace/src/project_libbacktrace/configure --enable-host-shared --prefix=${PROJECT_BINARY_DIR}/libbacktrace/install --enable-shared=no --enable-static=yes
|
||||||
|
BUILD_COMMAND ${MAKE_EXE}
|
||||||
|
INSTALL_COMMAND ${MAKE_EXE} install
|
||||||
|
BUILD_IN_SOURCE 1
|
||||||
|
)
|
||||||
|
add_library(libbacktrace STATIC IMPORTED GLOBAL)
|
||||||
|
set_target_properties(libbacktrace PROPERTIES IMPORTED_LOCATION "${PROJECT_BINARY_DIR}/libbacktrace/install/lib/libbacktrace.a")
|
||||||
|
set_target_properties(libbacktrace PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${PROJECT_BINARY_DIR}/libbacktrace/install/include")
|
||||||
|
# Hack for INTERFACE_INCLUDE_DIRECTORIES propagation
|
||||||
|
# https://gitlab.kitware.com/cmake/cmake/-/issues/15052
|
||||||
|
file(MAKE_DIRECTORY "${PROJECT_BINARY_DIR}/libbacktrace/install/include")
|
||||||
|
add_dependencies(libbacktrace project_libbacktrace)
|
||||||
|
set(BACKTRACE_LIBS libbacktrace)
|
||||||
|
else()
|
||||||
|
set(BACKTRACE_LIBS "")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
target_link_libraries(logvisor PUBLIC fmt)
|
||||||
|
if(NX)
|
||||||
|
target_link_libraries(logvisor PUBLIC debug nxd optimized nx)
|
||||||
|
else()
|
||||||
|
target_link_libraries(logvisor PRIVATE ${CMAKE_DL_LIBS} ${BACKTRACE_LIBS})
|
||||||
|
endif()
|
||||||
target_include_directories(logvisor PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
|
target_include_directories(logvisor PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
|
||||||
|
|
||||||
install(DIRECTORY include/logvisor DESTINATION include)
|
install(DIRECTORY include/logvisor DESTINATION include)
|
||||||
install(DIRECTORY fmt/include/fmt DESTINATION include)
|
install(DIRECTORY fmt/include/fmt DESTINATION include)
|
||||||
|
|
||||||
set(version_config_file "${PROJECT_BINARY_DIR}/logvisorConfigVersion.cmake")
|
set(version_config_file "${PROJECT_BINARY_DIR}/logvisorConfigVersion.cmake")
|
||||||
|
|||||||
2
fmt
2
fmt
Submodule fmt updated: 25ff2efc0a...9bdd1596ce
@@ -10,11 +10,10 @@
|
|||||||
|
|
||||||
#define FMT_STRING_ALIAS 1
|
#define FMT_STRING_ALIAS 1
|
||||||
#define FMT_ENFORCE_COMPILE_STRING 1
|
#define FMT_ENFORCE_COMPILE_STRING 1
|
||||||
#define FMT_USE_GRISU 0
|
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
|
||||||
#ifdef __SWITCH__
|
#if defined(__SWITCH__) && !defined(LOGVISOR_NX_LM)
|
||||||
#include "nxstl/mutex"
|
#define LOGVISOR_NX_LM 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern "C" void logvisorBp();
|
extern "C" void logvisorBp();
|
||||||
@@ -264,7 +263,7 @@ struct formatter<tp, char> { \
|
|||||||
constexpr auto parse(ParseContext &ctx) { return ctx.begin(); } \
|
constexpr auto parse(ParseContext &ctx) { return ctx.begin(); } \
|
||||||
template <typename FormatContext> \
|
template <typename FormatContext> \
|
||||||
auto format(const tp &obj, FormatContext &ctx) { \
|
auto format(const tp &obj, FormatContext &ctx) { \
|
||||||
return format_to(ctx.out(), fmt(fmtstr), __VA_ARGS__); \
|
return format_to(ctx.out(), FMT_STRING(fmtstr), __VA_ARGS__); \
|
||||||
} \
|
} \
|
||||||
}; \
|
}; \
|
||||||
template <> \
|
template <> \
|
||||||
@@ -273,7 +272,7 @@ struct formatter<tp, wchar_t> { \
|
|||||||
constexpr auto parse(ParseContext &ctx) { return ctx.begin(); } \
|
constexpr auto parse(ParseContext &ctx) { return ctx.begin(); } \
|
||||||
template <typename FormatContext> \
|
template <typename FormatContext> \
|
||||||
auto format(const tp &obj, FormatContext &ctx) { \
|
auto format(const tp &obj, FormatContext &ctx) { \
|
||||||
return format_to(ctx.out(), fmt(L##fmtstr), __VA_ARGS__); \
|
return format_to(ctx.out(), FMT_STRING(L##fmtstr), __VA_ARGS__); \
|
||||||
} \
|
} \
|
||||||
}; \
|
}; \
|
||||||
template <> \
|
template <> \
|
||||||
@@ -282,7 +281,7 @@ struct formatter<tp, char16_t> { \
|
|||||||
constexpr auto parse(ParseContext &ctx) { return ctx.begin(); } \
|
constexpr auto parse(ParseContext &ctx) { return ctx.begin(); } \
|
||||||
template <typename FormatContext> \
|
template <typename FormatContext> \
|
||||||
auto format(const tp &obj, FormatContext &ctx) { \
|
auto format(const tp &obj, FormatContext &ctx) { \
|
||||||
return format_to(ctx.out(), fmt(u##fmtstr), __VA_ARGS__); \
|
return format_to(ctx.out(), FMT_STRING(u##fmtstr), __VA_ARGS__); \
|
||||||
} \
|
} \
|
||||||
}; \
|
}; \
|
||||||
template <> \
|
template <> \
|
||||||
@@ -291,9 +290,17 @@ struct formatter<tp, char32_t> { \
|
|||||||
constexpr auto parse(ParseContext &ctx) { return ctx.begin(); } \
|
constexpr auto parse(ParseContext &ctx) { return ctx.begin(); } \
|
||||||
template <typename FormatContext> \
|
template <typename FormatContext> \
|
||||||
auto format(const tp &obj, FormatContext &ctx) { \
|
auto format(const tp &obj, FormatContext &ctx) { \
|
||||||
return format_to(ctx.out(), fmt(U##fmtstr), __VA_ARGS__); \
|
return format_to(ctx.out(), FMT_STRING(U##fmtstr), __VA_ARGS__); \
|
||||||
} \
|
} \
|
||||||
}; \
|
}; \
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace logvisor
|
} // namespace logvisor
|
||||||
|
|
||||||
|
template <typename S, typename... Args, typename Char = fmt::char_t<S>>
|
||||||
|
void quicklog(const S& format, Args&&... args) {
|
||||||
|
logvisor::MainLoggers[0]->report(
|
||||||
|
"quick", logvisor::Info, fmt::to_string_view<Char>(format),
|
||||||
|
fmt::basic_format_args<fmt::buffer_context<Char>>(
|
||||||
|
fmt::internal::make_args_checked<Args...>(format, std::forward<Args>(args)...)));
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,155 +0,0 @@
|
|||||||
#ifndef _NXSTL_CONDVAR
|
|
||||||
#define _NXSTL_CONDVAR 1
|
|
||||||
#ifdef __SWITCH__
|
|
||||||
extern "C" {
|
|
||||||
#include <switch/kernel/condvar.h>
|
|
||||||
#include <switch/result.h>
|
|
||||||
}
|
|
||||||
|
|
||||||
#include <chrono>
|
|
||||||
#include <bits/std_mutex.h>
|
|
||||||
#include <ext/concurrence.h>
|
|
||||||
#include <bits/alloc_traits.h>
|
|
||||||
#include <bits/allocator.h>
|
|
||||||
#include <bits/unique_ptr.h>
|
|
||||||
#include <bits/shared_ptr.h>
|
|
||||||
#include <bits/cxxabi_forced.h>
|
|
||||||
|
|
||||||
namespace std _GLIBCXX_VISIBILITY(default)
|
|
||||||
{
|
|
||||||
|
|
||||||
/// cv_status
|
|
||||||
enum class cv_status { no_timeout, timeout };
|
|
||||||
|
|
||||||
/// condition_variable
|
|
||||||
class condition_variable
|
|
||||||
{
|
|
||||||
typedef chrono::system_clock __clock_t;
|
|
||||||
typedef CondVar __native_type;
|
|
||||||
|
|
||||||
__native_type _M_cond = {};
|
|
||||||
public:
|
|
||||||
typedef __native_type* native_handle_type;
|
|
||||||
|
|
||||||
constexpr condition_variable() noexcept = default;
|
|
||||||
~condition_variable() noexcept = default;
|
|
||||||
|
|
||||||
condition_variable(const condition_variable&) = delete;
|
|
||||||
condition_variable& operator=(const condition_variable&) = delete;
|
|
||||||
|
|
||||||
void
|
|
||||||
notify_one() noexcept
|
|
||||||
{
|
|
||||||
condvarWakeOne(&_M_cond);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
notify_all() noexcept
|
|
||||||
{
|
|
||||||
condvarWakeAll(&_M_cond);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
wait(unique_lock<mutex>& __lock) noexcept
|
|
||||||
{
|
|
||||||
condvarWait(&_M_cond, __lock.mutex()->native_handle());
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename _Predicate>
|
|
||||||
void
|
|
||||||
wait(unique_lock<mutex>& __lock, _Predicate __p)
|
|
||||||
{
|
|
||||||
while (!__p())
|
|
||||||
wait(__lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename _Duration>
|
|
||||||
cv_status
|
|
||||||
wait_until(unique_lock<mutex>& __lock,
|
|
||||||
const chrono::time_point<__clock_t, _Duration>& __atime)
|
|
||||||
{ return __wait_until_impl(__lock, __atime); }
|
|
||||||
|
|
||||||
template<typename _Clock, typename _Duration>
|
|
||||||
cv_status
|
|
||||||
wait_until(unique_lock<mutex>& __lock,
|
|
||||||
const chrono::time_point<_Clock, _Duration>& __atime)
|
|
||||||
{
|
|
||||||
// DR 887 - Sync unknown clock to known clock.
|
|
||||||
const typename _Clock::time_point __c_entry = _Clock::now();
|
|
||||||
const __clock_t::time_point __s_entry = __clock_t::now();
|
|
||||||
const auto __delta = __atime - __c_entry;
|
|
||||||
const auto __s_atime = __s_entry + __delta;
|
|
||||||
|
|
||||||
return __wait_until_impl(__lock, __s_atime);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename _Clock, typename _Duration, typename _Predicate>
|
|
||||||
bool
|
|
||||||
wait_until(unique_lock<mutex>& __lock,
|
|
||||||
const chrono::time_point<_Clock, _Duration>& __atime,
|
|
||||||
_Predicate __p)
|
|
||||||
{
|
|
||||||
while (!__p())
|
|
||||||
if (wait_until(__lock, __atime) == cv_status::timeout)
|
|
||||||
return __p();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename _Rep, typename _Period>
|
|
||||||
cv_status
|
|
||||||
wait_for(unique_lock<mutex>& __lock,
|
|
||||||
const chrono::duration<_Rep, _Period>& __rtime)
|
|
||||||
{
|
|
||||||
using __dur = typename __clock_t::duration;
|
|
||||||
auto __reltime = chrono::duration_cast<__dur>(__rtime);
|
|
||||||
if (__reltime < __rtime)
|
|
||||||
++__reltime;
|
|
||||||
return wait_until(__lock, __clock_t::now() + __reltime);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename _Rep, typename _Period, typename _Predicate>
|
|
||||||
bool
|
|
||||||
wait_for(unique_lock<mutex>& __lock,
|
|
||||||
const chrono::duration<_Rep, _Period>& __rtime,
|
|
||||||
_Predicate __p)
|
|
||||||
{
|
|
||||||
using __dur = typename __clock_t::duration;
|
|
||||||
auto __reltime = chrono::duration_cast<__dur>(__rtime);
|
|
||||||
if (__reltime < __rtime)
|
|
||||||
++__reltime;
|
|
||||||
return wait_until(__lock, __clock_t::now() + __reltime, std::move(__p));
|
|
||||||
}
|
|
||||||
|
|
||||||
native_handle_type
|
|
||||||
native_handle()
|
|
||||||
{ return &_M_cond; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
template<typename _Dur>
|
|
||||||
cv_status
|
|
||||||
__wait_until_impl(unique_lock<mutex>& __lock,
|
|
||||||
const chrono::time_point<__clock_t, _Dur>& __atime)
|
|
||||||
{
|
|
||||||
auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime);
|
|
||||||
|
|
||||||
Result res = condvarWaitTimeout(&_M_cond, __lock.mutex()->native_handle(), __ns.count());
|
|
||||||
|
|
||||||
if (R_DESCRIPTION(res) == KernelError_Timeout)
|
|
||||||
return cv_status::timeout;
|
|
||||||
return cv_status::no_timeout;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void
|
|
||||||
notify_all_at_thread_exit(condition_variable&, unique_lock<mutex>);
|
|
||||||
|
|
||||||
struct __at_thread_exit_elt
|
|
||||||
{
|
|
||||||
__at_thread_exit_elt* _M_next;
|
|
||||||
void (*_M_cb)(void*);
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
@@ -1,112 +0,0 @@
|
|||||||
#ifndef _NXSTL_MUTEX
|
|
||||||
#define _NXSTL_MUTEX 1
|
|
||||||
#ifdef __SWITCH__
|
|
||||||
extern "C" {
|
|
||||||
#include <switch/kernel/mutex.h>
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace std _GLIBCXX_VISIBILITY(default)
|
|
||||||
{
|
|
||||||
|
|
||||||
// Common base class for std::mutex
|
|
||||||
class __mutex_base
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
typedef Mutex __native_type;
|
|
||||||
|
|
||||||
__native_type _M_mutex = {};
|
|
||||||
|
|
||||||
constexpr __mutex_base() noexcept = default;
|
|
||||||
|
|
||||||
__mutex_base(const __mutex_base&) = delete;
|
|
||||||
__mutex_base& operator=(const __mutex_base&) = delete;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// The standard mutex type.
|
|
||||||
class mutex : private __mutex_base
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef __native_type* native_handle_type;
|
|
||||||
|
|
||||||
constexpr mutex() noexcept = default;
|
|
||||||
~mutex() = default;
|
|
||||||
|
|
||||||
mutex(const mutex&) = delete;
|
|
||||||
mutex& operator=(const mutex&) = delete;
|
|
||||||
|
|
||||||
void
|
|
||||||
lock()
|
|
||||||
{
|
|
||||||
mutexLock(&_M_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
try_lock() noexcept
|
|
||||||
{
|
|
||||||
return mutexTryLock(&_M_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
unlock()
|
|
||||||
{
|
|
||||||
mutexUnlock(&_M_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
native_handle_type
|
|
||||||
native_handle() noexcept
|
|
||||||
{ return &_M_mutex; }
|
|
||||||
};
|
|
||||||
|
|
||||||
// Common base class for std::recursive_mutex
|
|
||||||
class __recursive_mutex_base
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
typedef RMutex __native_type;
|
|
||||||
|
|
||||||
__recursive_mutex_base(const __recursive_mutex_base&) = delete;
|
|
||||||
__recursive_mutex_base& operator=(const __recursive_mutex_base&) = delete;
|
|
||||||
|
|
||||||
__native_type _M_mutex = {};
|
|
||||||
|
|
||||||
__recursive_mutex_base() = default;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// The standard recursive mutex type.
|
|
||||||
class recursive_mutex : private __recursive_mutex_base
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef __native_type* native_handle_type;
|
|
||||||
|
|
||||||
constexpr recursive_mutex() = default;
|
|
||||||
~recursive_mutex() = default;
|
|
||||||
|
|
||||||
recursive_mutex(const recursive_mutex&) = delete;
|
|
||||||
recursive_mutex& operator=(const recursive_mutex&) = delete;
|
|
||||||
|
|
||||||
void
|
|
||||||
lock()
|
|
||||||
{
|
|
||||||
rmutexLock(&_M_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
try_lock() noexcept
|
|
||||||
{
|
|
||||||
return rmutexTryLock(&_M_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
unlock()
|
|
||||||
{
|
|
||||||
rmutexUnlock(&_M_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
native_handle_type
|
|
||||||
native_handle() noexcept
|
|
||||||
{ return &_M_mutex; }
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
@@ -1,295 +0,0 @@
|
|||||||
#ifndef _NXSTL_THREAD
|
|
||||||
#define _NXSTL_THREAD 1
|
|
||||||
#ifdef __SWITCH__
|
|
||||||
extern "C" {
|
|
||||||
#include <switch/kernel/thread.h>
|
|
||||||
#include <switch/arm/tls.h>
|
|
||||||
#include <switch/result.h>
|
|
||||||
}
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
namespace std _GLIBCXX_VISIBILITY(default)
|
|
||||||
{
|
|
||||||
|
|
||||||
/// thread
|
|
||||||
class thread
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
// Abstract base class for types that wrap arbitrary functors to be
|
|
||||||
// invoked in the new thread of execution.
|
|
||||||
struct _State
|
|
||||||
{
|
|
||||||
virtual ~_State() = default;
|
|
||||||
virtual void _M_run() = 0;
|
|
||||||
};
|
|
||||||
using _State_ptr = unique_ptr<_State>;
|
|
||||||
|
|
||||||
typedef Thread native_handle_type;
|
|
||||||
|
|
||||||
/// thread::id
|
|
||||||
class id
|
|
||||||
{
|
|
||||||
native_handle_type _M_thread;
|
|
||||||
|
|
||||||
public:
|
|
||||||
id() noexcept : _M_thread() { }
|
|
||||||
|
|
||||||
explicit
|
|
||||||
id(native_handle_type __id) : _M_thread(__id) { }
|
|
||||||
|
|
||||||
private:
|
|
||||||
friend class thread;
|
|
||||||
friend class hash<thread::id>;
|
|
||||||
|
|
||||||
friend bool
|
|
||||||
operator==(thread::id __x, thread::id __y) noexcept;
|
|
||||||
|
|
||||||
friend bool
|
|
||||||
operator<(thread::id __x, thread::id __y) noexcept;
|
|
||||||
|
|
||||||
template<class _CharT, class _Traits>
|
|
||||||
friend basic_ostream<_CharT, _Traits>&
|
|
||||||
operator<<(basic_ostream<_CharT, _Traits>& __out, thread::id __id);
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
|
||||||
id _M_id;
|
|
||||||
|
|
||||||
public:
|
|
||||||
thread() noexcept = default;
|
|
||||||
// _GLIBCXX_RESOLVE_LIB_DEFECTS
|
|
||||||
// 2097. packaged_task constructors should be constrained
|
|
||||||
thread(thread&) = delete;
|
|
||||||
thread(const thread&) = delete;
|
|
||||||
thread(const thread&&) = delete;
|
|
||||||
|
|
||||||
thread(thread&& __t) noexcept
|
|
||||||
{ swap(__t); }
|
|
||||||
|
|
||||||
template<typename _Callable, typename... _Args>
|
|
||||||
explicit
|
|
||||||
thread(_Callable&& __f, _Args&&... __args)
|
|
||||||
{
|
|
||||||
_M_start_thread(_S_make_state(
|
|
||||||
__make_invoker(std::forward<_Callable>(__f),
|
|
||||||
std::forward<_Args>(__args)...)));
|
|
||||||
}
|
|
||||||
|
|
||||||
~thread()
|
|
||||||
{
|
|
||||||
if (joinable())
|
|
||||||
std::terminate();
|
|
||||||
}
|
|
||||||
|
|
||||||
thread& operator=(const thread&) = delete;
|
|
||||||
|
|
||||||
thread& operator=(thread&& __t) noexcept
|
|
||||||
{
|
|
||||||
if (joinable())
|
|
||||||
std::terminate();
|
|
||||||
swap(__t);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
swap(thread& __t) noexcept
|
|
||||||
{ std::swap(_M_id, __t._M_id); }
|
|
||||||
|
|
||||||
bool
|
|
||||||
joinable() const noexcept
|
|
||||||
{ return !(_M_id == id()); }
|
|
||||||
|
|
||||||
void
|
|
||||||
join()
|
|
||||||
{
|
|
||||||
threadWaitForExit(&_M_id._M_thread);
|
|
||||||
_M_id = id();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
detach()
|
|
||||||
{
|
|
||||||
_M_id = id();
|
|
||||||
}
|
|
||||||
|
|
||||||
thread::id
|
|
||||||
get_id() const noexcept
|
|
||||||
{ return _M_id; }
|
|
||||||
|
|
||||||
/** @pre thread is joinable
|
|
||||||
*/
|
|
||||||
native_handle_type
|
|
||||||
native_handle()
|
|
||||||
{ return _M_id._M_thread; }
|
|
||||||
|
|
||||||
// Returns a value that hints at the number of hardware thread contexts.
|
|
||||||
static unsigned int
|
|
||||||
hardware_concurrency() noexcept
|
|
||||||
{
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
template<typename _Callable>
|
|
||||||
struct _State_impl : public _State
|
|
||||||
{
|
|
||||||
_Callable _M_func;
|
|
||||||
|
|
||||||
_State_impl(_Callable&& __f) : _M_func(std::forward<_Callable>(__f))
|
|
||||||
{ }
|
|
||||||
|
|
||||||
void
|
|
||||||
_M_run() { _M_func(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
static void
|
|
||||||
execute_native_thread_routine(void *arg)
|
|
||||||
{
|
|
||||||
reinterpret_cast<_State*>(arg)->_M_run();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
_M_start_thread(_State_ptr state)
|
|
||||||
{
|
|
||||||
Result res = threadCreate(&_M_id._M_thread, execute_native_thread_routine,
|
|
||||||
state.get(), 8192, 0x2B, -2);
|
|
||||||
if (R_FAILED(res))
|
|
||||||
__throw_system_error(res);
|
|
||||||
res = threadStart(&_M_id._M_thread);
|
|
||||||
if (R_FAILED(res))
|
|
||||||
__throw_system_error(res);
|
|
||||||
state.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename _Callable>
|
|
||||||
static _State_ptr
|
|
||||||
_S_make_state(_Callable&& __f)
|
|
||||||
{
|
|
||||||
using _Impl = _State_impl<_Callable>;
|
|
||||||
return _State_ptr{new _Impl{std::forward<_Callable>(__f)}};
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
// A call wrapper that does INVOKE(forwarded tuple elements...)
|
|
||||||
template<typename _Tuple>
|
|
||||||
struct _Invoker
|
|
||||||
{
|
|
||||||
_Tuple _M_t;
|
|
||||||
|
|
||||||
template<size_t _Index>
|
|
||||||
static __tuple_element_t<_Index, _Tuple>&&
|
|
||||||
_S_declval();
|
|
||||||
|
|
||||||
template<size_t... _Ind>
|
|
||||||
auto
|
|
||||||
_M_invoke(_Index_tuple<_Ind...>)
|
|
||||||
noexcept(noexcept(std::__invoke(_S_declval<_Ind>()...)))
|
|
||||||
-> decltype(std::__invoke(_S_declval<_Ind>()...))
|
|
||||||
{ return std::__invoke(std::get<_Ind>(std::move(_M_t))...); }
|
|
||||||
|
|
||||||
using _Indices
|
|
||||||
= typename _Build_index_tuple<tuple_size<_Tuple>::value>::__type;
|
|
||||||
|
|
||||||
auto
|
|
||||||
operator()()
|
|
||||||
noexcept(noexcept(std::declval<_Invoker&>()._M_invoke(_Indices())))
|
|
||||||
-> decltype(std::declval<_Invoker&>()._M_invoke(_Indices()))
|
|
||||||
{ return _M_invoke(_Indices()); }
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename... _Tp>
|
|
||||||
using __decayed_tuple = tuple<typename std::decay<_Tp>::type...>;
|
|
||||||
|
|
||||||
public:
|
|
||||||
// Returns a call wrapper that stores
|
|
||||||
// tuple{DECAY_COPY(__callable), DECAY_COPY(__args)...}.
|
|
||||||
template<typename _Callable, typename... _Args>
|
|
||||||
static _Invoker<__decayed_tuple<_Callable, _Args...>>
|
|
||||||
__make_invoker(_Callable&& __callable, _Args&&... __args)
|
|
||||||
{
|
|
||||||
return { __decayed_tuple<_Callable, _Args...>{
|
|
||||||
std::forward<_Callable>(__callable), std::forward<_Args>(__args)...
|
|
||||||
} };
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
inline void
|
|
||||||
swap(thread& __x, thread& __y) noexcept
|
|
||||||
{ __x.swap(__y); }
|
|
||||||
|
|
||||||
inline bool
|
|
||||||
operator==(thread::id __x, thread::id __y) noexcept
|
|
||||||
{
|
|
||||||
// pthread_equal is undefined if either thread ID is not valid, so we
|
|
||||||
// can't safely use __gthread_equal on default-constructed values (nor
|
|
||||||
// the non-zero value returned by this_thread::get_id() for
|
|
||||||
// single-threaded programs using GNU libc). Assume EqualityComparable.
|
|
||||||
return __x._M_thread.handle == __y._M_thread.handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool
|
|
||||||
operator!=(thread::id __x, thread::id __y) noexcept
|
|
||||||
{ return !(__x == __y); }
|
|
||||||
|
|
||||||
inline bool
|
|
||||||
operator<(thread::id __x, thread::id __y) noexcept
|
|
||||||
{
|
|
||||||
// Pthreads doesn't define any way to do this, so we just have to
|
|
||||||
// assume native_handle_type is LessThanComparable.
|
|
||||||
return __x._M_thread.handle < __y._M_thread.handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool
|
|
||||||
operator<=(thread::id __x, thread::id __y) noexcept
|
|
||||||
{ return !(__y < __x); }
|
|
||||||
|
|
||||||
inline bool
|
|
||||||
operator>(thread::id __x, thread::id __y) noexcept
|
|
||||||
{ return __y < __x; }
|
|
||||||
|
|
||||||
inline bool
|
|
||||||
operator>=(thread::id __x, thread::id __y) noexcept
|
|
||||||
{ return !(__x < __y); }
|
|
||||||
|
|
||||||
// DR 889.
|
|
||||||
/// std::hash specialization for thread::id.
|
|
||||||
template<>
|
|
||||||
struct hash<thread::id>
|
|
||||||
: public __hash_base<size_t, thread::id>
|
|
||||||
{
|
|
||||||
size_t
|
|
||||||
operator()(const thread::id& __id) const noexcept
|
|
||||||
{ return std::_Hash_impl::hash(__id._M_thread); }
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class _CharT, class _Traits>
|
|
||||||
inline basic_ostream<_CharT, _Traits>&
|
|
||||||
operator<<(basic_ostream<_CharT, _Traits>& __out, thread::id __id)
|
|
||||||
{
|
|
||||||
if (__id == thread::id())
|
|
||||||
return __out << "thread::id of a non-executing thread";
|
|
||||||
else
|
|
||||||
return __out << __id._M_thread;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace this_thread
|
|
||||||
{
|
|
||||||
/// get_id
|
|
||||||
inline thread::id
|
|
||||||
get_id() noexcept
|
|
||||||
{
|
|
||||||
Thread ret;
|
|
||||||
uint8_t* tls = (uint8_t*)armGetTls();
|
|
||||||
uint8_t* threadCtx = *(uint8_t**)(tls + 0x1F8);
|
|
||||||
ret.handle = *(Handle*)(threadCtx + 0x1B8);
|
|
||||||
ret.stack_mem = *(void**)(threadCtx + 0x48);
|
|
||||||
ret.stack_mirror = *(void**)(threadCtx + 0x50);
|
|
||||||
ret.stack_sz = *(size_t*)(threadCtx + 0x58);
|
|
||||||
return thread::id(ret);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
401
lib/logvisor.cpp
401
lib/logvisor.cpp
@@ -11,7 +11,7 @@
|
|||||||
#include <TlHelp32.h>
|
#include <TlHelp32.h>
|
||||||
#elif defined(__SWITCH__)
|
#elif defined(__SWITCH__)
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include "nxstl/thread"
|
#include <switch.h>
|
||||||
#else
|
#else
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cinttypes>
|
#include <cinttypes>
|
||||||
#include <signal.h>
|
#include <csignal>
|
||||||
#include "logvisor/logvisor.hpp"
|
#include "logvisor/logvisor.hpp"
|
||||||
|
|
||||||
/* ANSI sequences */
|
/* ANSI sequences */
|
||||||
@@ -47,7 +47,9 @@
|
|||||||
#define FOREGROUND_WHITE FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
|
#define FOREGROUND_WHITE FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef _MSC_VER
|
||||||
#pragma GCC diagnostic ignored "-Wformat-truncation"
|
#pragma GCC diagnostic ignored "-Wformat-truncation"
|
||||||
|
#endif
|
||||||
|
|
||||||
void logvisorBp() {}
|
void logvisorBp() {}
|
||||||
|
|
||||||
@@ -91,18 +93,18 @@ void RegisterThreadName(const char* name) {
|
|||||||
|
|
||||||
void KillProcessTree() {
|
void KillProcessTree() {
|
||||||
DWORD myprocID = GetCurrentProcessId();
|
DWORD myprocID = GetCurrentProcessId();
|
||||||
PROCESSENTRY32 pe = {};
|
PROCESSENTRY32W pe = {};
|
||||||
pe.dwSize = sizeof(PROCESSENTRY32);
|
pe.dwSize = sizeof(pe);
|
||||||
|
|
||||||
HANDLE hSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
HANDLE hSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
||||||
|
|
||||||
if (::Process32First(hSnap, &pe)) {
|
if (::Process32FirstW(hSnap, &pe)) {
|
||||||
BOOL bContinue = TRUE;
|
BOOL bContinue = TRUE;
|
||||||
|
|
||||||
// kill child processes
|
// kill child processes
|
||||||
while (bContinue) {
|
while (bContinue) {
|
||||||
// only kill child processes and let console window remain
|
// only kill child processes and let console window remain
|
||||||
if (pe.th32ParentProcessID == myprocID && wcscmp(pe.szExeFile, L"conhost.exe")) {
|
if (pe.th32ParentProcessID == myprocID && std::wcscmp(pe.szExeFile, L"conhost.exe") != 0) {
|
||||||
HANDLE hChildProc = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, pe.th32ProcessID);
|
HANDLE hChildProc = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, pe.th32ProcessID);
|
||||||
|
|
||||||
if (hChildProc) {
|
if (hChildProc) {
|
||||||
@@ -111,7 +113,7 @@ void KillProcessTree() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bContinue = ::Process32Next(hSnap, &pe);
|
bContinue = ::Process32NextW(hSnap, &pe);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -167,62 +169,35 @@ void KillProcessTree() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#elif defined(__SWITCH__)
|
#elif defined(__SWITCH__)
|
||||||
[[noreturn]] void logvisorAbort() { exit(1); }
|
[[noreturn]] void logvisorAbort() {
|
||||||
|
MainLoggers.clear();
|
||||||
|
nvExit();
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
|
|
||||||
void KillProcessTree() {}
|
void KillProcessTree() {}
|
||||||
|
|
||||||
#include <execinfo.h>
|
#include <backtrace.h>
|
||||||
[[noreturn]] void logvisorAbort() {
|
|
||||||
void* array[128];
|
|
||||||
size_t size = backtrace(array, 128);
|
|
||||||
|
|
||||||
constexpr size_t exeBufSize = 1024 + 1;
|
void backtrace_error(void* data, const char* msg, int errnum) {
|
||||||
char exeNameBuffer[exeBufSize] = {};
|
std::fprintf(stderr, "Error retrieving stack trace: %d %s\n", errnum, msg);
|
||||||
|
}
|
||||||
|
|
||||||
#if __linux__
|
int backtrace_callback(void* data, uintptr_t pc, const char* filename, int lineno, const char* function) {
|
||||||
readlink("/proc/self/exe", exeNameBuffer, exeBufSize);
|
int status = -255;
|
||||||
#endif
|
char* demangledName = abi::__cxa_demangle(function, nullptr, nullptr, &status);
|
||||||
|
std::fprintf(stderr, "0x%lX %s\n\t%s:%d\n", pc, status == 0 ? demangledName : function, filename, lineno);
|
||||||
#if __APPLE__
|
if (demangledName != nullptr) {
|
||||||
std::string cmdLineStr = fmt::format(fmt("atos -p {}"), getpid());
|
std::free(demangledName);
|
||||||
#else
|
|
||||||
std::string cmdLineStr = fmt::format(fmt("2>/dev/null addr2line -C -f -e \"{}\""), exeNameBuffer);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
for (size_t i = 0; i < size; i++) {
|
|
||||||
#if __linux__
|
|
||||||
Dl_info dlip;
|
|
||||||
if (dladdr(array[i], &dlip))
|
|
||||||
cmdLineStr += fmt::format(fmt(" 0x{:016X}"), (uintptr_t)((uint8_t*)array[i] - (uint8_t*)dlip.dli_fbase));
|
|
||||||
else
|
|
||||||
cmdLineStr += fmt::format(fmt(" 0x{:016X}"), (uintptr_t)array[i]);
|
|
||||||
#else
|
|
||||||
cmdLineStr += fmt::format(fmt(" 0x{:016X}"), (uintptr_t)array[i]);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
FILE* fp = popen(cmdLineStr.c_str(), "r");
|
[[noreturn]] void logvisorAbort() {
|
||||||
if (fp) {
|
backtrace_state* state = backtrace_create_state(nullptr, 0, backtrace_error, nullptr);
|
||||||
char readBuf[256];
|
if (state != nullptr) {
|
||||||
size_t readSz;
|
backtrace_full(state, 0, backtrace_callback, backtrace_error, nullptr);
|
||||||
while ((readSz = fread(readBuf, 1, 256, fp)))
|
|
||||||
std::fwrite(readBuf, 1, readSz, stderr);
|
|
||||||
pclose(fp);
|
|
||||||
} else {
|
|
||||||
for (size_t i = 0; i < size; i++) {
|
|
||||||
std::fputs("- ", stderr);
|
|
||||||
Dl_info dlip;
|
|
||||||
if (dladdr(array[i], &dlip)) {
|
|
||||||
int status;
|
|
||||||
char* demangledName = abi::__cxa_demangle(dlip.dli_sname, nullptr, nullptr, &status);
|
|
||||||
std::fprintf(stderr, "%p(%s+%p)\n", dlip.dli_saddr, demangledName ? demangledName : dlip.dli_sname,
|
|
||||||
(void*)((uint8_t*)array[i] - (uint8_t*)dlip.dli_fbase));
|
|
||||||
std::free(demangledName);
|
|
||||||
} else {
|
|
||||||
std::fprintf(stderr, "%p\n", array[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::fflush(stderr);
|
std::fflush(stderr);
|
||||||
@@ -245,19 +220,19 @@ static void AbortHandler(int signum) {
|
|||||||
_LogMutex.enabled = false;
|
_LogMutex.enabled = false;
|
||||||
switch (signum) {
|
switch (signum) {
|
||||||
case SIGSEGV:
|
case SIGSEGV:
|
||||||
Log.report(logvisor::Fatal, fmt("Segmentation Fault"));
|
Log.report(logvisor::Fatal, FMT_STRING("Segmentation Fault"));
|
||||||
break;
|
break;
|
||||||
case SIGILL:
|
case SIGILL:
|
||||||
Log.report(logvisor::Fatal, fmt("Bad Execution"));
|
Log.report(logvisor::Fatal, FMT_STRING("Bad Execution"));
|
||||||
break;
|
break;
|
||||||
case SIGFPE:
|
case SIGFPE:
|
||||||
Log.report(logvisor::Fatal, fmt("Floating Point Exception"));
|
Log.report(logvisor::Fatal, FMT_STRING("Floating Point Exception"));
|
||||||
break;
|
break;
|
||||||
case SIGABRT:
|
case SIGABRT:
|
||||||
Log.report(logvisor::Fatal, fmt("Abort Signal"));
|
Log.report(logvisor::Fatal, FMT_STRING("Abort Signal"));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
Log.report(logvisor::Fatal, fmt("unknown signal {}"), signum);
|
Log.report(logvisor::Fatal, FMT_STRING("unknown signal {}"), signum);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -291,6 +266,238 @@ static inline int ConsoleWidth() {
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if LOGVISOR_NX_LM
|
||||||
|
|
||||||
|
struct ConsoleLogger : public ILogger {
|
||||||
|
Service m_svc{};
|
||||||
|
Service m_logger{};
|
||||||
|
bool m_ready = false;
|
||||||
|
|
||||||
|
struct MessageHeader {
|
||||||
|
enum Flags : u32 {
|
||||||
|
IsHead = 1,
|
||||||
|
IsTail = 2,
|
||||||
|
};
|
||||||
|
enum Severity : u32 {
|
||||||
|
Trace,
|
||||||
|
Info,
|
||||||
|
Warning,
|
||||||
|
Error,
|
||||||
|
Critical,
|
||||||
|
};
|
||||||
|
|
||||||
|
u64 pid;
|
||||||
|
u64 thread_context;
|
||||||
|
//union {
|
||||||
|
//BitField<0, 16, Flags> flags;
|
||||||
|
//BitField<16, 8, Severity> severity;
|
||||||
|
//BitField<24, 8, u32> verbosity;
|
||||||
|
//};
|
||||||
|
u32 flags;
|
||||||
|
u32 payload_size;
|
||||||
|
|
||||||
|
Flags GetFlags() const {
|
||||||
|
return Flags(flags & u32(0xffff));
|
||||||
|
}
|
||||||
|
void SetFlags(Flags f) {
|
||||||
|
flags &= ~u32(0xffff);
|
||||||
|
flags |= f;
|
||||||
|
}
|
||||||
|
Severity GetSeverity() const {
|
||||||
|
return Severity((flags >> u32(16)) & u32(0xff));
|
||||||
|
}
|
||||||
|
void SetSeverity(Severity f) {
|
||||||
|
flags &= ~u32(0xff0000);
|
||||||
|
flags |= f << u32(16);
|
||||||
|
}
|
||||||
|
u32 GetVerbosity() const {
|
||||||
|
return u32((flags >> u32(24)) & u32(0xff));
|
||||||
|
}
|
||||||
|
void SetVerbosity(u32 f) {
|
||||||
|
flags &= ~u32(0xff000000);
|
||||||
|
flags |= f << u32(24);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsHeadLog() const {
|
||||||
|
return flags & IsHead;
|
||||||
|
}
|
||||||
|
bool IsTailLog() const {
|
||||||
|
return flags & IsTail;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
static_assert(sizeof(MessageHeader) == 0x18, "MessageHeader is incorrect size");
|
||||||
|
|
||||||
|
enum class Field : u8 {
|
||||||
|
Skip = 1,
|
||||||
|
Message = 2,
|
||||||
|
Line = 3,
|
||||||
|
Filename = 4,
|
||||||
|
Function = 5,
|
||||||
|
Module = 6,
|
||||||
|
Thread = 7,
|
||||||
|
};
|
||||||
|
|
||||||
|
static constexpr MessageHeader::Severity LevelToSeverity(Level l) {
|
||||||
|
switch (l) {
|
||||||
|
case Level::Info:
|
||||||
|
default:
|
||||||
|
return MessageHeader::Info;
|
||||||
|
case Level::Warning:
|
||||||
|
return MessageHeader::Warning;
|
||||||
|
case Level::Error:
|
||||||
|
return MessageHeader::Error;
|
||||||
|
case Level::Fatal:
|
||||||
|
return MessageHeader::Critical;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ConsoleLogger() {
|
||||||
|
if (R_SUCCEEDED(smGetService(&m_svc, "lm"))) {
|
||||||
|
auto pid = getpid();
|
||||||
|
if (R_SUCCEEDED(serviceDispatchIn(&m_svc, 0, pid, .out_num_objects = 1, .out_objects = &m_logger))) {
|
||||||
|
m_ready = true;
|
||||||
|
MessageHeader head{};
|
||||||
|
head.pid = getpid();
|
||||||
|
head.SetFlags(MessageHeader::IsHead);
|
||||||
|
serviceDispatch(&m_logger, 0,
|
||||||
|
.buffer_attrs = { SfBufferAttr_HipcPointer | SfBufferAttr_In },
|
||||||
|
.buffers = { { &head, sizeof(head) } });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~ConsoleLogger() override {
|
||||||
|
if (m_ready) {
|
||||||
|
MessageHeader head{};
|
||||||
|
head.pid = getpid();
|
||||||
|
head.SetFlags(MessageHeader::IsTail);
|
||||||
|
serviceDispatch(&m_logger, 0,
|
||||||
|
.buffer_attrs = { SfBufferAttr_HipcPointer | SfBufferAttr_In },
|
||||||
|
.buffers = { { &head, sizeof(head) } });
|
||||||
|
}
|
||||||
|
serviceClose(&m_logger);
|
||||||
|
serviceClose(&m_svc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SendBuffer(const std::vector<u8>& buf) {
|
||||||
|
serviceDispatch(&m_logger, 0,
|
||||||
|
.buffer_attrs = { SfBufferAttr_HipcPointer | SfBufferAttr_In },
|
||||||
|
.buffers = { { buf.data(), buf.size() } });
|
||||||
|
}
|
||||||
|
|
||||||
|
void report(const char* modName, Level severity, fmt::string_view format, fmt::format_args args) override {
|
||||||
|
if (!m_ready)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const std::thread::id thrId = std::this_thread::get_id();
|
||||||
|
const char* thrName = nullptr;
|
||||||
|
size_t thrNameSize = 0;
|
||||||
|
if (ThreadMap.find(thrId) != ThreadMap.end()) {
|
||||||
|
thrName = ThreadMap[thrId];
|
||||||
|
thrNameSize = std::min(std::strlen(thrName), size_t(255));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto modNameSize = std::min(std::strlen(modName), size_t(255));
|
||||||
|
auto message = fmt::vformat(format, args);
|
||||||
|
auto messageSize = std::min(message.size(), size_t(255));
|
||||||
|
|
||||||
|
std::vector<u8> bufOut(sizeof(MessageHeader) + (thrNameSize ? 2 + thrNameSize : 0) + 2 + modNameSize + 2 + messageSize, '\0');
|
||||||
|
|
||||||
|
auto it = bufOut.begin();
|
||||||
|
|
||||||
|
auto& head = *reinterpret_cast<MessageHeader*>(&*it);
|
||||||
|
head.pid = getpid();
|
||||||
|
head.payload_size = bufOut.size() - sizeof(MessageHeader);
|
||||||
|
head.SetSeverity(LevelToSeverity(severity));
|
||||||
|
it += sizeof(MessageHeader);
|
||||||
|
|
||||||
|
if (thrNameSize) {
|
||||||
|
*it++ = u8(Field::Thread);
|
||||||
|
*it++ = thrNameSize;
|
||||||
|
std::memcpy(&*it, thrName, thrNameSize);
|
||||||
|
it += thrNameSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
*it++ = u8(Field::Module);
|
||||||
|
*it++ = modNameSize;
|
||||||
|
std::memcpy(&*it, modName, modNameSize);
|
||||||
|
it += modNameSize;
|
||||||
|
|
||||||
|
*it++ = u8(Field::Message);
|
||||||
|
*it++ = messageSize;
|
||||||
|
std::memcpy(&*it, message.data(), messageSize);
|
||||||
|
it += messageSize;
|
||||||
|
|
||||||
|
SendBuffer(bufOut);
|
||||||
|
}
|
||||||
|
|
||||||
|
void report(const char* modName, Level severity, fmt::wstring_view format, fmt::wformat_args args) override {}
|
||||||
|
|
||||||
|
void reportSource(const char* modName, Level severity, const char* file, unsigned linenum, fmt::string_view format,
|
||||||
|
fmt::format_args args) override {
|
||||||
|
if (!m_ready)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const std::thread::id thrId = std::this_thread::get_id();
|
||||||
|
const char* thrName = nullptr;
|
||||||
|
size_t thrNameSize = 0;
|
||||||
|
if (ThreadMap.find(thrId) != ThreadMap.end()) {
|
||||||
|
thrName = ThreadMap[thrId];
|
||||||
|
thrNameSize = std::min(std::strlen(thrName), size_t(255));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto modNameSize = std::min(std::strlen(modName), size_t(255));
|
||||||
|
auto fileNameSize = std::min(std::strlen(file), size_t(255));
|
||||||
|
auto message = fmt::vformat(format, args);
|
||||||
|
auto messageSize = std::min(message.size(), size_t(255));
|
||||||
|
|
||||||
|
std::vector<u8> bufOut(sizeof(MessageHeader) + (thrNameSize ? 2 + thrNameSize : 0) + 2 + modNameSize + 2 + fileNameSize + 3 + 4 + 2 + messageSize, '\0');
|
||||||
|
|
||||||
|
auto it = bufOut.begin();
|
||||||
|
|
||||||
|
auto& head = *reinterpret_cast<MessageHeader*>(&*it);
|
||||||
|
head.pid = getpid();
|
||||||
|
head.payload_size = bufOut.size() - sizeof(MessageHeader);
|
||||||
|
head.SetSeverity(LevelToSeverity(severity));
|
||||||
|
it += sizeof(MessageHeader);
|
||||||
|
|
||||||
|
if (thrNameSize) {
|
||||||
|
*it++ = u8(Field::Thread);
|
||||||
|
*it++ = thrNameSize;
|
||||||
|
std::memcpy(&*it, thrName, thrNameSize);
|
||||||
|
it += thrNameSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
*it++ = u8(Field::Module);
|
||||||
|
*it++ = modNameSize;
|
||||||
|
std::memcpy(&*it, modName, modNameSize);
|
||||||
|
it += modNameSize;
|
||||||
|
|
||||||
|
*it++ = u8(Field::Filename);
|
||||||
|
*it++ = fileNameSize;
|
||||||
|
std::memcpy(&*it, file, fileNameSize);
|
||||||
|
it += fileNameSize;
|
||||||
|
|
||||||
|
*it++ = u8(Field::Line);
|
||||||
|
*it++ = 4;
|
||||||
|
*it++ = u8(Field::Skip);
|
||||||
|
std::memcpy(&*it, &linenum, 4);
|
||||||
|
it += 4;
|
||||||
|
|
||||||
|
*it++ = u8(Field::Message);
|
||||||
|
*it++ = messageSize;
|
||||||
|
std::memcpy(&*it, message.data(), messageSize);
|
||||||
|
it += messageSize;
|
||||||
|
|
||||||
|
SendBuffer(bufOut);
|
||||||
|
}
|
||||||
|
|
||||||
|
void reportSource(const char* modName, Level severity, const char* file, unsigned linenum, fmt::wstring_view format,
|
||||||
|
fmt::wformat_args args) override {}
|
||||||
|
};
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
static HANDLE Term = 0;
|
static HANDLE Term = 0;
|
||||||
#else
|
#else
|
||||||
@@ -322,9 +529,8 @@ struct ConsoleLogger : public ILogger {
|
|||||||
/* Clear current line out */
|
/* Clear current line out */
|
||||||
const int width = ConsoleWidth();
|
const int width = ConsoleWidth();
|
||||||
std::fputc('\r', stderr);
|
std::fputc('\r', stderr);
|
||||||
for (int w = 0; w < width; ++w) {
|
for (int w = 0; w < width; ++w)
|
||||||
std::fputc(' ', stderr);
|
std::fputc(' ', stderr);
|
||||||
}
|
|
||||||
std::fputc('\r', stderr);
|
std::fputc('\r', stderr);
|
||||||
|
|
||||||
const std::chrono::steady_clock::duration tm = CurrentUptime();
|
const std::chrono::steady_clock::duration tm = CurrentUptime();
|
||||||
@@ -332,17 +538,15 @@ struct ConsoleLogger : public ILogger {
|
|||||||
static_cast<double>(std::chrono::steady_clock::duration::period::den);
|
static_cast<double>(std::chrono::steady_clock::duration::period::den);
|
||||||
const std::thread::id thrId = std::this_thread::get_id();
|
const std::thread::id thrId = std::this_thread::get_id();
|
||||||
const char* thrName = nullptr;
|
const char* thrName = nullptr;
|
||||||
if (ThreadMap.find(thrId) != ThreadMap.end()) {
|
if (ThreadMap.find(thrId) != ThreadMap.end())
|
||||||
thrName = ThreadMap[thrId];
|
thrName = ThreadMap[thrId];
|
||||||
}
|
|
||||||
|
|
||||||
if (XtermColor) {
|
if (XtermColor) {
|
||||||
std::fputs(BOLD "[", stderr);
|
std::fputs(BOLD "[", stderr);
|
||||||
fmt::print(stderr, fmt(GREEN "{:5.4} "), tmd);
|
fmt::print(stderr, FMT_STRING(GREEN "{:.4f} "), tmd);
|
||||||
const uint_fast64_t fIdx = FrameIndex.load();
|
const uint_fast64_t fIdx = FrameIndex.load();
|
||||||
if (fIdx != 0) {
|
if (fIdx != 0)
|
||||||
fmt::print(stderr, fmt("({}) "), fIdx);
|
fmt::print(stderr, FMT_STRING("({}) "), fIdx);
|
||||||
}
|
|
||||||
switch (severity) {
|
switch (severity) {
|
||||||
case Info:
|
case Info:
|
||||||
std::fputs(BOLD CYAN "INFO", stderr);
|
std::fputs(BOLD CYAN "INFO", stderr);
|
||||||
@@ -359,13 +563,11 @@ struct ConsoleLogger : public ILogger {
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
fmt::print(stderr, fmt(NORMAL BOLD " {}"), modName);
|
fmt::print(stderr, FMT_STRING(NORMAL BOLD " {}"), modName);
|
||||||
if (sourceInfo) {
|
if (sourceInfo)
|
||||||
fmt::print(stderr, fmt(BOLD YELLOW " {{}}"), sourceInfo);
|
fmt::print(stderr, FMT_STRING(BOLD YELLOW " {{}}"), sourceInfo);
|
||||||
}
|
if (thrName)
|
||||||
if (thrName) {
|
fmt::print(stderr, FMT_STRING(BOLD MAGENTA " ({})"), thrName);
|
||||||
fmt::print(stderr, fmt(BOLD MAGENTA " ({})"), thrName);
|
|
||||||
}
|
|
||||||
std::fputs(NORMAL BOLD "] " NORMAL, stderr);
|
std::fputs(NORMAL BOLD "] " NORMAL, stderr);
|
||||||
} else {
|
} else {
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
@@ -373,11 +575,10 @@ struct ConsoleLogger : public ILogger {
|
|||||||
SetConsoleTextAttribute(Term, FOREGROUND_INTENSITY | FOREGROUND_WHITE);
|
SetConsoleTextAttribute(Term, FOREGROUND_INTENSITY | FOREGROUND_WHITE);
|
||||||
std::fputc('[', stderr);
|
std::fputc('[', stderr);
|
||||||
SetConsoleTextAttribute(Term, FOREGROUND_INTENSITY | FOREGROUND_GREEN);
|
SetConsoleTextAttribute(Term, FOREGROUND_INTENSITY | FOREGROUND_GREEN);
|
||||||
std::fprintf(stderr, "%5.4f ", tmd);
|
fmt::print(stderr, FMT_STRING("{:.4f} "), tmd);
|
||||||
const uint64_t fi = FrameIndex.load();
|
const uint64_t fi = FrameIndex.load();
|
||||||
if (fi != 0) {
|
if (fi != 0)
|
||||||
std::fprintf(stderr, "(%" PRIu64 ") ", fi);
|
std::fprintf(stderr, "(%" PRIu64 ") ", fi);
|
||||||
}
|
|
||||||
switch (severity) {
|
switch (severity) {
|
||||||
case Info:
|
case Info:
|
||||||
SetConsoleTextAttribute(Term, FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_BLUE);
|
SetConsoleTextAttribute(Term, FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_BLUE);
|
||||||
@@ -399,25 +600,23 @@ struct ConsoleLogger : public ILogger {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
SetConsoleTextAttribute(Term, FOREGROUND_INTENSITY | FOREGROUND_WHITE);
|
SetConsoleTextAttribute(Term, FOREGROUND_INTENSITY | FOREGROUND_WHITE);
|
||||||
std::fprintf(stderr, " %s", modName);
|
fmt::print(stderr, FMT_STRING(" {}"), modName);
|
||||||
SetConsoleTextAttribute(Term, FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN);
|
SetConsoleTextAttribute(Term, FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN);
|
||||||
if (sourceInfo) {
|
if (sourceInfo)
|
||||||
std::fprintf(stderr, " {%s}", sourceInfo);
|
fmt::print(stderr, FMT_STRING(" {{}}"), sourceInfo);
|
||||||
}
|
|
||||||
SetConsoleTextAttribute(Term, FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_BLUE);
|
SetConsoleTextAttribute(Term, FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_BLUE);
|
||||||
if (thrName) {
|
if (thrName)
|
||||||
std::fprintf(stderr, " (%s)", thrName);
|
fmt::print(stderr, FMT_STRING(" ({})"), thrName);
|
||||||
}
|
|
||||||
SetConsoleTextAttribute(Term, FOREGROUND_INTENSITY | FOREGROUND_WHITE);
|
SetConsoleTextAttribute(Term, FOREGROUND_INTENSITY | FOREGROUND_WHITE);
|
||||||
std::fputs("] ", stderr);
|
std::fputs("] ", stderr);
|
||||||
SetConsoleTextAttribute(Term, FOREGROUND_WHITE);
|
SetConsoleTextAttribute(Term, FOREGROUND_WHITE);
|
||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
std::fputc('[', stderr);
|
std::fputc('[', stderr);
|
||||||
fmt::print(stderr, fmt("{:5.4} "), tmd);
|
fmt::print(stderr, FMT_STRING("{:.4f} "), tmd);
|
||||||
uint_fast64_t fIdx = FrameIndex.load();
|
uint_fast64_t fIdx = FrameIndex.load();
|
||||||
if (fIdx)
|
if (fIdx)
|
||||||
fmt::print(stderr, fmt("({}) "), fIdx);
|
fmt::print(stderr, FMT_STRING("({}) "), fIdx);
|
||||||
switch (severity) {
|
switch (severity) {
|
||||||
case Info:
|
case Info:
|
||||||
std::fputs("INFO", stderr);
|
std::fputs("INFO", stderr);
|
||||||
@@ -434,13 +633,11 @@ struct ConsoleLogger : public ILogger {
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
fmt::print(stderr, fmt(" {}"), modName);
|
fmt::print(stderr, FMT_STRING(" {}"), modName);
|
||||||
if (sourceInfo) {
|
if (sourceInfo)
|
||||||
fmt::print(stderr, fmt(" {{}}"), sourceInfo);
|
fmt::print(stderr, FMT_STRING(" {{}}"), sourceInfo);
|
||||||
}
|
if (thrName)
|
||||||
if (thrName) {
|
fmt::print(stderr, FMT_STRING(" ({})"), thrName);
|
||||||
fmt::print(stderr, fmt(" ({})"), thrName);
|
|
||||||
}
|
|
||||||
std::fputs("] ", stderr);
|
std::fputs("] ", stderr);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -462,7 +659,7 @@ struct ConsoleLogger : public ILogger {
|
|||||||
|
|
||||||
void reportSource(const char* modName, Level severity, const char* file, unsigned linenum, fmt::string_view format,
|
void reportSource(const char* modName, Level severity, const char* file, unsigned linenum, fmt::string_view format,
|
||||||
fmt::format_args args) override {
|
fmt::format_args args) override {
|
||||||
_reportHead(modName, fmt::format(fmt("{}:{}"), file, linenum).c_str(), severity);
|
_reportHead(modName, fmt::format(FMT_STRING("{}:{}"), file, linenum).c_str(), severity);
|
||||||
fmt::vprint(stderr, format, args);
|
fmt::vprint(stderr, format, args);
|
||||||
std::fputc('\n', stderr);
|
std::fputc('\n', stderr);
|
||||||
std::fflush(stderr);
|
std::fflush(stderr);
|
||||||
@@ -470,16 +667,22 @@ struct ConsoleLogger : public ILogger {
|
|||||||
|
|
||||||
void reportSource(const char* modName, Level severity, const char* file, unsigned linenum, fmt::wstring_view format,
|
void reportSource(const char* modName, Level severity, const char* file, unsigned linenum, fmt::wstring_view format,
|
||||||
fmt::wformat_args args) override {
|
fmt::wformat_args args) override {
|
||||||
_reportHead(modName, fmt::format(fmt("{}:{}"), file, linenum).c_str(), severity);
|
_reportHead(modName, fmt::format(FMT_STRING("{}:{}"), file, linenum).c_str(), severity);
|
||||||
fmt::vprint(stderr, format, args);
|
fmt::vprint(stderr, format, args);
|
||||||
std::fputc('\n', stderr);
|
std::fputc('\n', stderr);
|
||||||
std::fflush(stderr);
|
std::fflush(stderr);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static bool ConsoleLoggerRegistered = false;
|
||||||
|
|
||||||
void RegisterConsoleLogger() {
|
void RegisterConsoleLogger() {
|
||||||
/* Otherwise construct new console logger */
|
/* Otherwise construct new console logger */
|
||||||
MainLoggers.emplace_back(new ConsoleLogger);
|
if (!ConsoleLoggerRegistered) {
|
||||||
|
MainLoggers.emplace_back(new ConsoleLogger);
|
||||||
|
ConsoleLoggerRegistered = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
@@ -568,7 +771,7 @@ struct FileLogger : public ILogger {
|
|||||||
void reportSource(const char* modName, Level severity, const char* file, unsigned linenum, fmt::string_view format,
|
void reportSource(const char* modName, Level severity, const char* file, unsigned linenum, fmt::string_view format,
|
||||||
fmt::format_args args) override {
|
fmt::format_args args) override {
|
||||||
openFile();
|
openFile();
|
||||||
_reportHead(modName, fmt::format(fmt("{}:{}"), file, linenum).c_str(), severity);
|
_reportHead(modName, fmt::format(FMT_STRING("{}:{}"), file, linenum).c_str(), severity);
|
||||||
fmt::vprint(fp, format, args);
|
fmt::vprint(fp, format, args);
|
||||||
std::fputc('\n', fp);
|
std::fputc('\n', fp);
|
||||||
closeFile();
|
closeFile();
|
||||||
@@ -577,7 +780,7 @@ struct FileLogger : public ILogger {
|
|||||||
void reportSource(const char* modName, Level severity, const char* file, unsigned linenum, fmt::wstring_view format,
|
void reportSource(const char* modName, Level severity, const char* file, unsigned linenum, fmt::wstring_view format,
|
||||||
fmt::wformat_args args) override {
|
fmt::wformat_args args) override {
|
||||||
openFile();
|
openFile();
|
||||||
_reportHead(modName, fmt::format(fmt("{}:{}"), file, linenum).c_str(), severity);
|
_reportHead(modName, fmt::format(FMT_STRING("{}:{}"), file, linenum).c_str(), severity);
|
||||||
fmt::vprint(fp, format, args);
|
fmt::vprint(fp, format, args);
|
||||||
std::fputc('\n', fp);
|
std::fputc('\n', fp);
|
||||||
closeFile();
|
closeFile();
|
||||||
|
|||||||
Reference in New Issue
Block a user