exp_ch4.adb (Expand_N_Allocator): Generate meaningful names for a dynamic task if...
[platform/upstream/gcc.git] / gcc / ada / 5wmemory.adb
1 ------------------------------------------------------------------------------
2 --                                                                          --
3 --                         GNAT RUN-TIME COMPONENTS                         --
4 --                                                                          --
5 --                         S Y S T E M . M E M O R Y                        --
6 --                                                                          --
7 --                                 S p e c                                  --
8 --                                                                          --
9 --                            $Revision: 1.2 $
10 --                                                                          --
11 --             Copyright (C) 2001 Free Software Foundation, Inc.            --
12 --                                                                          --
13 -- This specification is derived from the Ada Reference Manual for use with --
14 -- GNAT. The copyright notice above, and the license provisions that follow --
15 -- apply solely to the  contents of the part following the private keyword. --
16 --                                                                          --
17 -- GNAT is free software;  you can  redistribute it  and/or modify it under --
18 -- terms of the  GNU General Public License as published  by the Free Soft- --
19 -- ware  Foundation;  either version 2,  or (at your option) any later ver- --
20 -- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
21 -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
22 -- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
23 -- for  more details.  You should have  received  a copy of the GNU General --
24 -- Public License  distributed with GNAT;  see file COPYING.  If not, write --
25 -- to  the Free Software Foundation,  59 Temple Place - Suite 330,  Boston, --
26 -- MA 02111-1307, USA.                                                      --
27 --                                                                          --
28 -- As a special exception,  if other files  instantiate  generics from this --
29 -- unit, or you link  this unit with other files  to produce an executable, --
30 -- this  unit  does not  by itself cause  the resulting  executable  to  be --
31 -- covered  by the  GNU  General  Public  License.  This exception does not --
32 -- however invalidate  any other reasons why  the executable file  might be --
33 -- covered by the  GNU Public License.                                      --
34 --                                                                          --
35 -- GNAT was originally developed  by the GNAT team at  New York University. --
36 -- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). --
37 --                                                                          --
38 ------------------------------------------------------------------------------
39
40 --  This version provides ways to limit the amount of used memory for systems
41 --  that do not have OS support for that.
42
43 --  The amount of available memory available for dynamic allocation is limited
44 --  by setting the environment variable GNAT_MEMORY_LIMIT to the number of
45 --  kilobytes that can be used.
46 --
47 --  Windows is currently using this version.
48
49 with Ada.Exceptions;
50 with System.Soft_Links;
51
52 package body System.Memory is
53
54    use Ada.Exceptions;
55    use System.Soft_Links;
56
57    function c_malloc (Size : size_t) return System.Address;
58    pragma Import (C, c_malloc, "malloc");
59
60    procedure c_free (Ptr : System.Address);
61    pragma Import (C, c_free, "free");
62
63    function c_realloc
64      (Ptr : System.Address; Size : size_t) return System.Address;
65    pragma Import (C, c_realloc, "realloc");
66
67    function msize (Ptr : System.Address) return size_t;
68    pragma Import (C, msize, "_msize");
69
70    function getenv (Str : String) return System.Address;
71    pragma Import (C, getenv);
72
73    function atoi (Str : System.Address) return Integer;
74    pragma Import (C, atoi);
75
76    Available_Memory : size_t := 0;
77    --  Amount of memory that is available for heap allocations.
78    --  A value of 0 means that the amount is not yet initialized.
79
80    Msize_Accuracy   : constant := 4096;
81    --  Defines the amount of memory to add to requested allocation sizes,
82    --  because malloc may return a bigger block than requested. As msize
83    --  is used when by Free, it must be used on allocation as well. To
84    --  prevent underflow of available_memory we need to use a reserve.
85
86    procedure Check_Available_Memory (Size : size_t);
87    --  This routine must be called while holding the task lock. When the
88    --  memory limit is not yet initialized, it will be set to the value of
89    --  the GNAT_MEMORY_LIMIT environment variable or to unlimited if that
90    --  does not exist. If the size is larger than the amount of available
91    --  memory, the task lock will be freed and a storage_error exception
92    --  will be raised.
93
94    -----------
95    -- Alloc --
96    -----------
97
98    function Alloc (Size : size_t) return System.Address is
99       Result      : System.Address;
100       Actual_Size : size_t := Size;
101
102    begin
103       if Size = size_t'Last then
104          Raise_Exception (Storage_Error'Identity, "object too large");
105       end if;
106
107       --  Change size from zero to non-zero. We still want a proper pointer
108       --  for the zero case because pointers to zero length objects have to
109       --  be distinct, but we can't just go ahead and allocate zero bytes,
110       --  since some malloc's return zero for a zero argument.
111
112       if Size = 0 then
113          Actual_Size := 1;
114       end if;
115
116       Lock_Task.all;
117
118       if Actual_Size + Msize_Accuracy >= Available_Memory then
119          Check_Available_Memory (Size + Msize_Accuracy);
120       end if;
121
122       Result := c_malloc (Actual_Size);
123
124       if Result /= System.Null_Address then
125          Available_Memory := Available_Memory - msize (Result);
126       end if;
127
128       Unlock_Task.all;
129
130       if Result = System.Null_Address then
131          Raise_Exception (Storage_Error'Identity, "heap exhausted");
132       end if;
133
134       return Result;
135    end Alloc;
136
137    ----------------------------
138    -- Check_Available_Memory --
139    ----------------------------
140
141    procedure Check_Available_Memory (Size : size_t) is
142       Gnat_Memory_Limit : System.Address;
143
144    begin
145       if Available_Memory = 0 then
146
147          --  The amount of available memory hasn't been initialized yet
148
149          Gnat_Memory_Limit := getenv ("GNAT_MEMORY_LIMIT" & ASCII.NUL);
150
151          if Gnat_Memory_Limit /= System.Null_Address then
152             Available_Memory :=
153               size_t (atoi (Gnat_Memory_Limit)) * 1024 + Msize_Accuracy;
154          else
155             Available_Memory := size_t'Last;
156          end if;
157       end if;
158
159       if Size >= Available_Memory then
160
161          --  There is a memory overflow
162
163          Unlock_Task.all;
164          Raise_Exception
165            (Storage_Error'Identity, "heap memory limit exceeded");
166       end if;
167    end Check_Available_Memory;
168
169    ----------
170    -- Free --
171    ----------
172
173    procedure Free (Ptr : System.Address) is
174    begin
175       Lock_Task.all;
176
177       if Ptr /= System.Null_Address then
178          Available_Memory := Available_Memory + msize (Ptr);
179       end if;
180
181       c_free (Ptr);
182
183       Unlock_Task.all;
184    end Free;
185
186    -------------
187    -- Realloc --
188    -------------
189
190    function Realloc
191      (Ptr  : System.Address;
192       Size : size_t)
193       return System.Address
194    is
195       Result      : System.Address;
196       Actual_Size : size_t := Size;
197       Old_Size    : size_t;
198
199    begin
200       if Size = size_t'Last then
201          Raise_Exception (Storage_Error'Identity, "object too large");
202       end if;
203
204       Lock_Task.all;
205
206       Old_Size := msize (Ptr);
207
208       --  Conservative check - no need to try to be precise here
209
210       if Size + Msize_Accuracy >= Available_Memory then
211          Check_Available_Memory (Size + Msize_Accuracy);
212       end if;
213
214       Result := c_realloc (Ptr, Actual_Size);
215
216       if Result /= System.Null_Address then
217          Available_Memory := Available_Memory + Old_Size - msize (Ptr);
218       end if;
219
220       Unlock_Task.all;
221
222       if Result = System.Null_Address then
223          Raise_Exception (Storage_Error'Identity, "heap exhausted");
224       end if;
225
226       return Result;
227    end Realloc;
228
229 end System.Memory;