[comp.unix.questions] Interrupting a Round Robin Dispatcher

dymm@b.cs.wvu.wvnet.edu (David Dymm) (03/11/89)

    First, THANK YOU to all of the people who took the time
to answer my first (& second) requests for help on the
interrupt handler problem.

    I have a second problem that also involves interrupt handlers,
but is somewhat different from the previous problems.
I would appreciate comments, criticisms, laughter, etc. about
the following architecture, and answers to the questions at
the end.

    The architecture of the system is as follows (running on
BSD 4-2 Unix on a Sun 3 and/or 4):


	Kernel (single process) |   Separate Tasks (separate processes)
	------			|   -----------------------------------
			        |
	Round-Robin Dispatcher	|	task1
				|	task2
	Query Processor		|	task3
				|	task4
				|	task5
				|	  .
				|	  .

    The round robin dispatcher loops between the separate tasks.
Each task is a separate process.  The purpose of a task is to
act as a query interface between some external user and the Kernel
The task uses IPC to communicate user queries for information to the
kernel, and to return the requested information from the kernel to the
user.  Each task is a small, efficient process used solely for
communications.  Each task is fast and will not cause appreciable
degradation of the kernel.
(Note:  The nature of the tasks is such that the above architecture
	is required.)

    Most queries from the user (via a task) to the kernel are
simple queries for information.  The query is processed quickly
by the kernel's "query processor", and the dispatcher can 
quickly move on to the next task.  The user attached to the next
task will see no appreciable time delay.

    However an Occasional query from a user will require an
"appreciable" amount of computation by the query processor.
This will delay the dispatcher and cause appreciable delays
for the waiting users.

SOLUTION (???):

    To handle these delays, use the system calls "signal" and
"ualarm".  "Signal" will interrupt the kernel in the middle
of its processing, and cause the "alarm_handler" to execute.
The alarm handler will do some minor processing, and then a
"longjmp" back to the dispatcher.  The dispatcher will then go
on to the next task.  When the dispatcher comes back to the
interrupted task, it will "longjmp" to the end (IS THIS CORRECT??)
of the alarm_handler which will do a "return (0)", and cause the
dispatcher to pick up from where it left off when the task
was interrupted.

    Assume 6 tasks where tasks 2, 5, and 6 pass queries causing
the kernel to be slow and to be interrupted.  The flow of the
dispatcher  should be:

    (top of dispatcher loop)

	task 1 -- ok

	task 2 ** slow, interrupt ==> to alarm_handler

	task 3 -- ok

	task 4 -- ok

	task 5 ** slow, interrupt ==> to alarm_handler

	task 6 ** slow, interrupt ==> to alarm_handler

 
   (back to top of dispatcher loop)

	task 1 -- ok

	task 2 ** was interrupted, so longjmp to alarm handler
		  which does a return (0)

	task 3 -- ok

	task 4 -- ok

	task 5 ** was interrupted, so longjmp to alarm handler
		  which does a return (0)

	task 6 ** was interrupted, so longjmp to alarm handler
		  which does a return (0)

    (etc .......)

PROBLEM:  the system stack after the first loop through
the dispatcher will look like the following:

	(top)
	task 6
	task 5
	task 2

When the stack gets popped in alarm_handler (via the "return (0)" ),
task 6 will get popped first.  But since task 2 got interrupted
first, I want task 2 to get popped first.

How do I manipulate the system stack to have tasks popped
in the "correct" order ???

Are there any holes/bugs/etc. with the above architecture ???

    Thanks in advance for any help, comments, criticisms, etc.


David Dymm			Software Engineer

USMAIL: Bell Atlantic Knowledge Systems,
        145 Fayette Street, Morgantown, WV 26505
PHONE:	304 291-9898 (8:30-4:30 EST)
USENET:  {allegra,bellcore, cadre,idis,psuvax1}!pitt!wvucsb!dymm
INTERNET: dymm@b.cs.wvu.wvnet.edu

chris@mimsy.UUCP (Chris Torek) (03/12/89)

In article <321@h.cs.wvu.wvnet.edu> dymm@b.cs.wvu.wvnet.edu (David Dymm)
writes:
>...  When the dispatcher comes back to the interrupted task, it will
>"longjmp" to the end (IS THIS CORRECT??)

If you mean `using the function longjmp() found in the C library',
the answer is `no'.  If you try this under 4.2BSD or 4.3BSD (by
which I mean `4.2BSD or 4.3BSD', not `SunOS', nor any other system
*derived from* 4.2BSD, although it *may* still happen there),
you will get a `longjmp botch' and a core dump.

>of the alarm_handler which will do a "return (0)", and cause the
>dispatcher to pick up from where it left off when the task
>was interrupted.

It is possible (although difficult and nonportable) to do what you have
described (a variant of coroutines), but you cannot use longjmp(), as
it is restricted to jumping `upward' in the stack (assuming the stack
grows downward).  Coroutines jump upward half the time and downward half
the time.  (Well, close enough. :-) )

In addition, it is necessary to reserve sufficient stack space to each
task so that no one task will write over another.  How much space is
required depends upon the tasks.  Most existing 4BSD and SysV
implementations will not help you detect collisions.  Under operating
systems that let you protect individual pages in different ways, you
can make an inaccessible `red zone' below each task stack.  SunOS 4.x
should be able to do this.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris