view gcc/testsuite/ada/acats/tests/c9/c954022.a @ 111:04ced10e8804

gcc 7
author kono
date Fri, 27 Oct 2017 22:46:09 +0900
parents
children
line wrap: on
line source

-- C954022.A
--
--                             Grant of Unlimited Rights
--
--     Under contracts F33600-87-D-0337, F33600-84-D-0280, MDA903-79-C-0687,
--     F08630-91-C-0015, and DCA100-97-D-0025, the U.S. Government obtained 
--     unlimited rights in the software and documentation contained herein.
--     Unlimited rights are defined in DFAR 252.227-7013(a)(19).  By making 
--     this public release, the Government intends to confer upon all 
--     recipients unlimited rights  equal to those held by the Government.  
--     These rights include rights to use, duplicate, release or disclose the 
--     released technical data and computer software in whole or in part, in 
--     any manner and for any purpose whatsoever, and to have or permit others 
--     to do so.
--
--                                    DISCLAIMER
--
--     ALL MATERIALS OR INFORMATION HEREIN RELEASED, MADE AVAILABLE OR
--     DISCLOSED ARE AS IS.  THE GOVERNMENT MAKES NO EXPRESS OR IMPLIED 
--     WARRANTY AS TO ANY MATTER WHATSOEVER, INCLUDING THE CONDITIONS OF THE
--     SOFTWARE, DOCUMENTATION OR OTHER INFORMATION RELEASED, MADE AVAILABLE 
--     OR DISCLOSED, OR THE OWNERSHIP, MERCHANTABILITY, OR FITNESS FOR A
--     PARTICULAR PURPOSE OF SAID MATERIAL.
--*
--
-- OBJECTIVE:
--      In an entry body requeue the call to the same entry.  Check that the
--      items go to the right queue and that they are placed back on the end 
--      of the queue
--
-- TEST DESCRIPTION:
--      Simulate part of a message handling application where the messages are
--      composed of several segments.  The sequence of the segments within the
--      message is specified by Seg_Sequence_No.   The segments are handled by
--      different tasks and finally forwarded to an output driver.  The
--      segments can arrive in any order but must be assembled into the proper
--      sequence for final output.  There is a Sequencer task interposed
--      before the Driver.  This takes the segments of the message off the
--      Ordering_Queue and those that are in the right order it sends on to
--      the driver; those that are out of order it places back on the end of
--      the queue.
--
--      The test just simulates the arrival of the segments at the Sequencer.
--      The task generating the segments handshakes with the Sequencer during
--      the  "Await Arrival" phase  ensuring that the three segments of a
--      message arrive in REVERSE order (the End-of-Message segment arrives
--      first and the Header last).  In the first cycle the sequencer pulls
--      segments off the queue and puts them back on the end till it
--      encounters the header.  It checks the sequence of the ones it pulls
--      off in case the segments are being put back on in the wrong part of
--      the queue.  Having cycled once through it no longer verifies the
--      sequence - it just executes the "application" code for the correct
--      order for dispatch to the driver.
-- 
--      In this simple example no attempt is made to address segments of
--      another message arriving or any other error conditions (such as
--      missing segments, timing etc.)
-- 
--
-- CHANGE HISTORY:
--      06 Dec 94   SAIC    ACVC 2.0
--      07 Nov 95   SAIC    ACVC 2.0.1
--
--!

with Report;
with ImpDef;

procedure C954022 is

   -- These global Booleans are set when failure conditions inside Protected
   -- objects are encountered.  Report.Failed cannot be called within
   -- the object or a Bounded Error would occur
   --
   TC_Failed_1 : Boolean := false;
   TC_Failed_2 : Boolean := false;
   TC_Failed_3 : Boolean := false;

