Re: New "timeout" api, to replace callout
- From: John Baldwin <jhb@xxxxxxxxxxx>
- Date: Fri, 28 Dec 2007 12:25:13 -0500
On Friday 28 December 2007 05:30:14 am Robert Watson wrote:
backing
On Fri, 28 Dec 2007, Hans Petter Selasky wrote:
The reason you need to do a drain is to allow for safe destroying of the
lock. Specifically, drivers tend to do this:
FOO_LOCK(sc);
...
callout_stop(...);
FOO_UNLOCK(sc);
...
callout_drain(...);
...
mtx_destroy(&sc->foo_mtx);
If you don't have the drain and softclock is trying to acquire the
canmutex while you have it held (before the callout_stop) then Bad Things
beinghappen if you don't do the drain. Having the lock just "give up" doesn't
work either because if the memory containing the lock is free'd and
reinitialized such that it looks enough like a valid lock then softclock
(or its equivalent) will still try to obtain it. Also, you need to do a
drain so it is safe to free the callout structure to prevent it from
butrecycled and having weird races where it gets recycled and rescheduled
mightthe timer code thinks it has a pending stop for that pointer and so it
aborts the wrong instance of the timer, etc.
I completely agree to what John Baldwin is writing. You need two
stop-functions:
xxx_stop which is non-blocking and xxx_drain which can block i.e. sleep
BTW: The USB code in P4 uses the same semantics, due to the same reasons:
usbd_transfer_stop() and usbd_transfer_drain()
The only difference is that I pass an error code to the callback which
behappen after that usbd_transfer_stop is called.
I think that xxx_stop() and xxx_drain() is a generic approach that should
beapplied to all callback systems. Whenever you have a callback you need to
drainable to stop it and drain it.
I think the argument that Poul-Henning is making is not that you don't need
something that behaves "like drain", but rather, we're like the wait for
to be a short, mutex-length wait rather than a long, msleep-length wait.way
Remember that the bodies of callouts are expected to run in a very short
period of time in order to not stall the timer system, in fact, in such a
that a mutex could be held over the entirely timeout call. Given that thisis
the case, one might reasonably expect callout_stop() to perform the drainsafely
rather than having a separate call. Such a model would be very advantageous
in TCP, where rather than having to defer GC'ing the inpcb/tcpcb to a GC
worker thread, which we don't do but should, we could use the stop call
and eliminate a whole class of races from the stack.
The problem is if softclock() (or similar replacement in future) was preempted
and hasn't run yet but has already gotten to the point that callout_drain()
has to block, then sitting in a spin loop waiting for softclock() to
acknowledge the stop isn't very optimal. The amount of time you are asleep
in this case is actually very small, and you probably won't even block the
vast majority of the time if you follow the 'lock / stop / unlock / drain'
model. You only sleep when you lose the race and softclock() has chosen to
run your callout and is waiting for the driver/client/whatever's lock.
--
John Baldwin
_______________________________________________
freebsd-arch@xxxxxxxxxxx mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-arch
To unsubscribe, send any mail to "freebsd-arch-unsubscribe@xxxxxxxxxxx"
- References:
- Re: New "timeout" api, to replace callout
- From: Poul-Henning Kamp
- Re: New "timeout" api, to replace callout
- From: Hans Petter Selasky
- Re: New "timeout" api, to replace callout
- From: Robert Watson
- Re: New "timeout" api, to replace callout
- Prev by Date: Re: kernel features MIB
- Next by Date: Re: kernel features MIB
- Previous by thread: Re: New "timeout" api, to replace callout
- Next by thread: Re: New "timeout" api, to replace callout
- Index(es):
Relevant Pages
|