OSDN Git Service

* c-decl.c (grokfield): Allow typedefs for anonymous structs and
[pf3gnuchains/gcc-fork.git] / gcc / ada / s-tpoben.adb
index 8e90a9d..4694310 100644 (file)
@@ -1,68 +1,55 @@
 ------------------------------------------------------------------------------
 --                                                                          --
---               GNU ADA RUN-TIME LIBRARY (GNARL) COMPONENTS                --
+--                GNAT RUN-TIME LIBRARY (GNARL) COMPONENTS                  --
 --                                                                          --
---                 SYSTEM.TASKING.PROTECTED_OBJECTS.ENTRIES                 --
+--                SYSTEM.TASKING.PROTECTED_OBJECTS.ENTRIES                  --
 --                                                                          --
---                                  B o d y                                 --
+--                               B o d y                                    --
 --                                                                          --
---         Copyright (C) 1998-2001, Free Software Foundation, Inc.          --
+--          Copyright (C) 1998-2010, Free Software Foundation, Inc.         --
 --                                                                          --
 -- GNARL 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- --
--- sion. GNARL is distributed in the hope that it will be useful, but WITH- --
+-- 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 GNARL; 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.               --
 --                                                                          --
--- GNARL was developed by the GNARL team at Florida State University. It is --
--- now maintained by Ada Core Technologies, Inc. (http://www.gnat.com).     --
+-- 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/>.                                          --
+--                                                                          --
+-- GNARL was developed by the GNARL team at Florida State University.       --
+-- Extensive contributions were provided by Ada Core Technologies, Inc.     --
 --                                                                          --
 ------------------------------------------------------------------------------
 
---  This package contains all the simple primitives related to
---  Protected_Objects with entries (i.e init, lock, unlock).
+--  This package contains all the simple primitives related to protected
+--  objects with entries (i.e init, lock, unlock).
 
 --  The handling of protected objects with no entries is done in
 --  System.Tasking.Protected_Objects, the complex routines for protected
 --  objects with entries in System.Tasking.Protected_Objects.Operations.
+
 --  The split between Entries and Operations is needed to break circular
 --  dependencies inside the run time.
 
---  Note: the compiler generates direct calls to this interface, via Rtsfind.
+--  Note: the compiler generates direct calls to this interface, via Rtsfind
 
-with Ada.Exceptions;
---  used for Exception_Occurrence_Access
+with Ada.Unchecked_Deallocation;
 
 with System.Task_Primitives.Operations;
---  used for Initialize_Lock
---           Write_Lock
---           Unlock
---           Get_Priority
---           Wakeup
+with System.Restrictions;
+with System.Parameters;
 
 with System.Tasking.Initialization;
---  used for Defer_Abort,
---           Undefer_Abort,
---           Change_Base_Priority
-
 pragma Elaborate_All (System.Tasking.Initialization);
---  this insures that tasking is initialized if any protected objects are
---  created.
-
-with System.Parameters;
---  used for Single_Lock
+--  To insure that tasking is initialized if any protected objects are created
 
 package body System.Tasking.Protected_Objects.Entries is
 
@@ -70,7 +57,17 @@ package body System.Tasking.Protected_Objects.Entries is
 
    use Parameters;
    use Task_Primitives.Operations;
-   use Ada.Exceptions;
+
+   -----------------------
+   -- Local Subprograms --
+   -----------------------
+
+   procedure Free_Entry_Names (Object : Protection_Entries);
+   --  Deallocate all string names associated with protected entries
+
+   ----------------
+   -- Local Data --
+   ----------------
 
    Locking_Policy : Character;
    pragma Import (C, Locking_Policy, "__gl_locking_policy");
@@ -79,11 +76,11 @@ package body System.Tasking.Protected_Objects.Entries is
    -- Finalize --
    --------------
 
-   procedure Finalize (Object : in out Protection_Entries) is
+   overriding procedure Finalize (Object : in out Protection_Entries) is
       Entry_Call        : Entry_Call_Link;
-      Caller            : Task_ID;
+      Caller            : Task_Id;
       Ceiling_Violation : Boolean;
-      Self_ID           : constant Task_ID := STPO.Self;
+      Self_ID           : constant Task_Id := STPO.Self;
       Old_Base_Priority : System.Any_Priority;
 
    begin
@@ -98,8 +95,9 @@ package body System.Tasking.Protected_Objects.Entries is
       end if;
 
       if Ceiling_Violation then
-         --  Dip our own priority down to ceiling of lock.
-         --  See similar code in Tasking.Entry_Calls.Lock_Server.
+
+         --  Dip our own priority down to ceiling of lock. See similar code in
+         --  Tasking.Entry_Calls.Lock_Server.
 
          STPO.Write_Lock (Self_ID);
          Old_Base_Priority := Self_ID.Common.Base_Priority;
@@ -114,7 +112,7 @@ package body System.Tasking.Protected_Objects.Entries is
          STPO.Write_Lock (Object.L'Unrestricted_Access, Ceiling_Violation);
 
          if Ceiling_Violation then
-            Raise_Exception (Program_Error'Identity, "Ceiling Violation");
+            raise Program_Error with "Ceiling Violation";
          end if;
 
          if Single_Lock then
@@ -125,7 +123,7 @@ package body System.Tasking.Protected_Objects.Entries is
          Object.Pending_Action := True;
       end if;
 
-      --  Send program_error to all tasks still queued on this object.
+      --  Send program_error to all tasks still queued on this object
 
       for E in Object.Entry_Queues'Range loop
          Entry_Call := Object.Entry_Queues (E).Head;
@@ -143,6 +141,8 @@ package body System.Tasking.Protected_Objects.Entries is
          end loop;
       end loop;
 
+      Free_Entry_Names (Object);
+
       Object.Finalized := True;
 
       if Single_Lock then
@@ -154,6 +154,36 @@ package body System.Tasking.Protected_Objects.Entries is
       STPO.Finalize_Lock (Object.L'Unrestricted_Access);
    end Finalize;
 
+   ----------------------
+   -- Free_Entry_Names --
+   ----------------------
+
+   procedure Free_Entry_Names (Object : Protection_Entries) is
+      Names : Entry_Names_Array_Access := Object.Entry_Names;
+
+      procedure Free_Entry_Names_Array_Access is new
+        Ada.Unchecked_Deallocation
+          (Entry_Names_Array, Entry_Names_Array_Access);
+
+   begin
+      if Names = null then
+         return;
+      end if;
+
+      Free_Entry_Names_Array (Names.all);
+      Free_Entry_Names_Array_Access (Names);
+   end Free_Entry_Names;
+
+   -----------------
+   -- Get_Ceiling --
+   -----------------
+
+   function Get_Ceiling
+     (Object : Protection_Entries_Access) return System.Any_Priority is
+   begin
+      return Object.New_Ceiling;
+   end Get_Ceiling;
+
    -------------------------------------
    -- Has_Interrupt_Or_Attach_Handler --
    -------------------------------------
@@ -176,14 +206,15 @@ package body System.Tasking.Protected_Objects.Entries is
       Ceiling_Priority  : Integer;
       Compiler_Info     : System.Address;
       Entry_Bodies      : Protected_Entry_Body_Access;
-      Find_Body_Index   : Find_Body_Index_Access)
+      Find_Body_Index   : Find_Body_Index_Access;
+      Build_Entry_Names : Boolean)
    is
       Init_Priority : Integer := Ceiling_Priority;
-      Self_ID       : constant Task_ID := STPO.Self;
+      Self_ID       : constant Task_Id := STPO.Self;
 
    begin
       if Init_Priority = Unspecified_Priority then
-         Init_Priority  := System.Priority'Last;
+         Init_Priority := System.Priority'Last;
       end if;
 
       if Locking_Policy = 'C'
@@ -195,20 +226,35 @@ package body System.Tasking.Protected_Objects.Entries is
          raise Program_Error;
       end if;
 
-      Initialization.Defer_Abort (Self_ID);
+      --  pragma Assert (Self_Id.Deferral_Level = 0);
+      --  If a PO is created from a controlled operation, abort is already
+      --  deferred at this point, so we need to use Defer_Abort_Nestable
+      --  In some cases, the above assertion can be useful to spot
+      --  inconsistencies, outside the above scenario involving controlled
+      --  types.
+
+      Initialization.Defer_Abort_Nestable (Self_ID);
       Initialize_Lock (Init_Priority, Object.L'Access);
-      Initialization.Undefer_Abort (Self_ID);
-      Object.Ceiling := System.Any_Priority (Init_Priority);
-      Object.Compiler_Info := Compiler_Info;
-      Object.Pending_Action := False;
+      Initialization.Undefer_Abort_Nestable (Self_ID);
+
+      Object.Ceiling          := System.Any_Priority (Init_Priority);
+      Object.New_Ceiling      := System.Any_Priority (Init_Priority);
+      Object.Owner            := Null_Task;
+      Object.Compiler_Info    := Compiler_Info;
+      Object.Pending_Action   := False;
       Object.Call_In_Progress := null;
-      Object.Entry_Bodies := Entry_Bodies;
-      Object.Find_Body_Index :=  Find_Body_Index;
+      Object.Entry_Bodies     := Entry_Bodies;
+      Object.Find_Body_Index  := Find_Body_Index;
 
       for E in Object.Entry_Queues'Range loop
          Object.Entry_Queues (E).Head := null;
          Object.Entry_Queues (E).Tail := null;
       end loop;
+
+      if Build_Entry_Names then
+         Object.Entry_Names :=
+           new Entry_Names_Array (1 .. Entry_Index (Object.Num_Entries));
+      end if;
    end Initialize_Protection_Entries;
 
    ------------------
@@ -216,40 +262,71 @@ package body System.Tasking.Protected_Objects.Entries is
    ------------------
 
    procedure Lock_Entries
-     (Object : Protection_Entries_Access; Ceiling_Violation : out Boolean) is
+     (Object            : Protection_Entries_Access;
+      Ceiling_Violation : out Boolean)
+   is
    begin
       if Object.Finalized then
-         Raise_Exception
-           (Program_Error'Identity, "Protected Object is finalized");
+         raise Program_Error with "Protected Object is finalized";
+      end if;
+
+      --  If pragma Detect_Blocking is active then, as described in the ARM
+      --  9.5.1, par. 15, we must check whether this is an external call on a
+      --  protected subprogram with the same target object as that of the
+      --  protected action that is currently in progress (i.e., if the caller
+      --  is already the protected object's owner). If this is the case hence
+      --  Program_Error must be raised.
+
+      if Detect_Blocking and then Object.Owner = Self then
+         raise Program_Error;
       end if;
 
-      --  The lock is made without defering abortion.
+      --  The lock is made without deferring abort
 
-      --  Therefore the abortion has to be deferred before calling this
-      --  routine. This means that the compiler has to generate a Defer_Abort
-      --  call before the call to Lock.
+      --  Therefore the abort has to be deferred before calling this routine.
+      --  This means that the compiler has to generate a Defer_Abort call
+      --  before the call to Lock.
 
-      --  The caller is responsible for undeferring abortion, and compiler
+      --  The caller is responsible for undeferring abort, and compiler
       --  generated calls must be protected with cleanup handlers to ensure
-      --  that abortion is undeferred in all cases.
+      --  that abort is undeferred in all cases.
+
+      pragma Assert
+        (STPO.Self.Deferral_Level > 0
+          or else not Restrictions.Abort_Allowed);
 
-      pragma Assert (STPO.Self.Deferral_Level > 0);
       Write_Lock (Object.L'Access, Ceiling_Violation);
+
+      --  We are entering in a protected action, so that we increase the
+      --  protected object nesting level (if pragma Detect_Blocking is
+      --  active), and update the protected object's owner.
+
+      if Detect_Blocking then
+         declare
+            Self_Id : constant Task_Id := Self;
+
+         begin
+            --  Update the protected object's owner
+
+            Object.Owner := Self_Id;
+
+            --  Increase protected object nesting level
+
+            Self_Id.Common.Protected_Action_Nesting :=
+              Self_Id.Common.Protected_Action_Nesting + 1;
+         end;
+      end if;
+
    end Lock_Entries;
 
    procedure Lock_Entries (Object : Protection_Entries_Access) is
       Ceiling_Violation : Boolean;
-   begin
-      if Object.Finalized then
-         Raise_Exception
-           (Program_Error'Identity, "Protected Object is finalized");
-      end if;
 
-      pragma Assert (STPO.Self.Deferral_Level > 0);
-      Write_Lock (Object.L'Access, Ceiling_Violation);
+   begin
+      Lock_Entries (Object, Ceiling_Violation);
 
       if Ceiling_Violation then
-         Raise_Exception (Program_Error'Identity, "Ceiling Violation");
+         raise Program_Error with "Ceiling Violation";
       end if;
    end Lock_Entries;
 
@@ -259,25 +336,127 @@ package body System.Tasking.Protected_Objects.Entries is
 
    procedure Lock_Read_Only_Entries (Object : Protection_Entries_Access) is
       Ceiling_Violation : Boolean;
+
    begin
       if Object.Finalized then
-         Raise_Exception
-           (Program_Error'Identity, "Protected Object is finalized");
+         raise Program_Error with "Protected Object is finalized";
+      end if;
+
+      --  If pragma Detect_Blocking is active then, as described in the ARM
+      --  9.5.1, par. 15, we must check whether this is an external call on a
+      --  protected subprogram with the same target object as that of the
+      --  protected action that is currently in progress (i.e., if the caller
+      --  is already the protected object's owner). If this is the case hence
+      --  Program_Error must be raised.
+
+      --  Note that in this case (getting read access), several tasks may
+      --  have read ownership of the protected object, so that this method of
+      --  storing the (single) protected object's owner does not work
+      --  reliably for read locks. However, this is the approach taken for two
+      --  major reasons: first, this function is not currently being used (it
+      --  is provided for possible future use), and second, it largely
+      --  simplifies the implementation.
+
+      if Detect_Blocking and then Object.Owner = Self then
+         raise Program_Error;
       end if;
 
       Read_Lock (Object.L'Access, Ceiling_Violation);
 
       if Ceiling_Violation then
-         Raise_Exception (Program_Error'Identity, "Ceiling Violation");
+         raise Program_Error with "Ceiling Violation";
+      end if;
+
+      --  We are entering in a protected action, so that we increase the
+      --  protected object nesting level (if pragma Detect_Blocking is
+      --  active), and update the protected object's owner.
+
+      if Detect_Blocking then
+         declare
+            Self_Id : constant Task_Id := Self;
+
+         begin
+            --  Update the protected object's owner
+
+            Object.Owner := Self_Id;
+
+            --  Increase protected object nesting level
+
+            Self_Id.Common.Protected_Action_Nesting :=
+              Self_Id.Common.Protected_Action_Nesting + 1;
+         end;
       end if;
    end Lock_Read_Only_Entries;
 
+   -----------------
+   -- Set_Ceiling --
+   -----------------
+
+   procedure Set_Ceiling
+     (Object : Protection_Entries_Access;
+      Prio   : System.Any_Priority) is
+   begin
+      Object.New_Ceiling := Prio;
+   end Set_Ceiling;
+
+   --------------------
+   -- Set_Entry_Name --
+   --------------------
+
+   procedure Set_Entry_Name
+     (Object : Protection_Entries'Class;
+      Pos    : Protected_Entry_Index;
+      Val    : String_Access)
+   is
+   begin
+      pragma Assert (Object.Entry_Names /= null);
+
+      Object.Entry_Names (Entry_Index (Pos)) := Val;
+   end Set_Entry_Name;
+
    --------------------
    -- Unlock_Entries --
    --------------------
 
    procedure Unlock_Entries (Object : Protection_Entries_Access) is
    begin
+      --  We are exiting from a protected action, so that we decrease the
+      --  protected object nesting level (if pragma Detect_Blocking is
+      --  active), and remove ownership of the protected object.
+
+      if Detect_Blocking then
+         declare
+            Self_Id : constant Task_Id := Self;
+
+         begin
+            --  Calls to this procedure can only take place when being within
+            --  a protected action and when the caller is the protected
+            --  object's owner.
+
+            pragma Assert (Self_Id.Common.Protected_Action_Nesting > 0
+                             and then Object.Owner = Self_Id);
+
+            --  Remove ownership of the protected object
+
+            Object.Owner := Null_Task;
+
+            Self_Id.Common.Protected_Action_Nesting :=
+              Self_Id.Common.Protected_Action_Nesting - 1;
+         end;
+      end if;
+
+      --  Before releasing the mutex we must actually update its ceiling
+      --  priority if it has been changed.
+
+      if Object.New_Ceiling /= Object.Ceiling then
+         if Locking_Policy = 'C' then
+            System.Task_Primitives.Operations.Set_Ceiling
+              (Object.L'Access, Object.New_Ceiling);
+         end if;
+
+         Object.Ceiling := Object.New_Ceiling;
+      end if;
+
       Unlock (Object.L'Access);
    end Unlock_Entries;