Async IPC continuations can finish while System::Shutdown is tearing down service, kernel, and timing state. The dump showed an HTTP ReceiveData RunAsync task calling Thread::WakeAfterDelay after shutdown had begun, which reached Core::Timing::ScheduleEvent with invalid timing state and crashed.
Mark KernelSystem as shutting down at the start of System::Shutdown and in the kernel destructor. Route RunAsync and RunOnThreadWorker completions through HLERequestContext::WakeAfterAsync, which skips scheduling guest-thread wakes once shutdown starts and balances the pending async counter instead.
Validation: git diff --check
The previous NullWaitObject fix only covered WaitSynchronizationN (0x25).
WaitSynchronization1 (0x24) had the same issue: handle=0 returned
ResultInvalidHandle immediately, crashing any process whose wait handle
had not been populated yet.
Apply the same fix: handle=0 is substituted with a NullWaitObject so the
thread sleeps until the timeout expires and receives ResultTimeout, matching
real hardware behaviour.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
svc.cpp / kernel:
- Add NullWaitObject: handle=0 in svcWaitSynchronizationN is treated as a
permanently-unavailable slot (never fires) instead of returning
ResultInvalidHandle. Official Nintendo APT library builds pass aptSleepSync=0
when sleeping for HOME Menu; real hardware silently ignores null slots and lets
the other handles (APT:Parameter) drive the wakeup.
- Process now inherits WaitObject so svcWaitSynchronizationN on process handles
works correctly. LLE HOME Menu waits on a process handle during startup;
previously Azahar returned ResultInvalidHandle because Process only extended
Object, not WaitObject. Process becomes available (ShouldWait=false) when it
exits; TerminateProcess calls WakeupAllWaitingThreads.
applet_manager.cpp / apt.cpp:
- RequestForSysApplet auto-Response now attaches a pre-signaled event so the
application can svcWaitSynchronizationN on the received handle without hanging.
- Wakeup parameters with no object now get a pre-signaled event (same fix).
- RegisterApplet initial Wakeup now sends a pre-signaled event.
- LeaveHomeMenu: supply a pre-signaled event when HOME Menu passes handle=0, so
the application does not crash when it calls svcSignalEvent on the result.
- Removed the old logic that force-nulled objects on system→application sends
(this was masking the real issue and breaking Wakeup handle delivery).
cfg.cpp:
- GetRegion defaults from_secure_info=true so CFGU_SecureInfoGetRegion reads
SecureInfo_A (contains the hardware region) instead of falling back to
auto-detect which returned JPN(0) for 3DSX homebrew with no preferred regions.
fs_user.cpp/h:
- Implement GetSdmcCtrRootPath (0x0848): returns /Nintendo 3DS/<ID0>/<ID1> as a
UTF-16LE wide string.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* Add random delay to app main thread
* Suggestions
* Remove randomness, only delay with lle
* Apply suggestions
* Fix clang format
* Fix compilation (again)
* Remove unused include
* Implement some missing/wrong AC functionality.
* Schedule NDM connect event into the future
* Disable NDM connect for now as it's causing issues
* Apply latest changes and suggestions.
* Workaround to fake wifi connection.
* Add missing command to ac:i
* Fix compilation
* Fix error codes for CamcelConnectAsync
* Fix missing global state.
* do not move constant variables
* applet_manager: avoid possible use after move
* use constant references where pointed out by msvc
* extra_hid: initialize response
* ValidateSaveState: passing slot separately is not necessary
* common: mark HashCombine as nodiscard
* cityhash: remove use of using namespace std
* Prefix all size_t with std::
done automatically by executing regex replace `([^:0-9a-zA-Z_])size_t([^0-9a-zA-Z_])` -> `$1std::size_t$2`
based on 7d8f115
* shared_memory.cpp: fix log error format
* fix compiling with pch off
* core: Config plg_ldr after its creation
* Also use service manager to retrieve the service
* thread: Release resource limit in Thread::Stop
* service: Undo plgldr change
* kernel: Switch to atmosphere style macros
* code: Rename ResultCode to Result
* code: Result constants are lower case
* Address review comments
* core: Remove CASCADE_CODE
* R_TRY replaces completely
* core: Run clang format
* renderer_gl: Make rasterizer normal class member
* It doesn't need to be heap allocated anymore
* gl_rasterizer: Remove default_texture
* It's unused
* gl_rasterizer: General cleanup
* gl_rasterizer: Lower case lambdas
* Match style with review comments from vulkan backend
* rasterizer_cache: Prevent memory leak
* Since the switch from shared_ptr these surfaces were no longer being destroyed properly. Use our garbage collector for that purpose to destroy it safely for both backends
* rasterizer_cache: Make temp copy of old surface
* The custom surface would override the memory region of the old region resulting in garbage data, this ensures the custom surface is constructed correctly
* citra_qt: Manually create dialog tabs
* Allows for custom constructors which is very useful. While at it, global state is now eliminated from configuration
* citra_qt: Eliminate global system usage
* core: Remove global system usage in memory and HIO
* citra_qt: Use qOverload
* tests: Run clang format
* gl_texture_runtime: Fix surface scaling
* service/apt: Add and implement more service commands.
* service/apt: Implement power button.
* Address review comments and fix GetApplicationRunningMode bug.
* kernel: Properly clean up process threads on exit.
* kernel: Track process-owned memory and free on destruction.
* apt: Implement DoApplicationJump via home menu when available.
* kernel: Move TLS allocation management to owning process.