Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 20 Oct 1998 22:00:30 -0400 (EDT)
From:      Daniel Eischen <eischen@vigrid.com>
To:        dima@tejblum.dnttm.rssi.ru, eischen@vigrid.com
Cc:        current@FreeBSD.ORG, info@highwind.com, lists@tar.com, tejblum@arc.hq.cti.ru
Subject:   Re: Another Serious libc_r problem
Message-ID:  <199810210200.WAA04708@pcnet1.pcnet.com>

next in thread | raw e-mail | index | archive | help
Dima wrote:
> Daniel Eischen wrote:
>
> > I don't think you want to wrap anything other than the condtion
> > queue and dequeue with the condition spin locks; they should be
> > used just to protect changing the condition variable.
> > 
> > As long as you enqueue the condition variable before you unlock the
> > mutex, there should be no race conditions.
>
> Well, specs says that mutex unlocking and enqueuing are atomic, so we may 
> put it in the code ;-|. (Note also that mutex_unlock may fail.)
>
> Anyway, what if a rescheduling happens just after thread was enqueued for 
> condition variable, and some other thread signaled the condition?

Yes, it seems that we need a method of disabling task scheduing
while we enqueue the condition variable and call the thread
kern scheduler.  You should be able to do this by setting
_thread_kern_in_sched = 1.  Something like this (from
pthread_cond_timedwait):

		/* Lock the condition variable structure: */
		_SPINLOCK(&(*cond)->lock);

		/* Process according to condition variable type: */
		switch ((*cond)->c_type) {
		/* Fast condition variable: */
		case COND_TYPE_FAST:
			/*
			 * Disable thread scheduling.
			 */
			_thread_kern_in_sched = 1;

			/* Set the wakeup time: */
			_thread_run->wakeup_time.tv_sec = abstime->tv_sec;
			_thread_run->wakeup_time.tv_nsec = abstime->tv_nsec;

			/* Reset the timeout flag: */
			_thread_run->timeout = 0;

			/*
			 * Queue the running thread for the condition
			 * variable:
			 */
			_thread_queue_enq(&(*cond)->c_queue, _thread_run);

			/* Unlock the condition variable structure: */
			_SPINUNLOCK(&(*cond)->lock);

			/* Unlock the mutex: */
			if ((rval = pthread_mutex_unlock(mutex)) != 0) {
				/* Lock the condition variable structure: */
				_SPINLOCK(&(*cond)->lock);

				/*
				 * Cannot unlock the mutex, so remove the
				 * running thread from the condition
				 * variable queue: 
				 */
				_thread_queue_deq(&(*cond)->c_queue);

				/* Unlock the condition variable structure: */
				_SPINUNLOCK(&(*cond)->lock);

				/*
				 * There could have had a SIGVTALRM between
				 * here and where we disabled thread
				 * scheduling; force a reschedule.
				 */
				pthread_yield();

			} else {
				/* Schedule the next thread: */
				_thread_kern_sched_state(PS_COND_WAIT,
				    __FILE__, __LINE__);

				/* Lock the mutex: */
				if ((rval = pthread_mutex_lock(mutex)) != 0) {
				}
				/* Check if the wait timed out: */
				else if (_thread_run->timeout) {
					/* Return a timeout error: */
					rval = ETIMEDOUT;
				}
			}
			break;

		/* Trap invalid condition variable types: */
		default:
			/* Unlock the condition variable structure: */
			_SPINUNLOCK(&(*cond)->lock);

			/* Return an invalid argument error: */
			rval = EINVAL;
			break;
		}

Calling _thread_kern_sched_state will end up clearing _thread_kern_in_sched,
(and so will pthread_yield).  The signal handler will not cause a
reschedule when _thread_kern_sched_state is non-zero.

You could always block signals to disable thread scheduling, but that
seems too costly for something that can be done simply by using
what's already in place.

Dan Eischen
eischen@vigrid.com

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-current" in the body of the message



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199810210200.WAA04708>