1 ------------------------------------------------------------------------------
3 -- GNAT RUN-TIME COMPONENTS --
5 -- S Y S T E M . P O O L _ S I Z E --
9 -- Copyright (C) 1992-2006 Free Software Foundation, Inc. --
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. --
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. --
29 -- GNAT was originally developed by the GNAT team at New York University. --
30 -- Extensive contributions were provided by Ada Core Technologies Inc. --
32 ------------------------------------------------------------------------------
34 with System
.Soft_Links
;
36 with Unchecked_Conversion
;
38 package body System
.Pool_Size
is
40 package SSE
renames System
.Storage_Elements
;
41 use type SSE
.Storage_Offset
;
43 -- Even though these storage pools are typically only used
44 -- by a single task, if multiple tasks are declared at the
45 -- same or a more nested scope as the storage pool, there
46 -- still may be concurrent access. The current implementation
47 -- of Stack_Bounded_Pool always uses a global lock for protecting
48 -- access. This should eventually be replaced by an atomic
49 -- linked list implementation for efficiency reasons.
51 package SSL
renames System
.Soft_Links
;
53 type Storage_Count_Access
is access SSE
.Storage_Count
;
54 function To_Storage_Count_Access
is
55 new Unchecked_Conversion
(Address
, Storage_Count_Access
);
57 SC_Size
: constant := SSE
.Storage_Count
'Object_Size / System
.Storage_Unit
;
59 package Variable_Size_Management
is
61 -- Embedded pool that manages allocation of variable-size data.
63 -- This pool is used as soon as the Elmt_sizS of the pool object is 0.
65 -- Allocation is done on the first chunk long enough for the request.
66 -- Deallocation just puts the freed chunk at the beginning of the list.
68 procedure Initialize
(Pool
: in out Stack_Bounded_Pool
);
70 (Pool
: in out Stack_Bounded_Pool
;
71 Address
: out System
.Address
;
72 Storage_Size
: SSE
.Storage_Count
;
73 Alignment
: SSE
.Storage_Count
);
76 (Pool
: in out Stack_Bounded_Pool
;
77 Address
: System
.Address
;
78 Storage_Size
: SSE
.Storage_Count
;
79 Alignment
: SSE
.Storage_Count
);
80 end Variable_Size_Management
;
82 package Vsize
renames Variable_Size_Management
;
89 (Pool
: in out Stack_Bounded_Pool
;
90 Address
: out System
.Address
;
91 Storage_Size
: SSE
.Storage_Count
;
92 Alignment
: SSE
.Storage_Count
)
97 if Pool
.Elmt_Size
= 0 then
98 Vsize
.Allocate
(Pool
, Address
, Storage_Size
, Alignment
);
100 elsif Pool
.First_Free
/= 0 then
101 Address
:= Pool
.The_Pool
(Pool
.First_Free
)'Address;
102 Pool
.First_Free
:= To_Storage_Count_Access
(Address
).all;
105 Pool
.First_Empty
<= (Pool
.Pool_Size
- Pool
.Aligned_Elmt_Size
+ 1)
107 Address
:= Pool
.The_Pool
(Pool
.First_Empty
)'Address;
108 Pool
.First_Empty
:= Pool
.First_Empty
+ Pool
.Aligned_Elmt_Size
;
127 (Pool
: in out Stack_Bounded_Pool
;
128 Address
: System
.Address
;
129 Storage_Size
: SSE
.Storage_Count
;
130 Alignment
: SSE
.Storage_Count
)
135 if Pool
.Elmt_Size
= 0 then
136 Vsize
.Deallocate
(Pool
, Address
, Storage_Size
, Alignment
);
139 To_Storage_Count_Access
(Address
).all := Pool
.First_Free
;
140 Pool
.First_Free
:= Address
- Pool
.The_Pool
'Address + 1;
154 procedure Initialize
(Pool
: in out Stack_Bounded_Pool
) is
156 -- Define the appropriate alignment for allocations. This is the
157 -- maximum of the requested alignment, and the alignment required
158 -- for Storage_Count values. The latter test is to ensure that we
159 -- can properly reference the linked list pointers for free lists.
161 Align
: constant SSE
.Storage_Count
:=
162 SSE
.Storage_Count
'Max
163 (SSE
.Storage_Count
'Alignment, Pool
.Alignment
);
166 if Pool
.Elmt_Size
= 0 then
167 Vsize
.Initialize
(Pool
);
170 Pool
.First_Free
:= 0;
171 Pool
.First_Empty
:= 1;
173 -- Compute the size to allocate given the size of the element and
174 -- the possible alignment requirement as defined above.
176 Pool
.Aligned_Elmt_Size
:=
177 SSE
.Storage_Count
'Max (SC_Size
,
178 ((Pool
.Elmt_Size
+ Align
- 1) / Align
) * Align
);
186 function Storage_Size
187 (Pool
: Stack_Bounded_Pool
) return SSE
.Storage_Count
190 return Pool
.Pool_Size
;
193 ------------------------------
194 -- Variable_Size_Management --
195 ------------------------------
197 package body Variable_Size_Management
is
199 Minimum_Size
: constant := 2 * SC_Size
;
202 (Pool
: Stack_Bounded_Pool
;
203 Chunk
, Size
: SSE
.Storage_Count
);
204 -- Update the field 'size' of a chunk of available storage
207 (Pool
: Stack_Bounded_Pool
;
208 Chunk
, Next
: SSE
.Storage_Count
);
209 -- Update the field 'next' of a chunk of available storage
212 (Pool
: Stack_Bounded_Pool
;
213 Chunk
: SSE
.Storage_Count
) return SSE
.Storage_Count
;
214 -- Fetch the field 'size' of a chunk of available storage
217 (Pool
: Stack_Bounded_Pool
;
218 Chunk
: SSE
.Storage_Count
) return SSE
.Storage_Count
;
219 -- Fetch the field 'next' of a chunk of available storage
222 (Pool
: Stack_Bounded_Pool
;
223 Addr
: System
.Address
) return SSE
.Storage_Count
;
224 -- Give the chunk number in the pool from its Address
231 (Pool
: in out Stack_Bounded_Pool
;
232 Address
: out System
.Address
;
233 Storage_Size
: SSE
.Storage_Count
;
234 Alignment
: SSE
.Storage_Count
)
236 Chunk
: SSE
.Storage_Count
;
237 New_Chunk
: SSE
.Storage_Count
;
238 Prev_Chunk
: SSE
.Storage_Count
;
239 Our_Align
: constant SSE
.Storage_Count
:=
240 SSE
.Storage_Count
'Max (SSE
.Storage_Count
'Alignment,
242 Align_Size
: constant SSE
.Storage_Count
:=
243 SSE
.Storage_Count
'Max (
245 ((Storage_Size
+ Our_Align
- 1) / Our_Align
) *
249 -- Look for the first big enough chunk
251 Prev_Chunk
:= Pool
.First_Free
;
252 Chunk
:= Next
(Pool
, Prev_Chunk
);
254 while Chunk
/= 0 and then Size
(Pool
, Chunk
) < Align_Size
loop
256 Chunk
:= Next
(Pool
, Chunk
);
259 -- Raise storage_error if no big enough chunk available
265 -- When the chunk is bigger than what is needed, take appropraite
266 -- amount and build a new shrinked chunk with the remainder.
268 if Size
(Pool
, Chunk
) - Align_Size
> Minimum_Size
then
269 New_Chunk
:= Chunk
+ Align_Size
;
270 Set_Size
(Pool
, New_Chunk
, Size
(Pool
, Chunk
) - Align_Size
);
271 Set_Next
(Pool
, New_Chunk
, Next
(Pool
, Chunk
));
272 Set_Next
(Pool
, Prev_Chunk
, New_Chunk
);
274 -- If the chunk is the right size, just delete it from the chain
277 Set_Next
(Pool
, Prev_Chunk
, Next
(Pool
, Chunk
));
280 Address
:= Pool
.The_Pool
(Chunk
)'Address;
288 (Pool
: Stack_Bounded_Pool
;
289 Addr
: System
.Address
) return SSE
.Storage_Count
292 return 1 + abs (Addr
- Pool
.The_Pool
(1)'Address);
300 (Pool
: in out Stack_Bounded_Pool
;
301 Address
: System
.Address
;
302 Storage_Size
: SSE
.Storage_Count
;
303 Alignment
: SSE
.Storage_Count
)
305 Align_Size
: constant SSE
.Storage_Count
:=
306 ((Storage_Size
+ Alignment
- 1) / Alignment
) *
308 Chunk
: constant SSE
.Storage_Count
:= Chunk_Of
(Pool
, Address
);
311 -- Attach the freed chunk to the chain
313 Set_Size
(Pool
, Chunk
,
314 SSE
.Storage_Count
'Max (Align_Size
, Minimum_Size
));
315 Set_Next
(Pool
, Chunk
, Next
(Pool
, Pool
.First_Free
));
316 Set_Next
(Pool
, Pool
.First_Free
, Chunk
);
324 procedure Initialize
(Pool
: in out Stack_Bounded_Pool
) is
326 Pool
.First_Free
:= 1;
328 if Pool
.Pool_Size
> Minimum_Size
then
329 Set_Next
(Pool
, Pool
.First_Free
, Pool
.First_Free
+ Minimum_Size
);
330 Set_Size
(Pool
, Pool
.First_Free
, 0);
331 Set_Size
(Pool
, Pool
.First_Free
+ Minimum_Size
,
332 Pool
.Pool_Size
- Minimum_Size
);
333 Set_Next
(Pool
, Pool
.First_Free
+ Minimum_Size
, 0);
342 (Pool
: Stack_Bounded_Pool
;
343 Chunk
: SSE
.Storage_Count
) return SSE
.Storage_Count
346 pragma Warnings
(Off
);
347 -- Kill alignment warnings, we are careful to make sure
348 -- that the alignment is correct.
350 return To_Storage_Count_Access
351 (Pool
.The_Pool
(Chunk
+ SC_Size
)'Address).all;
353 pragma Warnings
(On
);
361 (Pool
: Stack_Bounded_Pool
;
362 Chunk
, Next
: SSE
.Storage_Count
)
365 pragma Warnings
(Off
);
366 -- Kill alignment warnings, we are careful to make sure
367 -- that the alignment is correct.
369 To_Storage_Count_Access
370 (Pool
.The_Pool
(Chunk
+ SC_Size
)'Address).all := Next
;
372 pragma Warnings
(On
);
380 (Pool
: Stack_Bounded_Pool
;
381 Chunk
, Size
: SSE
.Storage_Count
)
384 pragma Warnings
(Off
);
385 -- Kill alignment warnings, we are careful to make sure
386 -- that the alignment is correct.
388 To_Storage_Count_Access
389 (Pool
.The_Pool
(Chunk
)'Address).all := Size
;
391 pragma Warnings
(On
);
399 (Pool
: Stack_Bounded_Pool
;
400 Chunk
: SSE
.Storage_Count
) return SSE
.Storage_Count
403 pragma Warnings
(Off
);
404 -- Kill alignment warnings, we are careful to make sure
405 -- that the alignment is correct.
407 return To_Storage_Count_Access
(Pool
.The_Pool
(Chunk
)'Address).all;
409 pragma Warnings
(On
);
412 end Variable_Size_Management
;
413 end System
.Pool_Size
;