Newsgroups: comp.unix.internals

In / hpcupt3:comp.unix.internals / avalon@coombs.anu.edu.au (Darren Reed) writes

> Can anyone enlighten me to the purpose of the splnet(), splimp(), etc
> calls that are made by the various BSD kernels ?
> 

This question has been asked earlier on this newsgroup. Seems to qualify for
FAQ ! I had saved a copy of the answer which I had posted earlier (Oct 28 '91).
I am posting it again. Hope this answers your question.

- Aakash
________________________________________________________________________________

> Also the functions (macros??) splimp(),splnet and splx() 
> leave me completely stumped.....
> Portions of the BSD code are surrounded with them almost
> like a mutex_lock/mutex_unlock pairing.....
> If anyone could give me a run down on the spl*
> Thanks,
> Kell

These functions are used to protect the critical regions of the code from
interrupts. On Uniprocessor system these routines, in a way, work like 
semaphores. They help protect data structures which can be modified by
the kernel code from both the system call entry as well as Interrupt Service
routines. As an example, consider a linked list where list elements are
enqueued as a result of a system call and are dequeued on receipt of an
interrupt. As the interrupts occur asynchronously we need to protect the
enqueuing operation from interrupts ( If we do not protect it may result in
garbling of the list - well you know why ! ). The interrupt level activity 
(the dequeing operation in the above example) need not be explicitly protected
from further interrupt activity because UNIX blocks the interrupts of the same
and lower priority while interrupt processing is going on.

The splnet() routine blocks all interrupts of the same and lower Interrupt
Priority Level ( IPL ) which may be caused by the network devices.
It does not check to see if any of the interrupts are already blocked or not.

The splimp() routine does the same thing but it checks to see if the
priority of the interrupts already blocked is equal to or higher than
the network interrupts or not - if it is, it does not do anything and
if it is not then it raises it to the level of network device interrupt
level. This can be used to block the interrupts in the routine which can
be called both through system call entry or from the interrupts service
routines and which require that the network device interrupt activity be
blocked.

Both of these ( and all other spl* routines ) return the priority of the
interrupts which were blocked before call to this routine. The splx()
routine takes this return value as an argument and is used to restore the
previous Interrupt Priority Level.

As another example consider a case where disk, network and clock devices
are at priorities 5,6 and 7 respectively.

		.........	<- system call entry ( IPL =  0 )
		.........
		b = splbio()	<- Block disk interrupt. IPL raised to 5
		........
		........
		c = splclock()	<- IPL raised to 7.
		........
		........
		i = splimp()	<- IPL remains at 7.
		........
		........
		n = splnet()	<- IPL lowered to 6. /* Should not be done */
					      /* normally, unless too sure */
		........
		........
		splx(n)		<- IPL back to 7.
		........
		........
		splx(i)		<- IPL still at 7.
		........
		........
		splx(c)		<- IPL back to 5.
		........
		........
		splx(b)		<- IPL back to 0.
		.......

---------------------------------------------------------------------------
/*
 * Disclaimer : The views expressed here are mine and in no way express the
 *		views of my employer or company in this matter.
 */