OSDN Git Service

2011-10-16 Tristan Gingold <gingold@adacore.com>
[pf3gnuchains/gcc-fork.git] / gcc / ada / s-poosiz.adb
index ad6f759..c2dd03b 100644 (file)
@@ -6,49 +6,58 @@
 --                                                                          --
 --                                 B o d y                                  --
 --                                                                          --
---          Copyright (C) 1992-2001 Free Software Foundation, Inc.          --
+--          Copyright (C) 1992-2009, Free Software Foundation, Inc.         --
 --                                                                          --
 -- GNAT is free software;  you can  redistribute it  and/or modify it under --
 -- terms of the  GNU General Public License as published  by the Free Soft- --
--- ware  Foundation;  either version 2,  or (at your option) any later ver- --
+-- ware  Foundation;  either version 3,  or (at your option) any later ver- --
 -- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
 -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
--- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
--- for  more details.  You should have  received  a copy of the GNU General --
--- Public License  distributed with GNAT;  see file COPYING.  If not, write --
--- to  the Free Software Foundation,  59 Temple Place - Suite 330,  Boston, --
--- MA 02111-1307, USA.                                                      --
+-- or FITNESS FOR A PARTICULAR PURPOSE.                                     --
 --                                                                          --
--- As a special exception,  if other files  instantiate  generics from this --
--- unit, or you link  this unit with other files  to produce an executable, --
--- this  unit  does not  by itself cause  the resulting  executable  to  be --
--- covered  by the  GNU  General  Public  License.  This exception does not --
--- however invalidate  any other reasons why  the executable file  might be --
--- covered by the  GNU Public License.                                      --
+-- As a special exception under Section 7 of GPL version 3, you are granted --
+-- additional permissions described in the GCC Runtime Library Exception,   --
+-- version 3.1, as published by the Free Software Foundation.               --
+--                                                                          --
+-- You should have received a copy of the GNU General Public License and    --
+-- a copy of the GCC Runtime Library Exception along with this program;     --
+-- see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see    --
+-- <http://www.gnu.org/licenses/>.                                          --
 --                                                                          --
 -- GNAT was originally developed  by the GNAT team at  New York University. --
 -- Extensive contributions were provided by Ada Core Technologies Inc.      --
 --                                                                          --
 ------------------------------------------------------------------------------
 
-with System.Storage_Elements;
-with System.Address_To_Access_Conversions;
+with System.Soft_Links;
+
+with Ada.Unchecked_Conversion;
 
 package body System.Pool_Size is
 
    package SSE renames System.Storage_Elements;
    use type SSE.Storage_Offset;
 
-   package SC is new Address_To_Access_Conversions (SSE.Storage_Count);
+   --  Even though these storage pools are typically only used by a single
+   --  task, if multiple tasks are declared at the same or a more nested scope
+   --  as the storage pool, there still may be concurrent access. The current
+   --  implementation of Stack_Bounded_Pool always uses a global lock for
+   --  protecting access. This should eventually be replaced by an atomic
+   --  linked list implementation for efficiency reasons.
+
+   package SSL renames System.Soft_Links;
 
-   SC_Size : constant
-     :=  SSE.Storage_Count'Object_Size / System.Storage_Unit;
+   type Storage_Count_Access is access SSE.Storage_Count;
+   function To_Storage_Count_Access is
+     new Ada.Unchecked_Conversion (Address, Storage_Count_Access);
+
+   SC_Size : constant :=  SSE.Storage_Count'Object_Size / System.Storage_Unit;
 
    package Variable_Size_Management is
 
-      --  Embedded pool that manages allocation of variable-size data.
+      --  Embedded pool that manages allocation of variable-size data
 
-      --  This pool is used as soon as the Elmt_sizS of the pool object is 0.
+      --  This pool is used as soon as the Elmt_Size of the pool object is 0
 
       --  Allocation is done on the first chunk long enough for the request.
       --  Deallocation just puts the freed chunk at the beginning of the list.
