objc-act.c (synth_module_prologue): Use TREE_NO_WARNING instead of DECL_IN_SYSTEM_HEADER.
[official-gcc.git] / gcc / ada / s-taasde.adb
blob84a8504fb11dc042d5190ae47792db6fcb1d27d2
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT RUN-TIME LIBRARY (GNARL) COMPONENTS --
4 -- --
5 -- S Y S T E M . T A S K I N G . A S Y N C _ D E L A Y S --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 1998-2008, Free Software Foundation, Inc. --
10 -- --
11 -- GNARL 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 2, or (at your option) any later ver- --
14 -- sion. GNARL 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. See the GNU General Public License --
17 -- for more details. You should have received a copy of the GNU General --
18 -- Public License distributed with GNARL; see file COPYING. If not, write --
19 -- to the Free Software Foundation, 51 Franklin Street, Fifth Floor, --
20 -- Boston, MA 02110-1301, USA. --
21 -- --
22 -- As a special exception, if other files instantiate generics from this --
23 -- unit, or you link this unit with other files to produce an executable, --
24 -- this unit does not by itself cause the resulting executable to be --
25 -- covered by the GNU General Public License. This exception does not --
26 -- however invalidate any other reasons why the executable file might be --
27 -- covered by the GNU Public License. --
28 -- --
29 -- GNARL was developed by the GNARL team at Florida State University. --
30 -- Extensive contributions were provided by Ada Core Technologies, Inc. --
31 -- --
32 ------------------------------------------------------------------------------
34 pragma Polling (Off);
35 -- Turn off polling, we do not want ATC polling to take place during
36 -- tasking operations. It causes infinite loops and other problems.
38 with Ada.Unchecked_Conversion;
39 with Ada.Task_Identification;
41 with System.Task_Primitives.Operations;
42 with System.Tasking.Utilities;
43 with System.Tasking.Initialization;
44 with System.Tasking.Debug;
45 with System.OS_Primitives;
46 with System.Interrupt_Management.Operations;
47 with System.Parameters;
48 with System.Traces.Tasking;
50 package body System.Tasking.Async_Delays is
52 package STPO renames System.Task_Primitives.Operations;
53 package ST renames System.Tasking;
54 package STU renames System.Tasking.Utilities;
55 package STI renames System.Tasking.Initialization;
56 package OSP renames System.OS_Primitives;
58 use Parameters;
59 use System.Traces;
60 use System.Traces.Tasking;
62 function To_System is new Ada.Unchecked_Conversion
63 (Ada.Task_Identification.Task_Id, Task_Id);
65 Timer_Server_ID : ST.Task_Id;
67 Timer_Attention : Boolean := False;
68 pragma Atomic (Timer_Attention);
70 task Timer_Server is
71 pragma Interrupt_Priority (System.Any_Priority'Last);
72 end Timer_Server;
74 -- The timer queue is a circular doubly linked list, ordered by absolute
75 -- wakeup time. The first item in the queue is Timer_Queue.Succ.
76 -- It is given a Resume_Time that is larger than any legitimate wakeup
77 -- time, so that the ordered insertion will always stop searching when it
78 -- gets back to the queue header block.
80 Timer_Queue : aliased Delay_Block;
82 ------------------------
83 -- Cancel_Async_Delay --
84 ------------------------
86 -- This should (only) be called from the compiler-generated cleanup routine
87 -- for an async. select statement with delay statement as trigger. The
88 -- effect should be to remove the delay from the timer queue, and exit one
89 -- ATC nesting level.
90 -- The usage and logic are similar to Cancel_Protected_Entry_Call, but
91 -- simplified because this is not a true entry call.
93 procedure Cancel_Async_Delay (D : Delay_Block_Access) is
94 Dpred : Delay_Block_Access;
95 Dsucc : Delay_Block_Access;
97 begin
98 -- Note that we mark the delay as being cancelled
99 -- using a level value that is reserved.
101 -- make this operation idempotent
103 if D.Level = ATC_Level_Infinity then
104 return;
105 end if;
107 D.Level := ATC_Level_Infinity;
109 -- remove self from timer queue
111 STI.Defer_Abort_Nestable (D.Self_Id);
113 if Single_Lock then
114 STPO.Lock_RTS;
115 end if;
117 STPO.Write_Lock (Timer_Server_ID);
118 Dpred := D.Pred;
119 Dsucc := D.Succ;
120 Dpred.Succ := Dsucc;
121 Dsucc.Pred := Dpred;
122 D.Succ := D;
123 D.Pred := D;
124 STPO.Unlock (Timer_Server_ID);
126 -- Note that the above deletion code is required to be
127 -- idempotent, since the block may have been dequeued
128 -- previously by the Timer_Server.
130 -- leave the asynchronous select
132 STPO.Write_Lock (D.Self_Id);
133 STU.Exit_One_ATC_Level (D.Self_Id);
134 STPO.Unlock (D.Self_Id);
136 if Single_Lock then
137 STPO.Unlock_RTS;
138 end if;
140 STI.Undefer_Abort_Nestable (D.Self_Id);
141 end Cancel_Async_Delay;
143 ---------------------------
144 -- Enqueue_Time_Duration --
145 ---------------------------
147 function Enqueue_Duration
148 (T : Duration;
149 D : Delay_Block_Access) return Boolean
151 begin
152 if T <= 0.0 then
153 D.Timed_Out := True;
154 STPO.Yield;
155 return False;
157 else
158 -- The corresponding call to Undefer_Abort is performed by the
159 -- expanded code (see exp_ch9).
161 STI.Defer_Abort (STPO.Self);
162 Time_Enqueue
163 (STPO.Monotonic_Clock
164 + Duration'Min (T, OSP.Max_Sensible_Delay), D);
165 return True;
166 end if;
167 end Enqueue_Duration;
169 ------------------
170 -- Time_Enqueue --
171 ------------------
173 -- Allocate a queue element for the wakeup time T and put it in the
174 -- queue in wakeup time order. Assume we are on an asynchronous
175 -- select statement with delay trigger. Put the calling task to
176 -- sleep until either the delay expires or is cancelled.
178 -- We use one entry call record for this delay, since we have
179 -- to increment the ATC nesting level, but since it is not a
180 -- real entry call we do not need to use any of the fields of
181 -- the call record. The following code implements a subset of
182 -- the actions for the asynchronous case of Protected_Entry_Call,
183 -- much simplified since we know this never blocks, and does not
184 -- have the full semantics of a protected entry call.
186 procedure Time_Enqueue
187 (T : Duration;
188 D : Delay_Block_Access)
190 Self_Id : constant Task_Id := STPO.Self;
191 Q : Delay_Block_Access;
193 use type ST.Task_Id;
194 -- for visibility of operator "="
196 begin
197 pragma Debug (Debug.Trace (Self_Id, "Async_Delay", 'P'));
198 pragma Assert (Self_Id.Deferral_Level = 1,
199 "async delay from within abort-deferred region");
201 if Self_Id.ATC_Nesting_Level = ATC_Level'Last then
202 raise Storage_Error with "not enough ATC nesting levels";
203 end if;
205 Self_Id.ATC_Nesting_Level := Self_Id.ATC_Nesting_Level + 1;
207 pragma Debug
208 (Debug.Trace (Self_Id, "ASD: entered ATC level: " &
209 ATC_Level'Image (Self_Id.ATC_Nesting_Level), 'A'));
211 D.Level := Self_Id.ATC_Nesting_Level;
212 D.Self_Id := Self_Id;
213 D.Resume_Time := T;
215 if Single_Lock then
216 STPO.Lock_RTS;
217 end if;
219 STPO.Write_Lock (Timer_Server_ID);
221 -- Previously, there was code here to dynamically create
222 -- the Timer_Server task, if one did not already exist.
223 -- That code had a timing window that could allow multiple
224 -- timer servers to be created. Luckily, the need for
225 -- postponing creation of the timer server should now be
226 -- gone, since this package will only be linked in if
227 -- there are calls to enqueue calls on the timer server.
229 -- Insert D in the timer queue, at the position determined
230 -- by the wakeup time T.
232 Q := Timer_Queue.Succ;
234 while Q.Resume_Time < T loop
235 Q := Q.Succ;
236 end loop;
238 -- Q is the block that has Resume_Time equal to or greater than
239 -- T. After the insertion we want Q to be the successor of D.
241 D.Succ := Q;
242 D.Pred := Q.Pred;
243 D.Pred.Succ := D;
244 Q.Pred := D;
246 -- If the new element became the head of the queue,
247 -- signal the Timer_Server to wake up.
249 if Timer_Queue.Succ = D then
250 Timer_Attention := True;
251 STPO.Wakeup (Timer_Server_ID, ST.Timer_Server_Sleep);
252 end if;
254 STPO.Unlock (Timer_Server_ID);
256 if Single_Lock then
257 STPO.Unlock_RTS;
258 end if;
259 end Time_Enqueue;
261 ---------------
262 -- Timed_Out --
263 ---------------
265 function Timed_Out (D : Delay_Block_Access) return Boolean is
266 begin
267 return D.Timed_Out;
268 end Timed_Out;
270 ------------------
271 -- Timer_Server --
272 ------------------
274 task body Timer_Server is
275 function Get_Next_Wakeup_Time return Duration;
276 -- Used to initialize Next_Wakeup_Time, but also to ensure that
277 -- Make_Independent is called during the elaboration of this task.
279 --------------------------
280 -- Get_Next_Wakeup_Time --
281 --------------------------
283 function Get_Next_Wakeup_Time return Duration is
284 begin
285 STU.Make_Independent;
286 return Duration'Last;
287 end Get_Next_Wakeup_Time;
289 -- Local Declarations
291 Next_Wakeup_Time : Duration := Get_Next_Wakeup_Time;
292 Timedout : Boolean;
293 Yielded : Boolean;
294 Now : Duration;
295 Dequeued : Delay_Block_Access;
296 Dequeued_Task : Task_Id;
298 pragma Unreferenced (Timedout, Yielded);
300 begin
301 Timer_Server_ID := STPO.Self;
303 -- Since this package may be elaborated before System.Interrupt,
304 -- we need to call Setup_Interrupt_Mask explicitly to ensure that
305 -- this task has the proper signal mask.
307 Interrupt_Management.Operations.Setup_Interrupt_Mask;
309 -- Initialize the timer queue to empty, and make the wakeup time of the
310 -- header node be larger than any real wakeup time we will ever use.
312 loop
313 STI.Defer_Abort (Timer_Server_ID);
315 if Single_Lock then
316 STPO.Lock_RTS;
317 end if;
319 STPO.Write_Lock (Timer_Server_ID);
321 -- The timer server needs to catch pending aborts after finalization
322 -- of library packages. If it doesn't poll for it, the server will
323 -- sometimes hang.
325 if not Timer_Attention then
326 Timer_Server_ID.Common.State := ST.Timer_Server_Sleep;
328 if Next_Wakeup_Time = Duration'Last then
329 Timer_Server_ID.User_State := 1;
330 Next_Wakeup_Time :=
331 STPO.Monotonic_Clock + OSP.Max_Sensible_Delay;
333 else
334 Timer_Server_ID.User_State := 2;
335 end if;
337 STPO.Timed_Sleep
338 (Timer_Server_ID, Next_Wakeup_Time,
339 OSP.Absolute_RT, ST.Timer_Server_Sleep,
340 Timedout, Yielded);
341 Timer_Server_ID.Common.State := ST.Runnable;
342 end if;
344 -- Service all of the wakeup requests on the queue whose times have
345 -- been reached, and update Next_Wakeup_Time to next wakeup time
346 -- after that (the wakeup time of the head of the queue if any, else
347 -- a time far in the future).
349 Timer_Server_ID.User_State := 3;
350 Timer_Attention := False;
352 Now := STPO.Monotonic_Clock;
353 while Timer_Queue.Succ.Resume_Time <= Now loop
355 -- Dequeue the waiting task from the front of the queue
357 pragma Debug (System.Tasking.Debug.Trace
358 (Timer_Server_ID, "Timer service: waking up waiting task", 'E'));
360 Dequeued := Timer_Queue.Succ;
361 Timer_Queue.Succ := Dequeued.Succ;
362 Dequeued.Succ.Pred := Dequeued.Pred;
363 Dequeued.Succ := Dequeued;
364 Dequeued.Pred := Dequeued;
366 -- We want to abort the queued task to the level of the async.
367 -- select statement with the delay. To do that, we need to lock
368 -- the ATCB of that task, but to avoid deadlock we need to release
369 -- the lock of the Timer_Server. This leaves a window in which
370 -- another task might perform an enqueue or dequeue operation on
371 -- the timer queue, but that is OK because we always restart the
372 -- next iteration at the head of the queue.
374 if Parameters.Runtime_Traces then
375 Send_Trace_Info (E_Kill, Dequeued.Self_Id);
376 end if;
378 STPO.Unlock (Timer_Server_ID);
379 STPO.Write_Lock (Dequeued.Self_Id);
380 Dequeued_Task := Dequeued.Self_Id;
381 Dequeued.Timed_Out := True;
382 STI.Locked_Abort_To_Level
383 (Timer_Server_ID, Dequeued_Task, Dequeued.Level - 1);
384 STPO.Unlock (Dequeued_Task);
385 STPO.Write_Lock (Timer_Server_ID);
386 end loop;
388 Next_Wakeup_Time := Timer_Queue.Succ.Resume_Time;
390 -- Service returns the Next_Wakeup_Time.
391 -- The Next_Wakeup_Time is either an infinity (no delay request)
392 -- or the wakeup time of the queue head. This value is used for
393 -- an actual delay in this server.
395 STPO.Unlock (Timer_Server_ID);
397 if Single_Lock then
398 STPO.Unlock_RTS;
399 end if;
401 STI.Undefer_Abort (Timer_Server_ID);
402 end loop;
403 end Timer_Server;
405 ------------------------------
406 -- Package Body Elaboration --
407 ------------------------------
409 begin
410 Timer_Queue.Succ := Timer_Queue'Access;
411 Timer_Queue.Pred := Timer_Queue'Access;
412 Timer_Queue.Resume_Time := Duration'Last;
413 Timer_Server_ID := To_System (Timer_Server'Identity);
414 end System.Tasking.Async_Delays;