Beispiel #1
0
/*
 * the semaphore's count is incremented by one. a blocked thread
 * is awakened and re-tries to acquire the semaphore.
 */
void
sema_v(ksema_t *sp)
{
	sema_impl_t 	*s;
	kthread_t 	*sq, *tp;
	disp_lock_t	*sqlp;

	s = (sema_impl_t *)sp;
	sqlp = &SQHASH(s)->sq_lock;
	disp_lock_enter(sqlp);
	if (panicstr) {
		disp_lock_exit(sqlp);
		return;
	}
	s->s_count++;
	sq = s->s_slpq;
	if (sq != NULL) {
		tp = sq;
		ASSERT(THREAD_LOCK_HELD(tp));
		sq = sq->t_link;
		tp->t_link = NULL;
		DTRACE_SCHED1(wakeup, kthread_t *, tp);
		tp->t_sobj_ops = NULL;
		tp->t_wchan = NULL;
		ASSERT(tp->t_state == TS_SLEEP);
		CL_WAKEUP(tp);
		s->s_slpq = sq;
		disp_lock_exit_high(sqlp);
		thread_unlock(tp);
	} else {
		disp_lock_exit(sqlp);
	}
}
Beispiel #2
0
void
cv_signal(kcondvar_t *cvp)
{
	condvar_impl_t *cp = (condvar_impl_t *)cvp;

	/* make sure the cv_waiters field looks sane */
	ASSERT(cp->cv_waiters <= CV_MAX_WAITERS);
	if (cp->cv_waiters > 0) {
		sleepq_head_t *sqh = SQHASH(cp);
		disp_lock_enter(&sqh->sq_lock);
		ASSERT(CPU_ON_INTR(CPU) == 0);
		if (cp->cv_waiters & CV_WAITERS_MASK) {
			kthread_t *t;
			cp->cv_waiters--;
			t = sleepq_wakeone_chan(&sqh->sq_queue, cp);
			/*
			 * If cv_waiters is non-zero (and less than
			 * CV_MAX_WAITERS) there should be a thread
			 * in the queue.
			 */
			ASSERT(t != NULL);
		} else if (sleepq_wakeone_chan(&sqh->sq_queue, cp) == NULL) {
			cp->cv_waiters = 0;
		}
		disp_lock_exit(&sqh->sq_lock);
	}
}
Beispiel #3
0
/*
 * Change the priority of a thread that's blocked on a condition variable.
 */
static void
cv_change_pri(kthread_t *t, pri_t pri, pri_t *t_prip)
{
	condvar_impl_t *cvp = (condvar_impl_t *)t->t_wchan;
	sleepq_t *sqp = t->t_sleepq;

	ASSERT(THREAD_LOCK_HELD(t));
	ASSERT(&SQHASH(cvp)->sq_queue == sqp);

	if (cvp == NULL)
		panic("cv_change_pri: %p not on sleep queue", t);
	sleepq_dequeue(t);
	*t_prip = pri;
	sleepq_insert(sqp, t);
}
Beispiel #4
0
void
cv_broadcast(kcondvar_t *cvp)
{
	condvar_impl_t *cp = (condvar_impl_t *)cvp;

	/* make sure the cv_waiters field looks sane */
	ASSERT(cp->cv_waiters <= CV_MAX_WAITERS);
	if (cp->cv_waiters > 0) {
		sleepq_head_t *sqh = SQHASH(cp);
		disp_lock_enter(&sqh->sq_lock);
		ASSERT(CPU_ON_INTR(CPU) == 0);
		sleepq_wakeall_chan(&sqh->sq_queue, cp);
		cp->cv_waiters = 0;
		disp_lock_exit(&sqh->sq_lock);
	}
}
Beispiel #5
0
/*
 * Unsleep a thread that's blocked on a condition variable.
 */
static void
cv_unsleep(kthread_t *t)
{
	condvar_impl_t *cvp = (condvar_impl_t *)t->t_wchan;
	sleepq_head_t *sqh = SQHASH(cvp);

	ASSERT(THREAD_LOCK_HELD(t));

	if (cvp == NULL)
		panic("cv_unsleep: thread %p not on sleepq %p", t, sqh);
	DTRACE_SCHED1(wakeup, kthread_t *, t);
	sleepq_unsleep(t);
	if (cvp->cv_waiters != CV_MAX_WAITERS)
		cvp->cv_waiters--;
	disp_lock_exit_high(&sqh->sq_lock);
	CL_SETRUN(t);
}
Beispiel #6
0
/*
 * try to acquire the semaphore. if the semaphore is greater than
 * zero, then the semaphore is granted and returns 1. otherwise
 * return 0.
 */
int
sema_tryp(ksema_t *sp)
{
	sema_impl_t	*s;
	sleepq_head_t	*sqh;

	int	gotit = 0;

	s = (sema_impl_t *)sp;
	sqh = SQHASH(s);
	disp_lock_enter(&sqh->sq_lock);
	if (s->s_count > 0) {
		s->s_count--;
		gotit = 1;
	}
	disp_lock_exit(&sqh->sq_lock);
	return (gotit);
}
Beispiel #7
0
/*
 * The cv_block() function blocks a thread on a condition variable
 * by putting it in a hashed sleep queue associated with the
 * synchronization object.
 *
 * Threads are taken off the hashed sleep queues via calls to
 * cv_signal(), cv_broadcast(), or cv_unsleep().
 */
