PR tree-optimization/43833
[official-gcc/alias-decl.git] / gcc / ada / a-rttiev.adb
blob2fe78212c3da9ec2ab76140fddf6d36ea4c9ac87
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT RUN-TIME COMPONENTS --
4 -- --
5 -- A D A . R E A L _ T I M E . T I M I N G _ E V E N T S --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 2005-2009, Free Software Foundation, Inc. --
10 -- --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 3, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. --
17 -- --
18 -- As a special exception under Section 7 of GPL version 3, you are granted --
19 -- additional permissions described in the GCC Runtime Library Exception, --
20 -- version 3.1, as published by the Free Software Foundation. --
21 -- --
22 -- You should have received a copy of the GNU General Public License and --
23 -- a copy of the GCC Runtime Library Exception along with this program; --
24 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
25 -- <http://www.gnu.org/licenses/>. --
26 -- --
27 -- GNAT was originally developed by the GNAT team at New York University. --
28 -- Extensive contributions were provided by Ada Core Technologies Inc. --
29 -- --
30 ------------------------------------------------------------------------------
32 with System.Task_Primitives.Operations;
33 with System.Tasking.Utilities;
34 with System.Soft_Links;
36 with Ada.Containers.Doubly_Linked_Lists;
37 pragma Elaborate_All (Ada.Containers.Doubly_Linked_Lists);
39 ---------------------------------
40 -- Ada.Real_Time.Timing_Events --
41 ---------------------------------
43 package body Ada.Real_Time.Timing_Events is
45 use System.Task_Primitives.Operations;
47 package SSL renames System.Soft_Links;
49 type Any_Timing_Event is access all Timing_Event'Class;
50 -- We must also handle user-defined types derived from Timing_Event
52 ------------
53 -- Events --
54 ------------
56 package Events is new Ada.Containers.Doubly_Linked_Lists (Any_Timing_Event);
57 -- Provides the type for the container holding pointers to events
59 All_Events : Events.List;
60 -- The queue of pending events, ordered by increasing timeout value, that
61 -- have been "set" by the user via Set_Handler.
63 Event_Queue_Lock : aliased System.Task_Primitives.RTS_Lock;
64 -- Used for mutually exclusive access to All_Events
66 procedure Process_Queued_Events;
67 -- Examine the queue of pending events for any that have timed out. For
68 -- those that have timed out, remove them from the queue and invoke their
69 -- handler (unless the user has cancelled the event by setting the handler
70 -- pointer to null). Mutually exclusive access is held via Event_Queue_Lock
71 -- during part of the processing.
73 procedure Insert_Into_Queue (This : Any_Timing_Event);
74 -- Insert the specified event pointer into the queue of pending events
75 -- with mutually exclusive access via Event_Queue_Lock.
77 procedure Remove_From_Queue (This : Any_Timing_Event);
78 -- Remove the specified event pointer from the queue of pending events with
79 -- mutually exclusive access via Event_Queue_Lock. This procedure is used
80 -- by the client-side routines (Set_Handler, etc.).
82 -----------
83 -- Timer --
84 -----------
86 task Timer is
87 pragma Priority (System.Priority'Last);
88 entry Start;
89 end Timer;
91 task body Timer is
92 Period : constant Time_Span := Milliseconds (100);
93 -- This is a "chiming" clock timer that fires periodically. The period
94 -- selected is arbitrary and could be changed to suit the application
95 -- requirements. Obviously a shorter period would give better resolution
96 -- at the cost of more overhead.
98 begin
99 System.Tasking.Utilities.Make_Independent;
101 -- We await the call to Start to ensure that Event_Queue_Lock has been
102 -- initialized by the package executable part prior to accessing it in
103 -- the loop. The task is activated before the first statement of the
104 -- executable part so it would otherwise be possible for the task to
105 -- call EnterCriticalSection in Process_Queued_Events before the
106 -- initialization.
108 -- We don't simply put the initialization here, prior to the loop,
109 -- because other application tasks could call the visible routines that
110 -- also call Enter/LeaveCriticalSection prior to this task doing the
111 -- initialization.
113 accept Start;
115 loop
116 Process_Queued_Events;
117 delay until Clock + Period;
118 end loop;
119 end Timer;
121 ---------------------------
122 -- Process_Queued_Events --
123 ---------------------------
125 procedure Process_Queued_Events is
126 Next_Event : Any_Timing_Event;
128 begin
129 loop
130 SSL.Abort_Defer.all;
132 Write_Lock (Event_Queue_Lock'Access);
134 if All_Events.Is_Empty then
135 Unlock (Event_Queue_Lock'Access);
136 SSL.Abort_Undefer.all;
137 return;
138 else
139 Next_Event := All_Events.First_Element;
140 end if;
142 if Next_Event.Timeout > Clock then
144 -- We found one that has not yet timed out. The queue is in
145 -- ascending order by Timeout so there is no need to continue
146 -- processing (and indeed we must not continue since we always
147 -- delete the first element).
149 Unlock (Event_Queue_Lock'Access);
150 SSL.Abort_Undefer.all;
151 return;
152 end if;
154 -- We have an event that has timed out so we will process it. It must
155 -- be the first in the queue so no search is needed.
157 All_Events.Delete_First;
159 -- A fundamental issue is that the invocation of the event's handler
160 -- might call Set_Handler on itself to re-insert itself back into the
161 -- queue of future events. Thus we cannot hold the lock on the queue
162 -- while invoking the event's handler.
164 Unlock (Event_Queue_Lock'Access);
166 SSL.Abort_Undefer.all;
168 -- There is no race condition with the user changing the handler
169 -- pointer while we are processing because we are executing at the
170 -- highest possible application task priority and are not doing
171 -- anything to block prior to invoking their handler.
173 declare
174 Handler : constant Timing_Event_Handler := Next_Event.Handler;
176 begin
177 -- The first act is to clear the event, per D.15(13/2). Besides,
178 -- we cannot clear the handler pointer *after* invoking the
179 -- handler because the handler may have re-inserted the event via
180 -- Set_Event. Thus we take a copy and then clear the component.
182 Next_Event.Handler := null;
184 if Handler /= null then
185 Handler.all (Timing_Event (Next_Event.all));
186 end if;
188 -- Ignore exceptions propagated by Handler.all, as required by
189 -- RM D.15(21/2).
191 exception
192 when others =>
193 null;
194 end;
195 end loop;
196 end Process_Queued_Events;
198 -----------------------
199 -- Insert_Into_Queue --
200 -----------------------
202 procedure Insert_Into_Queue (This : Any_Timing_Event) is
204 function Sooner (Left, Right : Any_Timing_Event) return Boolean;
205 -- Compares events in terms of timeout values
207 package By_Timeout is new Events.Generic_Sorting (Sooner);
208 -- Used to keep the events in ascending order by timeout value
210 ------------
211 -- Sooner --
212 ------------
214 function Sooner (Left, Right : Any_Timing_Event) return Boolean is
215 begin
216 return Left.Timeout < Right.Timeout;
217 end Sooner;
219 -- Start of processing for Insert_Into_Queue
221 begin
222 SSL.Abort_Defer.all;
224 Write_Lock (Event_Queue_Lock'Access);
226 All_Events.Append (This);
228 -- A critical property of the implementation of this package is that
229 -- all occurrences are in ascending order by Timeout. Thus the first
230 -- event in the queue always has the "next" value for the Timer task
231 -- to use in its delay statement.
233 By_Timeout.Sort (All_Events);
235 Unlock (Event_Queue_Lock'Access);
237 SSL.Abort_Undefer.all;
238 end Insert_Into_Queue;
240 -----------------------
241 -- Remove_From_Queue --
242 -----------------------
244 procedure Remove_From_Queue (This : Any_Timing_Event) is
245 use Events;
246 Location : Cursor;
248 begin
249 SSL.Abort_Defer.all;
251 Write_Lock (Event_Queue_Lock'Access);
253 Location := All_Events.Find (This);
255 if Location /= No_Element then
256 All_Events.Delete (Location);
257 end if;
259 Unlock (Event_Queue_Lock'Access);
261 SSL.Abort_Undefer.all;
262 end Remove_From_Queue;
264 -----------------
265 -- Set_Handler --
266 -----------------
268 procedure Set_Handler
269 (Event : in out Timing_Event;
270 At_Time : Time;
271 Handler : Timing_Event_Handler)
273 begin
274 Remove_From_Queue (Event'Unchecked_Access);
275 Event.Handler := null;
277 -- RM D.15(15/2) requires that at this point, we check whether the time
278 -- has already passed, and if so, call Handler.all directly from here
279 -- instead of doing the enqueuing below. However, this causes a nasty
280 -- race condition and potential deadlock. If the current task has
281 -- already locked the protected object of Handler.all, and the time has
282 -- passed, deadlock would occur. Therefore, we ignore the requirement.
283 -- The same comment applies to the other Set_Handler below.
285 if Handler /= null then
286 Event.Timeout := At_Time;
287 Event.Handler := Handler;
288 Insert_Into_Queue (Event'Unchecked_Access);
289 end if;
290 end Set_Handler;
292 -----------------
293 -- Set_Handler --
294 -----------------
296 procedure Set_Handler
297 (Event : in out Timing_Event;
298 In_Time : Time_Span;
299 Handler : Timing_Event_Handler)
301 begin
302 Remove_From_Queue (Event'Unchecked_Access);
303 Event.Handler := null;
305 -- See comment in the other Set_Handler above
307 if Handler /= null then
308 Event.Timeout := Clock + In_Time;
309 Event.Handler := Handler;
310 Insert_Into_Queue (Event'Unchecked_Access);
311 end if;
312 end Set_Handler;
314 ---------------------
315 -- Current_Handler --
316 ---------------------
318 function Current_Handler
319 (Event : Timing_Event) return Timing_Event_Handler
321 begin
322 return Event.Handler;
323 end Current_Handler;
325 --------------------
326 -- Cancel_Handler --
327 --------------------
329 procedure Cancel_Handler
330 (Event : in out Timing_Event;
331 Cancelled : out Boolean)
333 begin
334 Remove_From_Queue (Event'Unchecked_Access);
335 Cancelled := Event.Handler /= null;
336 Event.Handler := null;
337 end Cancel_Handler;
339 -------------------
340 -- Time_Of_Event --
341 -------------------
343 function Time_Of_Event (Event : Timing_Event) return Time is
344 begin
345 -- RM D.15(18/2): Time_First must be returned in the event is not set
347 return (if Event.Handler = null then Time_First else Event.Timeout);
348 end Time_Of_Event;
350 --------------
351 -- Finalize --
352 --------------
354 procedure Finalize (This : in out Timing_Event) is
355 begin
356 -- D.15 (19/2) says finalization clears the event
358 This.Handler := null;
359 Remove_From_Queue (This'Unchecked_Access);
360 end Finalize;
362 begin
363 Initialize_Lock (Event_Queue_Lock'Access, Level => PO_Level);
364 Timer.Start;
365 end Ada.Real_Time.Timing_Events;