@@ -80,12 +89,14 @@ package body System.Pool_Size is
       Alignment    : SSE.Storage_Count)
    is
    begin
+      SSL.Lock_Task.all;
+
       if Pool.Elmt_Size = 0 then
          Vsize.Allocate (Pool, Address, Storage_Size, Alignment);
 
       elsif Pool.First_Free /= 0 then
          Address := Pool.The_Pool (Pool.First_Free)'Address;
-         Pool.First_Free := SC.To_Pointer (Address).all;
+         Pool.First_Free := To_Storage_Count_Access (Address).all;
 
       elsif
         Pool.First_Empty <= (Pool.Pool_Size - Pool.Aligned_Elmt_Size + 1)
@@ -96,6 +107,13 @@ package body System.Pool_Size is
       else
          raise Storage_Error;
       end if;
+
+      SSL.Unlock_Task.all;
+
+   exception
+      when others =>
+         SSL.Unlock_Task.all;
+         raise;
    end Allocate;
 
    ----------------
@@ -109,13 +127,21 @@ package body System.Pool_Size is
       Alignment    : SSE.Storage_Count)
    is
    begin
+      SSL.Lock_Task.all;
+
       if Pool.Elmt_Size = 0 then
          Vsize.Deallocate (Pool, Address, Storage_Size, Alignment);
 
       else
-         SC.To_Pointer (Address).all := Pool.First_Free;
+         To_Storage_Count_Access (Address).all := Pool.First_Free;
          Pool.First_Free := Address - Pool.The_Pool'Address + 1;
       end if;
+
+      SSL.Unlock_Task.all;
+   exception
+      when others =>
+         SSL.Unlock_Task.all;
+         raise;
    end Deallocate;
 
    ----------------
@@ -123,8 +149,15 @@ package body System.Pool_Size is
    ----------------
 
    procedure Initialize  (Pool : in out Stack_Bounded_Pool) is
+
+      --  Define the appropriate alignment for allocations. This is the
+      --  maximum of the requested alignment, and the alignment required
+      --  for Storage_Count values. The latter test is to ensure that we
+      --  can properly reference the linked list pointers for free lists.
+
       Align : constant SSE.Storage_Count :=
-        SSE.Storage_Count'Max (SSE.Storage_Count'Alignment, Pool.Alignment);
+                SSE.Storage_Count'Max
+                  (SSE.Storage_Count'Alignment, Pool.Alignment);
 
    begin
       if Pool.Elmt_Size = 0 then
@@ -135,7 +168,7 @@ package body System.Pool_Size is
          Pool.First_Empty := 1;
 
          --  Compute the size to allocate given the size of the element and
-         --  the possible Alignment clause
+         --  the possible alignment requirement as defined above.
 
          Pool.Aligned_Elmt_Size :=
            SSE.Storage_Count'Max (SC_Size,
@@ -148,8 +181,7 @@ package body System.Pool_Size is
    ------------------
 
    function  Storage_Size
-     (Pool : Stack_Bounded_Pool)
-      return SSE.Storage_Count
+     (Pool : Stack_Bounded_Pool) return SSE.Storage_Count
    is
    begin
       return Pool.Pool_Size;
@@ -175,20 +207,17 @@ package body System.Pool_Size is
 
       function Size
         (Pool  : Stack_Bounded_Pool;
-         Chunk : SSE.Storage_Count)
-         return SSE.Storage_Count;
+         Chunk : SSE.Storage_Count) return SSE.Storage_Count;
       --  Fetch the field 'size' of a chunk of available storage
 
       function Next
         (Pool  : Stack_Bounded_Pool;
-         Chunk : SSE.Storage_Count)
-         return  SSE.Storage_Count;
+         Chunk : SSE.Storage_Count) return SSE.Storage_Count;
       --  Fetch the field 'next' of a chunk of available storage
 
       function Chunk_Of
         (Pool : Stack_Bounded_Pool;
-         Addr : System.Address)
-         return SSE.Storage_Count;
+         Addr : System.Address) return SSE.Storage_Count;
       --  Give the chunk number in the pool from its Address
 
       --------------
