OSDN Git Service

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