OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [gcc/] [ada/] [s-tasque.adb] - Blame information for rev 717

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 706 jeremybenn
------------------------------------------------------------------------------
2
--                                                                          --
3
--                  GNAT RUN-TIME LIBRARY (GNARL) COMPONENTS                --
4
--                                                                          --
5
--                 S Y S T E M . T A S K I N G . Q U E U I N G              --
6
--                                                                          --
7
--                                  B o d y                                 --
8
--                                                                          --
9
--         Copyright (C) 1992-2009, Free Software Foundation, Inc.          --
10
--                                                                          --
11
-- GNARL is free software; you can  redistribute it  and/or modify it under --
12
-- terms of the  GNU General Public License as published  by the Free Soft- --
13
-- ware  Foundation;  either version 3,  or (at your option) any later ver- --
14
-- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
15
-- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
16
-- or FITNESS FOR A PARTICULAR PURPOSE.                                     --
17
--                                                                          --
18
-- As a special exception under Section 7 of GPL version 3, you are granted --
19
-- additional permissions described in the GCC Runtime Library Exception,   --
20
-- version 3.1, as published by the Free Software Foundation.               --
21
--                                                                          --
22
-- You should have received a copy of the GNU General Public License and    --
23
-- a copy of the GCC Runtime Library Exception along with this program;     --
24
-- see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see    --
25
-- <http://www.gnu.org/licenses/>.                                          --
26
--                                                                          --
27
-- GNARL was developed by the GNARL team at Florida State University.       --
28
-- Extensive contributions were provided by Ada Core Technologies, Inc.     --
29
--                                                                          --
30
------------------------------------------------------------------------------
31
 
32
--  This version of the body implements queueing policy according to the policy
33
--  specified by the pragma Queuing_Policy. When no such pragma is specified
34
--  FIFO policy is used as default.
35
 
36
with System.Task_Primitives.Operations;
37
with System.Tasking.Initialization;
38
with System.Parameters;
39
 
40
package body System.Tasking.Queuing is
41
 
42
   use Parameters;
43
   use Task_Primitives.Operations;
44
   use Protected_Objects;
45
   use Protected_Objects.Entries;
46
 
47
   --  Entry Queues implemented as doubly linked list
48
 
49
   Queuing_Policy : Character;
50
   pragma Import (C, Queuing_Policy, "__gl_queuing_policy");
51
 
52
   Priority_Queuing : constant Boolean := Queuing_Policy = 'P';
53
 
54
   procedure Send_Program_Error
55
     (Self_ID    : Task_Id;
56
      Entry_Call : Entry_Call_Link);
57
   --  Raise Program_Error in the caller of the specified entry call
58
 
59
   function Check_Queue (E : Entry_Queue) return Boolean;
60
   --  Check the validity of E.
61
   --  Return True if E is valid, raise Assert_Failure if assertions are
62
   --  enabled and False otherwise.
63
 
64
   -----------------------------
65
   -- Broadcast_Program_Error --
66
   -----------------------------
67
 
68
   procedure Broadcast_Program_Error
69
     (Self_ID      : Task_Id;
70
      Object       : Protection_Entries_Access;
71
      Pending_Call : Entry_Call_Link;
72
      RTS_Locked   : Boolean := False)
73
   is
74
      Entry_Call : Entry_Call_Link;
75
   begin
76
      if Single_Lock and then not RTS_Locked then
77
         Lock_RTS;
78
      end if;
79
 
80
      if Pending_Call /= null then
81
         Send_Program_Error (Self_ID, Pending_Call);
82
      end if;
83
 
84
      for E in Object.Entry_Queues'Range loop
85
         Dequeue_Head (Object.Entry_Queues (E), Entry_Call);
86
 
87
         while Entry_Call /= null loop
88
            pragma Assert (Entry_Call.Mode /= Conditional_Call);
89
 
90
            Send_Program_Error (Self_ID, Entry_Call);
91
            Dequeue_Head (Object.Entry_Queues (E), Entry_Call);
92
         end loop;
93
      end loop;
94
 
95
      if Single_Lock and then not RTS_Locked then
