In a real 3DS, threads that call svcSyncRequest are put to sleep until the server responds via svcReplyAndReceive. Our HLE services don't implement this mechanism and are effectively immediate from the 3DS's point of view. This commit makes it so that we at least simulate the IPC delay.
Specific HLE handlers might need to put their callers to sleep for a longer period of time to simulate IO timings. This is their responsibility but doing so is currently not implemented.
See https://gist.github.com/ds84182/4a7690c5376e045cab9129ca4185bbeb for a test that was not passing before this commit.
Kernel/Threads: Add a new thread status that will allow using a Kernel::Event to put a guest thread to sleep inside an HLE handler until said event is signaled
This could happen if the guest application performs a request with static buffer id X, and the service module responds with another static buffer with the same id X.
Kernel/Arbiters: When doing ArbitrateAddress(Signal), always pick the highest priority thread, using the first one that was put to sleep if more than one thread with the same highest priority exists.
The real kernel requires services to set up their static buffer targets ahead of time. This implementation does not require that and will simply create the storage for the buffers as they are processed in the incoming IPC request.
Static buffers are kept in an unordered_map keyed by their buffer id, and are written into the already-setup area of the request thread when responding an IPC request.
This fixes a regression (crash) introduced in #2992.
This PR introduces more warnings due to the [[deprecated]] attribute being added to void PushStaticBuffer(VAddr buffer_vaddr, size_t size, u8 buffer_id); and VAddr PopStaticBuffer(size_t* data_size);
The error code 0xC920181A will be returned by svcReplyAndReceive when the wakeup callback runs.
This lets LLE services be properly notified of clients closing the connection so they can end their handler threads instead of letting them linger indefinitely, taking up connection slots in their parent port.
This descriptor requires the target process to set up a "receive buffer" beforehand, where the input data will be written to when the descriptor is processed.
This change makes for a clearer (less confusing) path of execution in the scheduler, now the code to execute when a thread awakes is closer to the code that puts the thread to sleep (WaitSynch1, WaitSynchN). It also allows us to implement the special wake up behavior of ReplyAndReceive without hacking up WaitObject::WakeupAllWaitingThreads.
If savestates are desired in the future, we can change this implementation to one similar to the CoreTiming event system, where we first register the callback functions at startup and assign their identifiers to the Thread callback variable instead of directly assigning a lambda to the wake up callback variable.
Don't automatically assume that Thread::Create will only be called when the parent process is currently scheduled. This assumption will be broken when applets or system modules are loaded.
Kernel/HLE: Use a mutex to synchronize access to the HLE kernel state between the cpu thread and any other possible threads that might touch the kernel (network thread, etc).