blob: 059c97f41b6b2366143f8dff406549fbfa20db66 [file] [log] [blame]
-- 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;