Skip to content

Instantly share code, notes, and snippets.

@neobrain
Forked from Subv/kernel_scheduling.md
Created December 3, 2016 18:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save neobrain/8b0e8a4a3252418a8d76a3b4b51766f9 to your computer and use it in GitHub Desktop.
Save neobrain/8b0e8a4a3252418a8d76a3b4b51766f9 to your computer and use it in GitHub Desktop.
Nintendo 3DS Kernel scheduler findings

Kernel synchronization

  • Each core has its own KScheduler instance.

KObject waitlists

Each KObject manages a list of threads that are waiting on it. This list is iterated over each time the KObject is signaled.

The KObject will try to retrieve the KThread with the highest priority from this list, check if it is ready to run (See KThread waitlist), and append it to the scheduler's queue if it is ready.

This awakening operation is performed for every KThread that is ready to run.

KThread waitlist

Each KThread has a list of objects that it is waiting on as a result of a WaitSynchronizationN call. A KThread will only be added to the scheduler's queue if all of the objects in this list are signalled and ready.

This list is reset during a WaitSynchronizationN call, and is unused otherwise.

WaitSynchronization1

When called with Timeout = 0, WaitSynchronization1 does not cause a reschedule if the KObject is already signalled, it only acquires it and returns control to the caller thread.

On the other hand, if Timeout is 0 but the KObject is not ready, it will immediately return error code 0x9401BFE and return control to the caller thread.

If the KObject is not ready and the Timeout is greater than 0, WaitSynchronization1 will add the KThread to the KObject's waitlist and suspend the thread, to be awoken later by the KObject during the signalling procedure.

If the KObject is ready and Timeout is not 0, the KObject is acquired and no reschedule happens.

The KThread waitlist is left untouched by this function.

WaitSynchronizationN

WaitSynchronizationN has two divergent behaviors, it either waits until all the objects are ready, or waits until one of the objects are ready.

WaitSynchronizationN will clear the KThread's waitlist and add the KThread to each of the KObjects' waitlist regardless of the wait mode used. However, only wait_all = true will re-populate the KThread's waitlist with the KObjects.

Waiting for any object (wait_all = false)

In this mode, WaitSynchronizationN will iterate over the KObjects in order and acquire the first one that is ready.

If the specified Timeout is 0, no rescheduling will be performed and error code 0x9401BFE will be returned in case that no KObjects were available.

If no Timeout was specified (-1) and an object was available, said object will be acquired and no rescheduling will be performed.

However, if a Timeout value greater than 0 was given, then the thread will be suspended for up to the specified amount of time if no KObjects were ready.

Waiting for all objects (wait_all = true)

In this mode, the kernel will first check if all the objects are ready before acquiring them all.

If the specified Timeout is 0, no rescheduling will be performed and error code 0x9401BFE will be returned in case that not all the KObjects were available.

If the KThread couldn't acquire all objects, and an unknown field in KThread is true (offset 0x36), then the thread is descheduled and added to the scheduler's queue again (Presumably to force a context switch?), and the WaitSynchronizationN call returns 0xD920060D

If the aforementioned KThread field (offset 0x36) is false, WaitSynchronizationN will add the thread to each object's waitlist and add all objects to the thread's waitlist. The thread will be suspended with the specified timeout (if it is greater than zero).

There is some weird behavior in this last case, after the thread is suspended, WaitSynchronizationN will remove the thread from each of the objects' waitlist, and clear the thread's waitlist again. It is speculated that something akin to a coroutine return occurs somewhere between putting the thread to sleep, and running this code, as it appears to be the code that sets the return value of WaitSynchronizationN.

ReplyAndReceive

TODO

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment