home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / gnat-2.06-src.tgz / tar.out / fsf / gnat / ada / s-tasini.adb < prev    next >
Text File  |  1996-09-28  |  18KB  |  546 lines

  1. ------------------------------------------------------------------------------
  2. --                                                                          --
  3. --                 GNU ADA RUNTIME 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.1 $                             --
  10. --                                                                          --
  11. --      Copyright (c) 1991,1992,1993,1994,1995 FSU, All Rights Reserved     --
  12. --                                                                          --
  13. -- GNARL is free software; you can redistribute it  and/or modify it  under --
  14. -- terms  of  the  GNU  Library General Public License  as published by the --
  15. -- Free Software  Foundation;  either version 2, or (at  your  option)  any --
  16. -- later  version.  GNARL is distributed  in the hope that  it will be use- --
  17. -- ful, but but WITHOUT ANY WARRANTY;  without even the implied warranty of --
  18. -- MERCHANTABILITY  or  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Gen- --
  19. -- eral Library Public License  for more details.  You should have received --
  20. -- a  copy of the GNU Library General Public License along with GNARL;  see --
  21. -- file COPYING.LIB.  If not,  write to the  Free Software Foundation,  675 --
  22. -- Mass Ave, Cambridge, MA 02139, USA.                                      --
  23. --                                                                          --
  24. ------------------------------------------------------------------------------
  25.  
  26. --  This package provides overall initialization of the tasking portion
  27. --  of the RTS.  This package must be elaborated before any tasking
  28. --  features are used.  It also contains initialization for
  29. --  Ada Task Control Block (ATCB) records.
  30.  
  31. with System.Task_Primitives; use System.Task_Primitives;
  32.  
  33. with System.Tasking_Soft_Links;
  34. --  Used for, Abort_Defer, Abort_Undefer, Get_TSD_Address
  35. --  These are procedure pointers to non-tasking routines that use
  36. --  task specific data.  In the absence of tasking, these routines
  37. --  refer to global data.  In the presense of tasking, they must be
  38. --  replaced with pointers to task-specific versions.
  39.  
  40. with System.Task_Memory;
  41. --  Used for, Task_Memory.Low_Level_New,
  42. --            Task_Memory.Unsafe_Low_Level_New,
  43. --            Task_Memory.Low_Level_Free
  44.  
  45. with System.Compiler_Options;
  46. --  Used for, Main_Priority
  47.  
  48. with System.Task_Specific_Data;
  49. --  Used for, Create_TSD, Destroy_TSD
  50. --  This package provides initialization routines for task specific data.
  51. --  The GNARL must call these to be sure that all non-tasking
  52. --  Ada constructs will work.
  53.  
  54. pragma Elaborate_All (System.Task_Primitives);
  55. pragma Elaborate_All (System.Task_Memory);
  56.  
  57. pragma Elaborate_All (System.Tasking_Soft_Links);
  58. --  This must be elaborated first, to prevent its initialization of
  59. --  the global procedure pointers from overwriting the pointers installed
  60. --  by Stages.
  61.  
  62. with Unchecked_Deallocation;
  63.  
  64. package body System.Tasking.Initialization is
  65.  
  66.    Global_Task_Lock : Lock;
  67.    --  This is a global lock; it is used to execute in mutual exclusion
  68.    --  from all other tasks.  It is only used by Task_Lock and
  69.    --  Task_Unlock.
  70.  
  71.    -----------------------------------------------------------------
  72.    -- Tasking versions of services needed by non-tasking programs --
  73.    -----------------------------------------------------------------
  74.  
  75.    function Get_TSD_Address (Dummy : Boolean) return Address;
  76.    --  This procedure returns the task-specific data pointer installed at
  77.    --  task creation time by the GNARL on behalf of the compiler.  A pointer
  78.    --  to this routine replaces the default pointer installed for the
  79.    --  non-tasking case.
  80.    --  The dummy parameter avoids a bug in GNAT.
  81.  
  82.    procedure Task_Lock;
  83.    --  Locks out other tasks. Preceding a section of code by Task_Lock and
  84.    --  following it by Task_Unlock creates a critical region. This is used
  85.    --  for ensuring that a region of non-tasking code (such as code used to
  86.    --  allocate memory) is tasking safe. Note that it is valid for calls to
  87.    --  Task_Lock/Task_Unlock to be nested, and this must work properly, i.e.
  88.    --  only the corresponding outer level Task_Unlock will actually unlock.
  89.  
  90.    procedure Task_Unlock;
  91.    --  Releases lock previously set by call to Task_Lock. In the nested case,
  92.    --  all nested locks must be released before other tasks competing for the
  93.    --  tasking lock are released.
  94.  
  95.    ----------------------------
  96.    -- Tasking Initialization --
  97.    ----------------------------
  98.  
  99.    procedure Init_RTS (Main_Task_Priority : System.Priority);
  100.    --  This procedure initializes the GNARL.  This includes creating
  101.    --  data structures to make the initial thread into the environment
  102.    --  task, setting up handlers for ATC and errors, and
  103.    --  installing tasking versions of certain operations used by the
  104.    --  compiler.  Init_RTS is called during elaboration.
  105.  
  106.    -------------------
  107.    -- Abort_Handler --
  108.    -------------------
  109.  
  110.    procedure Abort_Handler
  111.      (Context : Task_Primitives.Pre_Call_State)
  112.    is
  113.       T : Task_ID := Self;
  114.  
  115.    begin
  116.       if T.Deferral_Level = 0
  117.         and then T.Pending_ATC_Level < T.ATC_Nesting_Level
  118.       then
  119.  
  120.          --  ???  This is implementation dependent.  Some implementations
  121.          --       might not allow an exception to be propagated out of a
  122.          --       handler, and others might leave the signal or interrupt
  123.          --       that invoked this handler masked after the exceptional
  124.          --       return to the application code.
  125.          --       GNAT exceptions are originally implemented using
  126.          --       setjmp()/longjmp().  On most UNIX systems, this will
  127.          --       allow transfer out of a signal handler, which is
  128.          --       usually the only mechanism available for implementing
  129.          --       asynchronous handlers of this kind.  However, some
  130.          --       systems do not restore the signal mask, leaving the
  131.          --       abortion signal masked.
  132.          --       Possible solutions:
  133.          --
  134.          --       1. Change the PC saved in the system-dependent Context
  135.          --          parameter to point to code that raises the exception.
  136.          --          Normal return from this handler will then raise
  137.          --          the exception after the mask and other system state has
  138.          --          been restored.
  139.          --       2. Use siglongjmp()/sigsetjmp() to implement exceptions.
  140.          --       3. Unmask the signal in the Abortion exception handler
  141.          --          (in the RTS).
  142.  
  143.          raise Standard'Abort_Signal;
  144.  
  145.       end if;
  146.    end Abort_Handler;
  147.  
  148.    --------------------------
  149.    -- Change_Base_Priority --
  150.    --------------------------
  151.  
  152.    procedure Change_Base_Priority (T : Task_ID) is
  153.  
  154.    begin
  155.       --  check for ceiling violations ???
  156.       T.Pending_Priority_Change := False;
  157.       T.Base_Priority := T.New_Base_Priority;
  158.       T.Current_Priority := T.Base_Priority;
  159.       Set_Priority (T.LL_TCB'Access, T. Current_Priority);
  160.    end Change_Base_Priority;
  161.  
  162.    ----------------------
  163.    -- Decrement_Master --
  164.    ----------------------
  165.  
  166.    function Decrement_Master (M : Master_ID) return Master_ID is
  167.    begin
  168.       return M - 1;
  169.    end Decrement_Master;
  170.  
  171.    --------------------
  172.    -- Defer_Abortion --
  173.    --------------------
  174.  
  175.    procedure Defer_Abortion is
  176.       T : Task_ID := Self;
  177.  
  178.    begin
  179.       T.Deferral_Level := T.Deferral_Level + 1;
  180.    end Defer_Abortion;
  181.  
  182.    ---------------
  183.    -- Free_ATCB --
  184.    ---------------
  185.  
  186.    procedure Free_ATCB (T : in out Task_ID) is
  187.       procedure Free is new Unchecked_Deallocation (
  188.         Ada_Task_Control_Block, Task_ID);
  189.       Error : Boolean;
  190.    begin
  191.       Finalize_Lock (T.L);
  192.       Finalize_Cond (T.Cond);
  193.       Free (T);
  194.    end Free_ATCB;
  195.  
  196.    ---------------------
  197.    -- Get_TSD_Address --
  198.    ---------------------
  199.  
  200.    function Get_TSD_Address (Dummy : Boolean) return Address is
  201.       T : Task_ID := Self;
  202.    begin
  203.       return T.Compiler_Data;
  204.    end Get_TSD_Address;
  205.  
  206.    ----------------------
  207.    -- Increment_Master --
  208.    ----------------------
  209.  
  210.    function Increment_Master (M : Master_ID) return Master_ID is
  211.    begin
  212.       return M + 1;
  213.    end Increment_Master;
  214.  
  215.    ---------------------
  216.    -- Initialize_ATCB --
  217.    ---------------------
  218.  
  219.    procedure Initialize_ATCB
  220.      (T     : Task_ID;
  221.       Init  : ATCB_Init)
  222.    is
  223.       Error : Boolean;
  224.    begin
  225.       --  Initialize all fields of the TCB
  226.  
  227.       Initialize_Lock (System.Priority'Last, T.L);
  228.       Initialize_Cond (T.Cond);
  229.       T.Activation_Count := 0;
  230.       T.Awake_Count := 1;                       --  Counting this task.
  231.       T.Awaited_Dependent_Count := 0;
  232.       T.Terminating_Dependent_Count := 0;
  233.       T.Pending_Action := False;
  234.       T.Pending_ATC_Level := ATC_Level_Infinity;
  235.       T.ATC_Nesting_Level := 1;                 --  1 deep; 0 = abnormal.
  236.       T.Deferral_Level := 1;                    --  Start out deferred.
  237.       T.Stage := Created;
  238.       T.Global_Task_Lock_Nesting := 0;
  239.       T.Exception_To_Raise := Compiler_Exceptions.Null_Exception;
  240.       T.Accepting := Not_Accepting;
  241.       T.Aborting := False;
  242.       T.Call := null;
  243.       T.Elaborated := Init.Elaborated;
  244.       T.Parent := Init.Parent;
  245.       T.Task_Entry_Point := Init.Task_Entry_Point;
  246.       T.Task_Arg := Init.Task_Arg;
  247.       T.Stack_Size := Init.Stack_Size;
  248.       T.Current_Priority := Init.Priority;
  249.       T.Base_Priority := Init.Priority;
  250.       T.Pending_Priority_Change := False;
  251.       T.Activator := Init.Activator;
  252.       T.Master_of_Task := Init.Master_of_Task;
  253.       T.Master_Within := Increment_Master (Init.Master_of_Task);
  254.       T.Terminate_Alternative := false;
  255.  
  256.       for J in 1 .. T.Entry_Num loop
  257.          T.Entry_Queues (J).Head := null;
  258.          T.Entry_Queues (J).Tail := null;
  259.       end loop;
  260.  
  261.       for L in T.Entry_Calls'Range loop
  262.          T.Entry_Calls (L).Next := null;
  263.          T.Entry_Calls (L).Self := T;
  264.          T.Entry_Calls (L).Level := L;
  265.       end loop;
  266.  
  267.       --  Link the task into the list of all tasks.
  268.  
  269.       if T.Parent /= null then
  270.          Defer_Abortion;
  271.          Write_Lock (All_Tasks_L, Error);
  272.       end if;
  273.  
  274.       T.All_Tasks_Link := All_Tasks_List;
  275.       All_Tasks_List := T;
  276.  
  277.       if T.Parent /= null then
  278.          Unlock (All_Tasks_L);
  279.          Undefer_Abortion;
  280.       end if;
  281.    end Initialize_ATCB;
  282.  
  283.    -----------------
  284.    -- Init_Master --
  285.    -----------------
  286.  
  287.    procedure Init_Master (M : out Master_ID) is
  288.    begin
  289.       M := 0;
  290.    end Init_Master;
  291.  
  292.    --------------
  293.    -- Init_RTS --
  294.    --------------
  295.  
  296.    procedure Init_RTS (Main_Task_Priority : System.Priority) is
  297.       T    : Task_ID;
  298.       Init : ATCB_Init;
  299.  
  300.    begin
  301.       All_Tasks_List := null;
  302.       Init.Entry_Num := 0;
  303.       Init.Parent := null;
  304.  
  305.       Init.Task_Entry_Point := null;
  306.  
  307.       Init.Stack_Size := 0;
  308.       Init.Activator := null;
  309.       Init_Master (Init.Master_of_Task);
  310.       Init.Elaborated := null;
  311.       if Main_Task_Priority = Unspecified_Priority then
  312.          Init.Priority := Default_Priority;
  313.       else
  314.          Init.Priority := Main_Task_Priority;
  315.       end if;
  316.  
  317.       T := Unsafe_New_ATCB (Init);
  318.  
  319.       T.Compiler_Data := Task_Specific_Data.Create_TSD;
  320.       --  This needs to be done as early as possible in the creation
  321.       --  of a task, since the operation of Ada code within the task may
  322.       --  depend on task specific data.
  323.  
  324.       Initialize_LL_Tasks (T.LL_TCB'Access);
  325.       Initialize_ATCB (T, Init);
  326.  
  327.       T.Stage := Active;
  328.  
  329.       --  The allocation of the initial task ATCB is different from
  330.       --  that of subsequent ATCBs, which are allocated with ATCB.New_ATCB.
  331.       --  New_ATCB performs all of the functions of Unsafe_New_ATCB
  332.       --  and Initialize_ATCB.  However, it uses GNULLI operations, which
  333.       --  should not be called until after Initialize_LL_Tasks.  Since
  334.       --  Initialize_LL_Tasks needs the initial ATCB, New_ATCB was broken
  335.       --  down into two parts, the first of which allocates the ATCB without
  336.       --  calling any GNULLI operations.
  337.  
  338.       Set_Own_Priority (T.Current_Priority);
  339.  
  340.       Initialize_Lock (Priority'Last, All_Tasks_L);
  341.       --  Initialize the lock used to synchronize chain of all ATCBs.
  342.  
  343.       Initialize_Lock (Priority'Last, Global_Task_Lock);
  344.       --  Initialize the lock used to implement mutual exclusion between
  345.       --  all tasks.
  346.  
  347.       --  This is not according the the GNULLI, which specifies
  348.       --  access procedure (Context: Pre_Call_State) for the handler.
  349.       --  This may be a mistake in the interface. ???
  350.  
  351.       Install_Abort_Handler (Abort_Handler'Access);
  352.  
  353.       --  Install handlers for asynchronous error signals.
  354.  
  355.       --  This is not according the the GNULLI, which specifies
  356.       --  access procedure(...) for the handler.
  357.       --  This may be a mistake in the interface. ???
  358.  
  359.       Install_Error_Handler (Compiler_Exceptions.Notify_Exception'Address);
  360.  
  361.       --  Set up the soft links to tasking services used in the absence of
  362.       --  tasking.  These replace tasking-free defaults.
  363.  
  364.       System.Tasking_Soft_Links.Abort_Defer :=
  365.         Defer_Abortion'Access;
  366.       System.Tasking_Soft_Links.Abort_Undefer :=
  367.         Undefer_Abortion'Access;
  368.       System.Tasking_Soft_Links.Get_TSD_Address :=
  369.         Get_TSD_Address'Access;
  370.       System.Tasking_Soft_Links.Lock_Task :=
  371.         Task_Lock'Access;
  372.       System.Tasking_Soft_Links.Unlock_Task :=
  373.          Task_Unlock'Access;
  374.  
  375.       --  Abortion is deferred in a new ATCB, so we need to undefer abortion
  376.       --  at this stage to make the environment task abortable.
  377.  
  378.       Undefer_Abortion;
  379.  
  380.    end Init_RTS;
  381.  
  382.    --------------
  383.    -- New_ATCB --
  384.    --------------
  385.  
  386.    function New_ATCB
  387.      (Init : ATCB_Init)
  388.       return Task_ID
  389.    is
  390.       T                : Task_ID;
  391.       Error : Boolean;
  392.    begin
  393.       T := new Ada_Task_Control_Block (Init.Entry_Num);
  394.       Initialize_ATCB (T, Init);
  395.       return T;
  396.    end New_ATCB;
  397.  
  398.    --------------------------------
  399.    -- Remove_From_All_Tasks_List --
  400.    --------------------------------
  401.  
  402.    procedure Remove_From_All_Tasks_List (
  403.       Source : Task_ID;
  404.       Result : out Boolean) is
  405.  
  406.       C        : Task_ID;
  407.       P        : Task_ID;
  408.       Previous : Task_ID;
  409.       Error    : Boolean;
  410.    begin
  411.  
  412.       Write_Lock (All_Tasks_L, Error);
  413.  
  414.       Result := False;
  415.  
  416.       Previous := Null_Task;
  417.       C := All_Tasks_List;
  418.  
  419.       while C /= Null_Task loop
  420.          if C = Source then
  421.             Result := True;
  422.  
  423.             if Previous = Null_Task then
  424.                All_Tasks_List :=
  425.                  All_Tasks_List.All_Tasks_Link;
  426.             else
  427.                Previous.All_Tasks_Link := C.All_Tasks_Link;
  428.             end if;
  429.  
  430.             exit;
  431.  
  432.          end if;
  433.  
  434.          Previous := C;
  435.          C := C.All_Tasks_Link;
  436.  
  437.       end loop;
  438.  
  439.       Unlock (All_Tasks_L);
  440.  
  441.    end Remove_From_All_Tasks_List;
  442.  
  443.    -----------------------------
  444.    -- Runtime_Assert_Shutdown --
  445.    -----------------------------
  446.  
  447.    function Runtime_Assert_Shutdown (Msg : in String) return boolean is
  448.    begin
  449.       LL_Assert (false, Msg);
  450.       --  This call should never return
  451.       return false;
  452.    end Runtime_Assert_Shutdown;
  453.  
  454.    ---------------
  455.    -- Task_Lock --
  456.    ---------------
  457.  
  458.    procedure Task_Lock is
  459.       T     : Task_ID := Self;
  460.       Error : Boolean;
  461.    begin
  462.       T.Global_Task_Lock_Nesting := T.Global_Task_Lock_Nesting + 1;
  463.       if T.Global_Task_Lock_Nesting = 1 then
  464.          Write_Lock (Global_Task_Lock, Error);
  465.       end if;
  466.    end Task_Lock;
  467.  
  468.    -----------------
  469.    -- Task_Unlock --
  470.    -----------------
  471.  
  472.    procedure Task_Unlock is
  473.       T     : Task_ID := Self;
  474.    begin
  475.       pragma Assert (
  476.         T.Global_Task_Lock_Nesting > 0 or else
  477.           Runtime_Assert_Shutdown (
  478.             "Unlock_Task_T: Improper lock nesting"));
  479.  
  480.       T.Global_Task_Lock_Nesting := T.Global_Task_Lock_Nesting - 1;
  481.       if T.Global_Task_Lock_Nesting = 0 then
  482.          Unlock (Global_Task_Lock);
  483.       end if;
  484.    end Task_Unlock;
  485.  
  486.    ----------------------
  487.    -- Undefer_Abortion --
  488.    ----------------------
  489.  
  490.    --  Precondition : Self does not hold any locks!
  491.  
  492.    --  Undefer_Abortion is called on any abortion completion point (aka.
  493.    --  synchronization point). It performs the following actions if they
  494.    --  are pending: (1) change the base priority, (2) abort the task.
  495.    --  The priority change has to occur before abortion. Otherwise, it would
  496.    --  take effect no earlier than the next abortion completion point.
  497.    --  This version of Undefer_Abortion redefers abortion if abortion is
  498.    --  in progress.  There has been some discussion of having
  499.    --  the raise statement defer abortion to prevent abortion of
  500.    --  handlers performing required completion.  This would make
  501.    --  the explicit deferral unnecessary. ???
  502.  
  503.    procedure Undefer_Abortion is
  504.       T : Task_ID := Self;
  505.       Error : Boolean;
  506.  
  507.    begin
  508.       T.Deferral_Level := T.Deferral_Level - 1;
  509.  
  510.       if T.Deferral_Level = ATC_Level'First and then T.Pending_Action then
  511.          Write_Lock (T.L, Error);
  512.          T.Pending_Action := False;
  513.  
  514.          if T.Pending_Priority_Change then
  515.             Change_Base_Priority (T);
  516.          end if;
  517.  
  518.          Unlock (T.L);
  519.  
  520.          if T.Pending_ATC_Level < T.ATC_Nesting_Level then
  521.             raise Standard'Abort_Signal;
  522.          end if;
  523.       end if;
  524.  
  525.    end Undefer_Abortion;
  526.  
  527.    ---------------------
  528.    -- Unsafe_New_ATCB --
  529.    ---------------------
  530.  
  531.    function Unsafe_New_ATCB
  532.      (Init : ATCB_Init)
  533.       return Task_ID
  534.    is
  535.    begin
  536.       return new Ada_Task_Control_Block (Init.Entry_Num);
  537.    end Unsafe_New_ATCB;
  538.  
  539.    -----------------------------------
  540.    -- Tasking System Initialization --
  541.    -----------------------------------
  542.  
  543. begin
  544.    Init_RTS (Compiler_Options.Main_Priority);
  545. end System.Tasking.Initialization;
  546.