/gcc/ada/libgnarl/s-taprob.adb

https://gitlab.com/adotout/gcc · Ada · 267 lines · 104 code · 57 blank · 106 comment · 10 complexity · 4b44bbfaf2b28f517960c74f544e51bf MD5 · raw file

  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-2017, Florida State University --
  10. -- Copyright (C) 1995-2022, 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. -- As a special exception under Section 7 of GPL version 3, you are granted --
  20. -- additional permissions described in the GCC Runtime Library Exception, --
  21. -- version 3.1, as published by the Free Software Foundation. --
  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. with System.Task_Primitives.Operations;
  33. with System.Soft_Links.Tasking;
  34. with System.Secondary_Stack;
  35. pragma Elaborate_All (System.Secondary_Stack);
  36. pragma Unreferenced (System.Secondary_Stack);
  37. -- Make sure the body of Secondary_Stack is elaborated before calling
  38. -- Init_Tasking_Soft_Links. See comments for this routine for explanation.
  39. package body System.Tasking.Protected_Objects is
  40. use System.Task_Primitives.Operations;
  41. ----------------
  42. -- Local Data --
  43. ----------------
  44. Locking_Policy : constant Character;
  45. pragma Import (C, Locking_Policy, "__gl_locking_policy");
  46. -------------------------
  47. -- Finalize_Protection --
  48. -------------------------
  49. procedure Finalize_Protection (Object : in out Protection) is
  50. begin
  51. Finalize_Lock (Object.L'Unrestricted_Access);
  52. end Finalize_Protection;
  53. ---------------------------
  54. -- Initialize_Protection --
  55. ---------------------------
  56. procedure Initialize_Protection
  57. (Object : Protection_Access;
  58. Ceiling_Priority : Integer)
  59. is
  60. Init_Priority : Integer := Ceiling_Priority;
  61. begin
  62. if Init_Priority = Unspecified_Priority then
  63. Init_Priority := System.Priority'Last;
  64. end if;
  65. Initialize_Lock (Init_Priority, Object.L'Access);
  66. Object.Ceiling := System.Any_Priority (Init_Priority);
  67. Object.New_Ceiling := System.Any_Priority (Init_Priority);
  68. Object.Owner := Null_Task;
  69. end Initialize_Protection;
  70. -----------------
  71. -- Get_Ceiling --
  72. -----------------
  73. function Get_Ceiling
  74. (Object : Protection_Access) return System.Any_Priority is
  75. begin
  76. return Object.New_Ceiling;
  77. end Get_Ceiling;
  78. ----------
  79. -- Lock --
  80. ----------
  81. procedure Lock (Object : Protection_Access) is
  82. Ceiling_Violation : Boolean;
  83. begin
  84. -- The lock is made without deferring abort
  85. -- Therefore the abort has to be deferred before calling this routine.
  86. -- This means that the compiler has to generate a Defer_Abort call
  87. -- before the call to Lock.
  88. -- The caller is responsible for undeferring abort, and compiler
  89. -- generated calls must be protected with cleanup handlers to ensure
  90. -- that abort is undeferred in all cases.
  91. -- If pragma Detect_Blocking is active then, as described in the ARM
  92. -- 9.5.1, par. 15, we must check whether this is an external call on a
  93. -- protected subprogram with the same target object as that of the
  94. -- protected action that is currently in progress (i.e., if the caller
  95. -- is already the protected object's owner). If this is the case hence
  96. -- Program_Error must be raised.
  97. if Detect_Blocking and then Object.Owner = Self then
  98. raise Program_Error;
  99. end if;
  100. Write_Lock (Object.L'Access, Ceiling_Violation);
  101. if Ceiling_Violation then
  102. raise Program_Error;
  103. end if;
  104. -- We are entering in a protected action, so that we increase the
  105. -- protected object nesting level (if pragma Detect_Blocking is
  106. -- active), and update the protected object's owner.
  107. if Detect_Blocking then
  108. declare
  109. Self_Id : constant Task_Id := Self;
  110. begin
  111. -- Update the protected object's owner
  112. Object.Owner := Self_Id;
  113. -- Increase protected object nesting level
  114. Self_Id.Common.Protected_Action_Nesting :=
  115. Self_Id.Common.Protected_Action_Nesting + 1;
  116. end;
  117. end if;
  118. end Lock;
  119. --------------------
  120. -- Lock_Read_Only --
  121. --------------------
  122. procedure Lock_Read_Only (Object : Protection_Access) is
  123. Ceiling_Violation : Boolean;
  124. begin
  125. -- If pragma Detect_Blocking is active then, as described in the ARM
  126. -- 9.5.1, par. 15, we must check whether this is an external call on
  127. -- protected subprogram with the same target object as that of the
  128. -- protected action that is currently in progress (i.e., if the caller
  129. -- is already the protected object's owner). If this is the case hence
  130. -- Program_Error must be raised.
  131. --
  132. -- Note that in this case (getting read access), several tasks may have
  133. -- read ownership of the protected object, so that this method of
  134. -- storing the (single) protected object's owner does not work reliably
  135. -- for read locks. However, this is the approach taken for two major
  136. -- reasons: first, this function is not currently being used (it is
  137. -- provided for possible future use), and second, it largely simplifies
  138. -- the implementation.
  139. if Detect_Blocking and then Object.Owner = Self then
  140. raise Program_Error;
  141. end if;
  142. Read_Lock (Object.L'Access, Ceiling_Violation);
  143. if Ceiling_Violation then
  144. raise Program_Error;
  145. end if;
  146. -- We are entering in a protected action, so we increase the protected
  147. -- object nesting level (if pragma Detect_Blocking is active).
  148. if Detect_Blocking then
  149. declare
  150. Self_Id : constant Task_Id := Self;
  151. begin
  152. -- Update the protected object's owner
  153. Object.Owner := Self_Id;
  154. -- Increase protected object nesting level
  155. Self_Id.Common.Protected_Action_Nesting :=
  156. Self_Id.Common.Protected_Action_Nesting + 1;
  157. end;
  158. end if;
  159. end Lock_Read_Only;
  160. -----------------
  161. -- Set_Ceiling --
  162. -----------------
  163. procedure Set_Ceiling
  164. (Object : Protection_Access;
  165. Prio : System.Any_Priority) is
  166. begin
  167. Object.New_Ceiling := Prio;
  168. end Set_Ceiling;
  169. ------------
  170. -- Unlock --
  171. ------------
  172. procedure Unlock (Object : Protection_Access) is
  173. begin
  174. -- We are exiting from a protected action, so that we decrease the
  175. -- protected object nesting level (if pragma Detect_Blocking is
  176. -- active), and remove ownership of the protected object.
  177. if Detect_Blocking then
  178. declare
  179. Self_Id : constant Task_Id := Self;
  180. begin
  181. -- Calls to this procedure can only take place when being within
  182. -- a protected action and when the caller is the protected
  183. -- object's owner.
  184. pragma Assert (Self_Id.Common.Protected_Action_Nesting > 0
  185. and then Object.Owner = Self_Id);
  186. -- Remove ownership of the protected object
  187. Object.Owner := Null_Task;
  188. -- We are exiting from a protected action, so we decrease the
  189. -- protected object nesting level.
  190. Self_Id.Common.Protected_Action_Nesting :=
  191. Self_Id.Common.Protected_Action_Nesting - 1;
  192. end;
  193. end if;
  194. -- Before releasing the mutex we must actually update its ceiling
  195. -- priority if it has been changed.
  196. if Object.New_Ceiling /= Object.Ceiling then
  197. if Locking_Policy = 'C' then
  198. System.Task_Primitives.Operations.Set_Ceiling
  199. (Object.L'Access, Object.New_Ceiling);
  200. end if;
  201. Object.Ceiling := Object.New_Ceiling;
  202. end if;
  203. Unlock (Object.L'Access);
  204. end Unlock;
  205. begin
  206. -- Ensure that tasking is initialized, as well as tasking soft links
  207. -- when using protected objects.
  208. Tasking.Initialize;
  209. System.Soft_Links.Tasking.Init_Tasking_Soft_Links;
  210. end System.Tasking.Protected_Objects;