96
         Unlock_RTS;
97
      end if;
98
   end Broadcast_Program_Error;
99
 
100
   -----------------
101
   -- Check_Queue --
102
   -----------------
103
 
104
   function Check_Queue (E : Entry_Queue) return Boolean is
105
      Valid   : Boolean := True;
106
      C, Prev : Entry_Call_Link;
107
 
108
   begin
109
      if E.Head = null then
110
         if E.Tail /= null then
111
            Valid := False;
112
            pragma Assert (Valid);
113
         end if;
114
      else
115
         if E.Tail = null
116
           or else E.Tail.Next /= E.Head
117
         then
118
            Valid := False;
119
            pragma Assert (Valid);
120
 
121
         else
122
            C := E.Head;
123
 
124
            loop
125
               Prev := C;
126
               C := C.Next;
127
 
128
               if C = null then
129
                  Valid := False;
130
                  pragma Assert (Valid);
131
                  exit;
132
               end if;
133
 
134
               if Prev /= C.Prev then
135
                  Valid := False;
136
                  pragma Assert (Valid);
137
                  exit;
138
               end if;
139
 
140
               exit when C = E.Head;
141
            end loop;
142
 
143
            if Prev /= E.Tail then
144
               Valid := False;
145
               pragma Assert (Valid);
146
            end if;
147
         end if;
148
      end if;
149
 
150
      return Valid;
151
   end Check_Queue;
152
 
153
   -------------------
154
   -- Count_Waiting --
155
   -------------------
156
 
157
   --  Return number of calls on the waiting queue of E
158
 
159
   function Count_Waiting (E : Entry_Queue) return Natural is
160
      Count   : Natural;
161
      Temp    : Entry_Call_Link;
162
 
163
   begin
164
      pragma Assert (Check_Queue (E));
165
 
166
      Count := 0;
167
 
168
      if E.Head /= null then
169
         Temp := E.Head;
170
 
171
         loop
172
            Count := Count + 1;
173
            exit when E.Tail = Temp;
174
            Temp := Temp.Next;
175
         end loop;
176
      end if;
177
 
178
      return Count;
179
   end Count_Waiting;
180
 
181
   -------------
182
   -- Dequeue --
183
   -------------
184
 
185
   --  Dequeue call from entry_queue E
186
 
187
   procedure Dequeue (E : in out Entry_Queue; Call : Entry_Call_Link) is
188
   begin
189
      pragma Assert (Check_Queue (E));
190
      pragma Assert (Call /= null);
191
 
192
      --  If empty queue, simply return
193
 
194
      if E.Head = null then
195
         return;
196
      end if;
197
 
198
      pragma Assert (Call.Prev /= null);
199
      pragma Assert (Call.Next /= null);
200
 
201
      Call.Prev.Next := Call.Next;
202
      Call.Next.Prev := Call.Prev;
203
 
204
      if E.Head = Call then
205
 
206
         --  Case of one element
207
 
208
         if E.Tail = Call then
209
            E.Head := null;
210
            E.Tail := null;
211
 
212
         --  More than one element
213
 
214
         else
215
            E.Head := Call.Next;
216
         end if;
217
 
218
      elsif E.Tail = Call then
219
         E.Tail := Call.Prev;
220
      end if;
221
 
222
      --  Successfully dequeued
223
 
224
      Call.Prev := null;
225
      Call.Next := null;
226
      pragma Assert (Check_Queue (E));
227
   end Dequeue;
228
 
229
   ------------------
230
   -- Dequeue_Call --
231
   ------------------
232
 
233
   procedure Dequeue_Call (Entry_Call : Entry_Call_Link) is
234
      Called_PO : Protection_Entries_Access;
235
 
236
   begin
237
      pragma Assert (Entry_Call /= null);
238
 
239
      if Entry_Call.Called_Task /= null then
240
         Dequeue
241
           (Entry_Call.Called_Task.Entry_Queues
242
             (Task_Entry_Index (Entry_Call.E)),
243
           Entry_Call);
244
 
245
      else
246
         Called_PO := To_Protection (Entry_Call.Called_PO);
