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

Subversion Repositories openrisc

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

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 . S T A G E S                --
6
--                                                                          --
7
--                                  B o d y                                 --
8
--                                                                          --
9
--         Copyright (C) 1992-2011, 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
pragma Polling (Off);
33
--  Turn off polling, we do not want ATC polling to take place during tasking
34
--  operations. It causes infinite loops and other problems.
35
 
36
with Ada.Exceptions;
37
with Ada.Unchecked_Deallocation;
38
 
39
with System.Interrupt_Management;
40
with System.Tasking.Debug;
41
with System.Address_Image;
42
with System.Task_Primitives;
43
with System.Task_Primitives.Operations;
44
with System.Tasking.Utilities;
45
with System.Tasking.Queuing;
46
with System.Tasking.Rendezvous;
47
with System.OS_Primitives;
48
with System.Secondary_Stack;
49
with System.Storage_Elements;
50
with System.Restrictions;
51
with System.Standard_Library;
52
with System.Traces.Tasking;
53
with System.Stack_Usage;
54
 
55
with System.Soft_Links;
56
--  These are procedure pointers to non-tasking routines that use task
57
--  specific data. In the absence of tasking, these routines refer to global
58
--  data. In the presence of tasking, they must be replaced with pointers to
59
--  task-specific versions. Also used for Create_TSD, Destroy_TSD, Get_Current
60
--  _Excep, Finalize_Library_Objects, Task_Termination, Handler.
61
 
62
with System.Tasking.Initialization;
63
pragma Elaborate_All (System.Tasking.Initialization);
64
--  This insures that tasking is initialized if any tasks are created
65
 
66
package body System.Tasking.Stages is
67
 
68
   package STPO renames System.Task_Primitives.Operations;
69
   package SSL  renames System.Soft_Links;
70
   package SSE  renames System.Storage_Elements;
71
   package SST  renames System.Secondary_Stack;
72
 
73
   use Ada.Exceptions;
74
 
75
   use Parameters;
76
   use Task_Primitives;
77
   use Task_Primitives.Operations;
78
   use Task_Info;
79
 
80
   use System.Traces;
81
   use System.Traces.Tasking;
82
 
83
   -----------------------
84
   -- Local Subprograms --
85
   -----------------------
86
 
87
   procedure Free is new
88
     Ada.Unchecked_Deallocation (Ada_Task_Control_Block, Task_Id);
89
 
90
   procedure Free_Entry_Names (T : Task_Id);
91
   --  Deallocate all string names associated with task entries
92
 
93
   procedure Trace_Unhandled_Exception_In_Task (Self_Id : Task_Id);
94
   --  This procedure outputs the task specific message for exception
95
   --  tracing purposes.
96
 
97
   procedure Task_Wrapper (Self_ID : Task_Id);
98
   pragma Convention (C, Task_Wrapper);
99
   --  This is the procedure that is called by the GNULL from the new context
100
   --  when a task is created. It waits for activation and then calls the task
101
   --  body procedure. When the task body procedure completes, it terminates
102
   --  the task.
103
   --
104
   --  The Task_Wrapper's address will be provided to the underlying threads
105
   --  library as the task entry point. Convention C is what makes most sense
106
   --  for that purpose (Export C would make the function globally visible,
107
   --  and affect the link name on which GDB depends). This will in addition
108
   --  trigger an automatic stack alignment suitable for GCC's assumptions if
109
   --  need be.
110
 
111
   --  "Vulnerable_..." in the procedure names below means they must be called
112
   --  with abort deferred.
113
 
114
   procedure Vulnerable_Complete_Task (Self_ID : Task_Id);
115
   --  Complete the calling task. This procedure must be called with
116
   --  abort deferred. It should only be called by Complete_Task and
117
   --  Finalize_Global_Tasks (for the environment task).
118
 
119
   procedure Vulnerable_Complete_Master (Self_ID : Task_Id);
120
   --  Complete the current master of the calling task. This procedure
121
   --  must be called with abort deferred. It should only be called by
122
   --  Vulnerable_Complete_Task and Complete_Master.
123
 
124
   procedure Vulnerable_Complete_Activation (Self_ID : Task_Id);
125
   --  Signal to Self_ID's activator that Self_ID has completed activation.
126
   --  This procedure must be called with abort deferred.
127
 
128
   procedure Abort_Dependents (Self_ID : Task_Id);
129
   --  Abort all the direct dependents of Self at its current master nesting
130
   --  level, plus all of their dependents, transitively. RTS_Lock should be
131
   --  locked by the caller.
132
 
133
   procedure Vulnerable_Free_Task (T : Task_Id);
134
   --  Recover all runtime system storage associated with the task T. This
135
   --  should only be called after T has terminated and will no longer be
136
   --  referenced.
137
   --
138
   --  For tasks created by an allocator that fails, due to an exception, it is
139
   --  called from Expunge_Unactivated_Tasks.
140
   --
141
   --  Different code is used at master completion, in Terminate_Dependents,
142
   --  due to a need for tighter synchronization with the master.
143
 
144
   ----------------------
145
   -- Abort_Dependents --
146
   ----------------------
147
 
148
   procedure Abort_Dependents (Self_ID : Task_Id) is
149
      C : Task_Id;
150
      P : Task_Id;
151
 
152
   begin
153
      C := All_Tasks_List;
154
      while C /= null loop
155
         P := C.Common.Parent;
156
         while P /= null loop
157
            if P = Self_ID then
158
 
159
               --  ??? C is supposed to take care of its own dependents, so
160
               --  there should be no need to worry about them. Need to double
161
               --  check this.
162
 
163
               if C.Master_of_Task = Self_ID.Master_Within then
164
                  Utilities.Abort_One_Task (Self_ID, C);
165
                  C.Dependents_Aborted := True;
166
               end if;
167
 
168
               exit;
169
            end if;
170
 
171
            P := P.Common.Parent;
172
         end loop;
173
 
174
         C := C.Common.All_Tasks_Link;
175
      end loop;
176
 
177
      Self_ID.Dependents_Aborted := True;
178
   end Abort_Dependents;
179
 
180
   -----------------
181
   -- Abort_Tasks --
182
   -----------------
183
 
184
   procedure Abort_Tasks (Tasks : Task_List) is
185
   begin
186
      Utilities.Abort_Tasks (Tasks);
187
   end Abort_Tasks;
188
 
189
   --------------------
190
   -- Activate_Tasks --
191
   --------------------
192
 
193
   --  Note that locks of activator and activated task are both locked here.
194
   --  This is necessary because C.Common.State and Self.Common.Wait_Count have
195
   --  to be synchronized. This is safe from deadlock because the activator is
196
   --  always created before the activated task. That satisfies our
197
   --  in-order-of-creation ATCB locking policy.
198
 
199
   --  At one point, we may also lock the parent, if the parent is different
200
   --  from the activator. That is also consistent with the lock ordering
201
   --  policy, since the activator cannot be created before the parent.
202
 
203
   --  Since we are holding both the activator's lock, and Task_Wrapper locks
204
   --  that before it does anything more than initialize the low-level ATCB
205
   --  components, it should be safe to wait to update the counts until we see
206
   --  that the thread creation is successful.
207
 
208
   --  If the thread creation fails, we do need to close the entries of the
209
   --  task. The first phase, of dequeuing calls, only requires locking the
210
   --  acceptor's ATCB, but the waking up of the callers requires locking the
211
   --  caller's ATCB. We cannot safely do this while we are holding other
212
   --  locks. Therefore, the queue-clearing operation is done in a separate
213
   --  pass over the activation chain.
214
 
215
   procedure Activate_Tasks (Chain_Access : Activation_Chain_Access) is
216
      Self_ID        : constant Task_Id := STPO.Self;
217
      P              : Task_Id;
218
      C              : Task_Id;
219
      Next_C, Last_C : Task_Id;
220
      Activate_Prio  : System.Any_Priority;
221
      Success        : Boolean;
222
      All_Elaborated : Boolean := True;
223
 
224
   begin
225
      --  If pragma Detect_Blocking is active, then we must check whether this
226
      --  potentially blocking operation is called from a protected action.
227
 
228
      if System.Tasking.Detect_Blocking
229
        and then Self_ID.Common.Protected_Action_Nesting > 0
230
      then
231
         raise Program_Error with "potentially blocking operation";
232
      end if;
233
 
234
      pragma Debug
235
        (Debug.Trace (Self_ID, "Activate_Tasks", 'C'));
236
 
237
      Initialization.Defer_Abort_Nestable (Self_ID);
238
 
239
      pragma Assert (Self_ID.Common.Wait_Count = 0);
240
 
241
      --  Lock RTS_Lock, to prevent activated tasks from racing ahead before
242
      --  we finish activating the chain.
243
 
244
      Lock_RTS;
245
 
246
      --  Check that all task bodies have been elaborated
247
 
248
      C := Chain_Access.T_ID;
249
      Last_C := null;
250
      while C /= null loop
251
         if C.Common.Elaborated /= null
252
           and then not C.Common.Elaborated.all
253
         then
254
            All_Elaborated := False;
255
         end if;
256
 
257
         --  Reverse the activation chain so that tasks are activated in the
258
         --  same order they're declared.
259
 
260
         Next_C := C.Common.Activation_Link;
261
         C.Common.Activation_Link := Last_C;
262
         Last_C := C;
263
         C := Next_C;
264
      end loop;
265
 
266
      Chain_Access.T_ID := Last_C;
267
 
268
      if not All_Elaborated then
269
         Unlock_RTS;
270
         Initialization.Undefer_Abort_Nestable (Self_ID);
271
         raise Program_Error with "Some tasks have not been elaborated";
272
      end if;
273
 
274
      --  Activate all the tasks in the chain. Creation of the thread of
275
      --  control was deferred until activation. So create it now.
276
 
277
      C := Chain_Access.T_ID;
278
      while C /= null loop
279
         if C.Common.State /= Terminated then
280
            pragma Assert (C.Common.State = Unactivated);
281
 
282
            P := C.Common.Parent;
283
            Write_Lock (P);
284
            Write_Lock (C);
285
 
286
            Activate_Prio :=
287
              (if C.Common.Base_Priority < Get_Priority (Self_ID)
288
               then Get_Priority (Self_ID)
289
               else C.Common.Base_Priority);
290
 