static void
cv_block(condvar_impl_t *cvp)
{
	kthread_t *t = curthread;
	klwp_t *lwp = ttolwp(t);
	sleepq_head_t *sqh;

	ASSERT(THREAD_LOCK_HELD(t));
	ASSERT(t != CPU->cpu_idle_thread);
	ASSERT(CPU_ON_INTR(CPU) == 0);
	ASSERT(t->t_wchan0 == NULL && t->t_wchan == NULL);
	ASSERT(t->t_state == TS_ONPROC);

	t->t_schedflag &= ~TS_SIGNALLED;
	CL_SLEEP(t);			/* assign kernel priority */
	t->t_wchan = (caddr_t)cvp;
	t->t_sobj_ops = &cv_sobj_ops;
	DTRACE_SCHED(sleep);

	/*
	 * The check for t_intr is to avoid doing the
	 * account for an interrupt thread on the still-pinned
	 * lwp's statistics.
	 */
	if (lwp != NULL && t->t_intr == NULL) {
		lwp->lwp_ru.nvcsw++;
		(void) new_mstate(t, LMS_SLEEP);
	}

	sqh = SQHASH(cvp);
	disp_lock_enter_high(&sqh->sq_lock);
	if (cvp->cv_waiters < CV_MAX_WAITERS)
		cvp->cv_waiters++;
	ASSERT(cvp->cv_waiters <= CV_MAX_WAITERS);
	THREAD_SLEEP(t, &sqh->sq_lock);
	sleepq_insert(&sqh->sq_queue, t);
	/*
	 * THREAD_SLEEP() moves curthread->t_lockp to point to the
	 * lock sqh->sq_lock. This lock is later released by the caller
	 * when it calls thread_unlock() on curthread.
	 */
}
Beispiel #8
0
/*
 * the semaphore is granted when the semaphore's
 * count is greater than zero and blocks when equal
 * to zero.
 */
void
sema_p(ksema_t *sp)
{
	sema_impl_t	*s;
	disp_lock_t	*sqlp;

	s = (sema_impl_t *)sp;
	sqlp = &SQHASH(s)->sq_lock;
	disp_lock_enter(sqlp);
	ASSERT(s->s_count >= 0);
	while (s->s_count == 0) {
		if (panicstr) {
			disp_lock_exit(sqlp);
			return;
		}
		thread_lock_high(curthread);
		SEMA_BLOCK(s, sqlp);
		thread_unlock_nopreempt(curthread);
		swtch();
		disp_lock_enter(sqlp);
	}
	s->s_count--;
	disp_lock_exit(sqlp);
}
Beispiel #9
0
/*
 * similiar to sema_p except that it blocks at an interruptible
 * priority. if a signal is present then return 1 otherwise 0.
 */
int
sema_p_sig(ksema_t *sp)
{
	kthread_t	*t = curthread;
	klwp_t		*lwp = ttolwp(t);
	sema_impl_t	*s;
	disp_lock_t	*sqlp;

	if (lwp == NULL) {
		sema_p(sp);
		return (0);
	}

	s = (sema_impl_t *)sp;
	sqlp = &SQHASH(s)->sq_lock;
	disp_lock_enter(sqlp);
	ASSERT(s->s_count >= 0);
	while (s->s_count == 0) {
		proc_t *p = ttoproc(t);
		thread_lock_high(t);
		t->t_flag |= T_WAKEABLE;
		SEMA_BLOCK(s, sqlp);
		lwp->lwp_asleep = 1;
		lwp->lwp_sysabort = 0;
		thread_unlock_nopreempt(t);
		if (ISSIG(t, JUSTLOOKING) || MUSTRETURN(p, t))
			setrun(t);
		swtch();
		t->t_flag &= ~T_WAKEABLE;
		if (ISSIG(t, FORREAL) ||
		    lwp->lwp_sysabort || MUSTRETURN(p, t)) {
			kthread_t *sq, *tp;
			lwp->lwp_asleep = 0;
			lwp->lwp_sysabort = 0;
			disp_lock_enter(sqlp);
			sq = s->s_slpq;
			/*
			 * in case sema_v and interrupt happen
			 * at the same time, we need to pass the
			 * sema_v to the next thread.
			 */
			if ((sq != NULL) && (s->s_count > 0)) {
				tp = sq;
				ASSERT(THREAD_LOCK_HELD(tp));
				sq = sq->t_link;
				tp->t_link = NULL;
				DTRACE_SCHED1(wakeup, kthread_t *, tp);
				tp->t_sobj_ops = NULL;
				tp->t_wchan = NULL;
				ASSERT(tp->t_state == TS_SLEEP);
				CL_WAKEUP(tp);
				s->s_slpq = sq;
				disp_lock_exit_high(sqlp);
				thread_unlock(tp);
			} else {
				disp_lock_exit(sqlp);
			}
			return (1);
		}
		lwp->lwp_asleep = 0;
		disp_lock_enter(sqlp);
	}
	s->s_count--;
	disp_lock_exit(sqlp);
	return (0);
}