| 18 | } |
| 19 | |
| 20 | Thread threadCreate(ThreadFunc entrypoint, void* arg, size_t stack_size, int prio, int core_id, bool detached) |
| 21 | { |
| 22 | // The stack must be 8-aligned at minimum. |
| 23 | size_t align = __tdata_align > 8 ? __tdata_align : 8; |
| 24 | |
| 25 | size_t stackoffset = alignTo(sizeof(struct Thread_tag), align); |
| 26 | size_t allocsize = alignTo(stackoffset + stack_size, align); |
| 27 | |
| 28 | size_t tlssize = __tls_end-__tls_start; |
| 29 | size_t tlsloadsize = __tdata_lma_end-__tdata_lma; |
| 30 | size_t tbsssize = tlssize - tlsloadsize; |
| 31 | |
| 32 | // memalign seems to have an implicit requirement that (size % align) == 0. |
| 33 | // Without this, it seems to return NULL whenever (align > 8). |
| 34 | size_t size = alignTo(allocsize + tlssize, align); |
| 35 | |
| 36 | // Guard against overflow |
| 37 | if (allocsize < stackoffset) return NULL; |
| 38 | if ((allocsize - stackoffset) < stack_size) return NULL; |
| 39 | if (size < allocsize) return NULL; |
| 40 | |
| 41 | Thread t = (Thread)memalign(align, size); |
| 42 | if (!t) return NULL; |
| 43 | |
| 44 | t->ep = entrypoint; |
| 45 | t->arg = arg; |
| 46 | t->detached = detached; |
| 47 | t->finished = false; |
| 48 | t->stacktop = (u8*)t + allocsize; |
| 49 | |
| 50 | // ThreadVars.tls_tp must be aligned correctly, so we bump tdata_start to |
| 51 | // ensure that after subtracting 8 bytes for the TLS header, it will be aligned. |
| 52 | size_t tdata_start = 8 + alignTo((size_t)t->stacktop - 8, align); |
| 53 | |
| 54 | if (tlsloadsize) |
| 55 | memcpy((void*)tdata_start, __tdata_lma, tlsloadsize); |
| 56 | if (tbsssize) |
| 57 | memset((void*)tdata_start + tlsloadsize, 0, tbsssize); |
| 58 | |
| 59 | // Set up child thread's reent struct, inheriting standard file handles |
| 60 | _REENT_INIT_PTR(&t->reent); |
| 61 | struct _reent* cur = getThreadVars()->reent; |
| 62 | t->reent._stdin = cur->_stdin; |
| 63 | t->reent._stdout = cur->_stdout; |
| 64 | t->reent._stderr = cur->_stderr; |
| 65 | |
| 66 | Result rc; |
| 67 | rc = svcCreateThread(&t->handle, _thread_begin, (u32)t, (u32*)t->stacktop, prio, core_id); |
| 68 | if (R_FAILED(rc)) |
| 69 | { |
| 70 | free(t); |
| 71 | return NULL; |
| 72 | } |
| 73 | |
| 74 | return t; |
| 75 | } |
| 76 | |
| 77 | Handle threadGetHandle(Thread thread) |
no test coverage detected