OSDN Git Service

2007-08-31 Hristian Kirtchev <kirtchev@adacore.com>
[pf3gnuchains/gcc-fork.git] / gcc / ada / s-poosiz.adb
1 ------------------------------------------------------------------------------
2 --                                                                          --
3 --                         GNAT RUN-TIME COMPONENTS                         --
4 --                                                                          --
5 --                     S Y S T E M . P O O L _ S I Z E                      --
6 --                                                                          --
7 --                                 B o d y                                  --
8 --                                                                          --
9 --          Copyright (C) 1992-2007, Free Software Foundation, Inc.         --
10 --                                                                          --
11 -- GNAT is free software;  you can  redistribute it  and/or modify it under --
12 -- terms of the  GNU General Public License as published  by the Free Soft- --
13 -- ware  Foundation;  either version 2,  or (at your option) any later ver- --
14 -- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
17 -- for  more details.  You should have  received  a copy of the GNU General --
18 -- Public License  distributed with GNAT;  see file COPYING.  If not, write --
19 -- to  the  Free Software Foundation,  51  Franklin  Street,  Fifth  Floor, --
20 -- Boston, MA 02110-1301, USA.                                              --
21 --                                                                          --
22 -- As a special exception,  if other files  instantiate  generics from this --
23 -- unit, or you link  this unit with other files  to produce an executable, --
24 -- this  unit  does not  by itself cause  the resulting  executable  to  be --
25 -- covered  by the  GNU  General  Public  License.  This exception does not --
26 -- however invalidate  any other reasons why  the executable file  might be --
27 -- covered by the  GNU Public License.                                      --
28 --                                                                          --
29 -- GNAT was originally developed  by the GNAT team at  New York University. --
30 -- Extensive contributions were provided by Ada Core Technologies Inc.      --
31 --                                                                          --
32 ------------------------------------------------------------------------------
33
34 with System.Soft_Links;
35
36 with Ada.Unchecked_Conversion;
37
38 package body System.Pool_Size is
39
40    package SSE renames System.Storage_Elements;
41    use type SSE.Storage_Offset;
42
43    --  Even though these storage pools are typically only used by a single
44    --  task, if multiple tasks are declared at the same or a more nested scope
45    --  as the storage pool, there still may be concurrent access. The current
46    --  implementation of Stack_Bounded_Pool always uses a global lock for
47    --  protecting access. This should eventually be replaced by an atomic
48    --  linked list implementation for efficiency reasons.
49
50    package SSL renames System.Soft_Links;
51
52    type Storage_Count_Access is access SSE.Storage_Count;
53    function To_Storage_Count_Access is
54      new Ada.Unchecked_Conversion (Address, Storage_Count_Access);
55
56    SC_Size : constant :=  SSE.Storage_Count'Object_Size / System.Storage_Unit;
57
58    package Variable_Size_Management is
59
60       --  Embedded pool that manages allocation of variable-size data
61
62       --  This pool is used as soon as the Elmt_sizS of the pool object is 0
63
64       --  Allocation is done on the first chunk long enough for the request.
65       --  Deallocation just puts the freed chunk at the beginning of the list.
66
67       procedure Initialize  (Pool : in out Stack_Bounded_Pool);
68       procedure Allocate
69         (Pool         : in out Stack_Bounded_Pool;
70          Address      : out System.Address;
71          Storage_Size : SSE.Storage_Count;
72          Alignment    : SSE.Storage_Count);
73
74       procedure Deallocate
75         (Pool         : in out Stack_Bounded_Pool;
76          Address      : System.Address;
77          Storage_Size : SSE.Storage_Count;
78          Alignment    : SSE.Storage_Count);
79    end Variable_Size_Management;
80
81    package Vsize renames Variable_Size_Management;
82
83    --------------
84    -- Allocate --
85    --------------
86
87    procedure Allocate
88      (Pool         : in out Stack_Bounded_Pool;
89       Address      : out System.Address;
90       Storage_Size : SSE.Storage_Count;
91       Alignment    : SSE.Storage_Count)
92    is
93    begin
94       SSL.Lock_Task.all;
95
96       if Pool.Elmt_Size = 0 then
97          Vsize.Allocate (Pool, Address, Storage_Size, Alignment);
98
99       elsif Pool.First_Free /= 0 then
100          Address := Pool.The_Pool (Pool.First_Free)'Address;
101          Pool.First_Free := To_Storage_Count_Access (Address).all;
102
103       elsif
104         Pool.First_Empty <= (Pool.Pool_Size - Pool.Aligned_Elmt_Size + 1)
105       then
106          Address := Pool.The_Pool (Pool.First_Empty)'Address;
107          Pool.First_Empty := Pool.First_Empty + Pool.Aligned_Elmt_Size;
108
109       else
110          raise Storage_Error;
111       end if;
112
113       SSL.Unlock_Task.all;
114
115    exception
116       when others =>
117          SSL.Unlock_Task.all;
118          raise;
119    end Allocate;
120
121    ----------------
122    -- Deallocate --
123    ----------------
124
125    procedure Deallocate
126      (Pool         : in out Stack_Bounded_Pool;
127       Address      : System.Address;
128       Storage_Size : SSE.Storage_Count;
129       Alignment    : SSE.Storage_Count)
130    is
131    begin
132       SSL.Lock_Task.all;
133
134       if Pool.Elmt_Size = 0 then
135          Vsize.Deallocate (Pool, Address, Storage_Size, Alignment);
136
137       else
138          To_Storage_Count_Access (Address).all := Pool.First_Free;
139          Pool.First_Free := Address - Pool.The_Pool'Address + 1;
140       end if;
141
142       SSL.Unlock_Task.all;
143    exception
144       when others =>
145          SSL.Unlock_Task.all;
146          raise;
147    end Deallocate;
148
149    ----------------
150    -- Initialize --
151    ----------------
152
153    procedure Initialize  (Pool : in out Stack_Bounded_Pool) is
154
155       --  Define the appropriate alignment for allocations. This is the
156       --  maximum of the requested alignment, and the alignment required
157       --  for Storage_Count values. The latter test is to ensure that we
158       --  can properly reference the linked list pointers for free lists.
159
160       Align : constant SSE.Storage_Count :=
161                 SSE.Storage_Count'Max
162                   (SSE.Storage_Count'Alignment, Pool.Alignment);
163
164    begin
165       if Pool.Elmt_Size = 0 then
166          Vsize.Initialize (Pool);
167
168       else
169          Pool.First_Free := 0;
170          Pool.First_Empty := 1;
171
172          --  Compute the size to allocate given the size of the element and
173          --  the possible alignment requirement as defined above.
174
175          Pool.Aligned_Elmt_Size :=
176            SSE.Storage_Count'Max (SC_Size,
177              ((Pool.Elmt_Size + Align - 1) / Align) * Align);
178       end if;
179    end Initialize;
180
181    ------------------
182    -- Storage_Size --
183    ------------------
184
185    function  Storage_Size
186      (Pool : Stack_Bounded_Pool) return SSE.Storage_Count
187    is
188    begin
189       return Pool.Pool_Size;
190    end Storage_Size;
191
192    ------------------------------
193    -- Variable_Size_Management --
194    ------------------------------
195
196    package body Variable_Size_Management is
197
198       Minimum_Size : constant := 2 * SC_Size;
199
200       procedure Set_Size
201         (Pool        : Stack_Bounded_Pool;
202          Chunk, Size : SSE.Storage_Count);
203       --  Update the field 'size' of a chunk of available storage
204
205       procedure Set_Next
206         (Pool        : Stack_Bounded_Pool;
207          Chunk, Next : SSE.Storage_Count);
208       --  Update the field 'next' of a chunk of available storage
209
210       function Size
211         (Pool  : Stack_Bounded_Pool;
212          Chunk : SSE.Storage_Count) return SSE.Storage_Count;
213       --  Fetch the field 'size' of a chunk of available storage
214
215       function Next
216         (Pool  : Stack_Bounded_Pool;
217          Chunk : SSE.Storage_Count) return SSE.Storage_Count;
218       --  Fetch the field 'next' of a chunk of available storage
219
220       function Chunk_Of
221         (Pool : Stack_Bounded_Pool;
222          Addr : System.Address) return SSE.Storage_Count;
223       --  Give the chunk number in the pool from its Address
224
225       --------------
226       -- Allocate --
227       --------------
228
229       procedure Allocate
230         (Pool         : in out Stack_Bounded_Pool;
231          Address      : out System.Address;
232          Storage_Size : SSE.Storage_Count;
233          Alignment    : SSE.Storage_Count)
234       is
235          Chunk      : SSE.Storage_Count;
236          New_Chunk  : SSE.Storage_Count;
237          Prev_Chunk : SSE.Storage_Count;
238          Our_Align  : constant SSE.Storage_Count :=
239                         SSE.Storage_Count'Max (SSE.Storage_Count'Alignment,
240                                                Alignment);
241          Align_Size : constant SSE.Storage_Count :=
242                         SSE.Storage_Count'Max (
243                           Minimum_Size,
244                           ((Storage_Size + Our_Align - 1) / Our_Align) *
245                                                                   Our_Align);
246
247       begin
248          --  Look for the first big enough chunk
249
250          Prev_Chunk := Pool.First_Free;
251          Chunk := Next (Pool, Prev_Chunk);
252
253          while Chunk /= 0 and then Size (Pool, Chunk) < Align_Size loop
254             Prev_Chunk := Chunk;
255             Chunk := Next (Pool, Chunk);
256          end loop;
257
258          --  Raise storage_error if no big enough chunk available
259
260          if Chunk = 0 then
261             raise Storage_Error;
262          end if;
263
264          --  When the chunk is bigger than what is needed, take appropraite
265          --  amount and build a new shrinked chunk with the remainder.
266
267          if Size (Pool, Chunk) - Align_Size  > Minimum_Size then
268             New_Chunk := Chunk + Align_Size;
269             Set_Size (Pool, New_Chunk, Size (Pool, Chunk) - Align_Size);
270             Set_Next (Pool, New_Chunk, Next (Pool, Chunk));
271             Set_Next (Pool, Prev_Chunk, New_Chunk);
272
273          --  If the chunk is the right size, just delete it from the chain
274
275          else
276             Set_Next (Pool, Prev_Chunk, Next (Pool, Chunk));
277          end if;
278
279          Address := Pool.The_Pool (Chunk)'Address;
280       end Allocate;
281
282       --------------
283       -- Chunk_Of --
284       --------------
285
286       function Chunk_Of
287         (Pool : Stack_Bounded_Pool;
288          Addr : System.Address) return SSE.Storage_Count
289       is
290       begin
291          return 1 + abs (Addr - Pool.The_Pool (1)'Address);
292       end Chunk_Of;
293
294       ----------------
295       -- Deallocate --
296       ----------------
297
298       procedure Deallocate
299         (Pool         : in out Stack_Bounded_Pool;
300          Address      : System.Address;
301          Storage_Size : SSE.Storage_Count;
302          Alignment    : SSE.Storage_Count)
303       is
304          Align_Size : constant SSE.Storage_Count :=
305                         ((Storage_Size + Alignment - 1) / Alignment) *
306                                                                  Alignment;
307          Chunk : constant SSE.Storage_Count := Chunk_Of (Pool, Address);
308
309       begin
310          --  Attach the freed chunk to the chain
311
312          Set_Size (Pool, Chunk,
313                          SSE.Storage_Count'Max (Align_Size, Minimum_Size));
314          Set_Next (Pool, Chunk, Next (Pool, Pool.First_Free));
315          Set_Next (Pool, Pool.First_Free,  Chunk);
316
317       end Deallocate;
318
319       ----------------
320       -- Initialize --
321       ----------------
322
323       procedure Initialize  (Pool : in out Stack_Bounded_Pool) is
324       begin
325          Pool.First_Free := 1;
326
327          if Pool.Pool_Size > Minimum_Size then
328             Set_Next (Pool, Pool.First_Free, Pool.First_Free + Minimum_Size);
329             Set_Size (Pool, Pool.First_Free, 0);
330             Set_Size (Pool, Pool.First_Free + Minimum_Size,
331                                               Pool.Pool_Size - Minimum_Size);
332             Set_Next (Pool, Pool.First_Free + Minimum_Size, 0);
333          end if;
334       end Initialize;
335
336       ----------
337       -- Next --
338       ----------
339
340       function Next
341         (Pool  : Stack_Bounded_Pool;
342          Chunk : SSE.Storage_Count) return SSE.Storage_Count
343       is
344       begin
345          pragma Warnings (Off);
346          --  Kill alignment warnings, we are careful to make sure
347          --  that the alignment is correct.
348
349          return To_Storage_Count_Access
350                   (Pool.The_Pool (Chunk + SC_Size)'Address).all;
351
352          pragma Warnings (On);
353       end Next;
354
355       --------------
356       -- Set_Next --
357       --------------
358
359       procedure Set_Next
360         (Pool        : Stack_Bounded_Pool;
361          Chunk, Next : SSE.Storage_Count)
362       is
363       begin
364          pragma Warnings (Off);
365          --  Kill alignment warnings, we are careful to make sure
366          --  that the alignment is correct.
367
368          To_Storage_Count_Access
369            (Pool.The_Pool (Chunk + SC_Size)'Address).all := Next;
370
371          pragma Warnings (On);
372       end Set_Next;
373
374       --------------
375       -- Set_Size --
376       --------------
377
378       procedure Set_Size
379         (Pool        : Stack_Bounded_Pool;
380          Chunk, Size : SSE.Storage_Count)
381       is
382       begin
383          pragma Warnings (Off);
384          --  Kill alignment warnings, we are careful to make sure
385          --  that the alignment is correct.
386
387          To_Storage_Count_Access
388            (Pool.The_Pool (Chunk)'Address).all := Size;
389
390          pragma Warnings (On);
391       end Set_Size;
392
393       ----------
394       -- Size --
395       ----------
396
397       function Size
398         (Pool  : Stack_Bounded_Pool;
399          Chunk : SSE.Storage_Count) return SSE.Storage_Count
400       is
401       begin
402          pragma Warnings (Off);
403          --  Kill alignment warnings, we are careful to make sure
404          --  that the alignment is correct.
405
406          return To_Storage_Count_Access (Pool.The_Pool (Chunk)'Address).all;
407
408          pragma Warnings (On);
409       end Size;
410
411    end  Variable_Size_Management;
412 end System.Pool_Size;