------------------------------------------------------------------------------ ------------------------------------------------------------------------------ -- Cheddar is a GNU GPL real-time scheduling analysis tool. -- This program provides services to automatically check schedulability and -- other performance criteria of real-time architecture models. -- -- Copyright (C) 2002-2016, Frank Singhoff, Alain Plantec, Jerome Legrand -- -- The Cheddar project was started in 2002 by -- Frank Singhoff, Lab-STICC UMR 6285 laboratory, Université de Bretagne Occidentale -- -- Cheddar has been published in the "Agence de Protection des Programmes/France" in 2008. -- Since 2008, Ellidiss technologies also contributes to the development of -- Cheddar and provides industrial support. -- -- The full list of contributors and sponsors can be found in AUTHORS.txt and SPONSORS.txt -- -- This program is free software; you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation; either version 2 of the License, or -- (at your option) any later version. -- -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with this program; if not, write to the Free Software -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -- -- -- Contact : cheddar@listes.univ-brest.fr -- ------------------------------------------------------------------------------ -- Last update : -- $Rev: 1249 $ -- $Date: 2014-08-28 07:02:15 +0200 (Fri, 28 Aug 2014) $ -- $Author: singhoff $ ------------------------------------------------------------------------------ ------------------------------------------------------------------------------ with io_tools; use io_tools; with Ada.IO_Exceptions; use Ada.IO_Exceptions; with Ada.Strings.Unbounded.Text_IO; use Ada.Strings.Unbounded.Text_IO; with Ada.Exceptions; use Ada.Exceptions; with Translate; use Translate; with scheduler_io; use scheduler_io; with Statements; use Statements; with Simulations; use Simulations; with Simulations.extended; use Simulations.extended; with Parameters; use Parameters; use Parameters.User_Defined_Parameters_Table_Package; with Parser; use Parser; with Debug; use Debug; with Sections; use Sections; with Automaton.extended; use Automaton.extended; use Automaton.Transition_Lists_Package; use Automaton.Package_Transition_Status; with GNAT.Current_Exception; use GNAT.Current_Exception; with Interpreter.extended; use Interpreter.extended; with Text_IO; use Text_IO; package body Scheduler.user_defined.interpreted.Automata is -- Sketch of the simulation engine algorithm for an automaton user-defined --scheduler. -- This algorithm is performed at each unit of time by the Do_Election --sub-program -- -- Step at $n$th unit of time : -- 1. Change transition status : -- 1.1 Transition which are "ready", "rendezvous" or "guarded" must --be set to "ready" -- 1.2 Transition which are "pended" : stay "pended" if the delay --is not exhausted. If the -- delay is exhausted, update the current location (transition --outgoing location) and -- becomes "ready" -- 2. Check reachability for all transition : set transition status to --"unreachable" -- transitions which are not outgoing transition of the current -- location for the corresponding automaton. -- We only analyze transitions with has -- a "ready" status. -- 3. Check guard (eg. timed constraints) for all transition. -- We only analyze transitions with has -- a "ready" status. -- A transition blocked due to a guard constraint see its status --becoming "guarded". -- 4. Check synchronization constraint for all transitions. -- We only analyze transitions with has -- a "ready" status. -- A transition blocked due to a synchronization constraint see its --status becoming "rendezvous". -- 5. Fire all transitions with a "ready" transition status. -- It means : -- 5.1. Run delay/clock statement (if so). This may lead to --change the -- wakeup automaton date and its state to "pended" -- 5.2. Run sections. It means, run synchronization with the --scheduling engine. -- Section run there can be priority, start, election or --task_activation section. -- If an election section is run, then, the Do_Election --sub-program is over. -- Depending on which automaton the election section --belong, Do_Election chose a task -- in the task set corresponding to the given --processor/address space automaton. -- 5.3. Update current location (transition outgoing location) --for all fired transition -- except for those which are "pended" -- 6. Restart at step 1 if, at least one transition is fire at step 5. -- -- procedure Do_Election (My_Scheduler : in out Automata_User_Defined_Scheduler; Si : in out Scheduling_Information; Result : in out Scheduling_Sequence_Ptr; Msg : in out Unbounded_String; Current_Time : in Natural; Processor_Name : in Unbounded_String; Address_Space_Name : in Unbounded_String; My_Dependencies : in Tasks_Dependencies_Ptr; With_Offsets : in Boolean; With_Precedencies : in Boolean; With_Resources : in Boolean; With_jitters : in Boolean; With_minimize_preemption : in Boolean; Event_To_Generate : in Time_Unit_Event_Type_Boolean_Table; Elected : in out Tasks_Range; No_Task : in out Boolean) is First_Step : Boolean := True; Second_Step : Boolean := True; Run_A_Transition : Boolean := False; Run_Election_Section : Boolean := False; begin -- By default, no task is elected : it's a way -- to safely schedule an user_defined scheduler without -- a correctly designed code -- No_Task := True; -- Load statement execution, we load writtable user defined variable -- Load_Read_Write_Interpreter_Variables (My_Scheduler, Si, Processor_Name); -- We update simulation engine variables which has to update -- because of the task which was running at the previous unit of time -- update_interpreter_variables_after_task_execution (My_Scheduler, Si, Current_Time, Processor_Name, empty_string, My_Dependencies, With_Offsets, With_Precedencies, With_Resources); -- Transitions are run until an election section is called or -- all transitions are blocked (no task to run) -- while (First_Step or Second_Step) loop -- 1. Change transition status : -- 1.1 Transition which are "ready", "rendezvous" or --"guarded" must be set to "ready" -- 1.2 Transition which are "pended" : stay "pended" if the --delay is not exhausted. If the -- delay is exhausted, update the current location --(transition outgoing location) and -- becomes "ready" -- for I in 0 .. My_Scheduler.Transition_Data.nb_entries - 1 loop if My_Scheduler.Transition_Data.entries (I).data.status /= Pended then My_Scheduler.Transition_Data.entries (I).data.status := Ready; else Check_Delay_Constraints (My_Scheduler, My_Scheduler.Transition_Data.entries (I).data, My_Scheduler.Transition_Data.entries (I).item, Current_Time); end if; end loop; -- 2. Check reachability for all transition : set transition --status to "unreachable" -- transitions which are not outgoing transition of the current -- location for the corresponding automaton. -- We only analyze transitions with has -- a "ready" status. -- 3. Check guard (eg. timed constraints) for all transition. -- We only analyze transitions with has -- a "ready" status. -- for I in 0 .. My_Scheduler.Transition_Data.nb_entries - 1 loop Check_Reachability (My_Scheduler, My_Scheduler.Transition_Data.entries (I).data, My_Scheduler.Transition_Data.entries (I).item); Check_Guard_Constraints (My_Scheduler, My_Scheduler.Transition_Data.entries (I).data); end loop; -- 4. Check synchronization constraint for all transitions. -- We only analyze transitions with has -- a "ready" status. -- A transition blocked due to a synchronization constraint --see its status becoming "rendezvous". -- for I in 0 .. My_Scheduler.Transition_Data.nb_entries - 1 loop Check_Synchronization_Constraints (My_Scheduler, My_Scheduler.Transition_Data.entries (I).data, Si, Result, Msg, Current_Time, Processor_Name, My_Dependencies, With_Offsets, With_Precedencies, With_Resources, Event_To_Generate, Elected, No_Task); end loop; -- 5. Fire all transitions with a "ready" transition status. -- It means : -- 5.1. Run delay/clock statement (if so). This may lead --to change the -- wakeup automaton date and its state to "pended" -- 5.2. Run sections. It means, run synchronization with --the scheduling engine. -- Section run there can be priority, start, --election or task_activation section. -- If an election section is run, then, the --Do_Election sub-program is over. -- Depending on which automaton the election section --belong, Do_Election chose a task -- in the task set corresponding to the given --processor/address space automaton. -- 5.3. Update current location (transition outgoing --location) for all fired transition -- except for those which are "pended" -- Run_A_Transition := False; for I in 0 .. My_Scheduler.Transition_Data.nb_entries - 1 loop -- Is the transition ready ? if so, fire it -- if My_Scheduler.Transition_Data.entries (I).data.status = Ready then Run_Election_Section := False; Fire_A_Transition (My_Scheduler, My_Scheduler.Transition_Data.entries (I).data, My_Scheduler.Transition_Data.entries (I).item, Si, Result, Msg, Current_Time, Processor_Name, My_Dependencies, With_Offsets, With_Precedencies, With_Resources, Event_To_Generate, Elected, No_Task, Run_Election_Section); if Run_Election_Section then -- We update variables which has a clock type by --incrementing their value -- for I in 0 .. My_Scheduler.Variables_Table.Nb_Entries - 1 loop if (Get_Type (My_Scheduler.Variables_Table.Entries (I).Variable. all) = Simulation_clock) then My_Scheduler.Variables_Table.Entries (I).Simulation. Integer_Value := My_Scheduler.Variables_Table.Entries (I).Simulation. Integer_Value + 1; end if; if (Get_Type (My_Scheduler.Variables_Table.Entries (I).Variable. all) = Simulation_array_clock) then for J in Integer_Table'Range loop My_Scheduler.Variables_Table.Entries (I).Simulation. Integer_Table_Value (J) := My_Scheduler.Variables_Table.Entries (I). Simulation.Integer_Table_Value (J) + 1; end loop; end if; end loop; -- After statement execution, we -- save some task run time information -- Save_Read_Write_Interpreter_Variables (My_Scheduler, Si, Processor_Name); return; end if; Run_A_Transition := True; end if; end loop; -- 6. Restart at step 1 if, at least one transition is fired at --step 5. -- if Run_A_Transition then First_Step := True; Second_Step := True; end if; if (not First_Step) and (not Run_A_Transition) then Second_Step := False; end if; if not Run_A_Transition then First_Step := False; end if; end loop; -- No task was elected -- save simuluation data -- -- We update variables which has a clock type by incrementing their value -- for I in 0 .. My_Scheduler.Variables_Table.Nb_Entries - 1 loop if (Get_Type (My_Scheduler.Variables_Table.Entries (I).Variable.all) = Simulation_clock) then My_Scheduler.Variables_Table.Entries (I).Simulation.Integer_Value := My_Scheduler.Variables_Table.Entries (I).Simulation. Integer_Value + 1; end if; if (Get_Type (My_Scheduler.Variables_Table.Entries (I).Variable.all) = Simulation_array_clock) then for J in Integer_Table'Range loop My_Scheduler.Variables_Table.Entries (I).Simulation. Integer_Table_Value (J) := My_Scheduler.Variables_Table.Entries (I).Simulation. Integer_Table_Value (J) + 1; end loop; end if; end loop; -- After statement execution, we -- save some task run time information -- Save_Read_Write_Interpreter_Variables (My_Scheduler, Si, Processor_Name); end Do_Election; -- 5. Fire all transitions with a "ready" transition status. -- It means : -- 5.1. Run delay/clock statement (if so). This may lead to --change the -- wakeup automaton date and its state to "pended" -- 5.2. Run sections. It means, run synchronization with the --scheduling engine. -- Section run there can be priority, start, election or --task_activation section. -- If an election section is run, then, the Do_Election --sub-program is over. -- Depending on which automaton the election section --belong, Do_Election chose a task -- in the task set corresponding to the given --processor/address space automaton. -- 5.3. Update current location (transition outgoing location) --for all fired transition -- except for those which are "pended" -- procedure Fire_A_Transition (My_Scheduler : in out Automata_User_Defined_Scheduler; A_Transition : in out Transition_Status; Automaton_Name_Of_The_Transition : in Unbounded_String; Si : in out Scheduling_Information; Result : in out Scheduling_Sequence_Ptr; Msg : in out Unbounded_String; Current_Time : in Natural; Processor_Name : in Unbounded_String; My_Dependencies : in Tasks_Dependencies_Ptr; With_Offsets : in Boolean; With_Precedencies : in Boolean; With_Resources : in Boolean; Event_To_Generate : in Time_Unit_Event_Type_Boolean_Table; Elected : in out Tasks_Range; No_Task : in out Boolean; An_Election_Section_Was_Run : in out Boolean) is Found_A_Section_To_Run : Boolean := False; A_Section : Generic_Section_Ptr; Election_On_Processor : Unbounded_String; Election_On_Address_Space : Unbounded_String; Found_Automaton : Boolean; begin Put_Debug ("fire transition (" & Automaton_Name_Of_The_Transition & ") : " & A_Transition.code.name); -- Run the clock statement of the transition -- This statement delays the transition firing if a delay statement is --present -- otherwhise, this statement update user-defiend variables -- if A_Transition.code.clocks /= null then declare Simu_Ptr : Simulation_Value_Ptr; begin -- is it a "delay" statement or an assignement statement ? -- if A_Transition.code.clocks.statement_type = Clock_Statement_Type then -- It's a delay statement -- Read the delay expression and save it into the transition --status descriptor -- Simu_Ptr := Value_Of (Clock_Statement_Ptr (A_Transition.code.clocks).lvalue.all, My_Scheduler.Variables_Table, A_Transition.code.clocks.line_number, A_Transition.code.clocks.file_name); if (Simu_Ptr.Ptype /= Simulation_clock) and (Simu_Ptr.Ptype /= Simulation_Integer) then Raise_Exception (Type_Error'Identity, "Delay statement expression ; transition name " & To_String (A_Transition.code.name) & To_String ("; " & Lb_Uncompatible_Type_Error (Current_Language))); end if; A_Transition.wakeup_time := Current_Time + Simu_Ptr.Integer_Value; A_Transition.status := Pended; Free (Simu_Ptr); else -- It's an assignment statement which updates user-defined --variables ... -- run it ! -- Dispatch (A_Transition.code.clocks, Priority_Type, Processor_Name, My_Scheduler.Variables_Table, Msg); end if; exception when Constraint_Error => Raise_Exception (Statement_Error'Identity, "transition " & To_String (A_Transition.code.name) & " ; Exception raised :" & Exception_Name & "; " & Exception_Message); when Storage_Error => Raise_Exception (Statement_Error'Identity, "transition " & To_String (A_Transition.code.name) & " ; Exception raised :" & Exception_Name & "; " & Exception_Message); when Program_Error => Raise_Exception (Statement_Error'Identity, "transition " & To_String (A_Transition.code.name) & " ; Exception raised :" & Exception_Name & "; " & Exception_Message); end; end if; -- Run the synchronization statement of the transition -- if A_Transition.code.synchronization /= null then begin Found_A_Section_To_Run := True; A_Section := Generic_Section_Ptr (Search_section (Root_Statement_Pointer, A_Transition.code.synchronization.name)) ; exception when section_Not_Found => Found_A_Section_To_Run := False; end; -- 3 cases : 1) it is an election section (synchronization between an --automaton and the simulation engine) -- 2) it is a priority section (synchronization between an --automaton and the simulation engine) -- 3) it is a synchronization between two automata -- if Found_A_Section_To_Run then if A_Section.section_type = Election_Type then Put_Debug ("Run election section : " & A_Transition.code.synchronization.name); -- The return statement must be run either on the processor, --either on -- the address space depending on the automaton which call the --election_section -- If no processor nor address space can be detected, it means --that the Cheddar program is wrong ! -- -- 3 cases can be found at this step : -- -- 1) "Automaton_Name_Of_The_Transition" is equal to the --processor automaton ... -- it means the scheduling must select amound the tasks of --the processor -- 2) If we found an address space which has an automaton name --equal to "Automaton_Name_Of_The_Transition" ... -- it means the scheduling must select amound the tasks of --this address space -- 3) Otherwise, something is wrong ! (may be the automaton --name ??), then we raise an exception ! -- if (Automaton_Name_Of_The_Transition = My_Scheduler.Automaton_Name) then Election_On_Processor := Processor_Name; Election_On_Address_Space := empty_string; Put_Debug ("Run an election section on address space"); else Found_Automaton := False; for I in 0.. My_Scheduler.Local_Scheduler.nb_entries-1 loop if My_Scheduler.Local_Scheduler.entries(I).scheduler. parameters.scheduler_type = Automata_User_Defined_Protocol then if Get_Automaton_Name (Automata_User_Defined_Scheduler ( My_Scheduler.Local_Scheduler.entries(I).scheduler.all) ) = Automaton_Name_Of_The_Transition then Election_On_Processor := empty_string; Election_On_Address_Space := address_space_scheduler_ptr(My_Scheduler.Local_Scheduler.entries(I)). entity.name; Found_Automaton := True; end if; end if; end loop; if not Found_Automaton then Raise_Exception (Statement_Error'Identity, "Return statement ; transition name " & To_String (A_Transition.code.name) & "; Unable to know if the election " & To_String (A_Transition.code.synchronization.name) & " must be run on the processor task set or on an address space task set"); end if; end if; -- Run the election section now -- dispatch_return_statement (My_Scheduler, Computation_Section_Ptr (A_Section).first_statement, Si, Current_Time, Election_On_Processor, Election_On_Address_Space, My_Dependencies, With_Offsets, With_Precedencies, With_Resources, Elected, No_Task); An_Election_Section_Was_Run := True; else Put_Debug ("Run priority section : " & A_Transition.code.synchronization.name); Dispatch (Computation_Section_Ptr (A_Section).first_statement, Priority_Type, Processor_Name, My_Scheduler.Variables_Table, Msg); end if; end if; end if; -- find the associated automaton and change its current state -- if A_Transition.status = Pended then Check_Delay_Constraints (My_Scheduler, A_Transition, Automaton_Name_Of_The_Transition, Current_Time); else for I in 0 .. My_Scheduler.Automaton_Data.nb_entries - 1 loop if (My_Scheduler.Automaton_Data.entries (I).item = Automaton_Name_Of_The_Transition) then if A_Transition.code.from_state.name = My_Scheduler.Automaton_Data.entries (I).data.current_state. name then My_Scheduler.Automaton_Data.entries (I).data.current_state := A_Transition.code.to_state; exit; end if; end if; end loop; end if; end Fire_A_Transition; -- 1. Change transition status : -- 1.1 Transition which are "ready", "rendezvous" or "guarded" must --be set to "ready" -- 1.2 Transition which are "pended" : stay "pended" if the delay --is not exhausted. If the -- delay is exhausted, update the current location (transition --outgoing location) and -- becomes "ready" -- procedure Check_Delay_Constraints (My_Scheduler : in out Automata_User_Defined_Scheduler; A_Transition : in out Transition_Status; Automaton_Name_Of_The_Transition : in Unbounded_String; Current_Time : in Natural) is begin if A_Transition.status = Pended then if A_Transition.wakeup_time <= Current_Time then -- find the associated automaton and change its current location -- A_Transition.status := Ready; for I in 0 .. My_Scheduler.Automaton_Data.nb_entries - 1 loop if (My_Scheduler.Automaton_Data.entries (I).item = Automaton_Name_Of_The_Transition) then if A_Transition.code.from_state.name = My_Scheduler.Automaton_Data.entries (I).data. current_state.name then My_Scheduler.Automaton_Data.entries (I).data. current_state := A_Transition.code.to_state; exit; end if; end if; end loop; end if; end if; end Check_Delay_Constraints; -- 2. Check reachability for all transition : set transition status to --"unreachable" -- transitions which are not outgoing transition of the current -- location for the corresponding automaton. -- We only analyze transitions with has -- a "ready" status. -- procedure Check_Reachability (My_Scheduler : in out Automata_User_Defined_Scheduler; A_Transition : in out Transition_Status; Automaton_Name_Of_The_Transition : in Unbounded_String) is begin if A_Transition.status = Ready then for I in 0 .. My_Scheduler.Automaton_Data.nb_entries - 1 loop -- Find the right automaton -- if (My_Scheduler.Automaton_Data.entries (I).item = Automaton_Name_Of_The_Transition) then -- find the transition and check it according to the automaton --current states -- if A_Transition.code.from_state.name /= My_Scheduler.Automaton_Data.entries (I).data.current_state. name then A_Transition.status := Unreachable; exit; end if; end if; end loop; end if; end Check_Reachability; -- 4. Check synchronization constraint for all transitions. -- We only analyze transitions with has -- a "ready" status. -- A transition blocked due to a synchronization constraint see its --status becoming "rendezvous". -- procedure Check_Synchronization_Constraints (My_Scheduler : in out Automata_User_Defined_Scheduler; A_Transition : in out Transition_Status; Si : in out Scheduling_Information; Result : in out Scheduling_Sequence_Ptr; Msg : in out Unbounded_String; Current_Time : in Natural; Processor_Name : in Unbounded_String; My_Dependencies : in Tasks_Dependencies_Ptr; With_Offsets : in Boolean; With_Precedencies : in Boolean; With_Resources : in Boolean; Event_To_Generate : in Time_Unit_Event_Type_Boolean_Table; Elected : in out Tasks_Range; No_Task : in out Boolean) is Found_A_Synchronization : Boolean := True; A_Section : Generic_Section_Ptr; begin if A_Transition.status = Ready then -- A synchronization is present ... check it ! -- if A_Transition.code.synchronization /= null then -- First, the synchronization has not to be a section to run -- begin Found_A_Synchronization := False; A_Section := Generic_Section_Ptr (Search_section (Root_Statement_Pointer, A_Transition.code.synchronization. name)); exception when section_Not_Found => Found_A_Synchronization := True; end; -- We found something which is not a section to run ... -- we found something which is a synchronization -- if Found_A_Synchronization then A_Transition.status := Rendezvous; for I in 0 .. My_Scheduler.Transition_Data.nb_entries - 1 loop -- Now, to fire the current transition, we must check that --the other -- transition is also ready to be fired and that .... the --synchronization operator is -- the opposite one -- if My_Scheduler.Transition_Data.entries (I).data.status = Ready then if My_Scheduler.Transition_Data.entries (I).data.code. synchronization /= null then if My_Scheduler.Transition_Data.entries (I).data.code. synchronization.synchronization_type /= A_Transition.code.synchronization. synchronization_type then if My_Scheduler.Transition_Data.entries (I).data. code.synchronization.name = A_Transition.code.synchronization.name then A_Transition.status := Ready; end if; end if; end if; end if; end loop; end if; end if; end if; end Check_Synchronization_Constraints; -- 3. Check guard (eg. timed constraints) for all transition. -- We only analyze transitions with has -- a "ready" status. -- procedure Check_Guard_Constraints (My_Scheduler : in out Automata_User_Defined_Scheduler; A_Transition : in out Transition_Status) is Simu_Ptr : Simulation_Value_Ptr; begin if A_Transition.status = Ready then if A_Transition.code.guards /= null then Simu_Ptr := Value_Of (A_Transition.code.guards.all, My_Scheduler.Variables_Table); if Simu_Ptr.Ptype /= Simulation_Boolean then Raise_Exception (Type_Error'Identity, "Guard expression ; transition name " & To_String (A_Transition.code.name) & To_String (Lb_Comma & Lb_Uncompatible_Type_Error (Current_Language))); end if; -- If the guard is false, block the transition -- if not Simu_Ptr.Boolean_Value then A_Transition.status := Guarded; end if; Free (Simu_Ptr); end if; end if; exception when Constraint_Error => Raise_Exception (Statement_Error'Identity, "transition " & To_String (A_Transition.code.name) & " ; Exception raised :" & Exception_Name & "; " & Exception_Message); when Storage_Error => Raise_Exception (Statement_Error'Identity, "transition " & To_String (A_Transition.code.name) & " ; Exception raised :" & Exception_Name & "; " & Exception_Message); when Program_Error => Raise_Exception (Statement_Error'Identity, "transition " & To_String (A_Transition.code.name) & " ; Exception raised :" & Exception_Name & "; " & Exception_Message); end Check_Guard_Constraints; procedure Specific_Scheduler_Initialization (My_Scheduler : in out Automata_User_Defined_Scheduler; Si : in out Scheduling_Information; Processor_Name : in Unbounded_String; address_space_name : in Unbounded_String; My_Tasks : in out Tasks_Set; My_Schedulers : in Scheduler_table; My_Resources : in out Resources_Set; My_Buffers : in out Buffers_Set; My_Messages : in Messages_Set; Msg : in out Unbounded_String) is Sc_File_Content : Unbounded_String; Sc_File_Name : Unbounded_String; Var : Variables_Range; My_Iterator : sections_Iterator; An_Automaton_Status : Automaton_Status; A_Transition_Status : Transition_Status; A_Section : Generic_Section_Ptr; A_Transition : Transition_Ptr; List_Ite : Transition_Lists_Iterator; begin -- We should check the scheduler behavior syntax ... -- Open_Input (My_Scheduler.parameters.user_defined_scheduler_source); Create_Parametric_Variables (Parser.Variables_Table, My_Tasks); Parser.First_File (My_Scheduler.parameters.user_defined_scheduler_source_file_name); Parser.Yyparse; -- -- And now, read address spaces .sc files -- My_Scheduler.Local_Scheduler := My_Schedulers; for I in 0..My_Schedulers.nb_entries-1 loop if My_Schedulers.entries(I).scheduler /= null then if (Get_Name (My_Schedulers.entries(I).scheduler.all) /= Automata_User_Defined_Protocol) and (Get_Name (My_Schedulers.entries(I).scheduler.all) /= No_Scheduling_Protocol) then Raise_Exception (Syntax_Error'Identity, "Address space " & To_String (address_space_scheduler_ptr(My_Schedulers.entries(I)).entity.name) & " must own either an automaton user defined scheduler or no local scheduler"); else -- We should check the local scheduler behavior syntax ... -- if (Get_Name (My_Schedulers.entries(I).scheduler.all) = Automata_User_Defined_Protocol) then begin Sc_File_Name := Get_Behavior_File_Name (user_defined_Scheduler ( My_Schedulers.entries(I).scheduler.all)); if Sc_File_Name /= empty_string then Sc_File_Content := read_sequential_file (Sc_File_Name); end if; exception when Ada.IO_Exceptions.Name_Error => Raise_Exception (Parametric_File_Error'Identity, To_String (Lb_File (Current_Language) & Lb_Colon & Sc_File_Name & Lb_Comma & Lb_Can_Not_Open_File (Current_Language)) & ", Name_Error"); when Ada.IO_Exceptions.Status_Error => Raise_Exception (Parametric_File_Error'Identity, To_String (Lb_File (Current_Language) & Lb_Colon & Sc_File_Name & Lb_Comma & Lb_Can_Not_Open_File (Current_Language)) & ", Status_Error"); when Ada.IO_Exceptions.Mode_Error => Raise_Exception (Parametric_File_Error'Identity, To_String (Lb_File (Current_Language) & Lb_Colon & Sc_File_Name & Lb_Comma & Lb_Can_Not_Open_File (Current_Language)) & ", Mode_Error"); when Ada.IO_Exceptions.Use_Error => Raise_Exception (Parametric_File_Error'Identity, To_String (Lb_File (Current_Language) & Lb_Colon & Sc_File_Name & Lb_Comma & Lb_Can_Not_Open_File (Current_Language)) & ", Use_Error"); when Ada.IO_Exceptions.Device_Error => Raise_Exception (Parametric_File_Error'Identity, To_String (Lb_File (Current_Language) & Lb_Colon & Sc_File_Name & Lb_Comma & Lb_Can_Not_Open_File (Current_Language)) & ", Device_Error"); when Ada.IO_Exceptions.End_Error => Raise_Exception (Parametric_File_Error'Identity, To_String (Lb_File (Current_Language) & Lb_Colon & Sc_File_Name & Lb_Comma & Lb_Can_Not_Open_File (Current_Language)) & ", End_Error"); when Ada.IO_Exceptions.Data_Error => Raise_Exception (Parametric_File_Error'Identity, To_String (Lb_File (Current_Language) & Lb_Colon & Sc_File_Name & Lb_Comma & Lb_Can_Not_Open_File (Current_Language)) & ", Data_Error"); when Ada.IO_Exceptions.Layout_Error => Raise_Exception (Parametric_File_Error'Identity, To_String (Lb_File (Current_Language) & Lb_Colon & Sc_File_Name & Lb_Comma & Lb_Can_Not_Open_File (Current_Language)) & ", Layout_Error"); when others => Raise_Exception (Parametric_File_Error'Identity, To_String (Lb_File (Current_Language) & Lb_Colon & Sc_File_Name & Lb_Comma & Lb_Can_Not_Open_File (Current_Language))); end; Open_Input (Sc_File_Content); Parser.Next_File (Sc_File_Name); Parser.Yyparse; end if; end if; end if; end loop; ------------------------------------------------------------------------- --- -- Initialize the set of variables of the user-defined scheduler ------------------------------------------------------------------------- --- My_Scheduler.Variables_Table := Parser.Variables_Table; My_Scheduler.Sets_Table := Parser.Sets_Table; -- Initialize user defined constant -- Initialize_Parametric_Variables (My_Scheduler.Variables_Table, My_Messages, My_Buffers, My_Resources, My_Tasks, Processor_Name); -- Initialize user defined variables -- -- "nb_processors" -- Var := Find_Variable (My_Scheduler.Variables_Table, To_Unbounded_String ("nb_processors")); My_Scheduler.Variables_Table.Entries (Var).Simulation.Integer_Value := Si.Number_Of_Processors; -- "nb_address_spaces" -- Var := Find_Variable (My_Scheduler.Variables_Table, To_Unbounded_String ("nb_address_spaces")); My_Scheduler.Variables_Table.Entries (Var).Simulation.Integer_Value := Si.Number_Of_Address_Spaces; -- "simulation_length" -- Var := Find_Variable (My_Scheduler.Variables_Table, To_Unbounded_String ("simulation_length")); My_Scheduler.Variables_Table.Entries (Var).Simulation.Integer_Value := Si.Simulation_Length; ------------------------------------------------------------------------- --- -- Initialize data for the simulation (transition and state data) ------------------------------------------------------------------------- --- My_Scheduler.Root_Statement_Pointer := Parser.Root_Statement_Pointer; initialize (My_Scheduler.Transition_Data); initialize (My_Scheduler.Automaton_Data); if (get_number_of_elements (My_Scheduler.Root_Statement_Pointer) > 0) then reset_iterator (My_Scheduler.Root_Statement_Pointer, My_Iterator); loop current_element (My_Scheduler.Root_Statement_Pointer, A_Section, My_Iterator); if A_Section.all in Synchronization_Section then if is_empty (Synchronization_Section_Ptr (A_Section).transition_list) then Raise_Exception (Syntax_Error'Identity, "automaton section " & To_String (A_Section.name) & " ; an automaton must contain at least one transition"); end if; -- Store simulation data related to the transition -- reset_head_iterator (Synchronization_Section_Ptr (A_Section).transition_list, List_Ite); loop current_element (Synchronization_Section_Ptr (A_Section).transition_list, A_Transition, List_Ite); A_Transition_Status.code := A_Transition; A_Transition_Status.status := Unreachable; A_Transition_Status.wakeup_time := 0; add (My_Scheduler.Transition_Data, A_Section.name, A_Transition_Status); if is_tail_element (Synchronization_Section_Ptr (A_Section). transition_list, List_Ite) then exit; end if; next_element (Synchronization_Section_Ptr (A_Section).transition_list, List_Ite); end loop; -- Store simulation data related to the automaton -- An_Automaton_Status.current_state := Search_initial_state (Synchronization_Section_Ptr (A_Section).state_list); add (My_Scheduler.Automaton_Data, A_Section.name, An_Automaton_Status); end if; exit when is_last_element (My_Scheduler.Root_Statement_Pointer, My_Iterator); next_element (My_Scheduler.Root_Statement_Pointer, My_Iterator); end loop; end if; if (My_Scheduler.Automaton_Data.nb_entries = 0) then Raise_Exception (Syntax_Error'Identity, "An automaton scheduler must contain at least one automaton"); end if; -- At the beginning of the scheduling simulation, all transitions must --be "ready" -- for I in 0 .. My_Scheduler.Transition_Data.nb_entries - 1 loop My_Scheduler.Transition_Data.entries (I).data.status := Ready; end loop; -- Run all start section : we first run start section which come from the -- processor sc file, and then, we run start section from address space --sc files -- -- Load user_defined variable which can be changed by the programmer -- before executing sections -- Load_Read_Write_Interpreter_Variables (My_Scheduler, Si, Processor_Name); if (get_number_of_elements (My_Scheduler.Root_Statement_Pointer) > 0) then reset_iterator (My_Scheduler.Root_Statement_Pointer, My_Iterator); loop current_element (My_Scheduler.Root_Statement_Pointer, A_Section, My_Iterator); if A_Section.all in Computation_Section then if A_Section.section_type = Start_Type then -- Now : run "start" statements -- Dispatch (Computation_Section_Ptr (A_Section).first_statement, Start_Type, Processor_Name, My_Scheduler.Variables_Table, Msg); end if; end if; exit when is_last_element (My_Scheduler.Root_Statement_Pointer, My_Iterator); next_element (My_Scheduler.Root_Statement_Pointer, My_Iterator); end loop; end if; -- After start section, we -- save some task run time information -- Save_Read_Write_Interpreter_Variables (My_Scheduler, Si, Processor_Name); end Specific_Scheduler_Initialization; procedure Set_Automaton_Name (My_Scheduler : in out Automata_User_Defined_Scheduler; To_Set : in Unbounded_String) is begin My_Scheduler.Automaton_Name := To_Set; end Set_Automaton_Name; function Get_Automaton_Name (My_Scheduler : in Automata_User_Defined_Scheduler) return Unbounded_String is begin return My_Scheduler.Automaton_Name; end Get_Automaton_Name; procedure Initialize (A_Scheduler : in out Automata_User_Defined_Scheduler) is begin Reset (A_Scheduler); A_Scheduler.parameters.scheduler_type := Automata_User_Defined_Protocol; A_Scheduler.parameters.user_defined_scheduler_source := empty_string; end Initialize; function Copy (A_Scheduler : in Automata_User_Defined_Scheduler) return Generic_Scheduler_Ptr is Ptr : Automata_User_Defined_Scheduler_Ptr; begin Ptr := new Automata_User_Defined_Scheduler; Ptr.Previously_Elected := A_Scheduler.Previously_Elected; Ptr.parameters := A_Scheduler.parameters; Ptr.Root_Statement_Pointer := A_Scheduler.Root_Statement_Pointer; Ptr.Variables_Table := A_Scheduler.Variables_Table; return Generic_Scheduler_Ptr (Ptr); end Copy; procedure Put (My_Scheduler : in Automata_User_Defined_Scheduler) is begin Put (Generic_Scheduler (My_Scheduler)); put (My_Scheduler.Root_Statement_Pointer); Put (My_Scheduler.Variables_Table); end Put; end Scheduler.user_defined.interpreted.Automata;