-- C954019.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: -- Check that when a requeue is to the same entry 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 -- 19 Dec 94 SAIC Remove parameter from requeue statement -- --! with Report; with ImpDef; procedure C954019 is begin Report.Test ("C954019", "Check Requeue to the same Accept"); 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 Alpha : string (1..128); EOM : Boolean := false; -- true for final msg segment 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; task Sequencer is entry Ordering_Queue ( Segment : acc_Message_Segment ); entry TC_Handshake_1; entry TC_Handshake_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.EOM := true; elsif i = 2 then -- Wait for the first segment to arrive at the Sequencer -- before "sending" the second Sequencer.TC_Handshake_1; -- 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 Sequencer.TC_Handshake_2; -- 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.Ordering_Queue ( This_Segment ); exception when others => Report.Failed ("Unexpected Exception in Carrier_Task"); end Carrier_Task; -- Pull segments off the Ordering_Queue and deliver them in the correct -- sequence to the Output_Driver. -- task body Sequencer is Next_Needed : Segment_Sequence := Header; TC_Await_Arrival : Boolean := true; TC_First_Cycle : Boolean := true; TC_Expected_Sequence : Segment_Sequence := Header+2; begin loop select accept Ordering_Queue ( Segment : acc_Message_Segment ) do --===================================================== -- This part is all Test_Control code if TC_Await_Arrival then -- We have to arrange that the segments arrive on the -- queue in the right order, so we handshake with the -- TC_Simulate_Arrival task to "send" only one at -- a time accept TC_Handshake_1; -- the first has arrived -- and has been pulled off the -- queue -- Wait for the second to arrive (the first has already -- been pulled off the queue while Ordering_Queue'count < 1 loop delay ImpDef.Minimum_Task_Switch; end loop; -- accept TC_Handshake_2; -- the second has arrived -- Wait for the third to arrive while Ordering_Queue'count < 2 loop delay ImpDef.Minimum_Task_Switch; end loop; -- Subsequent passes through the loop, bypass this code TC_Await_Arrival := false; end if; -- await arrival 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. Report.Failed ("Sequencer: Segment out of sequence"); 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 pass --===================================================== -- 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 else Next_Needed := Next_Needed + 1; end if; requeue Output_Driver.Input with abort; Report.Failed ("Requeue did not complete accept body"); else -- Not the next needed - put it back on the queue requeue Sequencer.Ordering_Queue; Report.Failed ("Requeue did not complete accept body"); end if; end Ordering_Queue; or terminate; end select; end loop; exception when others => Report.Failed ("Unexpected Exception in Sequencer"); 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 Report.Result; end C954019;