1570af302Sopenharmony_ci#define _GNU_SOURCE 2570af302Sopenharmony_ci#include "pthread_impl.h" 3570af302Sopenharmony_ci#include "stdio_impl.h" 4570af302Sopenharmony_ci#include "libc.h" 5570af302Sopenharmony_ci#include "lock.h" 6570af302Sopenharmony_ci#include <sys/mman.h> 7570af302Sopenharmony_ci#include <string.h> 8570af302Sopenharmony_ci#include <stddef.h> 9570af302Sopenharmony_ci#include <stdarg.h> 10570af302Sopenharmony_ci 11570af302Sopenharmony_civoid log_print(const char* info,...) 12570af302Sopenharmony_ci{ 13570af302Sopenharmony_ci va_list ap; 14570af302Sopenharmony_ci va_start(ap, info); 15570af302Sopenharmony_ci vfprintf(stdout,info, ap); 16570af302Sopenharmony_ci va_end(ap); 17570af302Sopenharmony_ci} 18570af302Sopenharmony_ci 19570af302Sopenharmony_cistatic void dummy_0() 20570af302Sopenharmony_ci{ 21570af302Sopenharmony_ci} 22570af302Sopenharmony_ciweak_alias(dummy_0, __acquire_ptc); 23570af302Sopenharmony_ciweak_alias(dummy_0, __release_ptc); 24570af302Sopenharmony_ciweak_alias(dummy_0, __pthread_tsd_run_dtors); 25570af302Sopenharmony_ciweak_alias(dummy_0, __do_orphaned_stdio_locks); 26570af302Sopenharmony_ciweak_alias(dummy_0, __dl_thread_cleanup); 27570af302Sopenharmony_ciweak_alias(dummy_0, __membarrier_init); 28570af302Sopenharmony_ci 29570af302Sopenharmony_cistatic int tl_lock_count; 30570af302Sopenharmony_cistatic int tl_lock_waiters; 31570af302Sopenharmony_ci 32570af302Sopenharmony_civoid __tl_lock(void) 33570af302Sopenharmony_ci{ 34570af302Sopenharmony_ci int tid = __pthread_self()->tid; 35570af302Sopenharmony_ci int val = __thread_list_lock; 36570af302Sopenharmony_ci if (val == tid) { 37570af302Sopenharmony_ci tl_lock_count++; 38570af302Sopenharmony_ci return; 39570af302Sopenharmony_ci } 40570af302Sopenharmony_ci while ((val = a_cas(&__thread_list_lock, 0, tid))) 41570af302Sopenharmony_ci __wait(&__thread_list_lock, &tl_lock_waiters, val, 0); 42570af302Sopenharmony_ci} 43570af302Sopenharmony_ci 44570af302Sopenharmony_civoid __tl_unlock(void) 45570af302Sopenharmony_ci{ 46570af302Sopenharmony_ci if (tl_lock_count) { 47570af302Sopenharmony_ci tl_lock_count--; 48570af302Sopenharmony_ci return; 49570af302Sopenharmony_ci } 50570af302Sopenharmony_ci a_store(&__thread_list_lock, 0); 51570af302Sopenharmony_ci if (tl_lock_waiters) __wake(&__thread_list_lock, 1, 0); 52570af302Sopenharmony_ci} 53570af302Sopenharmony_ci 54570af302Sopenharmony_civoid __tl_sync(pthread_t td) 55570af302Sopenharmony_ci{ 56570af302Sopenharmony_ci a_barrier(); 57570af302Sopenharmony_ci int val = __thread_list_lock; 58570af302Sopenharmony_ci if (!val) return; 59570af302Sopenharmony_ci __wait(&__thread_list_lock, &tl_lock_waiters, val, 0); 60570af302Sopenharmony_ci if (tl_lock_waiters) __wake(&__thread_list_lock, 1, 0); 61570af302Sopenharmony_ci} 62570af302Sopenharmony_ci 63570af302Sopenharmony_ci_Noreturn void __pthread_exit(void *result) 64570af302Sopenharmony_ci{ 65570af302Sopenharmony_ci pthread_t self = __pthread_self(); 66570af302Sopenharmony_ci sigset_t set; 67570af302Sopenharmony_ci 68570af302Sopenharmony_ci self->canceldisable = 1; 69570af302Sopenharmony_ci self->cancelasync = 0; 70570af302Sopenharmony_ci self->result = result; 71570af302Sopenharmony_ci 72570af302Sopenharmony_ci while (self->cancelbuf) { 73570af302Sopenharmony_ci void (*f)(void *) = self->cancelbuf->__f; 74570af302Sopenharmony_ci void *x = self->cancelbuf->__x; 75570af302Sopenharmony_ci self->cancelbuf = self->cancelbuf->__next; 76570af302Sopenharmony_ci f(x); 77570af302Sopenharmony_ci } 78570af302Sopenharmony_ci 79570af302Sopenharmony_ci __pthread_tsd_run_dtors(); 80570af302Sopenharmony_ci 81570af302Sopenharmony_ci __block_app_sigs(&set); 82570af302Sopenharmony_ci 83570af302Sopenharmony_ci /* This atomic potentially competes with a concurrent pthread_detach 84570af302Sopenharmony_ci * call; the loser is responsible for freeing thread resources. */ 85570af302Sopenharmony_ci int state = a_cas(&self->detach_state, DT_JOINABLE, DT_EXITING); 86570af302Sopenharmony_ci 87570af302Sopenharmony_ci if (state==DT_DETACHED && self->map_base) { 88570af302Sopenharmony_ci /* Since __unmapself bypasses the normal munmap code path, 89570af302Sopenharmony_ci * explicitly wait for vmlock holders first. This must be 90570af302Sopenharmony_ci * done before any locks are taken, to avoid lock ordering 91570af302Sopenharmony_ci * issues that could lead to deadlock. */ 92570af302Sopenharmony_ci __vm_wait(); 93570af302Sopenharmony_ci } 94570af302Sopenharmony_ci 95570af302Sopenharmony_ci /* Access to target the exiting thread with syscalls that use 96570af302Sopenharmony_ci * its kernel tid is controlled by killlock. For detached threads, 97570af302Sopenharmony_ci * any use past this point would have undefined behavior, but for 98570af302Sopenharmony_ci * joinable threads it's a valid usage that must be handled. 99570af302Sopenharmony_ci * Signals must be blocked since pthread_kill must be AS-safe. */ 100570af302Sopenharmony_ci LOCK(self->killlock); 101570af302Sopenharmony_ci 102570af302Sopenharmony_ci /* The thread list lock must be AS-safe, and thus depends on 103570af302Sopenharmony_ci * application signals being blocked above. */ 104570af302Sopenharmony_ci __tl_lock(); 105570af302Sopenharmony_ci 106570af302Sopenharmony_ci /* If this is the only thread in the list, don't proceed with 107570af302Sopenharmony_ci * termination of the thread, but restore the previous lock and 108570af302Sopenharmony_ci * signal state to prepare for exit to call atexit handlers. */ 109570af302Sopenharmony_ci if (self->next == self) { 110570af302Sopenharmony_ci __tl_unlock(); 111570af302Sopenharmony_ci UNLOCK(self->killlock); 112570af302Sopenharmony_ci self->detach_state = state; 113570af302Sopenharmony_ci __restore_sigs(&set); 114570af302Sopenharmony_ci exit(0); 115570af302Sopenharmony_ci } 116570af302Sopenharmony_ci 117570af302Sopenharmony_ci /* At this point we are committed to thread termination. */ 118570af302Sopenharmony_ci 119570af302Sopenharmony_ci /* After the kernel thread exits, its tid may be reused. Clear it 120570af302Sopenharmony_ci * to prevent inadvertent use and inform functions that would use 121570af302Sopenharmony_ci * it that it's no longer available. At this point the killlock 122570af302Sopenharmony_ci * may be released, since functions that use it will consistently 123570af302Sopenharmony_ci * see the thread as having exited. Release it now so that no 124570af302Sopenharmony_ci * remaining locks (except thread list) are held if we end up 125570af302Sopenharmony_ci * resetting need_locks below. */ 126570af302Sopenharmony_ci self->tid = 0; 127570af302Sopenharmony_ci UNLOCK(self->killlock); 128570af302Sopenharmony_ci 129570af302Sopenharmony_ci /* Process robust list in userspace to handle non-pshared mutexes 130570af302Sopenharmony_ci * and the detached thread case where the robust list head will 131570af302Sopenharmony_ci * be invalid when the kernel would process it. */ 132570af302Sopenharmony_ci __vm_lock(); 133570af302Sopenharmony_ci volatile void *volatile *rp; 134570af302Sopenharmony_ci while ((rp=self->robust_list.head) && rp != &self->robust_list.head) { 135570af302Sopenharmony_ci pthread_mutex_t *m = (void *)((char *)rp 136570af302Sopenharmony_ci - offsetof(pthread_mutex_t, _m_next)); 137570af302Sopenharmony_ci int waiters = m->_m_waiters; 138570af302Sopenharmony_ci int priv = (m->_m_type & 128) ^ 128; 139570af302Sopenharmony_ci self->robust_list.pending = rp; 140570af302Sopenharmony_ci self->robust_list.head = *rp; 141570af302Sopenharmony_ci int cont = a_swap(&m->_m_lock, 0x40000000); 142570af302Sopenharmony_ci self->robust_list.pending = 0; 143570af302Sopenharmony_ci if (cont < 0 || waiters) 144570af302Sopenharmony_ci __wake(&m->_m_lock, 1, priv); 145570af302Sopenharmony_ci } 146570af302Sopenharmony_ci __vm_unlock(); 147570af302Sopenharmony_ci 148570af302Sopenharmony_ci __do_orphaned_stdio_locks(); 149570af302Sopenharmony_ci __dl_thread_cleanup(); 150570af302Sopenharmony_ci 151570af302Sopenharmony_ci /* Last, unlink thread from the list. This change will not be visible 152570af302Sopenharmony_ci * until the lock is released, which only happens after SYS_exit 153570af302Sopenharmony_ci * has been called, via the exit futex address pointing at the lock. 154570af302Sopenharmony_ci * This needs to happen after any possible calls to LOCK() that might 155570af302Sopenharmony_ci * skip locking if process appears single-threaded. */ 156570af302Sopenharmony_ci if (!--libc.threads_minus_1) libc.need_locks = -1; 157570af302Sopenharmony_ci self->next->prev = self->prev; 158570af302Sopenharmony_ci self->prev->next = self->next; 159570af302Sopenharmony_ci self->prev = self->next = self; 160570af302Sopenharmony_ci 161570af302Sopenharmony_ci if (state==DT_DETACHED && self->map_base) { 162570af302Sopenharmony_ci /* Detached threads must block even implementation-internal 163570af302Sopenharmony_ci * signals, since they will not have a stack in their last 164570af302Sopenharmony_ci * moments of existence. */ 165570af302Sopenharmony_ci __block_all_sigs(&set); 166570af302Sopenharmony_ci 167570af302Sopenharmony_ci /* Robust list will no longer be valid, and was already 168570af302Sopenharmony_ci * processed above, so unregister it with the kernel. */ 169570af302Sopenharmony_ci if (self->robust_list.off) 170570af302Sopenharmony_ci __syscall(SYS_set_robust_list, 0, 3*sizeof(long)); 171570af302Sopenharmony_ci 172570af302Sopenharmony_ci /* The following call unmaps the thread's stack mapping 173570af302Sopenharmony_ci * and then exits without touching the stack. */ 174570af302Sopenharmony_ci __unmapself(self->map_base, self->map_size); 175570af302Sopenharmony_ci } 176570af302Sopenharmony_ci 177570af302Sopenharmony_ci /* Wake any joiner. */ 178570af302Sopenharmony_ci a_store(&self->detach_state, DT_EXITED); 179570af302Sopenharmony_ci __wake(&self->detach_state, 1, 1); 180570af302Sopenharmony_ci 181570af302Sopenharmony_ci for (;;) __syscall(SYS_exit, 0); 182570af302Sopenharmony_ci} 183570af302Sopenharmony_ci 184570af302Sopenharmony_civoid __do_cleanup_push(struct __ptcb *cb) 185570af302Sopenharmony_ci{ 186570af302Sopenharmony_ci struct pthread *self = __pthread_self(); 187570af302Sopenharmony_ci cb->__next = self->cancelbuf; 188570af302Sopenharmony_ci self->cancelbuf = cb; 189570af302Sopenharmony_ci} 190570af302Sopenharmony_ci 191570af302Sopenharmony_civoid __do_cleanup_pop(struct __ptcb *cb) 192570af302Sopenharmony_ci{ 193570af302Sopenharmony_ci __pthread_self()->cancelbuf = cb->__next; 194570af302Sopenharmony_ci} 195570af302Sopenharmony_ci 196570af302Sopenharmony_cistruct start_args { 197570af302Sopenharmony_ci void *(*start_func)(void *); 198570af302Sopenharmony_ci void *start_arg; 199570af302Sopenharmony_ci volatile int control; 200570af302Sopenharmony_ci unsigned long sig_mask[_NSIG/8/sizeof(long)]; 201570af302Sopenharmony_ci}; 202570af302Sopenharmony_ci 203570af302Sopenharmony_cistatic int start(void *p) 204570af302Sopenharmony_ci{ 205570af302Sopenharmony_ci struct start_args *args = p; 206570af302Sopenharmony_ci int state = args->control; 207570af302Sopenharmony_ci if (state) { 208570af302Sopenharmony_ci if (a_cas(&args->control, 1, 2)==1) 209570af302Sopenharmony_ci __wait(&args->control, 0, 2, 1); 210570af302Sopenharmony_ci if (args->control) { 211570af302Sopenharmony_ci __syscall(SYS_set_tid_address, &args->control); 212570af302Sopenharmony_ci for (;;) __syscall(SYS_exit, 0); 213570af302Sopenharmony_ci } 214570af302Sopenharmony_ci } 215570af302Sopenharmony_ci __syscall(SYS_rt_sigprocmask, SIG_SETMASK, &args->sig_mask, 0, _NSIG/8); 216570af302Sopenharmony_ci __pthread_exit(args->start_func(args->start_arg)); 217570af302Sopenharmony_ci return 0; 218570af302Sopenharmony_ci} 219570af302Sopenharmony_ci 220570af302Sopenharmony_cistatic int start_c11(void *p) 221570af302Sopenharmony_ci{ 222570af302Sopenharmony_ci struct start_args *args = p; 223570af302Sopenharmony_ci int (*start)(void*) = (int(*)(void*)) args->start_func; 224570af302Sopenharmony_ci __pthread_exit((void *)(uintptr_t)start(args->start_arg)); 225570af302Sopenharmony_ci return 0; 226570af302Sopenharmony_ci} 227570af302Sopenharmony_ci 228570af302Sopenharmony_ci#define ROUND(x) (((x)+PAGE_SIZE-1)&-PAGE_SIZE) 229570af302Sopenharmony_ci 230570af302Sopenharmony_ci/* pthread_key_create.c overrides this */ 231570af302Sopenharmony_cistatic volatile size_t dummy = 0; 232570af302Sopenharmony_ciweak_alias(dummy, __pthread_tsd_size); 233570af302Sopenharmony_cistatic void *dummy_tsd[1] = { 0 }; 234570af302Sopenharmony_ciweak_alias(dummy_tsd, __pthread_tsd_main); 235570af302Sopenharmony_ci 236570af302Sopenharmony_cistatic FILE *volatile dummy_file = 0; 237570af302Sopenharmony_ciweak_alias(dummy_file, __stdin_used); 238570af302Sopenharmony_ciweak_alias(dummy_file, __stdout_used); 239570af302Sopenharmony_ciweak_alias(dummy_file, __stderr_used); 240570af302Sopenharmony_ci 241570af302Sopenharmony_cistatic void init_file_lock(FILE *f) 242570af302Sopenharmony_ci{ 243570af302Sopenharmony_ci if (f && f->lock<0) f->lock = 0; 244570af302Sopenharmony_ci} 245570af302Sopenharmony_ci 246570af302Sopenharmony_ciint __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict attrp, void *(*entry)(void *), void *restrict arg) 247570af302Sopenharmony_ci{ 248570af302Sopenharmony_ci int ret, c11 = (attrp == __ATTRP_C11_THREAD); 249570af302Sopenharmony_ci size_t size, guard; 250570af302Sopenharmony_ci struct pthread *self, *new; 251570af302Sopenharmony_ci unsigned char *map = 0, *stack = 0, *tsd = 0, *stack_limit; 252570af302Sopenharmony_ci unsigned flags = CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND 253570af302Sopenharmony_ci | CLONE_THREAD | CLONE_SYSVSEM | CLONE_SETTLS 254570af302Sopenharmony_ci | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID | CLONE_DETACHED; 255570af302Sopenharmony_ci pthread_attr_t attr = { 0 }; 256570af302Sopenharmony_ci sigset_t set; 257570af302Sopenharmony_ci 258570af302Sopenharmony_ci if (!libc.can_do_threads) return ENOSYS; 259570af302Sopenharmony_ci self = __pthread_self(); 260570af302Sopenharmony_ci if (!libc.threaded) { 261570af302Sopenharmony_ci for (FILE *f=*__ofl_lock(); f; f=f->next) 262570af302Sopenharmony_ci init_file_lock(f); 263570af302Sopenharmony_ci __ofl_unlock(); 264570af302Sopenharmony_ci init_file_lock(__stdin_used); 265570af302Sopenharmony_ci init_file_lock(__stdout_used); 266570af302Sopenharmony_ci init_file_lock(__stderr_used); 267570af302Sopenharmony_ci __syscall(SYS_rt_sigprocmask, SIG_UNBLOCK, SIGPT_SET, 0, _NSIG/8); 268570af302Sopenharmony_ci self->tsd = (void **)__pthread_tsd_main; 269570af302Sopenharmony_ci __membarrier_init(); 270570af302Sopenharmony_ci libc.threaded = 1; 271570af302Sopenharmony_ci } 272570af302Sopenharmony_ci if (attrp && !c11) attr = *attrp; 273570af302Sopenharmony_ci 274570af302Sopenharmony_ci __acquire_ptc(); 275570af302Sopenharmony_ci if (!attrp || c11) { 276570af302Sopenharmony_ci attr._a_stacksize = __default_stacksize; 277570af302Sopenharmony_ci attr._a_guardsize = __default_guardsize; 278570af302Sopenharmony_ci } 279570af302Sopenharmony_ci 280570af302Sopenharmony_ci if (attr._a_stackaddr) { 281570af302Sopenharmony_ci size_t need = libc.tls_size + __pthread_tsd_size; 282570af302Sopenharmony_ci size = attr._a_stacksize; 283570af302Sopenharmony_ci stack = (void *)(attr._a_stackaddr & -16); 284570af302Sopenharmony_ci stack_limit = (void *)(attr._a_stackaddr - size); 285570af302Sopenharmony_ci /* Use application-provided stack for TLS only when 286570af302Sopenharmony_ci * it does not take more than ~12% or 2k of the 287570af302Sopenharmony_ci * application's stack space. */ 288570af302Sopenharmony_ci if (need < size/8 && need < 2048) { 289570af302Sopenharmony_ci tsd = stack - __pthread_tsd_size; 290570af302Sopenharmony_ci stack = tsd - libc.tls_size; 291570af302Sopenharmony_ci memset(stack, 0, need); 292570af302Sopenharmony_ci } else { 293570af302Sopenharmony_ci size = ROUND(need); 294570af302Sopenharmony_ci } 295570af302Sopenharmony_ci guard = 0; 296570af302Sopenharmony_ci } else { 297570af302Sopenharmony_ci guard = ROUND(attr._a_guardsize); 298570af302Sopenharmony_ci size = guard + ROUND(attr._a_stacksize 299570af302Sopenharmony_ci + libc.tls_size + __pthread_tsd_size); 300570af302Sopenharmony_ci } 301570af302Sopenharmony_ci 302570af302Sopenharmony_ci if (!tsd) { 303570af302Sopenharmony_ci if (guard) { 304570af302Sopenharmony_ci map = __mmap(0, size, PROT_NONE, MAP_PRIVATE|MAP_ANON, -1, 0); 305570af302Sopenharmony_ci if (map == MAP_FAILED) goto fail; 306570af302Sopenharmony_ci if (__mprotect(map+guard, size-guard, PROT_READ|PROT_WRITE) 307570af302Sopenharmony_ci && errno != ENOSYS) { 308570af302Sopenharmony_ci __munmap(map, size); 309570af302Sopenharmony_ci goto fail; 310570af302Sopenharmony_ci } 311570af302Sopenharmony_ci } else { 312570af302Sopenharmony_ci map = __mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0); 313570af302Sopenharmony_ci if (map == MAP_FAILED) goto fail; 314570af302Sopenharmony_ci } 315570af302Sopenharmony_ci tsd = map + size - __pthread_tsd_size; 316570af302Sopenharmony_ci if (!stack) { 317570af302Sopenharmony_ci stack = tsd - libc.tls_size; 318570af302Sopenharmony_ci stack_limit = map + guard; 319570af302Sopenharmony_ci } 320570af302Sopenharmony_ci } 321570af302Sopenharmony_ci 322570af302Sopenharmony_ci new = __copy_tls(tsd - libc.tls_size); 323570af302Sopenharmony_ci new->map_base = map; 324570af302Sopenharmony_ci new->map_size = size; 325570af302Sopenharmony_ci new->stack = stack; 326570af302Sopenharmony_ci new->stack_size = stack - stack_limit; 327570af302Sopenharmony_ci new->guard_size = guard; 328570af302Sopenharmony_ci new->self = new; 329570af302Sopenharmony_ci new->tsd = (void *)tsd; 330570af302Sopenharmony_ci new->locale = &libc.global_locale; 331570af302Sopenharmony_ci if (attr._a_detach) { 332570af302Sopenharmony_ci new->detach_state = DT_DETACHED; 333570af302Sopenharmony_ci } else { 334570af302Sopenharmony_ci new->detach_state = DT_JOINABLE; 335570af302Sopenharmony_ci } 336570af302Sopenharmony_ci new->robust_list.head = &new->robust_list.head; 337570af302Sopenharmony_ci new->canary = self->canary; 338570af302Sopenharmony_ci new->sysinfo = self->sysinfo; 339570af302Sopenharmony_ci 340570af302Sopenharmony_ci /* Setup argument structure for the new thread on its stack. 341570af302Sopenharmony_ci * It's safe to access from the caller only until the thread 342570af302Sopenharmony_ci * list is unlocked. */ 343570af302Sopenharmony_ci stack -= (uintptr_t)stack % sizeof(uintptr_t); 344570af302Sopenharmony_ci stack -= sizeof(struct start_args); 345570af302Sopenharmony_ci struct start_args *args = (void *)stack; 346570af302Sopenharmony_ci args->start_func = entry; 347570af302Sopenharmony_ci args->start_arg = arg; 348570af302Sopenharmony_ci args->control = attr._a_sched ? 1 : 0; 349570af302Sopenharmony_ci 350570af302Sopenharmony_ci /* Application signals (but not the synccall signal) must be 351570af302Sopenharmony_ci * blocked before the thread list lock can be taken, to ensure 352570af302Sopenharmony_ci * that the lock is AS-safe. */ 353570af302Sopenharmony_ci __block_app_sigs(&set); 354570af302Sopenharmony_ci 355570af302Sopenharmony_ci /* Ensure SIGCANCEL is unblocked in new thread. This requires 356570af302Sopenharmony_ci * working with a copy of the set so we can restore the 357570af302Sopenharmony_ci * original mask in the calling thread. */ 358570af302Sopenharmony_ci memcpy(&args->sig_mask, &set, sizeof args->sig_mask); 359570af302Sopenharmony_ci args->sig_mask[(SIGCANCEL-1)/8/sizeof(long)] &= 360570af302Sopenharmony_ci ~(1UL<<((SIGCANCEL-1)%(8*sizeof(long)))); 361570af302Sopenharmony_ci 362570af302Sopenharmony_ci __tl_lock(); 363570af302Sopenharmony_ci if (!libc.threads_minus_1++) libc.need_locks = 1; 364570af302Sopenharmony_ci ret = __clone((c11 ? start_c11 : start), stack, flags, args, &new->tid, TP_ADJ(new), &__thread_list_lock); 365570af302Sopenharmony_ci 366570af302Sopenharmony_ci /* All clone failures translate to EAGAIN. If explicit scheduling 367570af302Sopenharmony_ci * was requested, attempt it before unlocking the thread list so 368570af302Sopenharmony_ci * that the failed thread is never exposed and so that we can 369570af302Sopenharmony_ci * clean up all transient resource usage before returning. */ 370570af302Sopenharmony_ci if (ret < 0) { 371570af302Sopenharmony_ci ret = -EAGAIN; 372570af302Sopenharmony_ci } else if (attr._a_sched) { 373570af302Sopenharmony_ci ret = __syscall(SYS_sched_setscheduler, 374570af302Sopenharmony_ci new->tid, attr._a_policy, &attr._a_prio); 375570af302Sopenharmony_ci if (a_swap(&args->control, ret ? 3 : 0)==2) 376570af302Sopenharmony_ci __wake(&args->control, 1, 1); 377570af302Sopenharmony_ci if (ret) 378570af302Sopenharmony_ci __wait(&args->control, 0, 3, 0); 379570af302Sopenharmony_ci } 380570af302Sopenharmony_ci 381570af302Sopenharmony_ci if (ret >= 0) { 382570af302Sopenharmony_ci new->next = self->next; 383570af302Sopenharmony_ci new->prev = self; 384570af302Sopenharmony_ci new->next->prev = new; 385570af302Sopenharmony_ci new->prev->next = new; 386570af302Sopenharmony_ci } else { 387570af302Sopenharmony_ci if (!--libc.threads_minus_1) libc.need_locks = 0; 388570af302Sopenharmony_ci } 389570af302Sopenharmony_ci __tl_unlock(); 390570af302Sopenharmony_ci __restore_sigs(&set); 391570af302Sopenharmony_ci __release_ptc(); 392570af302Sopenharmony_ci 393570af302Sopenharmony_ci if (ret < 0) { 394570af302Sopenharmony_ci if (map) __munmap(map, size); 395570af302Sopenharmony_ci return -ret; 396570af302Sopenharmony_ci } 397570af302Sopenharmony_ci 398570af302Sopenharmony_ci *res = new; 399570af302Sopenharmony_ci return 0; 400570af302Sopenharmony_cifail: 401570af302Sopenharmony_ci __release_ptc(); 402570af302Sopenharmony_ci return EAGAIN; 403570af302Sopenharmony_ci} 404570af302Sopenharmony_ci 405570af302Sopenharmony_ciweak_alias(__pthread_exit, pthread_exit); 406570af302Sopenharmony_ciweak_alias(__pthread_create, pthread_create); 407570af302Sopenharmony_ci 408570af302Sopenharmony_cistruct pthread* __pthread_list_find(pthread_t thread_id, const char* info) 409570af302Sopenharmony_ci{ 410570af302Sopenharmony_ci struct pthread *thread = (struct pthread *)thread_id; 411570af302Sopenharmony_ci if (NULL == thread) { 412570af302Sopenharmony_ci log_print("invalid pthread_t (0) passed to %s\n", info); 413570af302Sopenharmony_ci return NULL; 414570af302Sopenharmony_ci } 415570af302Sopenharmony_ci 416570af302Sopenharmony_ci struct pthread *self = __pthread_self(); 417570af302Sopenharmony_ci if (thread == self) { 418570af302Sopenharmony_ci return thread; 419570af302Sopenharmony_ci } 420570af302Sopenharmony_ci struct pthread *t = self; 421570af302Sopenharmony_ci t = t->next ; 422570af302Sopenharmony_ci while (t != self) { 423570af302Sopenharmony_ci if (t == thread) return thread; 424570af302Sopenharmony_ci t = t->next ; 425570af302Sopenharmony_ci } 426570af302Sopenharmony_ci log_print("invalid pthread_t %p passed to %s\n", thread, info); 427570af302Sopenharmony_ci return NULL; 428570af302Sopenharmony_ci} 429570af302Sopenharmony_ci 430570af302Sopenharmony_cipid_t __pthread_gettid_np(pthread_t t) 431570af302Sopenharmony_ci{ 432570af302Sopenharmony_ci __tl_lock(); 433570af302Sopenharmony_ci struct pthread* thread = __pthread_list_find(t, "pthread_gettid_np"); 434570af302Sopenharmony_ci __tl_unlock(); 435570af302Sopenharmony_ci return thread ? thread->tid : -1; 436570af302Sopenharmony_ci} 437570af302Sopenharmony_ciweak_alias(__pthread_gettid_np, pthread_gettid_np);