Thread threadGetCurrent(void) { ThreadVars* tv = getThreadVars(); if (tv->magic != THREADVARS_MAGIC) __panic(); return tv->thread_ptr; }
void __system_initSyscalls(void) { // Register newlib syscalls __syscalls.exit = __ctru_exit; __syscalls.gettod_r = __libctru_gtod; __syscalls.getreent = __ctru_get_reent; __syscalls.nanosleep = __libctru_nanosleep; // Register locking syscalls __syscalls.lock_init = LightLock_Init; __syscalls.lock_acquire = LightLock_Lock; __syscalls.lock_try_acquire = LightLock_TryLock; __syscalls.lock_release = LightLock_Unlock; __syscalls.lock_init_recursive = RecursiveLock_Init; __syscalls.lock_acquire_recursive = RecursiveLock_Lock; __syscalls.lock_try_acquire_recursive = RecursiveLock_TryLock; __syscalls.lock_release_recursive = RecursiveLock_Unlock; // Initialize thread vars for the main thread ThreadVars* tv = getThreadVars(); tv->magic = THREADVARS_MAGIC; tv->reent = _impure_ptr; tv->thread_ptr = NULL; tv->tls_tp = __tls_start-8; // ARM ELF TLS ABI mandates an 8-byte header tv->srv_blocking_policy = false; u32 tls_size = __tdata_lma_end - __tdata_lma; if (tls_size) memcpy(__tls_start, __tdata_lma, tls_size); }
boolean isErrAbortInProgress() /* Flag to indicate that an error abort is in progress. * Needed so that a warn handler can tell if it's really * being called because of a warning or an error. */ { struct perThreadAbortVars *ptav = getThreadVars(); return ptav->errAbortInProgress; }
void noWarnAbort() /* Abort without message. */ { struct perThreadAbortVars *ptav = getThreadVars(); ptav->abortArray[ptav->abortIx](); exit(-1); /* This is just to make compiler happy. * We have already exited or longjmped by now. */ }
static struct _reent* __ctru_get_reent() { ThreadVars* tv = getThreadVars(); if (tv->magic != THREADVARS_MAGIC) { svcBreak(USERBREAK_PANIC); for (;;); } return tv->reent; }
static void _thread_begin(void* arg) { Thread t = (Thread)arg; ThreadVars* tv = getThreadVars(); tv->magic = THREADVARS_MAGIC; tv->reent = &t->reent; tv->thread_ptr = t; tv->tls_tp = (u8*)t->stacktop-8; // ARM ELF TLS ABI mandates an 8-byte header t->ep(t->arg); threadExit(0); }
void popAbortHandler() /* Revert to old abort handler. */ { struct perThreadAbortVars *ptav = getThreadVars(); if (ptav->abortIx <= 0) { if (ptav->debugPushPopErr) dumpStack("popAbortHandler underflow"); errAbort("Too many popAbortHandlers\n"); } --ptav->abortIx; }
void pushAbortHandler(AbortHandler handler) /* Set abort handler */ { struct perThreadAbortVars *ptav = getThreadVars(); if (ptav->abortIx >= maxAbortHandlers-1) { if (ptav->debugPushPopErr) dumpStack("pushAbortHandler overflow"); errAbort("Too many pushAbortHandlers, can only handle %d", maxAbortHandlers-1); } ptav->abortArray[++ptav->abortIx] = handler; }
void popWarnHandler() /* Revert to old warn handler. */ { struct perThreadAbortVars *ptav = getThreadVars(); if (ptav->warnIx <= 0) { if (ptav->debugPushPopErr) dumpStack("popWarnHandler underflow"); errAbort("Too few popWarnHandlers"); } --ptav->warnIx; }
void vaErrAbort(char *format, va_list args) /* Abort function, with optional (vprintf formatted) error message. */ { /* flag is needed because both errAbort and warn generate message * using the warn handler, however sometimes one needed to know * (like when logging), if it's an error or a warning. This is far from * perfect, as this isn't cleared if the error handler continues, * as with an exception mechanism. */ struct perThreadAbortVars *ptav = getThreadVars(); ptav->errAbortInProgress = TRUE; vaWarn(format, args); noWarnAbort(); }
Thread threadCreate(ThreadFunc entrypoint, void* arg, size_t stack_size, int prio, int affinity, bool detached) { size_t stackoffset = (sizeof(struct Thread_tag)+7)&~7; size_t allocsize = stackoffset + ((stack_size+7)&~7); size_t tlssize = __tls_end-__tls_start; size_t tlsloadsize = __tdata_lma_end-__tdata_lma; size_t tbsssize = tlssize-tlsloadsize; // Guard against overflow if (allocsize < stackoffset) return NULL; if ((allocsize-stackoffset) < stack_size) return NULL; if ((allocsize+tlssize) < allocsize) return NULL; Thread t = (Thread)memalign(8,allocsize+tlssize); if (!t) return NULL; t->ep = entrypoint; t->arg = arg; t->detached = detached; t->finished = false; t->stacktop = (u8*)t + allocsize; if (tlsloadsize) memcpy(t->stacktop, __tdata_lma, tlsloadsize); if (tbsssize) memset((u8*)t->stacktop+tlsloadsize, 0, tbsssize); // Set up child thread's reent struct, inheriting standard file handles _REENT_INIT_PTR(&t->reent); struct _reent* cur = getThreadVars()->reent; t->reent._stdin = cur->_stdin; t->reent._stdout = cur->_stdout; t->reent._stderr = cur->_stderr; Result rc; rc = svcCreateThread(&t->handle, _thread_begin, (u32)t, (u32*)t->stacktop, prio, affinity); if (R_FAILED(rc)) { free(t); return NULL; } return t; }
void vaWarn(char *format, va_list args) /* Call top of warning stack to issue warning. */ { struct perThreadAbortVars *ptav = getThreadVars(); ptav->warnArray[ptav->warnIx](format, args); }
void errAbortDebugnPushPopErr() /* generate stack dump if there is a error in the push/pop functions */ { struct perThreadAbortVars *ptav = getThreadVars(); ptav->debugPushPopErr = TRUE; }