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-finimp.adb < prev    next >
Text File  |  2000-07-19  |  18KB  |  565 lines

  1. ------------------------------------------------------------------------------
  2. --                                                                          --
  3. --                         GNAT RUN-TIME COMPONENTS                         --
  4. --                                                                          --
  5. --    S Y S T E M . F I N A L I Z A T I O N _ I M P L E M E N T A T I O N   --
  6. --                                                                          --
  7. --                                 B o d y                                  --
  8. --                                                                          --
  9. --                            $Revision: 1.43 $
  10. --                                                                          --
  11. --          Copyright (C) 1992-2000 Free Software Foundation, Inc.          --
  12. --                                                                          --
  13. -- GNAT 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.  GNAT 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 GNAT;  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. -- GNAT was originally developed  by the GNAT team at  New York University. --
  32. -- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). --
  33. --                                                                          --
  34. ------------------------------------------------------------------------------
  35.  
  36. with Ada.Exceptions;
  37. with Ada.Tags;
  38. with Ada.Unchecked_Conversion;
  39. with System.Storage_Elements;
  40. with System.Soft_Links;
  41.  
  42. package body System.Finalization_Implementation is
  43.  
  44.    use Ada.Exceptions;
  45.    use System.Finalization_Root;
  46.  
  47.    package SSL renames System.Soft_Links;
  48.  
  49.    package SSE renames System.Storage_Elements;
  50.    use type SSE.Storage_Offset;
  51.  
  52.    -----------------------
  53.    -- Local Subprograms --
  54.    -----------------------
  55.  
  56.    function To_Finalizable_Ptr is
  57.      new Ada.Unchecked_Conversion (Address, Finalizable_Ptr);
  58.  
  59.    function To_Addr is
  60.      new Ada.Unchecked_Conversion (Finalizable_Ptr, Address);
  61.  
  62.    type RC_Ptr is access all Record_Controller;
  63.  
  64.    function To_RC_Ptr is
  65.      new Ada.Unchecked_Conversion (Address, RC_Ptr);
  66.  
  67.    procedure Raise_Exception_No_Defer
  68.      (E       : in Exception_Id;
  69.       Message : in String := "");
  70.    pragma Import (Ada, Raise_Exception_No_Defer,
  71.      "ada__exceptions__raise_exception_no_defer");
  72.    pragma No_Return (Raise_Exception_No_Defer);
  73.    --  Raise an exception without deferring abort. Note that we have to
  74.    --  use this rather kludgy Ada Import interface, since this subprogram
  75.    --  is not available in the visible spec of Ada.Exceptions.
  76.  
  77.    procedure Raise_From_Finalize
  78.      (L          : Finalizable_Ptr;
  79.       From_Abort : Boolean;
  80.       E_Occ      : Exception_Occurrence);
  81.    --  Deal with an exception raised during finalization of a list. L is a
  82.    --  pointer to the list of element not yet finalized. From_Abort is true
  83.    --  if the finalization actions come from an abort rather than a normal
  84.    --  exit. E_Occ represents the exception being raised.
  85.  
  86.    function RC_Offset (T : Ada.Tags.Tag) return SSE.Storage_Offset;
  87.    pragma Import (Ada, RC_Offset, "ada__tags__get_rc_offset");
  88.  
  89.    function Parent_Size (Obj : Address) return SSE.Storage_Count;
  90.    pragma Import (Ada, Parent_Size, "ada__tags__parent_size");
  91.  
  92.    function Get_RC_Dynamically (Obj : Address) return Address;
  93.    --  Given an the address of an object (obj) of a tagged extension with
  94.    --  controlled component, computes the address of the record controller
  95.    --  located just after the _parent field
  96.  
  97.    --------------------------
  98.    -- Attach_To_Final_List --
  99.    --------------------------
  100.  
  101.    procedure Attach_To_Final_List
  102.      (L       : in out Finalizable_Ptr;
  103.       Obj     : in out Finalizable;
  104.       Nb_Link : Short_Short_Integer)
  105.    is
  106.    begin
  107.       --  Simple case: attachement to a one way list
  108.  
  109.       if Nb_Link = 1 then
  110.          Obj.Next         := L;
  111.          L                := Obj'Unchecked_Access;
  112.  
  113.       --  Dynamically allocated objects: they are attached to a doubly
  114.       --  linked list, so that an element can be finalized at any moment
  115.       --  by means of an unchecked deallocation. Attachement is
  116.       --  protected against multi-threaded access.
  117.  
  118.       elsif Nb_Link = 2 then
  119.  
  120.          Locked_Processing : begin
  121.             SSL.Lock_Task.all;
  122.             Obj.Next    := L.Next;
  123.             Obj.Prev    := L.Next.Prev;
  124.             L.Next.Prev := Obj'Unchecked_Access;
  125.             L.Next      := Obj'Unchecked_Access;
  126.             SSL.Unlock_Task.all;
  127.  
  128.          exception
  129.             when others =>
  130.                SSL.Unlock_Task.all;
  131.                raise;
  132.          end Locked_Processing;
  133.  
  134.       --  Attachement of arrays to the final list (used only for objects
  135.       --  returned by function). Obj, in this case is the last element,
  136.       --  but all other elements are already threaded after it. We just
  137.       --  attach the rest of the final list at the end of the array list.
  138.  
  139.       elsif Nb_Link = 3 then
  140.          declare
  141.             P : Finalizable_Ptr := Obj'Unchecked_Access;
  142.  
  143.          begin
  144.             while P.Next /= null loop
  145.                P := P.Next;
  146.             end loop;
  147.  
  148.             P.Next := L;
  149.             L := Obj'Unchecked_Access;
  150.          end;
  151.       end if;
  152.  
  153.    end Attach_To_Final_List;
  154.  
  155.    -----------------------------
  156.    -- Detach_From_Final_List --
  157.    -----------------------------
  158.  
  159.    --  We know that the detach object is neither at the beginning nor at the
  160.    --  end of the list, thank's to the dummy First and Last Elements but the
  161.    --  object may not be attached at all if it is Finalize_Sortage_Only
  162.  
  163.    procedure Detach_From_Final_List (Obj : in out Finalizable) is
  164.    begin
  165.  
  166.       --  When objects are not properly attached to a doubly linked
  167.       --  list do not try to detach them. The only case where it can
  168.       --  happen is when dealing with Finalize_Storage_Only objects
  169.       --  which are not always attached.
  170.  
  171.       if Obj.Next /= null and then Obj.Prev /= null then
  172.          SSL.Lock_Task.all;
  173.          Obj.Next.Prev := Obj.Prev;
  174.          Obj.Prev.Next := Obj.Next;
  175.          SSL.Unlock_Task.all;
  176.       end if;
  177.  
  178.    exception
  179.       when others =>
  180.          SSL.Unlock_Task.all;
  181.          raise;
  182.    end Detach_From_Final_List;
  183.  
  184.    --------------------------
  185.    --  Raise_From_Finalize --
  186.    --------------------------
  187.  
  188.    procedure Raise_From_Finalize
  189.      (L          : Finalizable_Ptr;
  190.       From_Abort : Boolean;
  191.       E_Occ      : Exception_Occurrence)
  192.    is
  193.       Msg : constant String := Exception_Message (E_Occ);
  194.       P   : Finalizable_Ptr := L;
  195.       Q   : Finalizable_Ptr;
  196.  
  197.    begin
  198.       --  We already got an exception. We now finalize the remainder of
  199.       --  the list, ignoring all further exceptions.
  200.  
  201.       while P /= null loop
  202.          Q := P.Next;
  203.  
  204.          begin
  205.             Finalize (P.all);
  206.          exception
  207.             when others => null;
  208.          end;
  209.  
  210.          P := Q;
  211.       end loop;
  212.  
  213.       --  If finalization from an Abort, then nothing to do
  214.  
  215.       if From_Abort then
  216.          null;
  217.  
  218.       --  If no message, then add our own message saying what happened
  219.  
  220.       elsif Msg = "" then
  221.          Raise_Exception_No_Defer
  222.            (E       => Program_Error'Identity,
  223.             Message => "exception " &
  224.                        Exception_Name (E_Occ) &
  225.                        " raised during finalization");
  226.  
  227.       --  If there was a message, pass it on
  228.  
  229.       else
  230.          Raise_Exception_No_Defer (Program_Error'Identity, Msg);
  231.       end if;
  232.    end Raise_From_Finalize;
  233.  
  234.    -------------------
  235.    -- Finalize_List --
  236.    -------------------
  237.  
  238.    procedure Finalize_List (L : Finalizable_Ptr) is
  239.       P : Finalizable_Ptr := L;
  240.       Q : Finalizable_Ptr;
  241.  
  242.       type Fake_Exception_Occurence is record
  243.          Id : Exception_Id;
  244.       end record;
  245.       type Ptr is access all Fake_Exception_Occurence;
  246.  
  247.       --  Let's get the current exception before starting to finalize in
  248.       --  order to check if we are in the abort case if an exception is
  249.       --  raised.
  250.  
  251.       function To_Ptr is new
  252.          Ada.Unchecked_Conversion (Exception_Occurrence_Access, Ptr);
  253.       X : Exception_Id :=
  254.         To_Ptr (System.Soft_Links.Get_Current_Excep.all).Id;
  255.  
  256.    begin
  257.       while P /= null loop
  258.          Q := P.Next;
  259.          Finalize (P.all);
  260.          P := Q;
  261.       end loop;
  262.  
  263.    exception
  264.       when E_Occ : others =>
  265.          Raise_From_Finalize (
  266.            Q,
  267.            X = Standard'Abort_Signal'Identity,
  268.            E_Occ);
  269.    end Finalize_List;
  270.  
  271.    --------------------------
  272.    -- Finalize_Global_List --
  273.    --------------------------
  274.  
  275.    procedure Finalize_Global_List is
  276.    begin
  277.       --  There are three case here:
  278.       --  a. the application uses tasks, in which case Finalize_Global_Tasks
  279.       --     will defer abortion
  280.       --  b. the application doesn't use tasks but uses other tasking
  281.       --     constructs, such as ATCs and protected objects. In this case,
  282.       --     the binder will call Finalize_Global_List instead of
  283.       --     Finalize_Global_Tasks, letting abort undeferred, and leading
  284.       --     to assertion failures in the GNULL
  285.       --  c. the application doesn't use any tasking construct in which case
  286.       --     deferring abort isn't necessary.
  287.       --
  288.       --  Until another solution is found to deal with case b, we need to
  289.       --  call abort_defer here to pass the checks, but we do not need to
  290.       --  undefer abortion, since Finalize_Global_List is the last procedure
  291.       --  called before exiting the partition.
  292.  
  293.       SSL.Abort_Defer.all;
  294.       Finalize_List (Global_Final_List);
  295.    end Finalize_Global_List;
  296.  
  297.    ------------------
  298.    -- Finalize_One --
  299.    ------------------
  300.  
  301.    procedure Finalize_One (Obj : in out  Finalizable) is
  302.    begin
  303.       Detach_From_Final_List (Obj);
  304.       Finalize (Obj);
  305.  
  306.    exception
  307.       when E_Occ : others => Raise_From_Finalize (null, False, E_Occ);
  308.    end Finalize_One;
  309.  
  310.    ------------------------
  311.    -- Get_RC_Dynamically --
  312.    ------------------------
  313.  
  314.    function Get_RC_Dynamically (Obj : Address) return Address is
  315.  
  316.       --  define a faked record controller to avoid generating
  317.       --  unnecessary expanded code for controlled types
  318.  
  319.       type Faked_Record_Controller is record
  320.          Tag, Prec, Next : Address;
  321.       end record;
  322.  
  323.       --  Reconstruction of a type with characteristics
  324.       --  comparable to the original type
  325.  
  326.       D : constant := Storage_Unit - 1;
  327.  
  328.       type Faked_Type_Of_Obj is record
  329.          Parent : SSE.Storage_Array
  330.            (1 .. (Parent_Size (Obj) + D) / Storage_Unit);
  331.          Controller : Faked_Record_Controller;
  332.       end record;
  333.  
  334.       type Obj_Ptr is access all Faked_Type_Of_Obj;
  335.       function To_Obj_Ptr is new Ada.Unchecked_Conversion (Address, Obj_Ptr);
  336.  
  337.    begin
  338.       return To_Obj_Ptr (Obj).Controller'Address;
  339.    end Get_RC_Dynamically;
  340.  
  341.    --------------------------
  342.    --  Deep_Tag_Initialize --
  343.    --------------------------
  344.  
  345.    procedure Deep_Tag_Initialize
  346.      (L : in out SFR.Finalizable_Ptr;
  347.       A :        System.Address;
  348.       B :        Short_Short_Integer)
  349.    is
  350.       V      : constant SFR.Finalizable_Ptr := To_Finalizable_Ptr (A);
  351.       Offset : constant SSE.Storage_Offset := RC_Offset (V'Tag);
  352.  
  353.       Controller : RC_Ptr;
  354.  
  355.    begin
  356.       --  This procedure should not be called if the object has no
  357.       --  controlled components
  358.  
  359.       if Offset = 0 then
  360.  
  361.          raise Program_Error;
  362.  
  363.       --  Has controlled components
  364.  
  365.       else
  366.          if Offset > 0 then
  367.             Controller := To_RC_Ptr (A + Offset);
  368.          else
  369.             Controller := To_RC_Ptr (Get_RC_Dynamically (A));
  370.          end if;
  371.       end if;
  372.  
  373.       Initialize (Controller.all);
  374.       Attach_To_Final_List (L, Controller.all, B);
  375.  
  376.       --  Is controlled
  377.  
  378.       if V.all in Finalizable then
  379.          Initialize (V.all);
  380.          Attach_To_Final_List (Controller.F, Finalizable (Controller.all), 1);
  381.       end if;
  382.    end Deep_Tag_Initialize;
  383.  
  384.    ----------------------
  385.    --  Deep_Tag_Adjust --
  386.    ----------------------
  387.  
  388.    procedure Deep_Tag_Adjust
  389.      (L : in out SFR.Finalizable_Ptr;
  390.       A : System.Address;
  391.       B : Short_Short_Integer)
  392.    is
  393.       V      : constant SFR.Finalizable_Ptr := To_Finalizable_Ptr (A);
  394.       Offset : constant SSE.Storage_Offset := RC_Offset (V'Tag);
  395.  
  396.       Controller : RC_Ptr;
  397.  
  398.    begin
  399.       --  Has controlled components
  400.  
  401.       if Offset /= 0 then
  402.          if Offset > 0 then
  403.             Controller := To_RC_Ptr (A + Offset);
  404.          else
  405.             Controller := To_RC_Ptr (Get_RC_Dynamically (A));
  406.          end if;
  407.  
  408.          Adjust (Controller.all);
  409.          Attach_To_Final_List (L, Controller.all, B);
  410.  
  411.       --  Is controlled
  412.  
  413.       elsif V.all in Finalizable then
  414.          Adjust (V.all);
  415.          Attach_To_Final_List (L, Finalizable (V.all), 1);
  416.       end if;
  417.    end Deep_Tag_Adjust;
  418.  
  419.    ------------------------
  420.    --  Deep_Tag_Finalize --
  421.    ------------------------
  422.  
  423.    procedure Deep_Tag_Finalize
  424.      (L : in out SFR.Finalizable_Ptr;
  425.       A : System.Address;
  426.       B : Boolean)
  427.    is
  428.       V      : constant SFR.Finalizable_Ptr := To_Finalizable_Ptr (A);
  429.       Offset : constant SSE.Storage_Offset := RC_Offset (V'Tag);
  430.  
  431.       Controller : RC_Ptr;
  432.  
  433.    begin
  434.       --  Has controlled components
  435.  
  436.       if Offset /= 0 then
  437.          if Offset > 0 then
  438.             Controller := To_RC_Ptr (A + Offset);
  439.          else
  440.             Controller := To_RC_Ptr (Get_RC_Dynamically (A));
  441.          end if;
  442.  
  443.          if B then
  444.             Finalize_One (Controller.all);
  445.          else
  446.             Finalize (Controller.all);
  447.          end if;
  448.  
  449.       --  Is controlled
  450.  
  451.       elsif V.all in Finalizable then
  452.          if B then
  453.             Finalize_One (V.all);
  454.          else
  455.             Finalize (V.all);
  456.          end if;
  457.       end if;
  458.    end Deep_Tag_Finalize;
  459.  
  460.    ----------------------
  461.    --  Deep_Tag_Attach --
  462.    -----------------------
  463.  
  464.    procedure Deep_Tag_Attach
  465.      (L : in out SFR.Finalizable_Ptr;
  466.       A : System.Address;
  467.       B : Short_Short_Integer)
  468.    is
  469.       V      : constant SFR.Finalizable_Ptr := To_Finalizable_Ptr (A);
  470.       Offset : constant SSE.Storage_Offset  := RC_Offset (V'Tag);
  471.  
  472.       Controller : RC_Ptr;
  473.  
  474.    begin
  475.       if Offset /= 0 then
  476.          if Offset > 0 then
  477.             Controller := To_RC_Ptr (A + Offset);
  478.          else
  479.             Controller := To_RC_Ptr (Get_RC_Dynamically (A));
  480.          end if;
  481.  
  482.          Attach_To_Final_List (L, Controller.all, B);
  483.  
  484.       --  Is controlled
  485.  
  486.       elsif V.all in Finalizable then
  487.          Attach_To_Final_List (L, V.all, B);
  488.       end if;
  489.    end Deep_Tag_Attach;
  490.  
  491.    ----------------------------------
  492.    -- Record_Controller Management --
  493.    ----------------------------------
  494.  
  495.    ----------------
  496.    -- Initialize --
  497.    ----------------
  498.  
  499.    procedure Initialize (Object : in out Limited_Record_Controller) is
  500.    begin
  501.       null;
  502.    end Initialize;
  503.  
  504.    procedure Initialize (Object : in out Record_Controller) is
  505.    begin
  506.       Object.My_Address := Object'Address;
  507.    end Initialize;
  508.  
  509.    -------------
  510.    --  Adjust --
  511.    -------------
  512.  
  513.    procedure Adjust (Object : in out Record_Controller) is
  514.  
  515.       My_Offset : constant SSE.Storage_Offset :=
  516.                     Object.My_Address - Object'Address;
  517.  
  518.       procedure Ptr_Adjust (Ptr : in out Finalizable_Ptr);
  519.       --  Substract the offset to the pointer
  520.  
  521.       procedure Reverse_Adjust (P : Finalizable_Ptr);
  522.       --  Ajust the components in the reverse order in which they are stored
  523.       --  on the finalization list. (Adjust and Finalization are not done in
  524.       --  the same order)
  525.  
  526.       procedure Ptr_Adjust (Ptr : in out Finalizable_Ptr) is
  527.       begin
  528.          if Ptr /= null then
  529.             Ptr := To_Finalizable_Ptr (To_Addr (Ptr) - My_Offset);
  530.          end if;
  531.       end Ptr_Adjust;
  532.  
  533.       procedure Reverse_Adjust (P : Finalizable_Ptr) is
  534.       begin
  535.          if P /= null then
  536.             Ptr_Adjust (P.Next);
  537.             Reverse_Adjust (P.Next);
  538.             Adjust (P.all);
  539.          end if;
  540.       end Reverse_Adjust;
  541.  
  542.    --  Start of processing for Adjust
  543.  
  544.    begin
  545.       --  Adjust the components and their finalization pointers next
  546.  
  547.       Ptr_Adjust (Object.F);
  548.       Reverse_Adjust (Object.F);
  549.  
  550.       --  Then Adjust the object itself
  551.  
  552.       Object.My_Address := Object'Address;
  553.    end Adjust;
  554.  
  555.    --------------
  556.    -- Finalize --
  557.    --------------
  558.  
  559.    procedure Finalize   (Object : in out Limited_Record_Controller) is
  560.    begin
  561.       Finalize_List (Object.F);
  562.    end Finalize;
  563.  
  564. end System.Finalization_Implementation;
  565.