1. -- 
  2. -- Uwe R. Zimmer, Australia, 2014 
  3. -- 
  4.  
  5. pragma Initialize_Scalars; 
  6.  
  7. -- Not all policies need to be supported when executing on top of a desktop-operating system 
  8. pragma Task_Dispatching_Policy (FIFO_Within_Priorities); -- default policy 
  9. --  pragma Task_Dispatching_Policy (Non_Preemptive_Within_Priorities); 
  10. --  pragma Task_Dispatching_Policy (EDF_Across_Priorities); 
  11. --  pragma Task_Dispatching_Policy (Round_Robin_Within_Priorities); 
  12.  
  13. pragma Queuing_Policy (FIFO_Queuing); -- default policy 
  14. --  pragma Queuing_Policy (Priority_Queuing); -- does this change the behaviour of this program? 
  15.  
  16. with Ada.Dynamic_Priorities;                use Ada.Dynamic_Priorities; 
  17. with Ada.Text_IO;                           use Ada.Text_IO; 
  18. with Exceptions;                            use Exceptions; 
  19. with Queues; 
  20. with System;                                use System; 
  21.  
  22. procedure Queues_Test is 
  23.    pragma Priority (Priority'Last); 
  24.  
  25.    type Sequence         is (Ready, Set, Go); 
  26.    type Modules          is (Startup, Taxi, Takeoff, Climb, Cruise, Avoid, 
  27.                              Acrobatics, Looping, Inverted, Glidepath, Landing); 
  28.  
  29.    type Queue_Size is mod 2; 
  30.  
  31.    package Avionics_Queue is 
  32.      new Queues (Element => Sequence, Queue_Enum => Modules, Index => Queue_Size); 
  33.    use Avionics_Queue; 
  34.  
  35.    Queue : Protected_Queue; 
  36.  
  37.    task type Avionics_Module is 
  38.       entry Provide_Id (Id : Modules); 
  39.    end Avionics_Module; 
  40.  
  41.    Avionics : array (Modules) of Avionics_Module; 
  42.  
  43.    protected type Synchronizer (No_of_tasks : Positive) is 
  44.       -- holds all tasks before letting them proceed 
  45.       -- and prints out their reported priorities on release. 
  46.       entry Wait_for_all (P : Priority); 
  47.    private 
  48.       Everybody_ready : Boolean := False; 
  49.    end Synchronizer; 
  50.  
  51.    protected body Synchronizer is 
  52.  
  53.       entry Wait_for_all  (P : Priority) 
  54.          when Wait_for_all'Count = No_of_tasks or else Everybody_ready is 
  55.  
  56.       begin 
  57.          Put_Line ("Some task released on priority: " & Priority'Image (P)); 
  58.          Everybody_ready := Wait_for_all'Count /= 0; 
  59.       end Wait_for_all; 
  60.  
  61.    end Synchronizer; 
  62.  
  63.    Avionics_Synchronizer : Synchronizer (Avionics'Length + 1); 
  64.    -- "+ 1" in order to synchronize the main task too. 
  65.  
  66.    task body Avionics_Module is 
  67.  
  68.       Module : Modules; 
  69.  
  70.    begin 
  71.       accept Provide_Id (Id : Modules) do 
  72.          Module := Id; 
  73.       end Provide_Id; 
  74.       -- Spread the available priorities over the defined modules 
  75.       Set_Priority (Priority => Priority (Priority'First + Priority (Float (Modules'Pos (Module) - Modules'Pos (Modules'First)) 
  76.                     * Float (Priority'Last - Priority'First) / Float (Modules'Pos (Modules'Last) - Modules'Pos (Modules'First))))); 
  77.  
  78.       Avionics_Synchronizer.Wait_for_all (Get_Priority); 
  79.  
  80.       declare 
  81.          Accumulator : Natural := Natural (Get_Priority); 
  82.       begin 
  83.          for i in 1 .. 10_000 loop -- burn some CPU time here by incrementing by one 
  84.             for j in 1 .. 10_000 loop -- in a slightly clumsy way. 
  85.                Accumulator := Accumulator + Natural'Min (i / 10_000, j / 10_000); 
  86.             end loop; 
  87.          end loop; 
  88.          Put_Line ("Task " & Modules'Image (Module) & " on priority: " & Priority'Image (Get_Priority) 
  89.                    & " accumulates: " & Natural'Image (Accumulator)); 
  90.       end; 
  91.  
  92.       declare 
  93.          Item : Sequence; 
  94.       begin 
  95.          for Order in Sequence loop 
  96.             Queue.Dequeue (Module) (Item); 
  97.             Put_Line (Modules'Image (Module) & " on priority: " & Priority'Image (Get_Priority) & " removed " & Sequence'Image (Item) & " from queue."); 
  98.          end loop; 
  99.       end; 
  100.  
  101.       Avionics_Synchronizer.Wait_for_all (Get_Priority); 
  102.  
  103.    exception 
  104.       when Exception_Id : others => Show_Exception (Exception_Id); 
  105.    end Avionics_Module; 
  106.  
  107. begin 
  108.    for Module in Modules loop 
  109. --     for Module in reverse Modules loop -- will starting the tasks in reverse will have an effect? 
  110.       Avionics (Module).Provide_Id (Module); 
  111.    end loop; 
  112.  
  113.    Avionics_Synchronizer.Wait_for_all (Get_Priority); 
  114.  
  115.    declare 
  116.       Accumulator : Natural := Natural (Get_Priority); 
  117.    begin 
  118.       for i in 1 .. 10_000 loop -- burn some CPU time here by incrementing by one 
  119.          for j in 1 .. 10_000 loop -- in a slightly clumsy way. 
  120.             Accumulator := Accumulator + Natural'Min (i / 10_000, j / 10_000); 
  121.          end loop; 
  122.       end loop; 
  123.       Put_Line ("Main task on priority: " & Priority'Image (Get_Priority) 
  124.                 & " accumulates: " & Natural'Image (Accumulator)); 
  125.    end; 
  126.  
  127.    for Order in Sequence loop 
  128.       Queue.Enqueue_For_All (Order); 
  129.       Put_Line (Sequence'Image (Order) & " added to queue."); 
  130.    end loop; 
  131.  
  132.    Avionics_Synchronizer.Wait_for_all (Get_Priority); 
  133.  
  134. exception 
  135.    when Exception_Id : others => Show_Exception (Exception_Id); 
  136. end Queues_Test;