haze: tear down sessions on suspension

This commit is contained in:
Liam 2023-04-17 11:08:37 -04:00
parent a1175feab1
commit d0364c31cc
8 changed files with 125 additions and 56 deletions

View File

@ -45,12 +45,16 @@ namespace haze {
int idx; int idx;
while (true) { while (true) {
/* Wait for up to 1 frame delay time to be cancelled. */
Waiter cancel_waiter = waiterForUEvent(std::addressof(m_cancel_event)); Waiter cancel_waiter = waiterForUEvent(std::addressof(m_cancel_event));
Result rc = waitObjects(std::addressof(idx), std::addressof(cancel_waiter), 1, FrameDelayNs); Result rc = waitObjects(std::addressof(idx), std::addressof(cancel_waiter), 1, FrameDelayNs);
/* Finish if we were cancelled. */
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {
break; break;
} }
/* Otherwise, signal the console update event. */
if (svc::ResultTimedOut::Includes(rc)) { if (svc::ResultTimedOut::Includes(rc)) {
ueventSignal(std::addressof(m_event)); ueventSignal(std::addressof(m_event));
} }
@ -154,13 +158,91 @@ namespace haze {
/* If the plus button is held, request immediate exit. */ /* If the plus button is held, request immediate exit. */
if (padGetButtonsDown(std::addressof(m_pad)) & HidNpadButton_Plus) { if (padGetButtonsDown(std::addressof(m_pad)) & HidNpadButton_Plus) {
m_reactor->RequestStop(); m_reactor->SetResult(haze::ResultStopRequested());
} }
/* Pump applet event loop. */ /* Pump applet events, and check if exit was requested. */
if (!appletMainLoop()) { if (!appletMainLoop()) {
m_reactor->RequestStop(); m_reactor->SetResult(haze::ResultStopRequested());
} }
/* Check if focus was lost. */
if (appletGetFocusState() == AppletFocusState_Background) {
m_reactor->SetResult(haze::ResultFocusLost());
}
}
private:
static bool SuspendAndWaitForFocus() {
/* Enable suspension with resume notification. */
appletSetFocusHandlingMode(AppletFocusHandlingMode_SuspendHomeSleepNotify);
/* Pump applet events. */
while (appletMainLoop()) {
/* Check if focus was regained. */
if (appletGetFocusState() != AppletFocusState_Background) {
return true;
}
}
/* Exit was requested. */
return false;
}
public:
static void RunApplication() {
/* Declare the object heap, to hold the database for an active session. */
PtpObjectHeap ptp_object_heap;
/* Declare the event reactor, and components which use it. */
EventReactor event_reactor;
PtpResponder ptp_responder;
ConsoleMainLoop console_main_loop;
/* Initialize the console.*/
consoleInit(nullptr);
while (true) {
/* Disable suspension. */
appletSetFocusHandlingMode(AppletFocusHandlingMode_NoSuspend);
/* Declare result from serving to use. */
Result rc;
{
/* Ensure we don't go to sleep while transferring files. */
appletSetAutoSleepDisabled(true);
/* Clear the event reactor. */
event_reactor.SetResult(ResultSuccess());
/* Configure the PTP responder and console main loop. */
ptp_responder.Initialize(std::addressof(event_reactor), std::addressof(ptp_object_heap));
console_main_loop.Initialize(std::addressof(event_reactor), std::addressof(ptp_object_heap));
/* Ensure we maintain a clean state on exit. */
ON_SCOPE_EXIT {
/* Finalize the console main loop and PTP responder. */
console_main_loop.Finalize();
ptp_responder.Finalize();
/* Restore auto sleep setting. */
appletSetAutoSleepDisabled(false);
};
/* Begin processing requests. */
rc = ptp_responder.LoopProcess();
}
/* If focus was lost, try to pump the applet main loop until we receive focus again. */
if (haze::ResultFocusLost::Includes(rc) && SuspendAndWaitForFocus()) {
continue;
}
/* Otherwise, enable suspension and finish. */
appletSetFocusHandlingMode(AppletFocusHandlingMode_SuspendHomeSleep);
break;
}
/* Finalize the console. */
consoleExit(nullptr);
} }
}; };

View File

