Results: Implement namespaced, type-safe results.

Because I was working on multiple things at once, this commit also:
- Adds wrappers for/linker flags to wrap CXX exceptions to make them
  abort. This saves ~0x8000 of memory in every system module.
- Broadly replaces lines of the pattern if (cond) { return ResultX; }
  with R_UNLESS(!cond, ResultX());.
- Reworks the R_TRY_CATCH macros (and the result macros in general).
This commit is contained in:
Michael Scire 2019-10-24 01:40:44 -07:00 committed by SciresM
parent 15773e4755
commit 4059dc6187
169 changed files with 2172 additions and 1868 deletions

View file

@ -31,7 +31,7 @@ DATA := data
INCLUDES := include ../../common/include
EXEFS_SRC := exefs_src
DEFINES := -DRESULT_ABORT_ON_ASSERT -DATMOSPHERE_GIT_BRANCH=\"$(AMSBRANCH)\" -DATMOSPHERE_GIT_REV=\"$(AMSREV)\"
DEFINES := -DATMOSPHERE_GIT_BRANCH=\"$(AMSBRANCH)\" -DATMOSPHERE_GIT_REV=\"$(AMSREV)\"
#---------------------------------------------------------------------------------
# options for code generation
@ -45,8 +45,18 @@ CFLAGS += $(INCLUDE) -D__SWITCH__
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++17
CXXWRAPS := -Wl,--wrap,__cxa_pure_virtual \
-Wl,--wrap,__cxa_throw \
-Wl,--wrap,__cxa_rethrow \
-Wl,--wrap,__cxa_allocate_exception \
-Wl,--wrap,__cxa_begin_catch \
-Wl,--wrap,__cxa_end_catch \
-Wl,--wrap,__cxa_call_unexpected \
-Wl,--wrap,__cxa_call_terminate \
-Wl,--wrap,__gxx_personality_v0
ASFLAGS := -g $(ARCH)
LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) $(CXXWRAPS) -Wl,-Map,$(notdir $*.map)
LIBS := -lstratosphere -lnx

View file

