1. -- 
  2. -- Jan & Uwe R. Zimmer, Australia, July 2011 
  3. -- 
  4.  
  5. with Exceptions;            use Exceptions; 
  6. with Swarm_Control;         use Swarm_Control; 
  7. with Swarm_Data;            use Swarm_Data; 
  8. with Swarm_Structures;      use Swarm_Structures; 
  9. with Swarm_Structures_Base; use Swarm_Structures_Base; 
  10.  
  11. package body Swarm_Control_Concurrent_Generic is 
  12.  
  13.    -- 
  14.  
  15.    protected Synchroniser is 
  16.       entry All_Jobs_Done; 
  17.    private 
  18.       Synchroniser_Open : Boolean := False; 
  19.    end Synchroniser; 
  20.  
  21.    -- 
  22.  
  23.    protected body Synchroniser is 
  24.       entry All_Jobs_Done when 
  25.         All_Jobs_Done'Count = No_Of_CPU_Cores + 1 or else Synchroniser_Open is 
  26.       begin 
  27.          Synchroniser_Open := All_Jobs_Done'Count > 0; 
  28.       end All_Jobs_Done; 
  29.    end Synchroniser; 
  30.  
  31.    -- 
  32.    -- 
  33.    -- 
  34.  
  35.    task type Worker is 
  36.       entry Set_Job (Job : Job_Type; Start_Index, End_Index : Swarm_Element_Index); 
  37.    end Worker; 
  38.  
  39.    -- 
  40.  
  41.    Workers : array (1 .. No_Of_CPU_Cores) of Worker; 
  42.  
  43.    -- 
  44.  
  45.    task body Worker is 
  46.  
  47.       Current_Job   : Job_Type; 
  48.       Start, Finish : Swarm_Element_Index; 
  49.  
  50.    begin 
  51.       loop 
  52.          select 
  53.             accept Set_Job (Job : Job_Type; Start_Index, End_Index : Swarm_Element_Index) do 
  54.                Current_Job := Job; 
  55.                Start       := Start_Index; 
  56.                Finish      := End_Index; 
  57.             end Set_Job; 
  58.             for Element_Index in Start .. Finish loop 
  59.                case Current_Job is 
  60.                   when Set_Accelerations => Set_Acceleration (Element_Index); 
  61.                   when Forward_Messages  => Forward_Messages (Element_Index); 
  62.                   when Move_Elements     => Move_Element     (Element_Index); 
  63.                   when Update_Rotations  => Update_Rotation  (Element_Index); 
  64.                   when No_Job            => null; 
  65.                end case; 
  66.             end loop; 
  67.             Synchroniser.All_Jobs_Done; 
  68.          or 
  69.             terminate; 
  70.          end select; 
  71.       end loop; 
  72.  
  73.    exception 
  74.       when E : others => Show_Exception (E); 
  75.  
  76.    end Worker; 
  77.  
  78.    -------------------------------------- 
  79.    -- Distribute_Jobs -- 
  80.    -------------------------------------- 
  81.  
  82.    procedure Distribute_Jobs (Job : Job_Type) is 
  83.  
  84.       use Swarm_Vectors; 
  85.  
  86.       First_Element_Ix  : constant Swarm_Element_Index := First_Index (Swarm_State); 
  87.       Last_Element_Ix   : constant Swarm_Element_Index := Last_Index  (Swarm_State); 
  88.       No_Of_Elements    : constant Swarm_Element_Index := Swarm_Element_Index (Length (Swarm_State)); 
  89.       Elements_Per_Task : constant Swarm_Element_Index := Natural'Max (1, No_Of_Elements / No_Of_CPU_Cores); 
  90.  
  91.    begin 
  92.       for Task_Index in Workers'First .. Workers'Last - 1 loop 
  93.          declare 
  94.             From_Ix : constant Integer := Swarm_Element_Index ((Integer (Task_Index) - Workers'First)     * Elements_Per_Task + First_Element_Ix); 
  95.             To_Ix   : constant Integer := Swarm_Element_Index ((Integer (Task_Index) - Workers'First + 1) * Elements_Per_Task + First_Element_Ix - 1); 
  96.          begin 
  97.             if From_Ix >= First_Element_Ix and then To_Ix <= Last_Element_Ix then 
  98.                Workers (Task_Index).Set_Job (Job, From_Ix, To_Ix); 
  99.             else 
  100.                Workers (Task_Index).Set_Job (No_Job, From_Ix, To_Ix); 
  101.             end if; 
  102.          end; 
  103.       end loop; 
  104.  
  105.       declare 
  106.          From_Ix : constant Integer := Swarm_Element_Index ((Integer (Workers'Last) - Workers'First)      * Elements_Per_Task + First_Element_Ix); 
  107.          To_Ix   : constant Integer := Last_Element_Ix; 
  108.       begin 
  109.          if From_Ix >= First_Element_Ix and then To_Ix <= Last_Element_Ix then 
  110.             Workers (Workers'Last).Set_Job (Job, From_Ix, To_Ix); 
  111.          else 
  112.             Workers (Workers'Last).Set_Job (No_Job, From_Ix, To_Ix); 
  113.          end if; 
  114.       end; 
  115.  
  116.       Synchroniser.All_Jobs_Done; 
  117.    end Distribute_Jobs; 
  118.  
  119.    -- 
  120.  
  121. end Swarm_Control_Concurrent_Generic;