1-- C954014.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 a requeue is not canceled and that the requeueing 28-- task is unaffected when a calling task is aborted. Check that the 29-- abort is deferred until the entry call is complete. 30-- Specifically, check requeue to an entry in a different task, 31-- requeue where the entry call has parameters, and requeue 32-- without the abort option. 33-- 34-- TEST DESCRIPTION 35-- In the Driver create a task that places a call on the 36-- Distributor. In the Distributor requeue this call on the Credit task. 37-- Abort the calling task when it is known to be in rendezvous with the 38-- Credit task. (We arrange this by using artificial synchronization 39-- points in the Driver and the accept body of the Credit task) Ensure 40-- that the abort is deferred (the task is not terminated) until the 41-- accept body completes. Afterwards, send one extra message through 42-- the Distributor to check that the requeueing task has not been 43-- disrupted. 44-- 45-- This series of tests uses a simulation of a transaction driven 46-- processing system. Line Drivers accept input from an external source 47-- and build them into transaction records. These records are then 48-- encapsulated in message tasks which remain extant for the life of the 49-- transaction in the system. The message tasks put themselves on the 50-- input queue of a Distributor which, from information in the 51-- transaction and/or system load conditions forwards them to other 52-- operating tasks. These in turn might forward the transactions to yet 53-- other tasks for further action. The routing is, in real life, dynamic 54-- and unpredictable at the time of message generation. All rerouting in 55-- this model is done by means of requeues. 56-- 57-- 58-- CHANGE HISTORY: 59-- 06 Dec 94 SAIC ACVC 2.0 60-- 25 Nov 95 SAIC Replaced global variables with protected objects 61-- for ACVC 2.0.1. 62-- 63--! 64 65with Report; 66with ImpDef; 67 68procedure C954014 is 69 70 -- Arbitrary test values 71 Credit_Return : constant := 1; 72 Debit_Return : constant := 2; 73 74 75 protected type Shared_Boolean (Initial_Value : Boolean := False) is 76 procedure Set_True; 77 procedure Set_False; 78 function Value return Boolean; 79 private 80 Current_Value : Boolean := Initial_Value; 81 end Shared_Boolean; 82 83 protected body Shared_Boolean is 84 procedure Set_True is 85 begin 86 Current_Value := True; 87 end Set_True; 88 89 procedure Set_False is 90 begin 91 Current_Value := False; 92 end Set_False; 93 94 function Value return Boolean is 95 begin 96 return Current_Value; 97 end Value; 98 end Shared_Boolean; 99 100 101 TC_Debit_Message_Complete : Shared_Boolean (False); 102 103 -- Synchronization flags for handshaking between the Line_Driver 104 -- and the Accept body in the Credit Task 105 TC_Handshake_A : Shared_Boolean (False); 106 TC_Handshake_B : Shared_Boolean (False); 107 TC_Handshake_C : Shared_Boolean (False); 108 TC_Handshake_D : Shared_Boolean (False); 109 TC_Handshake_E : Shared_Boolean (False); 110 TC_Handshake_F : Shared_Boolean (False); 111 112 113 type Transaction_Code is (Credit, Debit); 114 115 type Transaction_Record; 116 type acc_Transaction_Record is access Transaction_Record; 117 type Transaction_Record is 118 record 119 ID : integer := 0; 120 Code : Transaction_Code := Debit; 121 Account_Number : integer := 0; 122 Stock_Number : integer := 0; 123 Quantity : integer := 0; 124 Return_Value : integer := 0; 125 TC_Message_Count : integer := 0; 126 TC_Thru_Distrib : Boolean; 127 end record; 128 129 130 task type Message_Task is 131 entry Accept_Transaction (In_Transaction : acc_Transaction_Record); 132 end Message_Task; 133 type acc_Message_Task is access Message_Task; 134 135 task Line_Driver is 136 entry start; 137 end Line_Driver; 138 139 task Distributor is 140 entry Input(Transaction : acc_Transaction_Record); 141 end Distributor; 142 143 task Credit_Computation is 144 entry Input(Transaction : acc_Transaction_Record); 145 end Credit_Computation; 146 147 task Debit_Computation is 148 entry Input(Transaction : acc_Transaction_Record); 149 end Debit_Computation; 150 151 152 -- Assemble messages received from an external source 153 -- Creates a message task for each. The message tasks remain extant 154 -- for the life of the messages in the system. 155 -- TC: The Line Driver task would normally be designed to loop 156 -- continuously creating the messages as input is received. Simulate 157 -- this but limit it to two dummy messages for this test and use 158 -- special artificial handshaking checks with the Credit accept body 159 -- to control the test. Allow it to terminate at the end 160 -- 161 task body Line_Driver is 162 Current_ID : integer := 1; 163 TC_First_message_sent: Boolean := false; 164 165 procedure Build_Credit_Record 166 ( Next_Transaction : acc_Transaction_Record ) is 167 Dummy_Account : constant integer := 100; 168 begin 169 Next_Transaction.ID := Current_ID; 170 Next_Transaction.Code := Credit; 171 172 Next_Transaction.Account_Number := Dummy_Account; 173 Current_ID := Current_ID + 1; 174 end Build_Credit_Record; 175 176 177 procedure Build_Debit_Record 178 ( Next_Transaction : acc_Transaction_Record ) is 179 Dummy_Account : constant integer := 200; 180 begin 181 Next_Transaction.ID := Current_ID; 182 Next_Transaction.Code := Debit; 183 184 Next_Transaction.Account_Number := Dummy_Account; 185 Current_ID := Current_ID + 1; 186 end Build_Debit_Record; 187 188 begin 189 190 accept Start; -- Wait for trigger from main 191 192 for i in 1..2 loop -- TC: arbitrarily limit to one credit message 193 -- and one debit, then complete 194 declare 195 -- Create a task for the next message 196 Next_Message_Task : acc_Message_Task := new Message_Task; 197 -- Create a record for it 198 Next_Transaction : acc_Transaction_Record := 199 new Transaction_Record; 200 begin 201 if not TC_First_Message_Sent then 202 -- send out the first message which will be aborted 203 Build_Credit_Record ( Next_Transaction ); 204 Next_Message_Task.Accept_Transaction ( Next_Transaction ); 205 TC_First_Message_Sent := true; 206 207 -- Wait for Credit task to get into the accept body 208 -- The call from the Message Task has been requeued by 209 -- the distributor 210 while not TC_Handshake_A.Value loop 211 delay ImpDef.Minimum_Task_Switch; 212 end loop; 213 214 -- Abort the calling task; the Credit task is guaranteed to 215 -- be in the accept body 216 abort Next_Message_Task.all; -- We are still in this declare 217 -- block 218 219 -- Inform the Credit task that the abort has been initiated 220 TC_Handshake_B.Set_True; 221 222 -- Now wait for the "acknowledgment" from the Credit task 223 -- this ensures a complete task switch (at least) 224 while not TC_Handshake_C.Value loop 225 delay ImpDef.Minimum_Task_Switch; 226 end loop; 227 228 -- The aborted task must not terminate till the accept body 229 -- has completed 230 if Next_Message_Task'terminated then 231 Report.Failed ("The abort was not deferred"); 232 end if; 233 234 -- Inform the Credit task that the termination has been checked 235 TC_Handshake_D.Set_True; 236 237 -- Now wait for the completion of the accept body in the 238 -- Credit task 239 while not TC_Handshake_E.Value loop 240 delay ImpDef.Minimum_Task_Switch; 241 end loop; 242 243 while not ( Next_Message_Task'terminated ) loop 244 delay ImpDef.Minimum_Task_Switch; 245 end loop; 246 247 -- Indicate to the Main program that this section is complete 248 TC_Handshake_F.Set_True; 249 250 else 251 -- The main part of the test is complete. Send one Debit message 252 -- as further exercise of the Distributor to ensure it has not 253 -- been affected by the abort of the requeue; 254 Build_Debit_Record ( Next_Transaction ); 255 Next_Message_Task.Accept_Transaction ( Next_Transaction ); 256 end if; 257 end; -- declare 258 end loop; 259 260 exception 261 when others => 262 Report.Failed ("Unexpected exception in Line_Driver"); 263 end Line_Driver; 264 265 266 267 task body Message_Task is 268 269 TC_Original_Transaction_Code : Transaction_Code; 270 This_Transaction : acc_Transaction_Record := new Transaction_Record; 271 272 begin 273 274 accept Accept_Transaction (In_Transaction : acc_Transaction_Record) do 275 This_Transaction.all := In_Transaction.all; 276 end Accept_Transaction; 277 278 -- Note the original code to ensure correct return 279 TC_Original_Transaction_Code := This_Transaction.Code; 280 281 -- Queue up on Distributor's Input queue 282 Distributor.Input ( This_Transaction ); 283 -- This task will now wait for the requeued rendezvous 284 -- to complete before proceeding 285 286 -- After the required computations have been performed 287 -- return the Transaction_Record appropriately (probably to an output 288 -- line driver) 289 null; -- stub 290 291 -- For the test check that the return values are as expected 292 if TC_Original_Transaction_Code /= This_Transaction.Code then 293 -- Incorrect rendezvous 294 Report.Failed ("Message Task: Incorrect code returned"); 295 end if; 296 297 if This_Transaction.Code = Credit then 298 -- The only Credit message was the one that should have been aborted 299 Report.Failed ("Abort was not effective"); 300 else 301 if This_Transaction.Return_Value /= Debit_Return or 302 This_Transaction.TC_Message_Count /= 1 or not 303 This_Transaction.TC_Thru_Distrib then 304 Report.Failed ("Expected path not traversed"); 305 end if; 306 TC_Debit_Message_Complete.Set_True; 307 end if; 308 309 exception 310 when others => 311 Report.Failed ("Unexpected exception in Message_Task"); 312 313 end Message_Task; 314 315 316 317 -- Dispose each input Transaction_Record to the appropriate 318 -- computation tasks 319 -- 320 task body Distributor is 321 322 begin 323 loop 324 select 325 accept Input (Transaction : acc_Transaction_Record) do 326 327 -- Indicate that the message did pass through the 328 -- Distributor Task 329 Transaction.TC_Thru_Distrib := true; 330 331 -- Pass this transaction on the appropriate computation 332 -- task 333 case Transaction.Code is 334 when Credit => 335 requeue Credit_Computation.Input; -- without abort 336 when Debit => 337 requeue Debit_Computation.Input; -- without abort 338 end case; 339 end Input; 340 or 341 terminate; 342 end select; 343 end loop; 344 345 exception 346 when others => 347 Report.Failed ("Unexpected exception in Distributor"); 348 end Distributor; 349 350 351 352 -- Computation task. 353 -- Note: After the computation is performed in this task and the 354 -- accept body is completed the rendezvous in the original 355 -- message task is completed. 356 task body Credit_Computation is 357 Message_Count : integer := 0; 358 begin 359 loop 360 select 361 accept Input ( Transaction : acc_Transaction_Record) do 362 -- Perform the computations required for this transaction 363 -- 364 null; -- stub 365 366 -- The rest of this code is for Test Control 367 -- 368 if not Transaction.TC_Thru_Distrib then 369 Report.Failed 370 ("Credit Task: Wrong queue, Distributor bypassed"); 371 end if; 372 if Transaction.code /= Credit then 373 Report.Failed 374 ("Credit Task: Requeue delivered to the wrong queue"); 375 end if; 376 377 -- for the test plug a known value and count 378 Transaction.Return_Value := Credit_Return; 379 -- one, and only one message should pass through 380 if Message_Count /= 0 then 381 Report.Failed ("Aborted Requeue was not canceled -1"); 382 end if; 383 Message_Count := Message_Count + 1; 384 Transaction.TC_Message_Count := Message_Count; 385 386 -- Having done the basic housekeeping we now need to signal 387 -- that we are in the accept body of the credit task. The 388 -- message has arrived and the Line Driver may now abort the 389 -- calling task 390 TC_Handshake_A.Set_True; 391 392 -- Now wait for the Line Driver to inform us the calling 393 -- task has been aborted 394 while not TC_Handshake_B.Value loop 395 delay ImpDef.Minimum_Task_Switch; 396 end loop; 397 398 -- The abort has taken place 399 -- Inform the Line Driver that we are still running in the 400 -- accept body 401 TC_Handshake_C.Set_True; 402 403 -- Now wait for the Line Driver to digest this information 404 while not TC_Handshake_D.Value loop 405 delay ImpDef.Minimum_Task_Switch; 406 end loop; 407 408 -- The Line driver has checked that the caller is not terminated 409 -- We can now complete the accept 410 411 end Input; 412 -- We are out of the accept 413 TC_Handshake_E.Set_True; 414 415 or 416 terminate; 417 end select; 418 end loop; 419 exception 420 when others => 421 Report.Failed ("Unexpected exception in Credit_Computation"); 422 end Credit_Computation; 423 424 425 426 -- Computation task. 427 -- Note: After the computation is performed in this task and the 428 -- accept body is completed the rendezvous in the original 429 -- message task is completed. 430 task body Debit_Computation is 431 Message_Count : integer := 0; 432 begin 433 loop 434 select 435 accept Input (Transaction : acc_Transaction_Record) do 436 -- Perform the computations required for this message 437 -- 438 null; -- stub 439 440 -- The rest of this code is for Test Control 441 -- 442 if not Transaction.TC_Thru_Distrib then 443 Report.Failed 444 ("Debit Task: Wrong queue, Distributor bypassed"); 445 end if; 446 if Transaction.code /= Debit then 447 Report.Failed 448 ("Debit Task: Requeue delivered to the wrong queue"); 449 end if; 450 451 -- for the test plug a known value and count 452 Transaction.Return_Value := Debit_Return; 453 -- one, and only one, message should pass through 454 Message_Count := Message_Count + 1; 455 Transaction.TC_Message_Count := Message_Count; 456 end Input; 457 or 458 terminate; 459 end select; 460 end loop; 461 exception 462 when others => 463 Report.Failed ("Unexpected exception in Debit_Computation"); 464 465 466 end Debit_Computation; 467 468 469begin -- c954014 470 Report.Test ("C954014", "Abort a task that has a call" & 471 " requeued_without_abort"); 472 473 Line_Driver.Start; -- Start the test 474 475 -- Wait for the message tasks to complete before reporting the result 476 -- 477 while not (TC_Handshake_F.Value -- abort not effective? 478 and TC_Debit_Message_Complete.Value -- Distributor affected? 479 and TC_Handshake_E.Value ) loop -- accept not completed? 480 delay ImpDef.Minimum_Task_Switch; 481 end loop; 482 483 Report.Result; 484 485end C954014; 486