gnat_arm_elf_13.2.1_db1e9283/arm-eabi/lib/gnat/embedded-stm32f4/gnarl/s-tposen.adb

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
------------------------------------------------------------------------------
--                                                                          --
--                 GNAT RUN-TIME LIBRARY (GNARL) COMPONENTS                 --
--                                                                          --
--               SYSTEM.TASKING.PROTECTED_OBJECTS.SINGLE_ENTRY              --
--                                                                          --
--                                B o d y                                   --
--                                                                          --
--                     Copyright (C) 1998-2023, AdaCore                     --
--                                                                          --
-- 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 3,  or (at your option) any later ver- --
-- sion. GNARL 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.                                     --
--                                                                          --
-- 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/>.                                          --
--                                                                          --
-- GNARL was developed by the GNARL team at Florida State University.       --
-- Extensive contributions were provided by Ada Core Technologies, Inc.     --
--                                                                          --
------------------------------------------------------------------------------

pragma Style_Checks (All_Checks);
--  Turn off subprogram ordering check, since restricted GNARLI subprograms are
--  gathered together at end.

--  This package provides an optimized version of Protected_Objects.Operations
--  and Protected_Objects.Entries making the following assumptions:

--    PO's have only one entry
--    There is only one caller at a time (No_Entry_Queue)
--    There is no dynamic priority support (No_Dynamic_Priorities)
--    No Abort Statements
--     (No_Abort_Statements, Max_Asynchronous_Select_Nesting => 0)
--    PO are at library level
--    No Requeue
--    None of the tasks will terminate (no need for finalization)
--
--  This interface is intended to be used in the ravenscar and restricted
--  profiles, the compiler is responsible for ensuring that the conditions
--  mentioned above are respected, except for the No_Entry_Queue restriction
--  that is checked dynamically in this package, since the check cannot be
--  performed at compile time (see Protected_Single_Entry_Call, Service_Entry).
--
--  Note that the difference with respect to the high integrity version of
--  this package is that exception handlers are allowed, so that support for
--  exceptional completion of entry bodies needs to be provided.

pragma Suppress (All_Checks);
--  Why is this needed???

with System.Multiprocessors;

with System.Task_Primitives.Operations;

with System.Tasking.Protected_Objects.Multiprocessors;

