| -- C940004.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. |
| --* |
| -- |
| -- TEST OBJECTIVE: |
| -- Check that a protected record can be used to control access to |
| -- resources (data internal to the protected record). |
| -- |
| -- TEST DESCRIPTION: |
| -- Declare a resource descriptor tagged type. Extend the type and |
| -- use the extended type in a protected data structure. |
| -- Implement a binary semaphore type. Declare an entry for |
| -- requesting a specific resource and an procedure for releasing the |
| -- same resource. Declare an object of this (protected) type. |
| -- Declare and start three tasks each of which asks for a resource |
| -- when directed to. Verify that resources are properly allocated |
| -- and deallocated. |
| -- |
| -- |
| -- CHANGE HISTORY: |
| -- |
| -- 12 DEC 93 SAIC Initial PreRelease version |
| -- 23 JUL 95 SAIC Second PreRelease version |
| -- 16 OCT 95 SAIC ACVC 2.1 |
| -- 13 MAR 03 RLB Fixed race condition in test. |
| -- |
| --! |
| |
| package C940004_0 is |
| -- Resource_Pkg |
| |
| type ID_Type is new Integer range 0..10; |
| type User_Descriptor_Type is tagged record |
| Id : ID_Type := 0; |
| end record; |
| |
| end C940004_0; -- Resource_Pkg |
| |
| --============================-- |
| -- no body for C940004_0 |
| --=============================-- |
| |
| with C940004_0; -- Resource_Pkg |
| |
| -- This generic package implements a semaphore to control a single resource |
| |
| generic |
| |
| type Generic_Record_Type is new C940004_0.User_Descriptor_Type |
| with private; |
| |
| package C940004_1 is |
| -- Generic_Semaphore_Pkg |
| -- generic package extends the tagged formal generic |
| -- type with some implementation relevant details, and |
| -- it provides a semaphore with operations that work |
| -- on that type |
| type User_Rec_Type is new Generic_Record_Type with private; |
| |
| protected type Semaphore_Type is |
| function TC_Count return Integer; |
| entry Request (R : in out User_Rec_Type); |
| procedure Release (R : in out User_Rec_Type); |
| private |
| In_Use : Boolean := false; |
| end Semaphore_Type; |
| |
| function Has_Access (R : User_Rec_Type) return Boolean; |
| |
| private |
| |
| type User_Rec_Type is new Generic_Record_Type with record |
| Access_To_Resource : boolean := false; |
| end record; |
| |
| end C940004_1; -- Generic_Semaphore_Pkg |
| |
| --===================================================-- |
| |
| package body C940004_1 is |
| -- Generic_Semaphore_Pkg |
| |
| protected body Semaphore_Type is |
| |
| function TC_Count return Integer is |
| begin |
| return Request'Count; |
| end TC_Count; |
| |
| entry Request (R : in out User_Rec_Type) |
| when not In_Use is |
| begin |
| In_Use := true; |
| R.Access_To_Resource := true; |
| end Request; |
| |
| procedure Release (R : in out User_Rec_Type) is |
| begin |
| In_Use := false; |
| R.Access_To_Resource := false; |
| end Release; |
| |
| end Semaphore_Type; |
| |
| function Has_Access (R : User_Rec_Type) return Boolean is |
| begin |
| return R.Access_To_Resource; |
| end Has_Access; |
| |
| end C940004_1; -- Generic_Semaphore_Pkg |
| |
| --=============================================-- |
| |
| with Report; |
| with C940004_0; -- Resource_Pkg, |
| with C940004_1; -- Generic_Semaphore_Pkg; |
| |
| package C940004_2 is |
| -- Printer_Mgr_Pkg |
| |
| -- Instantiate the generic to get code to manage a single printer; |
| -- User processes contend for the printer, asking for it by a call |
| -- to Request, and relinquishing it by a call to Release |
| |
| -- This package extends a tagged type to customize it for the printer |
| -- in question, then it uses the type to instantiate the generic and |
| -- declare a semaphore specific to the particular resource |
| |
| package Resource_Pkg renames C940004_0; |
| |
| type User_Desc_Type is new Resource_Pkg.User_Descriptor_Type with record |
| New_Details : Integer := 0; -- for example |
| end record; |
| |
| package Instantiation is new C940004_1 -- Generic_Semaphore_Pkg |
| (Generic_Record_Type => User_Desc_Type); |
| |
| Printer_Access_Mgr : Instantiation.Semaphore_Type; |
| |
| |
| end C940004_2; -- Printer_Mgr_Pkg |
| |
| --============================-- |
| -- no body for C940004_2 |
| --============================-- |
| |
| with C940004_0; -- Resource_Pkg, |
| with C940004_2; -- Printer_Mgr_Pkg; |
| |
| package C940004_3 is |
| -- User_Task_Pkg |
| |
| -- This package models user tasks that will request and release |
| -- the printer |
| package Resource_Pkg renames C940004_0; |
| package Printer_Mgr_Pkg renames C940004_2; |
| |
| task type User_Task_Type (ID : Resource_Pkg.ID_Type) is |
| entry Get_Printer; -- instructs task to request resource |
| |
| entry Release_Printer -- instructs task to release printer |
| (Descriptor : in out Printer_Mgr_pkg.Instantiation.User_Rec_Type); |
| |
| --==================-- |
| -- Test management machinery |
| --==================-- |
| entry TC_Get_Descriptor -- returns descriptor |
| (Descriptor : out Printer_Mgr_Pkg.Instantiation.User_Rec_Type); |
| |
| end User_Task_Type; |
| |
| --==================-- |
| -- Test management machinery |
| --==================-- |
| TC_Times_Obtained : Integer := 0; |
| TC_Times_Released : Integer := 0; |
| |
| end C940004_3; -- User_Task_Pkg; |
| |
| --==============================================-- |
| |
| with Report; |
| with C940004_0; -- Resource_Pkg, |
| with C940004_2; -- Printer_Mgr_Pkg, |
| |
| package body C940004_3 is |
| -- User_Task_Pkg |
| |
| task body User_Task_Type is |
| D : Printer_Mgr_Pkg.Instantiation.User_Rec_Type; |
| begin |
| D.Id := ID; |
| ----------------------------------- |
| Main: |
| loop |
| select |
| accept Get_Printer; |
| Printer_Mgr_Pkg.Printer_Access_Mgr.Request (D); |
| -- request resource; if resource is not available, |
| -- task will be queued to wait |
| --===================-- |
| -- Test management machinery |
| --===================-- |
| TC_Times_Obtained := TC_Times_Obtained + 1; |
| -- when request granted, note it and post a message |
| |
| or |
| accept Release_Printer (Descriptor : in out |
| Printer_Mgr_Pkg.Instantiation.User_Rec_Type) do |
| |
| Printer_Mgr_Pkg.Printer_Access_Mgr.Release (D); |
| -- release the resource, note its release |
| TC_Times_Released := TC_Times_Released + 1; |
| Descriptor := D; |
| end Release_Printer; |
| exit Main; |
| |
| or |
| accept TC_Get_Descriptor (Descriptor : out |
| Printer_Mgr_Pkg.Instantiation.User_Rec_Type) do |
| |
| Descriptor := D; |
| end TC_Get_Descriptor; |
| |
| end select; |
| end loop main; |
| |
| exception |
| when others => Report.Failed ("exception raised in User_Task"); |
| end User_Task_Type; |
| |
| end C940004_3; -- User_Task_Pkg; |
| |
| --==========================================================-- |
| |
| with Report; |
| with ImpDef; |
| |
| with C940004_0; -- Resource_Pkg, |
| with C940004_2; -- Printer_Mgr_Pkg, |
| with C940004_3; -- User_Task_Pkg; |
| |
| procedure C940004 is |
| Verbose : constant Boolean := False; |
| package Resource_Pkg renames C940004_0; |
| package Printer_Mgr_Pkg renames C940004_2; |
| package User_Task_Pkg renames C940004_3; |
| |
| Task1 : User_Task_Pkg.User_Task_Type (1); |
| Task2 : User_Task_Pkg.User_Task_Type (2); |
| Task3 : User_Task_Pkg.User_Task_Type (3); |
| |
| User_Rec_1, |
| User_Rec_2, |
| User_Rec_3 : Printer_Mgr_Pkg.Instantiation.User_Rec_Type; |
| |
| begin |
| |
| Report.Test ("C940004", "Check that a protected record can be used to " & |
| "control access to resources"); |
| |
| if (User_Task_Pkg.TC_Times_Obtained /= 0) |
| or (User_Task_Pkg.TC_Times_Released /= 0) |
| or Printer_Mgr_Pkg.Instantiation.Has_Access (User_Rec_1) |
| or Printer_Mgr_Pkg.Instantiation.Has_Access (User_Rec_2) |
| or Printer_Mgr_Pkg.Instantiation.Has_Access (User_Rec_3) then |
| Report.Failed ("Wrong initial conditions"); |
| end if; |
| |
| Task1.Get_Printer; -- ask for resource |
| -- request for resource should be granted |
| Task1.TC_Get_Descriptor (User_Rec_1);-- wait here 'til task gets resource |
| |
| if (User_Task_Pkg.TC_Times_Obtained /= 1) |
| or (User_Task_Pkg.TC_Times_Released /= 0) |
| or not Printer_Mgr_Pkg.Instantiation.Has_Access (User_Rec_1) then |
| Report.Failed ("Resource not assigned to task 1"); |
| end if; |
| |
| Task2.Get_Printer; -- ask for resource |
| -- request for resource should be denied |
| -- and task queued to wait |
| |
| -- Task 1 still waiting to accept Release_Printer, still holds resource |
| -- Task 2 queued on Semaphore.Request |
| |
| -- Ensure that Task2 is queued before continuing to make checks and queue |
| -- Task3. We use a for loop here to avoid hangs in broken implementations. |
| for TC_Cnt in 1 .. 20 loop |
| exit when Printer_Mgr_Pkg.Printer_Access_Mgr.TC_Count >= 1; |
| delay Impdef.Minimum_Task_Switch; |
| end loop; |
| |
| if (User_Task_Pkg.TC_Times_Obtained /= 1) |
| or (User_Task_Pkg.TC_Times_Released /= 0) then |
| Report.Failed ("Resource assigned to task 2"); |
| end if; |
| |
| Task3.Get_Printer; -- ask for resource |
| -- request for resource should be denied |
| -- and task 3 queued on Semaphore.Request |
| |
| Task1.Release_Printer (User_Rec_1);-- task 1 releases resource |
| -- released resource should be given to |
| -- queued task 2. |
| |
| Task2.TC_Get_Descriptor (User_Rec_2);-- wait here for task 2 |
| |
| -- Task 1 has released resource and completed |
| -- Task 2 has seized the resource |
| -- Task 3 is queued on Semaphore.Request |
| |
| if (User_Task_Pkg.TC_Times_Obtained /= 2) |
| or (User_Task_Pkg.TC_Times_Released /= 1) |
| or Printer_Mgr_Pkg.Instantiation.Has_Access (User_Rec_1) |
| or not Printer_Mgr_Pkg.Instantiation.Has_Access (User_Rec_2) then |
| Report.Failed ("Resource not properly released/assigned" & |
| " to task 2"); |
| if Verbose then |
| Report.Comment ("TC_Times_Obtained: " & |
| Integer'Image (User_Task_Pkg.TC_Times_Obtained)); |
| Report.Comment ("TC_Times_Released: " & |
| Integer'Image (User_Task_Pkg.TC_Times_Released)); |
| Report.Comment ("User 1 Has_Access:" & |
| Boolean'Image (Printer_Mgr_Pkg.Instantiation. |
| Has_Access (User_Rec_1))); |
| Report.Comment ("User 2 Has_Access:" & |
| Boolean'Image (Printer_Mgr_Pkg.Instantiation. |
| Has_Access (User_Rec_2))); |
| end if; |
| end if; |
| |
| Task2.Release_Printer (User_Rec_2);-- task 2 releases resource |
| |
| -- task 3 is released from queue, and is given resource |
| |
| Task3.TC_Get_Descriptor (User_Rec_3);-- wait for task 3 |
| |
| if (User_Task_Pkg.TC_Times_Obtained /= 3) |
| or (User_Task_Pkg.TC_Times_Released /= 2) |
| or Printer_Mgr_Pkg.Instantiation.Has_Access (User_Rec_2) |
| or not Printer_Mgr_Pkg.Instantiation.Has_Access (User_Rec_3) then |
| Report.Failed ("Resource not properly released/assigned " & |
| "to task 3"); |
| if Verbose then |
| Report.Comment ("TC_Times_Obtained: " & |
| Integer'Image (User_Task_Pkg.TC_Times_Obtained)); |
| Report.Comment ("TC_Times_Released: " & |
| Integer'Image (User_Task_Pkg.TC_Times_Released)); |
| Report.Comment ("User 1 Has_Access:" & |
| Boolean'Image (Printer_Mgr_Pkg.Instantiation. |
| Has_Access (User_Rec_1))); |
| Report.Comment ("User 2 Has_Access:" & |
| Boolean'Image (Printer_Mgr_Pkg.Instantiation. |
| Has_Access (User_Rec_2))); |
| Report.Comment ("User 3 Has_Access:" & |
| Boolean'Image (Printer_Mgr_Pkg.Instantiation. |
| Has_Access (User_Rec_3))); |
| end if; |
| end if; |
| |
| Task3.Release_Printer (User_Rec_3);-- task 3 releases resource |
| |
| if (User_Task_Pkg.TC_Times_Obtained /=3) |
| or (User_Task_Pkg.TC_Times_Released /=3) |
| or Printer_Mgr_Pkg.Instantiation.Has_Access (User_Rec_3) then |
| Report.Failed ("Resource not properly released by task 3"); |
| if Verbose then |
| Report.Comment ("TC_Times_Obtained: " & |
| Integer'Image (User_Task_Pkg.TC_Times_Obtained)); |
| Report.Comment ("TC_Times_Released: " & |
| Integer'Image (User_Task_Pkg.TC_Times_Released)); |
| Report.Comment ("User 1 Has_Access:" & |
| Boolean'Image (Printer_Mgr_Pkg.Instantiation. |
| Has_Access (User_Rec_1))); |
| Report.Comment ("User 2 Has_Access:" & |
| Boolean'Image (Printer_Mgr_Pkg.Instantiation. |
| Has_Access (User_Rec_2))); |
| Report.Comment ("User 3 Has_Access:" & |
| Boolean'Image (Printer_Mgr_Pkg.Instantiation. |
| Has_Access (User_Rec_3))); |
| end if; |
| |
| end if; |
| |
| -- Ensure that all tasks have terminated before reporting the result |
| while not (Task1'terminated |
| and Task2'terminated |
| and Task3'terminated) loop |
| delay ImpDef.Minimum_Task_Switch; |
| end loop; |
| |
| Report.Result; |
| |
| end C940004; |