@ -205,7 +205,7 @@ namespace sts::pm::impl {
/* Process Launch synchronization globals. */
os::Event g_process_launch_start_event;
os::Event g_process_launch_finish_event;
Result g_process_launch_result = ResultSuccess;
Result g_process_launch_result = ResultSuccess();
LaunchProcessArgs g_process_launch_args = {};
/* Hook globals. */
@ -214,7 +214,7 @@ namespace sts::pm::impl {
/* Forward declarations. */
Result LaunchProcess(os::WaitableManager &waitable_manager, const LaunchProcessArgs &args);
Result OnProcessSignaled(ProcessListAccessor &list, ProcessInfo *process_info);
void OnProcessSignaled(ProcessListAccessor &list, ProcessInfo *process_info);
/* Helpers. */
void ProcessTrackingMain(void *arg) {
@ -270,7 +270,7 @@ namespace sts::pm::impl {
Result StartProcess(ProcessInfo *process_info, const ldr::ProgramInfo *program_info) {
R_TRY(svcStartProcess(process_info->GetHandle(), program_info->main_thread_priority, program_info->default_cpu_id, program_info->main_thread_stack_size));
process_info->SetState(ProcessState_Running);
return ResultSuccess;
return ResultSuccess();
}
void CleanupProcessInfo(ProcessListAccessor &list, ProcessInfo *process_info) {
@ -289,9 +289,7 @@ namespace sts::pm::impl {
const bool allow_debug = (program_info.flags & ldr::ProgramInfoFlag_AllowDebug) || hos::GetVersion() < hos::Version_200;
/* Ensure we only try to run one application. */
if (is_application && HasApplicationProcess()) {
return ResultPmApplicationRunning;
}
R_UNLESS(!is_application || !HasApplicationProcess(), pm::ResultApplicationRunning());
/* Fix the title location to use the right title id. */
const ncm::TitleLocation location = ncm::TitleLocation::Make(program_info.title_id, static_cast<ncm::StorageId>(args.location.storage_id));
@ -300,14 +298,17 @@ namespace sts::pm::impl {
ldr::PinId pin_id;
R_TRY(ldr::pm::PinTitle(&pin_id, location));
/* Ensure resources are available. */
resource::WaitResourceAvailable(&program_info);
/* Actually create the process. */
Handle process_handle;
R_TRY_CLEANUP(ldr::pm::CreateProcess(&process_handle, pin_id, GetLoaderCreateProcessFlags(args.flags), resource::GetResourceLimitHandle(&program_info)), {
ldr::pm::UnpinTitle(pin_id);
});
{
auto pin_guard = SCOPE_GUARD { ldr::pm::UnpinTitle(pin_id); };
R_TRY(ldr::pm::CreateProcess(&process_handle, pin_id, GetLoaderCreateProcessFlags(args.flags), resource::GetResourceLimitHandle(&program_info)));
pin_guard.Cancel();
}
/* Get the process id. */
os::ProcessId process_id = os::GetProcessId(process_handle);
@ -369,11 +370,11 @@ namespace sts::pm::impl {
cleanup_guard.Cancel();
*args.out_process_id = process_id;
return ResultSuccess;
return ResultSuccess();
}
Result OnProcessSignaled(ProcessListAccessor &list, ProcessInfo *process_info) {
/* Resest the process's signal. */
void OnProcessSignaled(ProcessListAccessor &list, ProcessInfo *process_info) {
/* Reset the process's signal. */
svcResetSignal(process_info->GetHandle());
/* Update the process's state. */
@ -442,8 +443,6 @@ namespace sts::pm::impl {
CleanupProcessInfo(list, process_info);
}
}
/* Return ConnectionClosed to cause libstratosphere to stop waiting on the process. */
return ResultKernelConnectionClosed;
case ProcessState_DebugSuspended:
if (process_info->ShouldSignalOnDebugEvent()) {
process_info->SetSuspended();
@ -452,8 +451,6 @@ namespace sts::pm::impl {
}
break;
}
return ResultSuccess;
}
}
@ -472,7 +469,7 @@ namespace sts::pm::impl {
/* Start thread. */
R_ASSERT(g_process_track_thread.Start());
return ResultSuccess;
return ResultSuccess();
}
/* Process Management. */
@ -497,13 +494,8 @@ namespace sts::pm::impl {
ProcessListAccessor list(g_process_list);
auto process_info = list->Find(process_id);
if (process_info == nullptr) {
return ResultPmProcessNotFound;
}
if (process_info->HasStarted()) {
return ResultPmAlreadyStarted;
}
R_UNLESS(process_info != nullptr, pm::ResultProcessNotFound());
R_UNLESS(!process_info->HasStarted(), pm::ResultAlreadyStarted());
ldr::ProgramInfo program_info;
R_TRY(ldr::pm::GetProgramInfo(&program_info, process_info->GetTitleLocation()));
@ -514,9 +506,7 @@ namespace sts::pm::impl {
ProcessListAccessor list(g_process_list);
auto process_info = list->Find(process_id);
if (process_info == nullptr) {
return ResultPmProcessNotFound;
}
R_UNLESS(process_info != nullptr, pm::ResultProcessNotFound());
return svcTerminateProcess(process_info->GetHandle());
}
@ -525,16 +515,14 @@ namespace sts::pm::impl {
ProcessListAccessor list(g_process_list);
auto process_info = list->Find(title_id);
if (process_info == nullptr) {
return ResultPmProcessNotFound;
}
R_UNLESS(process_info != nullptr, pm::ResultProcessNotFound());
return svcTerminateProcess(process_info->GetHandle());
}
Result GetProcessEventHandle(Handle *out) {
*out = g_process_event.GetReadableHandle();
return ResultSuccess;
return ResultSuccess();
}
Result GetProcessEventInfo(ProcessEventInfo *out) {
@ -548,7 +536,7 @@ namespace sts::pm::impl {
process.ClearStartedStateChanged();
out->event = GetProcessEventValue(ProcessEvent::Started);
out->process_id = process.GetProcessId();
return ResultSuccess;
return ResultSuccess();
}
if (process.HasSuspendedStateChanged()) {
process.ClearSuspendedStateChanged();
@ -558,18 +546,18 @@ namespace sts::pm::impl {
out->event = GetProcessEventValue(ProcessEvent::DebugRunning);
}
out->process_id = process.GetProcessId();
return ResultSuccess;
return ResultSuccess();
}
if (process.HasExceptionOccurred()) {
process.ClearExceptionOccurred();
out->event = GetProcessEventValue(ProcessEvent::Exception);
out->process_id = process.GetProcessId();
return ResultSuccess;
return ResultSuccess();
}
if (hos::GetVersion() < hos::Version_500 && process.ShouldSignalOnExit() && process.HasExited()) {
out->event = GetProcessEventValue(ProcessEvent::Exited);
out->process_id = process.GetProcessId();
return ResultSuccess;
return ResultSuccess();
}
}
}
@ -584,48 +572,41 @@ namespace sts::pm::impl {
out->process_id = process_info.GetProcessId();
CleanupProcessInfo(dead_list, &process_info);
return ResultSuccess;
return ResultSuccess();
}
}
out->process_id = os::ProcessId{};
out->event = GetProcessEventValue(ProcessEvent::None);
return ResultSuccess;
return ResultSuccess();
}
Result CleanupProcess(os::ProcessId process_id) {
ProcessListAccessor list(g_process_list);
auto process_info = list->Find(process_id);
if (process_info == nullptr) {
return ResultPmProcessNotFound;
}
if (!process_info->HasExited()) {
return ResultPmNotExited;
}
R_UNLESS(process_info != nullptr, pm::ResultProcessNotFound());
R_UNLESS(process_info->HasExited(), pm::ResultNotExited());
CleanupProcessInfo(list, process_info);
return ResultSuccess;
return ResultSuccess();
}
Result ClearExceptionOccurred(os::ProcessId process_id) {
ProcessListAccessor list(g_process_list);
auto process_info = list->Find(process_id);
if (process_info == nullptr) {
return ResultPmProcessNotFound;
}
R_UNLESS(process_info != nullptr, pm::ResultProcessNotFound());
process_info->ClearExceptionOccurred();
return ResultSuccess;
return ResultSuccess();
}
/* Information Getters. */
Result GetModuleIdList(u32 *out_count, u8 *out_buf, size_t max_out_count, u64 unused) {
/* This function was always stubbed... */
*out_count = 0;
return ResultSuccess;
return ResultSuccess();
}
Result GetExceptionProcessIdList(u32 *out_count, os::ProcessId *out_process_ids, size_t max_out_count) {
@ -638,31 +619,27 @@ namespace sts::pm::impl {
}
}
*out_count = static_cast<u32>(count);
return ResultSuccess;
return ResultSuccess();
}
Result GetProcessId(os::ProcessId *out, ncm::TitleId title_id) {
ProcessListAccessor list(g_process_list);
auto process_info = list->Find(title_id);
if (process_info == nullptr) {
return ResultPmProcessNotFound;
}
R_UNLESS(process_info != nullptr, pm::ResultProcessNotFound());
*out = process_info->GetProcessId();
return ResultSuccess;
return ResultSuccess();
}
Result GetTitleId(ncm::TitleId *out, os::ProcessId process_id) {
ProcessListAccessor list(g_process_list);
auto process_info = list->Find(process_id);
if (process_info == nullptr) {
return ResultPmProcessNotFound;
}
R_UNLESS(process_info != nullptr, pm::ResultProcessNotFound());
*out = process_info->GetTitleLocation().title_id;
return ResultSuccess;
return ResultSuccess();
}
Result GetApplicationProcessId(os::ProcessId *out_process_id) {
@ -671,49 +648,47 @@ namespace sts::pm::impl {
for (auto &process : *list) {
if (process.IsApplication()) {
*out_process_id = process.GetProcessId();
return ResultSuccess;
return ResultSuccess();
}
}
return ResultPmProcessNotFound;
return pm::ResultProcessNotFound();
}
Result AtmosphereGetProcessInfo(Handle *out_process_handle, ncm::TitleLocation *out_loc, os::ProcessId process_id) {
ProcessListAccessor list(g_process_list);
auto process_info = list->Find(process_id);
if (process_info == nullptr) {
return ResultPmProcessNotFound;
}
R_UNLESS(process_info != nullptr, pm::ResultProcessNotFound());
*out_process_handle = process_info->GetHandle();
*out_loc = process_info->GetTitleLocation();
return ResultSuccess;
return ResultSuccess();
}
/* Hook API. */
Result HookToCreateProcess(Handle *out_hook, ncm::TitleId title_id) {
*out_hook = INVALID_HANDLE;
ncm::TitleId old_value = ncm::TitleId::Invalid;
if (!g_title_id_hook.compare_exchange_strong(old_value, title_id)) {
return ResultPmDebugHookInUse;
{
ncm::TitleId old_value = ncm::TitleId::Invalid;
R_UNLESS(g_title_id_hook.compare_exchange_strong(old_value, title_id), pm::ResultDebugHookInUse());
}
*out_hook = g_hook_to_create_process_event.GetReadableHandle();
return ResultSuccess;
return ResultSuccess();
}
Result HookToCreateApplicationProcess(Handle *out_hook) {
*out_hook = INVALID_HANDLE;
bool old_value = false;
if (!g_application_hook.compare_exchange_strong(old_value, true)) {
return ResultPmDebugHookInUse;
{
bool old_value = false;
R_UNLESS(g_application_hook.compare_exchange_strong(old_value, true), pm::ResultDebugHookInUse());
}
*out_hook = g_hook_to_create_application_process_event.GetReadableHandle();
return ResultSuccess;
return ResultSuccess();
}
Result ClearHook(u32 which) {
@ -723,7 +698,7 @@ namespace sts::pm::impl {
if (which & HookType_Application) {
g_application_hook = false;
}
return ResultSuccess;
return ResultSuccess();
}
/* Boot API. */
@ -734,7 +709,7 @@ namespace sts::pm::impl {
g_has_boot_finished = true;
g_boot_finished_event.Signal();
}
return ResultSuccess;
return ResultSuccess();
}
Result GetBootFinishedEventHandle(Handle *out) {
@ -743,7 +718,7 @@ namespace sts::pm::impl {
/* We will signal it always, but only allow this function to succeed on safe mode. */
STS_ASSERT(spl::IsRecoveryBoot());
*out = g_boot_finished_event.GetReadableHandle();
return ResultSuccess;
return ResultSuccess();
}
/* Resource Limit API. */

View file

@ -14,6 +14,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stratosphere.hpp>
#include <stratosphere/spl.hpp>
#include "pm_resource_manager.hpp"
@ -107,11 +108,15 @@ namespace sts::pm::resource {
Result SetMemoryResourceLimitLimitValue(ResourceLimitGroup group, u64 new_memory_limit) {
const u64 old_memory_limit = g_resource_limits[group][LimitableResource_Memory];
g_resource_limits[group][LimitableResource_Memory] = new_memory_limit;
R_TRY_CLEANUP(svcSetResourceLimitLimitValue(GetResourceLimitHandle(group), LimitableResource_Memory, g_resource_limits[group][LimitableResource_Memory]), {
{
/* If we fail, restore the old memory limit. */
g_resource_limits[group][LimitableResource_Memory] = old_memory_limit;
});
return ResultSuccess;
auto limit_guard = SCOPE_GUARD { g_resource_limits[group][LimitableResource_Memory] = old_memory_limit; };
R_TRY(svcSetResourceLimitLimitValue(GetResourceLimitHandle(group), LimitableResource_Memory, g_resource_limits[group][LimitableResource_Memory]));
limit_guard.Cancel();
}
return ResultSuccess();
}
Result SetResourceLimitLimitValues(ResourceLimitGroup group, u64 new_memory_limit) {
@ -126,7 +131,7 @@ namespace sts::pm::resource {
}
R_TRY(svcSetResourceLimitLimitValue(GetResourceLimitHandle(group), resource, g_resource_limits[group][resource]));
}
return ResultSuccess;
return ResultSuccess();
}
inline ResourceLimitGroup GetResourceLimitGroup(const ldr::ProgramInfo *info) {
@ -269,14 +274,12 @@ namespace sts::pm::resource {
}
}
return ResultSuccess;
return ResultSuccess();
}
Result BoostSystemMemoryResourceLimit(u64 boost_size) {
/* Don't allow all application memory to be taken away. */
if (boost_size > g_memory_resource_limits[g_memory_arrangement][ResourceLimitGroup_Application]) {
return ResultPmInvalidSize;
}
R_UNLESS(boost_size <= g_memory_resource_limits[g_memory_arrangement][ResourceLimitGroup_Application], pm::ResultInvalidSize());
const u64 new_app_size = g_memory_resource_limits[g_memory_arrangement][ResourceLimitGroup_Application] - boost_size;
{
@ -305,7 +308,7 @@ namespace sts::pm::resource {
g_system_memory_boost_size = boost_size;
}
return ResultSuccess;
return ResultSuccess();
}
Result BoostApplicationThreadResourceLimit() {
@ -318,7 +321,7 @@ namespace sts::pm::resource {
g_resource_limits[ResourceLimitGroup_Application][LimitableResource_Threads] = new_thread_count;
g_extra_application_threads_available = 0;
return ResultSuccess;
return ResultSuccess();
}
Handle GetResourceLimitHandle(ResourceLimitGroup group) {
@ -347,7 +350,7 @@ namespace sts::pm::resource {
R_TRY(svcGetResourceLimitCurrentValue(out_cur, reslimit_hnd, resource));
R_TRY(svcGetResourceLimitLimitValue(out_lim, reslimit_hnd, resource));
return ResultSuccess;
return ResultSuccess();
}
}

View file

@ -22,16 +22,12 @@ namespace sts::pm::dmnt {
/* Actual command implementations. */
Result DebugMonitorServiceBase::GetModuleIdList(sf::Out<u32> out_count, const sf::OutBuffer &out_buf, u64 unused) {
if (out_buf.GetSize() > std::numeric_limits<s32>::max()) {
return ResultPmInvalidSize;
}
R_UNLESS(out_buf.GetSize() <= std::numeric_limits<s32>::max(), pm::ResultInvalidSize());
return impl::GetModuleIdList(out_count.GetPointer(), out_buf.GetPointer(), out_buf.GetSize(), unused);
}
Result DebugMonitorServiceBase::GetExceptionProcessIdList(sf::Out<u32> out_count, const sf::OutArray<os::ProcessId> &out_process_ids) {
if (out_process_ids.GetSize() > std::numeric_limits<s32>::max()) {
return ResultPmInvalidSize;
}
R_UNLESS(out_process_ids.GetSize() <= std::numeric_limits<s32>::max(), pm::ResultInvalidSize());
return impl::GetExceptionProcessIdList(out_count.GetPointer(), out_process_ids.GetPointer(), out_process_ids.GetSize());
}

View file

@ -56,6 +56,12 @@ namespace sts::ams {
}
namespace sts::result {
bool CallFatalOnResultAssertion = false;
}
using namespace sts;
void __libnx_exception_handler(ThreadExceptionDump *ctx) {