File : s-bbtime.ads
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 -- S p e c --
8 -- --
9 -- Copyright (C) 1999-2002 Universidad Politecnica de Madrid --
10 -- Copyright (C) 2003-2004 The European Space Agency --
11 -- Copyright (C) 2003-2016, 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 -- Package in charge of implementing clock and timer functionalities
38
39 pragma Restrictions (No_Elaboration_Code);
40
41 with System.Multiprocessors;
42
43 package System.BB.Time is
44 pragma Preelaborate;
45
46 type Time is mod 2 ** 64;
47 for Time'Size use 64;
48
49 ------------------
50 -- Time keeping --
51 ------------------
52
53 -- Time is represented at this level as a 64-bit unsigned number. We assume
54 -- that the Board_Support.Read_Clock function provides access to a hardware
55 -- clock with a resolution of 20 microseconds or better, counting from
56 -- 0 to Board_Support.Max_Timer_Interval over a period of at least 0.735
57 -- seconds, and returning a value of the 32-bit Timer_Interval type. The
58 -- clock resolution should be an integral number of nanoseconds between 1
59 -- and 20_000.
60
61 -- In addition, Board_Support provides an alarm facility, generating an
62 -- alarm interrupt at up to Max_Timer_Interval clock ticks in the future.
63 -- The clock frequency is the same as for Read_Clock, but it may or may not
64 -- use the same timer. See the next section for more information.
65
66 -- The Time package uses these facilities to keep a 64-bit clock that will
67 -- allow a program to keep track of up to 50 years in the future without
68 -- having the most significant bit set. This means it is always safe to
69 -- subtract two Clock readings to determine a Time_Span without overflow.
70
71 -- We need to support a clock running for 50 years, so this requires
72 -- a hardware clock period of at least 1_577_880_000 / 2**31 or 0.735
73 -- seconds. As comparison, a LEON2 at 80 MHz with 24-bit clock and the
74 -- minimum prescale factor of 4, has a period of 2**24 / (80E6 / 4) = 0.839
75 -- seconds, while a 200 MHz LEON3 has a period of 2**32 / (200E6 / 5) =
76 -- 107 seconds. For faster clocks or smaller clock width, higher prescaler
77 -- values may be needed to achieve 50 year run time. The prescale factor
78 -- should be chosen such that the period between clock ticks is an integral
79 -- number of nanoseconds between 1 and 20_000.
80
81 type Time_Span is range -2 ** 63 .. 2 ** 63 - 1;
82 for Time_Span'Size use 64;
83 -- Time_Span represents the length of time intervals, and it is defined as
84 -- a 64-bit signed integer.
85
86 ------------
87 -- Alarms --
88 ------------
89
90 -- Alarms are used for two purposes:
91
92 -- * Waking up tasks that sleep as result of Delay_Until
93
94 -- * Clock updates, to prevent undetected wrap-around of the
95 -- hardware clock
96
97 -- Alarms use the same time unit as the clock used for time keeping,
98 -- and need to be able to provide an alarm up to slightly less than
99 -- Max_Timer_Interval ticks in the future; there always will be a pending
100 -- alarm within this time frame because of required clock updates. A
101 -- requirement is that an alarm always can be handled within 1/8th of the
102 -- time it takes the hardware clock to wrap around. This gives an upper
103 -- bound to how early we have to set the alarm to ensure timely clock
104 -- updates. This will result in an interrupt rate 14% higher than
105 -- absolutely necessary. However, as long as sleep-related alarms are
106 -- sufficiently frequent, no extra clock-related interrupts are necessary.
107
108 --------------------
109 -- Execution time --
110 --------------------
111
112 -- System.BB.Execution_Time will set these hooks to enable execution time
113 -- computation only when needed.
114
115 Scheduling_Event_Hook : access procedure := null;
116 -- This hooks must be called when the charged account change: in case of
117 -- rescheduling and before and after the handling of interrupt.
118
119 --------------------
120 -- Initialization --
121 --------------------
122
123 procedure Initialize_Timers;
124 -- Initialize this package (clock and alarm handlers). Must be called
125 -- before any other functions.
126
127 ----------------
128 -- Operations --
129 ----------------
130
131 function Epoch return Time;
132 -- Get the reference startup time
133
134 function Clock return Time;
135 -- Get the number of ticks elapsed since startup
136
137 procedure Delay_Until (T : Time);
138 -- Suspend the calling thread until the absolute time specified by T
139
140 function Get_Next_Timeout (CPU_Id : System.Multiprocessors.CPU) return Time;
141 -- Get the date of the next alarm or timing event
142
143 procedure Update_Alarm (Alarm : Time);
144 -- Re-configure the timer if "Alarm" is earlier than the Pending_Alarm.
145 -- Update_Alarm is the only routine allowed to set an alarm.
146
147 -- Execution time
148
149 -- Ada allows reading the execution time of any task. To support that, we
150 -- need to have exclusive access to the time (which is costly as it is not
151 -- possible to atomically read that value without using a spin lock and
152 -- masking interrupts). To avoid that cost, let's split that type in two
153 -- parts (that can be read or written atomically by the processor). It
154 -- is not possible to read atomically the whole value, but it is possible
155 -- to read a coherent value: if the time has been changed from A to B
156 -- while being read, the value read is between A and B. Because of the
157 -- architecture of the runtime, the execution time is always written
158 -- atomically (written by the processor executing the task, within the
159 -- kernel).
160
161 -- The type Composite_Execution_Time is declared here so that s-bbthre
162 -- doesn't depend on s-bbtiev. But this type is used by s-bbtiev.
163
164 type Word is mod 2 ** 32;
165
166 type Composite_Execution_Time is record
167 High : Word;
168 pragma Atomic (High);
169 -- High part of execution time
170
171 Low : Word;
172 pragma Atomic (Low);
173 -- Low part of execution time
174 end record;
175
176 Initial_Composite_Execution_Time : constant Composite_Execution_Time :=
177 (0, 0);
178 -- The initial value for Composite_Execution_Time
179
180 private
181 pragma Inline (Clock);
182 pragma Inline (Epoch);
183
184 end System.BB.Time;