OSDN Git Service

Update FSF address
[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-2004 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.Storage_Elements;
35 with System.Soft_Links;
36
37 with Unchecked_Conversion;
38
39 package body System.Pool_Size is
40
41    package SSE renames System.Storage_Elements;
42    use type SSE.Storage_Offset;
43
44    --  Even though these storage pools are typically only used
45    --  by a single task, if multiple tasks are declared at the
46    --  same or a more nested scope as the storage pool, there
47    --  still may be concurrent access. The current implementation
48    --  of Stack_Bounded_Pool always uses a global lock for protecting
49    --  access. This should eventually be replaced by an atomic
50    --  linked list implementation for efficiency reasons.
51
52    package SSL renames System.Soft_Links;
53
54    type Storage_Count_Access is access SSE.Storage_Count;
55    function To_Storage_Count_Access is
56      new Unchecked_Conversion (Address, Storage_Count_Access);
57
58    SC_Size : constant :=  SSE.Storage_Count'Object_Size / System.Storage_Unit;
59
60    package Variable_Size_Management is
61
62       --  Embedded pool that manages allocation of variable-size data.
63
64       --  This pool is used as soon as the Elmt_sizS of the pool object is 0.
65
66       --  Allocation is done on the first chunk long enough for the request.
67       --  Deallocation just puts the freed chunk at the beginning of the list.
68
69       procedure Initialize  (Pool : in out Stack_Bounded_Pool);
70       procedure Allocate
71         (Pool         : in out Stack_Bounded_Pool;
72          Address      : out System.Address;
73          Storage_Size : SSE.Storage_Count;
74          Alignment    : SSE.Storage_Count);
75
76       procedure Deallocate
77         (Pool         : in out Stack_Bounded_Pool;
78          Address      : System.Address;
79          Storage_Size : SSE.Storage_Count;
80          Alignment    : SSE.Storage_Count);
81    end Variable_Size_Management;
82
83    package Vsize renames Variable_Size_Management;
84
85    --------------
86    -- Allocate --
87    --------------
88
89    procedure Allocate
90      (Pool         : in out Stack_Bounded_Pool;
91       Address      : out System.Address;
92       Storage_Size : SSE.Storage_Count;
93       Alignment    : SSE.Storage_Count)
94    is
95    begin
96       SSL.Lock_Task.all;
97
98       if Pool.Elmt_Size = 0 then
99          Vsize.Allocate (Pool, Address, Storage_Size, Alignment);
100
101       elsif Pool.First_Free /= 0 then
102          Address := Pool.The_Pool (Pool.First_Free)'Address;
103          Pool.First_Free := To_Storage_Count_Access (Address).all;
104
105       elsif
106         Pool.First_Empty <= (Pool.Pool_Size - Pool.Aligned_Elmt_Size + 1)
107       then
108          Address := Pool.The_Pool (Pool.First_Empty)'Address;
109          Pool.First_Empty := Pool.First_Empty + Pool.Aligned_Elmt_Size;
110
111       else
112          raise Storage_Error;
113       end if;
114
115       SSL.Unlock_Task.all;
116
117    exception
118       when others =>
119          SSL.Unlock_Task.all;
120          raise;
121    end Allocate;
122
123    ----------------
124    -- Deallocate --
125    ----------------
126
127    procedure Deallocate
128      (Pool         : in out Stack_Bounded_Pool;
129       Address      : System.Address;
130       Storage_Size : SSE.Storage_Count;
131       Alignment    : SSE.Storage_Count)
132    is
133    begin
134       SSL.Lock_Task.all;
135
136       if Pool.Elmt_Size = 0 then
137          Vsize.Deallocate (Pool, Address, Storage_Size, Alignment);
138
139       else
140          To_Storage_Count_Access (Address).all := Pool.First_Free;
141          Pool.First_Free := Address - Pool.The_Pool'Address + 1;
142       end if;
143
144       SSL.Unlock_Task.all;
145    exception
146       when others =>
147          SSL.Unlock_Task.all;
148          raise;
149    end Deallocate;
150
151    ----------------
152    -- Initialize --
153    ----------------
154
155    procedure Initialize  (Pool : in out Stack_Bounded_Pool) is
156
157       --  Define the appropriate alignment for allocations. This is the
158       --  maximum of the requested alignment, and the alignment required
159       --  for Storage_Count values. The latter test is to ensure that we
160       --  can properly reference the linked list pointers for free lists.
161
162       Align : constant SSE.Storage_Count :=
163                 SSE.Storage_Count'Max
164                   (SSE.Storage_Count'Alignment, Pool.Alignment);
165
166    begin
167       if Pool.Elmt_Size = 0 then
168          Vsize.Initialize (Pool);
169
170       else
171          Pool.First_Free := 0;
172          Pool.First_Empty := 1;
173
174          --  Compute the size to allocate given the size of the element and
175          --  the possible alignment requirement as defined above.
176
177          Pool.Aligned_Elmt_Size :=
178            SSE.Storage_Count'Max (SC_Size,
179              ((Pool.Elmt_Size + Align - 1) / Align) * Align);
180       end if;
181    end Initialize;
182
183    ------------------
184    -- Storage_Size --
185    ------------------
186
187    function  Storage_Size
188      (Pool : Stack_Bounded_Pool) return SSE.Storage_Count
189    is
190    begin
191       return Pool.Pool_Size;
192    end Storage_Size;
193
194    ------------------------------
195    -- Variable_Size_Management --
196    ------------------------------
197
198    package body Variable_Size_Management is
199
200       Minimum_Size : constant := 2 * SC_Size;
201
202       procedure Set_Size
203         (Pool        : Stack_Bounded_Pool;
204          Chunk, Size : SSE.Storage_Count);
205       --  Update the field 'size' of a chunk of available storage
206
207       procedure Set_Next
208         (Pool        : Stack_Bounded_Pool;
209          Chunk, Next : SSE.Storage_Count);
210       --  Update the field 'next' of a chunk of available storage
211
212       function Size
213         (Pool  : Stack_Bounded_Pool;
214          Chunk : SSE.Storage_Count) return SSE.Storage_Count;
215       --  Fetch the field 'size' of a chunk of available storage
216
217       function Next
218         (Pool  : Stack_Bounded_Pool;
219          Chunk : SSE.Storage_Count) return SSE.Storage_Count;
220       --  Fetch the field 'next' of a chunk of available storage
221
222       function Chunk_Of
223         (Pool : Stack_Bounded_Pool;
224          Addr : System.Address) return SSE.Storage_Count;
225       --  Give the chunk number in the pool from its Address
226
227       --------------
228       -- Allocate --
229       --------------
230
231       procedure Allocate
232         (Pool         : in out Stack_Bounded_Pool;
233          Address      : out System.Address;
234          Storage_Size : SSE.Storage_Count;
235          Alignment    : SSE.Storage_Count)
236       is
237          Chunk      : SSE.Storage_Count;
238          New_Chunk  : SSE.Storage_Count;
239          Prev_Chunk : SSE.Storage_Count;
240          Our_Align  : constant SSE.Storage_Count :=
241                         SSE.Storage_Count'Max (SSE.Storage_Count'Alignment,
242                                                Alignment);
243          Align_Size : constant SSE.Storage_Count :=
244                         SSE.Storage_Count'Max (
245                           Minimum_Size,
246                           ((Storage_Size + Our_Align - 1) / Our_Align) *
247                                                                   Our_Align);
248
249       begin
250          --  Look for the first big enough chunk
251
252          Prev_Chunk := Pool.First_Free;
253          Chunk := Next (Pool, Prev_Chunk);
254
255          while Chunk /= 0 and then Size (Pool, Chunk) < Align_Size loop
256             Prev_Chunk := Chunk;
257             Chunk := Next (Pool, Chunk);
258          end loop;
259
260          --  Raise storage_error if no big enough chunk available
261
262          if Chunk = 0 then
263             raise Storage_Error;
264          end if;
265
266          --  When the chunk is bigger than what is needed, take appropraite
267          --  amount and build a new shrinked chunk with the remainder.
268
269          if Size (Pool, Chunk) - Align_Size  > Minimum_Size then
270             New_Chunk := Chunk + Align_Size;
271             Set_Size (Pool, New_Chunk, Size (Pool, Chunk) - Align_Size);
272             Set_Next (Pool, New_Chunk, Next (Pool, Chunk));
273             Set_Next (Pool, Prev_Chunk, New_Chunk);
274
275          --  If the chunk is the right size, just delete it from the chain
276
277          else
278             Set_Next (Pool, Prev_Chunk, Next (Pool, Chunk));
279          end if;
280
281          Address := Pool.The_Pool (Chunk)'Address;
282       end Allocate;
283
284       --------------
285       -- Chunk_Of --
286       --------------
287
288       function Chunk_Of
289         (Pool : Stack_Bounded_Pool;
290          Addr : System.Address) return SSE.Storage_Count
291       is
292       begin
293          return 1 + abs (Addr - Pool.The_Pool (1)'Address);
294       end Chunk_Of;
295
296       ----------------
297       -- Deallocate --
298       ----------------
299
300       procedure Deallocate
301         (Pool         : in out Stack_Bounded_Pool;
302          Address      : System.Address;
303          Storage_Size : SSE.Storage_Count;
304          Alignment    : SSE.Storage_Count)
305       is
306          Align_Size : constant SSE.Storage_Count :=
307                         ((Storage_Size + Alignment - 1) / Alignment) *
308                                                                  Alignment;
309          Chunk : constant SSE.Storage_Count := Chunk_Of (Pool, Address);
310
311       begin
312          --  Attach the freed chunk to the chain
313
314          Set_Size (Pool, Chunk,
315                          SSE.Storage_Count'Max (Align_Size, Minimum_Size));
316          Set_Next (Pool, Chunk, Next (Pool, Pool.First_Free));
317          Set_Next (Pool, Pool.First_Free,  Chunk);
318
319       end Deallocate;
320
321       ----------------
322       -- Initialize --
323       ----------------
324
325       procedure Initialize  (Pool : in out Stack_Bounded_Pool) is
326       begin
327          Pool.First_Free := 1;
328
329          if Pool.Pool_Size > Minimum_Size then
330             Set_Next (Pool, Pool.First_Free, Pool.First_Free + Minimum_Size);
331             Set_Size (Pool, Pool.First_Free, 0);
332             Set_Size (Pool, Pool.First_Free + Minimum_Size,
333                                               Pool.Pool_Size - Minimum_Size);
334             Set_Next (Pool, Pool.First_Free + Minimum_Size, 0);
335          end if;
336       end Initialize;
337
338       ----------
339       -- Next --
340       ----------
341
342       function Next
343         (Pool  : Stack_Bounded_Pool;
344          Chunk : SSE.Storage_Count) return SSE.Storage_Count
345       is
346       begin
347          pragma Warnings (Off);
348          --  Kill alignment warnings, we are careful to make sure
349          --  that the alignment is correct.
350
351          return To_Storage_Count_Access
352                   (Pool.The_Pool (Chunk + SC_Size)'Address).all;
353
354          pragma Warnings (On);
355       end Next;
356
357       --------------
358       -- Set_Next --
359       --------------
360
361       procedure Set_Next
362         (Pool        : Stack_Bounded_Pool;
363          Chunk, Next : SSE.Storage_Count)
364       is
365       begin
366          pragma Warnings (Off);
367          --  Kill alignment warnings, we are careful to make sure
368          --  that the alignment is correct.
369
370          To_Storage_Count_Access
371            (Pool.The_Pool (Chunk + SC_Size)'Address).all := Next;
372
373          pragma Warnings (On);
374       end Set_Next;
375
376       --------------
377       -- Set_Size --
378       --------------
379
380       procedure Set_Size
381         (Pool        : Stack_Bounded_Pool;
382          Chunk, Size : SSE.Storage_Count)
383       is
384       begin
385          pragma Warnings (Off);
386          --  Kill alignment warnings, we are careful to make sure
387          --  that the alignment is correct.
388
389          To_Storage_Count_Access
390            (Pool.The_Pool (Chunk)'Address).all := Size;
391
392          pragma Warnings (On);
393       end Set_Size;
394
395       ----------
396       -- Size --
397       ----------
398
399       function Size
400         (Pool  : Stack_Bounded_Pool;
401          Chunk : SSE.Storage_Count) return SSE.Storage_Count
402       is
403       begin
404          pragma Warnings (Off);
405          --  Kill alignment warnings, we are careful to make sure
406          --  that the alignment is correct.
407
408          return To_Storage_Count_Access (Pool.The_Pool (Chunk)'Address).all;
409
410          pragma Warnings (On);
411       end Size;
412
413    end  Variable_Size_Management;
414 end System.Pool_Size;