Subject: Re: splraise?
To: None <leo@ahwau.ahold.nl>
From: Jason Thorpe <thorpej@nas.nasa.gov>
List: tech-kern
Date: 03/05/1997 13:09:53
[ Catching up on mail after being on vacation... ]

On Sat, 1 Mar 1997 22:46:35 +0100 (MET) 
 Leo Weppelman <leo@wau.mis.ah.nl> wrote:

 > Gordon W. Ross wrote:
 > > 
 > > Where is it appropriate to use splraise?
 > 
 > My guess is that it would solve some problems with diagnostic printf's
 > when spltty would be defined in terms of splraise on the atari. There
 > are places (like the spurious interrupt reports for instance) that
 > occaisionally crash because somewhere in the tty-code the spl is lowered.

...I've always understood that the spl calls were meant to "raise priority".
So, if you were already at a priority that blocked an interrupt that
a new call would make, you don't actually have to do anything.

If there is _ANY_ chance that spl calls may be nested, you need something
like splraise().  A good example of this is in kern/subr_disk.c:

void
disk_unbusy(diskp, bcount)
	struct disk *diskp;
	long bcount; 
{
	. . .

	s = splclock();
	dv_time = mono_time;
	splx(s);

	. . .
}

disk_unbusy() is assumed to be called _while already at_ splbio(),
so splclock() _must not_ reenable interrupts blocked by splbio().

(For those who don't know, mono_time is a struct timeval
representing monotonically incrementing time... it is incremented
by the clock interrupt.  Since it's a structure, assignment is
not atomic, and clock interrupts must be blocked during the duration
of the copy.)

Now, it is _highly_ unlikely that the clock will be of a lower
priority than bio devices on architectures that have level-structured
interrupts (i.e. m68k), although this did bite the mac68k port at
one point.

However, on architectures which don't associate levels with interrupt
lines (mips, i386), software must be aware of this, and make sure
"priority" isn't accidentally lowered.  ("All the world's a VAX ... All
the world's a VAX ... All the world's a VAX...")

To this end, something like splraise() is handy... (Actually, it's
handy even on architectures that have level-structured interrupts,
for various reasons.)

Now, note that splraise() is _NOT_ part of the "spl interface" ... it
is simply a tool which may be used to implement the spl interface
presented to the rest of the kernel.  For this reason, I prefer to
call it _splraise()...

 > > It is my understanding that in most places, splraise should not be
 > > necessary (just splbio or whatever) thanks to the following rules:
 > > 
 > > splsoftxxx <= min(splbio, splnet, spltty)
 > > 
 > > splbio >= max(disk H/W interrupts)
 > > splnet >= max(network H/W interrupts)
 > > spltty >= max(tty H/W interrupts)

Actually... the heirarchy that is "best" goes something like this:

splsoftxxx() ... block software interrupt processing at that level,
no more, really.  Since callouts are not used for TCP timers,
softclock and softnet don't have to block each other (I don't think;
someone may want to sanity check me, here...).

You have what the individual bio/net/tty interrupts must block, except
for a couple of extra rules...

Since device drivers may call malloc() or free() at interrupt time, you
must serialize access to the malloc free list.  This means:

	splimp >= max(splbio, splnet, spltty)

Since run queues may be manipulated by both the statclock and tty,
network, and disk drivers (i.e. call wakeup(), or whatever):

	splstatclock >= max(splbio, splnet, spltty)

...and a heirarchy:

	splbio <= splnet <= spltty
or (preferred)
	splbio < splnet < spltty

...rationale being that disks will never drop data if their interrupt
isn't services quickly, and network interfaces tend to have more buffering
than serial interfaces.

 > > So, can someone explain the rationale for defining splbio and
 > > friends as splraise?  Also, what is the performance impact?
 > 
 > I sure am interested in the performance impact. I expect it to be
 > low, but there is no splraise (yet) on the atari to prove it ;-)

I borrowed the mac68k port's _splraise() and define the following
in terms of it in the hp300 port:

#define splbio()        _splraise(hp300_bioipl)
#define splnet()        _splraise(hp300_netipl)
#define spltty()        _splraise(hp300_ttyipl)
#define splimp()        _splraise(hp300_impipl)

The levels are computed dynamically as interrupt handlers are registered
with the system.  I have yet to see any noticeable performance impact.

Ciao.

Jason R. Thorpe                                       thorpej@nas.nasa.gov
NASA Ames Research Center                               Home: 408.866.1912
NAS: M/S 258-6                                          Work: 415.604.0935
Moffett Field, CA 94035                                Pager: 415.428.6939