int _pthread_getschedparam(pthread_t pthread, int *policy, struct sched_param *param) { struct pthread *curthread = _get_curthread(); int ret; if (policy == NULL || param == NULL) return (EINVAL); if (pthread == curthread) { /* * Avoid searching the thread list when it is the current * thread. */ THR_LOCK(curthread); *policy = curthread->attr.sched_policy; param->sched_priority = curthread->attr.prio; THR_UNLOCK(curthread); ret = 0; } /* Find the thread in the list of active threads. */ else if ((ret = _thr_ref_add(curthread, pthread, /*include dead*/0)) == 0) { THR_THREAD_LOCK(curthread, pthread); *policy = pthread->attr.sched_policy; param->sched_priority = pthread->attr.prio; THR_THREAD_UNLOCK(curthread, pthread); _thr_ref_delete(curthread, pthread); } return (ret); }
static void thread_start(struct pthread *curthread) { sigset_t set; if (curthread->attr.suspend == THR_CREATE_SUSPENDED) set = curthread->sigmask; /* * This is used as a serialization point to allow parent * to report 'new thread' event to debugger or tweak new thread's * attributes before the new thread does real-world work. */ THR_LOCK(curthread); THR_UNLOCK(curthread); if (curthread->force_exit) _pthread_exit(PTHREAD_CANCELED); if (curthread->attr.suspend == THR_CREATE_SUSPENDED) { #if 0 /* Done in THR_UNLOCK() */ _thr_ast(curthread); #endif /* * Parent thread have stored signal mask for us, * we should restore it now. */ __sys_sigprocmask(SIG_SETMASK, &set, NULL); } #ifdef _PTHREAD_FORCED_UNWIND curthread->unwind_stackend = (char *)curthread->attr.stackaddr_attr + curthread->attr.stacksize_attr; #endif /* Run the current thread's start routine with argument: */ _pthread_exit(curthread->start_routine(curthread->arg)); /* This point should never be reached. */ PANIC("Thread has resumed after exit"); }
static void thread_start(void *arg) { struct pthread *curthread = (struct pthread *)arg; tls_set_tcb(curthread->tcb); /* Thread was created with all signals blocked, unblock them. */ __sys_sigprocmask(SIG_SETMASK, &curthread->sigmask, NULL); THR_LOCK(curthread); THR_UNLOCK(curthread); if (curthread->flags & THR_FLAGS_NEED_SUSPEND) _thr_suspend_check(curthread); _nmalloc_thr_init(); /* Run the current thread's start routine with argument: */ _pthread_exit(curthread->start_routine(curthread->arg)); /* This point should never be reached. */ PANIC("Thread has resumed after exit"); }
int _pthread_create(pthread_t * thread, const pthread_attr_t * attr, void *(*start_routine) (void *), void *arg) { struct lwp_params create_params; void *stack; sigset_t sigmask, oldsigmask; struct pthread *curthread, *new_thread; int ret = 0, locked; _thr_check_init(); /* * Tell libc and others now they need lock to protect their data. */ if (_thr_isthreaded() == 0 && _thr_setthreaded(1)) return (EAGAIN); curthread = tls_get_curthread(); if ((new_thread = _thr_alloc(curthread)) == NULL) return (EAGAIN); if (attr == NULL || *attr == NULL) { /* Use the default thread attributes: */ new_thread->attr = _pthread_attr_default; } else { new_thread->attr = *(*attr); } if (new_thread->attr.sched_inherit == PTHREAD_INHERIT_SCHED) { /* inherit scheduling contention scope */ if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) new_thread->attr.flags |= PTHREAD_SCOPE_SYSTEM; else new_thread->attr.flags &= ~PTHREAD_SCOPE_SYSTEM; /* * scheduling policy and scheduling parameters will be * inherited in following code. */ } if (create_stack(&new_thread->attr) != 0) { /* Insufficient memory to create a stack: */ new_thread->terminated = 1; _thr_free(curthread, new_thread); return (EAGAIN); } /* * Write a magic value to the thread structure * to help identify valid ones: */ new_thread->magic = THR_MAGIC; new_thread->start_routine = start_routine; new_thread->arg = arg; new_thread->cancelflags = PTHREAD_CANCEL_ENABLE | PTHREAD_CANCEL_DEFERRED; /* * Check if this thread is to inherit the scheduling * attributes from its parent: */ if (new_thread->attr.sched_inherit == PTHREAD_INHERIT_SCHED) { /* * Copy the scheduling attributes. Lock the scheduling * lock to get consistent scheduling parameters. */ THR_LOCK(curthread); new_thread->base_priority = curthread->base_priority; new_thread->attr.prio = curthread->attr.prio; new_thread->attr.sched_policy = curthread->attr.sched_policy; THR_UNLOCK(curthread); } else { /* * Use just the thread priority, leaving the * other scheduling attributes as their * default values: */ new_thread->base_priority = new_thread->attr.prio; } new_thread->active_priority = new_thread->base_priority; /* Initialize the mutex queue: */ TAILQ_INIT(&new_thread->mutexq); /* Initialise hooks in the thread structure: */ if (new_thread->attr.suspend == THR_CREATE_SUSPENDED) new_thread->flags = THR_FLAGS_NEED_SUSPEND; new_thread->state = PS_RUNNING; if (new_thread->attr.flags & PTHREAD_CREATE_DETACHED) new_thread->tlflags |= TLFLAGS_DETACHED; /* Add the new thread. */ new_thread->refcount = 1; _thr_link(curthread, new_thread); /* Return thread pointer eariler so that new thread can use it. */ (*thread) = new_thread; if (SHOULD_REPORT_EVENT(curthread, TD_CREATE)) { THR_THREAD_LOCK(curthread, new_thread); locked = 1; } else locked = 0; /* Schedule the new thread. */ stack = (char *)new_thread->attr.stackaddr_attr + new_thread->attr.stacksize_attr; bzero(&create_params, sizeof(create_params)); create_params.lwp_func = thread_start; create_params.lwp_arg = new_thread; create_params.lwp_stack = stack; create_params.lwp_tid1 = &new_thread->tid; /* * Thread created by thr_create() inherits currrent thread * sigmask, however, before new thread setup itself correctly, * it can not handle signal, so we should mask all signals here. * We do this at the very last moment, so that we don't run * into problems while we have all signals disabled. */ SIGFILLSET(sigmask); __sys_sigprocmask(SIG_SETMASK, &sigmask, &oldsigmask); new_thread->sigmask = oldsigmask; ret = lwp_create(&create_params); __sys_sigprocmask(SIG_SETMASK, &oldsigmask, NULL); if (ret != 0) { if (!locked) THR_THREAD_LOCK(curthread, new_thread); new_thread->state = PS_DEAD; new_thread->terminated = 1; if (new_thread->flags & THR_FLAGS_NEED_SUSPEND) { new_thread->cycle++; _thr_umtx_wake(&new_thread->cycle, INT_MAX); } THR_THREAD_UNLOCK(curthread, new_thread); THREAD_LIST_LOCK(curthread); _thread_active_threads--; new_thread->tlflags |= TLFLAGS_DETACHED; _thr_ref_delete_unlocked(curthread, new_thread); THREAD_LIST_UNLOCK(curthread); (*thread) = NULL; ret = EAGAIN; } else if (locked) { _thr_report_creation(curthread, new_thread); THR_THREAD_UNLOCK(curthread, new_thread); } return (ret); }
void _pthread_exit(void *status) { struct pthread *curthread = _get_curthread(); /* Check if this thread is already in the process of exiting: */ if (curthread->cancelling) { char msg[128]; snprintf(msg, sizeof(msg), "Thread %p has called " "pthread_exit() from a destructor. POSIX 1003.1 " "1996 s16.2.5.2 does not allow this!", curthread); PANIC(msg); } /* Flag this thread as exiting. */ curthread->cancelling = 1; _thr_exit_cleanup(); /* Save the return value: */ curthread->ret = status; while (curthread->cleanup != NULL) { _pthread_cleanup_pop(1); } /* Check if there is thread specific data: */ if (curthread->specific != NULL) { /* Run the thread-specific data destructors: */ _thread_cleanupspecific(); } if (!_thr_isthreaded()) exit(0); THREAD_LIST_LOCK(curthread); _thread_active_threads--; if (_thread_active_threads == 0) { THREAD_LIST_UNLOCK(curthread); exit(0); /* Never reach! */ } THREAD_LIST_UNLOCK(curthread); /* Tell malloc that the thread is exiting. */ _malloc_thread_cleanup(); THREAD_LIST_LOCK(curthread); THR_LOCK(curthread); curthread->state = PS_DEAD; if (curthread->flags & THR_FLAGS_NEED_SUSPEND) { curthread->cycle++; _thr_umtx_wake(&curthread->cycle, INT_MAX, 0); } THR_UNLOCK(curthread); /* * Thread was created with initial refcount 1, we drop the * reference count to allow it to be garbage collected. */ curthread->refcount--; if (curthread->tlflags & TLFLAGS_DETACHED) THR_GCLIST_ADD(curthread); THREAD_LIST_UNLOCK(curthread); if (!curthread->force_exit && SHOULD_REPORT_EVENT(curthread, TD_DEATH)) _thr_report_death(curthread); /* * Kernel will do wakeup at the address, so joiner thread * will be resumed if it is sleeping at the address. */ thr_exit(&curthread->tid); #ifndef __AVM2__ // might exit if we're impersonating another thread! PANIC("thr_exit() returned"); #endif /* Never reach! */ }