Subject: Re: Interrupt, interrupt threads, continuations, and kernel lwps
To: None <tech-kern@NetBSD.org>
From: Andrew Doran <ad@NetBSD.org>
List: tech-kern
Date: 07/01/2007 15:05:35
On Mon, Jun 25, 2007 at 08:03:52PM +0200, Manuel Bouyer wrote:

> On Mon, Jun 25, 2007 at 01:55:43PM +0100, Andrew Doran wrote:
> > > Do you have a way to do this easily ? A lot of drivers do schedule or
> > > stop callouts from their interrupt function.
> > 
> > Thinking about it further, maybe the only function that needs to do the
> > blocking synchronization (wait for the callout to complete) is callout_stop
> > itself. In that case, if a driver really needs to ensure that callouts occur
> > in a rigid order, then it would need to use a thread to call callout_stop
> > before the other operations, like callout_reset. Do you think that would
> > work?
> 
> Would it still be possible to call callout_stop() from interrupt context
> if we don't care waiting for the call to complete ? For most cases in drivers
> the callout is scheduled for several seconds (at minimum) in the future while
> the interrupt will happen within milliseconds, so in the common case
> the callout will be armed for a very short period. 

After some thought the best suggestion I have is to synchronize only if the
callout is marked with the CALLOUT_MPSAFE flag. If the code is MT safe, then
someone has gone over it and thought about the synchronization issues
involved. And I think that synchronization really only needs to happen for
callout_stop().

I've been making some more general changes to the callouts which I'm going
to check in shortly. The first is to hide the callout implementation from
the user, so we can have a stable ABI/API for LKMs. I initially wanted to do
that by having the callout structures dynamically allocated. That would
require a fairly massive set of changes to device drivers to handle the new
semantics (e.g., callout_init() can fail, callouts must be destroyed). I'm
also cognizant of the fact that external allocation means more cache
pressure. So what I have done is to have the callers provide a fixed block,
which should leave plenty of room for expansion:

typedef struct callout {
        void    *_c_store[12];
} callout_t;

We could be clever about it and allocate callouts on a strictly as-needed
basis, but that means returning more to a simple API more like the original
timeout/untimeout.

Andrew