291
            System.Task_Primitives.Operations.Create_Task
292
              (C, Task_Wrapper'Address,
293
               Parameters.Size_Type
294
                 (C.Common.Compiler_Data.Pri_Stack_Info.Size),
295
               Activate_Prio, Success);
296
 
297
            --  There would be a race between the created task and the creator
298
            --  to do the following initialization, if we did not have a
299
            --  Lock/Unlock_RTS pair in the task wrapper to prevent it from
300
            --  racing ahead.
301
 
302
            if Success then
303
               C.Common.State := Activating;
304
               C.Awake_Count := 1;
305
               C.Alive_Count := 1;
306
               P.Awake_Count := P.Awake_Count + 1;
307
               P.Alive_Count := P.Alive_Count + 1;
308
 
309
               if P.Common.State = Master_Completion_Sleep and then
310
                 C.Master_of_Task = P.Master_Within
311
               then
312
                  pragma Assert (Self_ID /= P);
313
                  P.Common.Wait_Count := P.Common.Wait_Count + 1;
314
               end if;
315
 
316
               for J in System.Tasking.Debug.Known_Tasks'Range loop
317
                  if System.Tasking.Debug.Known_Tasks (J) = null then
318
                     System.Tasking.Debug.Known_Tasks (J) := C;
319
                     C.Known_Tasks_Index := J;
320
                     exit;
321
                  end if;
322
               end loop;
323
 
324
               if Global_Task_Debug_Event_Set then
325
                  Debug.Signal_Debug_Event
326
                   (Debug.Debug_Event_Activating, C);
327
               end if;
328
 
329
               C.Common.State := Runnable;
330
 
331
               Unlock (C);
332
               Unlock (P);
333
 
334
            else
335
               --  No need to set Awake_Count, State, etc. here since the loop
336
               --  below will do that for any Unactivated tasks.
337
 
338
               Unlock (C);
339
               Unlock (P);
340
               Self_ID.Common.Activation_Failed := True;
341
            end if;
342
         end if;
343
 
344
         C := C.Common.Activation_Link;
345
      end loop;
346
 
347
      if not Single_Lock then
348
         Unlock_RTS;
349
      end if;
350
 
351
      --  Close the entries of any tasks that failed thread creation, and count
352
      --  those that have not finished activation.
353
 
354
      Write_Lock (Self_ID);
355
      Self_ID.Common.State := Activator_Sleep;
356
 
357
      C := Chain_Access.T_ID;
358
      while C /= null loop
359
         Write_Lock (C);
360
 
361
         if C.Common.State = Unactivated then
362
            C.Common.Activator := null;
363
            C.Common.State := Terminated;
364
            C.Callable := False;
365
            Utilities.Cancel_Queued_Entry_Calls (C);
366
 
367
         elsif C.Common.Activator /= null then
368
            Self_ID.Common.Wait_Count := Self_ID.Common.Wait_Count + 1;
369
         end if;
370
 
371
         Unlock (C);
372
         P := C.Common.Activation_Link;
373
         C.Common.Activation_Link := null;
374
         C := P;
375
      end loop;
376
 
377
      --  Wait for the activated tasks to complete activation. It is
378
      --  unsafe to abort any of these tasks until the count goes to zero.
379
 
380
      loop
381
         exit when Self_ID.Common.Wait_Count = 0;
382
         Sleep (Self_ID, Activator_Sleep);
383
      end loop;
384
 
385
      Self_ID.Common.State := Runnable;
386
      Unlock (Self_ID);
387
 
388
      if Single_Lock then
389
         Unlock_RTS;
390
      end if;
391
 
392
      --  Remove the tasks from the chain
393
 
394
      Chain_Access.T_ID := null;
395
      Initialization.Undefer_Abort_Nestable (Self_ID);
396
 
397
      if Self_ID.Common.Activation_Failed then
398
         Self_ID.Common.Activation_Failed := False;
399
         raise Tasking_Error with "Failure during activation";
400
      end if;
401
   end Activate_Tasks;
402
 
403
   -------------------------
404
   -- Complete_Activation --
405
   -------------------------
406
 
407
   procedure Complete_Activation is
408
      Self_ID : constant Task_Id := STPO.Self;
409
 
410
   begin
411
      Initialization.Defer_Abort_Nestable (Self_ID);
412
 
413
      if Single_Lock then
414
         Lock_RTS;
415
      end if;
416
 
417
      Vulnerable_Complete_Activation (Self_ID);
418
 
419
      if Single_Lock then
420
         Unlock_RTS;
421
      end if;
422
 
423
      Initialization.Undefer_Abort_Nestable (Self_ID);
424
 
425
      --  ??? Why do we need to allow for nested deferral here?
426
 
427
      if Runtime_Traces then
428
         Send_Trace_Info (T_Activate);
429
      end if;
430
   end Complete_Activation;
431
 
432
   ---------------------
433
   -- Complete_Master --
434
   ---------------------
435
 
436
   procedure Complete_Master is
437
      Self_ID : constant Task_Id := STPO.Self;
438
   begin
439
      pragma Assert
440
        (Self_ID.Deferral_Level > 0
441
          or else not System.Restrictions.Abort_Allowed);
442
      Vulnerable_Complete_Master (Self_ID);
443
   end Complete_Master;
444
 
445
   -------------------
446
   -- Complete_Task --
447
   -------------------
448
 
449
   --  See comments on Vulnerable_Complete_Task for details
450
 
451
   procedure Complete_Task is
452
      Self_ID  : constant Task_Id := STPO.Self;
453
 
454
   begin
455
      pragma Assert
456
        (Self_ID.Deferral_Level > 0
457
          or else not System.Restrictions.Abort_Allowed);
458
 
459
      Vulnerable_Complete_Task (Self_ID);
460
 
461
      --  All of our dependents have terminated. Never undefer abort again!
462
 
463
   end Complete_Task;
464
 
465
   -----------------
466
   -- Create_Task --
467
   -----------------
468
 
469
   --  Compiler interface only. Do not call from within the RTS. This must be
470
   --  called to create a new task.
471
 
472
   procedure Create_Task
473
     (Priority          : Integer;
474
      Size              : System.Parameters.Size_Type;
475
      Task_Info         : System.Task_Info.Task_Info_Type;
476
      CPU               : Integer;
477
      Relative_Deadline : Ada.Real_Time.Time_Span;
478
      Domain            : Dispatching_Domain_Access;
479
      Num_Entries       : Task_Entry_Index;
480
      Master            : Master_Level;
481
      State             : Task_Procedure_Access;
482
      Discriminants     : System.Address;
483
      Elaborated        : Access_Boolean;
484
      Chain             : in out Activation_Chain;
485
      Task_Image        : String;
486
      Created_Task      : out Task_Id;
487
      Build_Entry_Names : Boolean)
488
   is
489
      T, P          : Task_Id;
490
      Self_ID       : constant Task_Id := STPO.Self;
491
      Success       : Boolean;
492
      Base_Priority : System.Any_Priority;
493
      Len           : Natural;
494
      Base_CPU      : System.Multiprocessors.CPU_Range;
495
 
496
      use type System.Multiprocessors.CPU_Range;
497
 
498
      pragma Unreferenced (Relative_Deadline);
499
      --  EDF scheduling is not supported by any of the target platforms so
500
      --  this parameter is not passed any further.
501
 
502
   begin
503
      --  If Master is greater than the current master, it means that Master
504
      --  has already awaited its dependent tasks. This raises Program_Error,
505
      --  by 4.8(10.3/2). See AI-280. Ignore this check for foreign threads.
506
 
507
      if Self_ID.Master_of_Task /= Foreign_Task_Level
508
        and then Master > Self_ID.Master_Within
509
      then
510
         raise Program_Error with
511
           "create task after awaiting termination";
512
      end if;
513
 
514
      --  If pragma Detect_Blocking is active must be checked whether this
515
      --  potentially blocking operation is called from a protected action.
516
 
517
      if System.Tasking.Detect_Blocking
518
        and then Self_ID.Common.Protected_Action_Nesting > 0
519
      then
520
         raise Program_Error with "potentially blocking operation";
521
      end if;
522
 
523
      pragma Debug (Debug.Trace (Self_ID, "Create_Task", 'C'));
524
 
525
      Base_Priority :=
526
        (if Priority = Unspecified_Priority
527
         then Self_ID.Common.Base_Priority
528
         else System.Any_Priority (Priority));
529
 
530
      if CPU /= Unspecified_CPU
