int _pthread_cond_broadcast(pthread_cond_t * cond) { struct pthread *curthread = _get_curthread(); struct pthread *pthread; struct kse_mailbox *kmbx; int rval = 0; THR_ASSERT(curthread->locklevel == 0, "cv_timedwait: locklevel is not zero!"); if (cond == NULL) rval = EINVAL; /* * If the condition variable is statically initialized, perform dynamic * initialization. */ else if (*cond != NULL || (rval = _pthread_cond_init(cond, NULL)) == 0) { /* Lock the condition variable structure: */ THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock); /* Process according to condition variable type: */ switch ((*cond)->c_type) { /* Fast condition variable: */ case COND_TYPE_FAST: /* Increment the sequence number: */ (*cond)->c_seqno++; /* * Enter a loop to bring all threads off the * condition queue: */ while ((pthread = TAILQ_FIRST(&(*cond)->c_queue)) != NULL) { THR_SCHED_LOCK(curthread, pthread); cond_queue_remove(*cond, pthread); pthread->sigbackout = NULL; if ((pthread->kseg == curthread->kseg) && (pthread->active_priority > curthread->active_priority)) curthread->critical_yield = 1; kmbx = _thr_setrunnable_unlocked(pthread); THR_SCHED_UNLOCK(curthread, pthread); if (kmbx != NULL) kse_wakeup(kmbx); } /* There are no more waiting threads: */ (*cond)->c_mutex = NULL; break; /* Trap invalid condition variable types: */ default: /* Return an invalid argument error: */ rval = EINVAL; break; } /* Unlock the condition variable structure: */ THR_LOCK_RELEASE(curthread, &(*cond)->c_lock); } /* Return the completion status: */ return (rval); }
int _pthread_cancel(pthread_t pthread) { struct pthread *curthread = _get_curthread(); struct pthread *joinee = NULL; struct kse_mailbox *kmbx = NULL; int ret; if ((ret = _thr_ref_add(curthread, pthread, /*include dead*/0)) == 0) { /* * Take the thread's lock while we change the cancel flags. */ THR_THREAD_LOCK(curthread, pthread); THR_SCHED_LOCK(curthread, pthread); if (pthread->flags & THR_FLAGS_EXITING) { THR_SCHED_UNLOCK(curthread, pthread); THR_THREAD_UNLOCK(curthread, pthread); _thr_ref_delete(curthread, pthread); return (ESRCH); } if (((pthread->cancelflags & PTHREAD_CANCEL_DISABLE) != 0) || (((pthread->cancelflags & THR_AT_CANCEL_POINT) == 0) && ((pthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) == 0))) /* Just mark it for cancellation: */ pthread->cancelflags |= THR_CANCELLING; else { /* * Check if we need to kick it back into the * run queue: */ switch (pthread->state) { case PS_RUNNING: /* No need to resume: */ pthread->cancelflags |= THR_CANCELLING; break; case PS_LOCKWAIT: /* * These can't be removed from the queue. * Just mark it as cancelling and tell it * to yield once it leaves the critical * region. */ pthread->cancelflags |= THR_CANCELLING; pthread->critical_yield = 1; break; case PS_SLEEP_WAIT: case PS_SIGSUSPEND: case PS_SIGWAIT: /* Interrupt and resume: */ pthread->interrupted = 1; pthread->cancelflags |= THR_CANCELLING; kmbx = _thr_setrunnable_unlocked(pthread); break; case PS_JOIN: /* Disconnect the thread from the joinee: */ joinee = pthread->join_status.thread; pthread->join_status.thread = NULL; pthread->cancelflags |= THR_CANCELLING; kmbx = _thr_setrunnable_unlocked(pthread); if ((joinee != NULL) && (pthread->kseg == joinee->kseg)) { /* Remove the joiner from the joinee. */ joinee->joiner = NULL; joinee = NULL; } break; case PS_SUSPENDED: case PS_MUTEX_WAIT: case PS_COND_WAIT: /* * Threads in these states may be in queues. * In order to preserve queue integrity, the * cancelled thread must remove itself from the * queue. Mark the thread as interrupted and * needing cancellation, and set the state to * running. When the thread resumes, it will * remove itself from the queue and call the * cancellation completion routine. */ pthread->interrupted = 1; pthread->cancelflags |= THR_CANCEL_NEEDED; kmbx = _thr_setrunnable_unlocked(pthread); pthread->continuation = _thr_finish_cancellation; break; case PS_DEAD: case PS_DEADLOCK: case PS_STATE_MAX: /* Ignore - only here to silence -Wall: */ break; } if ((pthread->cancelflags & THR_AT_CANCEL_POINT) && (pthread->blocked != 0 || pthread->attr.flags & PTHREAD_SCOPE_SYSTEM)) kse_thr_interrupt(&pthread->tcb->tcb_tmbx, KSE_INTR_INTERRUPT, 0); } /* * Release the thread's lock and remove the * reference: */ THR_SCHED_UNLOCK(curthread, pthread); THR_THREAD_UNLOCK(curthread, pthread); _thr_ref_delete(curthread, pthread); if (kmbx != NULL) kse_wakeup(kmbx); if ((joinee != NULL) && (_thr_ref_add(curthread, joinee, /* include dead */1) == 0)) { /* Remove the joiner from the joinee. */ THR_SCHED_LOCK(curthread, joinee); joinee->joiner = NULL; THR_SCHED_UNLOCK(curthread, joinee); _thr_ref_delete(curthread, joinee); } } return (ret); }
int _pthread_cond_signal(pthread_cond_t * cond) { struct pthread *curthread = _get_curthread(); struct pthread *pthread; struct kse_mailbox *kmbx; int rval = 0; THR_ASSERT(curthread->locklevel == 0, "cv_timedwait: locklevel is not zero!"); if (cond == NULL) rval = EINVAL; /* * If the condition variable is statically initialized, perform dynamic * initialization. */ else if (*cond != NULL || (rval = _pthread_cond_init(cond, NULL)) == 0) { /* Lock the condition variable structure: */ THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock); /* Process according to condition variable type: */ switch ((*cond)->c_type) { /* Fast condition variable: */ case COND_TYPE_FAST: /* Increment the sequence number: */ (*cond)->c_seqno++; /* * Wakeups have to be done with the CV lock held; * otherwise there is a race condition where the * thread can timeout, run on another KSE, and enter * another blocking state (including blocking on a CV). */ if ((pthread = TAILQ_FIRST(&(*cond)->c_queue)) != NULL) { THR_SCHED_LOCK(curthread, pthread); cond_queue_remove(*cond, pthread); pthread->sigbackout = NULL; if ((pthread->kseg == curthread->kseg) && (pthread->active_priority > curthread->active_priority)) curthread->critical_yield = 1; kmbx = _thr_setrunnable_unlocked(pthread); THR_SCHED_UNLOCK(curthread, pthread); if (kmbx != NULL) kse_wakeup(kmbx); } /* Check for no more waiters: */ if (TAILQ_EMPTY(&(*cond)->c_queue)) (*cond)->c_mutex = NULL; break; /* Trap invalid condition variable types: */ default: /* Return an invalid argument error: */ rval = EINVAL; break; } /* Unlock the condition variable structure: */ THR_LOCK_RELEASE(curthread, &(*cond)->c_lock); } /* Return the completion status: */ return (rval); }