LogManager: implement system module, client api, logging api (#1617)

Some notes:

* Unless `atmosphere!enable_log_manager` is true, Nintendo's log manager will be used instead.
  * This prevents paying memory costs for LM when not enabling logging.
  * To facilitate this, Atmosphere's log manager has a different program id from Nintendo's.
  * `atmosphere!enable_htc` implies `atmosphere!enable_log_manager`.
* LogManager logs to tma, and the SD card (if `lm!enable_sd_card_logging` is true, which it is by default).
* Binary logs are saved to `lm!sd_card_log_output_directory`, which is `atmosphere/binlogs` by default.
This commit is contained in:
SciresM 2021-09-11 19:32:14 -07:00 committed by GitHub
parent a1fb8a91c8
commit e9849c74cf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
94 changed files with 5595 additions and 45 deletions

View file

@ -17,6 +17,140 @@
namespace ams::time::impl::util {
namespace {
constexpr inline const int DaysPerMonth[12] = {
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
static_assert(std::accumulate(std::begin(DaysPerMonth), std::end(DaysPerMonth), 0) == 365);
constexpr inline const std::array<int, 12> SumDaysPerMonth = [] {
std::array<int, 12> days = {};
for (size_t i = 1; i < days.size(); ++i) {
days[i] = days[i - 1] + DaysPerMonth[i - 1];
}
return days;
}();
static_assert(SumDaysPerMonth[ 0] == 0);
static_assert(SumDaysPerMonth[11] + DaysPerMonth[11] == 365);
constexpr bool IsLeapYearImpl(int year) {
if ((year % 400) == 0) {
return true;
} else if ((year % 100) == 0) {
return false;
} else if ((year % 4) == 0) {
return true;
} else {
return false;
}
}
constexpr int DateToDaysImpl(int year, int month, int day) {
/* Lightly validate input. */
AMS_ASSERT(year > 0);
AMS_ASSERT(month > 0);
AMS_ASSERT(day > 0);
/* Adjust months within range. */
year += month / 12;
month %= 12;
if (month == 0) {
month = 12;
}
AMS_ASSERT(1 <= month && month <= 12);
/* Calculate days. */
int res = (year - 1) * 365;
res += (year / 4) - (year / 100) + (year / 400);
res += SumDaysPerMonth[month - 1] + day;
/* Subtract leap day, if it hasn't happened yet. */
if (month < 3 && IsLeapYearImpl(year)) {
res -= 1;
}
/* Subtract the current day. */
res -= 1;
return res;
}
constexpr void DaysToDateImpl(int *out_year, int *out_month, int *out_day, int days) {
/* Lightly validate input. */
AMS_ASSERT(days > 0);
/* Declare unit conversion factors. */
constexpr int DaysPerYear = 365;
constexpr int DaysPerFourYears = DaysPerYear * 4 + 1;
constexpr int DaysPerCentury = DaysPerFourYears * 25 - 1;
constexpr int DaysPerFourCenturies = DaysPerCentury * 4 + 1;
/* Adjust date. */
days -= 59;
days += 365;
/* Determine various units. */
int four_centuries = days / DaysPerFourCenturies;
int four_centuries_rem = days % DaysPerFourCenturies;
if (four_centuries_rem < 0) {
four_centuries_rem += DaysPerFourCenturies;
--four_centuries;
}
int centuries = four_centuries_rem / DaysPerCentury;
int centuries_rem = four_centuries_rem % DaysPerCentury;
int four_years = centuries_rem / DaysPerFourYears;
int four_years_rem = centuries_rem % DaysPerFourYears;
int years = four_years_rem / DaysPerYear;
int years_rem = four_years_rem % DaysPerYear;
/* Adjust into range. */
int year = 400 * four_centuries + 100 * centuries + 4 * four_years + years;
int month = (5 * years_rem + 2) / 153;
int day = years_rem - (153 * month + 2) / 5 + 1;
/* Adjust in case we fell into a pathological case. */
if (years == 4 || centuries == 4) {
month = 11;
day = 29;
year -= 1;
}
/* Adjust month. */
if (month <= 9) {
month += 3;
} else {
month -= 9;
year += 1;
}
/* Set output. */
if (out_year) {
*out_year = year;
}
if (out_month) {
*out_month = month;
}
if (out_day) {
*out_day = day;
}
}
constexpr inline int EpochDays = DateToDaysImpl(1970, 1, 1);
static_assert([]() -> bool {
int year{}, month{}, day{};
DaysToDateImpl(std::addressof(year), std::addressof(month), std::addressof(day), EpochDays);
return year == 1970 && month == 1 && day == 1;
}());
}
Result GetSpanBetween(s64 *out, const SteadyClockTimePoint &from, const SteadyClockTimePoint &to) {
AMS_ASSERT(out != nullptr);
@ -31,4 +165,97 @@ namespace ams::time::impl::util {
return ResultSuccess();
}
bool IsValidDate(int year, int month, int day) {
return 1 <= year && 1 <= month && month <= 12 && 1 <= day && day <= GetDaysInMonth(year, month);
}
bool IsLeapYear(int year) {
AMS_ASSERT(year > 0);
return IsLeapYearImpl(year);
}
int GetDaysInMonth(int year, int month) {
/* Check pre-conditions. */
AMS_ASSERT(year > 0);
AMS_ASSERT(1 <= month && month <= 12);
if (month == 2 && IsLeapYear(year)) {
return DaysPerMonth[month - 1] + 1;
} else {
return DaysPerMonth[month - 1];
}
}
int DateToDays(int year, int month, int day) {
return DateToDaysImpl(year, month, day);
}
void DaysToDate(int *out_year, int *out_month, int *out_day, int days) {
DaysToDateImpl(out_year, out_month, out_day, days);
}
CalendarTime ToCalendarTimeInUtc(const PosixTime &posix_time) {
constexpr s64 SecondsPerDay = TimeSpan::FromDays(1).GetSeconds();
constexpr s64 SecondsPerHour = TimeSpan::FromHours(1).GetSeconds();
constexpr s64 SecondsPerMinute = TimeSpan::FromMinutes(1).GetSeconds();
/* Get year/month/day. */
int year, month, day;
DaysToDate(std::addressof(year), std::addressof(month), std::addressof(day), static_cast<int>(posix_time.value / SecondsPerDay) + EpochDays);
/* Handle negative posix times. */
s64 posix_abs = posix_time.value >= 0 ? posix_time.value : -1 * posix_time.value;
s64 posix_rem = posix_abs % SecondsPerDay;
if (posix_time.value < 0) {
posix_rem *= -1;
}
/* Adjust remainder if negative. */
if (posix_rem < 0) {
if ((--day) <= 0) {
if ((--month) <= 0) {
--year;
month = 12;
}
day = time::impl::util::GetDaysInMonth(year, month);
}
posix_rem += SecondsPerDay;
}
const int hour = posix_rem / SecondsPerHour;
posix_rem %= SecondsPerHour;
const int minute = posix_rem / SecondsPerMinute;
posix_rem %= SecondsPerMinute;
const int second = posix_rem;
return CalendarTime {
.year = static_cast<s16>(year),
.month = static_cast<s8>(month),
.day = static_cast<s8>(day),
.hour = static_cast<s8>(hour),
.minute = static_cast<s8>(minute),
.second = static_cast<s8>(second),
};
}
PosixTime ToPosixTimeFromUtc(const CalendarTime &calendar_time) {
/* Validate pre-conditions. */
AMS_ASSERT(IsValidDate(calendar_time.year, calendar_time.month, calendar_time.day));
AMS_ASSERT(0 <= calendar_time.hour && calendar_time.hour <= 23);
AMS_ASSERT(0 <= calendar_time.minute && calendar_time.minute <= 59);
AMS_ASSERT(0 <= calendar_time.second && calendar_time.second <= 59);
/* Extract/convert fields. */
const s64 days = static_cast<s64>(time::impl::util::DateToDays(calendar_time.year, calendar_time.month, calendar_time.day)) - EpochDays;
const s64 hours = calendar_time.hour;
const s64 minutes = calendar_time.minute;
const s64 seconds = calendar_time.second;
return PosixTime { .value = ((((days * 24) + hours) * 60) + minutes) * 60 + seconds };
}
}

View file

@ -34,11 +34,10 @@ namespace ams::time {
InitializeMode_SystemUser,
};
u32 g_initialize_count = 0;
InitializeMode g_initialize_mode = InitializeMode_None;
constinit u32 g_initialize_count = 0;
constinit InitializeMode g_initialize_mode = InitializeMode_None;
/* TODO: os::SdkMutex */
os::Mutex g_initialize_mutex(false);
constinit os::SdkMutex g_initialize_mutex;
Result InitializeImpl(InitializeMode mode) {
std::scoped_lock lk(g_initialize_mutex);
@ -76,7 +75,11 @@ namespace ams::time {
}
Result InitializeForSystemUser() {
return InitializeImpl(InitializeMode_System);
if (hos::GetVersion() >= hos::Version_9_0_0) {
return InitializeImpl(InitializeMode_SystemUser);
} else {
return InitializeImpl(InitializeMode_Normal);
}
}
Result Finalize() {
@ -98,6 +101,10 @@ namespace ams::time {
return g_initialize_count > 0;
}
bool IsValidDate(int year, int month, int day) {
return impl::util::IsValidDate(year, month, day);
}
Result GetElapsedSecondsBetween(s64 *out, const SteadyClockTimePoint &from, const SteadyClockTimePoint &to) {
return impl::util::GetSpanBetween(out, from, to);
}

View file

@ -0,0 +1,46 @@
/*
* Copyright (c) 2019-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::time {
bool CalendarTime::IsValid() const {
return time::IsValidDate(this->year, this->month, this->day);
}
CalendarTime &CalendarTime::operator+=(const TimeSpan &ts) {
*this = ToCalendarTimeInUtc(ToPosixTimeFromUtc(*this) + ts);
return *this;
}
CalendarTime &CalendarTime::operator-=(const TimeSpan &ts) {
*this = ToCalendarTimeInUtc(ToPosixTimeFromUtc(*this) - ts);
return *this;
}
CalendarTime operator+(const CalendarTime &lhs, const TimeSpan &rhs) {
return ToCalendarTimeInUtc(ToPosixTimeFromUtc(lhs) + rhs);
}
CalendarTime operator-(const CalendarTime &lhs, const TimeSpan &rhs) {
return ToCalendarTimeInUtc(ToPosixTimeFromUtc(lhs) - rhs);
}
TimeSpan operator-(const CalendarTime &lhs, const CalendarTime &rhs) {
return ToPosixTimeFromUtc(lhs) - ToPosixTimeFromUtc(rhs);
}
}

View file

@ -0,0 +1,28 @@
/*
* Copyright (c) 2019-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::time {
CalendarTime ToCalendarTimeInUtc(const PosixTime &posix_time) {
return impl::util::ToCalendarTimeInUtc(posix_time);
}
PosixTime ToPosixTimeFromUtc(const CalendarTime &calendar_time) {
return impl::util::ToPosixTimeFromUtc(calendar_time);
}
}