From: gary@intrepid.com (Gary Funck)
Subject: Re: Ada passive tasks (was: Ada delay)
Organization: Intrepid Technology, Inc.
Date: Sun, 27 Sep 1992 18:51:19 GMT
Keywords: ada, delay, realtime

In article <53620@dime.cs.umass.edu> shri@legato.cs.umass.edu.CS.UMASS.EDU (H.Shrikumar{shri@ncst.in}) writes:
>In article <1992Sep19.175645.10076@intrepid.com> 
>  gary@intrepid.com (Gary Funck) writes:
>>For example, Verdix has something called "passive interrupt tasks" that give
>>you the syntax of tasks, and most of the efficiency of interrupt
>>service routines.  
>
>Could you post a small description of what this looks like, please ?
>Sounds interesting (and similar to something I have).
>
>
>-- shrikumar ( shri@legato.cs.umass.edu, shri@iucaa.ernet.in )

Below is an excerpt from the Verdix documentation:

Passive tasks are a compiler/runtime optimization that reduces the overhead
associated with an Ada task. The use of passive tasks usually results
in improved application performance.  Passive tasks are simply subroutines,
an an entry call to a passive task is no different than a simple
subroutine call.  A passive task is defined to only exist while in
rendezvous with an active (full-fledged) Ada task.  A passive task
does not have its own thread of control or its own stack storage
space.  While a passive task is in rendezvous with an active task
the passive task uses the stack and thread of control of the calling
active task.

Passive tasks are little more than critical regions guarding a sequence
of code; the sequence of code is the passive task accept body. 

There are two types of passive tasks: semaphore and interrupt:
    - a semaphore passive task uses semaphores to guard the critical region
    - an interrupt passive task uses the processor's interrupt mask
      to guard the critical region.

A passive interrupt task is declared using a pragram:
    pragma PASSIVE(INTERRUPT, DISABLE_STATUS);

where DISABLE_STATUS is an implementation-defined value giving the
processor mask used to disable interrupts.

Below is an example, illustrating the use of a passive interrupt
task that buffers incoming characters.  A real-world implementation
would need to deal with input data errors, and to process data overruns
differently.

with system;
package intr_pkg is

    data_overrun: exception;

    interrupt_number: constant := 16#40#; -- implementation defined
    disable_status: constant integer := 16#ffff#; -- implementation defined

    task io_task is
        entry char_ready_intr;
        entry next_char(data: out character);
        for char_ready_intr use at system.memory_address(interrupt_number);
        pragma passive(interrupt, disable_status);
    end io_task;

end;
package body intr_pkg is

    --
    -- Here we assume that io_port is a memory mapped I/O port
    -- at an implementation defined address.
    --
    io_port: character;
    for io_port use at system.memory_address(16#a0000010#);

    task body io_task is
	qsize: constant integer := 16;
	f: integer := 0;
	r: integer := 0;
	char_buf: array (0..qsize-1) of character;
    begin
        loop
            select
		accept char_ready_intr do
		    char_buf(r) := io_port;
		    r := (r + 1) mod qsize;
		    if r = f then
			raise data_overrun;
		    end if;
		end;
            or when f /= r =>
                accept next_char(data: out character) do
		    data := char_buf(f);
		    f := (f + 1) mod qsize;
                end;
            end select;
        end loop;
    end io_task;
end;

In this example, "char_ready_intr" is entered directly from a complier
generated interrupt service routine, and "next_char" is entered at
the level of a normal active task.  However, both critical regions
(the accept bodies) are protected using the interrupt mask.

-- 
| Gary Funck  		    gary@intrepid.com  [uunet!uupsi!intrepid!gary]
| Intrepid Technology Inc., Mountain View CA (415) 964-8135
--