package body System.Tasking.Protected_Objects.Single_Entry is

   use System.Multiprocessors;

   package STPO renames System.Task_Primitives.Operations;
   package STPOM renames System.Tasking.Protected_Objects.Multiprocessors;

   Multiprocessor : constant Boolean := CPU'Range_Length /= 1;

   --------------------------------------------
   -- Exceptional_Complete_Single_Entry_Body --
   --------------------------------------------

   procedure Exceptional_Complete_Single_Entry_Body
     (Object : Protection_Entry_Access;
      Ex     : Ada.Exceptions.Exception_Id)
   is
   begin
      Object.Call_In_Progress.Exception_To_Raise := Ex;
   end Exceptional_Complete_Single_Entry_Body;

   ---------------------------------
   -- Initialize_Protection_Entry --
   ---------------------------------

   procedure Initialize_Protection_Entry
     (Object           : Protection_Entry_Access;
      Ceiling_Priority : Integer;
      Compiler_Info    : System.Address;
      Entry_Body       : Entry_Body_Access)
   is
   begin
      Initialize_Protection (Object.Common'Access, Ceiling_Priority);

      Object.Compiler_Info := Compiler_Info;
      Object.Call_In_Progress := null;
      Object.Entry_Body := Entry_Body;
      Object.Entry_Queue := null;
   end Initialize_Protection_Entry;

   ----------------
   -- Lock_Entry --
   ----------------

   procedure Lock_Entry (Object : Protection_Entry_Access) is
   begin
      Lock (Object.Common'Access);
   end Lock_Entry;

   ---------------------------
   -- Protected_Count_Entry --
   ---------------------------

   function Protected_Count_Entry (Object : Protection_Entry) return Natural is
   begin
      return Boolean'Pos (Object.Entry_Queue /= null);
   end Protected_Count_Entry;

   ---------------------------------
   -- Protected_Single_Entry_Call --
   ---------------------------------

   procedure Protected_Single_Entry_Call
     (Object             : Protection_Entry_Access;
      Uninterpreted_Data : System.Address)
   is
      Self_Id : constant Task_Id := STPO.Self;

      use type Ada.Exceptions.Exception_Id;

   begin
      --  For this run time, pragma Detect_Blocking is always active, so we
      --  must raise Program_Error if this potentially blocking operation is
      --  called from a protected action.

      if Self_Id.Common.Protected_Action_Nesting > 0 then
         raise Program_Error;
      end if;

      Lock_Entry (Object);
      Self_Id.Entry_Call.Uninterpreted_Data := Uninterpreted_Data;
      Self_Id.Entry_Call.Exception_To_Raise := Ada.Exceptions.Null_Id;

      if Object.Entry_Body.Barrier (Object.Compiler_Info, 1) then

         --  No other task can be executing an entry within this protected
         --  object. On a single processor implementation (such as this one),
         --  the ceiling priority protocol and the strictly preemptive priority
         --  scheduling policy guarantee that protected objects are always
         --  available when any task tries to use them (otherwise, either the
         --  currently executing task would not have had a high enough priority
         --  to be executing, or a blocking operation would have been called
         --  from within the entry body).

         pragma Assert (Object.Call_In_Progress = null);

         Object.Call_In_Progress := Self_Id.Entry_Call'Access;
         Object.Entry_Body.Action
           (Object.Compiler_Info, Self_Id.Entry_Call.Uninterpreted_Data, 1);
         Object.Call_In_Progress := null;

         --  Entry call is over

         Unlock_Entry (Object);

      else
         if Object.Entry_Queue /= null then

            --  This violates restriction No_Entry_Queue, raise Program_Error

            Unlock_Entry (Object);
            raise Program_Error with "No_Entry_Queue restriction violated";
         end if;

         --  There is a potential race condition between the Unlock_Entry and
         --  the Sleep below (the Wakeup may be called before the Sleep). This
         --  case is explicitly handled in the Sleep and Wakeup procedures:
         --  Sleep won't block if Wakeup has been called before.

         Object.Entry_Queue := Self_Id.Entry_Call'Access;
         Unlock_Entry (Object);

         --  Suspend until entry call has been completed. On exit, the call
         --  will not be queued.

         Self_Id.Common.State := Entry_Caller_Sleep;
         STPO.Sleep (Self_Id, Entry_Caller_Sleep);
         Self_Id.Common.State := Runnable;
      end if;

      --  Check whether there is any exception to raise

      if Self_Id.Entry_Call.Exception_To_Raise /= Ada.Exceptions.Null_Id then
         Ada.Exceptions.Raise_Exception
           (Self_Id.Entry_Call.Exception_To_Raise);
      end if;
   end Protected_Single_Entry_Call;

   -----------------------------------
   -- Protected_Single_Entry_Caller --
   -----------------------------------

   function Protected_Single_Entry_Caller
     (Object : Protection_Entry) return Task_Id
   is
   begin
      return Object.Call_In_Progress.Self;
   end Protected_Single_Entry_Caller;

   -------------------
   -- Service_Entry --
   -------------------

   procedure Service_Entry (Object : Protection_Entry_Access) is
      Entry_Call : constant Entry_Call_Link := Object.Entry_Queue;
      Caller     : Task_Id;

   begin
      if Entry_Call /= null
        and then Object.Entry_Body.Barrier (Object.Compiler_Info, 1)
      then
         Object.Entry_Queue := null;

         --  No other task can be executing an entry within this protected
         --  object. On a single processor implementation (such as this one),
         --  the ceiling priority protocol and the strictly preemptive priority
         --  scheduling policy guarantee that protected objects are always
         --  available when any task tries to use them (otherwise, either the
         --  currently executing task would not have had a high enough priority
         --  to be executing, or a blocking operation would have been called
         --  from within the entry body).

         pragma Assert (Object.Call_In_Progress = null);

         Object.Call_In_Progress := Entry_Call;
         Object.Entry_Body.Action
           (Object.Compiler_Info, Entry_Call.Uninterpreted_Data, 1);
         Object.Call_In_Progress := null;
         Caller := Entry_Call.Self;
         Unlock_Entry (Object);

         --  Signal the entry caller that the entry is completed

         if not Multiprocessor
           or else Caller.Common.Base_CPU = STPO.Self.Common.Base_CPU
         then
            --  Entry caller and servicing tasks are on the same CPU.
            --  We are allowed to directly wake up the task.

            STPO.Wakeup (Caller, Entry_Caller_Sleep);
         else
            --  The entry caller is on a different CPU.

            STPOM.Served (Entry_Call);
         end if;

      else
         --  Just unlock the entry

         Unlock_Entry (Object);
      end if;
   end Service_Entry;

   ------------------
   -- Unlock_Entry --
   ------------------

   procedure Unlock_Entry (Object : Protection_Entry_Access) is
   begin
      Unlock (Object.Common'Access);
   end Unlock_Entry;

end System.Tasking.Protected_Objects.Single_Entry;