File : s-bbtime.adb
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT RUN-TIME LIBRARY (GNARL) COMPONENTS --
4 -- --
5 -- S Y S T E M . B B . T I M E --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 1999-2002 Universidad Politecnica de Madrid --
10 -- Copyright (C) 2003-2005 The European Space Agency --
11 -- Copyright (C) 2003-2015, AdaCore --
12 -- --
13 -- GNARL is free software; you can redistribute it and/or modify it under --
14 -- terms of the GNU General Public License as published by the Free Soft- --
15 -- ware Foundation; either version 3, or (at your option) any later ver- --
16 -- sion. GNARL is distributed in the hope that it will be useful, but WITH- --
17 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
18 -- or FITNESS FOR A PARTICULAR PURPOSE. --
19 -- --
20 -- --
21 -- --
22 -- --
23 -- --
24 -- You should have received a copy of the GNU General Public License and --
25 -- a copy of the GCC Runtime Library Exception along with this program; --
26 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
27 -- <http://www.gnu.org/licenses/>. --
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 -- The port of GNARL to bare board targets was initially developed by the --
33 -- Real-Time Systems Group at the Technical University of Madrid. --
34 -- --
35 ------------------------------------------------------------------------------
36
37 pragma Restrictions (No_Elaboration_Code);
38
39 with System.BB.Interrupts;
40 with System.BB.Board_Support;
41 with System.BB.Protection;
42 with System.BB.Parameters;
43 with System.BB.Threads.Queues;
44 with System.BB.Timing_Events;
45 with System.BB.CPU_Primitives.Multiprocessors;
46 with System.Multiprocessors.Fair_Locks;
47 with System.Multiprocessors.Spin_Locks;
48
49 package body System.BB.Time is
50
51 use Board_Support;
52 use Parameters;
53 use CPU_Primitives.Multiprocessors;
54 use System.Multiprocessors;
55 use System.Multiprocessors.Fair_Locks;
56 use System.Multiprocessors.Spin_Locks;
57 use Threads, Threads.Queues;
58
59 -----------------------
60 -- Local definitions --
61 -----------------------
62
63 Alarm_Lock : Fair_Lock := (Spinning => (others => False),
64 Lock => (Flag => 0));
65 -- Used to protect access to shared alarm resources
66 -- (Timer configuration and Pending_Alarm variable)
67
68 subtype Clock_Interval is Timer_Interval;
69
70 type Clock_Periods is mod 2 ** 32;
71 for Clock_Periods'Size use 32;
72
73 function "&" (Left : Clock_Periods; Right : Clock_Interval) return Time is
74 (Time (Left) * (Time (Max_Timer_Interval) + 1) + Time (Right));
75 -- Combine MSP and LSP of clock to form time
76
77 Update_In_Progress : constant Clock_Periods := 0;
78 Periods_In_Epoch : constant Clock_Periods := 1;
79 -- Special value to signify Last_Clock_Update is going on, so on
80 -- multiprocessor systems can avoid race conditions during updates.
81 -- Choose 0, and have epoch start at 1, so Unsynchronized_Clock can
82 -- ignore updates and just return an early time instead.
83
84 type Composite_Time is record
85 MSP : Clock_Periods := Periods_In_Epoch;
86 pragma Atomic (MSP);
87 LSP : Clock_Interval := 0;
88 pragma Atomic (LSP);
89 end record;
90 -- Time representation used for the software clock, allowing concurrent
91 -- updates and reads, see Update_Clock.
92 --
93 -- Include a default expression for component LSP, even when not needed, to
94 -- prevent the need for elaboration code to initialize default-initialized
95 -- objects of this type (note that this package has a restriction
96 -- No_Elaboration_Code).
97
98 Software_Clock : Composite_Time;
99 -- Clock with same time-base as hardware clock, but allowing a larger
100 -- range. This is always behind the actual time by less than one hardware
101 -- clock period. See Update_Clock for read and update protocol.
102
103 Pending_Alarm : Time := Time'Last;
104 -- Time of the current alarm handled by the timer. Used to determine if a
105 -- given alarm is before the current one, and so needs to re-configure the
106 -- timer.
107
108 Max_Sleep : Time := 0;
109 -- The longest time we can sleep without updating the Software_Clock.
110 -- Initialized by Initialize_Timers.
111
112 -----------------------
113 -- Local subprograms --
114 -----------------------
115
116 procedure Alarm_Handler (Interrupt : Interrupts.Interrupt_ID);
117 -- Handler for the alarm interrupt
118
119 procedure Update_Clock (Now : out Time);
120 -- This procedure has to be executed at least once each period of the
121 -- hardware clock. We also require that this procedure be called with
122 -- interrupts disabled, to ensure no stale values will be written. Given
123 -- that limitation, it is fine to do concurrent updates on SMP systems:
124 -- no matter which update ultimately prevails, it can't be old. While, on
125 -- SMP systems, the Period_Counter may not always be monotone, the time
126 -- returned by Update_Clock and Clock is.
127
128 -------------------
129 -- Alarm_Handler --
130 -------------------
131
132 procedure Alarm_Handler (Interrupt : Interrupts.Interrupt_ID) is
133 Now : Time;
134 Next_Alarm : Time; -- Time
135
136 begin
137 -- Make sure we are handling the right interrupt and there is an alarm
138 -- pending.
139
140 pragma Assert
141 (Pending_Alarm /= Time'Last
142 and then Interrupt = Alarm_Interrupt_ID);
143
144 Board_Support.Clear_Alarm_Interrupt;
145
146 -- The access to the queues must be protected
147
148 Protection.Enter_Kernel;
149
150 -- Reset Pending_Alarm before computing the next alarm time, as other
151 -- processors may set alarms concurrently, and these alarms would be
152 -- ignored otherwise. The alarm lock must be held for this.
153
154 if Multiprocessor then
155 Lock (Alarm_Lock);
156 Pending_Alarm := Time'Last;
157 Unlock (Alarm_Lock);
158
159 -- No need for lock if not on multiprocessor
160
161 else
162 Pending_Alarm := Time'Last;
163 end if;
164
165 Update_Clock (Now);
166
167 -- Ensure alarms will keep going to keep the software clock up-to-date.
168
169 Next_Alarm := Now + Max_Sleep;
170
171 -- Multiprocessor case special processing
172
173 if Parameters.Multiprocessor then
174
175 -- This is the alarm CPU, we have to wake up the other CPUs with
176 -- expired alarms.
177
178 for CPU_Id in CPU loop
179
180 if CPU_Id /= Current_CPU then
181 declare
182 Alarm_Time : constant Time := Get_Next_Timeout (CPU_Id);
183
184 begin
185 if Alarm_Time <= Now then
186
187 -- Alarm expired, wake up the CPU
188
189 Poke_CPU (CPU_Id);
190
191 else
192 -- Check if this is the next non-expired alarm of the
193 -- overall system.
194
195 if Alarm_Time < Next_Alarm then
196 Next_Alarm := Alarm_Time;
197 end if;
198 end if;
199 end;
200 end if;
201 end loop;
202 end if;
203
204 -- Execute expired events of the current CPU
205
206 Timing_Events.Execute_Expired_Timing_Events (Now);
207
208 -- Wake up our alarms, and set any new alarm
209
210 Wakeup_Expired_Alarms (Now);
211
212 Next_Alarm := Time'Min (Get_Next_Timeout (Current_CPU), Next_Alarm);
213 Update_Alarm (Next_Alarm);
214
215 Protection.Leave_Kernel;
216 end Alarm_Handler;
217
218 -----------
219 -- Clock --
220 -----------
221
222 function Clock return Time is
223 First_MSP : Clock_Periods;
224 Before_MSP : Clock_Periods;
225 Before_LSP : Clock_Interval;
226 Now_LSP : Clock_Interval;
227 After_MSP : Clock_Periods;
228
229 begin
230 -- Reading the clock needs to access to the software and the hardware
231 -- clock. In a multiprocessor, masking interrupts is not enough because
232 -- the software clock can be updated by another processor. Therefore, we
233 -- keep reading until we get a consistent value (no updates of the
234 -- software MSP while we read the hardware clock).
235
236 -- We can limit the iterations in the loop to 3. In the worst case, if
237 -- the MSP keeps increasing within the loop, it means that we are
238 -- spending an extremely long time in this function (we get preempted
239 -- all the time). If the first time we read 1, and then the MSP gets
240 -- increased, we know that the time is between 1 & X and 2 & X (because
241 -- the software clock can be behind the actual time by at most one
242 -- hardware clock period). It means that the actual time when we entered
243 -- this function was before 3 & 0. In the second iteration we can read
244 -- 2 and then get increased again. Hence actual time is between 2 & X
245 -- and 3 & X. Hence, the actual time when we leave function clock is at
246 -- least 2 & 0. However, we do not know when between 2 & 0 and 3 & 0.
247 -- Hence we read a third time, and if we read 3 and then a change, it
248 -- means that the actual time is between 3 & X and 4 & X (so at least
249 -- 3 & 0). Hence, at the end of the third iteration, we can return 3 & 0
250 -- as a safe value that is between the beginning and end of the
251 -- execution of this call to Clock.
252
253 for Iteration in 1 .. 3 loop
254
255 -- On multiprocessor systems there may be a concurrent update of the
256 -- software clock (signaled with Update_In_Progress). Retry if this
257 -- happens. On monoprocessors the loop is performed only once.
258
259 loop
260 Before_MSP := Software_Clock.MSP;
261
262 exit when not Multiprocessor
263 or else Before_MSP /= Update_In_Progress;
264 end loop;
265
266 -- After the loop, Before_MSP cannot be equal to Update_In_Progress.
267 -- In the case of multiprocessors because of the exit condition, and
268 -- in the case of monoprocessors because the update is done
269 -- atomically.
270
271 Before_LSP := Software_Clock.LSP;
272
273 Now_LSP := Read_Clock;
274
275 After_MSP := Software_Clock.MSP;
276
277 -- If the MSP in Software_Clock has changed (or is changing), we
278 -- do not know the time at which the software clock was updated. It
279 -- is important to note that the implementation does not force the
280 -- software clock to be updated at a time close to the LSP wraparound
281 -- (it needs to be done at least once per hardware clock period, but
282 -- we do not know when). Hence, returning (Before_MSP + 1) & 0 is
283 -- not correct because the updated LSP in the Software_Clock does
284 -- not need to be close to zero.
285
286 -- Normal case, no updates in MSP
287
288 if Before_MSP = After_MSP then
289
290 -- If we know the value of the software clock at the time of the
291 -- read of the hardware clock, we know the time of that read,
292 -- because the software clock can never be more than one period
293 -- behind. Hence, we build a Time value from two consecutive
294 -- readings of the hardware clock (Before_LSP and Now_LSP) and one
295 -- reading of the MSP from the Software_Clock (and we know that
296 -- the MSP did not change between the two readings of Before_LSP
297 -- and Now_LSP).
298
299 return
300 Before_MSP + (if Now_LSP < Before_LSP then 1 else 0) & Now_LSP;
301
302 -- After the first unsuccessful iteration we store the first MSP
303 -- value read to have a reference of the initial time when we entered
304 -- the clock function (before First_MSP + 2 & 0).
305
306 elsif Iteration = 1 then
307 First_MSP := Before_MSP;
308
309 -- During the second or third iteration, if the clock has been
310 -- increased by two or more then Before_MSP & 0 is certainly within
311 -- the beginning and end of the execution of this call to Clock.
312
313 elsif Before_MSP - First_MSP >= 2 then
314 exit;
315 end if;
316 end loop;
317
318 pragma Assert (Before_MSP - First_MSP >= 2);
319
320 return Before_MSP & 0;
321 end Clock;
322
323 -----------------
324 -- Delay_Until --
325 -----------------
326
327 procedure Delay_Until (T : Time) is
328 Now : Time;
329 Self : Thread_Id;
330 Inserted_As_First : Boolean;
331
332 begin
333 Protection.Enter_Kernel;
334
335 Now := Clock;
336
337 Self := Thread_Self;
338
339 pragma Assert (Self.State = Runnable);
340
341 -- Test if the alarm time is in the future
342
343 if T > Now then
344
345 -- Extract the thread from the ready queue. When a thread wants to
346 -- wait for an alarm it becomes blocked.
347
348 Self.State := Delayed;
349
350 Extract (Self);
351
352 -- Insert Thread_Id in the alarm queue (ordered by time) and if it
353 -- was inserted at head then check if Alarm Time is closer than the
354 -- next clock interrupt.
355
356 Insert_Alarm (T, Self, Inserted_As_First);
357
358 if Inserted_As_First then
359 Update_Alarm (Get_Next_Timeout (Current_CPU));
360 end if;
361
362 else
363 -- If alarm time is not in the future, the thread must yield the CPU
364
365 Yield (Self);
366 end if;
367
368 Protection.Leave_Kernel;
369 end Delay_Until;
370
371 -----------
372 -- Epoch --
373 -----------
374
375 function Epoch return Time is
376 begin
377 return Periods_In_Epoch & 0;
378 end Epoch;
379
380 ----------------------
381 -- Get_Next_Timeout --
382 ----------------------
383
384 function Get_Next_Timeout (CPU_Id : CPU) return Time is
385 Alarm_Time : constant Time := Get_Next_Alarm_Time (CPU_Id);
386 Event_Time : constant Time := Timing_Events.Get_Next_Timeout (CPU_Id);
387 begin
388 return Time'Min (Alarm_Time, Event_Time);
389 end Get_Next_Timeout;
390
391 -----------------------
392 -- Initialize_Timers --
393 -----------------------
394
395 procedure Initialize_Timers is
396 begin
397 -- There may never be more than Max_Timer_Interval clocks between
398 -- updates of Software_Clock, or we lose track of time. Allow a 1/8th
399 -- period safety for early wakeup. The alarm CPU should never have
400 -- alarm interrupts disabled for longer than this, or we may miss
401 -- clock updates.
402
403 Max_Sleep := Time (Max_Timer_Interval / 8 * 7);
404
405 -- Install alarm handler
406
407 Interrupts.Attach_Handler
408 (Alarm_Handler'Access,
409 Alarm_Interrupt_ID,
410 Priority_Of_Interrupt (Alarm_Interrupt_ID));
411
412 -- It is important to initialize the software LSP with the value coming
413 -- from the hardware. There is no guarantee that this hardware value is
414 -- close to zero (it may have been initialized by monitor software with
415 -- any value and at any moment in time). With this initialization we
416 -- ensure that the first alarm is not too far (we need to ensure that
417 -- the value in the software LSP is less than a period away from the
418 -- actual value in hardware).
419
420 Software_Clock.LSP := Read_Clock;
421
422 -- Establish invariant that there always is a pending alarm at most
423 -- Max_Sleep time in the future.
424
425 Pending_Alarm := Clock + Max_Sleep;
426 Board_Support.Set_Alarm (Clock_Interval (Max_Sleep));
427 end Initialize_Timers;
428
429 -------------------
430 -- Update_Alarm --
431 -------------------
432
433 procedure Update_Alarm (Alarm : Time) is
434 Now : constant Time := Clock;
435 Time_Difference : Time;
436
437 begin
438 -- On multiprocessors we want to do the entire procedure while holding
439 -- the alarm lock, as we shouldn't read or update the Pending_Alarm
440 -- variable, or program the alarm, concurrently with another update.
441
442 if Parameters.Multiprocessor then
443 Lock (Alarm_Lock);
444 end if;
445
446 if Alarm <= Now then
447
448 -- If alarm is in the past, set the minimum timer value so the
449 -- interrupt will be triggered as soon as possible.
450
451 Time_Difference := 1;
452
453 else
454 Time_Difference := Alarm - Now;
455 end if;
456
457 Time_Difference := Time'Min (Time_Difference, Max_Sleep);
458
459 -- If next alarm time is closer than the currently pending alarm,
460 -- reprogram the alarm.
461
462 if Alarm < Pending_Alarm then
463 pragma Assert (Time_Difference in 1 .. Max_Sleep);
464
465 Board_Support.Set_Alarm (Clock_Interval (Time_Difference));
466 Pending_Alarm := Alarm;
467 end if;
468
469 if Parameters.Multiprocessor then
470 Unlock (Alarm_Lock);
471 end if;
472 end Update_Alarm;
473
474 ------------------
475 -- Update_Clock --
476 ------------------
477
478 -- Must be called from within Kernel (interrupts disabled). Must only be
479 -- called from one processor at a time.
480
481 procedure Update_Clock (Now : out Time) is
482 Update_MSP : constant Clock_Periods := Software_Clock.MSP;
483 Update_LSP : constant Clock_Interval := Software_Clock.LSP;
484 Now_LSP : constant Clock_Interval := Read_Clock;
485 Now_MSP : Clock_Periods;
486
487 begin
488 if Now_LSP < Update_LSP then
489 Now_MSP := Update_MSP + 1;
490
491 -- Need to do "atomic" update of both parts of the clock
492
493 -- Mark Software_Clock.MSP as invalid during updates. The read
494 -- protocol is to read Software_Clock.MSP both before and after
495 -- reading Software_Clock.LSP. Only consider the MSP as that
496 -- belonging to the LSP if both values are the same and not equal
497 -- to the special Update_In_Progress value.
498
499 -- Because interrupts are disabled, this special read protocol is
500 -- only necessary on multiprocessor systems.
501
502 Software_Clock.MSP := Update_In_Progress;
503 Software_Clock.LSP := Now_LSP;
504 Software_Clock.MSP := Now_MSP;
505
506 else
507 Now_MSP := Update_MSP;
508
509 -- Only need to change the LSP, so we can do this atomically
510
511 Software_Clock.LSP := Now_LSP;
512 end if;
513
514 Now := Now_MSP & Now_LSP;
515 end Update_Clock;
516 end System.BB.Time;