[comp.lang.ada] Interactive I/O in Ada

wtwolfe@hubcap.clemson.edu (Bill Wolfe) (01/19/90)

  In the current issue of ACM SIGAda Ada Letters, Doug Bryan provides
  a simple answer to a commonly asked question: How does one do keyboard
  input in Ada while having other tasks do some work in the background
  in between keystrokes?  Since Text_IO generally is not implemented so
  as to permit this to be done trivially, it is necessary to isolate the
  task which is handling the keyboard; the keyboard-handling task repeatedly 
  calls Text_IO.Get to obtain a character and deposits it into a virtual 
  keyboard.  The tasks which are to run in the background can then make 
  their entry calls to the virtual keyboard, such that a rendezvous will 
  only occur if a character is waiting to be consumed.

  Sample code (Bryan's solution, with improved documentation) follows:


    task Keyboard is    -- Keyboard abstraction, for use by other tasks 
       entry Read  (Next_Character : in  Character); -- Other tasks call... 
       entry Write (Next_Character : out Character); -- Only handler calls... 
    end Keyboard;


    task Keyboard_Handler;

    with Text_IO;

    task body Keyboard_Handler is 
       Character_Buffer : Character;
    begin
       loop
          Text_IO.Get (Character_Buffer);
          Keyboard.Write (Character_Buffer);
       end loop;
    end Keyboard_Handler;
 

    with Generic_Queue;   -- You'll need to write this generic package, to
                          --  provide type Queue with operations Enqueue, 
                          --  Dequeue, and Empty.

    task body Keyboard is
       package Character_Queue_Handler is new Generic_Queue (Character);
       use Character_Queue_Handler;
       Character_Queue : Character_Queue_Handler.Queue;
    begin
       loop
          select
             accept Write (Next_Character : in Character) do
                Enqueue (Character_Queue, Next_Character); 
             end Write;
          or when not Empty (Character_Queue) =>
             accept Read (Next_Character : out Character) do
                Dequeue (Character_Queue, Next_Character);
             end Read;
          or 
             terminate;
          end select;
       end loop;
    end Keyboard;
 

    -- To use this keyboard abstraction, write code along these lines:
    --    
    -- loop    
    --    select
    --       Keyboard.Read (Keystroke);   -- Keystroke is of type Character
    --       -- code to process a keystroke
    --    else
    --       -- code to do other work "in the background"
    --    end select;
    -- end loop;
    --
    -- On each pass through the loop, if a character is available for
    --   immediate consumption, the code to process a keystroke will be 
    --   executed.  If a character is not immediately available, then the
    --   code to do other work "in the background" will be executed.  The
    --   code to process a keystroke will normally contain an exit statement
    --   whereby the loop is exited once continued monitoring of the keyboard
    --   is no longer desired (e.g., the user indicates a wish to exit this
    --   mode of interaction).  The code to do other work in the background
    --   will normally be set up to do small increments of work in order to 
    --   maintain a reasonable level of user responsiveness.


   Bill Wolfe, wtwolfe@hubcap.clemson.edu

harold@harvax.UUCP (Harold Rabbie) (01/24/90)

Bill Wolfe writes:

>> In the current issue of ACM SIGAda Ada Letters, Doug Bryan provides
>> a simple answer to a commonly asked question: How does one do keyboard
>> input in Ada while having other tasks do some work in the background
>> in between keystrokes?  Since Text_IO generally is 
>> not implemented so as to permit this to be done trivially
   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   
My question is:  WHY NOT?  The reason TEXT_IO isn't pre-emptible on
most systems is that the scheduler in the underlying OS isn't aware of the
Ada tasking scheduler.  It blocks on the call to read() or whatever, never
allowing the Ada scheduler to regain control.  This is just a BAD 
IMPLEMENTATION.  There's no reason why TEXT_IO shouldn't check before
issuing a potentially blocking system call, and then use an asynchronous
type of request.

Better yet, on embedded systems, you can use an operating system that only
has a single level of scheduling.  If an Ada task makes a blocking call, like
TEXT_IO, then the scheduler can find another Ada task to run.  Moral of the
story: if real-time I/O is important to you, then use a real-time Ada OS.
Accept no substitute.

--------------------------+--------------------------------------------
Harold Rabbie, Ready Systems   "when REAL_TIME => accept READY_SYSTEMS;"
UUNET: {sun!pyramid,hplabs}!harvax!harold ARPA: rabbieh@ajpo.sei.cmu.edu
--------------------------+--------------------------------------------

falis@ajpo.sei.cmu.edu (Edward Falis) (01/25/90)

Without getting too commercial here, your best bet on this issues is to
check with the vendor. Several vendors do provide this facility: a task
about to block on an I/O operation relinquished the processor so another
task caN be scheduled.  This is actually fairly trivial to implement
when an Ada task directly issues the I/O operation request. Where it
gets more interesting is when an Ada task calls interfaced code
(EG third party software) which issues an I/O call which will block.

ps most Ada systems intended for use on bare targets include an
"Ada OS" 	- Ed Falis, Alsys Inc.