@ -30,15 +30,15 @@ namespace haze {
EventConsumer *m_consumers[svc::ArgumentHandleCountMax]; EventConsumer *m_consumers[svc::ArgumentHandleCountMax];
Waiter m_waiters[svc::ArgumentHandleCountMax]; Waiter m_waiters[svc::ArgumentHandleCountMax];
s32 m_num_wait_objects; s32 m_num_wait_objects;
bool m_stop_requested; Result m_result;
public: public:
constexpr explicit EventReactor() : m_consumers(), m_waiters(), m_num_wait_objects(), m_stop_requested() { /* ... */ } constexpr explicit EventReactor() : m_consumers(), m_waiters(), m_num_wait_objects(), m_result(ResultSuccess()) { /* ... */ }
bool AddConsumer(EventConsumer *consumer, Waiter waiter); bool AddConsumer(EventConsumer *consumer, Waiter waiter);
void RemoveConsumer(EventConsumer *consumer); void RemoveConsumer(EventConsumer *consumer);
public: public:
void RequestStop() { m_stop_requested = true; } void SetResult(Result r) { m_result = r; }
bool GetStopRequested() const { return m_stop_requested; } Result GetResult() const { return m_result; }
public: public:
template <typename... Args> template <typename... Args>
Result WaitFor(s32 *out_arg_waiter, Args &&... arg_waiters) { Result WaitFor(s32 *out_arg_waiter, Args &&... arg_waiters) {

View File

@ -45,7 +45,7 @@ namespace haze {
const Result rc = func(std::forward<Args>(args)...); const Result rc = func(std::forward<Args>(args)...);
/* If the event loop was stopped, return that here. */ /* If the event loop was stopped, return that here. */
R_UNLESS(!m_reactor->GetStopRequested(), haze::ResultStopRequested()); R_TRY(m_reactor->GetResult());
/* Otherwise, return the call result. */ /* Otherwise, return the call result. */
R_RETURN(rc); R_RETURN(rc);

View File

@ -40,9 +40,10 @@ namespace haze {
Result Initialize(EventReactor *reactor, PtpObjectHeap *object_heap); Result Initialize(EventReactor *reactor, PtpObjectHeap *object_heap);
void Finalize(); void Finalize();
public: public:
Result HandleRequest(); Result LoopProcess();
private: private:
/* Request handling. */ /* Request handling. */
Result HandleRequest();
Result HandleRequestImpl(); Result HandleRequestImpl();
Result HandleCommandRequest(PtpDataParser &dp); Result HandleCommandRequest(PtpDataParser &dp);
void ForceCloseSession(); void ForceCloseSession();

View File

@ -26,16 +26,16 @@ namespace haze {
R_DEFINE_ERROR_RESULT(NotConfigured, 2); R_DEFINE_ERROR_RESULT(NotConfigured, 2);
R_DEFINE_ERROR_RESULT(TransferFailed, 3); R_DEFINE_ERROR_RESULT(TransferFailed, 3);
R_DEFINE_ERROR_RESULT(StopRequested, 4); R_DEFINE_ERROR_RESULT(StopRequested, 4);
R_DEFINE_ERROR_RESULT(EndOfTransmission, 5); R_DEFINE_ERROR_RESULT(FocusLost, 5);
R_DEFINE_ERROR_RESULT(UnknownPacketType, 6); R_DEFINE_ERROR_RESULT(EndOfTransmission, 6);
R_DEFINE_ERROR_RESULT(SessionNotOpen, 7); R_DEFINE_ERROR_RESULT(UnknownPacketType, 7);
R_DEFINE_ERROR_RESULT(OutOfMemory, 8); R_DEFINE_ERROR_RESULT(SessionNotOpen, 8);
R_DEFINE_ERROR_RESULT(InvalidObjectId, 9); R_DEFINE_ERROR_RESULT(OutOfMemory, 9);
R_DEFINE_ERROR_RESULT(InvalidStorageId, 10); R_DEFINE_ERROR_RESULT(InvalidObjectId, 10);
R_DEFINE_ERROR_RESULT(OperationNotSupported, 11); R_DEFINE_ERROR_RESULT(InvalidStorageId, 11);
R_DEFINE_ERROR_RESULT(UnknownRequestType, 12); R_DEFINE_ERROR_RESULT(OperationNotSupported, 12);
R_DEFINE_ERROR_RESULT(UnknownPropertyCode, 13); R_DEFINE_ERROR_RESULT(UnknownRequestType, 13);
R_DEFINE_ERROR_RESULT(InvalidPropertyValue, 14); R_DEFINE_ERROR_RESULT(UnknownPropertyCode, 14);
R_DEFINE_ERROR_RESULT(GeneralFailure, 15); R_DEFINE_ERROR_RESULT(InvalidPropertyValue, 15);
} }

View File

@ -53,7 +53,7 @@ namespace haze {
HAZE_ASSERT(m_num_wait_objects + num_arg_waiters <= svc::ArgumentHandleCountMax); HAZE_ASSERT(m_num_wait_objects + num_arg_waiters <= svc::ArgumentHandleCountMax);
while (true) { while (true) {
R_UNLESS(!m_stop_requested, haze::ResultStopRequested()); R_TRY(m_result);
/* Insert waiters from argument list. */ /* Insert waiters from argument list. */
for (s32 i = 0; i < num_arg_waiters; i++) { for (s32 i = 0; i < num_arg_waiters; i++) {

View File

@ -17,38 +17,8 @@
#include <haze/console_main_loop.hpp> #include <haze/console_main_loop.hpp>
int main(int argc, char **argv) { int main(int argc, char **argv) {
/* Declare the object heap, to hold the database for an active session. */ /* Run the application. */
haze::PtpObjectHeap ptp_object_heap; haze::ConsoleMainLoop::RunApplication();
/* Declare the event reactor, and components which use it. */
haze::EventReactor event_reactor;
haze::PtpResponder ptp_responder;
haze::ConsoleMainLoop console_main_loop;
/* Initialize the console.*/
consoleInit(nullptr);
/* Ensure we don't go to sleep while transferring files. */
appletSetAutoSleepDisabled(true);
/* Configure the PTP responder and console main loop. */
ptp_responder.Initialize(std::addressof(event_reactor), std::addressof(ptp_object_heap));
console_main_loop.Initialize(std::addressof(event_reactor), std::addressof(ptp_object_heap));
/* Process events until the user requests exit. */
while (!event_reactor.GetStopRequested()) {
ptp_responder.HandleRequest();
}
/* Finalize the console main loop and PTP responder. */
console_main_loop.Finalize();
ptp_responder.Finalize();
/* Restore auto sleep setting. */
appletSetAutoSleepDisabled(false);
/* Finalize the console. */
consoleExit(nullptr);
/* Return to the loader. */ /* Return to the loader. */
return 0; return 0;

View File

@ -191,6 +191,25 @@ namespace haze {
m_fs.Finalize(); m_fs.Finalize();
} }
Result PtpResponder::LoopProcess() {
while (true) {
/* Try to handle a request. */
R_TRY_CATCH(this->HandleRequest()) {
R_CATCH(haze::ResultStopRequested, haze::ResultFocusLost) {
/* If we encountered a stop condition, we're done.*/
R_THROW(R_CURRENT_RESULT);
}
R_CATCH_ALL() {
/* On other failures, try to handle another request. */
continue;
}
} R_END_TRY_CATCH;
/* Otherwise, handle the next request. */
/* ... */
}
}
Result PtpResponder::HandleRequest() { Result PtpResponder::HandleRequest() {
ON_RESULT_FAILURE { ON_RESULT_FAILURE {
/* For general failure modes, the failure is unrecoverable. Close the session. */ /* For general failure modes, the failure is unrecoverable. Close the session. */
@ -223,9 +242,6 @@ namespace haze {
/* Errors from fs are typically recoverable. */ /* Errors from fs are typically recoverable. */
R_TRY(this->WriteResponse(PtpResponseCode_GeneralError)); R_TRY(this->WriteResponse(PtpResponseCode_GeneralError));
} }
R_CATCH_ALL() {
R_THROW(haze::ResultGeneralFailure());
}
} R_END_TRY_CATCH; } R_END_TRY_CATCH;
R_SUCCEED(); R_SUCCEED();