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>