247
         Dequeue (Called_PO.Entry_Queues
248
             (Protected_Entry_Index (Entry_Call.E)),
249
           Entry_Call);
250
      end if;
251
   end Dequeue_Call;
252
 
253
   ------------------
254
   -- Dequeue_Head --
255
   ------------------
256
 
257
   --  Remove and return the head of entry_queue E
258
 
259
   procedure Dequeue_Head
260
     (E    : in out Entry_Queue;
261
      Call : out Entry_Call_Link)
262
   is
263
      Temp : Entry_Call_Link;
264
 
265
   begin
266
      pragma Assert (Check_Queue (E));
267
      --  If empty queue, return null pointer
268
 
269
      if E.Head = null then
270
         Call := null;
271
         return;
272
      end if;
273
 
274
      Temp := E.Head;
275
 
276
      --  Case of one element
277
 
278
      if E.Head = E.Tail then
279
         E.Head := null;
280
         E.Tail := null;
281
 
282
      --  More than one element
283
 
284
      else
285
         pragma Assert (Temp /= null);
286
         pragma Assert (Temp.Next /= null);
287
         pragma Assert (Temp.Prev /= null);
288
 
289
         E.Head := Temp.Next;
290
         Temp.Prev.Next := Temp.Next;
291
         Temp.Next.Prev := Temp.Prev;
292
      end if;
293
 
294
      --  Successfully dequeued
295
 
296
      Temp.Prev := null;
297
      Temp.Next := null;
298
      Call := Temp;
299
      pragma Assert (Check_Queue (E));
300
   end Dequeue_Head;
301
 
302
   -------------
303
   -- Enqueue --
304
   -------------
305
 
306
   --  Enqueue call at the end of entry_queue E, for FIFO queuing policy.
307
   --  Enqueue call priority ordered, FIFO at same priority level, for
308
   --  Priority queuing policy.
309
 
310
   procedure Enqueue (E : in out Entry_Queue; Call : Entry_Call_Link) is
311
      Temp : Entry_Call_Link := E.Head;
312
 
313
   begin
314
      pragma Assert (Check_Queue (E));
315
      pragma Assert (Call /= null);
316
 
317
      --  Priority Queuing
318
 
319
      if Priority_Queuing then
320
         if Temp = null then
321
            Call.Prev := Call;
322
            Call.Next := Call;
323
            E.Head := Call;
324
            E.Tail := Call;
325
 
326
         else
327
            loop
328
               --  Find the entry that the new guy should precede
329
 
330
               exit when Call.Prio > Temp.Prio;
331
               Temp := Temp.Next;
332
 
333
               if Temp = E.Head then
334
                  Temp := null;
335
                  exit;
336
               end if;
337
            end loop;
338
 
339
            if Temp = null then
340
               --  Insert at tail
341
 
342
               Call.Prev := E.Tail;
343
               Call.Next := E.Head;
344
               E.Tail := Call;
345
 
346
            else
347
               Call.Prev := Temp.Prev;
348
               Call.Next := Temp;
349
 
350
               --  Insert at head
351
 
352
               if Temp = E.Head then
353
                  E.Head := Call;
354
               end if;
355
            end if;
356
 
357
            pragma Assert (Call.Prev /= null);
358
            pragma Assert (Call.Next /= null);
359
 
360
            Call.Prev.Next := Call;
361
            Call.Next.Prev := Call;
362
         end if;
363
 
364
         pragma Assert (Check_Queue (E));
365
         return;
366
      end if;
367
 
368
      --  FIFO Queuing
369
 
370
      if E.Head = null then
371
         E.Head := Call;
372
      else
373
         E.Tail.Next := Call;
374
         Call.Prev   := E.Tail;
375
      end if;
376
 
377
      E.Head.Prev := Call;
378
      E.Tail      := Call;
379
      Call.Next   := E.Head;
380
      pragma Assert (Check_Queue (E));
381
   end Enqueue;
382
 
383
   ------------------
384
   -- Enqueue_Call --
385
   ------------------
386
 
387
   procedure Enqueue_Call (Entry_Call : Entry_Call_Link) is
388
      Called_PO : Protection_Entries_Access;
