Subject: Nitty-gritty questions on locking and interrupts
To: None <tech-kern@netbsd.org>
From: None <kpneal@pobox.com>
List: tech-kern
Date: 12/31/2002 14:28:22
Ok, so I've got some work I want to do in the kernel. It involves
code that lives in the top and bottom halves, and so runs in either
a process context (right?) or an interrupt context. 

Now, what does this top/bottom split mean in an SMP world? Different
processors in the same system can at any point in time have different spl
levels/masks, right? Are the spl calls going to go away?

What is the correct way to write code that lives on the boundry between
top and bottom but is still SMP-safe?

The simple_lock man page says this on struct simplelock:

              Simplelocks are usually used only by the high-level lock manager
              and to protect short, critical sections of code.  Simplelocks
              are the only locks that can be be used inside an interrupt han-
              dler.  For a simplelock to be used in an interrupt handler, care
              must be taken to disable the interrupt, acquire the lock, do any
              processing, release the simplelock and re-enable the interrupt.
              This procedure is necessary to avoid deadlock between the inter-
              rupt handler and other threads executing on the same processor.

Does this mean that an interrupt that uses a simplelock must be prevented
from running while code in a process context has the lock locked? If so,
who is the lock meant to coordinate between? Interrupt handlers running
on different CPUs? Because otherwise interrupt handlers can just assume
they have the necessary locks already locked (and never bother to unlock
them) -- code in a process context cannot have locks locked that may be
used by interrupt handlers.

If an interrupt handler tries to (simple)lock something already locked by
code in a process context, does that mean the interrupt handler would run
forever spinning?

What's the difference between a thread and an interrupt handler? Well,
an interrupt handler is scheduled because of an interrupt (or some code
in a process context requested it). Interrupt handlers do not have their
own address spaces, either, and do not show up in ps. Also, interrupt
handlers cannot do some forms of sleep. Is that about it?

Can an interrupt handler schedule an interrupt handler with 
softintr_schedule()? Should it? Is this, along with simple_lock_try(),
a way to share locks between interrupts and non-interrupts safely?
Probably not, because the interrupt might never ever actually be
able to lock the lock?

Do we have any platforms that do not __HAVE_GENERIC_SOFT_INTERRUPTS?
If not, will we ever?

Sanity check to make sure I'm not on crack - this code here is wrong, correct?

  if (foo->bar == NULL) {
     int l = splwhatever();

     something_operating_on_bar(foo);

     splx(l);
  }

What's the preferred way to correct this?

#1:

  int l = splwhatever();
  if (foo->bar == NULL) {
     something_operating_on_bar(foo);
  }
  splx(l);

Or #2: 

  if (foo->bar == NULL) {
     int l = splwhatever();

     if (foo->bar == NULL) 
        something_operating_on_bar(foo);

     splx(l);
  }

Choice #2 seems more efficient if foo->bar == NULL only occasionally,
but #1 is smaller and seems less error prone. 

Is this a correct way to make code SMP-safe?

  int l = splwhatever();   
#ifdef MULTIPROCESSOR
  simple_lock(&foo->foolock);
#endif
  if (foo->bar == NULL) {
     something_operating_on_bar(foo);
  }  
#ifdef MULTIPROCESSOR
  simple_unlock(&foo->foolock);
#endif
  splx(l);   

Thanks for the help, and happy new year!
-- 
"A method for inducing cats to exercise consists of directing a beam of
invisible light produced by a hand-held laser apparatus onto the floor ...
in the vicinity of the cat, then moving the laser ... in an irregular way
fascinating to cats,..." -- US patent 5443036, "Method of exercising a cat"