/* * Find a thread in the linked list of active threads and add a reference * to it. Threads with positive reference counts will not be deallocated * until all references are released. */ int _thr_ref_add(struct pthread *curthread, struct pthread *thread, int include_dead) { kse_critical_t crit; struct pthread *pthread; struct kse *curkse; if (thread == NULL) /* Invalid thread: */ return (EINVAL); crit = _kse_critical_enter(); curkse = _get_curkse(); KSE_LOCK_ACQUIRE(curkse, &_thread_list_lock); pthread = _thr_hash_find(thread); if (pthread) { if ((include_dead == 0) && ((pthread->state == PS_DEAD) || ((pthread->state == PS_DEADLOCK) || ((pthread->flags & THR_FLAGS_EXITING) != 0)))) pthread = NULL; else { pthread->refcount++; if (curthread != NULL) curthread->critical_count++; } } KSE_LOCK_RELEASE(curkse, &_thread_list_lock); _kse_critical_leave(crit); /* Return zero if the thread exists: */ return ((pthread != NULL) ? 0 : ESRCH); }
static void free_stack(struct pthread_attr *pattr) { struct kse *curkse; kse_critical_t crit; if ((pattr->flags & THR_STACK_USER) == 0) { crit = _kse_critical_enter(); curkse = _get_curkse(); KSE_LOCK_ACQUIRE(curkse, &_thread_list_lock); /* Stack routines don't use malloc/free. */ _thr_stack_free(pattr); KSE_LOCK_RELEASE(curkse, &_thread_list_lock); _kse_critical_leave(crit); } }
int * __error(void) { struct pthread *curthread; if (__isthreaded == 0) return (&errno); else if (_kse_in_critical()) return &(_get_curkse()->k_error); else { curthread = _get_curthread(); if ((curthread == NULL) || (curthread == _thr_initial)) return (&errno); else return (&curthread->error); } }
void _thr_ref_delete(struct pthread *curthread, struct pthread *thread) { kse_critical_t crit; struct kse *curkse; if (thread != NULL) { crit = _kse_critical_enter(); curkse = _get_curkse(); KSE_LOCK_ACQUIRE(curkse, &_thread_list_lock); thread->refcount--; if (curthread != NULL) curthread->critical_count--; if ((thread->refcount == 0) && (thread->tlflags & TLFLAGS_GC_SAFE) != 0) THR_GCLIST_ADD(thread); KSE_LOCK_RELEASE(curkse, &_thread_list_lock); _kse_critical_leave(crit); } }
void _pthread_exit(void *status) { struct pthread *curthread = _get_curthread(); kse_critical_t crit; struct kse *curkse; /* Check if this thread is already in the process of exiting: */ if ((curthread->flags & THR_FLAGS_EXITING) != 0) { 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. Threads should now be prevented * from joining to this thread. */ THR_SCHED_LOCK(curthread, curthread); curthread->flags |= THR_FLAGS_EXITING; THR_SCHED_UNLOCK(curthread, curthread); /* * To avoid signal-lost problem, if signals had already been * delivered to us, handle it. we have already set EXITING flag * so no new signals should be delivered to us. * XXX this is not enough if signal was delivered just before * thread called sigprocmask and masked it! in this case, we * might have to re-post the signal by kill() if the signal * is targeting process (not for a specified thread). * Kernel has same signal-lost problem, a signal may be delivered * to a thread which is on the way to call sigprocmask or thr_exit()! */ if (curthread->check_pending) _thr_sig_check_pending(curthread); /* Save the return value: */ curthread->ret = status; while (curthread->cleanup != NULL) { _pthread_cleanup_pop(1); } if (curthread->attr.cleanup_attr != NULL) { curthread->attr.cleanup_attr(curthread->attr.arg_attr); } /* Check if there is thread specific data: */ if (curthread->specific != NULL) { /* Run the thread-specific data destructors: */ _thread_cleanupspecific(); } if (!_kse_isthreaded()) exit(0); crit = _kse_critical_enter(); curkse = _get_curkse(); KSE_LOCK_ACQUIRE(curkse, &_thread_list_lock); /* Use thread_list_lock */ _thread_active_threads--; if ((_thread_scope_system <= 0 && _thread_active_threads == 1) || (_thread_scope_system > 0 && _thread_active_threads == 0)) { KSE_LOCK_RELEASE(curkse, &_thread_list_lock); _kse_critical_leave(crit); exit(0); /* Never reach! */ } KSE_LOCK_RELEASE(curkse, &_thread_list_lock); /* This thread will never be re-scheduled. */ KSE_LOCK(curkse); THR_SET_STATE(curthread, PS_DEAD); _thr_sched_switch_unlocked(curthread); /* Never reach! */ /* This point should not be reached. */ PANIC("Dead thread has resumed"); }
static void * sig_daemon(void *arg __unused) { int i; kse_critical_t crit; struct timespec ts; sigset_t set; struct kse *curkse; struct pthread *curthread = _get_curthread(); DBG_MSG("signal daemon started(%p)\n", curthread); curthread->name = strdup("signal thread"); crit = _kse_critical_enter(); curkse = _get_curkse(); /* * Daemon thread is a bound thread and we must be created with * all signals masked */ #if 0 SIGFILLSET(set); __sys_sigprocmask(SIG_SETMASK, &set, NULL); #endif __sys_sigpending(&set); ts.tv_sec = 0; ts.tv_nsec = 0; while (1) { KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock); _thr_proc_sigpending = set;