389
 
390
   begin
391
      pragma Assert (Entry_Call /= null);
392
 
393
      if Entry_Call.Called_Task /= null then
394
         Enqueue
395
           (Entry_Call.Called_Task.Entry_Queues
396
              (Task_Entry_Index (Entry_Call.E)),
397
           Entry_Call);
398
 
399
      else
400
         Called_PO := To_Protection (Entry_Call.Called_PO);
401
         Enqueue (Called_PO.Entry_Queues
402
             (Protected_Entry_Index (Entry_Call.E)),
403
           Entry_Call);
404
      end if;
405
   end Enqueue_Call;
406
 
407
   ----------
408
   -- Head --
409
   ----------
410
 
411
   --  Return the head of entry_queue E
412
 
413
   function Head (E : Entry_Queue) return Entry_Call_Link is
414
   begin
415
      pragma Assert (Check_Queue (E));
416
      return E.Head;
417
   end Head;
418
 
419
   -------------
420
   -- Onqueue --
421
   -------------
422
 
423
   --  Return True if Call is on any entry_queue at all
424
 
425
   function Onqueue (Call : Entry_Call_Link) return Boolean is
426
   begin
427
      pragma Assert (Call /= null);
428
 
429
      --  Utilize the fact that every queue is circular, so if Call
430
      --  is on any queue at all, Call.Next must NOT be null.
431
 
432
      return Call.Next /= null;
433
   end Onqueue;
434
 
435
   --------------------------------
436
   -- Requeue_Call_With_New_Prio --
437
   --------------------------------
438
 
439
   procedure Requeue_Call_With_New_Prio
440
     (Entry_Call : Entry_Call_Link; Prio : System.Any_Priority) is
441
   begin
442
      pragma Assert (Entry_Call /= null);
443
 
444
      --  Perform a queue reordering only when the policy being used is the
445
      --  Priority Queuing.
446
 
447
      if Priority_Queuing then
448
         if Onqueue (Entry_Call) then
449
            Dequeue_Call (Entry_Call);
450
            Entry_Call.Prio := Prio;
451
            Enqueue_Call (Entry_Call);
452
         end if;
453
      end if;
454
   end Requeue_Call_With_New_Prio;
455
 
456
   ---------------------------------
457
   -- Select_Protected_Entry_Call --
458
   ---------------------------------
459
 
460
   --  Select an entry of a protected object. Selection depends on the
461
   --  queuing policy being used.
462
 
463
   procedure Select_Protected_Entry_Call
464
     (Self_ID : Task_Id;
465
      Object  : Protection_Entries_Access;
466
      Call    : out Entry_Call_Link)
467
   is
468
      Entry_Call  : Entry_Call_Link;
469
      Temp_Call   : Entry_Call_Link;
470
      Entry_Index : Protected_Entry_Index := Null_Entry; -- stop warning
471
 
472
   begin
473
      Entry_Call := null;
474
 
475
      begin
476
         --  Priority queuing case
477
 
478
         if Priority_Queuing then
479
            for J in Object.Entry_Queues'Range loop
480
               Temp_Call := Head (Object.Entry_Queues (J));
481
 
482
               if Temp_Call /= null
483
                 and then
484
                   Object.Entry_Bodies
485
                     (Object.Find_Body_Index
486
                       (Object.Compiler_Info, J)).
487
                          Barrier (Object.Compiler_Info, J)
488
               then
489
                  if Entry_Call = null
490
                    or else Entry_Call.Prio < Temp_Call.Prio
491
                  then
492
                     Entry_Call := Temp_Call;
493
                     Entry_Index := J;
494
                  end if;
495
               end if;
496
            end loop;
497
 
498
         --  FIFO queueing case
499
 
500
         else
501
            for J in Object.Entry_Queues'Range loop
502
               Temp_Call := Head (Object.Entry_Queues (J));
503
 
504
               if Temp_Call /= null
505
                 and then
506
                   Object.Entry_Bodies
507
                     (Object.Find_Body_Index
508
                       (Object.Compiler_Info, J)).
509
                          Barrier (Object.Compiler_Info, J)
