Room manages the simulation:
- intanciates Philosophers and Sticks.
- assigns each Philosopher a seat and his chopsticks.
- creates windows on the screen.
- displays information dynamically inside each window.(cf.FR3/Report_events:)
This application is the HOOD version of "Dining Philosophers - Ada95 edition" from Michael B. Feldman, The George Washington University, July 1995.
HOOD adaptation was performed by Pierre Dissaux, TNI, June 1998, with STOOD toolset.
Room must manage:
SR1: dining room seats (cf.SR1/Dining_room_seats:)
SR2: Philosophers (cf.SR2/Philosophers:)
SR3: chopsticks (cf.SR3/Chopsticks:)
SR4: display windows (cf.SR4/Display_windows:)
SR5: simulation timing (cf.SR5/Simulation_timing:)
Room provides thre functional services:
FR1: prepare and begin the diner. (cf.FR1/Prepare&begin_diner:)
FR2: provide chopsticks to Philosophers. (cf.FR2/Provide_chopsticks:)
FR3: report events to outside world. (cf.FR3/Report_events:)
Dining room behaviour should be as follow:
BR3: start diner asynchronously (cf.BR3/Dynamic_events_report:)
BR4: report event synchronously (cf.BR4/Synchronous_events_report:)
BR5: Dining room has two possible states (Waiting or Dining) (cf.BR5/Dining_room_states:)
Please refer to parent module description.
Dining room is designed as an active HOOD4 object, as it must have its own control flow.
Structural element (types, constants and data) are all hidden inside internal part.
Behaviour is described by a HOOD4 STD (State Transtion Diagram) and constraints on provided operations, and encapsulated inside a HOOD OBCS (Object Control Structure).
Implementation of functional services are descibed directly inside HOOD OPCSs (Operation Control Structures).
Code generator will produce a package containing a task called OBCS.
(cf.BR5/Dining_room_states:)
Structural elements are all hidden inside internals of this module, as none of them is required from outside.
They are listed below:
SR1:
- type Table_Type describes the table.
- constant Table_Size specifies the size of the table (5 seats).
- data Phil_Seats is used to allocate a seat to each Philosopher.
SR2:
- data P1 to P5 are five instances of Phil.Philosopher.
- data Phils is an array of pointers on these Philosophers.
SR3:
- data S1 to S5 are five instances of Chop.Stick.
- data Sticks is an array of pointers on these chopsticks.
SR4:
- data Phil_Windows is an array of five Windows.window.
SR5:
- data Start_Time is initialized when simulation starts.
- data T provides current simulation time.
Operations provided by dining room are:
FR1:
Start_Serving: sets up the table and start the diner.
It is called by main procedure of the program.
FR2:
Get_Stick: implements the request from a Philosopher to pick up a chopstick.
This procedure didn't exist inside original Ada code where chopsticks were declared as public data, and were thus directly visible from Phil module. Provided data being forbidden when designing with HOOD, chopstick instances were declared within the internals, and Get_Stick access function was added to implement remote requests.
FR3:
Report_State: is used by Philosophers to indicate in which internal state they are.
None.
Dining room behaviour is represented by a State Transition model and constraints on operation execution requests:
BR5: Dining room has two distinct states:
- waiting state, identified by internal state variable "started" set to FALSE, where Room may only receive "Start_Serving" execution requests.
- dining state, identified by internal state variable "started" set to TRUE, where Room may only receive "Report_State" execution requests.
BR3: Start_Serving has an asynchronous execution request (ASER).
BR4: Report_State has a highly synchronous execution request (HSER), so that Philosopher 's internal state doesn't change while current state is displayed on relevant window.
A few changes in initial source code were required to fit HOOD4 design rules:
- Sticks variable was initially declared within package spec, which is forbidden with HOOD, so it was moved into package body, and an additional access function (Get_Stick) may be used to pick_up on one of the five chopsticks.
- As chopsticks are instances of a protected type, which is thus a limited type, they cannot be returned directly by an access function. Sticks thus became an array of pointers on chopsticks.
- To comply with standard HOOD code generation rules, task entries are not directly called from outside. Remote clients should call Room.Start_Serving and Room.Report_State which remame task entries of the same name. For the same reason, relevant bodies are implemented into additional internal OPCS_Start_serving and OPCS_Report_State procedures.
- Within original code, main control task was called "Maitre_D". Its name become "OBCS" when generated from a HOOD design. Task body is also automatically generated from STD and operation constraints: this implies changes to code structure.
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:)
start_serving;
WCET
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:)
report_state(
Which_Phil : in Society.Unique_DNA_Codes;
Which_State : in Phil.States;
How_Long : in Natural := --|0|--;
Which_Meal : in Natural := --|0|--
);
WCET
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:)
get_stick(which_Stick : in Positive) return Chop.Stick_Ptr;
WCET
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.
start_serving CONSTRAINED_BY ASER STATE;
report_state CONSTRAINED_BY HSER STATE;
OBJECT calendar;
TYPES
Time;
CONSTANTS
NONE
OPERATION_SETS
NONE
OPERATIONS
Clock;
EXCEPTIONS
NONE
OBJECT chop;
TYPES
Stick_Ptr; Stick;
CONSTANTS
NONE
OPERATION_SETS
NONE
OPERATIONS
NONE
EXCEPTIONS
NONE
OBJECT phil;
TYPES
States; Philosopher; Philosopher_Ptr;
CONSTANTS
NONE
OPERATION_SETS
NONE
OPERATIONS
start_eating;
EXCEPTIONS
NONE
OBJECT society;
TYPES
Unique_DNA_Codes;
CONSTANTS
NONE
OPERATION_SETS
NONE
OPERATIONS
get_name;
EXCEPTIONS
NONE
OBJECT standard;
TYPES
Natural; Integer; Positive; Boolean;
CONSTANTS
NONE
OPERATION_SETS
NONE
OPERATIONS
NONE
EXCEPTIONS
NONE
OBJECT windows;
TYPES
Window;
CONSTANTS
NONE
OPERATION_SETS
NONE
OPERATIONS
open; borders; title; put#1; new_line;
EXCEPTIONS
NONE
starting => phil;
displaying => windows;
Identifies the possible locations around the table.
ATTRIBUTES NONE
ENUMERATION NONE
subtype Table_Type is Positive range 1..Table_Size;
Specifies the total number of seats around the table. It is limited to five in this example.
Table_Size : constant := 5;
First chopstick shared between seats 5 and 1.
S1 : aliased Chop.Stick;
(da) room.S1 IS USED BY NONE
(da) room.S1 IS USED BY
(op) room.start_serving [R]
(da) room.S1 IS USED BY NONE
(da) room.S1 IS USED BY NONE
second chopstick shared between seats 1 and 2.
S2 : aliased Chop.Stick;
(da) room.S2 IS USED BY NONE
(da) room.S2 IS USED BY
(op) room.start_serving [R]
(da) room.S2 IS USED BY NONE
(da) room.S2 IS USED BY NONE
Third chopstick shared between seats 2 and 3.
S3 : aliased Chop.Stick;
(da) room.S3 IS USED BY NONE
(da) room.S3 IS USED BY
(op) room.start_serving [R]
(da) room.S3 IS USED BY NONE
(da) room.S3 IS USED BY NONE
Fourth chopstick shared between seats 3 and 4.
S4 : aliased Chop.Stick;
(da) room.S4 IS USED BY NONE
(da) room.S4 IS USED BY
(op) room.start_serving [R]
(da) room.S4 IS USED BY NONE
(da) room.S4 IS USED BY NONE
Fifth chopstick shared between seats 4 and 5.
S5 : aliased Chop.Stick;
(da) room.S5 IS USED BY NONE
(da) room.S5 IS USED BY
(op) room.start_serving [R]
(da) room.S5 IS USED BY NONE
(da) room.S5 IS USED BY NONE
An array of pointers to the chopsticks.
Sticks : array (Table_Type) of Chop.Stick_Ptr;
(da) room.Sticks IS USED BY NONE
(da) room.Sticks IS USED BY
(op) room.get_stick [R]
(op) room.start_serving [R]
(da) room.Sticks IS USED BY NONE
(da) room.Sticks IS USED BY NONE
First Philosopher.
P1 : aliased Phil.Philosopher(My_ID => 1);
(da) room.P1 IS USED BY NONE
(da) room.P1 IS USED BY
(op) room.start_serving [R]
(da) room.P1 IS USED BY NONE
(da) room.P1 IS USED BY NONE
Second Philosopher.
P2 : aliased Phil.Philosopher(My_ID => 2);
(da) room.P2 IS USED BY NONE
(da) room.P2 IS USED BY
(op) room.start_serving [R]
(da) room.P2 IS USED BY NONE
(da) room.P2 IS USED BY NONE
Third Philosopher.
P3 : aliased Phil.Philosopher(My_ID => 3);
(da) room.P3 IS USED BY NONE
(da) room.P3 IS USED BY
(op) room.start_serving [R]
(da) room.P3 IS USED BY NONE
(da) room.P3 IS USED BY NONE
Fourth Philosopher.
P4 : aliased Phil.Philosopher(My_ID => 4);
(da) room.P4 IS USED BY NONE
(da) room.P4 IS USED BY
(op) room.start_serving [R]
(da) room.P4 IS USED BY NONE
(da) room.P4 IS USED BY NONE
Fifth Philosopher.
P5 : aliased Phil.Philosopher(My_ID => 5);
(da) room.P5 IS USED BY NONE
(da) room.P5 IS USED BY
(op) room.start_serving [R]
(da) room.P5 IS USED BY NONE
(da) room.P5 IS USED BY NONE
An array of pointers to the Philosophers.
Phils : array (Table_Type) of Phil.Philosopher_Ptr;
(da) room.Phils IS USED BY NONE
(da) room.Phils IS USED BY
(op) room.start_serving [R]
(da) room.Phils IS USED BY NONE
(da) room.Phils IS USED BY NONE
An array of windows. One window for each seat.
Phil_Windows : array (Table_Type) of Windows.Window;
(da) room.Phil_Windows IS USED BY NONE
(da) room.Phil_Windows IS USED BY
(op) room.report_state [R]
(op) room.start_serving [R]
(da) room.Phil_Windows IS USED BY NONE
(da) room.Phil_Windows IS USED BY NONE
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;
(da) room.Phil_Seats IS USED BY NONE
(da) room.Phil_Seats IS USED BY
(op) room.report_state [R]
(op) room.start_serving [R]
(da) room.Phil_Seats IS USED BY NONE
(da) room.Phil_Seats IS USED BY NONE
Current time obtained by Calendar.Clock.
T : Natural;
(da) room.T IS USED BY NONE
(da) room.T IS USED BY
(op) room.report_state [R]
(da) room.T IS USED BY NONE
(da) room.T IS USED BY NONE
Time when application is launched.
Start_Time : Calendar.Time;
(da) room.Start_Time IS USED BY NONE
(da) room.Start_Time IS USED BY
(op) room.report_state [R]
(op) room.start_serving [R]
(da) room.Start_Time IS USED BY NONE
(da) room.Start_Time IS USED BY NONE
State variable to switch between "waiting" and "dining" states.
Initial state is "Waiting".
Started : boolean := false;
(da) room.Started IS USED BY NONE
(da) room.Started IS USED BY
(op) room.start_serving [R]
(da) room.Started IS USED BY NONE
(da) room.Started IS USED BY NONE
OBCS is automatically generated from STD and operation constraints.
starting
Initial state. Started is set to FALSE.
Started := false;
not Started
starting, serving
serving
Running state. Started is set to TRUE.
Started := true;
Started
start_serving
waiting
dining
This transition is triggered by Start_Serving execution request.
No additional condition, neither exception code is required.
report_state
dining
dining
This transition is triggered by Report_Sta te execution request.
No additional condition, neither exception code is required.
Current state is not changed.
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;
calendar.Clock
windows.open
windows.borders
phil.start_eating
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;
Performs following actions:
- Calculates current time;
- Displays a message on relevant window.
calendar.Clock
windows.title
society.get_name
windows.put
windows.new_line
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
Just returns a pointer to specified chopstick.
begin
return Sticks(Which_Stick);