Line 8:
Line 8:
Though it is possible to run multi-threaded programs, running those on different cores is not possible "as-is". One core is always dedicated to the OS, hence you will never get 100% of both cores.
Though it is possible to run multi-threaded programs, running those on different cores is not possible "as-is". One core is always dedicated to the OS, hence you will never get 100% of both cores.
+
+
Using CloseHandle() with a KThread handle will terminate the specified thread, only if the reference count reaches 0.
+
+
Lower priority values give the thread higher priority. For userland apps, priorities between 0x18 and 0x3F are allowed. The priority of the app's main thread seems to be 0x30.
+
+
The thread scheduler is cooperative, therefore if a thread takes up all the CPU time (for example if it enters an endless loop), all the other threads that run on the same CPU core won't get a chance to run. The main way of yielding another thread is using an address arbiter.
== Usage ==
== Usage ==
−
=== CreateThread ===
+
=== CreateThread (svc 0x08) ===
+
+
'''Definition'''
+
Result CreateThread(Handle* thread, func entrypoint, u32 arg, u32 stacktop, s32 threadpriority, s32 processorid);
+
+
'''Configuration'''
+
R0=s32 threadpriority
+
R1=func entrypoint
+
R2=u32 arg
+
R3=u32 stacktop
+
R4=s32 processorid
+
+
Result result=R0
+
Handle* thread=R1
+
+
'''Details'''
+
The processorid parameter specifies which processor the thread can run on. Non-negative values correspond to a specific CPU. (e.g. 0 for the Appcore and 1 for the Syscore on Old3DS) Special value -1 means all CPUs, and -2 means the default CPU for the process (Read from the [[NCCH/Extended Header|Exheader]], usually 0 for applications, 1 for system services). Games usually create threads using -2.
+
+
With the Old3DS kernel, the s32 processorid must be <=2.
+
+
With the New3DS kernel: processorid must be <= <total cores(MPCore "SCU Configuration Register" CPU number value + 1)>. When processorid==0x2 and the process is not an APPLICATION mem-region process, exheader kernel-flags bitmask 0x2000 must be set otherwise error 0xD9001BEA is returned. When processorid==0x3 and the process is not an APPLICATION mem-region process, error 0xD9001BEA is returned. These are the only restriction checks done by the kernel for processorid.
+
+
The thread priority value must be in the following range: 0x0..0x3F.
+
+
The stacktop must be aligned to 0x8-bytes, otherwise when not aligned to 0x8-bytes the ARM11 kernel clears the low 3-bits of the stacktop address.
+
+
The input address used for Entrypoint_Param and StackTop are normally the same, however these can be arbitrary. For the main thread the Entrypoint_Param is value 0.
+
+
=== ExitThread (svc 0x09)===
+
+
'''Definition'''
+
void ExitThread(void);
+
+
=== SleepThread (svc 0x0A)===
+
+
'''Definition'''
+
void SleepThread(s64 nanoseconds);
+
+
=== GetThreadPriority (svc 0x0B) ===
−
=== ExitThread ===
+
'''Definition'''
+
Result GetThreadPriority(s32* priority, Handle thread);
−
=== SleepThread ===
+
'''asm'''
+
.global svcGetThreadPriority
+
.type svcGetThreadPriority, %function
+
svcGetThreadPriority:
+
str r0, [sp, #-0x4]!
+
svc 0x0B
+
ldr r3, [sp], #4
+
str r1, [r3]
+
bx lr
−
=== GetThreadPriority ===
+
=== SetThreadPriority (svc 0x0C) ===
−
=== SetThreadPriority ===
+
'''Definition'''
+
Result SetThreadPriority(Handle thread, s32 priority);
=== OpenThread ===
=== OpenThread ===
+
+
'''Definition'''
+
Result OpenThread(Handle* thread, Handle process, u32 threadId);
=== GetProcessIdOfThread ===
=== GetProcessIdOfThread ===
+
+
'''Definition'''
+
Result GetProcessIdOfThread(u32* processId, Handle thread);
=== GetThreadId ===
=== GetThreadId ===
+
+
'''Definition'''
+
Result GetThreadId(u32* threadId, Handle thread);
=== GetThreadInfo ===
=== GetThreadInfo ===
+
+
'''Definition'''
+
Result GetThreadInfo(s64* out, Handle thread, ThreadInfoType type);
+
+
{| class="wikitable" border="1"
+
! ThreadInfoType value
+
! Description
+
|-
+
| ?
+
| ?
+
|}
=== GetThreadContext ===
=== GetThreadContext ===
+
+
'''Definition'''
+
Result GetThreadContext(ThreadContext* context, Handle thread);
+
+
'''Details'''
+
Stubbed?
== Core affinity ==
== Core affinity ==
=== GetThreadAffinityMask ===
=== GetThreadAffinityMask ===
+
+
'''Definition'''
+
Result GetThreadAffinityMask(u8* affinitymask, Handle thread, s32 processorcount);
=== SetThreadAffinityMask ===
=== SetThreadAffinityMask ===
+
+
'''Definition'''
+
Result SetThreadAffinityMask(Handle thread, u8* affinitymask, s32 processorcount);
=== GetThreadIdealProcessor ===
=== GetThreadIdealProcessor ===
+
+
'''Definition'''
+
Result GetThreadIdealProcessor(s32* processorid, Handle thread);
=== SetThreadIdealProcessor ===
=== SetThreadIdealProcessor ===
Line 56:
Line 145:
== Mutex (normal) ==
== Mutex (normal) ==
+
+
For Kernel implementation details, see [[KMutex]]
=== CreateMutex ===
=== CreateMutex ===