mirror of
https://github.com/switchbrew/libnx.git
synced 2025-07-04 18:42:15 +02:00
threads: support using existing mem as stack
This commit is contained in:
parent
5f5d4c9785
commit
3109b2c480
@ -12,6 +12,7 @@
|
|||||||
/// Thread information structure.
|
/// Thread information structure.
|
||||||
typedef struct Thread {
|
typedef struct Thread {
|
||||||
Handle handle; ///< Thread handle.
|
Handle handle; ///< Thread handle.
|
||||||
|
bool owns_stack_mem; ///< Whether the stack memory is automatically allocated.
|
||||||
void* stack_mem; ///< Pointer to stack memory.
|
void* stack_mem; ///< Pointer to stack memory.
|
||||||
void* stack_mirror; ///< Pointer to stack memory mirror.
|
void* stack_mirror; ///< Pointer to stack memory mirror.
|
||||||
size_t stack_sz; ///< Stack size.
|
size_t stack_sz; ///< Stack size.
|
||||||
@ -31,14 +32,15 @@ static inline Waiter waiterForThread(Thread* t)
|
|||||||
* @param t Thread information structure which will be filled in.
|
* @param t Thread information structure which will be filled in.
|
||||||
* @param entry Entrypoint of the thread.
|
* @param entry Entrypoint of the thread.
|
||||||
* @param arg Argument to pass to the entrypoint.
|
* @param arg Argument to pass to the entrypoint.
|
||||||
* @param stack_sz Stack size (rounded up to page alignment).
|
* @param stack_mem Memory to use as backing for stack/tls/reent. Must be page-aligned. NULL argument means to allocate new memory.
|
||||||
|
* @param stack_sz Stack size (rounded up to page alignment if stack_mem is NULL).
|
||||||
* @param prio Thread priority (0x00~0x3F); 0x2C is the usual priority of the main thread, 0x3B is a special priority on cores 0..2 that enables preemptive multithreading (0x3F on core 3).
|
* @param prio Thread priority (0x00~0x3F); 0x2C is the usual priority of the main thread, 0x3B is a special priority on cores 0..2 that enables preemptive multithreading (0x3F on core 3).
|
||||||
* @param cpuid ID of the core on which to create the thread (0~3); or -2 to use the default core for the current process.
|
* @param cpuid ID of the core on which to create the thread (0~3); or -2 to use the default core for the current process.
|
||||||
* @return Result code.
|
* @return Result code.
|
||||||
*/
|
*/
|
||||||
Result threadCreate(
|
Result threadCreate(
|
||||||
Thread* t, ThreadFunc entry, void* arg, size_t stack_sz, int prio,
|
Thread* t, ThreadFunc entry, void* arg, void *stack_mem, size_t stack_sz,
|
||||||
int cpuid);
|
int prio, int cpuid);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Starts the execution of a thread.
|
* @brief Starts the execution of a thread.
|
||||||
|
@ -61,26 +61,50 @@ static void _EntryWrap(ThreadEntryArgs* args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Result threadCreate(
|
Result threadCreate(
|
||||||
Thread* t, ThreadFunc entry, void* arg, size_t stack_sz, int prio,
|
Thread* t, ThreadFunc entry, void* arg, void* stack_mem, size_t stack_sz,
|
||||||
int cpuid)
|
int prio, int cpuid)
|
||||||
{
|
{
|
||||||
stack_sz = (stack_sz+0xFFF) &~ 0xFFF;
|
|
||||||
|
|
||||||
Result rc = 0;
|
void* tls;
|
||||||
size_t reent_sz = (sizeof(struct _reent)+0xF) &~ 0xF;
|
const size_t tls_sz = (__tls_end-__tls_start+0xF) &~ 0xF;
|
||||||
size_t tls_sz = (__tls_end-__tls_start+0xF) &~ 0xF;
|
void* reent;
|
||||||
void* stack = memalign(0x1000, stack_sz + reent_sz + tls_sz);
|
const size_t reent_sz = (sizeof(struct _reent)+0xF) &~ 0xF;
|
||||||
|
|
||||||
if (stack == NULL) {
|
if (stack_mem == NULL) {
|
||||||
rc = MAKERESULT(Module_Libnx, LibnxError_OutOfMemory);
|
// Allocate new memory, stack then reent then tls.
|
||||||
|
stack_sz = (stack_sz+0xFFF) & ~0xFFF;
|
||||||
|
stack_mem = memalign(0x1000, stack_sz + reent_sz + tls_sz);
|
||||||
|
reent = (void*)((uintptr_t)stack_mem + stack_sz);
|
||||||
|
tls = (void*)((uintptr_t)reent + reent_sz);
|
||||||
|
|
||||||
|
t->owns_stack_mem = true;
|
||||||
|
} else {
|
||||||
|
// Use provided memory for stack, reent, and tls.
|
||||||
|
if (((uintptr_t)stack_mem & 0xFFF) || (stack_sz & 0xFFF)) {
|
||||||
|
return MAKERESULT(Module_Libnx, LibnxError_BadInput);
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
|
tls = (void*)((uintptr_t)stack_mem + stack_sz - tls_sz);
|
||||||
|
reent = (void*)((uintptr_t)tls - reent_sz);
|
||||||
|
|
||||||
|
// Ensure we don't go out of bounds.
|
||||||
|
if ((uintptr_t)reent <= (uintptr_t)stack_mem) {
|
||||||
|
return MAKERESULT(Module_Libnx, LibnxError_OutOfMemory);
|
||||||
|
}
|
||||||
|
|
||||||
|
t->owns_stack_mem = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stack_mem == NULL) {
|
||||||
|
return MAKERESULT(Module_Libnx, LibnxError_OutOfMemory);
|
||||||
|
}
|
||||||
|
|
||||||
void* stack_mirror = virtmemReserveStack(stack_sz);
|
void* stack_mirror = virtmemReserveStack(stack_sz);
|
||||||
rc = svcMapMemory(stack_mirror, stack, stack_sz);
|
Result rc = svcMapMemory(stack_mirror, stack_mem, stack_sz);
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc))
|
if (R_SUCCEEDED(rc))
|
||||||
{
|
{
|
||||||
u64 stack_top = ((u64)stack_mirror) + stack_sz - sizeof(ThreadEntryArgs);
|
uintptr_t stack_top = ((uintptr_t)stack_mirror) + stack_sz - sizeof(ThreadEntryArgs);
|
||||||
ThreadEntryArgs* args = (ThreadEntryArgs*) stack_top;
|
ThreadEntryArgs* args = (ThreadEntryArgs*) stack_top;
|
||||||
Handle handle;
|
Handle handle;
|
||||||
|
|
||||||
@ -91,9 +115,9 @@ Result threadCreate(
|
|||||||
if (R_SUCCEEDED(rc))
|
if (R_SUCCEEDED(rc))
|
||||||
{
|
{
|
||||||
t->handle = handle;
|
t->handle = handle;
|
||||||
t->stack_mem = stack;
|
t->stack_mem = stack_mem;
|
||||||
t->stack_mirror = stack_mirror;
|
t->stack_mirror = stack_mirror;
|
||||||
t->stack_sz = stack_sz;
|
t->stack_sz = stack_sz - sizeof(ThreadEntryArgs);
|
||||||
t->tls_array = NULL;
|
t->tls_array = NULL;
|
||||||
t->next = NULL;
|
t->next = NULL;
|
||||||
t->prev_next = NULL;
|
t->prev_next = NULL;
|
||||||
@ -101,8 +125,8 @@ Result threadCreate(
|
|||||||
args->t = t;
|
args->t = t;
|
||||||
args->entry = entry;
|
args->entry = entry;
|
||||||
args->arg = arg;
|
args->arg = arg;
|
||||||
args->reent = (struct _reent*)((u8*)stack + stack_sz);
|
args->reent = reent;
|
||||||
args->tls = (u8*)stack + stack_sz + reent_sz;
|
args->tls = tls;
|
||||||
|
|
||||||
// Set up child thread's reent struct, inheriting standard file handles
|
// Set up child thread's reent struct, inheriting standard file handles
|
||||||
_REENT_INIT_PTR(args->reent);
|
_REENT_INIT_PTR(args->reent);
|
||||||
@ -121,13 +145,14 @@ Result threadCreate(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (R_FAILED(rc)) {
|
if (R_FAILED(rc)) {
|
||||||
svcUnmapMemory(stack_mirror, stack, stack_sz);
|
svcUnmapMemory(stack_mirror, stack_mem, stack_sz);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (R_FAILED(rc)) {
|
if (R_FAILED(rc)) {
|
||||||
virtmemFreeStack(stack_mirror, stack_sz);
|
virtmemFreeStack(stack_mirror, stack_sz);
|
||||||
free(stack);
|
if (t->owns_stack_mem) {
|
||||||
|
free(stack_mem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,9 +203,14 @@ Result threadClose(Thread* t) {
|
|||||||
return MAKERESULT(Module_Libnx, LibnxError_BadInput);
|
return MAKERESULT(Module_Libnx, LibnxError_BadInput);
|
||||||
|
|
||||||
rc = svcUnmapMemory(t->stack_mirror, t->stack_mem, t->stack_sz);
|
rc = svcUnmapMemory(t->stack_mirror, t->stack_mem, t->stack_sz);
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(rc)) {
|
||||||
virtmemFreeStack(t->stack_mirror, t->stack_sz);
|
virtmemFreeStack(t->stack_mirror, t->stack_sz);
|
||||||
|
if (t->owns_stack_mem) {
|
||||||
free(t->stack_mem);
|
free(t->stack_mem);
|
||||||
|
}
|
||||||
svcCloseHandle(t->handle);
|
svcCloseHandle(t->handle);
|
||||||
|
}
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
@ -170,7 +170,7 @@ static void __thread_entry(void* __arg)
|
|||||||
|
|
||||||
int __syscall_thread_create(struct __pthread_t **thread, void* (*func)(void*), void *arg, void *stack_addr, size_t stack_size)
|
int __syscall_thread_create(struct __pthread_t **thread, void* (*func)(void*), void *arg, void *stack_addr, size_t stack_size)
|
||||||
{
|
{
|
||||||
if (stack_addr || (stack_size & 0xFFF))
|
if (((uintptr_t)stack_addr & 0xFFF) || (stack_size & 0xFFF))
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
if (!stack_size)
|
if (!stack_size)
|
||||||
stack_size = 128*1024;
|
stack_size = 128*1024;
|
||||||
@ -194,7 +194,7 @@ int __syscall_thread_create(struct __pthread_t **thread, void* (*func)(void*), v
|
|||||||
mutexInit(&info.mutex);
|
mutexInit(&info.mutex);
|
||||||
condvarInit(&info.cond);
|
condvarInit(&info.cond);
|
||||||
|
|
||||||
rc = threadCreate(&t->thr, __thread_entry, &info, stack_size, 0x3B, -2);
|
rc = threadCreate(&t->thr, __thread_entry, &info, stack_addr, stack_size, 0x3B, -2);
|
||||||
if (R_FAILED(rc))
|
if (R_FAILED(rc))
|
||||||
goto _error1;
|
goto _error1;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user