wl_lib_0.1.3_1c94dc7c/src/wl-work.adb

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
with Ada.Containers.Doubly_Linked_Lists;
with Ada.Containers.Vectors;

package body WL.Work is

   protected type Handle_Manager is
      procedure Add_Job (Job : Job_Type);
      procedure Job_Finished (Job : Job_Type);
      entry Wait;
   private
      Count : Natural := 0;
   end Handle_Manager;

   type Handle_Manager_Access is access Handle_Manager;

   type Handle_Entry_Record is
      record
         Handle  : Work_Handle;
         Active  : Boolean;
         Manager : Handle_Manager_Access;
      end record;

   type Handle_Entry is access Handle_Entry_Record;

   package Handle_Vectors is
     new Ada.Containers.Vectors (Real_Work_Handle, Handle_Entry);

   protected Handle_Factory is
      procedure New_Handle (Handle : out Work_Handle);
      procedure Close_Handle (Handle : in out Work_Handle);
      function Manager (Handle : Work_Handle) return access Handle_Manager;
   private
      Handles : Handle_Vectors.Vector;
   end Handle_Factory;

   package List_Of_Jobs is
     new Ada.Containers.Doubly_Linked_Lists (Job_Type);

   protected Scheduler is
      function Empty return Boolean;
      procedure Stop;
      procedure Add_Job
        (Job    : Job_Type);
      entry Next_Job
        (Job    : out Job_Type);
   private
      Stopped : Boolean;
      List : List_Of_Jobs.List;
   end Scheduler;

   task type Job_Task;

   type Job_Task_Access is access all Job_Task;

   package Job_Task_Vectors is
     new Ada.Containers.Vectors (Positive, Job_Task_Access);

   Job_Tasks : Job_Task_Vectors.Vector;

   -------------
   -- Add_Job --
   -------------

   procedure Add_Job
     (Handle : Work_Handle;
      Job    : Job_Type)
   is
   begin
      Job.Handle := Handle;
      Handle_Factory.Manager (Handle).Add_Job (Job);
      Scheduler.Add_Job (Job);
   end Add_Job;

   -------------------
   -- Create_Handle --
   -------------------

   function Create_Handle return Work_Handle is
   begin
      return Handle : Work_Handle do
         Handle_Factory.New_Handle (Handle);
      end return;
   end Create_Handle;

   --------------------
   -- Handle_Factory --
   --------------------

   protected body Handle_Factory is

      ------------------
      -- Close_Handle --
      ------------------

      procedure Close_Handle (Handle : in out Work_Handle) is
      begin
         Handles (Handle).Active := False;
      end Close_Handle;

      -------------
      -- Manager --
      -------------

      function Manager (Handle : Work_Handle) return access Handle_Manager is
      begin
         return Handles (Handle).Manager;
      end Manager;

      ----------------
      -- New_Handle --
      ----------------

      procedure New_Handle (Handle : out Work_Handle) is
         Found : Handle_Entry := null;
      begin
         for I in 1 .. Handles.Last_Index loop
            if not Handles (I).Active then
               Found := Handles (I);
               Handle := I;
               exit;
            end if;
         end loop;
         if Found = null then
            Found := new Handle_Entry_Record;
            Found.Manager := new Handle_Manager;
            Handles.Append  (Found);
            Handle := Handles.Last_Index;
         end if;

         Found.Active := True;
         Found.Handle := Handle;

      end New_Handle;

   end Handle_Factory;

   --------------------
   -- Handle_Manager --
   --------------------

   protected body Handle_Manager is

      -------------
      -- Add_Job --
      -------------

      procedure Add_Job (Job : Job_Type) is
         pragma Unreferenced (Job);
      begin
         Count := Count + 1;
      end Add_Job;

      ------------------
      -- Job_Finished --
      ------------------

      procedure Job_Finished (Job : Job_Type) is
         pragma Unreferenced (Job);
      begin
         Count := Count - 1;
      end Job_Finished;

      ----------
      -- Wait --
      ----------

      entry Wait when Count = 0 is
      begin
         null;
      end Wait;

   end Handle_Manager;

   --------------
   -- Job_Task --
   --------------

   task body Job_Task is
      Current : Job_Type;
   begin
      loop
         Scheduler.Next_Job (Current);
         exit when Current = null or else Current.Handle = 0;
         Current.Execute;
         Handle_Factory.Manager (Current.Handle).Job_Finished (Current);
      end loop;
   end Job_Task;

   ---------------
   -- Scheduler --
   ---------------

   protected body Scheduler is

      -------------
      -- Add_Job --
      -------------

      procedure Add_Job
        (Job    : Job_Type)
      is
      begin
         List.Append (Job);
      end Add_Job;

      -----------
      -- Empty --
      -----------

      function Empty return Boolean is
      begin
         return List.Is_Empty;
      end Empty;

      --------------
      -- Next_Job --
      --------------

      entry Next_Job
        (Job    : out Job_Type)
        when not Empty or else Stopped
      is
      begin
         if Stopped then
            Job := null;
         else
            Job := List.First_Element;
            List.Delete_First;
         end if;
      end Next_Job;

      ----------
      -- Stop --
      ----------

      procedure Stop is
      begin
         Stopped := True;
      end Stop;

   end Scheduler;

   --------------------
   -- Set_Task_Count --
   --------------------

   procedure Set_Task_Count (Count : Positive) is
   begin
      Job_Tasks.Clear;
      for I in 1 .. Count loop
         Job_Tasks.Append (new Job_Task);
      end loop;
   end Set_Task_Count;

   ---------------------
   -- Stop_Work_Tasks --
   ---------------------

   procedure Stop_Work_Tasks is
   begin
      Scheduler.Stop;
   end Stop_Work_Tasks;

   ----------
   -- Wait --
   ----------

   procedure Wait (Handle : in out Work_Handle) is
   begin
      Handle_Factory.Manager (Handle).Wait;
      Handle_Factory.Close_Handle (Handle);
   end Wait;

end WL.Work;