-- Dining Philosophers - Ada 95 edition
--
-- Room.OBCS is responsible for assigning seats at the table,
-- "left" and "right" chopsticks, and for reporting interesting
-- events to the outside world.
--
-- Michael B. Feldman, The George Washington University, July 1995.
-- HOOD version by Pierre Dissaux, TNI, June 1998.
-- required interface :
-- Required OPERATION :
-- OPERATION : open of object : windows
-- OPERATION : title of object : windows
-- OPERATION : borders of object : windows
-- OPERATION : put#1 of object : windows
-- OPERATION : new_line of object : windows
-- OPERATION : start_eating of object : phil
-- OPERATION : get_name of object : society
-- OPERATION : Clock of object : calendar
-- Required EXCEPTION : NONE
-- Required TYPE :
-- TYPE : Window of object : windows
-- TYPE : Philosopher of object : phil
-- TYPE : Philosopher_Ptr of object : phil
-- TYPE : States of object : phil
-- TYPE : Unique_DNA_Codes of object : society
-- TYPE : Stick of object : chop
-- TYPE : Stick_Ptr of object : chop
-- TYPE : Boolean of object : standard
-- TYPE : Integer of object : standard
-- TYPE : Natural of object : standard
-- TYPE : Positive of object : standard
-- TYPE : Time of object : calendar
-- Required CONSTANT : NONE
-- Required DATA : NONE
-- visibility on required modules :
with phil;
use type phil.Philosopher;
use type phil.Philosopher_Ptr;
use type phil.States;
with society;
use type society.Unique_DNA_Codes;
with chop;
use type chop.Stick;
use type chop.Stick_Ptr;
package room is
-- Room.Get_Stick is an access function to internal Sticks variable.
-- It requires a chopstick ID (Which_Stick) to return a pointer to relevant
-- protected object.
-- (cf.FR2/Provide_chopsticks:)
function get_stick (
which_Stick : IN Positive)
return Chop.Stick_Ptr;
-- A dedicated state variable manages current state of dining room.
-- This variable "Started" has a default value of "FALSE" and become "TRUE"
-- after Start_Serving has been executed.
-- Start_Serving and Report_State have both STATE and protocole constraints.
task OBCS is
entry start_serving;
entry report_state (
Which_Phil : IN Society.Unique_DNA_Codes;
Which_State : IN Phil.States;
How_Long : IN Natural := 0;
Which_Meal : IN Natural := 0);
end OBCS;
-- Room.Start_Serving is called by main procedure and renames OBCS.Start_Serving
-- task entry.
-- This procedure has no parameter.
-- (cf.FR1/Prepare&begin_diner:)
procedure start_serving
renames OBCS.start_serving;
-- Room.Report_State is called by Phil.Start_Eating and renames OBCS.Report_State
-- task entry.
-- This procedure has four parameters:
-- - Which_Phil: identifies actual Philosopher sending the message.
-- - State: current state of sender.
-- - How_Long: length of current state (or identifier of used chopstick).
-- - Which_Meal: current meal.
-- (cf.FR3/Report_events:)
procedure report_state (
Which_Phil : IN Society.Unique_DNA_Codes;
Which_State : IN Phil.States;
How_Long : IN Natural := 0;
Which_Meal : IN Natural := 0)
renames OBCS.report_state;
end room;
-- Dining Philosophers - Ada 95 edition
--
-- Room.OBCS is responsible for assigning seats at the table,
-- "left" and "right" chopsticks, and for reporting interesting
-- events to the outside world.
--
-- Michael B. Feldman, The George Washington University, July 1995.
-- HOOD version by Pierre Dissaux, TNI, June 1998.
with Phil;
pragma Elaborate(Phil);
-- visibility on required modules :
with calendar;
use type calendar.Time;
with windows;
use type windows.Window;
-- visibility on objects required by nested operation bodies :
package body room is
-- Specifies the total number of seats around the table. It is limited to
-- five in this example.
Table_Size : constant := 5;
-- Identifies the possible locations around the table.
subtype Table_Type is Positive range 1..Table_Size;
-- First chopstick shared between seats 5 and 1.
S1 : aliased Chop.Stick;
-- second chopstick shared between seats 1 and 2.
S2 : aliased Chop.Stick;
-- Third chopstick shared between seats 2 and 3.
S3 : aliased Chop.Stick;
-- Fourth chopstick shared between seats 3 and 4.
S4 : aliased Chop.Stick;
-- Fifth chopstick shared between seats 4 and 5.
S5 : aliased Chop.Stick;
-- An array of pointers to the chopsticks.
Sticks : array (Table_Type) of Chop.Stick_Ptr;
-- First Philosopher.
P1 : aliased Phil.Philosopher(My_ID => 1);
-- Second Philosopher.
P2 : aliased Phil.Philosopher(My_ID => 2);
-- Third Philosopher.
P3 : aliased Phil.Philosopher(My_ID => 3);
-- Fourth Philosopher.
P4 : aliased Phil.Philosopher(My_ID => 4);
-- Fifth Philosopher.
P5 : aliased Phil.Philosopher(My_ID => 5);
-- An array of pointers to the Philosophers.
Phils : array (Table_Type) of Phil.Philosopher_Ptr;
-- An array of windows. One window for each seat.
Phil_Windows : array (Table_Type) of Windows.Window;
-- An array to indicate which seat each Philosopher occupies:
-- Philosopher 1 occupies seat 1;
-- Philosopher 2 occupies seat 3;
-- Philosopher 3 occupies seat 5;
-- Philosopher 4 occupies seat 4;
-- Philosopher 5 occupies seat 2;
Phil_Seats : array (Society.Unique_DNA_Codes) of Table_Type;
-- Current time obtained by Calendar.Clock.
T : Natural;
-- Time when application is launched.
Start_Time : Calendar.Time;
-- State variable to switch between "waiting" and "dining" states.
-- Initial state is "Waiting".
Started : boolean := false;
-- Performs following actions:
-- - Calculates Start_Time;
-- - Puts chopsticks on the table;
-- - Assigns Philosophers to seats at the table;
-- - Opens and draw a window to observe each seat;
-- - Assigns right and left chopsticks to each Philosopher;
procedure OPCS_start_serving is
begin
-- starting date is stored:
Start_Time := Calendar.Clock;
-- chopsticks are put on the table:
Sticks :=
(S1'Access,
S2'Access,
S3'Access,
S4'Access,
S5'Access);
-- philosophers are assigned to seats at the table
Phils :=
(P1'Access,
P3'Access,
P5'Access,
P4'Access,
P2'Access);
-- which seat each phil occupies:
Phil_Seats := (1, 3, 5, 4, 2);
-- a window is open for each seat:
Phil_Windows :=
(Windows.Open(( 1, 24), 7, 30),
Windows.Open(( 9, 2), 7, 30),
Windows.Open(( 9, 46), 7, 30),
Windows.Open((17, 7), 7, 30),
Windows.Open((17, 41), 7, 30));
-- windows borders are drawn:
for Which_Win in Phil_Windows'range loop
Windows.Borders(Phil_Windows(Which_Win),'+','|','-');
end loop;
-- philosophers are assigned their chopsticks:
Phils (1).Start_Eating(1, 1, 2);
Phils (3).Start_Eating(3, 3, 4);
Phils (2).Start_Eating(2, 2, 3);
Phils (5).Start_Eating(5, 1, 5);
Phils (4).Start_Eating(4, 4, 5);
-- dining room state changes:
Started := true;
end OPCS_start_serving;
-- Performs following actions:
-- - Calculates current time;
-- - Displays a message on relevant window.
procedure OPCS_report_state (
Which_Phil : IN Society.Unique_DNA_Codes;
Which_State : IN Phil.States;
How_Long : IN Natural := 0;
Which_Meal : IN Natural := 0) is
begin
T := Natural (Calendar.Clock - Start_Time);
case Which_State is
when Phil.Breathing =>
Windows.Title(
Phil_Windows(Phil_Seats(Which_Phil)),
Society.Get_Name(Which_Phil), '-');
Windows.Put(
Phil_Windows(Phil_Seats(Which_Phil)),
"T =" & Integer'Image (T) & " " & "Breathing...");
Windows.New_Line(Phil_Windows(Phil_Seats(Which_Phil)));
when Phil.Thinking =>
Windows.Put(
Phil_Windows(Phil_Seats(Which_Phil)),
"T =" & Integer'Image (T) & " " & "Thinking"
& Integer'Image (How_Long) & " seconds.");
Windows.New_Line(Phil_Windows(Phil_Seats(Which_Phil)));
when Phil.Eating =>
Windows.Put(
Phil_Windows(Phil_Seats(Which_Phil)),
"T =" & Integer'Image (T) & " " & "Meal"
& Integer'Image (Which_Meal) & ","
& Integer'Image (How_Long) & " seconds.");
Windows.New_Line(Phil_Windows(Phil_Seats(Which_Phil)));
when Phil.Done_Eating =>
Windows.Put(
Phil_Windows(Phil_Seats(Which_Phil)),
"T =" & Integer'Image (T) & " " & "Yum-yum (burp)");
Windows.New_Line(Phil_Windows(Phil_Seats(Which_Phil)));
when Phil.Got_One_Stick =>
Windows.Put(
Phil_Windows(Phil_Seats(Which_Phil)),
"T =" & Integer'Image (T) & " " & "First chopstick"
& Integer'Image (How_Long));
Windows.New_Line(Phil_Windows(Phil_Seats(Which_Phil)));
when Phil.Got_Other_Stick =>
Windows.Put(
Phil_Windows(Phil_Seats(Which_Phil)),
"T =" & Integer'Image (T) & " " & "Second chopstick"
& Integer'Image (How_Long));
Windows.New_Line(Phil_Windows(Phil_Seats(Which_Phil)));
when Phil.Dying =>
Windows.Put(
Phil_Windows(Phil_Seats(Which_Phil)),
"T =" & Integer'Image (T) & " " & "Croak");
Windows.New_Line(Phil_Windows(Phil_Seats(Which_Phil)));
end case; -- Which_State
end OPCS_report_state;
-- Just returns a pointer to specified chopstick.
function get_stick (
which_Stick : IN Positive)
return Chop.Stick_Ptr is
begin
return Sticks(Which_Stick);
end get_stick;
-- A dedicated state variable manages current state of dining room.
-- This variable "Started" has a default value of "FALSE" and become "TRUE"
-- after Start_Serving has been executed.
-- Start_Serving and Report_State have both STATE and protocole constraints.
task body OBCS is
start_serving_accepted : boolean := false;
report_state_accepted : boolean := false;
begin
loop
start_serving_accepted := not Started;
report_state_accepted := Started;
select
-- ASER
when start_serving_accepted =>
accept start_serving;
begin
OPCS_start_serving;
-- Initial state. Started is set to FALSE.
-- This transition is triggered by Start_Serving execution request.
-- No additional condition, neither exception code is required.
Started := true;
exception
when others =>
raise;
end;
or
when not start_serving_accepted =>
accept start_serving;
null;
or
-- HSER
when report_state_accepted =>
accept report_state (
Which_Phil : IN Society.Unique_DNA_Codes;
Which_State : IN Phil.States;
How_Long : IN Natural := 0;
Which_Meal : IN Natural := 0) do
begin
OPCS_report_state (Which_Phil, Which_State, How_Long, Which_Meal );
-- Running state. Started is set to TRUE.
-- This transition is triggered by Report_Sta te execution request.
-- No additional condition, neither exception code is required.
-- Current state is not changed.
Started := true;
exception
when others =>
raise;
end;
end report_state;
or
when not report_state_accepted =>
accept report_state (
Which_Phil : IN Society.Unique_DNA_Codes;
Which_State : IN Phil.States;
How_Long : IN Natural := 0;
Which_Meal : IN Natural := 0);
null;
or
terminate;
end select;
end loop;
end OBCS;
end room;