File : s-tasini.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 . I N I T I A L I Z A T I O N        --
   6 --                                                                          --
   7 --                                  B o d y                                 --
   8 --                                                                          --
   9 --         Copyright (C) 1992-2015, 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 --                                                                          --
  19 --                                                                          --
  20 --                                                                          --
  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 Style_Checks (All_Checks);
  33 --  Turn off subprogram alpha ordering check, since we group soft link bodies
  34 --  and dummy soft link bodies together separately in this unit.
  35 
  36 pragma Polling (Off);
  37 --  Turn polling off for this package. We don't need polling during any of the
  38 --  routines in this package, and more to the point, if we try to poll it can
  39 --  cause infinite loops.
  40 
  41 with Ada.Exceptions;
  42 
  43 with System.Task_Primitives;
  44 with System.Task_Primitives.Operations;
  45 with System.Soft_Links;
  46 with System.Soft_Links.Tasking;
  47 with System.Tasking.Debug;
  48 with System.Tasking.Task_Attributes;
  49 with System.Parameters;
  50 
  51 with System.Secondary_Stack;
  52 pragma Elaborate_All (System.Secondary_Stack);
  53 pragma Unreferenced (System.Secondary_Stack);
  54 --  Make sure the body of Secondary_Stack is elaborated before calling
  55 --  Init_Tasking_Soft_Links. See comments for this routine for explanation.
  56 
  57 package body System.Tasking.Initialization is
  58 
  59    package STPO renames System.Task_Primitives.Operations;
  60    package SSL  renames System.Soft_Links;
  61 
  62    use Parameters;
  63    use Task_Primitives.Operations;
  64 
  65    Global_Task_Lock : aliased System.Task_Primitives.RTS_Lock;
  66    --  This is a global lock; it is used to execute in mutual exclusion from
  67    --  all other tasks. It is only used by Task_Lock, Task_Unlock, and
  68    --  Final_Task_Unlock.
  69 
  70    ----------------------------------------------------------------------
  71    -- Tasking versions of some services needed by non-tasking programs --
  72    ----------------------------------------------------------------------
  73 
  74    procedure Abort_Defer;
  75    --  NON-INLINE versions without Self_ID for soft links
  76 
  77    procedure Abort_Undefer;
  78    --  NON-INLINE versions without Self_ID for soft links
  79 
  80    procedure Task_Lock;
  81    --  Locks out other tasks. Preceding a section of code by Task_Lock and
  82    --  following it by Task_Unlock creates a critical region. This is used
  83    --  for ensuring that a region of non-tasking code (such as code used to
  84    --  allocate memory) is tasking safe. Note that it is valid for calls to
  85    --  Task_Lock/Task_Unlock to be nested, and this must work properly, i.e.
  86    --  only the corresponding outer level Task_Unlock will actually unlock.
  87 
  88    procedure Task_Unlock;
  89    --  Releases lock previously set by call to Task_Lock. In the nested case,
  90    --  all nested locks must be released before other tasks competing for the
  91    --  tasking lock are released.
  92 
  93    function Get_Current_Excep return SSL.EOA;
  94    --  Task-safe version of SSL.Get_Current_Excep
  95 
  96    function Task_Name return String;
  97    --  Returns current task's name
  98 
  99    ------------------------
 100    --  Local Subprograms --
 101    ------------------------
 102 
 103    ----------------------------
 104    -- Tasking Initialization --
 105    ----------------------------
 106 
 107    procedure Init_RTS;
 108    --  This procedure completes the initialization of the GNARL. The first part
 109    --  of the initialization is done in the body of System.Tasking. It consists
 110    --  of initializing global locks, and installing tasking versions of certain
 111    --  operations used by the compiler. Init_RTS is called during elaboration.
 112 
 113    --------------------------
 114    -- Change_Base_Priority --
 115    --------------------------
 116 
 117    --  Call only with abort deferred and holding Self_ID locked
 118 
 119    procedure Change_Base_Priority (T : Task_Id) is
 120    begin
 121       if T.Common.Base_Priority /= T.New_Base_Priority then
 122          T.Common.Base_Priority := T.New_Base_Priority;
 123          Set_Priority (T, T.Common.Base_Priority);
 124       end if;
 125    end Change_Base_Priority;
 126 
 127    ------------------------
 128    -- Check_Abort_Status --
 129    ------------------------
 130 
 131    function Check_Abort_Status return Integer is
 132       Self_ID : constant Task_Id := Self;
 133    begin
 134       if Self_ID /= null
 135         and then Self_ID.Deferral_Level = 0
 136         and then Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level
 137       then
 138          return 1;
 139       else
 140          return 0;
 141       end if;
 142    end Check_Abort_Status;
 143 
 144    -----------------
 145    -- Defer_Abort --
 146    -----------------
 147 
 148    procedure Defer_Abort (Self_ID : Task_Id) is
 149    begin
 150       if No_Abort then
 151          return;
 152       end if;
 153 
 154       pragma Assert (Self_ID.Deferral_Level = 0);
 155 
 156       --  pragma Assert
 157       --    (Self_ID.Pending_ATC_Level >= Self_ID.ATC_Nesting_Level);
 158 
 159       --  The above check has been useful in detecting mismatched defer/undefer
 160       --  pairs. You may uncomment it when testing on systems that support
 161       --  preemptive abort.
 162 
 163       --  If the OS supports preemptive abort (e.g. pthread_kill), it should
 164       --  have happened already. A problem is with systems that do not support
 165       --  preemptive abort, and so rely on polling. On such systems we may get
 166       --  false failures of the assertion, since polling for pending abort does
 167       --  no occur until the abort undefer operation.
 168 
 169       --  Even on systems that only poll for abort, the assertion may be useful
 170       --  for catching missed abort completion polling points. The operations
 171       --  that undefer abort poll for pending aborts. This covers most of the
 172       --  places where the core Ada semantics require abort to be caught,
 173       --  without any special attention. However, this generally happens on
 174       --  exit from runtime system call, which means a pending abort will not
 175       --  be noticed on the way into the runtime system. We considered adding a
 176       --  check for pending aborts at this point, but chose not to, because of
 177       --  the overhead. Instead, we searched for RTS calls where abort
 178       --  completion is required and a task could go farther than Ada allows
 179       --  before undeferring abort; we then modified the code to ensure the
 180       --  abort would be detected.
 181 
 182       Self_ID.Deferral_Level := Self_ID.Deferral_Level + 1;
 183    end Defer_Abort;
 184 
 185    --------------------------
 186    -- Defer_Abort_Nestable --
 187    --------------------------
 188 
 189    procedure Defer_Abort_Nestable (Self_ID : Task_Id) is
 190    begin
 191       if No_Abort then
 192          return;
 193       end if;
 194 
 195       --  The following assertion is by default disabled. See the comment in
 196       --  Defer_Abort on the situations in which it may be useful to uncomment
 197       --  this assertion and enable the test.
 198 
 199       --  pragma Assert
 200       --    (Self_ID.Pending_ATC_Level >= Self_ID.ATC_Nesting_Level or else
 201       --     Self_ID.Deferral_Level > 0);
 202 
 203       Self_ID.Deferral_Level := Self_ID.Deferral_Level + 1;
 204    end Defer_Abort_Nestable;
 205 
 206    -----------------
 207    -- Abort_Defer --
 208    -----------------
 209 
 210    procedure Abort_Defer is
 211       Self_ID : Task_Id;
 212    begin
 213       if No_Abort then
 214          return;
 215       end if;
 216 
 217       Self_ID := STPO.Self;
 218       Self_ID.Deferral_Level := Self_ID.Deferral_Level + 1;
 219    end Abort_Defer;
 220 
 221    -----------------------
 222    -- Get_Current_Excep --
 223    -----------------------
 224 
 225    function Get_Current_Excep return SSL.EOA is
 226    begin
 227       return STPO.Self.Common.Compiler_Data.Current_Excep'Access;
 228    end Get_Current_Excep;
 229 
 230    -----------------------
 231    -- Do_Pending_Action --
 232    -----------------------
 233 
 234    --  Call only when holding no locks
 235 
 236    procedure Do_Pending_Action (Self_ID : Task_Id) is
 237       use type Ada.Exceptions.Exception_Id;
 238 
 239    begin
 240       pragma Assert (Self_ID = Self and then Self_ID.Deferral_Level = 0);
 241 
 242       --  Needs loop to recheck for pending action in case a new one occurred
 243       --  while we had abort deferred below.
 244 
 245       loop
 246          --  Temporarily defer abort so that we can lock Self_ID
 247 
 248          Self_ID.Deferral_Level := Self_ID.Deferral_Level + 1;
 249 
 250          if Single_Lock then
 251             Lock_RTS;
 252          end if;
 253 
 254          Write_Lock (Self_ID);
 255          Self_ID.Pending_Action := False;
 256          Unlock (Self_ID);
 257 
 258          if Single_Lock then
 259             Unlock_RTS;
 260          end if;
 261 
 262          --  Restore the original Deferral value
 263 
 264          Self_ID.Deferral_Level := Self_ID.Deferral_Level - 1;
 265 
 266          if not Self_ID.Pending_Action then
 267             if Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level then
 268                if not Self_ID.Aborting then
 269                   Self_ID.Aborting := True;
 270                   pragma Debug
 271                     (Debug.Trace (Self_ID, "raise Abort_Signal", 'B'));
 272                   raise Standard'Abort_Signal;
 273 
 274                   pragma Assert (not Self_ID.ATC_Hack);
 275 
 276                elsif Self_ID.ATC_Hack then
 277 
 278                   --  The solution really belongs in the Abort_Signal handler
 279                   --  for async. entry calls.  The present hack is very
 280                   --  fragile. It relies that the very next point after
 281                   --  Exit_One_ATC_Level at which the task becomes abortable
 282                   --  will be the call to Undefer_Abort in the
 283                   --  Abort_Signal handler.
 284 
 285                   Self_ID.ATC_Hack := False;
 286 
 287                   pragma Debug
 288                     (Debug.Trace
 289                      (Self_ID, "raise Abort_Signal (ATC hack)", 'B'));
 290                   raise Standard'Abort_Signal;
 291                end if;
 292             end if;
 293 
 294             return;
 295          end if;
 296       end loop;
 297    end Do_Pending_Action;
 298 
 299    -----------------------
 300    -- Final_Task_Unlock --
 301    -----------------------
 302 
 303    --  This version is only for use in Terminate_Task, when the task is
 304    --  relinquishing further rights to its own ATCB.
 305 
 306    --  There is a very interesting potential race condition there, where the
 307    --  old task may run concurrently with a new task that is allocated the old
 308    --  tasks (now reused) ATCB. The critical thing here is to not make any
 309    --  reference to the ATCB after the lock is released. See also comments on
 310    --  Terminate_Task and Unlock.
 311 
 312    procedure Final_Task_Unlock (Self_ID : Task_Id) is
 313    begin
 314       pragma Assert (Self_ID.Common.Global_Task_Lock_Nesting = 1);
 315       Unlock (Global_Task_Lock'Access, Global_Lock => True);
 316    end Final_Task_Unlock;
 317 
 318    --------------
 319    -- Init_RTS --
 320    --------------
 321 
 322    procedure Init_RTS is
 323       Self_Id : Task_Id;
 324    begin
 325       Tasking.Initialize;
 326 
 327       --  Terminate run time (regular vs restricted) specific initialization
 328       --  of the environment task.
 329 
 330       Self_Id := Environment_Task;
 331       Self_Id.Master_of_Task := Environment_Task_Level;
 332       Self_Id.Master_Within := Self_Id.Master_of_Task + 1;
 333 
 334       for L in Self_Id.Entry_Calls'Range loop
 335          Self_Id.Entry_Calls (L).Self := Self_Id;
 336          Self_Id.Entry_Calls (L).Level := L;
 337       end loop;
 338 
 339       Self_Id.Awake_Count := 1;
 340       Self_Id.Alive_Count := 1;
 341 
 342       --  Normally, a task starts out with internal master nesting level one
 343       --  larger than external master nesting level. It is incremented to one
 344       --  by Enter_Master, which is called in the task body only if the
 345       --  compiler thinks the task may have dependent tasks. There is no
 346       --  corresponding call to Enter_Master for the environment task, so we
 347       --  would need to increment it to 2 here. Instead, we set it to 3. By
 348       --  doing this we reserve the level 2 for server tasks of the runtime
 349       --  system. The environment task does not need to wait for these server
 350 
 351       Self_Id.Master_Within := Library_Task_Level;
 352 
 353       --  Initialize lock used to implement mutual exclusion between all tasks
 354 
 355       Initialize_Lock (Global_Task_Lock'Access, STPO.Global_Task_Level);
 356 
 357       --  Notify that the tasking run time has been elaborated so that
 358       --  the tasking version of the soft links can be used.
 359 
 360       if not No_Abort then
 361          SSL.Abort_Defer   := Abort_Defer'Access;
 362          SSL.Abort_Undefer := Abort_Undefer'Access;
 363       end if;
 364 
 365       SSL.Lock_Task          := Task_Lock'Access;
 366       SSL.Unlock_Task        := Task_Unlock'Access;
 367       SSL.Check_Abort_Status := Check_Abort_Status'Access;
 368       SSL.Task_Name          := Task_Name'Access;
 369       SSL.Get_Current_Excep  := Get_Current_Excep'Access;
 370 
 371       --  Initialize the tasking soft links (if not done yet) that are common
 372       --  to the full and the restricted run times.
 373 
 374       SSL.Tasking.Init_Tasking_Soft_Links;
 375 
 376       --  Abort is deferred in a new ATCB, so we need to undefer abort at this
 377       --  stage to make the environment task abortable.
 378 
 379       Undefer_Abort (Environment_Task);
 380    end Init_RTS;
 381 
 382    ---------------------------
 383    -- Locked_Abort_To_Level--
 384    ---------------------------
 385 
 386    --  Abort a task to the specified ATC nesting level.
 387    --  Call this only with T locked.
 388 
 389    --  An earlier version of this code contained a call to Wakeup. That should
 390    --  not be necessary here, if Abort_Task is implemented correctly, since
 391    --  Abort_Task should include the effect of Wakeup. However, the above call
 392    --  was in earlier versions of this file, and at least for some targets
 393    --  Abort_Task has not been doing Wakeup. It should not hurt to uncomment
 394    --  the above call, until the error is corrected for all targets.
 395 
 396    --  See extended comments in package body System.Tasking.Abort for the
 397    --  overall design of the implementation of task abort.
 398    --  ??? there is no such package ???
 399 
 400    --  If the task is sleeping it will be in an abort-deferred region, and will
 401    --  not have Abort_Signal raised by Abort_Task. Such an "abort deferral" is
 402    --  just to protect the RTS internals, and not necessarily required to
 403    --  enforce Ada semantics. Abort_Task should wake the task up and let it
 404    --  decide if it wants to complete the aborted construct immediately.
 405 
 406    --  Note that the effect of the low-level Abort_Task is not persistent.
 407    --  If the target task is not blocked, this wakeup will be missed.
 408 
 409    --  We don't bother calling Abort_Task if this task is aborting itself,
 410    --  since we are inside the RTS and have abort deferred. Similarly, We don't
 411    --  bother to call Abort_Task if T is terminated, since there is no need to
 412    --  abort a terminated task, and it could be dangerous to try if the task
 413    --  has stopped executing.
 414 
 415    --  Note that an earlier version of this code had some false reasoning about
 416    --  being able to reliably wake up a task that had suspended on a blocking
 417    --  system call that does not atomically release the task's lock (e.g., UNIX
 418    --  nanosleep, which we once thought could be used to implement delays).
 419    --  That still left the possibility of missed wakeups.
 420 
 421    --  We cannot safely call Vulnerable_Complete_Activation here, since that
 422    --  requires locking Self_ID.Parent. The anti-deadlock lock ordering rules
 423    --  would then require us to release the lock on Self_ID first, which would
 424    --  create a timing window for other tasks to lock Self_ID. This is
 425    --  significant for tasks that may be aborted before their execution can
 426    --  enter the task body, and so they do not get a chance to call
 427    --  Complete_Task. The actual work for this case is done in Terminate_Task.
 428 
 429    procedure Locked_Abort_To_Level
 430      (Self_ID : Task_Id;
 431       T       : Task_Id;
 432       L       : ATC_Level)
 433    is
 434    begin
 435       if not T.Aborting and then T /= Self_ID then
 436          case T.Common.State is
 437             when Unactivated | Terminated =>
 438                pragma Assert (False);
 439                null;
 440 
 441             when Activating | Runnable =>
 442 
 443                --  This is needed to cancel an asynchronous protected entry
 444                --  call during a requeue with abort.
 445 
 446                T.Entry_Calls
 447                  (T.ATC_Nesting_Level).Cancellation_Attempted := True;
 448 
 449             when Interrupt_Server_Blocked_On_Event_Flag =>
 450                null;
 451 
 452             when Delay_Sleep                              |
 453                  Async_Select_Sleep                       |
 454                  Interrupt_Server_Idle_Sleep              |
 455                  Interrupt_Server_Blocked_Interrupt_Sleep |
 456                  Timer_Server_Sleep                       |
 457                  AST_Server_Sleep                         =>
 458                Wakeup (T, T.Common.State);
 459 
 460             when Acceptor_Sleep | Acceptor_Delay_Sleep =>
 461                T.Open_Accepts := null;
 462                Wakeup (T, T.Common.State);
 463 
 464             when Entry_Caller_Sleep  =>
 465                T.Entry_Calls
 466                  (T.ATC_Nesting_Level).Cancellation_Attempted := True;
 467                Wakeup (T, T.Common.State);
 468 
 469             when Activator_Sleep         |
 470                  Master_Completion_Sleep |
 471                  Master_Phase_2_Sleep    |
 472                  Asynchronous_Hold       =>
 473                null;
 474          end case;
 475       end if;
 476 
 477       if T.Pending_ATC_Level > L then
 478          T.Pending_ATC_Level := L;
 479          T.Pending_Action := True;
 480 
 481          if L = 0 then
 482             T.Callable := False;
 483          end if;
 484 
 485          --  This prevents aborted task from accepting calls
 486 
 487          if T.Aborting then
 488 
 489             --  The test above is just a heuristic, to reduce wasteful
 490             --  calls to Abort_Task.  We are holding T locked, and this
 491             --  value will not be set to False except with T also locked,
 492             --  inside Exit_One_ATC_Level, so we should not miss wakeups.
 493 
 494             if T.Common.State = Acceptor_Sleep
 495                  or else
 496                T.Common.State = Acceptor_Delay_Sleep
 497             then
 498                T.Open_Accepts := null;
 499             end if;
 500 
 501          elsif T /= Self_ID and then
 502            (T.Common.State = Runnable
 503              or else T.Common.State = Interrupt_Server_Blocked_On_Event_Flag)
 504 
 505             --  The task is blocked on a system call waiting for the
 506             --  completion event. In this case Abort_Task may need to take
 507             --  special action in order to succeed.
 508 
 509          then
 510             Abort_Task (T);
 511          end if;
 512       end if;
 513    end Locked_Abort_To_Level;
 514 
 515    --------------------------------
 516    -- Remove_From_All_Tasks_List --
 517    --------------------------------
 518 
 519    procedure Remove_From_All_Tasks_List (T : Task_Id) is
 520       C        : Task_Id;
 521       Previous : Task_Id;
 522 
 523    begin
 524       pragma Debug
 525         (Debug.Trace (Self, "Remove_From_All_Tasks_List", 'C'));
 526 
 527       Previous := Null_Task;
 528       C := All_Tasks_List;
 529       while C /= Null_Task loop
 530          if C = T then
 531             if Previous = Null_Task then
 532                All_Tasks_List := All_Tasks_List.Common.All_Tasks_Link;
 533             else
 534                Previous.Common.All_Tasks_Link := C.Common.All_Tasks_Link;
 535             end if;
 536 
 537             return;
 538          end if;
 539 
 540          Previous := C;
 541          C := C.Common.All_Tasks_Link;
 542       end loop;
 543 
 544       pragma Assert (False);
 545    end Remove_From_All_Tasks_List;
 546 
 547    ---------------
 548    -- Task_Lock --
 549    ---------------
 550 
 551    procedure Task_Lock (Self_ID : Task_Id) is
 552    begin
 553       Self_ID.Common.Global_Task_Lock_Nesting :=
 554         Self_ID.Common.Global_Task_Lock_Nesting + 1;
 555 
 556       if Self_ID.Common.Global_Task_Lock_Nesting = 1 then
 557          Defer_Abort_Nestable (Self_ID);
 558          Write_Lock (Global_Task_Lock'Access, Global_Lock => True);
 559       end if;
 560    end Task_Lock;
 561 
 562    procedure Task_Lock is
 563    begin
 564       Task_Lock (STPO.Self);
 565    end Task_Lock;
 566 
 567    ---------------
 568    -- Task_Name --
 569    ---------------
 570 
 571    function Task_Name return String is
 572       Self_Id : constant Task_Id := STPO.Self;
 573    begin
 574       return Self_Id.Common.Task_Image (1 .. Self_Id.Common.Task_Image_Len);
 575    end Task_Name;
 576 
 577    -----------------
 578    -- Task_Unlock --
 579    -----------------
 580 
 581    procedure Task_Unlock (Self_ID : Task_Id) is
 582    begin
 583       pragma Assert (Self_ID.Common.Global_Task_Lock_Nesting > 0);
 584       Self_ID.Common.Global_Task_Lock_Nesting :=
 585         Self_ID.Common.Global_Task_Lock_Nesting - 1;
 586 
 587       if Self_ID.Common.Global_Task_Lock_Nesting = 0 then
 588          Unlock (Global_Task_Lock'Access, Global_Lock => True);
 589          Undefer_Abort_Nestable (Self_ID);
 590       end if;
 591    end Task_Unlock;
 592 
 593    procedure Task_Unlock is
 594    begin
 595       Task_Unlock (STPO.Self);
 596    end Task_Unlock;
 597 
 598    -------------------
 599    -- Undefer_Abort --
 600    -------------------
 601 
 602    --  Precondition : Self does not hold any locks
 603 
 604    --  Undefer_Abort is called on any abort completion point (aka.
 605    --  synchronization point). It performs the following actions if they
 606    --  are pending: (1) change the base priority, (2) abort the task.
 607 
 608    --  The priority change has to occur before abort. Otherwise, it would
 609    --  take effect no earlier than the next abort completion point.
 610 
 611    procedure Undefer_Abort (Self_ID : Task_Id) is
 612    begin
 613       if No_Abort then
 614          return;
 615       end if;
 616 
 617       pragma Assert (Self_ID.Deferral_Level = 1);
 618 
 619       Self_ID.Deferral_Level := Self_ID.Deferral_Level - 1;
 620 
 621       if Self_ID.Deferral_Level = 0 then
 622          pragma Assert (Check_No_Locks (Self_ID));
 623 
 624          if Self_ID.Pending_Action then
 625             Do_Pending_Action (Self_ID);
 626          end if;
 627       end if;
 628    end Undefer_Abort;
 629 
 630    ----------------------------
 631    -- Undefer_Abort_Nestable --
 632    ----------------------------
 633 
 634    --  An earlier version would re-defer abort if an abort is in progress.
 635    --  Then, we modified the effect of the raise statement so that it defers
 636    --  abort until control reaches a handler. That was done to prevent
 637    --  "skipping over" a handler if another asynchronous abort occurs during
 638    --  the propagation of the abort to the handler.
 639 
 640    --  There has been talk of reversing that decision, based on a newer
 641    --  implementation of exception propagation. Care must be taken to evaluate
 642    --  how such a change would interact with the above code and all the places
 643    --  where abort-deferral is used to bridge over critical transitions, such
 644    --  as entry to the scope of a region with a finalizer and entry into the
 645    --  body of an accept-procedure.
 646 
 647    procedure Undefer_Abort_Nestable (Self_ID : Task_Id) is
 648    begin
 649       if No_Abort then
 650          return;
 651       end if;
 652 
 653       pragma Assert (Self_ID.Deferral_Level > 0);
 654 
 655       Self_ID.Deferral_Level := Self_ID.Deferral_Level - 1;
 656 
 657       if Self_ID.Deferral_Level = 0 then
 658 
 659          pragma Assert (Check_No_Locks (Self_ID));
 660 
 661          if Self_ID.Pending_Action then
 662             Do_Pending_Action (Self_ID);
 663          end if;
 664       end if;
 665    end Undefer_Abort_Nestable;
 666 
 667    -------------------
 668    -- Abort_Undefer --
 669    -------------------
 670 
 671    procedure Abort_Undefer is
 672       Self_ID : Task_Id;
 673    begin
 674       if No_Abort then
 675          return;
 676       end if;
 677 
 678       Self_ID := STPO.Self;
 679 
 680       if Self_ID.Deferral_Level = 0 then
 681 
 682          --  In case there are different views on whether Abort is supported
 683          --  between the expander and the run time, we may end up with
 684          --  Self_ID.Deferral_Level being equal to zero, when called from
 685          --  the procedure created by the expander that corresponds to a
 686          --  task body. In this case, there's nothing to be done.
 687 
 688          --  See related code in System.Tasking.Stages.Create_Task resetting
 689          --  Deferral_Level when System.Restrictions.Abort_Allowed is False.
 690 
 691          return;
 692       end if;
 693 
 694       pragma Assert (Self_ID.Deferral_Level > 0);
 695       Self_ID.Deferral_Level := Self_ID.Deferral_Level - 1;
 696 
 697       if Self_ID.Deferral_Level = 0 then
 698          pragma Assert (Check_No_Locks (Self_ID));
 699 
 700          if Self_ID.Pending_Action then
 701             Do_Pending_Action (Self_ID);
 702          end if;
 703       end if;
 704    end Abort_Undefer;
 705 
 706    --------------------------
 707    -- Wakeup_Entry_Caller --
 708    --------------------------
 709 
 710    --  This is called at the end of service of an entry call, to abort the
 711    --  caller if he is in an abortable part, and to wake up the caller if it
 712    --  is on Entry_Caller_Sleep. It assumes that the call is already off-queue.
 713 
 714    --  (This enforces the rule that a task must be off-queue if its state is
 715    --  Done or Cancelled.) Call it holding the lock of Entry_Call.Self.
 716 
 717    --  Timed_Call or Simple_Call:
 718    --    The caller is waiting on Entry_Caller_Sleep, in
 719    --    Wait_For_Completion, or Wait_For_Completion_With_Timeout.
 720 
 721    --  Conditional_Call:
 722    --    The caller might be in Wait_For_Completion,
 723    --    waiting for a rendezvous (possibly requeued without abort)
 724    --    to complete.
 725 
 726    --  Asynchronous_Call:
 727    --    The caller may be executing in the abortable part o
 728    --    an async. select, or on a time delay,
 729    --    if Entry_Call.State >= Was_Abortable.
 730 
 731    procedure Wakeup_Entry_Caller
 732      (Self_ID    : Task_Id;
 733       Entry_Call : Entry_Call_Link;
 734       New_State  : Entry_Call_State)
 735    is
 736       Caller : constant Task_Id := Entry_Call.Self;
 737 
 738    begin
 739       pragma Debug (Debug.Trace
 740         (Self_ID, "Wakeup_Entry_Caller", 'E', Caller));
 741       pragma Assert (New_State = Done or else New_State = Cancelled);
 742 
 743       pragma Assert (Caller.Common.State /= Unactivated);
 744 
 745       Entry_Call.State := New_State;
 746 
 747       if Entry_Call.Mode = Asynchronous_Call then
 748 
 749          --  Abort the caller in his abortable part, but do so only if call has
 750          --  been queued abortably.
 751 
 752          if Entry_Call.State >= Was_Abortable or else New_State = Done then
 753             Locked_Abort_To_Level (Self_ID, Caller, Entry_Call.Level - 1);
 754          end if;
 755 
 756       elsif Caller.Common.State = Entry_Caller_Sleep then
 757          Wakeup (Caller, Entry_Caller_Sleep);
 758       end if;
 759    end Wakeup_Entry_Caller;
 760 
 761    -------------------------
 762    -- Finalize_Attributes --
 763    -------------------------
 764 
 765    procedure Finalize_Attributes (T : Task_Id) is
 766       Attr : Atomic_Address;
 767 
 768    begin
 769       for J in T.Attributes'Range loop
 770          Attr := T.Attributes (J);
 771 
 772          if Attr /= 0 and then Task_Attributes.Require_Finalization (J) then
 773             Task_Attributes.To_Attribute (Attr).Free (Attr);
 774             T.Attributes (J) := 0;
 775          end if;
 776       end loop;
 777    end Finalize_Attributes;
 778 
 779 begin
 780    Init_RTS;
 781 end System.Tasking.Initialization;