-- C940002.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. --* -- -- OBJECTIVE: -- Check that a protected object provides coordinated access to shared -- data. Check that it can implement a semaphore-like construct using a -- parameterless procedure which allows a specific maximum number of tasks -- to run and excludes all others -- -- TEST DESCRIPTION: -- Implement a counting semaphore type that can be initialized to a -- specific number of available resources. Declare an entry for -- requesting a resource and a procedure for releasing it. Declare an -- object of this type, initialized to two resources. Declare and start -- three tasks each of which asks for a resource. Verify that only two -- resources are granted and that the last task in is queued. -- -- -- CHANGE HISTORY: -- 06 Dec 94 SAIC ACVC 2.0 -- --! package C940002_0 is -- Semaphores protected type Semaphore_Type (Resources_Available : Integer :=1) is entry Request; procedure Release; function Available return Integer; private Currently_Available : Integer := Resources_Available; end Semaphore_Type; Max_Resources : constant Integer := 2; Resource : Semaphore_Type (Max_Resources); end C940002_0; -- Semaphores; --========================================================-- package body C940002_0 is -- Semaphores protected body Semaphore_Type is entry Request when Currently_Available >0 is -- when granted, secures begin -- a resource Currently_Available := Currently_Available - 1; end Request; procedure Release is -- when called, releases begin -- a resource Currently_Available := Currently_Available + 1; end Release; function Available return Integer is -- returns number of begin -- available resources return Currently_Available; end Available; end Semaphore_Type; end C940002_0; -- Semaphores; --========================================================-- package C940002_1 is -- Task_Pkg task type Requesting_Task is entry Done; -- call on Done instructs the task end Requesting_Task; -- to release resource type Task_Ptr is access Requesting_Task; protected Counter is procedure Increment; procedure Decrement; function Number return integer; private Count : Integer := 0; end Counter; protected Hold_Lock is procedure Lock; procedure Unlock; function Locked return Boolean; private Lock_State : Boolean := true; -- starts out locked end Hold_Lock; end C940002_1; -- Task_Pkg --========================================================-- with Report; with C940002_0; -- Semaphores; package body C940002_1 is -- Task_Pkg is protected body Counter is procedure Increment is begin Count := Count + 1; end Increment; procedure Decrement is begin Count := Count - 1; end Decrement; function Number return Integer is begin return Count; end Number; end Counter; protected body Hold_Lock is procedure Lock is begin Lock_State := true; end Lock; procedure Unlock is begin Lock_State := false; end Unlock; function Locked return Boolean is begin return Lock_State; end Locked; end Hold_Lock; task body Requesting_Task is begin C940002_0.Resource.Request; -- request a resource -- if resource is not available, -- task will be queued to wait Counter.Increment; -- add to count of resources obtained Hold_Lock.Unlock; -- and unlock Lock - system is stable; -- status may now be queried accept Done do -- hold resource until Done is called C940002_0.Resource.Release; -- release the resource and Counter.Decrement; -- note release end Done; exception when others => Report.Failed ("Unexpected Exception in Requesting_Task"); end Requesting_Task; end C940002_1; -- Task_Pkg; --========================================================-- with Report; with ImpDef; with C940002_0, -- Semaphores, C940002_1; -- Task_Pkg; procedure C940002 is package Semaphores renames C940002_0; package Task_Pkg renames C940002_1; Ptr1, Ptr2, Ptr3 : Task_Pkg.Task_Ptr; Num : Integer; procedure Spinlock is begin -- loop until unlocked while Task_Pkg.Hold_Lock.Locked loop delay ImpDef.Minimum_Task_Switch; end loop; Task_Pkg.Hold_Lock.Lock; end Spinlock; begin Report.Test ("C940002", "Check that a protected record can be used to " & "control access to resources"); if (Task_Pkg.Counter.Number /=0) or (Semaphores.Resource.Available /= 2) then Report.Failed ("Wrong initial conditions"); end if; Ptr1 := new Task_Pkg.Requesting_Task; -- newly allocated task requests -- resource; request for resource should -- be granted Spinlock; -- ensure that task obtains resource -- Task 1 waiting for call to Done -- One resource assigned to task 1 -- One resource still available if (Task_Pkg.Counter.Number /= 1) or (Semaphores.Resource.Available /= 1) then Report.Failed ("Resource not assigned to task 1"); end if; Ptr2 := new Task_Pkg.Requesting_Task; -- newly allocated task requests -- resource; request for resource should -- be granted Spinlock; -- ensure that task obtains resource -- Task 1 waiting for call to Done -- Task 2 waiting for call to Done -- Resources held by tasks 1 and 2 -- No resources available if (Task_Pkg.Counter.Number /= 2) or (Semaphores.Resource.Available /= 0) then Report.Failed ("Resource not assigned to task 2"); end if; Ptr3 := new Task_Pkg.Requesting_Task; -- newly allocated task requests -- resource; request for resource should -- be denied and task queued to wait for -- next available resource Ptr1.all.Done; -- Task 1 releases resource and lock -- Resource should be given to queued task Spinlock; -- ensure that resource is released -- Task 1 holds no resource -- One resource still assigned to task 2 -- One resource assigned to task 3 -- No resources available if (Task_Pkg.Counter.Number /= 2) or (Semaphores.Resource.Available /= 0) then Report.Failed ("Resource not properly released/assigned to task 3"); end if; Ptr2.all.Done; -- Task 2 releases resource and lock -- No outstanding request for resource -- Tasks 1 and 2 hold no resources -- One resource assigned to task 3 -- One resource available if (Task_Pkg.Counter.Number /= 1) or (Semaphores.Resource.Available /= 1) then Report.Failed ("Resource not properly released from task 2"); end if; Ptr3.all.Done; -- Task 3 releases resource and lock -- All resources released -- All tasks terminated (or close) -- Two resources available if (Task_Pkg.Counter.Number /=0) or (Semaphores.Resource.Available /= 2) then Report.Failed ("Resource not properly released from task 3"); end if; Report.Result; end C940002;