home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / adav313.zip / gnat-3_13p-os2-bin-20010916.zip / emx / gnatlib / s-tasini.adb < prev    next >
Text File  |  2000-07-19  |  34KB  |  937 lines

  1. ------------------------------------------------------------------------------
  2. --                                                                          --
  3. --                GNU ADA 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. --                             $Revision: 1.59 $
  10. --                                                                          --
  11. --            Copyright (C) 1991-1999, Florida State University             --
  12. --                                                                          --
  13. -- GNARL is free software; you can  redistribute it  and/or modify it under --
  14. -- terms of the  GNU General Public License as published  by the Free Soft- --
  15. -- ware  Foundation;  either version 2,  or (at your option) any later ver- --
  16. -- sion. GNARL is distributed in the hope that it will be useful, but WITH- --
  17. -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
  18. -- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
  19. -- for  more details.  You should have  received  a copy of the GNU General --
  20. -- Public License  distributed with GNARL; see file COPYING.  If not, write --
  21. -- to  the Free Software Foundation,  59 Temple Place - Suite 330,  Boston, --
  22. -- MA 02111-1307, USA.                                                      --
  23. --                                                                          --
  24. -- As a special exception,  if other files  instantiate  generics from this --
  25. -- unit, or you link  this unit with other files  to produce an executable, --
  26. -- this  unit  does not  by itself cause  the resulting  executable  to  be --
  27. -- covered  by the  GNU  General  Public  License.  This exception does not --
  28. -- however invalidate  any other reasons why  the executable file  might be --
  29. -- covered by the  GNU Public License.                                      --
  30. --                                                                          --
  31. -- GNARL was developed by the GNARL team at Florida State University. It is --
  32. -- now maintained by Ada Core Technologies Inc. in cooperation with Florida --
  33. -- State University (http://www.gnat.com).                                  --
  34. --                                                                          --
  35. ------------------------------------------------------------------------------
  36.  
  37. pragma Polling (Off);
  38. --  Turn polling off for this package. We don't need polling during any
  39. --  of the routines in this package, and more to the point, if we try
  40. --  to poll it can cause infinite loops.
  41.  
  42. --  This package provides overall initialization of the tasking portion
  43. --  of the RTS.  This package must be elaborated before any tasking
  44. --  features are used.  It also contains initialization for
  45. --  Ada Task Control Block (ATCB) records.
  46.  
  47. with Ada.Exceptions;
  48. --  used for Exception_Occurrence_Access.
  49.  
  50. with System.Tasking;
  51. pragma Elaborate_All (System.Tasking);
  52. --  ensure that the first step initializations have been performed
  53.  
  54. with System.Task_Primitives;
  55. --  used for Lock
  56.  
  57. with System.Task_Primitives.Operations;
  58. --  used for Set_Priority
  59. --           Write_Lock
  60. --           Unlock
  61. --           Initialize_Lock
  62.  
  63. with System.Soft_Links;
  64. --  used for the non-tasking routines (*_NT) that refer to global data.
  65. --  They are needed here before the tasking run time has been elaborated.
  66.  
  67. with System.Tasking.Debug;
  68. --  used for Trace
  69.  
  70. with System.Tasking.Task_Attributes;
  71. --  used for All_Attrs_L
  72.  
  73. with System.Stack_Checking;
  74.  
  75. package body System.Tasking.Initialization is
  76.  
  77.    package STPO renames System.Task_Primitives.Operations;
  78.    package SSL  renames System.Soft_Links;
  79.  
  80.    use System.Task_Primitives.Operations;
  81.  
  82.    Global_Task_Lock : aliased System.Task_Primitives.RTS_Lock;
  83.    --  This is a global lock; it is used to execute in mutual exclusion
  84.    --  from all other tasks.  It is only used by Task_Lock,
  85.    --  Task_Unlock, and Final_Task_Unlock.
  86.  
  87.    -----------------------------------------------------------------
  88.    -- Tasking versions of services needed by non-tasking programs --
  89.    -----------------------------------------------------------------
  90.  
  91.    procedure Task_Lock;
  92.    --  Locks out other tasks. Preceding a section of code by Task_Lock and
  93.    --  following it by Task_Unlock creates a critical region. This is used
  94.    --  for ensuring that a region of non-tasking code (such as code used to
  95.    --  allocate memory) is tasking safe. Note that it is valid for calls to
  96.    --  Task_Lock/Task_Unlock to be nested, and this must work properly, i.e.
  97.    --  only the corresponding outer level Task_Unlock will actually unlock.
  98.  
  99.    procedure Task_Unlock;
  100.    --  Releases lock previously set by call to Task_Lock. In the nested case,
  101.    --  all nested locks must be released before other tasks competing for the
  102.    --  tasking lock are released.
  103.  
  104.    function  Get_Jmpbuf_Address return  Address;
  105.    procedure Set_Jmpbuf_Address (Addr : Address);
  106.    --  Get/Set Jmpbuf_Address for current task
  107.  
  108.    function  Get_Sec_Stack_Addr return  Address;
  109.    procedure Set_Sec_Stack_Addr (Addr : Address);
  110.    --  Get/Set location of current task's secondary stack
  111.  
  112.    function  Get_Exc_Stack_Addr return Address;
  113.    --  Get the exception stack for the current task
  114.  
  115.    procedure Set_Exc_Stack_Addr (Self_ID : Address; Addr : Address);
  116.    --  Self_ID is the Task_ID of the task that gets the exception stack.
  117.    --  For Self_ID = Null_Address, the current task gets the exception stack.
  118.  
  119.    function  Get_Machine_State_Addr return Address;
  120.    procedure Set_Machine_State_Addr (Addr : Address);
  121.    --  Get/Set the address for storing the current task's machine state
  122.  
  123.    function Get_Current_Excep return SSL.EOA;
  124.    --  Comments needed???
  125.  
  126.    procedure Timed_Delay_T (Time : Duration; Mode : Integer);
  127.    --  Comments needed???
  128.  
  129.    function Get_Stack_Info return Stack_Checking.Stack_Access;
  130.    --  Get access to the current task's Stack_Info
  131.  
  132.    procedure Update_Exception
  133.      (X : Ada.Exceptions.Exception_Occurrence
  134.         := Ada.Exceptions.Current_Target_Exception);
  135.    --  Handle exception setting and check for pending actions
  136.  
  137.    ------------------------
  138.    --  Local Subprograms --
  139.    ------------------------
  140.  
  141.    procedure Do_Pending_Action (Self_ID : Task_ID);
  142.    --  This is introduced to allow more efficient
  143.    --  in-line expansion of Undefer_Abort.
  144.  
  145.    ----------------------------
  146.    -- Tasking Initialization --
  147.    ----------------------------
  148.  
  149.    procedure Init_RTS;
  150.    --  This procedure completes the initialization of the GNARL. The first
  151.    --  part of the initialization is done in the body of System.Tasking.
  152.    --  It consists of initializing global locks, and installing tasking
  153.    --  versions of certain operations used by the compiler. Init_RTS is called
  154.    --  during elaboration.
  155.  
  156.    --------------------------
  157.    -- Change_Base_Priority --
  158.    --------------------------
  159.  
  160.    --  Call only with abort deferred and holding Self_ID locked.
  161.  
  162.    procedure Change_Base_Priority (T : Task_ID) is
  163.    begin
  164.       if T.Common.Base_Priority /= T.New_Base_Priority then
  165.          T.Common.Base_Priority := T.New_Base_Priority;
  166.          Set_Priority (T, T.Common.Base_Priority);
  167.       end if;
  168.    end Change_Base_Priority;
  169.  
  170.    -------------------------------
  171.    -- Poll_Base_Priority_Change --
  172.    -------------------------------
  173.  
  174.    --  Poll for pending base priority change and for held tasks.
  175.    --  This should always be called with (only) Self_ID locked.
  176.    --  It may temporarily release Self_ID's lock.
  177.  
  178.    --  The call to Yield is to force enqueuing at the
  179.    --  tail of the dispatching queue.
  180.  
  181.    --  We must unlock Self_ID for this to take effect,
  182.    --  since we are inheriting high active priority from the lock.
  183.  
  184.    --  See also Poll_Base_Priority_Change_At_Entry_Call,
  185.    --  in package System.Tasking.Entry_Calls.
  186.  
  187.    --  In this version, we check if the task is held too because
  188.    --  doing this only in Do_Pending_Action is not enough.
  189.  
  190.    procedure Poll_Base_Priority_Change (Self_ID : Task_ID) is
  191.    begin
  192.       if Dynamic_Priority_Support
  193.         and then Self_ID.Pending_Priority_Change
  194.       then
  195.          --  Check for ceiling violations ???
  196.  
  197.          Self_ID.Pending_Priority_Change := False;
  198.  
  199.          if Self_ID.Common.Base_Priority = Self_ID.New_Base_Priority then
  200.             Unlock (Self_ID);
  201.             Yield;
  202.             Write_Lock (Self_ID);
  203.  
  204.          elsif Self_ID.Common.Base_Priority < Self_ID.New_Base_Priority then
  205.             Self_ID.Common.Base_Priority := Self_ID.New_Base_Priority;
  206.             Set_Priority (Self_ID, Self_ID.Common.Base_Priority);
  207.  
  208.          else
  209.             --  Lowering priority
  210.  
  211.             Self_ID.Common.Base_Priority := Self_ID.New_Base_Priority;
  212.             Set_Priority (Self_ID, Self_ID.Common.Base_Priority);
  213.             Unlock (Self_ID);
  214.             Yield;
  215.             Write_Lock (Self_ID);
  216.          end if;
  217.       end if;
  218.    end Poll_Base_Priority_Change;
  219.  
  220.    --------------------
  221.    -- Defer_Abortion --
  222.    --------------------
  223.  
  224.    --  ??????
  225.    --  Phase out Defer_Abortion without Self_ID
  226.    --  to reduce overhead due to multiple calls to Self
  227.  
  228.    procedure Defer_Abortion is
  229.       Self_ID : constant Task_ID := STPO.Self;
  230.  
  231.    begin
  232.       Self_ID.Deferral_Level := Self_ID.Deferral_Level + 1;
  233.    end Defer_Abortion;
  234.  
  235.    ----------------------
  236.    -- Undefer_Abortion --
  237.    ----------------------
  238.  
  239.    --  Phase out RTS-internal use of Undefer_Abortion
  240.    --  to reduce overhead due to multiple calls to Self.
  241.  
  242.    procedure Undefer_Abortion is
  243.       Self_ID : constant Task_ID := STPO.Self;
  244.  
  245.    begin
  246.       pragma Assert (Self_ID.Deferral_Level > 0);
  247.  
  248.       Self_ID.Deferral_Level := Self_ID.Deferral_Level - 1;
  249.  
  250.       if Self_ID.Deferral_Level = 0 then
  251.          pragma Assert (Check_No_Locks (Self_ID));
  252.  
  253.          if Self_ID.Pending_Action then
  254.             Do_Pending_Action (Self_ID);
  255.          end if;
  256.       end if;
  257.    end Undefer_Abortion;
  258.  
  259.    -----------------
  260.    -- Defer_Abort --
  261.    -----------------
  262.  
  263.    procedure Defer_Abort (Self_ID : Task_ID) is
  264.    begin
  265.  
  266.       pragma Assert (Self_ID.Deferral_Level = 0);
  267.  
  268. --        pragma Assert
  269. --          (Self_ID.Pending_ATC_Level >= Self_ID.ATC_Nesting_Level);
  270.  
  271.       --  The above check has been useful in detecting mismatched
  272.       --  defer/undefer pairs. You may uncomment it when testing on
  273.       --  systems that support preemptive abort.
  274.  
  275.       --  If the OS supports preemptive abort (e.g. pthread_kill),
  276.       --  it should have happened already. A problem is with systems
  277.       --  that do not support preemptive abort, and so rely on polling.
  278.       --  On such systems we may get false failures of the assertion,
  279.       --  since polling for pending abort does no occur until the abort
  280.       --  undefer operation.
  281.  
  282.       --  Even on systems that only poll for abort, the assertion may
  283.       --  be useful for catching missed abort completion polling points.
  284.       --  The operations that undefer abort poll for pending aborts.
  285.       --  This covers most of the places where the core Ada semantics
  286.       --  require abort to be caught, without any special attention.
  287.       --  However, this generally happens on exit from runtime system
  288.       --  call, which means a pending abort will not be noticed on the
  289.       --  way into the runtime system.  We considered adding a check
  290.       --  for pending aborts at this point, but chose not to, because
  291.       --  of the overhead.  Instead, we searched for RTS calls that
  292.       --  where abort completion is required and a task could go
  293.       --  farther than Ada allows  before undeferring abort; we then
  294.       --  modified the code to ensure the abort would be detected.
  295.  
  296.       Self_ID.Deferral_Level := Self_ID.Deferral_Level + 1;
  297.    end Defer_Abort;
  298.  
  299.    --------------------------
  300.    -- Defer_Abort_Nestable --
  301.    --------------------------
  302.  
  303.    procedure Defer_Abort_Nestable (Self_ID : Task_ID) is
  304.    begin
  305.  
  306. --        pragma Assert
  307. --          ((Self_ID.Pending_ATC_Level >= Self_ID.ATC_Nesting_Level or else
  308. --            Self_ID.Deferral_Level > 0));
  309.  
  310.       --  See comment in Defer_Abort on the situations in which it may
  311.       --  be useful to uncomment the above assertion.
  312.  
  313.       Self_ID.Deferral_Level := Self_ID.Deferral_Level + 1;
  314.    end Defer_Abort_Nestable;
  315.  
  316.    -------------------
  317.    -- Undefer_Abort --
  318.    -------------------
  319.  
  320.    --  Precondition : Self does not hold any locks!
  321.  
  322.    --  Undefer_Abort is called on any abortion completion point (aka.
  323.    --  synchronization point). It performs the following actions if they
  324.    --  are pending: (1) change the base priority, (2) abort the task,
  325.    --  (3) raise a pending exception.
  326.  
  327.    --  The priority change has to occur before abortion. Otherwise, it would
  328.    --  take effect no earlier than the next abortion completion point.
  329.  
  330.    procedure Undefer_Abort (Self_ID : Task_ID) is
  331.    begin
  332.       pragma Assert (Self_ID.Deferral_Level = 1);
  333.  
  334.       Self_ID.Deferral_Level := Self_ID.Deferral_Level - 1;
  335.  
  336.       if Self_ID.Deferral_Level = 0 then
  337.          pragma Assert (Check_No_Locks (Self_ID));
  338.  
  339.          if Self_ID.Pending_Action then
  340.             Do_Pending_Action (Self_ID);
  341.          end if;
  342.       end if;
  343.    end Undefer_Abort;
  344.  
  345.    ----------------------------
  346.    -- Undefer_Abort_Nestable --
  347.    ----------------------------
  348.    --  An earlier version  would re-defer abort if an abort is
  349.    --  in progress.  Then, we modified the effect of the raise
  350.    --  statement so that it defers abort until control reaches a
  351.    --  handler.  That was done to prevent "skipping over" a
  352.    --  handler if another asynchronous abort occurs during the
  353.    --  propagation of the abort to the handler.
  354.  
  355.    --  There has been talk of reversing that decision, based on
  356.    --  a newer implementation of exception propagation.  Care must
  357.    --  be taken to evaluate how such a change would interact with
  358.    --  the above code and all the places where abort-deferral is
  359.    --  used to bridge over critical transitions, such as entry to
  360.    --  the scope of a region with a finalizer and entry into the
  361.    --  body of an accept-procedure.
  362.  
  363.    procedure Undefer_Abort_Nestable (Self_ID : Task_ID) is
  364.    begin
  365.       pragma Assert (Self_ID.Deferral_Level > 0);
  366.  
  367.       Self_ID.Deferral_Level := Self_ID.Deferral_Level - 1;
  368.  
  369.       if Self_ID.Deferral_Level = 0 then
  370.  
  371.          pragma Assert (Check_No_Locks (Self_ID));
  372.  
  373.          if Self_ID.Pending_Action then
  374.             Do_Pending_Action (Self_ID);
  375.          end if;
  376.       end if;
  377.    end Undefer_Abort_Nestable;
  378.  
  379.    ----------------------
  380.    -- Update_Exception --
  381.    ----------------------
  382.  
  383.    --  Call only when holding no locks.
  384.  
  385.    procedure Update_Exception
  386.      (X : Ada.Exceptions.Exception_Occurrence
  387.         := Ada.Exceptions.Current_Target_Exception)
  388.    is
  389.       Self_Id : constant Task_ID := Self;
  390.  
  391.       use Ada.Exceptions;
  392.  
  393.    begin
  394.       Save_Occurrence (Self_Id.Common.Compiler_Data.Current_Excep, X);
  395.  
  396.       if Self_Id.Deferral_Level = 0 then
  397.          if Self_Id.Pending_Action then
  398.             Self_Id.Pending_Action := False;
  399.             Self_Id.Deferral_Level := Self_Id.Deferral_Level + 1;
  400.             Write_Lock (Self_Id);
  401.             Self_Id.Pending_Action := False;
  402.             Poll_Base_Priority_Change (Self_Id);
  403.             Unlock (Self_Id);
  404.             Self_Id.Deferral_Level := Self_Id.Deferral_Level - 1;
  405.  
  406.             if Self_Id.Pending_ATC_Level < Self_Id.ATC_Nesting_Level then
  407.                if not Self_Id.Aborting then
  408.                   Self_Id.Aborting := True;
  409.                   raise Standard'Abort_Signal;
  410.                end if;
  411.             end if;
  412.          end if;
  413.       end if;
  414.    end Update_Exception;
  415.  
  416.    -----------------------
  417.    -- Do_Pending_Action --
  418.    -----------------------
  419.  
  420.    --  Call only when holding no locks.
  421.  
  422.    procedure Do_Pending_Action (Self_ID : Task_ID) is
  423.       use type Ada.Exceptions.Exception_Id;
  424.    begin
  425.       pragma Assert (Self_ID = Self and then Self_ID.Deferral_Level = 0);
  426.  
  427.       --  Needs loop to recheck for pending action in case a new one occurred
  428.       --  while we had abort deferred below.
  429.  
  430.       loop
  431.          --  Temporarily defer abortion so that we can lock Self_ID.
  432.  
  433.          Self_ID.Deferral_Level := Self_ID.Deferral_Level + 1;
  434.  
  435.          Write_Lock (Self_ID);
  436.          Self_ID.Pending_Action := False;
  437.          Poll_Base_Priority_Change (Self_ID);
  438.          Unlock (Self_ID);
  439.  
  440.          --  Restore the original Deferral value.
  441.  
  442.          Self_ID.Deferral_Level := Self_ID.Deferral_Level - 1;
  443.  
  444.          if not Self_ID.Pending_Action then
  445.             if Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level then
  446.                if not Self_ID.Aborting then
  447.                   Self_ID.Aborting := True;
  448.                   pragma Debug
  449.                     (Debug.Trace (Self_ID, "raise Abort_Signal", 'B'));
  450.                   raise Standard'Abort_Signal;
  451.  
  452.                   pragma Assert (not Self_ID.ATC_Hack);
  453.  
  454.                elsif Self_ID.ATC_Hack then
  455.                   --  The solution really belongs in the Abort_Signal handler
  456.                   --  for async. entry calls.  The present hack is very
  457.                   --  fragile. It relies that the very next point after
  458.                   --  Exit_One_ATC_Level at which the task becomes abortable
  459.                   --  will be the call to Undefer_Abort in the
  460.                   --  Abort_Signal handler.
  461.  
  462.                   Self_ID.ATC_Hack := False;
  463.  
  464.                   pragma Debug
  465.                     (Debug.Trace
  466.                      (Self_ID, "raise Abort_Signal (ATC hack)", 'B'));
  467.                   raise Standard'Abort_Signal;
  468.                end if;
  469.             end if;
  470.  
  471.             return;
  472.          end if;
  473.       end loop;
  474.    end Do_Pending_Action;
  475.  
  476.    --------------
  477.    -- Init_RTS --
  478.    --------------
  479.  
  480.    procedure Init_RTS is
  481.    begin
  482.       --  Initialize lock used to implement mutual exclusion between all tasks
  483.  
  484.       Initialize_Lock (Global_Task_Lock'Access, STPO.Global_Task_Level);
  485.  
  486.       --  Initialize lock used to implement mutual exclusion in the package
  487.       --  System.Task_Attributes.
  488.  
  489.       Initialize_Lock (System.Tasking.Task_Attributes.All_Attrs_L'Access,
  490.         All_Attrs_Level);
  491.  
  492.       --  Notify that the tasking run time has been elaborated so that
  493.       --  the tasking version of the soft links can be used.
  494.  
  495.       SSL.Abort_Defer            := Defer_Abortion'Access;
  496.       SSL.Abort_Undefer          := Undefer_Abortion'Access;
  497.       SSL.Update_Exception       := Update_Exception'Access;
  498.       SSL.Lock_Task              := Task_Lock'Access;
  499.       SSL.Unlock_Task            := Task_Unlock'Access;
  500.       SSL.Get_Jmpbuf_Address     := Get_Jmpbuf_Address'Access;
  501.       SSL.Set_Jmpbuf_Address     := Set_Jmpbuf_Address'Access;
  502.       SSL.Get_Sec_Stack_Addr     := Get_Sec_Stack_Addr'Access;
  503.       SSL.Set_Sec_Stack_Addr     := Set_Sec_Stack_Addr'Access;
  504.       SSL.Get_Exc_Stack_Addr     := Get_Exc_Stack_Addr'Access;
  505.       SSL.Set_Exc_Stack_Addr     := Set_Exc_Stack_Addr'Access;
  506.       SSL.Get_Machine_State_Addr := Get_Machine_State_Addr'Access;
  507.       SSL.Set_Machine_State_Addr := Set_Machine_State_Addr'Access;
  508.       SSL.Get_Current_Excep      := Get_Current_Excep'Access;
  509.       SSL.Clock                  := STPO.Clock'Access;
  510.       SSL.Timed_Delay            := Timed_Delay_T'Access;
  511.       SSL.Check_Abort_Status     := Check_Abort_Status'Access;
  512.       SSL.Get_Stack_Info         := Get_Stack_Info'Access;
  513.  
  514.       --  No need to create a new Secondary Stack, since we will use the
  515.       --  default one created in s-secsta.adb
  516.  
  517.       SSL.Set_Sec_Stack_Addr     (SSL.Get_Sec_Stack_Addr_NT);
  518.       SSL.Set_Exc_Stack_Addr     (Null_Address, SSL.Get_Exc_Stack_Addr_NT);
  519.       SSL.Set_Jmpbuf_Address     (SSL.Get_Jmpbuf_Address_NT);
  520.       SSL.Set_Machine_State_Addr (SSL.Get_Machine_State_Addr_NT);
  521.  
  522.       --  Abortion is deferred in a new ATCB, so we need to undefer abortion
  523.       --  at this stage to make the environment task abortable.
  524.  
  525.       Undefer_Abort (Environment_Task);
  526.    end Init_RTS;
  527.  
  528.    --------------------------------
  529.    -- Remove_From_All_Tasks_List --
  530.    --------------------------------
  531.  
  532.    procedure Remove_From_All_Tasks_List (T : Task_ID) is
  533.       C        : Task_ID;
  534.       Previous : Task_ID;
  535.  
  536.    begin
  537.       pragma Debug
  538.         (Debug.Trace ("Remove_From_All_Tasks_List", 'C'));
  539.  
  540.       Lock_All_Tasks_List;
  541.  
  542.       Previous := Null_Task;
  543.       C := All_Tasks_List;
  544.       while C /= Null_Task loop
  545.          if C = T then
  546.             if Previous = Null_Task then
  547.                All_Tasks_List :=
  548.                  All_Tasks_List.Common.All_Tasks_Link;
  549.             else
  550.                Previous.Common.All_Tasks_Link := C.Common.All_Tasks_Link;
  551.             end if;
  552.  
  553.             Unlock_All_Tasks_List;
  554.             return;
  555.          end if;
  556.  
  557.          Previous := C;
  558.          C := C.Common.All_Tasks_Link;
  559.       end loop;
  560.  
  561.       pragma Assert (False);
  562.    end Remove_From_All_Tasks_List;
  563.  
  564.    ---------------
  565.    -- Task_Lock --
  566.    ---------------
  567.  
  568.    procedure Task_Lock is
  569.       T : Task_ID := STPO.Self;
  570.  
  571.    begin
  572.       T.Global_Task_Lock_Nesting := T.Global_Task_Lock_Nesting + 1;
  573.  
  574.       if T.Global_Task_Lock_Nesting = 1 then
  575.          Defer_Abort_Nestable (T);
  576.          Write_Lock (Global_Task_Lock'Access);
  577.       end if;
  578.    end Task_Lock;
  579.  
  580.    procedure Task_Lock (Self_ID : Task_ID) is
  581.    begin
  582.       Self_ID.Global_Task_Lock_Nesting := Self_ID.Global_Task_Lock_Nesting + 1;
  583.  
  584.       if Self_ID.Global_Task_Lock_Nesting = 1 then
  585.          Defer_Abort_Nestable (Self_ID);
  586.          Write_Lock (Global_Task_Lock'Access);
  587.       end if;
  588.    end Task_Lock;
  589.  
  590.    -----------------
  591.    -- Task_Unlock --
  592.    -----------------
  593.  
  594.    procedure Task_Unlock is
  595.       T : Task_ID := STPO.Self;
  596.  
  597.    begin
  598.       pragma Assert (T.Global_Task_Lock_Nesting > 0);
  599.  
  600.       T.Global_Task_Lock_Nesting := T.Global_Task_Lock_Nesting - 1;
  601.  
  602.       if T.Global_Task_Lock_Nesting = 0 then
  603.          Unlock (Global_Task_Lock'Access);
  604.          Undefer_Abort_Nestable (T);
  605.       end if;
  606.    end Task_Unlock;
  607.  
  608.    procedure Task_Unlock (Self_ID : Task_ID) is
  609.    begin
  610.       Self_ID.Global_Task_Lock_Nesting := Self_ID.Global_Task_Lock_Nesting - 1;
  611.  
  612.       if Self_ID.Global_Task_Lock_Nesting = 0 then
  613.          Unlock (Global_Task_Lock'Access);
  614.          Undefer_Abort_Nestable (Self_ID);
  615.       end if;
  616.    end Task_Unlock;
  617.  
  618.    -----------------------
  619.    -- Final_Task_Unlock --
  620.    -----------------------
  621.  
  622.    --  This version is only for use in Terminate_Task, when the task
  623.    --  is relinquishing further rights to its own ATCB.
  624.    --  There is a very interesting potential race condition there, where
  625.    --  the old task may run concurrently with a new task that is allocated
  626.    --  the old tasks (now reused) ATCB.  The critical thing here is to
  627.    --  not make any reference to the ATCB after the lock is released.
  628.    --  See also comments on Terminate_Task and Unlock.
  629.  
  630.    procedure Final_Task_Unlock (Self_ID : Task_ID) is
  631.    begin
  632.       pragma Assert (Self_ID.Global_Task_Lock_Nesting = 1);
  633.       Unlock (Global_Task_Lock'Access);
  634.    end Final_Task_Unlock;
  635.  
  636.    --------------------------
  637.    -- Wakeup_Entry_Caller --
  638.    --------------------------
  639.  
  640.    --  This is called at the end of service of an entry call, to abort the
  641.    --  caller if he is in an abortable part, and to wake up the caller if it
  642.    --  is on Entry_Caller_Sleep. It assumes that the call is already off-queue.
  643.  
  644.    --  (This enforces the rule that a task must be off-queue if its state is
  645.    --  Done or Cancelled.) Call it holding the lock of Entry_Call.Self.
  646.  
  647.    --  Timed_Call or Simple_Call:
  648.    --    The caller is waiting on Entry_Caller_Sleep, in
  649.    --    Wait_For_Completion, or Wait_For_Completion_With_Timeout.
  650.  
  651.    --  Conditional_Call:
  652.    --    The caller might be in Wait_For_Completion,
  653.    --    waiting for a rendezvous (possibly requeued without abort)
  654.    --    to complete.
  655.  
  656.    --  Asynchronous_Call:
  657.    --    The caller may be executing in the abortable part o
  658.    --    an async. select, or on a time delay,
  659.    --    if Entry_Call.State >= Was_Abortable.
  660.  
  661.    procedure Wakeup_Entry_Caller
  662.      (Self_ID    : Task_ID;
  663.       Entry_Call : Entry_Call_Link;
  664.       New_State  : Entry_Call_State)
  665.    is
  666.       Caller : constant Task_ID := Entry_Call.Self;
  667.  
  668.    begin
  669.       pragma Debug (Debug.Trace
  670.         (Self_ID, "Wakeup_Entry_Caller", Caller, 'E'));
  671.       pragma Assert (New_State = Done or else New_State = Cancelled);
  672.  
  673.       pragma Assert
  674.         (Caller.Common.State /= Terminated
  675.           and then Caller.Common.State /= Unactivated);
  676.  
  677.       Entry_Call.State := New_State;
  678.  
  679.       if Entry_Call.Mode = Asynchronous_Call then
  680.  
  681.          --  Abort the caller in his abortable part,
  682.          --  but do so only if call has been queued abortably
  683.  
  684.          if Entry_Call.State >= Was_Abortable or else New_State = Done then
  685.             Locked_Abort_To_Level (Self_ID, Caller, Entry_Call.Level - 1);
  686.          end if;
  687.  
  688.       elsif Caller.Common.State = Entry_Caller_Sleep then
  689.          Wakeup (Caller, Entry_Caller_Sleep);
  690.       end if;
  691.    end Wakeup_Entry_Caller;
  692.  
  693.    ---------------------------
  694.    -- Locked_Abort_To_Level--
  695.    ---------------------------
  696.  
  697.    --  Abort a task to the specified ATC nesting level.
  698.    --  Call this only with T locked.
  699.  
  700.    --  An earlier version of this code contained a call to Wakeup. That
  701.    --  should not be necessary here, if Abort_Task is implemented correctly,
  702.    --  since Abort_Task should include the effect of Wakeup. However, the
  703.    --  above call was in earlier versions of this file, and at least for
  704.    --  some targets Abort_Task has not beek doing Wakeup. It should not
  705.    --  hurt to uncomment the above call, until the error is corrected for
  706.    --  all targets.
  707.  
  708.    --  See extended comments in package body System.Tasking.Abortion
  709.    --  for the overall design of the implementation of task abort.
  710.  
  711.    --  If the task is sleeping it will be in an abort-deferred region,
  712.    --  and will not have Abort_Signal raised by Abort_Task.
  713.    --  Such an "abort deferral" is just to protect the RTS internals,
  714.    --  and not necessarily required to enforce Ada semantics.
  715.    --  Abort_Task should wake the task up and let it decide if it wants
  716.    --  to complete the aborted construct immediately.
  717.  
  718.    --  Note that the effect of the lowl-level Abort_Task is not persistent.
  719.    --  If the target task is not blocked, this wakeup will be missed.
  720.  
  721.    --  We don't bother calling Abort_Task if this task is aborting itself,
  722.    --  since we are inside the RTS and have abort deferred. Similarly, We
  723.    --  don't bother to call Abort_Task if T is terminated, since there is
  724.    --  no need to abort a terminated task, and it could be dangerous to try
  725.    --  if the task has stopped executing.
  726.  
  727.    --  Note that an earlier version of this code had some false reasoning
  728.    --  about being able to reliably wake up a task that had suspended on
  729.    --  a blocking system call that does not atomically relase the task's
  730.    --  lock (e.g., UNIX nanosleep, which we once thought could be used to
  731.    --  implement delays). That still left the possibility of missed
  732.    --  wakeups.
  733.  
  734.    --  We cannot safely call Vulnerable_Complete_Activation here,
  735.    --  since that requires locking Self_ID.Parent. The anti-deadlock
  736.    --  lock ordering rules would then require us to release the lock
  737.    --  on Self_ID first, which would create a timing window for other
  738.    --  tasks to lock Self_ID. This is significant for tasks that may be
  739.    --  aborted before their execution can enter the task body, and so
  740.    --  they do not get a chance to call Complete_Task. The actual work
  741.    --  for this case is done in Terminate_Task.
  742.  
  743.    procedure Locked_Abort_To_Level
  744.      (Self_ID : Task_ID;
  745.       T       : Task_ID;
  746.       L       : ATC_Level) is
  747.  
  748.    begin
  749.       if not T.Aborting and then T /= Self_ID then
  750.          case T.Common.State is
  751.             when Unactivated | Terminated =>
  752.                pragma Assert (False);
  753.                null;
  754.  
  755.             when Runnable =>
  756.                --  This is needed to cancel an asynchronous protected entry
  757.                --  call during a requeue with abort.
  758.  
  759.                T.Entry_Calls
  760.                  (T.ATC_Nesting_Level).Cancellation_Attempted := True;
  761.  
  762.             when Interrupt_Server_Blocked_On_Event_Flag =>
  763.                null;
  764.  
  765.             when Delay_Sleep                              |
  766.                  Async_Select_Sleep                       |
  767.                  Interrupt_Server_Idle_Sleep              |
  768.                  Interrupt_Server_Blocked_Interrupt_Sleep |
  769.                  Timer_Server_Sleep                       |
  770.                  AST_Server_Sleep                         =>
  771.                Wakeup (T, T.Common.State);
  772.  
  773.             when Acceptor_Sleep =>
  774.                T.Open_Accepts := null;
  775.                Wakeup (T, T.Common.State);
  776.  
  777.             when Entry_Caller_Sleep  =>
  778.                T.Entry_Calls
  779.                  (T.ATC_Nesting_Level).Cancellation_Attempted := True;
  780.                Wakeup (T, T.Common.State);
  781.  
  782.             when Activator_Sleep         |
  783.                  Master_Completion_Sleep |
  784.                  Master_Phase_2_Sleep    |
  785.                  Asynchronous_Hold       =>
  786.                null;
  787.          end case;
  788.       end if;
  789.  
  790.       if T.Pending_ATC_Level > L then
  791.          T.Pending_ATC_Level := L;
  792.          T.Pending_Action := True;
  793.  
  794.          if L = 0 then
  795.             T.Callable := False;
  796.          end if;
  797.  
  798.          --  This prevents aborted task from accepting calls
  799.  
  800.          if T.Aborting then
  801.  
  802.             --  The test above is just a heuristic, to reduce wasteful
  803.             --  calls to Abort_Task.  We are holding T locked, and this
  804.             --  value will not be set to False except with T also locked,
  805.             --  inside Exit_One_ATC_Level, so we should not miss wakeups.
  806.  
  807.             if T.Common.State = Acceptor_Sleep then
  808.                T.Open_Accepts := null;
  809.             end if;
  810.  
  811.          elsif T /= Self_ID and then
  812.            (T.Common.State = Runnable
  813.             or else T.Common.State = Interrupt_Server_Blocked_On_Event_Flag)
  814.             --  The task is blocked on a system call waiting for the
  815.             --  completion event. In this case Abort_Task may need to take
  816.             --  special action in order to succeed. Example system: VMS.
  817.  
  818.          then
  819.             Abort_Task (T);
  820.          end if;
  821.       end if;
  822.    end Locked_Abort_To_Level;
  823.  
  824.    -----------------------
  825.    --  Soft-Link Bodies --
  826.    -----------------------
  827.  
  828.    function Get_Jmpbuf_Address return  Address is
  829.       Me : constant Task_ID := STPO.Self;
  830.    begin
  831.       return Me.Common.Compiler_Data.Jmpbuf_Address;
  832.    end Get_Jmpbuf_Address;
  833.  
  834.    procedure Set_Jmpbuf_Address (Addr : Address) is
  835.       Me : Task_ID := STPO.Self;
  836.    begin
  837.       Me.Common.Compiler_Data.Jmpbuf_Address := Addr;
  838.    end Set_Jmpbuf_Address;
  839.  
  840.    function Get_Sec_Stack_Addr return  Address is
  841.       Me : constant Task_ID := STPO.Self;
  842.    begin
  843.       return Me.Common.Compiler_Data.Sec_Stack_Addr;
  844.    end Get_Sec_Stack_Addr;
  845.  
  846.    procedure Set_Sec_Stack_Addr (Addr : Address) is
  847.       Me : Task_ID := STPO.Self;
  848.    begin
  849.       Me.Common.Compiler_Data.Sec_Stack_Addr := Addr;
  850.    end Set_Sec_Stack_Addr;
  851.  
  852.    function Get_Exc_Stack_Addr return Address is
  853.       Me : constant Task_ID := STPO.Self;
  854.    begin
  855.       return Me.Common.Compiler_Data.Exc_Stack_Addr;
  856.    end Get_Exc_Stack_Addr;
  857.  
  858.    procedure Set_Exc_Stack_Addr (Self_ID : Address; Addr : Address) is
  859.       Me : Task_ID := To_Task_Id (Self_ID);
  860.    begin
  861.       if Me = Null_Task then
  862.          Me := STPO.Self;
  863.       end if;
  864.       Me.Common.Compiler_Data.Exc_Stack_Addr := Addr;
  865.    end Set_Exc_Stack_Addr;
  866.  
  867.    function Get_Machine_State_Addr return Address is
  868.       Me : constant Task_ID := STPO.Self;
  869.    begin
  870.       return Me.Common.Compiler_Data.Machine_State_Addr;
  871.    end Get_Machine_State_Addr;
  872.  
  873.    procedure Set_Machine_State_Addr (Addr : Address) is
  874.       Me : Task_ID := STPO.Self;
  875.    begin
  876.       Me.Common.Compiler_Data.Machine_State_Addr := Addr;
  877.    end Set_Machine_State_Addr;
  878.  
  879.    function Get_Current_Excep return SSL.EOA is
  880.       Me : constant Task_ID := STPO.Self;
  881.    begin
  882.       return Me.Common.Compiler_Data.Current_Excep'Access;
  883.    end Get_Current_Excep;
  884.  
  885.    procedure Timed_Delay_T (Time : Duration; Mode : Integer) is
  886.       Self_ID : constant Task_ID := Self;
  887.  
  888.    begin
  889.       STPO.Timed_Delay (Self_ID, Time, Mode);
  890.    end Timed_Delay_T;
  891.  
  892.    function Get_Stack_Info return Stack_Checking.Stack_Access is
  893.       Me : constant Task_ID := STPO.Self;
  894.    begin
  895.       return Me.Common.Compiler_Data.Pri_Stack_Info'Access;
  896.    end Get_Stack_Info;
  897.  
  898.  
  899.    ------------------------
  900.    -- Check_Abort_Status --
  901.    ------------------------
  902.  
  903.    function Check_Abort_Status return Integer is
  904.       Self_ID : Task_ID := Self;
  905.  
  906.    begin
  907.       if Self_ID /= null and then Self_ID.Deferral_Level = 0
  908.         and then Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level then
  909.          return 1;
  910.       else
  911.          return 0;
  912.       end if;
  913.    end Check_Abort_Status;
  914.  
  915.    ------------------------
  916.    -- Soft-Link Dummies  --
  917.    ------------------------
  918.  
  919.    --  These are dummies for subprograms that are only needed by certain
  920.    --  optional run-time system packages.  If they are needed, the soft
  921.    --  links will be redirected to the real subprogram by elaboration of
  922.    --  the subprogram body where the real subprogram is declared.
  923.  
  924.    procedure Finalize_Attributes (T : Task_ID) is
  925.    begin
  926.       null;
  927.    end Finalize_Attributes;
  928.  
  929.    procedure Initialize_Attributes (T : Task_ID) is
  930.    begin
  931.       null;
  932.    end Initialize_Attributes;
  933.  
  934. begin
  935.    Init_RTS;
  936. end System.Tasking.Initialization;
  937.