1-- C954019.A 2-- 3-- Grant of Unlimited Rights 4-- 5-- Under contracts F33600-87-D-0337, F33600-84-D-0280, MDA903-79-C-0687, 6-- F08630-91-C-0015, and DCA100-97-D-0025, the U.S. Government obtained 7-- unlimited rights in the software and documentation contained herein. 8-- Unlimited rights are defined in DFAR 252.227-7013(a)(19). By making 9-- this public release, the Government intends to confer upon all 10-- recipients unlimited rights equal to those held by the Government. 11-- These rights include rights to use, duplicate, release or disclose the 12-- released technical data and computer software in whole or in part, in 13-- any manner and for any purpose whatsoever, and to have or permit others 14-- to do so. 15-- 16-- DISCLAIMER 17-- 18-- ALL MATERIALS OR INFORMATION HEREIN RELEASED, MADE AVAILABLE OR 19-- DISCLOSED ARE AS IS. THE GOVERNMENT MAKES NO EXPRESS OR IMPLIED 20-- WARRANTY AS TO ANY MATTER WHATSOEVER, INCLUDING THE CONDITIONS OF THE 21-- SOFTWARE, DOCUMENTATION OR OTHER INFORMATION RELEASED, MADE AVAILABLE 22-- OR DISCLOSED, OR THE OWNERSHIP, MERCHANTABILITY, OR FITNESS FOR A 23-- PARTICULAR PURPOSE OF SAID MATERIAL. 24--* 25-- 26-- OBJECTIVE: 27-- Check that when a requeue is to the same entry the items go to the 28-- right queue and that they are placed back on the end of the queue. 29-- 30-- TEST DESCRIPTION: 31-- Simulate part of a message handling application where the messages are 32-- composed of several segments. The sequence of the segments within the 33-- message is specified by Seg_Sequence_No. The segments are handled by 34-- different tasks and finally forwarded to an output driver. The 35-- segments can arrive in any order but must be assembled into the proper 36-- sequence for final output. There is a Sequencer task interposed 37-- before the Driver. This takes the segments of the message off the 38-- Ordering_Queue and those that are in the right order it sends on to 39-- the driver; those that are out of order it places back on the end of 40-- the queue. 41-- 42-- The test just simulates the arrival of the segments at the Sequencer. 43-- The task generating the segments handshakes with the Sequencer during 44-- the "Await Arrival" phase ensuring that the three segments of a 45-- message arrive in REVERSE order (the End-of-Message segment arrives 46-- first and the Header last). In the first cycle the sequencer pulls 47-- segments off the queue and puts them back on the end till it 48-- encounters the header. It checks the sequence of the ones it pulls 49-- off in case the segments are being put back on in the wrong part of 50-- the queue. Having cycled once through it no longer verifies the 51-- sequence - it just executes the "application" code for the correct 52-- order for dispatch to the driver. 53-- 54-- In this simple example no attempt is made to address segments of 55-- another message arriving or any other error conditions (such as 56-- missing segments, timing etc.) 57-- 58-- 59-- CHANGE HISTORY: 60-- 06 Dec 94 SAIC ACVC 2.0 61-- 19 Dec 94 SAIC Remove parameter from requeue statement 62-- 63--! 64 65with Report; 66with ImpDef; 67 68procedure C954019 is 69begin 70 71 72 Report.Test ("C954019", "Check Requeue to the same Accept"); 73 74 declare -- encapsulate the test 75 76 type Segment_Sequence is range 1..8; 77 Header : constant Segment_Sequence := Segment_Sequence'first; 78 79 type Message_Segment is record 80 ID : integer; -- Message ID 81 Seg_Sequence_No : Segment_Sequence; -- Within the message 82 Alpha : string (1..128); 83 EOM : Boolean := false; -- true for final msg segment 84 end record; 85 type acc_Message_Segment is access Message_Segment; 86 87 task TC_Simulate_Arrival; 88 89 task type Carrier_Task is 90 entry Input ( Segment : acc_Message_Segment ); 91 end Carrier_Task; 92 type acc_Carrier_Task is access Carrier_Task; 93 94 task Sequencer is 95 entry Ordering_Queue ( Segment : acc_Message_Segment ); 96 entry TC_Handshake_1; 97 entry TC_Handshake_2; 98 end Sequencer; 99 100 task Output_Driver is 101 entry Input ( Segment : acc_Message_Segment ); 102 end Output_Driver; 103 104 105 -- Simulate the arrival of three message segments in REVERSE order 106 -- 107 task body TC_Simulate_Arrival is 108 begin 109 110 for i in 1..3 loop 111 declare 112 -- Create a task for the next message segment 113 Next_Segment_Task : acc_Carrier_Task := new Carrier_Task; 114 -- Create a record for the next segment 115 Next_Segment : acc_Message_Segment := new Message_Segment; 116 begin 117 if i = 1 then 118 -- Build the EOM segment as the first to "send" 119 Next_Segment.Seg_Sequence_No := Header + 2; 120 Next_Segment.EOM := true; 121 elsif i = 2 then 122 -- Wait for the first segment to arrive at the Sequencer 123 -- before "sending" the second 124 Sequencer.TC_Handshake_1; 125 -- Build the segment 126 Next_Segment.Seg_Sequence_No := Header + 1; 127 else 128 -- Wait for the second segment to arrive at the Sequencer 129 -- before "sending" the third 130 Sequencer.TC_Handshake_2; 131 -- Build the segment. The last segment in order to 132 -- arrive will be the "header" segment 133 Next_Segment.Seg_Sequence_No := Header; 134 end if; 135 -- pass the record to its carrier 136 Next_Segment_Task.Input ( Next_Segment ); 137 end; 138 end loop; 139 exception 140 when others => 141 Report.Failed ("Unexpected Exception in TC_Simulate_Arrival"); 142 end TC_Simulate_Arrival; 143 144 145 -- One of these is generated for each message segment and the flow 146 -- of the segments through the system is controlled by the calls the 147 -- task makes and the requeues of those calls 148 -- 149 task body Carrier_Task is 150 This_Segment : acc_Message_Segment := new Message_Segment; 151 begin 152 accept Input ( Segment : acc_Message_Segment ) do 153 This_Segment.all := Segment.all; 154 end Input; 155 null; --:: stub. Pass the segment around the application as needed 156 157 -- Now output the segment to the Output_Driver. First we have to 158 -- go through the Sequencer. 159 Sequencer.Ordering_Queue ( This_Segment ); 160 exception 161 when others => 162 Report.Failed ("Unexpected Exception in Carrier_Task"); 163 end Carrier_Task; 164 165 166 -- Pull segments off the Ordering_Queue and deliver them in the correct 167 -- sequence to the Output_Driver. 168 -- 169 task body Sequencer is 170 Next_Needed : Segment_Sequence := Header; 171 172 TC_Await_Arrival : Boolean := true; 173 TC_First_Cycle : Boolean := true; 174 TC_Expected_Sequence : Segment_Sequence := Header+2; 175 begin 176 loop 177 select 178 accept Ordering_Queue ( Segment : acc_Message_Segment ) do 179 180 --===================================================== 181 -- This part is all Test_Control code 182 183 if TC_Await_Arrival then 184 -- We have to arrange that the segments arrive on the 185 -- queue in the right order, so we handshake with the 186 -- TC_Simulate_Arrival task to "send" only one at 187 -- a time 188 accept TC_Handshake_1; -- the first has arrived 189 -- and has been pulled off the 190 -- queue 191 192 -- Wait for the second to arrive (the first has already 193 -- been pulled off the queue 194 while Ordering_Queue'count < 1 loop 195 delay ImpDef.Minimum_Task_Switch; 196 end loop; 197 -- 198 accept TC_Handshake_2; -- the second has arrived 199 200 -- Wait for the third to arrive 201 while Ordering_Queue'count < 2 loop 202 delay ImpDef.Minimum_Task_Switch; 203 end loop; 204 205 -- Subsequent passes through the loop, bypass this code 206 TC_Await_Arrival := false; 207 208 209 end if; -- await arrival 210 211 if TC_First_Cycle then 212 -- Check the order of the original three 213 if Segment.Seg_Sequence_No /= TC_Expected_Sequence then 214 -- The segments are not being pulled off in the 215 -- expected sequence. This could occur if the 216 -- requeue is not putting them back on the end. 217 Report.Failed ("Sequencer: Segment out of sequence"); 218 end if; -- sequence check 219 -- Decrement the expected sequence 220 if TC_Expected_Sequence /= Header then 221 TC_Expected_Sequence := TC_Expected_Sequence - 1; 222 else 223 TC_First_Cycle := false; -- This is the Header - the 224 -- first two segments are 225 -- back on the queue 226 227 end if; -- decrementing 228 end if; -- first pass 229 --===================================================== 230 231 -- And this is the Application code 232 if Segment.Seg_Sequence_No = Next_Needed then 233 if Segment.EOM then 234 Next_Needed := Header; -- reset for next message 235 else 236 Next_Needed := Next_Needed + 1; 237 end if; 238 requeue Output_Driver.Input with abort; 239 Report.Failed ("Requeue did not complete accept body"); 240 else 241 -- Not the next needed - put it back on the queue 242 requeue Sequencer.Ordering_Queue; 243 Report.Failed ("Requeue did not complete accept body"); 244 end if; 245 end Ordering_Queue; 246 or 247 terminate; 248 end select; 249 end loop; 250 exception 251 when others => 252 Report.Failed ("Unexpected Exception in Sequencer"); 253 end Sequencer; 254 255 256 task body Output_Driver is 257 This_Segment : acc_Message_Segment := new Message_Segment; 258 259 TC_Expected_Sequence : Segment_Sequence := Segment_Sequence'first; 260 TC_Segment_Total : integer := 0; 261 TC_Expected_Total : integer := 3; 262 begin 263 loop 264 -- Note: normally we would expect this Accept to be in a select 265 -- with terminate. For the test we exit the loop on completion 266 -- to give better control 267 accept Input ( Segment : acc_Message_Segment ) do 268 This_Segment.all := Segment.all; 269 end Input; 270 271 null; --::: stub - output the next segment of the message 272 273 -- The following is all test control code 274 -- 275 if This_Segment.Seg_Sequence_No /= TC_Expected_Sequence then 276 Report.Failed ("Output_Driver: Segment out of sequence"); 277 end if; 278 TC_Expected_Sequence := TC_Expected_Sequence + 1; 279 280 -- Now count the number of segments 281 TC_Segment_Total := TC_Segment_Total + 1; 282 283 -- Check the number and exit loop when complete 284 -- There must be exactly TC_Expected_Total in number and 285 -- the last one must be EOM 286 -- (test will hang if < TC_Expected_Total arrive 287 -- without EOM) 288 if This_Segment.EOM then 289 -- This is the last segment. 290 if TC_Segment_Total /= TC_Expected_Total then 291 Report.Failed ("EOM and wrong number of segments"); 292 end if; 293 exit; -- the loop and terminate the task 294 elsif TC_Segment_Total = TC_Expected_Total then 295 Report.Failed ("No EOM found"); 296 exit; 297 end if; 298 end loop; 299 exception 300 when others => 301 Report.Failed ("Unexpected Exception in Output_Driver"); 302 end Output_Driver; 303 304 305 306 begin 307 308 null; 309 310 end; -- encapsulation 311 312 Report.Result; 313 314end C954019; 315