Am Samstag, 24. September 2016 schrieb David Gwynne : > On Fri, Sep 23, 2016 at 10:16:34PM -0700, Philip Guenther wrote: > > On Fri, 23 Sep 2016, Christiano F. Haesbaert wrote: > > ... > > > The diff as it is will deadlock against SCHED_LOCK. > > > tsleep() calls sleep_setup(), which grabs SCHED_LOCK, > > > Then sleep_setup_timeout() will grab timeout_mutex in timeout_add() > > > > > > On softclock() you have the opposite: > > > Grabs timeout_mutex then does a wakeup, which grabs SCHED_LOCK. > > nice. > > > > > Hmm, yes. And softclock_thread() has the same problem: msleep() needs to > > grab SCHED_LOCK while the passed in mutex is held, so it'll hold > > timeout_mutex while grabbing SCHED_LOCK too. > > > > I just played around with using a separate mutex for protecting > > timeout_proc, a mutex which would be 'outside' SCHED_LOCK, unlike > > timeout_mutex which is 'inside' SCHED_LOCK. The catch is that supporting > > all the functionality of timeout_add() and timeout_del() becomes ugly and > > fragile: they would need to check whether the mutex has > > TIMEOUT_NEEDPROCCTX set and, if so, grab the new mutex before grabbing > > timeout_mutex. ??That's "safe" from being a lock loop from tsleep() > because > > the thread's p_sleep_to *can't* have that flag set, so the 'outside' > mutex > > wouldn't be needed....but geez is this ugly. I'm also unsure what > defined > > semantics, if any, timeout_triggered() should have for NEEDPROCCTX > > timeouts. Should it return true once the timeout has been dequeued from > > the timeout wheel, or should it only be set once softclock_thread is > > actually going to run it? > > > > > > ...or maybe this makes people think we should toss this out and go > > directly to dlg@'s proposal... > > let's not go crazy. > > i believe the deadlock can be fixed by moving the wakeup outside > the hold of timeout_mutex in timeout_add. you only need to wake up > the thread once even if you queued multiple timeouts, cos the thread > will loop until it completes all pending work. think of this as > interrupt mitigation.
Yes, that was my solution as well, i don't have access to the code right now, but I think this won't fix the msleep case guenther pointed out. > > it is worth noting that sleep_setup_timeout doesnt timeout_add if > the wait is 0, so the thread doesnt recurse. > > Index: kern/kern_timeout.c > =================================================================== > RCS file: /cvs/src/sys/kern/kern_timeout.c,v > retrieving revision 1.49 > diff -u -p -r1.49 kern_timeout.c > --- kern/kern_timeout.c 22 Sep 2016 12:55:24 -0000 1.49 > +++ kern/kern_timeout.c 24 Sep 2016 09:45:09 -0000 > @@ -375,6 +375,7 @@ softclock(void *arg) > int delta; > struct circq *bucket; > struct timeout *to; > + int needsproc = 0; > > mtx_enter(&timeout_mutex); > while (!CIRCQ_EMPTY(&timeout_todo)) { > @@ -391,7 +392,7 @@ softclock(void *arg) > CIRCQ_INSERT(&to->to_list, bucket); > } else if (to->to_flags & TIMEOUT_NEEDPROCCTX) { > CIRCQ_INSERT(&to->to_list, &timeout_proc); > - wakeup(&timeout_proc); > + needsproc = 1; > } else { > #ifdef DEBUG > if (delta < 0) > @@ -401,6 +402,9 @@ softclock(void *arg) > } > } > mtx_leave(&timeout_mutex); > + > + if (needsproc) > + wakeup(&timeout_proc); > } > > void >