------------------------------------------------------------------------------ ------------------------------------------------------------------------------ -- 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 Scheduler; use Scheduler; with Scheduling_Analysis; use Scheduling_Analysis; use Scheduling_Analysis.Double_Tasks_Parameters_Package; with Scheduler.Fixed_Priority; use Scheduler.Fixed_Priority; with Scheduler.Fixed_Priority.Hpf; use Scheduler.Fixed_Priority.Hpf; with text_io; use text_io; with debug; use debug; with expressions; use expressions; with Ada.IO_Exceptions; use Ada.IO_Exceptions; with Ada.Exceptions; use Ada.Exceptions; with GNAT.Current_Exception; use GNAT.Current_Exception; with translate; use translate; package body Scheduler.Hierarchical.offline is procedure Initialize (A_Scheduler : in out Hierarchical_offline_Scheduler) is begin Reset (A_Scheduler); A_Scheduler.parameters.scheduler_type := Hierarchical_Cyclic_Protocol; end Initialize; function Copy (A_Scheduler : in Hierarchical_offline_Scheduler) return Generic_Scheduler_Ptr is Ptr : Hierarchical_offline_Scheduler_Ptr; begin Ptr := new Hierarchical_offline_Scheduler; Ptr.parameters := A_Scheduler.parameters; Ptr.Previously_Elected := A_Scheduler.Previously_Elected; return Generic_Scheduler_Ptr (Ptr); end Copy; function Get_event_table (My_Scheduler : in Hierarchical_offline_Scheduler) return scheduling_table_ptr is begin return my_scheduler.address_space_scheduling_table; end get_event_table; procedure set_event_table (My_Scheduler : in out Hierarchical_offline_Scheduler; a_table : in scheduling_table_ptr) is begin my_scheduler.address_space_scheduling_table:=a_table; end set_event_table; procedure Check_Before_Scheduling (My_Scheduler : in Hierarchical_offline_Scheduler; My_Tasks : in Tasks_Set; Processor_Name : in Unbounded_String) is begin null; end Check_Before_Scheduling; procedure Specific_Scheduler_Initialization (My_Scheduler : in out Hierarchical_offline_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 begin -- Save local address schedulers -- My_Scheduler.Local_Scheduler := my_schedulers; -- We start with the first entry of the address space -- offline scheduling table -- my_scheduler.scheduling_table_index:=0; -- We check taht we have an address space scheduling table -- if my_scheduler.address_space_scheduling_table=null then Raise_Exception (Parametric_File_Error'Identity, To_String (Lb_File (Current_Language) & Lb_Colon & My_Scheduler.parameters. user_defined_scheduler_source_file_name & Lb_Comma & " Off-line address space scheduling table is mandatory")); end if; -- We check we the address space scheduling table has data for ONE and only ONE processor -- if my_scheduler.address_space_scheduling_table.nb_entries/=1 then Raise_Exception (Parametric_File_Error'Identity, To_String (Lb_File (Current_Language) & Lb_Colon & My_Scheduler.parameters. user_defined_scheduler_source_file_name & Lb_Comma & " Off-line address space scheduling table must contain events of one and only one processor here")); end if; -- We check we the address space scheduling table is not empty -- if my_scheduler.address_space_scheduling_table.entries(0).data.result.nb_entries<=0 then Raise_Exception (Parametric_File_Error'Identity, To_String (Lb_File (Current_Language) & Lb_Colon & My_Scheduler.parameters. user_defined_scheduler_source_file_name & Lb_Comma & " Empty off-line address space scheduling table not allowed here")); end if; -- We check that the event table for address_space scheduling has -- an address space activation event for all of its entries -- for i in 0 .. my_scheduler.address_space_scheduling_table.entries(0).data.result.nb_entries-1 loop if my_scheduler.address_space_scheduling_table.entries(0).data.result.entries(i).data.type_of_event /= address_space_activation then Raise_Exception (Parametric_File_Error'Identity, To_String (Lb_File (Current_Language) & Lb_Colon & My_Scheduler.parameters. user_defined_scheduler_source_file_name & Lb_Comma & " Off-line address space scheduling table must only contain address_space_activation events")); end if; end loop; -- We check that the event table, for its first entry, has an event for time 0 -- if my_scheduler.address_space_scheduling_table.entries(0).data.result.entries(0).item /= 0 then Raise_Exception (Parametric_File_Error'Identity, To_String (Lb_File (Current_Language) & Lb_Colon & My_Scheduler.parameters. user_defined_scheduler_source_file_name & Lb_Comma & " First entry of off-line address space scheduling table must provide an event for time zero ")); end if; -- Look for the local scheduler to run in the next units of time -- i.e. scheduler for the first entry of the address space scheduling table -- for i in 0..My_Scheduler.Local_Scheduler.nb_entries-1 loop if address_space_scheduler_ptr(My_Scheduler.Local_Scheduler.entries(i)).entity.name = my_scheduler.address_space_scheduling_table.entries(0).data.result.entries(0).data.activation_address_space then My_Scheduler.address_space_scheduler_index := i; exit; end if; end loop; -- Do local scheduler initializations -- for i in 0..My_Scheduler.Local_Scheduler.nb_entries-1 loop Specific_Scheduler_Initialization (My_Scheduler.Local_Scheduler.entries(i).scheduler.all, Si, Processor_Name, address_space_scheduler_ptr(My_Scheduler.Local_Scheduler.entries(i)).entity.name, My_Tasks, my_schedulers, My_Resources, My_Buffers, My_Messages, Msg); end loop; end Specific_Scheduler_Initialization; -- ellidiss simulation optimization procedure Increase_Used_CPU ( My_Scheduler : in out Hierarchical_offline_Scheduler; Value : in Natural) is begin address_space_scheduler_ptr(My_Scheduler.Local_Scheduler.entries(My_Scheduler.address_space_scheduler_index)).used_cpu := address_space_scheduler_ptr(My_Scheduler.Local_Scheduler.entries(My_Scheduler.address_space_scheduler_index)).used_cpu + Value; end Increase_Used_CPU; procedure Do_Election (My_Scheduler : in out Hierarchical_offline_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 A_Item : Time_Unit_Event_ptr; begin -- generate an address space activation event for this first entry in the scheduling table -- in the beginning of the simulation -- if current_time = 0 then if Event_To_Generate (address_space_Activation) then A_Item := new Time_Unit_Event (address_space_activation); A_Item.activation_address_space := my_scheduler.address_space_scheduling_table.entries(0).data.result.entries(0).data.activation_address_space; A_Item.duration:= my_scheduler.address_space_scheduling_table.entries(0).data.result.entries(0).data.duration; add (Result.all, 0, a_item); end if; end if; -- Call the scheduler associated to the current address space -- No method dispatch => some schedulers are not allowed -- put_debug("Active address space is " & to_string(address_space_scheduler_ptr(My_Scheduler.Local_Scheduler.entries(My_Scheduler.address_space_scheduler_index)).entity.name), very_verbose ); Do_Election ( My_Scheduler.Local_Scheduler.entries(My_Scheduler.address_space_scheduler_index). scheduler.all, Si, Result, Msg, Current_Time, Processor_Name, address_space_scheduler_ptr(My_Scheduler.Local_Scheduler.entries(My_Scheduler.address_space_scheduler_index)). entity.name, My_Dependencies, With_Offsets, With_Precedencies, With_Resources, With_jitters, With_minimize_preemption, Event_To_Generate, Elected, No_Task); ------------------------------------------------------ -- Update variables for multi core scheduling ------------------------------------------------------ -- Assign the task to the current core unit and put it -- in the already run state -- my_scheduler.corresponding_core_unit:= My_Scheduler.Local_Scheduler.entries(My_Scheduler.address_space_scheduler_index).scheduler.corresponding_core_unit; -- Check if we must switch the activated/schedulable address space -- address_space_scheduler_ptr(My_Scheduler.Local_Scheduler.entries(My_Scheduler.address_space_scheduler_index)).used_cpu := address_space_scheduler_ptr(My_Scheduler.Local_Scheduler.entries(My_Scheduler.address_space_scheduler_index)). used_cpu + 1; if address_space_scheduler_ptr(My_Scheduler.Local_Scheduler.entries(My_Scheduler.address_space_scheduler_index)). used_cpu >= my_scheduler.address_space_scheduling_table.entries(0).data.result.entries(my_scheduler.scheduling_table_index).data.duration then -- Address space switching -- put_debug("Change of running address space", very_verbose); -- do Address space switch -- my_scheduler.scheduling_table_index:=+my_scheduler.scheduling_table_index+1; if my_scheduler.scheduling_table_index = my_scheduler.address_space_scheduling_table.entries(0).data.result.nb_entries then my_scheduler.scheduling_table_index:=0; end if; -- Reset cpu usage of the previous scheduler -- address_space_scheduler_ptr(My_Scheduler.Local_Scheduler.entries(My_Scheduler.address_space_scheduler_index)). used_cpu := 0; -- Look for the local scheduler to run in the next units of time -- for i in 0..My_Scheduler.Local_Scheduler.nb_entries-1 loop if address_space_scheduler_ptr(My_Scheduler.Local_Scheduler.entries(i)).entity.name = my_scheduler.address_space_scheduling_table.entries(0).data.result.entries(my_scheduler.scheduling_table_index).data.activation_address_space then My_Scheduler.address_space_scheduler_index := i; exit; end if; end loop; -- generate address space activation event -- if Event_To_Generate (address_space_Activation) then A_Item := new Time_Unit_Event (address_space_activation); A_Item.activation_address_space := my_scheduler.address_space_scheduling_table.entries(0).data.result.entries(my_scheduler.scheduling_table_index).data.activation_address_space; A_Item.duration:= my_scheduler.address_space_scheduling_table.entries(0).data.result.entries(my_scheduler.scheduling_table_index).data.duration; add (Result.all, current_time+1, a_item); end if; end if; end Do_Election; function Build_Resource (My_Scheduler : in Hierarchical_offline_Scheduler; A_Resource : Generic_Resource_Ptr) return Shared_Resource_Ptr is New_A_Resource : Fixed_Priority_Resource_Ptr; begin New_A_Resource := new Fixed_Priority_Resource; New_A_Resource.Shared := A_Resource; -- Set priority ceiling of the resource -- New_A_Resource.Priority_Ceiling := Low_Priority; return Shared_Resource_Ptr (New_A_Resource); end Build_Resource; function Build_Tcb (My_Scheduler : in Hierarchical_offline_Scheduler; A_Task : Generic_Task_Ptr) return Tcb_Ptr is A_Tcb : Hpf_Tcb_Ptr; begin A_Tcb := new Hpf_Tcb; Initialize (Tcb (A_Tcb.all), A_Task); Initialize (Fixed_Priority_Tcb (A_Tcb.all)); Initialize (A_Tcb.all); return Tcb_Ptr (A_Tcb); end Build_Tcb; end Scheduler.Hierarchical.offline;