510
               then
511
                  Entry_Call := Temp_Call;
512
                  Entry_Index := J;
513
                  exit;
514
               end if;
515
            end loop;
516
         end if;
517
 
518
      exception
519
         when others =>
520
            Broadcast_Program_Error (Self_ID, Object, null);
521
      end;
522
 
523
      --  If a call was selected, dequeue it and return it for service
524
 
525
      if Entry_Call /= null then
526
         Temp_Call := Entry_Call;
527
         Dequeue_Head (Object.Entry_Queues (Entry_Index), Entry_Call);
528
         pragma Assert (Temp_Call = Entry_Call);
529
      end if;
530
 
531
      Call := Entry_Call;
532
   end Select_Protected_Entry_Call;
533
 
534
   ----------------------------
535
   -- Select_Task_Entry_Call --
536
   ----------------------------
537
 
538
   --  Select an entry for rendezvous. Selection depends on the queuing policy
539
   --  being used.
540
 
541
   procedure Select_Task_Entry_Call
542
     (Acceptor         : Task_Id;
543
      Open_Accepts     : Accept_List_Access;
544
      Call             : out Entry_Call_Link;
545
      Selection        : out Select_Index;
546
      Open_Alternative : out Boolean)
547
   is
548
      Entry_Call  : Entry_Call_Link;
549
      Temp_Call   : Entry_Call_Link;
550
      Entry_Index : Task_Entry_Index := Task_Entry_Index'First;
551
      Temp_Entry  : Task_Entry_Index;
552
 
553
   begin
554
      Open_Alternative := False;
555
      Entry_Call       := null;
556
      Selection        := No_Rendezvous;
557
 
558
      if Priority_Queuing then
559
         --  Priority queueing case
560
 
561
         for J in Open_Accepts'Range loop
562
            Temp_Entry := Open_Accepts (J).S;
563
 
564
            if Temp_Entry /= Null_Task_Entry then
565
               Open_Alternative := True;
566
               Temp_Call := Head (Acceptor.Entry_Queues (Temp_Entry));
567
 
568
               if Temp_Call /= null
569
                 and then (Entry_Call = null
570
                   or else Entry_Call.Prio < Temp_Call.Prio)
571
               then
572
                  Entry_Call  := Head (Acceptor.Entry_Queues (Temp_Entry));
573
                  Entry_Index := Temp_Entry;
574
                  Selection := J;
575
               end if;
576
            end if;
577
         end loop;
578
 
579
      else
580
         --  FIFO Queuing case
581
 
582
         for J in Open_Accepts'Range loop
583
            Temp_Entry := Open_Accepts (J).S;
584
 
585
            if Temp_Entry /= Null_Task_Entry then
586
               Open_Alternative := True;
587
               Temp_Call := Head (Acceptor.Entry_Queues (Temp_Entry));
588
 
589
               if Temp_Call /= null then
590
                  Entry_Call := Head (Acceptor.Entry_Queues (Temp_Entry));
591
                  Entry_Index := Temp_Entry;
592
                  Selection := J;
593
                  exit;
594
               end if;
595
            end if;
596
         end loop;
597
      end if;
598
 
599
      if Entry_Call /= null then
600
         Dequeue_Head (Acceptor.Entry_Queues (Entry_Index), Entry_Call);
601
 
602
         --  Guard is open
603
      end if;
604
 
605
      Call := Entry_Call;
606
   end Select_Task_Entry_Call;
607
 
608
   ------------------------
609
   -- Send_Program_Error --
610
   ------------------------
611
 
612
   procedure Send_Program_Error
613
     (Self_ID    : Task_Id;
614
      Entry_Call : Entry_Call_Link)
615
   is
616
      Caller : Task_Id;
617
   begin
618
      Caller := Entry_Call.Self;
619
      Entry_Call.Exception_To_Raise := Program_Error'Identity;
620
      Write_Lock (Caller);
621
      Initialization.Wakeup_Entry_Caller (Self_ID, Entry_Call, Done);
622
      Unlock (Caller);
623
   end Send_Program_Error;
624
 
625
end System.Tasking.Queuing;

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.