int _sched_yield(void) { struct pthread *curthread = _get_curthread(); if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) return (__sys_sched_yield()); /* Reset the accumulated time slice value for the current thread: */ curthread->slice_usec = -1; /* Schedule the next thread: */ _thr_sched_switch(curthread); /* Always return no error. */ return(0); }
/* Draft 4 yield */ void _pthread_yield(void) { struct pthread *curthread = _get_curthread(); if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) { __sys_sched_yield(); return; } /* Reset the accumulated time slice value for the current thread: */ curthread->slice_usec = -1; /* Schedule the next thread: */ _thr_sched_switch(curthread); }
int _pthread_join(pthread_t pthread, void **thread_return) { struct pthread *curthread = _get_curthread(); void *tmp; kse_critical_t crit; int ret = 0; _thr_cancel_enter(curthread); /* Check if the caller has specified an invalid thread: */ if (pthread == NULL || pthread->magic != THR_MAGIC) { /* Invalid thread: */ _thr_cancel_leave(curthread, 1); return (EINVAL); } /* Check if the caller has specified itself: */ if (pthread == curthread) { /* Avoid a deadlock condition: */ _thr_cancel_leave(curthread, 1); return (EDEADLK); } /* * Find the thread in the list of active threads or in the * list of dead threads: */ if ((ret = _thr_ref_add(curthread, pthread, /*include dead*/1)) != 0) { /* Return an error: */ _thr_cancel_leave(curthread, 1); return (ESRCH); } THR_SCHED_LOCK(curthread, pthread); /* Check if this thread has been detached: */ if ((pthread->attr.flags & PTHREAD_DETACHED) != 0) { THR_SCHED_UNLOCK(curthread, pthread); /* Remove the reference and return an error: */ _thr_ref_delete(curthread, pthread); ret = EINVAL; } else { /* Lock the target thread while checking its state. */ if (pthread->state == PS_DEAD) { /* Return the thread's return value: */ tmp = pthread->ret; /* Detach the thread. */ pthread->attr.flags |= PTHREAD_DETACHED; /* Unlock the thread. */ THR_SCHED_UNLOCK(curthread, pthread); /* * Remove the thread from the list of active * threads and add it to the GC list. */ crit = _kse_critical_enter(); KSE_LOCK_ACQUIRE(curthread->kse, &_thread_list_lock); THR_LIST_REMOVE(pthread); THR_GCLIST_ADD(pthread); KSE_LOCK_RELEASE(curthread->kse, &_thread_list_lock); _kse_critical_leave(crit); /* Remove the reference. */ _thr_ref_delete(curthread, pthread); if (thread_return != NULL) *thread_return = tmp; } else if (pthread->joiner != NULL) { /* Unlock the thread and remove the reference. */ THR_SCHED_UNLOCK(curthread, pthread); _thr_ref_delete(curthread, pthread); /* Multiple joiners are not supported. */ ret = ENOTSUP; } else { /* Set the running thread to be the joiner: */ pthread->joiner = curthread; /* Keep track of which thread we're joining to: */ curthread->join_status.thread = pthread; /* Unlock the thread and remove the reference. */ THR_SCHED_UNLOCK(curthread, pthread); _thr_ref_delete(curthread, pthread); THR_SCHED_LOCK(curthread, curthread); while (curthread->join_status.thread == pthread) { THR_SET_STATE(curthread, PS_JOIN); THR_SCHED_UNLOCK(curthread, curthread); /* Schedule the next thread: */ _thr_sched_switch(curthread); THR_SCHED_LOCK(curthread, curthread); } THR_SCHED_UNLOCK(curthread, curthread); if ((curthread->cancelflags & THR_CANCELLING) && !(curthread->cancelflags & PTHREAD_CANCEL_DISABLE)) { if (_thr_ref_add(curthread, pthread, 1) == 0) { THR_SCHED_LOCK(curthread, pthread); pthread->joiner = NULL; THR_SCHED_UNLOCK(curthread, pthread); _thr_ref_delete(curthread, pthread); } _pthread_exit(PTHREAD_CANCELED); } /* * The thread return value and error are set by the * thread we're joining to when it exits or detaches: */ ret = curthread->join_status.error; if ((ret == 0) && (thread_return != NULL)) *thread_return = curthread->join_status.ret; } } _thr_cancel_leave(curthread, 1); /* Return the completion status: */ return (ret); }
int _pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex, const struct timespec * abstime) { struct pthread *curthread = _get_curthread(); int rval = 0; int done = 0; int mutex_locked = 1; int seqno; THR_ASSERT(curthread->locklevel == 0, "cv_timedwait: locklevel is not zero!"); if (abstime == NULL || abstime->tv_sec < 0 || abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) return (EINVAL); /* * If the condition variable is statically initialized, perform dynamic * initialization. */ if (*cond == NULL && (rval = _pthread_cond_init(cond, NULL)) != 0) return (rval); if (!_kse_isthreaded()) _kse_setthreaded(1); /* * Enter a loop waiting for a condition signal or broadcast * to wake up this thread. A loop is needed in case the waiting * thread is interrupted by a signal to execute a signal handler. * It is not (currently) possible to remain in the waiting queue * while running a handler. Instead, the thread is interrupted * and backed out of the waiting queue prior to executing the * signal handler. */ /* Lock the condition variable structure: */ THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock); seqno = (*cond)->c_seqno; do { /* * If the condvar was statically allocated, properly * initialize the tail queue. */ if (((*cond)->c_flags & COND_FLAGS_INITED) == 0) { TAILQ_INIT(&(*cond)->c_queue); (*cond)->c_flags |= COND_FLAGS_INITED; } /* Process according to condition variable type: */ switch ((*cond)->c_type) { /* Fast condition variable: */ case COND_TYPE_FAST: if ((mutex == NULL) || (((*cond)->c_mutex != NULL) && ((*cond)->c_mutex != *mutex))) { /* Return invalid argument error: */ rval = EINVAL; } else { /* Reset the timeout and interrupted flags: */ curthread->timeout = 0; curthread->interrupted = 0; /* * Queue the running thread for the condition * variable: */ cond_queue_enq(*cond, curthread); /* Unlock the mutex: */ if (mutex_locked && ((rval = _mutex_cv_unlock(mutex)) != 0)) { /* * Cannot unlock the mutex; remove the * running thread from the condition * variable queue: */ cond_queue_remove(*cond, curthread); } else { /* Remember the mutex: */ (*cond)->c_mutex = *mutex; /* * Don't unlock the mutex the next * time through the loop (if the * thread has to be requeued after * handling a signal). */ mutex_locked = 0; /* * This thread is active and is in a * critical region (holding the cv * lock); we should be able to safely * set the state. */ THR_SCHED_LOCK(curthread, curthread); /* Set the wakeup time: */ curthread->wakeup_time.tv_sec = abstime->tv_sec; curthread->wakeup_time.tv_nsec = abstime->tv_nsec; THR_SET_STATE(curthread, PS_COND_WAIT); /* Remember the CV: */ curthread->data.cond = *cond; curthread->sigbackout = cond_wait_backout; THR_SCHED_UNLOCK(curthread, curthread); /* Unlock the CV structure: */ THR_LOCK_RELEASE(curthread, &(*cond)->c_lock); /* Schedule the next thread: */ _thr_sched_switch(curthread); /* * XXX - This really isn't a good check * since there can be more than one * thread waiting on the CV. Signals * sent to threads waiting on mutexes * or CVs should really be deferred * until the threads are no longer * waiting, but POSIX says that signals * should be sent "as soon as possible". */ done = (seqno != (*cond)->c_seqno); if (done && !THR_IN_CONDQ(curthread)) { /* * The thread is dequeued, so * it is safe to clear these. */ curthread->data.cond = NULL; curthread->sigbackout = NULL; check_continuation(curthread, NULL, mutex); return (_mutex_cv_lock(mutex)); } /* Relock the CV structure: */ THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock); /* * Clear these after taking the lock to * prevent a race condition where a * signal can arrive before dequeueing * the thread. */ curthread->data.cond = NULL; curthread->sigbackout = NULL; done = (seqno != (*cond)->c_seqno); if (THR_IN_CONDQ(curthread)) { cond_queue_remove(*cond, curthread); /* Check for no more waiters: */ if (TAILQ_EMPTY(&(*cond)->c_queue)) (*cond)->c_mutex = NULL; } if (curthread->timeout != 0) { /* The wait timedout. */ rval = ETIMEDOUT; } } } break; /* Trap invalid condition variable types: */ default: /* Return an invalid argument error: */ rval = EINVAL; break; } check_continuation(curthread, *cond, mutex_locked ? NULL : mutex); } while ((done == 0) && (rval == 0)); /* Unlock the condition variable structure: */ THR_LOCK_RELEASE(curthread, &(*cond)->c_lock); if (mutex_locked == 0) _mutex_cv_lock(mutex); /* Return the completion status: */ return (rval); }