1-- C954A03.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 statement in an accept_statement with
28--      parameters may requeue the entry call to a protected entry with no
29--      parameters. Check that, if the call is queued on the new entry's
30--      queue, the original caller remains blocked after the requeue, but
31--      the accept_statement containing the requeue is completed.
32--
33--      Note that this test uses a requeue "with abort," although it does not
34--      check that such a requeued caller can be aborted; that feature is
35--      tested elsewhere.
36--
37-- TEST DESCRIPTION:
38--      Declare a protected type which simulates a printer device driver
39--      (foundation code).
40--
41--      Declare a task which simulates a printer server for multiple printers.
42--
43--      For the protected type, declare an entry with a barrier that is set
44--      false by a protected procedure (which simulates starting a print job
45--      on the printer), and is set true by a second protected procedure (which
46--      simulates a handler called when the printer interrupts, indicating
47--      that printing is done).
48--
49--      For the task, declare an entry whose corresponding accept statement
50--      contains a call to first protected procedure of the protected type
51--      (which sets the barrier of the protected entry to false), followed by
52--      a requeue with abort to the protected entry. Declare a second entry
53--      which does nothing.
54--
55--      Declare a "requesting" task which calls the printer server task entry
56--      (and thus executes the requeue). Verify that, following the requeue,
57--      the requesting task remains blocked. Call the second entry of the
58--      printer server task (the acceptance of this entry call verifies that
59--      the requeue statement completed the entry call by the requesting task.
60--      Call the second protected procedure of the protected type (the
61--      interrupt handler) and verify that the protected entry completes for
62--      the requesting task (which verifies that the requeue statement queued
63--      the first task object to the protected entry).
64--
65-- TEST FILES:
66--      This test depends on the following foundation code:
67--
68--         F954A00.A
69--
70--
71-- CHANGE HISTORY:
72--      06 Dec 94   SAIC    ACVC 2.0
73--      10 Oct 96   SAIC    Added pragma elaborate.
74--
75--!
76
77package C954A03_0 is  -- Printer server abstraction.
78
79   -- Simulate a system with multiple printers. The entry Print requests
80   -- that data be printed on the next available printer. The entry call
81   -- is accepted when a printer is available, and completes when printing
82   -- is done.
83
84   task Printer_Server is
85      entry Print (File_Name : String);        -- Test the requeue statement.
86      entry Verify_Results;                    -- Artifice for test purposes.
87   end Printer_Server;
88
89end C954A03_0;
90
91
92     --==================================================================--
93
94
95with Report;
96with ImpDef;
97
98with F954A00;              -- Printer device abstraction.
99use  F954A00;
100pragma Elaborate(F954a00);
101
102package body C954A03_0 is  -- Printer server abstraction.
103
104
105   task body Printer_Server is
106      Printers_Busy  : Boolean    := True;
107      Index          : Printer_ID := 1;
108      Print_Accepted : Boolean    := False;
109   begin
110
111      loop
112         -- Wait for a printer to become available:
113
114         while Printers_Busy loop
115            Printers_Busy := False;                        -- Exit loop if
116                                                           -- entry accepted.
117            select
118               Printer(Index).Done_Printing;               -- Accepted immed.
119                                                           -- when printer is
120                                                           -- available.
121            else
122               Index := 1 + (Index mod Number_Of_Printers);-- Entry not immed.
123               Printers_Busy := True;                      -- accepted; keep
124            end select;                                    -- looping.
125
126            -- Allow other tasks to get control
127            delay ImpDef.Minimum_Task_Switch;
128
129         end loop;
130                                                           -- Value of Index
131                                                           -- at loop exit
132                                                           -- identifies the
133                                                           -- avail. printer.
134
135         -- Wait for a print request or terminate:
136
137         select
138            accept Print (File_Name : String) do
139               Print_Accepted := True;                     -- Allow
140                                                           -- Verify_Results
141                                                           -- to be accepted.
142
143               Printer(Index).Start_Printing (File_Name);  -- Begin printing on
144                                                           -- the available
145               --                        --                -- printer.
146               -- Requeue is tested here --
147               --                        --
148                                                           -- Requeue caller so
149               requeue Printer(Index).Done_Printing        -- server task free
150                 with abort;                               -- to accept other
151            end Print;                                     -- requests.
152         or
153            -- Guard ensures that Verify_Results cannot be accepted
154            -- until after Print has been accepted. This avoids a
155            -- race condition in the main program.
156
157            when Print_Accepted => accept Verify_Results;  -- Artifice for
158                                                           -- testing purposes.
159         or
160            terminate;
161         end select;
162
163      end loop;
164
165   exception
166      when others =>
167         Report.Failed ("Exception raised in Printer_Server task");
168   end Printer_Server;
169
170
171end C954A03_0;
172
173
174     --==================================================================--
175
176
177with Report;
178with ImpDef;
179
180with F954A00;    -- Printer device abstraction.
181with C954A03_0;  -- Printer server abstraction.
182
183use  C954A03_0;
184use  F954A00;
185
186procedure C954A03 is
187
188   Long_Enough : constant Duration := ImpDef.Clear_Ready_Queue;
189
190
191               --==============================================--
192
193   Task_Completed : Boolean := False;          -- Testing flag.
194
195   protected Interlock is                      -- Artifice for test purposes.
196      entry Wait;                              -- Wait for lock to be released.
197      procedure Release;                       -- Release the lock.
198   private
199      Locked : Boolean := True;
200   end Interlock;
201
202
203   protected body Interlock is
204
205      entry Wait when not Locked is            -- Calls are queued until after
206      --                                       -- Release is called.
207      begin
208         Task_Completed := True;
209      end Wait;
210
211      procedure Release is                     -- Called by Print_Request.
212      begin
213         Locked := False;
214      end Release;
215
216   end Interlock;
217
218               --==============================================--
219
220   task Print_Request is                       -- Send a print request.
221   end Print_Request;
222
223   task body Print_Request is
224      My_File : constant String := "MYFILE.DAT";
225   begin
226      Printer_Server.Print (My_File);          -- Invoke requeue statement.
227      Interlock.Release;                       -- Allow main to continue.
228   exception
229      when others =>
230         Report.Failed ("Exception raised in Print_Request task");
231   end Print_Request;
232
233               --==============================================--
234
235begin  -- Main program.
236
237   Report.Test ("C954A03", "Requeue from an Accept with parameters" &
238                              " to a Protected Entry without parameters");
239
240   -- To pass this test, the following must be true:
241   --
242   --    (A) The Print entry call made by the task Print_Request must be
243   --        completed by the requeue statement.
244   --    (B) Print_Request must remain blocked following the requeue.
245   --    (C) Print_Request must be queued on the Done_Printing queue of
246   --        Printer(1).
247   --    (D) Print_Request must continue execution after Done_Printing is
248   --        complete.
249   --
250   -- First, verify (A): that the Print entry call is complete.
251   --
252   -- Call the entry Verify_Results. If the requeue statement completed the
253   -- entry call to Print, the entry call to Verify_Results should be
254   -- accepted. Since the main will hang if this is NOT the case, make this
255   -- a timed entry call.
256
257   select
258      Printer_Server.Verify_Results;        -- Accepted if requeue completed
259                                            -- entry call to Print.
260   or
261      delay Long_Enough;                    -- Time out otherwise.
262      Report.Failed ("Requeue did not complete entry call");
263   end select;
264
265   -- Now verify (B): that Print_Request remains blocked following the
266   -- requeue. Also verify that Done_Printing (the entry to which
267   -- Print_Request should have been queued) has not yet executed.
268
269   if Printer(1).Is_Done then
270      Report.Failed ("Target entry of requeue executed prematurely");
271   elsif Print_Request'Terminated then
272      Report.Failed ("Caller did not remain blocked after the requeue");
273   else
274
275      -- Verify (C): that Print_Request is queued on the
276      -- Done_Printing queue of Printer(1).
277      --
278      -- Set the barrier for Printer(1).Done_Printing to true. Check
279      -- that the Done flag is updated and that Print_Request terminates.
280
281      Printer(1).Handle_Interrupt;             -- Simulate a printer interrupt,
282                                               -- signaling that printing is
283                                               -- done.
284
285      -- The Done_Printing entry body will complete before the next
286      -- protected action is called (Printer(1).Is_Done).
287
288      if not Printer(1).Is_Done then
289         Report.Failed ("Caller was not requeued on target entry");
290      end if;
291
292      -- Finally, verify (D): that Print_Request continues after Done_Printing
293      -- completes.
294      --
295      -- After Done_Printing completes, there is a potential race condition
296      -- between the main program and Print_Request. The protected object
297      -- Interlock is provided to ensure that the check of whether
298      -- Print_Request continued is made *after* it has had a chance to do so.
299      -- The main program waits until the statement in Print_Request following
300      -- the requeue-causing statement has executed, then checks to see
301      -- whether Print_Request did in fact continue executing.
302      --
303      -- Note that the test will hang here if Print_Request does not continue
304      -- executing following the completion of the requeued entry call.
305
306      Interlock.Wait;                          -- Wait until Print_Request is
307                                               -- done.
308      if not Task_Completed then
309         Report.Failed ("Caller remained blocked after target " &
310                        "entry released");
311      end if;
312
313      -- Wait for Print_Request to finish before calling Report.Result.
314      while not Print_Request'Terminated loop
315         delay ImpDef.Minimum_Task_Switch;
316      end loop;
317
318   end if;
319
320   Report.Result;
321
322end C954A03;
323