@@ -230,7 +259,7 @@ package body System.Pool_Size is
             raise Storage_Error;
          end if;
 
-         --  When the chunk is bigger than what is needed, take appropraite
+         --  When the chunk is bigger than what is needed, take appropriate
          --  amount and build a new shrinked chunk with the remainder.
 
          if Size (Pool, Chunk) - Align_Size  > Minimum_Size then
@@ -254,8 +283,7 @@ package body System.Pool_Size is
 
       function Chunk_Of
         (Pool : Stack_Bounded_Pool;
-         Addr : System.Address)
-         return SSE.Storage_Count
+         Addr : System.Address) return SSE.Storage_Count
       is
       begin
          return 1 + abs (Addr - Pool.The_Pool (1)'Address);
@@ -271,10 +299,12 @@ package body System.Pool_Size is
          Storage_Size : SSE.Storage_Count;
          Alignment    : SSE.Storage_Count)
       is
+         pragma Warnings (Off, Pool);
+
          Align_Size : constant SSE.Storage_Count :=
                         ((Storage_Size + Alignment - 1) / Alignment) *
                                                                  Alignment;
-         Chunk : SSE.Storage_Count := Chunk_Of (Pool, Address);
+         Chunk : constant SSE.Storage_Count := Chunk_Of (Pool, Address);
 
       begin
          --  Attach the freed chunk to the chain
@@ -309,11 +339,17 @@ package body System.Pool_Size is
 
       function Next
         (Pool  : Stack_Bounded_Pool;
-         Chunk : SSE.Storage_Count)
-         return  SSE.Storage_Count
+         Chunk : SSE.Storage_Count) return SSE.Storage_Count
       is
       begin
-         return SC.To_Pointer (Pool.The_Pool (Chunk + SC_Size)'Address).all;
+         pragma Warnings (Off);
+         --  Kill alignment warnings, we are careful to make sure
+         --  that the alignment is correct.
+
+         return To_Storage_Count_Access
+                  (Pool.The_Pool (Chunk + SC_Size)'Address).all;
+
+         pragma Warnings (On);
       end Next;
 
       --------------
@@ -325,7 +361,14 @@ package body System.Pool_Size is
          Chunk, Next : SSE.Storage_Count)
       is
       begin
-         SC.To_Pointer (Pool.The_Pool (Chunk + SC_Size)'Address).all := Next;
+         pragma Warnings (Off);
+         --  Kill alignment warnings, we are careful to make sure
+         --  that the alignment is correct.
+
+         To_Storage_Count_Access
+           (Pool.The_Pool (Chunk + SC_Size)'Address).all := Next;
+
+         pragma Warnings (On);
       end Set_Next;
 
       --------------
@@ -337,7 +380,14 @@ package body System.Pool_Size is
          Chunk, Size : SSE.Storage_Count)
       is
       begin
-         SC.To_Pointer (Pool.The_Pool (Chunk)'Address).all := Size;
+         pragma Warnings (Off);
+         --  Kill alignment warnings, we are careful to make sure
+         --  that the alignment is correct.
+
+         To_Storage_Count_Access
+           (Pool.The_Pool (Chunk)'Address).all := Size;
+
+         pragma Warnings (On);
       end Set_Size;
 
       ----------
@@ -346,11 +396,16 @@ package body System.Pool_Size is
 
       function Size
         (Pool  : Stack_Bounded_Pool;
-         Chunk : SSE.Storage_Count)
-         return  SSE.Storage_Count
+         Chunk : SSE.Storage_Count) return SSE.Storage_Count
       is
       begin
-         return  SC.To_Pointer (Pool.The_Pool (Chunk)'Address).all;
+         pragma Warnings (Off);
+         --  Kill alignment warnings, we are careful to make sure
+         --  that the alignment is correct.
+
+         return To_Storage_Count_Access (Pool.The_Pool (Chunk)'Address).all;
+
+         pragma Warnings (On);
       end Size;
 
    end  Variable_Size_Management;