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-stache.adb < prev    next >
Text File  |  2000-07-19  |  10KB  |  274 lines

  1. ------------------------------------------------------------------------------
  2. --                                                                          --
  3. --                GNU ADA RUN-TIME LIBRARY (GNARL) COMPONENTS               --
  4. --                                                                          --
  5. --                 S Y S T E M . S T A C K _ C H E C K I N G                --
  6. --                                                                          --
  7. --                                  B o d y                                 --
  8. --                                                                          --
  9. --                             $Revision: 1.7 $
  10. --                                                                          --
  11. --          Copyright (C) 1999-2000 Free Software Foundation, Inc.          --
  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. with Ada.Exceptions;
  38.  
  39. with System.Storage_Elements; use System.Storage_Elements;
  40. with System.Parameters; use System.Parameters;
  41. with System.Soft_Links;
  42.  
  43. package body System.Stack_Checking is
  44.  
  45.    function Set_Stack_Info (Stack : access Stack_Access) return Stack_Access;
  46.  
  47.    --  The function Set_Stack_Info is the actual function that updates
  48.    --  the cache containing a pointer to the Stack_Info. It may also
  49.    --  be used for detecting asynchronous abort in combination with
  50.    --  Invalidate_Self_Cache.
  51.  
  52.    --  Set_Stack_Info should do the following things in order:
  53.    --     1) Get the Stack_Access value for the current task
  54.    --     2) Set Stack.all to the value obtained in 1)
  55.    --     3) Optionally Poll to check for asynchronous abort
  56.  
  57.    --  This order is important because if at any time a write to
  58.    --  the stack cache is is pending, that write should be followed
  59.    --  by a Poll to prevent loosing signals.
  60.  
  61.    --  Note: This function must be compiled with Polling turned off
  62.  
  63.    --  Note: on systems like VxWorks and OS/2 with real thread-local storage,
  64.    --        Set_Stack_Info should return an access value for such local
  65.    --        storage. In those cases the cache will always be up-to-date.
  66.  
  67.    --  The following constants should be imported from some system-specific
  68.    --  constants package. The constants must be static for performance reasons.
  69.  
  70.    -----------------
  71.    -- Stack_Check --
  72.    -----------------
  73.  
  74.    function Stack_Check
  75.      (Stack_Address : System.Address)
  76.       return Stack_Access
  77.    is
  78.       type Frame_Marker is null record;
  79.       Marker        : Frame_Marker;
  80.       Cached_Stack  : constant Stack_Access := Cache;
  81.       Frame_Address : constant System.Address := Marker'Address;
  82.  
  83.    begin
  84.       --  This function first does a "cheap" check which is correct
  85.       --  if it succeeds. In case of failure, the full check is done.
  86.       --  Ideally the cheap check should be done in an optimized manner,
  87.       --  or be inlined.
  88.  
  89.       if (Stack_Grows_Down and then
  90.             (Frame_Address <= Cached_Stack.Base
  91.                and
  92.              Stack_Address > Cached_Stack.Limit))
  93.         or else
  94.          (not Stack_Grows_Down and then
  95.             (Frame_Address >= Cached_Stack.Base
  96.                and
  97.              Stack_Address < Cached_Stack.Limit))
  98.       then
  99.          --  Cached_Stack is valid as it passed the stack check
  100.          return Cached_Stack;
  101.       end if;
  102.  
  103.       Full_Check :
  104.       declare
  105.          My_Stack : Stack_Access := Set_Stack_Info (Cache'Access);
  106.          --  At this point Stack.all might already be invalid, so
  107.          --  it is essential to use our local copy of Stack!
  108.  
  109.       begin
  110.  
  111.          if (Stack_Grows_Down and then
  112.                (not (Frame_Address <= My_Stack.Base)))
  113.            or else
  114.             (not Stack_Grows_Down and then
  115.                (not (Frame_Address >= My_Stack.Base)))
  116.          then
  117.             --  The returned Base is lower than the stored one,
  118.             --  so assume that the original one wasn't right and use the
  119.             --  current Frame_Address as new one. This allows initializing
  120.             --  Base with the Frame_Address as approximation.
  121.             --  During initialization the Frame_Address will be close to
  122.             --  the stack base anyway: the difference should be compensated
  123.             --  for in the stack reserve.
  124.  
  125.             My_Stack.Base := Frame_Address;
  126.          end if;
  127.  
  128.          if (Stack_Grows_Down and then
  129.                   Stack_Address < My_Stack.Limit)
  130.            or else
  131.             (not Stack_Grows_Down and then
  132.                   Stack_Address > My_Stack.Limit)
  133.          then
  134.             Ada.Exceptions.Raise_Exception
  135.               (E       => Storage_Error'Identity,
  136.                Message => "stack overflow detected");
  137.          end if;
  138.  
  139.          return My_Stack;
  140.       end Full_Check;
  141.    end Stack_Check;
  142.  
  143.    ----------------------------
  144.    -- Invalidate_Stack_Cache --
  145.    ----------------------------
  146.  
  147.    procedure Invalidate_Stack_Cache (Any_Stack : Stack_Access) is
  148.    begin
  149.       Cache := Null_Stack;
  150.    end Invalidate_Stack_Cache;
  151.  
  152.    --------------------
  153.    -- Set_Stack_Info --
  154.    --------------------
  155.  
  156.    function Set_Stack_Info
  157.      (Stack : access Stack_Access)
  158.       return Stack_Access
  159.    is
  160.       type Frame_Mark is null record;
  161.       Frame_Location : Frame_Mark;
  162.       Frame_Address  : Address := Frame_Location'Address;
  163.  
  164.       My_Stack    : Stack_Access;
  165.       Limit_Chars : System.Address;
  166.       Limit       : Integer;
  167.  
  168.       function getenv (S : String) return System.Address;
  169.       pragma Import (C, getenv, External_Name => "getenv");
  170.  
  171.       function atoi (A : System.Address) return Integer;
  172.       pragma Import (C, atoi);
  173.  
  174.    begin
  175.       --  The order of steps 1 .. 3 is important, see specification.
  176.  
  177.       --  1) Get the Stack_Access value for the current task
  178.  
  179.       My_Stack := Soft_Links.Get_Stack_Info.all;
  180.  
  181.       if My_Stack.Base = Null_Address then
  182.  
  183.          --  First invocation, initialize based on the assumption that
  184.          --  there are Environment_Stack_Size bytes available beyond
  185.          --  the current frame address.
  186.  
  187.          if My_Stack.Size = 0 then
  188.  
  189.             My_Stack.Size := Storage_Offset'Last;
  190.  
  191.             --  When the environment variable GNAT_STACK_LIMIT is set,
  192.             --  set Environment_Stack_Size to that number of kB.
  193.  
  194.             Limit_Chars := getenv ("GNAT_STACK_LIMIT" & ASCII.NUL);
  195.  
  196.             if Limit_Chars /= Null_Address then
  197.                Limit := atoi (Limit_Chars);
  198.                if Limit >= 0 then
  199.                   My_Stack.Size := Storage_Offset (Limit) * 1024;
  200.                end if;
  201.             end if;
  202.          end if;
  203.  
  204.          My_Stack.Base := Frame_Address;
  205.  
  206.          if Stack_Grows_Down then
  207.  
  208.             --  Prevent wrap-around on too big stack sizes
  209.  
  210.             My_Stack.Limit := My_Stack.Base - My_Stack.Size;
  211.  
  212.             if My_Stack.Limit > My_Stack.Base then
  213.                My_Stack.Limit := Address'First;
  214.             end if;
  215.  
  216.          else
  217.             My_Stack.Limit := My_Stack.Base + My_Stack.Size;
  218.  
  219.             --  Prevent wrap-around on too big stack sizes
  220.  
  221.             if My_Stack.Limit < My_Stack.Base then
  222.                My_Stack.Limit := Address'Last;
  223.             end if;
  224.          end if;
  225.       end if;
  226.  
  227.       --  2) Set Stack.all to the value obtained in 1)
  228.  
  229.       Stack.all := My_Stack;
  230.  
  231.       --  3) Optionally Poll to check for asynchronous abort
  232.  
  233.       if Soft_Links.Check_Abort_Status.all /= 0 then
  234.          raise Standard'Abort_Signal;
  235.       end if;
  236.  
  237.       return My_Stack; -- Never trust the cached value, but return local copy!
  238.    end Set_Stack_Info;
  239.  
  240.    --------------------
  241.    -- Set_Stack_Size --
  242.    --------------------
  243.  
  244.    --  Specify the stack size for the current frame.
  245.  
  246.    procedure Set_Stack_Size
  247.      (Stack_Size : System.Storage_Elements.Storage_Offset)
  248.    is
  249.       My_Stack      : Stack_Access;
  250.       Frame_Address : constant System.Address := My_Stack'Address;
  251.  
  252.    begin
  253.       My_Stack := Stack_Check (Frame_Address);
  254.  
  255.       if Stack_Grows_Down then
  256.          My_Stack.Limit := My_Stack.Base - Stack_Size;
  257.       else
  258.          My_Stack.Limit := My_Stack.Base + Stack_Size;
  259.       end if;
  260.    end Set_Stack_Size;
  261.  
  262.    ------------------------
  263.    -- Update_Stack_Cache --
  264.    ------------------------
  265.  
  266.    procedure Update_Stack_Cache (Stack : Stack_Access) is
  267.    begin
  268.       if not Multi_Processor then
  269.          Cache := Stack;
  270.       end if;
  271.    end Update_Stack_Cache;
  272.  
  273. end System.Stack_Checking;
  274.