App Lifecycle¶
Every ReXGlue program is a class derived from rex::app::App, or from rex::app::TitleApp when it runs a game. The app object starts and stops the SDK. This page lists the steps the app runs, the hooks it calls during them, and the order in which a program starts, runs a title and stops.
Steps and Hooks¶
A step is a public method of the app that the program calls. A hook is a virtual method that a step calls at a fixed point, and that your class overrides to add its own work. Every hook does nothing or returns success by default.
App has four steps:
Initloads the modules, applies the settings and starts the systems.RunFrameruns one frame of the UI loop.Runcalls theOnRunhook, which by default callsRunFrameuntil a shutdown is requested.Shutdownstops everything thatInitstarted and returns the exit code. It is safe to call after a failedInit.
TitleApp adds two steps for the game:
LaunchTitleloads the title, callsOnTitleLaunchand starts it.UnloadTitlestops the title and frees its memory. A program can launch and unload the title any number of times.
See App and TitleApp in the API reference for the purpose of each hook.
UI Thread¶
The UI thread is the thread that calls App::Init. It runs the window and its event loop. In a TitleApp, every step and every hook runs on the UI thread.
- To run code on the UI thread from another thread, call
IUISystem::PostTask. IUISystem::HasWindowreturns false when the program runs headless, with no window.
Phases¶
App::GetPhase returns the AppPhase, the part of the lifecycle that is running. Only a TitleApp enters the three title phases.
stateDiagram-v2
[*] --> kStart : Init
kStart --> kProviders : settings applied
kStart --> kShutdown : Shutdown
kProviders --> kRunning : modules started
kProviders --> kShutdown : Shutdown
kRunning --> kTitleLaunch : LaunchTitle
kTitleLaunch --> kTitleRunning : launched
kTitleLaunch --> kRunning : launch fails
kTitleRunning --> kTitleStop : UnloadTitle
kTitleStop --> kRunning
kRunning --> kShutdown : Shutdown
kTitleRunning --> kShutdown : Shutdown
kShutdown --> [*]
Entry Macros¶
An entry macro defines main, and wWinMain on Windows. It parses the command line, constructs the app with its default constructor and calls the steps.
| Macro | Runs |
|---|---|
REX_CONSOLE_APP |
Init, then Run if it succeeded, then Shutdown. |
REX_TITLE_APP |
Init and LaunchTitle while each succeeds, then Run, then Shutdown. |
REX_CONSOLE_APP_MAIN, REX_TITLE_APP_MAIN |
Your function, which receives the app and the command line and returns the exit code. |
To run work between steps, such as an installer before the launch, use a _MAIN macro:
int GameMain(Game& game, const rex::CLIArgList& args) {
if (game.Init(args)) {
while (game.NeedsInstall() && game.RunFrame()) {
}
if (game.LaunchTitle()) {
game.Run();
}
}
return game.Shutdown();
}
REX_TITLE_APP_MAIN(Game, GameMain)
If an exception escapes, the entry macro prints it to standard error and returns 1.
Startup Order¶
REX_TITLE_APP runs the steps in this order and goes to Shutdown at the first step that fails:
flowchart TD
A["Parse the command line"] --> B["Construct the app"]
B --> C{"Init ok"}
C -->|no| S["Shutdown"]
C -->|yes| E{"LaunchTitle ok"}
E -->|no| S
E -->|yes| F["Run the UI loop"]
F --> S
S --> G["Return the exit code"]
See Exit Code for the value that main returns.
Init¶
App::Init runs these steps on the UI thread:
- The app installs the signal handlers and registers its own settings
app.name,app.root,app.log_rootandapp.single_instance. OnModulesruns, so the program can change the list of module libraries, andOnRegisterModulesruns, so it can add code modules.rex::Initloads and connects the modules. Each module registers its settings and log categories.- The app sets
app.nameandapp.rootat the title layer, then callsOnConfigure. - The app calls
GetActionsand reads the command line. OnActionruns once for each action given on the command line.- If
app.single_instanceis not empty, the app takes the instance lock of that name. - If the config file exists, the app loads it.
- The app applies the
REX_environment variables. - The app opens the log file.
- The app installs the crash reporter with the options from
GetCrashOptions. - The app calls
GetRequirementsand collects the driver modules that the driver settings select. rex::Initloads the driver modules, starts the profiler ifperf.profileris set, and inits every module. Each system starts its drivers. On Windows,rex::Initraises the timer resolution to 1 ms.- The app freezes the
kStartupOnlysettings. OnInitruns. The systems run and the window is open.- The app reports each setting name from a source that no settings class declares.
A shutdown or restart requested in OnConfigure or in OnAction ends Init after step 10, once the log file is open and holds what OnConfigure and OnAction logged. The instance lock and the config file apply before that point, and a failure in them is an error as usual. No driver module loads, OnInit does not run, Init returns Ok and logs no error, and the program goes on to Shutdown, which starts the new process when a restart was requested. A caller that calls Init itself tells this from a finished start with rex::app::IsShutdownRequested. A request made in OnInit or later does not change the start.
Steps 4 to 12 run inside the select_plugins callback of rex::Init, after the modules connect and before they init. See Modules and Interfaces for that callback.
The system getters such as GetUI work from OnConfigure on. A value that OnConfigure sets goes to the title layer, so the config file, the environment and the command line override it. See Sources and Precedence.
Failures¶
A failed step calls ReportError, which logs the error, and App::Init returns the error. TitleApp shows the error in a message box unless the program runs headless.
| Step | Fails when |
|---|---|
| 3, 13 | A module fails to load, connect or init. A driver module that fails to load only logs a warning, but a system that needs it then fails to init. |
| 4, 6, 15 | OnConfigure, OnAction or OnInit returns an error. |
| 5 | An option is not a setting name, an action or one of the older options, or a setting rejects its value. GetActions returns an action with an invalid name, a duplicate name or the name of an older option. |
| 7 | Another running copy holds the instance lock. |
| 8 | The config file does not parse. A missing file is not an error. Clearing app.config_file in OnConfigure skips the step. |
| 13 | A system that the app requires has no driver. A TitleApp fails when gpu.driver, apu.driver, ui.driver or hid.drivers is none. |
| 16 | No settings class declares a setting name from the command line. A name from the config file or the environment only logs a warning. |
See Selecting Drivers for the driver settings.
LaunchTitle¶
TitleApp::LaunchTitle returns success without loading anything when a shutdown was requested. It fails when title.game_root is empty or is not a folder. Otherwise it runs these steps:
- The app calls
TitleRuntime::Load. - The app registers the exit callback, which posts
TitleApp::OnTitleExitto the UI thread. - The app calls
OnTitleLaunch. If the hook returns an error, the title unloads and the launch fails. - The app calls
TitleRuntime::Launch.
From step 4 until the title unloads, a write to a kUntilLaunch setting such as title.game_root fails. See Runtime Lifecycle for what Load and Launch do.
Title Exit¶
A title can end on its own. The runtime then reports one of these kernel::TitleExitReason values:
| Reason | Cause |
|---|---|
kNormalExit |
The main thread of the title returns. The other guest threads run until the title unloads. |
kHardExit |
The title calls HalReturnToFirmware. |
kTitleDataError |
XAM reports that title data could not be read from the disc. |
kBugCheck |
The title calls KeBugCheck or KeBugCheckEx. |
The last three stop every guest thread at once. In every case TitleApp::OnTitleExit runs on the UI thread. It does not run when the program unloads the title with UnloadTitle or Shutdown.
The default OnTitleExit requests a shutdown with exit code 0 when a shutdown was requested before or no window is open. Otherwise it asks the player to restart the title or exit. If the player closes the prompt, nothing changes. If the restart fails to launch the title, the app requests a shutdown with exit code 1.
flowchart TD
A["Title exits"] --> B["OnTitleExit"]
B --> C{"Shutdown requested"}
C -->|yes| D["RequestShutdown 0"]
C -->|no| W{"Window open"}
W -->|no| D
W -->|yes| E["Prompt Restart or Exit"]
E -->|Exit| D
E -->|Closed| N["No change"]
E -->|Restart| F["UnloadTitle, LaunchTitle"]
F -->|fails| X["RequestShutdown 1"]
To return to your own launcher instead, override OnTitleExit.
Shutdown¶
A shutdown starts with a request, and the program then calls App::Shutdown, which the entry macros do after Run returns.
rex::app::RequestShutdownrequests a shutdown with an exit code. It works from any thread.rex::app::RequestRestartrequests a shutdown with code 0, then starts the process again with the given arguments or the original ones. Under gamescope on Linux the process does not start again.- Closing the window requests a shutdown with exit code 0.
- Ctrl+C, Ctrl+Break and closing the console window on Windows, and SIGINT and SIGTERM on Linux and macOS, request a shutdown with exit code 0.
Teardown Order¶
App::Shutdown runs these steps:
OnStopruns.TitleApp::OnStopends the frame loop, cancels open prompts and callsTitleRuntime::Unload.- The unload waits for every guest thread to stop. See Stopping a Thread.
- If
OnInitfinished,OnShutdownruns. Logging and settings work here. OnReleaseruns.TitleApp::OnReleaseshuts down COM on Windows.- The app removes its settings, releases the instance lock and calls
rex::Stop, which shuts down and disconnects the modules. - If a restart was requested, the app starts the new process.
- The app flushes the log and removes the signal handlers.
The App destructor then calls rex::Shutdown, which unloads the module libraries and ends the settings and logger sessions.
Exit Code¶
The exit code is the code of the first RequestShutdown. Later requests do not change it. Without a request, the code is 1 if a step failed and 0 otherwise.
Lifetimes¶
| Object | Valid until |
|---|---|
A context or factory passed to Initialize or Connect |
The matching Shutdown or Disconnect returns. |
| Guest memory of the title | TitleRuntime::Unload |
The process logger from REX_LOGGER() |
The process ends. |