531
        and then (CPU < Integer (System.Multiprocessors.CPU_Range'First)
532
                    or else
533
                  CPU > Integer (System.Multiprocessors.CPU_Range'Last)
534
                    or else
535
                  CPU > Integer (System.Multiprocessors.Number_Of_CPUs))
536
      then
537
         raise Tasking_Error with "CPU not in range";
538
 
539
      --  Normal CPU affinity
540
 
541
      else
542
         Base_CPU :=
543
           (if CPU = Unspecified_CPU
544
            then Self_ID.Common.Base_CPU
545
            else System.Multiprocessors.CPU_Range (CPU));
546
      end if;
547
 
548
      --  Find parent P of new Task, via master level number
549
 
550
      P := Self_ID;
551
 
552
      if P /= null then
553
         while P.Master_of_Task >= Master loop
554
            P := P.Common.Parent;
555
            exit when P = null;
556
         end loop;
557
      end if;
558
 
559
      Initialization.Defer_Abort_Nestable (Self_ID);
560
 
561
      begin
562
         T := New_ATCB (Num_Entries);
563
      exception
564
         when others =>
565
            Initialization.Undefer_Abort_Nestable (Self_ID);
566
            raise Storage_Error with "Cannot allocate task";
567
      end;
568
 
569
      --  RTS_Lock is used by Abort_Dependents and Abort_Tasks. Up to this
570
      --  point, it is possible that we may be part of a family of tasks that
571
      --  is being aborted.
572
 
573
      Lock_RTS;
574
      Write_Lock (Self_ID);
575
 
576
      --  Now, we must check that we have not been aborted. If so, we should
577
      --  give up on creating this task, and simply return.
578
 
579
      if not Self_ID.Callable then
580
         pragma Assert (Self_ID.Pending_ATC_Level = 0);
581
         pragma Assert (Self_ID.Pending_Action);
582
         pragma Assert
583
           (Chain.T_ID = null or else Chain.T_ID.Common.State = Unactivated);
584
 
585
         Unlock (Self_ID);
586
         Unlock_RTS;
587
         Initialization.Undefer_Abort_Nestable (Self_ID);
588
 
589
         --  ??? Should never get here
590
 
591
         pragma Assert (False);
592
         raise Standard'Abort_Signal;
593
      end if;
594
 
595
      Initialize_ATCB (Self_ID, State, Discriminants, P, Elaborated,
596
        Base_Priority, Base_CPU, Domain, Task_Info, Size, T, Success);
597
 
598
      if not Success then
599
         Free (T);
600
         Unlock (Self_ID);
601
         Unlock_RTS;
602
         Initialization.Undefer_Abort_Nestable (Self_ID);
603
         raise Storage_Error with "Failed to initialize task";
604
      end if;
605
 
606
      if Master = Foreign_Task_Level + 2 then
607
 
608
         --  This should not happen, except when a foreign task creates non
609
         --  library-level Ada tasks. In this case, we pretend the master is
610
         --  a regular library level task, otherwise the run-time will get
611
         --  confused when waiting for these tasks to terminate.
612
 
613
         T.Master_of_Task := Library_Task_Level;
614
 
615
      else
616
         T.Master_of_Task := Master;
617
      end if;
618
 
619
      T.Master_Within := T.Master_of_Task + 1;
620
 
621
      for L in T.Entry_Calls'Range loop
622
         T.Entry_Calls (L).Self := T;
623
         T.Entry_Calls (L).Level := L;
624
      end loop;
625
 
626
      if Task_Image'Length = 0 then
627
         T.Common.Task_Image_Len := 0;
628
      else
629
         Len := 1;
630
         T.Common.Task_Image (1) := Task_Image (Task_Image'First);
631
 
632
         --  Remove unwanted blank space generated by 'Image
633
 
634
         for J in Task_Image'First + 1 .. Task_Image'Last loop
635
            if Task_Image (J) /= ' '
636
              or else Task_Image (J - 1) /= '('
637
            then
638
               Len := Len + 1;
639
               T.Common.Task_Image (Len) := Task_Image (J);
640
               exit when Len = T.Common.Task_Image'Last;
641
            end if;
642
         end loop;
643
 
644
         T.Common.Task_Image_Len := Len;
645
      end if;
646
 
647
      --  The task inherits the dispatching domain of the parent only if no
648
      --  specific domain has been defined in the spec of the task (using the
649
      --  dispatching domain pragma or aspect).
650
 
651
      if T.Common.Domain /= null then
652
         null;
653
      elsif T.Common.Activator /= null then
654
         T.Common.Domain := T.Common.Activator.Common.Domain;
655
      else
656
         T.Common.Domain := System.Tasking.System_Domain;
657
      end if;
658
 
659
      Unlock (Self_ID);
660
      Unlock_RTS;
661
 
662
      --  The CPU associated to the task (if any) must belong to the
663
      --  dispatching domain.
664
 
665
      if Base_CPU /= System.Multiprocessors.Not_A_Specific_CPU
666
        and then
667
          (Base_CPU not in T.Common.Domain'Range
668
            or else not T.Common.Domain (Base_CPU))
669
      then
670
         Initialization.Undefer_Abort_Nestable (Self_ID);
671
         raise Tasking_Error with "CPU not in dispatching domain";
672
      end if;
673
 
674
      --  To handle the interaction between pragma CPU and dispatching domains
675
      --  we need to signal that this task is being allocated to a processor.
676
      --  This is needed only for tasks belonging to the system domain (the
677
      --  creation of new dispatching domains can only take processors from the
678
      --  system domain) and only before the environment task calls the main
679
      --  procedure (dispatching domains cannot be created after this).
680
 
681
      if Base_CPU /= System.Multiprocessors.Not_A_Specific_CPU
682
        and then T.Common.Domain = System.Tasking.System_Domain
683
        and then not System.Tasking.Dispatching_Domains_Frozen
684
      then
685
         --  Increase the number of tasks attached to the CPU to which this
686
         --  task is being moved.
687
 
688
         Dispatching_Domain_Tasks (Base_CPU) :=
689
           Dispatching_Domain_Tasks (Base_CPU) + 1;
690
      end if;
691
 
692
      --  Note: we should not call 'new' while holding locks since new may use
693
      --  locks (e.g. RTS_Lock under Windows) itself and cause a deadlock.
694
 
695
      if Build_Entry_Names then
696
         T.Entry_Names :=
697
           new Entry_Names_Array (1 .. Entry_Index (Num_Entries));
698
      end if;
699
 
700
      --  Create TSD as early as possible in the creation of a task, since it
701
      --  may be used by the operation of Ada code within the task.
702
 
703
      SSL.Create_TSD (T.Common.Compiler_Data);
704
      T.Common.Activation_Link := Chain.T_ID;
705
      Chain.T_ID := T;
706
      Initialization.Initialize_Attributes_Link.all (T);
707
      Created_Task := T;
708
      Initialization.Undefer_Abort_Nestable (Self_ID);
709
 
710
      if Runtime_Traces then
711
         Send_Trace_Info (T_Create, T);
712
      end if;
713
   end Create_Task;
714
 
715
   --------------------
716
   -- Current_Master --
717
   --------------------
718
 
719
   function Current_Master return Master_Level is
720
   begin
721
      return STPO.Self.Master_Within;
722
   end Current_Master;
723
 
724
   ------------------
725
   -- Enter_Master --
726
   ------------------
727
 
728
   procedure Enter_Master is
729
      Self_ID : constant Task_Id := STPO.Self;
730
   begin
731
      Self_ID.Master_Within := Self_ID.Master_Within + 1;
732
   end Enter_Master;
733
 
734
   -------------------------------
735
   -- Expunge_Unactivated_Tasks --
736
   -------------------------------
737
 
738
   --  See procedure Close_Entries for the general case
739
 
740
   procedure Expunge_Unactivated_Tasks (Chain : in out Activation_Chain) is
741
      Self_ID : constant Task_Id := STPO.Self;
742
      C       : Task_Id;
743
      Call    : Entry_Call_Link;
744
      Temp    : Task_Id;
745
 
746
   begin
747
      pragma Debug
748
        (Debug.Trace (Self_ID, "Expunge_Unactivated_Tasks", 'C'));
749
 
750
      Initialization.Defer_Abort_Nestable (Self_ID);
751
 
752
      --  ???
753
      --  Experimentation has shown that abort is sometimes (but not always)
754
      --  already deferred when this is called.
755
 
756
      --  That may indicate an error. Find out what is going on
757
 
758
      C := Chain.T_ID;
759
      while C /= null loop
760
         pragma Assert (C.Common.State = Unactivated);
761
 
762
         Temp := C.Common.Activation_Link;
763
 
764
         if C.Common.State = Unactivated then
765
            Lock_RTS;
766
            Write_Lock (C);
767
 
768
            for J in 1 .. C.Entry_Num loop
769
               Queuing.Dequeue_Head (C.Entry_Queues (J), Call);
770
               pragma Assert (Call = null);
771
            end loop;
772
 
773
            Unlock (C);
774
 
775
            Initialization.Remove_From_All_Tasks_List (C);
776
            Unlock_RTS;
777
 
778
            Vulnerable_Free_Task (C);
779
            C := Temp;
780
         end if;
781
      end loop;
782
 
783
      Chain.T_ID := null;
784
      Initialization.Undefer_Abort_Nestable (Self_ID);
785
   end Expunge_Unactivated_Tasks;
786
 
787
   ---------------------------
788
   -- Finalize_Global_Tasks --
789
   ---------------------------
790
 
791
   --  ???
792
   --  We have a potential problem here if finalization of global objects does
793
   --  anything with signals or the timer server, since by that time those
794
   --  servers have terminated.
795
 
796
   --  It is hard to see how that would occur
797
 
798
   --  However, a better solution might be to do all this finalization
799
   --  using the global finalization chain.
800
 
801
   procedure Finalize_Global_Tasks is
802
      Self_ID : constant Task_Id := STPO.Self;
803
 
804
      Ignore  : Boolean;
805
      pragma Unreferenced (Ignore);
806
 
807
      function State
808
        (Int : System.Interrupt_Management.Interrupt_ID) return Character;
809
      pragma Import (C, State, "__gnat_get_interrupt_state");
810
      --  Get interrupt state for interrupt number Int. Defined in init.c
811
 
812
      Default : constant Character := 's';
813
      --    's'   Interrupt_State pragma set state to System (use "default"
814
      --           system handler)
815
 
816
   begin
817
      if Self_ID.Deferral_Level = 0 then
818
         --  ???
819
         --  In principle, we should be able to predict whether abort is
820
         --  already deferred here (and it should not be deferred yet but in
821
         --  practice it seems Finalize_Global_Tasks is being called sometimes,
822
         --  from RTS code for exceptions, with abort already deferred.
823
 
824
         Initialization.Defer_Abort_Nestable (Self_ID);
825
 
826
         --  Never undefer again!!!
827
      end if;
828
 
829
      --  This code is only executed by the environment task
830
 
831
      pragma Assert (Self_ID = Environment_Task);
832
 
833
      --  Set Environment_Task'Callable to false to notify library-level tasks
834
      --  that it is waiting for them.
835
 
836
      Self_ID.Callable := False;
837
 
838
      --  Exit level 2 master, for normal tasks in library-level packages
839
 
840
      Complete_Master;
841
 
842
      --  Force termination of "independent" library-level server tasks
843
 
844
      Lock_RTS;
845
 
846
      Abort_Dependents (Self_ID);
847
 
848
      if not Single_Lock then
849
         Unlock_RTS;
850
      end if;
851
 
852
      --  We need to explicitly wait for the task to be terminated here
853
      --  because on true concurrent system, we may end this procedure before
854
      --  the tasks are really terminated.
855
 
856
      Write_Lock (Self_ID);
857
 
858
      --  If the Abort_Task signal is set to system, it means that we may not
859
      --  have been able to abort all independent tasks (in particular
860
      --  Server_Task may be blocked, waiting for a signal), in which case,
861
      --  do not wait for Independent_Task_Count to go down to 0.
862
 
863
      if State
864
          (System.Interrupt_Management.Abort_Task_Interrupt) /= Default
865
      then
866
         loop
867
            exit when Utilities.Independent_Task_Count = 0;
868
 
869
            --  We used to yield here, but this did not take into account low
870
            --  priority tasks that would cause dead lock in some cases (true
871
            --  FIFO scheduling).
872
 
873
            Timed_Sleep
874
              (Self_ID, 0.01, System.OS_Primitives.Relative,
875
               Self_ID.Common.State, Ignore, Ignore);
876
         end loop;
877
      end if;
878
 
879
      --  ??? On multi-processor environments, it seems that the above loop
880
      --  isn't sufficient, so we need to add an additional delay.
881
 
882
      Timed_Sleep
883
        (Self_ID, 0.01, System.OS_Primitives.Relative,
884
         Self_ID.Common.State, Ignore, Ignore);
885
 
886
      Unlock (Self_ID);
887
 
888
      if Single_Lock then
889
         Unlock_RTS;
890
      end if;
891
 
892
      --  Complete the environment task
893
 
894
      Vulnerable_Complete_Task (Self_ID);
895
 
896
      --  Handle normal task termination by the environment task, but only
897
      --  for the normal task termination. In the case of Abnormal and
898
      --  Unhandled_Exception they must have been handled before, and the
899
      --  task termination soft link must have been changed so the task
900
      --  termination routine is not executed twice.
901
 
902
      SSL.Task_Termination_Handler.all (Ada.Exceptions.Null_Occurrence);
903
 
904
      --  Finalize all library-level controlled objects
905
 
906
      if not SSL."=" (SSL.Finalize_Library_Objects, null) then
907
         SSL.Finalize_Library_Objects.all;
908
      end if;
909
 
910
      --  Reset the soft links to non-tasking
911
 
912
      SSL.Abort_Defer        := SSL.Abort_Defer_NT'Access;
913
      SSL.Abort_Undefer      := SSL.Abort_Undefer_NT'Access;
914
      SSL.Lock_Task          := SSL.Task_Lock_NT'Access;
915
      SSL.Unlock_Task        := SSL.Task_Unlock_NT'Access;
916
      SSL.Get_Jmpbuf_Address := SSL.Get_Jmpbuf_Address_NT'Access;
917
      SSL.Set_Jmpbuf_Address := SSL.Set_Jmpbuf_Address_NT'Access;
918
      SSL.Get_Sec_Stack_Addr := SSL.Get_Sec_Stack_Addr_NT'Access;
919
      SSL.Set_Sec_Stack_Addr := SSL.Set_Sec_Stack_Addr_NT'Access;
920
      SSL.Check_Abort_Status := SSL.Check_Abort_Status_NT'Access;
921
      SSL.Get_Stack_Info     := SSL.Get_Stack_Info_NT'Access;
922
 
923
      --  Don't bother trying to finalize Initialization.Global_Task_Lock
924
      --  and System.Task_Primitives.RTS_Lock.
925
 
926
   end Finalize_Global_Tasks;
927
 
928
   ----------------------
929
   -- Free_Entry_Names --
930
   ----------------------
931
 
932
   procedure Free_Entry_Names (T : Task_Id) is
933
      Names : Entry_Names_Array_Access := T.Entry_Names;
934
 
935
      procedure Free_Entry_Names_Array_Access is new
936
        Ada.Unchecked_Deallocation
937
          (Entry_Names_Array, Entry_Names_Array_Access);
938
 
939
   begin
940
      if Names = null then
941
         return;
942
      end if;
943
 
944
      Free_Entry_Names_Array (Names.all);
945
      Free_Entry_Names_Array_Access (Names);
946
   end Free_Entry_Names;
947
 
948
   ---------------
949
   -- Free_Task --
950
   ---------------
951
 
952
   procedure Free_Task (T : Task_Id) is
953
      Self_Id : constant Task_Id := Self;
954
 
955
   begin
956
      if T.Common.State = Terminated then
957
 
958
         --  It is not safe to call Abort_Defer or Write_Lock at this stage
959
 
960
         Initialization.Task_Lock (Self_Id);
961
 
962
         Lock_RTS;
963
         Initialization.Finalize_Attributes_Link.all (T);
964
         Initialization.Remove_From_All_Tasks_List (T);
965
         Unlock_RTS;
966
 
967
         Initialization.Task_Unlock (Self_Id);
968
 
969
         Free_Entry_Names (T);
970
         System.Task_Primitives.Operations.Finalize_TCB (T);
971
 
972
      else
973
         --  If the task is not terminated, then mark the task as to be freed
974
         --  upon termination.
975
 
976
         T.Free_On_Termination := True;
977
      end if;
978
   end Free_Task;
979
 
980
   ---------------------------
981
   -- Move_Activation_Chain --
982
   ---------------------------
983
 
984
   procedure Move_Activation_Chain
985
     (From, To   : Activation_Chain_Access;
986
      New_Master : Master_ID)
987
   is
988
      Self_ID : constant Task_Id := STPO.Self;
989
      C       : Task_Id;
990
 
991
   begin
992
      pragma Debug
993
        (Debug.Trace (Self_ID, "Move_Activation_Chain", 'C'));
994
 
995
      --  Nothing to do if From is empty, and we can check that without
996
      --  deferring aborts.
997
 
998
      C := From.all.T_ID;
999
 
1000
      if C = null then
1001
         return;
1002
      end if;
1003
 
1004
      Initialization.Defer_Abort (Self_ID);
1005
 
1006
      --  Loop through the From chain, changing their Master_of_Task fields,
1007
      --  and to find the end of the chain.
1008
 
1009
      loop
1010
         C.Master_of_Task := New_Master;
1011
         exit when C.Common.Activation_Link = null;
1012
         C := C.Common.Activation_Link;
1013
      end loop;
1014
 
1015
      --  Hook From in at the start of To
1016
 
1017
      C.Common.Activation_Link := To.all.T_ID;
1018
      To.all.T_ID := From.all.T_ID;
1019
 
1020
      --  Set From to empty
1021
 
1022
      From.all.T_ID := null;
1023
 
1024
      Initialization.Undefer_Abort (Self_ID);
1025
   end Move_Activation_Chain;
1026
 
1027
   --  Compiler interface only. Do not call from within the RTS
1028
 
1029
   --------------------
1030
   -- Set_Entry_Name --
1031
   --------------------
1032
 
1033
   procedure Set_Entry_Name
1034
     (T   : Task_Id;
1035
      Pos : Task_Entry_Index;
1036
      Val : String_Access)
1037
   is
1038
   begin
1039
      pragma Assert (T.Entry_Names /= null);
1040
 
1041
      T.Entry_Names (Entry_Index (Pos)) := Val;
1042
   end Set_Entry_Name;
1043
 
1044
   ------------------
1045
   -- Task_Wrapper --
1046
   ------------------
1047
 
1048
   --  The task wrapper is a procedure that is called first for each task body
1049
   --  and which in turn calls the compiler-generated task body procedure.
1050
   --  The wrapper's main job is to do initialization for the task. It also
1051
   --  has some locally declared objects that serve as per-task local data.
1052
   --  Task finalization is done by Complete_Task, which is called from an
1053
   --  at-end handler that the compiler generates.
1054
 
1055
   procedure Task_Wrapper (Self_ID : Task_Id) is
1056
      use type SSE.Storage_Offset;
1057
      use System.Standard_Library;
1058
      use System.Stack_Usage;
1059
 
1060
      Bottom_Of_Stack : aliased Integer;
1061
 
1062
      Task_Alternate_Stack :
1063
        aliased SSE.Storage_Array (1 .. Alternate_Stack_Size);
1064
      --  The alternate signal stack for this task, if any
1065
 
1066
      Use_Alternate_Stack : constant Boolean := Alternate_Stack_Size /= 0;
1067
      --  Whether to use above alternate signal stack for stack overflows
1068
 
1069
      Secondary_Stack_Size :
1070
        constant SSE.Storage_Offset :=
1071
          Self_ID.Common.Compiler_Data.Pri_Stack_Info.Size *
1072
            SSE.Storage_Offset (Parameters.Sec_Stack_Percentage) / 100;
1073
 
1074
      Secondary_Stack : aliased SSE.Storage_Array (1 .. Secondary_Stack_Size);
1075
      --  Actual area allocated for secondary stack
1076
 
1077
      Secondary_Stack_Address : System.Address := Secondary_Stack'Address;
1078
      --  Address of secondary stack. In the fixed secondary stack case, this
1079
      --  value is not modified, causing a warning, hence the bracketing with
1080
      --  Warnings (Off/On). But why is so much *more* bracketed???
1081
 
1082
      SEH_Table : aliased SSE.Storage_Array (1 .. 8);
1083
      --  Structured Exception Registration table (2 words)
1084
 
1085
      procedure Install_SEH_Handler (Addr : System.Address);
1086
      pragma Import (C, Install_SEH_Handler, "__gnat_install_SEH_handler");
1087
      --  Install the SEH (Structured Exception Handling) handler
1088
 
1089
      Cause : Cause_Of_Termination := Normal;
1090
      --  Indicates the reason why this task terminates. Normal corresponds to
1091
      --  a task terminating due to completing the last statement of its body,
1092
      --  or as a result of waiting on a terminate alternative. If the task
1093
      --  terminates because it is being aborted then Cause will be set
1094
      --  to Abnormal. If the task terminates because of an exception
1095
      --  raised by the execution of its task body, then Cause is set
1096
      --  to Unhandled_Exception.
1097
 
1098
      EO : Exception_Occurrence;
1099
      --  If the task terminates because of an exception raised by the
1100
      --  execution of its task body, then EO will contain the associated
1101
      --  exception occurrence. Otherwise, it will contain Null_Occurrence.
1102
 
1103
      TH : Termination_Handler := null;
1104
      --  Pointer to the protected procedure to be executed upon task
1105
      --  termination.
1106
 
1107
      procedure Search_Fall_Back_Handler (ID : Task_Id);
1108
      --  Procedure that searches recursively a fall-back handler through the
1109
      --  master relationship. If the handler is found, its pointer is stored
1110
      --  in TH.
1111
 
1112
      ------------------------------
1113
      -- Search_Fall_Back_Handler --
1114
      ------------------------------
1115
 
1116
      procedure Search_Fall_Back_Handler (ID : Task_Id) is
1117
      begin
1118
         --  If there is a fall back handler, store its pointer for later
1119
         --  execution.
1120
 
1121
         if ID.Common.Fall_Back_Handler /= null then
1122
            TH := ID.Common.Fall_Back_Handler;
1123
 
1124
         --  Otherwise look for a fall back handler in the parent
1125
 
1126
         elsif ID.Common.Parent /= null then
1127
            Search_Fall_Back_Handler (ID.Common.Parent);
1128
 
1129
         --  Otherwise, do nothing
1130
 
1131
         else
1132
            return;
1133
         end if;
1134
      end Search_Fall_Back_Handler;
1135
 
1136
   --  Start of processing for Task_Wrapper
1137
 
1138
   begin
1139
      pragma Assert (Self_ID.Deferral_Level = 1);
1140
 
1141
      --  Assume a size of the stack taken at this stage
1142
 
1143
      if not Parameters.Sec_Stack_Dynamic then
1144
         Self_ID.Common.Compiler_Data.Sec_Stack_Addr :=
1145
           Secondary_Stack'Address;
1146
         SST.SS_Init (Secondary_Stack_Address, Integer (Secondary_Stack'Last));
1147
      end if;
1148
 
1149
      if Use_Alternate_Stack then
1150
         Self_ID.Common.Task_Alternate_Stack := Task_Alternate_Stack'Address;
1151
      end if;
1152
 
1153
      --  Set the guard page at the bottom of the stack. The call to unprotect
1154
      --  the page is done in Terminate_Task
1155
 
1156
      Stack_Guard (Self_ID, True);
1157
 
1158
      --  Initialize low-level TCB components, that cannot be initialized by
1159
      --  the creator. Enter_Task sets Self_ID.LL.Thread.
1160
 
1161
      Enter_Task (Self_ID);
1162
 
1163
      --  Initialize dynamic stack usage
1164
 
1165
      if System.Stack_Usage.Is_Enabled then
1166
         declare
1167
            Guard_Page_Size : constant := 16 * 1024;
1168
            --  Part of the stack used as a guard page. This is an OS dependent
1169
            --  value, so we need to use the maximum. This value is only used
1170
            --  when the stack address is known, that is currently Windows.
1171
 
1172
            Small_Overflow_Guard : constant := 12 * 1024;
1173
            --  Note: this used to be 4K, but was changed to 12K, since
1174
            --  smaller values resulted in segmentation faults from dynamic
1175
            --  stack analysis.
1176
 
1177
            Big_Overflow_Guard : constant := 64 * 1024 + 8 * 1024;
1178
            Small_Stack_Limit  : constant := 64 * 1024;
1179
            --  ??? These three values are experimental, and seem to work on
1180
            --  most platforms. They still need to be analyzed further. They
1181
            --  also need documentation, what are they and why does the logic
1182
            --  differ depending on whether the stack is large or small???
1183
 
1184
            Pattern_Size : Natural :=
1185
                             Natural (Self_ID.Common.
1186
                                        Compiler_Data.Pri_Stack_Info.Size);
1187
            --  Size of the pattern
1188
 
1189
            Stack_Base : Address;
1190
            --  Address of the base of the stack
1191
 
1192
         begin
1193
            Stack_Base := Self_ID.Common.Compiler_Data.Pri_Stack_Info.Base;
1194
 
1195
            if Stack_Base = Null_Address then
1196
 
1197
               --  On many platforms, we don't know the real stack base
1198
               --  address. Estimate it using an address in the frame.
1199
 
1200
               Stack_Base := Bottom_Of_Stack'Address;
1201
 
1202
               --  Also reduce the size of the stack to take into account the
1203
               --  secondary stack array declared in this frame. This is for
1204
               --  sure very conservative.
1205
 
1206
               if not Parameters.Sec_Stack_Dynamic then
1207
                  Pattern_Size :=
1208
                    Pattern_Size - Natural (Secondary_Stack_Size);
1209
               end if;
1210
 
1211
               --  Adjustments for inner frames
1212
 
1213
               Pattern_Size := Pattern_Size -
1214
                 (if Pattern_Size < Small_Stack_Limit
1215
                    then Small_Overflow_Guard
1216
                    else Big_Overflow_Guard);
1217
            else
1218
               --  Reduce by the size of the final guard page
1219
 
1220
               Pattern_Size := Pattern_Size - Guard_Page_Size;
1221
            end if;
1222
 
1223
            STPO.Lock_RTS;
1224
            Initialize_Analyzer
1225
              (Self_ID.Common.Analyzer,
1226
               Self_ID.Common.Task_Image (1 .. Self_ID.Common.Task_Image_Len),
1227
               Natural (Self_ID.Common.Compiler_Data.Pri_Stack_Info.Size),
1228
               SSE.To_Integer (Stack_Base),
1229
               Pattern_Size);
1230
            STPO.Unlock_RTS;
1231
            Fill_Stack (Self_ID.Common.Analyzer);
1232
         end;
1233
      end if;
1234
 
1235
      --  We setup the SEH (Structured Exception Handling) handler if supported
1236
      --  on the target.
1237
 
1238
      Install_SEH_Handler (SEH_Table'Address);
1239
 
1240
      --  Initialize exception occurrence
1241
 
1242
      Save_Occurrence (EO, Ada.Exceptions.Null_Occurrence);
1243
 
1244
      --  We lock RTS_Lock to wait for activator to finish activating the rest
1245
      --  of the chain, so that everyone in the chain comes out in priority
1246
      --  order.
1247
 
1248
      --  This also protects the value of
1249
      --    Self_ID.Common.Activator.Common.Wait_Count.
1250
 
1251
      Lock_RTS;
1252
      Unlock_RTS;
1253
 
1254
      if not System.Restrictions.Abort_Allowed then
1255
 
1256
         --  If Abort is not allowed, reset the deferral level since it will
1257
         --  not get changed by the generated code. Keeping a default value
1258
         --  of one would prevent some operations (e.g. select or delay) to
1259
         --  proceed successfully.
1260
 
1261
         Self_ID.Deferral_Level := 0;
1262
      end if;
1263
 
1264
      if Global_Task_Debug_Event_Set then
1265
         Debug.Signal_Debug_Event (Debug.Debug_Event_Run, Self_ID);
1266
      end if;
1267
 
1268
      begin
1269
         --  We are separating the following portion of the code in order to
1270
         --  place the exception handlers in a different block. In this way,
1271
         --  we do not call Set_Jmpbuf_Address (which needs Self) before we
1272
         --  set Self in Enter_Task
1273
 
1274
         --  Call the task body procedure
1275
 
1276
         --  The task body is called with abort still deferred. That
1277
         --  eliminates a dangerous window, for which we had to patch-up in
1278
         --  Terminate_Task.
1279
 
1280
         --  During the expansion of the task body, we insert an RTS-call
1281
         --  to Abort_Undefer, at the first point where abort should be
1282
         --  allowed.
1283
 
1284
         Self_ID.Common.Task_Entry_Point (Self_ID.Common.Task_Arg);
1285
         Initialization.Defer_Abort_Nestable (Self_ID);
1286
 
1287
      exception
1288
         --  We can't call Terminate_Task in the exception handlers below,
1289
         --  since there may be (e.g. in the case of GCC exception handling)
1290
         --  clean ups associated with the exception handler that need to
1291
         --  access task specific data.
1292
 
1293
         --  Defer abort so that this task can't be aborted while exiting
1294
 
1295
         when Standard'Abort_Signal =>
1296
            Initialization.Defer_Abort_Nestable (Self_ID);
1297
 
1298
            --  Update the cause that motivated the task termination so that
1299
            --  the appropriate information is passed to the task termination
1300
            --  procedure. Task termination as a result of waiting on a
1301
            --  terminate alternative is a normal termination, although it is
1302
            --  implemented using the abort mechanisms.
1303
 
1304
            if Self_ID.Terminate_Alternative then
1305
               Cause := Normal;
1306
 
1307
               if Global_Task_Debug_Event_Set then
1308
                  Debug.Signal_Debug_Event
1309
                   (Debug.Debug_Event_Terminated, Self_ID);
1310
               end if;
1311
            else
1312
               Cause := Abnormal;
1313
 
1314
               if Global_Task_Debug_Event_Set then
1315
                  Debug.Signal_Debug_Event
1316
                   (Debug.Debug_Event_Abort_Terminated, Self_ID);
1317
               end if;
1318
            end if;
1319
 
1320
         when others =>
1321
            --  ??? Using an E : others here causes CD2C11A to fail on Tru64
1322
 
1323
            Initialization.Defer_Abort_Nestable (Self_ID);
1324
 
1325
            --  Perform the task specific exception tracing duty.  We handle
1326
            --  these outputs here and not in the common notification routine
1327
            --  because we need access to tasking related data and we don't
1328
            --  want to drag dependencies against tasking related units in the
1329
            --  the common notification units. Additionally, no trace is ever
1330
            --  triggered from the common routine for the Unhandled_Raise case
1331
            --  in tasks, since an exception never appears unhandled in this
1332
            --  context because of this handler.
1333
 
1334
            if Exception_Trace = Unhandled_Raise then
1335
               Trace_Unhandled_Exception_In_Task (Self_ID);
1336
            end if;
1337
 
1338
            --  Update the cause that motivated the task termination so that
1339
            --  the appropriate information is passed to the task termination
1340
            --  procedure, as well as the associated Exception_Occurrence.
1341
 
1342
            Cause := Unhandled_Exception;
1343
 
1344
            Save_Occurrence (EO, SSL.Get_Current_Excep.all.all);
1345
 
1346
            if Global_Task_Debug_Event_Set then
1347
               Debug.Signal_Debug_Event
1348
                 (Debug.Debug_Event_Exception_Terminated, Self_ID);
1349
            end if;
1350
      end;
1351
 
1352
      --  Look for a task termination handler. This code is for all tasks but
1353
      --  the environment task. The task termination code for the environment
1354
      --  task is executed by SSL.Task_Termination_Handler.
1355
 
1356
      if Single_Lock then
1357
         Lock_RTS;
1358
      end if;
1359
 
1360
      Write_Lock (Self_ID);
1361
 
1362
      if Self_ID.Common.Specific_Handler /= null then
1363
         TH := Self_ID.Common.Specific_Handler;
1364
      else
1365
         --  Look for a fall-back handler following the master relationship
1366
         --  for the task.
1367
 
1368
         Search_Fall_Back_Handler (Self_ID);
1369
      end if;
1370
 
1371
      Unlock (Self_ID);
1372
 
1373
      if Single_Lock then
1374
         Unlock_RTS;
1375
      end if;
1376
 
1377
      --  Execute the task termination handler if we found it
1378
 
1379
      if TH /= null then
1380
         begin
1381
            TH.all (Cause, Self_ID, EO);
1382
 
1383
         exception
1384
 
1385
            --  RM-C.7.3 requires all exceptions raised here to be ignored
1386
 
1387
            when others =>
1388
               null;
1389
         end;
1390
      end if;
1391
 
1392
      if System.Stack_Usage.Is_Enabled then
1393
         Compute_Result (Self_ID.Common.Analyzer);
1394
         Report_Result (Self_ID.Common.Analyzer);
1395
      end if;
1396
 
1397
      Terminate_Task (Self_ID);
1398
   end Task_Wrapper;
1399
 
1400
   --------------------
1401
   -- Terminate_Task --
1402
   --------------------
1403
 
1404
   --  Before we allow the thread to exit, we must clean up. This is a delicate
1405
   --  job. We must wake up the task's master, who may immediately try to
1406
   --  deallocate the ATCB from the current task WHILE IT IS STILL EXECUTING.
1407
 
1408
   --  To avoid this, the parent task must be blocked up to the latest
1409
   --  statement executed. The trouble is that we have another step that we
1410
   --  also want to postpone to the very end, i.e., calling SSL.Destroy_TSD.
1411
   --  We have to postpone that until the end because compiler-generated code
1412
   --  is likely to try to access that data at just about any point.
1413
 
1414
   --  We can't call Destroy_TSD while we are holding any other locks, because
1415
   --  it locks Global_Task_Lock, and our deadlock prevention rules require
1416
   --  that to be the outermost lock. Our first "solution" was to just lock
1417
   --  Global_Task_Lock in addition to the other locks, and force the parent to
1418
   --  also lock this lock between its wakeup and its freeing of the ATCB. See
1419
   --  Complete_Task for the parent-side of the code that has the matching
1420
   --  calls to Task_Lock and Task_Unlock. That was not really a solution,
1421
   --  since the operation Task_Unlock continued to access the ATCB after
1422
   --  unlocking, after which the parent was observed to race ahead, deallocate
1423
   --  the ATCB, and then reallocate it to another task. The call to
1424
   --  Undefer_Abort in Task_Unlock by the "terminated" task was overwriting
1425
   --  the data of the new task that reused the ATCB! To solve this problem, we
1426
   --  introduced the new operation Final_Task_Unlock.
1427
 
1428
   procedure Terminate_Task (Self_ID : Task_Id) is
1429
      Environment_Task : constant Task_Id := STPO.Environment_Task;
1430
      Master_of_Task   : Integer;
1431
      Deallocate       : Boolean;
1432
 
1433
   begin
1434
      Debug.Task_Termination_Hook;
1435
 
1436
      if Runtime_Traces then
1437
         Send_Trace_Info (T_Terminate);
1438
      end if;
1439
 
1440
      --  Since GCC cannot allocate stack chunks efficiently without reordering
1441
      --  some of the allocations, we have to handle this unexpected situation
1442
      --  here. Normally we never have to call Vulnerable_Complete_Task here.
1443
 
1444
      if Self_ID.Common.Activator /= null then
1445
         Vulnerable_Complete_Task (Self_ID);
1446
      end if;
1447
 
1448
      Initialization.Task_Lock (Self_ID);
1449
 
1450
      if Single_Lock then
1451
         Lock_RTS;
1452
      end if;
1453
 
1454
      Master_of_Task := Self_ID.Master_of_Task;
1455
 
1456
      --  Check if the current task is an independent task If so, decrement
1457
      --  the Independent_Task_Count value.
1458
 
1459
      if Master_of_Task = Independent_Task_Level then
1460
         if Single_Lock then
1461
            Utilities.Independent_Task_Count :=
1462
              Utilities.Independent_Task_Count - 1;
1463
 
1464
         else
1465
            Write_Lock (Environment_Task);
1466
            Utilities.Independent_Task_Count :=
1467
              Utilities.Independent_Task_Count - 1;
1468
            Unlock (Environment_Task);
1469
         end if;
1470
      end if;
1471
 
1472
      --  Unprotect the guard page if needed
1473
 
1474
      Stack_Guard (Self_ID, False);
1475
 
1476
      Utilities.Make_Passive (Self_ID, Task_Completed => True);
1477
      Deallocate := Self_ID.Free_On_Termination;
1478
 
1479
      if Single_Lock then
1480
         Unlock_RTS;
1481
      end if;
1482
 
1483
      pragma Assert (Check_Exit (Self_ID));
1484
 
1485
      SSL.Destroy_TSD (Self_ID.Common.Compiler_Data);
1486
      Initialization.Final_Task_Unlock (Self_ID);
1487
 
1488
      --  WARNING: past this point, this thread must assume that the ATCB has
1489
      --  been deallocated, and can't access it anymore (which is why we have
1490
      --  saved the Free_On_Termination flag in a temporary variable).
1491
 
1492
      if Deallocate then
1493
         Free_Task (Self_ID);
1494
      end if;
1495
 
1496
      if Master_of_Task > 0 then
1497
         STPO.Exit_Task;
1498
      end if;
1499
   end Terminate_Task;
1500
 
1501
   ----------------
1502
   -- Terminated --
1503
   ----------------
1504
 
1505
   function Terminated (T : Task_Id) return Boolean is
1506
      Self_ID : constant Task_Id := STPO.Self;
1507
      Result  : Boolean;
1508
 
1509
   begin
1510
      Initialization.Defer_Abort_Nestable (Self_ID);
1511
 
1512
      if Single_Lock then
1513
         Lock_RTS;
1514
      end if;
1515
 
1516
      Write_Lock (T);
1517
      Result := T.Common.State = Terminated;
1518
      Unlock (T);
1519
 
1520
      if Single_Lock then
1521
         Unlock_RTS;
1522
      end if;
1523
 
1524
      Initialization.Undefer_Abort_Nestable (Self_ID);
1525
      return Result;
1526
   end Terminated;
1527
 
1528
   ----------------------------------------
1529
   -- Trace_Unhandled_Exception_In_Task --
1530
   ----------------------------------------
1531
 
1532
   procedure Trace_Unhandled_Exception_In_Task (Self_Id : Task_Id) is
1533
      procedure To_Stderr (S : String);
1534
      pragma Import (Ada, To_Stderr, "__gnat_to_stderr");
1535
 
1536
      use System.Soft_Links;
1537
      use System.Standard_Library;
1538
 
1539
      function To_Address is new
1540
        Ada.Unchecked_Conversion
1541
         (Task_Id, System.Task_Primitives.Task_Address);
1542
 
1543
      function Tailored_Exception_Information
1544
        (E : Exception_Occurrence) return String;
1545
      pragma Import
1546
        (Ada, Tailored_Exception_Information,
1547
         "__gnat_tailored_exception_information");
1548
 
1549
      Excep : constant Exception_Occurrence_Access :=
1550
                SSL.Get_Current_Excep.all;
1551
 
1552
   begin
1553
      --  This procedure is called by the task outermost handler in
1554
      --  Task_Wrapper below, so only once the task stack has been fully
1555
      --  unwound. The common notification routine has been called at the
1556
      --  raise point already.
1557
 
1558
      --  Lock to prevent unsynchronized output
1559
 
1560
      Initialization.Task_Lock (Self_Id);
1561
      To_Stderr ("task ");
1562
 
1563
      if Self_Id.Common.Task_Image_Len /= 0 then
1564
         To_Stderr
1565
           (Self_Id.Common.Task_Image (1 .. Self_Id.Common.Task_Image_Len));
1566
         To_Stderr ("_");
1567
      end if;
1568
 
1569
      To_Stderr (System.Address_Image (To_Address (Self_Id)));
1570
      To_Stderr (" terminated by unhandled exception");
1571
      To_Stderr ((1 => ASCII.LF));
1572
      To_Stderr (Tailored_Exception_Information (Excep.all));
1573
      Initialization.Task_Unlock (Self_Id);
1574
   end Trace_Unhandled_Exception_In_Task;
1575
 
1576
   ------------------------------------
1577
   -- Vulnerable_Complete_Activation --
1578
   ------------------------------------
1579
 
1580
   --  As in several other places, the locks of the activator and activated
1581
   --  task are both locked here. This follows our deadlock prevention lock
1582
   --  ordering policy, since the activated task must be created after the
1583
   --  activator.
1584
 
1585
   procedure Vulnerable_Complete_Activation (Self_ID : Task_Id) is
1586
      Activator : constant Task_Id := Self_ID.Common.Activator;
1587
 
1588
   begin
1589
      pragma Debug (Debug.Trace (Self_ID, "V_Complete_Activation", 'C'));
1590
 
1591
      Write_Lock (Activator);
1592
      Write_Lock (Self_ID);
1593
 
1594
      pragma Assert (Self_ID.Common.Activator /= null);
1595
 
1596
      --  Remove dangling reference to Activator, since a task may outlive its
1597
      --  activator.
1598
 
1599
      Self_ID.Common.Activator := null;
1600
 
1601
      --  Wake up the activator, if it is waiting for a chain of tasks to
1602
      --  activate, and we are the last in the chain to complete activation.
1603
 
1604
      if Activator.Common.State = Activator_Sleep then
1605
         Activator.Common.Wait_Count := Activator.Common.Wait_Count - 1;
1606
 
1607
         if Activator.Common.Wait_Count = 0 then
1608
            Wakeup (Activator, Activator_Sleep);
1609
         end if;
1610
      end if;
1611
 
1612
      --  The activator raises a Tasking_Error if any task it is activating
1613
      --  is completed before the activation is done. However, if the reason
1614
      --  for the task completion is an abort, we do not raise an exception.
1615
      --  See RM 9.2(5).
1616
 
1617
      if not Self_ID.Callable and then Self_ID.Pending_ATC_Level /= 0 then
1618
         Activator.Common.Activation_Failed := True;
1619
      end if;
1620
 
1621
      Unlock (Self_ID);
1622
      Unlock (Activator);
1623
 
1624
      --  After the activation, active priority should be the same as base
1625
      --  priority. We must unlock the Activator first, though, since it
1626
      --  should not wait if we have lower priority.
1627
 
1628
      if Get_Priority (Self_ID) /= Self_ID.Common.Base_Priority then
1629
         Write_Lock (Self_ID);
1630
         Set_Priority (Self_ID, Self_ID.Common.Base_Priority);
1631
         Unlock (Self_ID);
1632
      end if;
1633
   end Vulnerable_Complete_Activation;
1634
 
1635
   --------------------------------
1636
   -- Vulnerable_Complete_Master --
1637
   --------------------------------
1638
 
1639
   procedure Vulnerable_Complete_Master (Self_ID : Task_Id) is
1640
      C  : Task_Id;
1641
      P  : Task_Id;
1642
      CM : constant Master_Level := Self_ID.Master_Within;
1643
      T  : aliased Task_Id;
1644
 
1645
      To_Be_Freed : Task_Id;
1646
      --  This is a list of ATCBs to be freed, after we have released all RTS
1647
      --  locks. This is necessary because of the locking order rules, since
1648
      --  the storage manager uses Global_Task_Lock.
1649
 
1650
      pragma Warnings (Off);
1651
      function Check_Unactivated_Tasks return Boolean;
1652
      pragma Warnings (On);
1653
      --  Temporary error-checking code below. This is part of the checks
1654
      --  added in the new run time. Call it only inside a pragma Assert.
1655
 
1656
      -----------------------------
1657
      -- Check_Unactivated_Tasks --
1658
      -----------------------------
1659
 
1660
      function Check_Unactivated_Tasks return Boolean is
1661
      begin
1662
         if not Single_Lock then
1663
            Lock_RTS;
1664
         end if;
1665
 
1666
         Write_Lock (Self_ID);
1667
 
1668
         C := All_Tasks_List;
1669
         while C /= null loop
1670
            if C.Common.Activator = Self_ID and then C.Master_of_Task = CM then
1671
               return False;
1672
            end if;
1673
 
1674
            if C.Common.Parent = Self_ID and then C.Master_of_Task = CM then
1675
               Write_Lock (C);
1676
 
1677
               if C.Common.State = Unactivated then
1678
                  return False;
1679
               end if;
1680
 
1681
               Unlock (C);
1682
            end if;
1683
 
1684
            C := C.Common.All_Tasks_Link;
1685
         end loop;
1686
 
1687
         Unlock (Self_ID);
1688
 
1689
         if not Single_Lock then
1690
            Unlock_RTS;
1691
         end if;
1692
 
1693
         return True;
1694
      end Check_Unactivated_Tasks;
1695
 
1696
   --  Start of processing for Vulnerable_Complete_Master
1697
 
1698
   begin
1699
      pragma Debug
1700
        (Debug.Trace (Self_ID, "V_Complete_Master", 'C'));
1701
 
1702
      pragma Assert (Self_ID.Common.Wait_Count = 0);
1703
      pragma Assert
1704
        (Self_ID.Deferral_Level > 0
1705
          or else not System.Restrictions.Abort_Allowed);
1706
 
1707
      --  Count how many active dependent tasks this master currently has, and
1708
      --  record this in Wait_Count.
1709
 
1710
      --  This count should start at zero, since it is initialized to zero for
1711
      --  new tasks, and the task should not exit the sleep-loops that use this
1712
      --  count until the count reaches zero.
1713
 
1714
      --  While we're counting, if we run across any unactivated tasks that
1715
      --  belong to this master, we summarily terminate them as required by
1716
      --  RM-9.2(6).
1717
 
1718
      Lock_RTS;
1719
      Write_Lock (Self_ID);
1720
 
1721
      C := All_Tasks_List;
1722
      while C /= null loop
1723
 
1724
         --  Terminate unactivated (never-to-be activated) tasks
1725
 
1726
         if C.Common.Activator = Self_ID and then C.Master_of_Task = CM then
1727
 
1728
            --  Usually, C.Common.Activator = Self_ID implies C.Master_of_Task
1729
            --  = CM. The only case where C is pending activation by this
1730
            --  task, but the master of C is not CM is in Ada 2005, when C is
1731
            --  part of a return object of a build-in-place function.
1732
 
1733
            pragma Assert (C.Common.State = Unactivated);
1734
 
1735
            Write_Lock (C);
1736
            C.Common.Activator := null;
1737
            C.Common.State := Terminated;
1738
            C.Callable := False;
1739
            Utilities.Cancel_Queued_Entry_Calls (C);
1740
            Unlock (C);
1741
         end if;
1742
 
1743
         --  Count it if dependent on this master
1744
 
1745
         if C.Common.Parent = Self_ID and then C.Master_of_Task = CM then
1746
            Write_Lock (C);
1747
 
1748
            if C.Awake_Count /= 0 then
1749
               Self_ID.Common.Wait_Count := Self_ID.Common.Wait_Count + 1;
1750
            end if;
1751
 
1752
            Unlock (C);
1753
         end if;
1754
 
1755
         C := C.Common.All_Tasks_Link;
1756
      end loop;
1757
 
1758
      Self_ID.Common.State := Master_Completion_Sleep;
1759
      Unlock (Self_ID);
1760
 
1761
      if not Single_Lock then
1762
         Unlock_RTS;
1763
      end if;
1764
 
1765
      --  Wait until dependent tasks are all terminated or ready to terminate.
1766
      --  While waiting, the task may be awakened if the task's priority needs
1767
      --  changing, or this master is aborted. In the latter case, we abort the
1768
      --  dependents, and resume waiting until Wait_Count goes to zero.
1769
 
1770
      Write_Lock (Self_ID);
1771
 
1772
      loop
1773
         exit when Self_ID.Common.Wait_Count = 0;
1774
 
1775
         --  Here is a difference as compared to Complete_Master
1776
 
1777
         if Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level
1778
           and then not Self_ID.Dependents_Aborted
1779
         then
1780
            if Single_Lock then
1781
               Abort_Dependents (Self_ID);
1782
            else
1783
               Unlock (Self_ID);
1784
               Lock_RTS;
1785
               Abort_Dependents (Self_ID);
1786
               Unlock_RTS;
1787
               Write_Lock (Self_ID);
1788
            end if;
1789
         else
1790
            Sleep (Self_ID, Master_Completion_Sleep);
1791
         end if;
1792
      end loop;
1793
 
1794
      Self_ID.Common.State := Runnable;
1795
      Unlock (Self_ID);
1796
 
1797
      --  Dependents are all terminated or on terminate alternatives. Now,
1798
      --  force those on terminate alternatives to terminate, by aborting them.
1799
 
1800
      pragma Assert (Check_Unactivated_Tasks);
1801
 
1802
      if Self_ID.Alive_Count > 1 then
1803
         --  ???
1804
         --  Consider finding a way to skip the following extra steps if there
1805
         --  are no dependents with terminate alternatives. This could be done
1806
         --  by adding another count to the ATCB, similar to Awake_Count, but
1807
         --  keeping track of tasks that are on terminate alternatives.
1808
 
1809
         pragma Assert (Self_ID.Common.Wait_Count = 0);
1810
 
1811
         --  Force any remaining dependents to terminate by aborting them
1812
 
1813
         if not Single_Lock then
1814
            Lock_RTS;
1815
         end if;
1816
 
1817
         Abort_Dependents (Self_ID);
1818
 
1819
         --  Above, when we "abort" the dependents we are simply using this
1820
         --  operation for convenience. We are not required to support the full
1821
         --  abort-statement semantics; in particular, we are not required to
1822
         --  immediately cancel any queued or in-service entry calls. That is
1823
         --  good, because if we tried to cancel a call we would need to lock
1824
         --  the caller, in order to wake the caller up. Our anti-deadlock
1825
         --  rules prevent us from doing that without releasing the locks on C
1826
         --  and Self_ID. Releasing and retaking those locks would be wasteful
1827
         --  at best, and should not be considered further without more
1828
         --  detailed analysis of potential concurrent accesses to the ATCBs
1829
         --  of C and Self_ID.
1830
 
1831
         --  Count how many "alive" dependent tasks this master currently has,
1832
         --  and record this in Wait_Count. This count should start at zero,
1833
         --  since it is initialized to zero for new tasks, and the task should
1834
         --  not exit the sleep-loops that use this count until the count
1835
         --  reaches zero.
1836
 
1837
         pragma Assert (Self_ID.Common.Wait_Count = 0);
1838
 
1839
         Write_Lock (Self_ID);
1840
 
1841
         C := All_Tasks_List;
1842
         while C /= null loop
1843
            if C.Common.Parent = Self_ID and then C.Master_of_Task = CM then
1844
               Write_Lock (C);
1845
 
1846
               pragma Assert (C.Awake_Count = 0);
1847
 
1848
               if C.Alive_Count > 0 then
1849
                  pragma Assert (C.Terminate_Alternative);
1850
                  Self_ID.Common.Wait_Count := Self_ID.Common.Wait_Count + 1;
1851
               end if;
1852
 
1853
               Unlock (C);
1854
            end if;
1855
 
1856
            C := C.Common.All_Tasks_Link;
1857
         end loop;
1858
 
1859
         Self_ID.Common.State := Master_Phase_2_Sleep;
1860
         Unlock (Self_ID);
1861
 
1862
         if not Single_Lock then
1863
            Unlock_RTS;
1864
         end if;
1865
 
1866
         --  Wait for all counted tasks to finish terminating themselves
1867
 
1868
         Write_Lock (Self_ID);
1869
 
1870
         loop
1871
            exit when Self_ID.Common.Wait_Count = 0;
1872
            Sleep (Self_ID, Master_Phase_2_Sleep);
1873
         end loop;
1874
 
1875
         Self_ID.Common.State := Runnable;
1876
         Unlock (Self_ID);
1877
      end if;
1878
 
1879
      --  We don't wake up for abort here. We are already terminating just as
1880
      --  fast as we can, so there is no point.
1881
 
1882
      --  Remove terminated tasks from the list of Self_ID's dependents, but
1883
      --  don't free their ATCBs yet, because of lock order restrictions, which
1884
      --  don't allow us to call "free" or "malloc" while holding any other
1885
      --  locks. Instead, we put those ATCBs to be freed onto a temporary list,
1886
      --  called To_Be_Freed.
1887
 
1888
      if not Single_Lock then
1889
         Lock_RTS;
1890
      end if;
1891
 
1892
      C := All_Tasks_List;
1893
      P := null;
1894
      while C /= null loop
1895
         if C.Common.Parent = Self_ID and then C.Master_of_Task >= CM then
1896
            if P /= null then
1897
               P.Common.All_Tasks_Link := C.Common.All_Tasks_Link;
1898
            else
1899
               All_Tasks_List := C.Common.All_Tasks_Link;
1900
            end if;
1901
 
1902
            T := C.Common.All_Tasks_Link;
1903
            C.Common.All_Tasks_Link := To_Be_Freed;
1904
            To_Be_Freed := C;
1905
            C := T;
1906
 
1907
         else
1908
            P := C;
1909
            C := C.Common.All_Tasks_Link;
1910
         end if;
1911
      end loop;
1912
 
1913
      Unlock_RTS;
1914
 
1915
      --  Free all the ATCBs on the list To_Be_Freed
1916
 
1917
      --  The ATCBs in the list are no longer in All_Tasks_List, and after
1918
      --  any interrupt entries are detached from them they should no longer
1919
      --  be referenced.
1920
 
1921
      --  Global_Task_Lock (Task_Lock/Unlock) is locked in the loop below to
1922
      --  avoid a race between a terminating task and its parent. The parent
1923
      --  might try to deallocate the ACTB out from underneath the exiting
1924
      --  task. Note that Free will also lock Global_Task_Lock, but that is
1925
      --  OK, since this is the *one* lock for which we have a mechanism to
1926
      --  support nested locking. See Task_Wrapper and its finalizer for more
1927
      --  explanation.
1928
 
1929
      --  ???
1930
      --  The check "T.Common.Parent /= null ..." below is to prevent dangling
1931
      --  references to terminated library-level tasks, which could otherwise
1932
      --  occur during finalization of library-level objects. A better solution
1933
      --  might be to hook task objects into the finalization chain and
1934
      --  deallocate the ATCB when the task object is deallocated. However,
1935
      --  this change is not likely to gain anything significant, since all
1936
      --  this storage should be recovered en-masse when the process exits.
1937
 
1938
      while To_Be_Freed /= null loop
1939
         T := To_Be_Freed;
1940
         To_Be_Freed := T.Common.All_Tasks_Link;
1941
 
1942
         --  ??? On SGI there is currently no Interrupt_Manager, that's why we
1943
         --  need to check if the Interrupt_Manager_ID is null.
1944
 
1945
         if T.Interrupt_Entry and then Interrupt_Manager_ID /= null then
1946
            declare
1947
               Detach_Interrupt_Entries_Index : constant Task_Entry_Index := 1;
1948
               --  Corresponds to the entry index of System.Interrupts.
1949
               --  Interrupt_Manager.Detach_Interrupt_Entries. Be sure
1950
               --  to update this value when changing Interrupt_Manager specs.
1951
 
1952
               type Param_Type is access all Task_Id;
1953
 
1954
               Param : aliased Param_Type := T'Access;
1955
 
1956
            begin
1957
               System.Tasking.Rendezvous.Call_Simple
1958
                 (Interrupt_Manager_ID, Detach_Interrupt_Entries_Index,
1959
                  Param'Address);
1960
            end;
1961
         end if;
1962
 
1963
         if (T.Common.Parent /= null
1964
              and then T.Common.Parent.Common.Parent /= null)
1965
           or else T.Master_of_Task > Library_Task_Level
1966
         then
1967
            Initialization.Task_Lock (Self_ID);
1968
 
1969
            --  If Sec_Stack_Addr is not null, it means that Destroy_TSD
1970
            --  has not been called yet (case of an unactivated task).
1971
 
1972
            if T.Common.Compiler_Data.Sec_Stack_Addr /= Null_Address then
1973
               SSL.Destroy_TSD (T.Common.Compiler_Data);
1974
            end if;
1975
 
1976
            Vulnerable_Free_Task (T);
1977
            Initialization.Task_Unlock (Self_ID);
1978
         end if;
1979
      end loop;
1980
 
1981
      --  It might seem nice to let the terminated task deallocate its own
1982
      --  ATCB. That would not cover the case of unactivated tasks. It also
1983
      --  would force us to keep the underlying thread around past termination,
1984
      --  since references to the ATCB are possible past termination.
1985
 
1986
      --  Currently, we get rid of the thread as soon as the task terminates,
1987
      --  and let the parent recover the ATCB later.
1988
 
1989
      --  Some day, if we want to recover the ATCB earlier, at task
1990
      --  termination, we could consider using "fat task IDs", that include the
1991
      --  serial number with the ATCB pointer, to catch references to tasks
1992
      --  that no longer have ATCBs. It is not clear how much this would gain,
1993
      --  since the user-level task object would still be occupying storage.
1994
 
1995
      --  Make next master level up active. We don't need to lock the ATCB,
1996
      --  since the value is only updated by each task for itself.
1997
 
1998
      Self_ID.Master_Within := CM - 1;
1999
   end Vulnerable_Complete_Master;
2000
 
2001
   ------------------------------
2002
   -- Vulnerable_Complete_Task --
2003
   ------------------------------
2004
 
2005
   --  Complete the calling task
2006
 
2007
   --  This procedure must be called with abort deferred. It should only be
2008
   --  called by Complete_Task and Finalize_Global_Tasks (for the environment
2009
   --  task).
2010
 
2011
   --  The effect is similar to that of Complete_Master. Differences include
2012
   --  the closing of entries here, and computation of the number of active
2013
   --  dependent tasks in Complete_Master.
2014
 
2015
   --  We don't lock Self_ID before the call to Vulnerable_Complete_Activation,
2016
   --  because that does its own locking, and because we do not need the lock
2017
   --  to test Self_ID.Common.Activator. That value should only be read and
2018
   --  modified by Self.
2019
 
2020
   procedure Vulnerable_Complete_Task (Self_ID : Task_Id) is
2021
   begin
2022
      pragma Assert
2023
        (Self_ID.Deferral_Level > 0
2024
          or else not System.Restrictions.Abort_Allowed);
2025
      pragma Assert (Self_ID = Self);
2026
      pragma Assert (Self_ID.Master_Within = Self_ID.Master_of_Task + 1
2027
                       or else
2028
                     Self_ID.Master_Within = Self_ID.Master_of_Task + 2);
2029
      pragma Assert (Self_ID.Common.Wait_Count = 0);
2030
      pragma Assert (Self_ID.Open_Accepts = null);
2031
      pragma Assert (Self_ID.ATC_Nesting_Level = 1);
2032
 
2033
      pragma Debug (Debug.Trace (Self_ID, "V_Complete_Task", 'C'));
2034
 
2035
      if Single_Lock then
2036
         Lock_RTS;
2037
      end if;
2038
 
2039
      Write_Lock (Self_ID);
2040
      Self_ID.Callable := False;
2041
 
2042
      --  In theory, Self should have no pending entry calls left on its
2043
      --  call-stack. Each async. select statement should clean its own call,
2044
      --  and blocking entry calls should defer abort until the calls are
2045
      --  cancelled, then clean up.
2046
 
2047
      Utilities.Cancel_Queued_Entry_Calls (Self_ID);
2048
      Unlock (Self_ID);
2049
 
2050
      if Self_ID.Common.Activator /= null then
2051
         Vulnerable_Complete_Activation (Self_ID);
2052
      end if;
2053
 
2054
      if Single_Lock then
2055
         Unlock_RTS;
2056
      end if;
2057
 
2058
      --  If Self_ID.Master_Within = Self_ID.Master_of_Task + 2 we may have
2059
      --  dependent tasks for which we need to wait. Otherwise we just exit.
2060
 
2061
      if Self_ID.Master_Within = Self_ID.Master_of_Task + 2 then
2062
         Vulnerable_Complete_Master (Self_ID);
2063
      end if;
2064
   end Vulnerable_Complete_Task;
2065
 
2066
   --------------------------
2067
   -- Vulnerable_Free_Task --
2068
   --------------------------
2069
 
2070
   --  Recover all runtime system storage associated with the task T. This
2071
   --  should only be called after T has terminated and will no longer be
2072
   --  referenced.
2073
 
2074
   --  For tasks created by an allocator that fails, due to an exception, it
2075
   --  is called from Expunge_Unactivated_Tasks.
2076
 
2077
   --  For tasks created by elaboration of task object declarations it is
2078
   --  called from the finalization code of the Task_Wrapper procedure. It is
2079
   --  also called from Ada.Unchecked_Deallocation, for objects that are or
2080
   --  contain tasks.
2081
 
2082
   procedure Vulnerable_Free_Task (T : Task_Id) is
2083
   begin
2084
      pragma Debug (Debug.Trace (Self, "Vulnerable_Free_Task", 'C', T));
2085
 
2086
      if Single_Lock then
2087
         Lock_RTS;
2088
      end if;
2089
 
2090
      Write_Lock (T);
2091
      Initialization.Finalize_Attributes_Link.all (T);
2092
      Unlock (T);
2093
 
2094
      if Single_Lock then
2095
         Unlock_RTS;
2096
      end if;
2097
 
2098
      Free_Entry_Names (T);
2099
      System.Task_Primitives.Operations.Finalize_TCB (T);
2100
   end Vulnerable_Free_Task;
2101
 
2102
--  Package elaboration code
2103
 
2104
begin
2105
   --  Establish the Adafinal softlink
2106
 
2107
   --  This is not done inside the central RTS initialization routine
2108
   --  to avoid with'ing this package from System.Tasking.Initialization.
2109
 
2110
   SSL.Adafinal := Finalize_Global_Tasks'Access;
2111
 
2112
   --  Establish soft links for subprograms that manipulate master_id's.
2113
   --  This cannot be done when the RTS is initialized, because of various
2114
   --  elaboration constraints.
2115
 
2116
   SSL.Current_Master  := Stages.Current_Master'Access;
2117
   SSL.Enter_Master    := Stages.Enter_Master'Access;
2118
   SSL.Complete_Master := Stages.Complete_Master'Access;
2119
end System.Tasking.Stages;

powered by: WebSVN 2.1.0

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