begin


   Report.Test ("C954022", "Check Requeue to the same Protected Entry");
   
   declare  -- encapsulate the test

      type Segment_Sequence is range 1..8;
      Header : constant Segment_Sequence := Segment_Sequence'first;

      type Message_Segment is record
         ID              : integer;            -- Message ID
         Seg_Sequence_No : Segment_Sequence;   -- Within the message
         Segs_In_Message : integer;            -- Total segs this message
         EOM             : Boolean := false;   -- true for final msg segment
         Alpha           : string (1..128);
      end record;
      type acc_Message_Segment is access Message_Segment;

      task TC_Simulate_Arrival;
   
      task type Carrier_Task is
         entry Input ( Segment : acc_Message_Segment );
      end Carrier_Task;
      type acc_Carrier_Task is access Carrier_Task;
   
      protected Sequencer is
         function  TC_Arrivals return integer;
         entry Input          ( Segment : acc_Message_Segment );
         entry Ordering_Queue ( Segment : acc_Message_Segment );
      private
         Number_of_Segments_Arrived  : integer := 0;
         Number_of_Segments_Expected : integer := 0;
         Next_Needed : Segment_Sequence := Header;
         All_Segments_Arrived : Boolean := false;
         Seen_EOM             : Boolean := false;

         TC_First_Cycle       : Boolean := true;
         TC_Expected_Sequence : Segment_Sequence := Header+2;

      end Sequencer;
   

      task Output_Driver is
         entry Input ( Segment : acc_Message_Segment );
      end Output_Driver;
   

      -- Simulate the arrival of three message segments in REVERSE order
      --
      task body TC_Simulate_Arrival is
         begin
            for i in 1..3 loop
               declare
                  -- Create a task for the next message segment
                  Next_Segment_Task : acc_Carrier_Task := new Carrier_Task;
                  -- Create a record for the next segment
                  Next_Segment : acc_Message_Segment := new Message_Segment;
               begin
                  if i = 1 then 
                     -- Build the EOM segment as the first to "send"
                     Next_Segment.Seg_Sequence_No := Header + 2;
                     Next_Segment.Segs_In_Message := 3;
                     Next_Segment.EOM := true;
                  elsif i = 2 then
                     -- Wait for the first segment to arrive at the Sequencer
                     -- before "sending" the second
                     while Sequencer.TC_Arrivals < 1 loop
                        delay ImpDef.Minimum_Task_Switch;
                     end loop;
                     -- Build the segment
                     Next_Segment.Seg_Sequence_No := Header +1;
                  else
                     -- Wait for the second segment to arrive at the Sequencer
                     -- before "sending" the third
                     while Sequencer.TC_Arrivals < 2 loop
                        delay ImpDef.Minimum_Task_Switch;
                     end loop;                  
                     -- Build the segment. The last segment (in order) to
                     -- arrive will be the "header" segment
                     Next_Segment.Seg_Sequence_No := Header;
                  end if;
                  -- pass the record to its carrier
                  Next_Segment_Task.Input ( Next_Segment );
               end;
            end loop;
 

      exception
         when others => 
              Report.Failed ("Unexpected Exception in TC_Simulate_Arrival");
      end TC_Simulate_Arrival;
   

      -- One of these is generated for each message segment and the flow 
      -- of the segments through the system is controlled by the calls the
      -- task makes and the requeues of those calls
      --
      task body Carrier_Task is
         This_Segment : acc_Message_Segment := new Message_Segment;
      begin
         accept Input ( Segment : acc_Message_Segment ) do
            This_Segment.all := Segment.all;
         end Input;
         null; --:: stub.  Pass the segment around the application as needed

         -- Now output the segment to the Output_Driver.  First we have to 
         -- go through the Sequencer.  
         Sequencer.Input ( This_Segment );
      exception
         when others => 
              Report.Failed ("Unexpected Exception in Carrier_Task");
      end Carrier_Task;
   
      -- Store segments on the Ordering_Queue then deliver them in the correct
      -- sequence to the Output_Driver.
      --
      protected body Sequencer is

         function  TC_Arrivals return integer is
         begin
            return Number_of_Segments_Arrived;
         end TC_Arrivals;

         
         -- Segments arriving at the Input queue are counted and checked
         -- against the total number of segments for the message.  They
         -- are requeued onto the ordering queue where they are held until
         -- all the segments have arrived.
         entry Input ( Segment : acc_Message_Segment ) when true is
         begin
            -- check for EOM, if so get the number of segments in the message
            -- Note: in this portion of code no attempt is made to address
            -- reset for new message , end conditions, missing segments, 
            -- segments of a different message etc.
            Number_of_Segments_Arrived := Number_of_Segments_Arrived + 1;
            if Segment.EOM then
               Number_of_Segments_Expected := Segment.Segs_In_Message;
               Seen_EOM := true;
            end if;

            if Seen_EOM then
               if Number_of_Segments_Arrived = Number_of_Segments_Expected then
                  -- This is the last segment for this message
                  All_Segments_Arrived := true;    -- clear the barrier
               end if;
            end if;

            requeue Ordering_Queue;

            -- At this exit point the entry queue barriers are evaluated

         end Input;


         entry Ordering_Queue ( Segment : acc_Message_Segment )
                                                  when All_Segments_Arrived is
            begin

            --=====================================================
            -- This part is all Test_Control code

            if TC_First_Cycle then 
               -- Check the order of the original three
               if Segment.Seg_Sequence_No /= TC_Expected_Sequence then
                  -- The segments are not being pulled off in the 
                  -- expected sequence.  This could occur if the 
                  -- requeue is not putting them back on the end.
                  TC_Failed_3 := true;
               end if; -- sequence check
               -- Decrement the expected sequence
               if TC_Expected_Sequence /= Header then
                  TC_Expected_Sequence := TC_Expected_Sequence - 1;
               else 
                  TC_First_Cycle := false; -- This is the Header - the
                                           -- first two segments are
                                           -- back on the queue
               end if; -- decrementing
            end if; -- first cycle 
            --=====================================================

            -- And this is the Application code
            if Segment.Seg_Sequence_No = Next_Needed then
               if Segment.EOM then
                  Next_Needed := Header;  -- reset for next message
                  -- :: other resets not shown
               else
                  Next_Needed := Next_Needed + 1;
               end if;
               requeue Output_Driver.Input  with abort;
               -- set to Report Failed - Requeue did not complete entry body
               TC_Failed_1 := true;
            else
               -- Not the next needed - put it back on the queue
               --    NOTE: here we are requeueing to the same entry
               requeue Sequencer.Ordering_Queue;
               -- set to Report Failed - Requeue did not complete entry body
               TC_Failed_2 := true;
            end if;
         end Ordering_Queue;
      end Sequencer;
   

      task body Output_Driver is
         This_Segment : acc_Message_Segment := new Message_Segment;

         TC_Expected_Sequence : Segment_Sequence := Segment_Sequence'first;
         TC_Segment_Total : integer := 0;
         TC_Expected_Total : integer := 3;
      begin
         loop
            -- Note: normally we would expect this Accept to be in a select 
            -- with terminate.  For the test we exit the loop on completion
            -- to give better control
            accept Input ( Segment : acc_Message_Segment ) do 
               This_Segment.all := Segment.all;
            end Input;
   
            null;  --::: stub - output the next segment of the message

            -- The following is all test control code
            --
            if This_Segment.Seg_Sequence_No /= TC_Expected_Sequence then
               Report.Failed ("Output_Driver: Segment out of sequence");
            end if;
            TC_Expected_Sequence := TC_Expected_Sequence + 1;

            -- Now count the number of segments
            TC_Segment_Total := TC_Segment_Total + 1;

            -- Check the number and exit loop when complete
            -- There must be exactly TC_Expected_Total in number and
            --    the last one must be EOM
            --    (test will hang if < TC_Expected_Total arrive
            --    without EOM)
            if This_Segment.EOM then
               -- This is the last segment.
               if TC_Segment_Total /= TC_Expected_Total then
                  Report.Failed ("EOM and wrong number of segments");
               end if;
               exit;   -- the loop and terminate the task
            elsif TC_Segment_Total = TC_Expected_Total then
               Report.Failed ("No EOM found");
               exit;
            end if;
         end loop;
      exception
         when others => 
              Report.Failed ("Unexpected Exception in Output_Driver");
      end Output_Driver;


   begin  

      null;

   end; -- encapsulation

   if TC_Failed_1 then
      Report.Failed ("Requeue did not complete entry body - 1");
   end if;

   if TC_Failed_2 then
      Report.Failed ("Requeue did not complete entry body - 2");
   end if;

   if TC_Failed_3 then
      Report.Failed ("Sequencer: Segment out of sequence");
   end if;

   Report.Result;
   
end C954022;