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>