1-- C954010.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 within an accept statement does not block.
28--      This test uses: Requeue to an entry in a different task
29--                      Parameterless call
30--                      Requeue with abort
31--
32-- TEST DESCRIPTION:
33--      In the Distributor task, requeue two successive calls on the entries
34--      of two separate target tasks.  Verify that the target tasks are
35--      run in parallel proving that the first requeue does not block
36--      while the first target rendezvous takes place.
37--
38--      This series of tests uses a simulation of a transaction driven
39--      processing system.  Line Drivers accept input from an external source
40--      and build them into transaction records.  These records are then
41--      encapsulated in message tasks which remain extant for the life of the
42--      transaction in the system. The message tasks put themselves on the
43--      input queue of a Distributor which, from information in the
44--      transaction and/or system load conditions forwards them to other
45--      operating tasks. These in turn might forward the transactions to yet
46--      other tasks for further action.  The  routing is, in real life,
47--      dynamic and unpredictable at the time of message generation. All
48--      rerouting in this  model is done by means of requeues.
49--
50--      This test is directed towards the BLOCKING of the REQUEUE only
51--      If the original caller does not block, the outcome of the test will
52--      not be affected.  If the original caller does not continue after
53--      the return, the test will not pass.
54--      If the requeue gets placed on the wrong entry a failing test could
55--      pass (eg. if the first message is delivered to the second
56--      computation task and the second message to the first) - a check for
57--      this condition is made in other tests
58--
59--
60-- CHANGE HISTORY:
61--      06 Dec 94   SAIC    ACVC 2.0
62--
63--!
64
65with Report;
66with ImpDef;
67
68procedure C954010 is
69
70   -- Mechanism to count the number of Message tasks completed
71   protected TC_Tasks_Completed is
72      procedure Increment;
73      function  Count return integer;
74   private
75      Number_Complete : integer := 0;
76   end TC_Tasks_Completed;
77   --
78   TC_Expected_To_Complete   : constant integer := 2;
79
80
81   task type Message_Task;
82   type acc_Message_Task is access Message_Task;
83
84   task Line_Driver is
85      entry Start;
86   end Line_Driver;
87
88   task Distributor is
89      entry Input;
90   end Distributor;
91
92   task Credit_Computation is
93      entry Input;
94   end Credit_Computation;
95
96   task Debit_Computation is
97      entry Input;
98      entry TC_Artificial_Rendezvous_1;      -- test purposes only
99      entry TC_Artificial_Rendezvous_2;      -- test purposes only
100   end Debit_Computation;
101
102
103   -- Mechanism to count the number of Message tasks completed
104   protected body TC_Tasks_Completed is
105      procedure Increment is
106      begin
107         Number_Complete := Number_Complete + 1;
108      end Increment;
109
110      function Count return integer is
111      begin
112         return Number_Complete;
113      end Count;
114   end TC_Tasks_Completed;
115
116
117
118   -- Assemble messages received from an external source
119   --   Creates a message task for each and sends this to a Distributor
120   --   for appropriate disposal around the network of tasks
121   --      Such a task would normally be designed to loop continuously
122   --      creating the messages as input is received.  Simulate this
123   --      but limit it to two dummy messages for this test and allow it
124   --      to terminate at that point
125   --
126   task body Line_Driver is
127
128   begin
129
130      accept Start;      -- Wait for trigger from main
131
132      for i in 1..2 loop
133         declare
134            -- create a new message task
135            N : acc_Message_Task := new Message_Task;
136         begin
137            -- preparation code
138            null; -- stub
139
140         end;   -- declare
141      end loop;
142
143   exception
144      when others =>
145         Report.Failed ("Unexpected exception in Line_Driver");
146   end Line_Driver;
147
148
149   task body Message_Task is
150   begin
151      -- Queue up on Distributor's Input queue
152      Distributor.Input;
153
154      -- After the required computations have been performed
155      -- return the message appropriately (probably to an output
156      -- line driver
157      null;            -- stub
158
159      -- Increment to show completion of this task
160      TC_Tasks_Completed.Increment;
161
162   exception
163      when others =>
164         Report.Failed ("Unexpected exception in Message_Task");
165
166   end Message_Task;
167
168
169   -- Dispose each input message to the appropriate computation tasks
170   --    Normally this would be according to some parameters in the entry
171   --    but this simple test is using parameterless entries.
172   --
173   task body Distributor is
174     Last_was_for_Credit_Computation : Boolean := false;   -- switch
175   begin
176      loop
177         select
178            accept Input do
179               -- Determine to which task the message should be
180               -- distributed
181               --      For this test arbitrarily send the first to
182               --      Credit_Computation and the second to Debit_Computation
183               if Last_was_for_Credit_Computation then
184                  requeue Debit_Computation.Input with abort;
185               else
186                  Last_was_for_Credit_Computation := true;
187                  requeue Credit_Computation.Input with abort;
188               end if;
189            end Input;
190         or
191            terminate;
192         end select;
193      end loop;
194
195   exception
196      when others =>
197         Report.Failed ("Unexpected exception in Distributor");
198   end Distributor;
199
200
201   -- Computation task.  After the computation is performed the rendezvous
202   -- in the original message task is completed.
203   task body Credit_Computation is
204   begin
205      loop
206         select
207            accept Input do
208               -- Perform the computations required for this message
209               --
210               null;     -- stub
211
212               --   For the test:
213               --   Artificially rendezvous with Debit_Computation.
214               --   If the first requeue in Distributor has blocked
215               --   waiting for the current rendezvous to complete then the
216               --   second message will not be sent to Debit_Computation
217               --   which will still be waiting on its Input accept.
218               --   This task will HANG
219               --
220               Debit_Computation.TC_Artificial_Rendezvous_1;
221               --
222            end Input;
223         or
224            terminate;
225         end select;
226      end loop;
227   exception
228      when others =>
229         Report.Failed ("Unexpected exception in Credit_Computation");
230   end Credit_Computation;
231
232
233   -- Computation task.  After the computation is performed the rendezvous
234   -- in the original message task is completed.
235   task body Debit_Computation is
236      Message_Count      : integer := 0;
237      TC_AR1_is_complete : Boolean := false;
238   begin
239      loop
240         select
241            accept Input do
242               -- Perform the computations required for this message
243               null;    -- stub
244            end Input;
245            Message_Count := Message_Count + 1;
246         or
247            -- Guard until the rendezvous with the message for this task
248            -- has completed
249            when Message_Count > 0 =>
250            accept TC_Artificial_Rendezvous_1;    -- see comments in
251                                                  -- Credit_Computation above
252            TC_AR1_is_complete := true;
253         or
254            -- Completion rendezvous with the main procedure
255            when TC_AR1_is_complete =>
256            accept TC_Artificial_Rendezvous_2;
257         or
258            terminate;
259         end select;
260      end loop;
261   exception
262      when others =>
263         Report.Failed ("Unexpected exception in Debit_Computation");
264
265
266   end Debit_Computation;
267
268
269begin -- c954010
270   Report.Test ("C954010", "Requeue in an accept body does not block");
271
272   Line_Driver.Start;
273
274   -- Ensure that both messages were delivered to the computation tasks
275   -- This shows that both requeues were effective.
276   --
277   Debit_Computation.TC_Artificial_Rendezvous_2;
278
279   -- Ensure that the message tasks completed
280   while (TC_Tasks_Completed.Count < TC_Expected_To_Complete) loop
281      delay ImpDef.Minimum_Task_Switch;
282   end loop;
283
284   Report.Result;
285
286end C954010;
287