blob: 5ebff8dcb0f2e0427fffcdd2904b9bc5a02978e9 [file] [log] [blame]
-- 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;