[comp.sys.amiga.tech] prioritized TASK interrupts

dillon@CORY.BERKELEY.EDU (Matt Dillon) (04/14/88)

	I am just finishing up a neat little module that will give a task
the ability to have prioritized vectored signals using task exceptions. 
I'll post it to comp.sys.amiga.tech in a day or two.  Essentially, the
entire interface works through two calls:

	oldpri = SetQPri(newpri)
	oldvec = SetQVector(signo, handler, pri)

	I call these Q interrupts to differentiate them from other types
of interrupts.  The Q interrupt priority of the task is set with SetQPri()
and has a range -128 to 127 (-128 is the default).  You may specify
one or more of the task's 32 signal bits to be a Q interrupt at some specific
priority.  

	Then, when that signal comes in, its handler will be run as soon
as the task's Q priority drops BELOW the priority of the handler (immediately
if possible).  The sequence works as follows:

	When the Q priority drops below the highest priority pending Q 
	interrupt, set the Q priority to that of the pending Q interrupt 
	and call the handler, then restore the Q priority to what it was 
	before.  The handler is run in the context of the task, in user mode,
	without turning off anything else in the system.

	Since this scheme is essentially the same as the 68000's hardware
interrupt scheme, you can, for instance, put all your Q interrupts at the same
priority to guarentee they will not interrupt each other.  OR, if you want 
one signal to have priority over another, you simply give it a higher priority
when you SetQVector() it.  You can 'forbid' some Q interrupts by setting the
task's priority higher than one or more Q Vectors with SetQPri().

	For instance, if you want to use DOS calls from both your main loop
and a Q interrupt, you must do something like:
 
	handler()
	{
	    puts("y");
	}

	main() {
	    SetQVector(SIGBREAKB_CTRL_F, handler, 23);
	    while (notdone) {
	        SetQPri(127)
	        puts("x");
	        SetQPri(-128);
	    }
	    SetQVector(SIGBREAKB_CTRL_F, NULL, 0);
	}

	in your main loop to avoid confusing stdio or DOS.  The same goes for
graphics calls and critical system calls.  So far, with no optimization,
a standard Amiga can process 1000 Q interrupts / sec.  This is quite a bit
more overhead than software interrupts and task switches, but has several
advantages:

	(1) By applying 'handlers' to signals, one has a distinctly different
	    way of handling events than the standard "main loop wait" method.

	(2) Many applications want to be able to handle events while doing
	    complex calculations.  For instance, a 'game of life' program
	    may want to handle menu events ("STOP") while calculating a
	    screen without having to continuously check to see if an
	    intuition message has come in.  Instead, a Q interrupt could
	    simply set a flag or modify some count variable that would 
	    cause the calculation to abort ("somebody wants me to stop" 
	    instead of "does somebody want me to stop?").  In this case,
	    there is zero overhead until the user actually selects the
	    menu item.

	    In, say, a terminal program, if you want to 'send' a file and
	    handle the full-duplex echo smoothly, you can create a Q
	    interrupt handler to handle all aspects of the serial receive.
	    (EXEC IO devices are independant of calls to other libraries and
	    to most EXEC calls and can be done asynchronously without having
	    to fool with SetQPri()).

	(3) All of this is done in the context of a single task without 
	    resorting to using multiple tasks (much more of a hassle), almost
	    as if the Q interrupt handler were called as a subroutine of the 
	    main program!

	look for it soon!
	
					-Matt