File : s-taprob.adb


   1 ------------------------------------------------------------------------------
   2 --                                                                          --
   3 --                 GNAT RUN-TIME LIBRARY (GNARL) COMPONENTS                 --
   4 --                                                                          --
   5 --      S Y S T E M . T A S K I N G . P R O T E C T E D _ O B J E C T S     --
   6 --                                                                          --
   7 --                                  B o d y                                 --
   8 --                                                                          --
   9 --            Copyright (C) 1991-1994, Florida State University             --
  10 --                     Copyright (C) 1995-2014, AdaCore                     --
  11 --                                                                          --
  12 -- GNAT is free software;  you can  redistribute it  and/or modify it under --
  13 -- terms of the  GNU General Public License as published  by the Free Soft- --
  14 -- ware  Foundation;  either version 3,  or (at your option) any later ver- --
  15 -- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
  16 -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
  17 -- or FITNESS FOR A PARTICULAR PURPOSE.                                     --
  18 --                                                                          --
  19 --                                                                          --
  20 --                                                                          --
  21 --                                                                          --
  22 --                                                                          --
  23 -- You should have received a copy of the GNU General Public License and    --
  24 -- a copy of the GCC Runtime Library Exception along with this program;     --
  25 -- see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see    --
  26 -- <http://www.gnu.org/licenses/>.                                          --
  27 --                                                                          --
  28 -- GNARL was developed by the GNARL team at Florida State University.       --
  29 -- Extensive contributions were provided by Ada Core Technologies, Inc.     --
  30 --                                                                          --
  31 ------------------------------------------------------------------------------
  32 
  33 pragma Polling (Off);
  34 --  Turn off polling, we do not want ATC polling to take place during tasking
  35 --  operations. It causes infinite loops and other problems.
  36 
  37 with System.Task_Primitives.Operations;
  38 with System.Parameters;
  39 with System.Traces;
  40 with System.Soft_Links.Tasking;
  41 
  42 with System.Secondary_Stack;
  43 pragma Elaborate_All (System.Secondary_Stack);
  44 pragma Unreferenced (System.Secondary_Stack);
  45 --  Make sure the body of Secondary_Stack is elaborated before calling
  46 --  Init_Tasking_Soft_Links. See comments for this routine for explanation.
  47 
  48 package body System.Tasking.Protected_Objects is
  49 
  50    use System.Task_Primitives.Operations;
  51    use System.Traces;
  52 
  53    ----------------
  54    -- Local Data --
  55    ----------------
  56 
  57    Locking_Policy : Character;
  58    pragma Import (C, Locking_Policy, "__gl_locking_policy");
  59 
  60    -------------------------
  61    -- Finalize_Protection --
  62    -------------------------
  63 
  64    procedure Finalize_Protection (Object : in out Protection) is
  65    begin
  66       Finalize_Lock (Object.L'Unrestricted_Access);
  67    end Finalize_Protection;
  68 
  69    ---------------------------
  70    -- Initialize_Protection --
  71    ---------------------------
  72 
  73    procedure Initialize_Protection
  74      (Object           : Protection_Access;
  75       Ceiling_Priority : Integer)
  76    is
  77       Init_Priority : Integer := Ceiling_Priority;
  78 
  79    begin
  80       if Init_Priority = Unspecified_Priority then
  81          Init_Priority  := System.Priority'Last;
  82       end if;
  83 
  84       Initialize_Lock (Init_Priority, Object.L'Access);
  85       Object.Ceiling := System.Any_Priority (Init_Priority);
  86       Object.New_Ceiling := System.Any_Priority (Init_Priority);
  87       Object.Owner := Null_Task;
  88    end Initialize_Protection;
  89 
  90    -----------------
  91    -- Get_Ceiling --
  92    -----------------
  93 
  94    function Get_Ceiling
  95      (Object : Protection_Access) return System.Any_Priority is
  96    begin
  97       return Object.New_Ceiling;
  98    end Get_Ceiling;
  99 
 100    ----------
 101    -- Lock --
 102    ----------
 103 
 104    procedure Lock (Object : Protection_Access) is
 105       Ceiling_Violation : Boolean;
 106 
 107    begin
 108       --  The lock is made without deferring abort
 109 
 110       --  Therefore the abort has to be deferred before calling this routine.
 111       --  This means that the compiler has to generate a Defer_Abort call
 112       --  before the call to Lock.
 113 
 114       --  The caller is responsible for undeferring abort, and compiler
 115       --  generated calls must be protected with cleanup handlers to ensure
 116       --  that abort is undeferred in all cases.
 117 
 118       --  If pragma Detect_Blocking is active then, as described in the ARM
 119       --  9.5.1, par. 15, we must check whether this is an external call on a
 120       --  protected subprogram with the same target object as that of the
 121       --  protected action that is currently in progress (i.e., if the caller
 122       --  is already the protected object's owner). If this is the case hence
 123       --  Program_Error must be raised.
 124 
 125       if Detect_Blocking and then Object.Owner = Self then
 126          raise Program_Error;
 127       end if;
 128 
 129       Write_Lock (Object.L'Access, Ceiling_Violation);
 130 
 131       if Parameters.Runtime_Traces then
 132          Send_Trace_Info (PO_Lock);
 133       end if;
 134 
 135       if Ceiling_Violation then
 136          raise Program_Error;
 137       end if;
 138 
 139       --  We are entering in a protected action, so that we increase the
 140       --  protected object nesting level (if pragma Detect_Blocking is
 141       --  active), and update the protected object's owner.
 142 
 143       if Detect_Blocking then
 144          declare
 145             Self_Id : constant Task_Id := Self;
 146          begin
 147             --  Update the protected object's owner
 148 
 149             Object.Owner := Self_Id;
 150 
 151             --  Increase protected object nesting level
 152 
 153             Self_Id.Common.Protected_Action_Nesting :=
 154               Self_Id.Common.Protected_Action_Nesting + 1;
 155          end;
 156       end if;
 157    end Lock;
 158 
 159    --------------------
 160    -- Lock_Read_Only --
 161    --------------------
 162 
 163    procedure Lock_Read_Only (Object : Protection_Access) is
 164       Ceiling_Violation : Boolean;
 165 
 166    begin
 167       --  If pragma Detect_Blocking is active then, as described in the ARM
 168       --  9.5.1, par. 15, we must check whether this is an external call on
 169       --  protected subprogram with the same target object as that of the
 170       --  protected action that is currently in progress (i.e., if the caller
 171       --  is already the protected object's owner). If this is the case hence
 172       --  Program_Error must be raised.
 173       --
 174       --  Note that in this case (getting read access), several tasks may have
 175       --  read ownership of the protected object, so that this method of
 176       --  storing the (single) protected object's owner does not work reliably
 177       --  for read locks. However, this is the approach taken for two major
 178       --  reasons: first, this function is not currently being used (it is
 179       --  provided for possible future use), and second, it largely simplifies
 180       --  the implementation.
 181 
 182       if Detect_Blocking and then Object.Owner = Self then
 183          raise Program_Error;
 184       end if;
 185 
 186       Read_Lock (Object.L'Access, Ceiling_Violation);
 187 
 188       if Parameters.Runtime_Traces then
 189          Send_Trace_Info (PO_Lock);
 190       end if;
 191 
 192       if Ceiling_Violation then
 193          raise Program_Error;
 194       end if;
 195 
 196       --  We are entering in a protected action, so we increase the protected
 197       --  object nesting level (if pragma Detect_Blocking is active).
 198 
 199       if Detect_Blocking then
 200          declare
 201             Self_Id : constant Task_Id := Self;
 202          begin
 203             --  Update the protected object's owner
 204 
 205             Object.Owner := Self_Id;
 206 
 207             --  Increase protected object nesting level
 208 
 209             Self_Id.Common.Protected_Action_Nesting :=
 210               Self_Id.Common.Protected_Action_Nesting + 1;
 211          end;
 212       end if;
 213    end Lock_Read_Only;
 214 
 215    -----------------
 216    -- Set_Ceiling --
 217    -----------------
 218 
 219    procedure Set_Ceiling
 220      (Object : Protection_Access;
 221       Prio   : System.Any_Priority) is
 222    begin
 223       Object.New_Ceiling := Prio;
 224    end Set_Ceiling;
 225 
 226    ------------
 227    -- Unlock --
 228    ------------
 229 
 230    procedure Unlock (Object : Protection_Access) is
 231    begin
 232       --  We are exiting from a protected action, so that we decrease the
 233       --  protected object nesting level (if pragma Detect_Blocking is
 234       --  active), and remove ownership of the protected object.
 235 
 236       if Detect_Blocking then
 237          declare
 238             Self_Id : constant Task_Id := Self;
 239 
 240          begin
 241             --  Calls to this procedure can only take place when being within
 242             --  a protected action and when the caller is the protected
 243             --  object's owner.
 244 
 245             pragma Assert (Self_Id.Common.Protected_Action_Nesting > 0
 246                              and then Object.Owner = Self_Id);
 247 
 248             --  Remove ownership of the protected object
 249 
 250             Object.Owner := Null_Task;
 251 
 252             --  We are exiting from a protected action, so we decrease the
 253             --  protected object nesting level.
 254 
 255             Self_Id.Common.Protected_Action_Nesting :=
 256               Self_Id.Common.Protected_Action_Nesting - 1;
 257          end;
 258       end if;
 259 
 260       --  Before releasing the mutex we must actually update its ceiling
 261       --  priority if it has been changed.
 262 
 263       if Object.New_Ceiling /= Object.Ceiling then
 264          if Locking_Policy = 'C' then
 265             System.Task_Primitives.Operations.Set_Ceiling
 266               (Object.L'Access, Object.New_Ceiling);
 267          end if;
 268 
 269          Object.Ceiling := Object.New_Ceiling;
 270       end if;
 271 
 272       Unlock (Object.L'Access);
 273 
 274       if Parameters.Runtime_Traces then
 275          Send_Trace_Info (PO_Unlock);
 276       end if;
 277    end Unlock;
 278 
 279 begin
 280    --  Ensure that tasking is initialized, as well as tasking soft links
 281    --  when using protected objects.
 282 
 283    Tasking.Initialize;
 284    System.Soft_Links.Tasking.Init_Tasking_Soft_Links;
 285 end System.Tasking.Protected_Objects;