2008-05-30 Vladimir Makarov <vmakarov@redhat.com>
[official-gcc.git] / gcc / ada / s-osprim-mingw.adb
blobd9712858c395080e4aec3fb1c2640ead8d9ac9a4
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT RUN-TIME LIBRARY (GNARL) COMPONENTS --
4 -- --
5 -- S Y S T E M . O S _ P R I M I T I V E 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 -- This is the NT version of this package
36 with System.Win32.Ext;
38 package body System.OS_Primitives is
40 use System.Win32;
41 use System.Win32.Ext;
43 ----------------------------------------
44 -- Data for the high resolution clock --
45 ----------------------------------------
47 -- Declare some pointers to access multi-word data above. This is needed
48 -- to workaround a limitation in the GNU/Linker auto-import feature used
49 -- to build the GNAT runtime DLLs. In fact the Clock and Monotonic_Clock
50 -- routines are inlined and they are using some multi-word variables.
51 -- GNU/Linker will fail to auto-import those variables when building
52 -- libgnarl.dll. The indirection level introduced here has no measurable
53 -- penalties.
55 -- Note that access variables below must not be declared as constant
56 -- otherwise the compiler optimization will remove this indirect access.
58 type DA is access all Duration;
59 -- Use to have indirect access to multi-word variables
61 type LIA is access all LARGE_INTEGER;
62 -- Use to have indirect access to multi-word variables
64 type LLIA is access all Long_Long_Integer;
65 -- Use to have indirect access to multi-word variables
67 Tick_Frequency : aliased LARGE_INTEGER;
68 TFA : constant LIA := Tick_Frequency'Access;
69 -- Holds frequency of high-performance counter used by Clock
70 -- Windows NT uses a 1_193_182 Hz counter on PCs.
72 Base_Ticks : aliased LARGE_INTEGER;
73 BTA : constant LIA := Base_Ticks'Access;
74 -- Holds the Tick count for the base time
76 Base_Monotonic_Ticks : aliased LARGE_INTEGER;
77 BMTA : constant LIA := Base_Monotonic_Ticks'Access;
78 -- Holds the Tick count for the base monotonic time
80 Base_Clock : aliased Duration;
81 BCA : constant DA := Base_Clock'Access;
82 -- Holds the current clock for the standard clock's base time
84 Base_Monotonic_Clock : aliased Duration;
85 BMCA : constant DA := Base_Monotonic_Clock'Access;
86 -- Holds the current clock for monotonic clock's base time
88 Base_Time : aliased Long_Long_Integer;
89 BTiA : constant LLIA := Base_Time'Access;
90 -- Holds the base time used to check for system time change, used with
91 -- the standard clock.
93 procedure Get_Base_Time;
94 -- Retrieve the base time and base ticks. These values will be used by
95 -- clock to compute the current time by adding to it a fraction of the
96 -- performance counter. This is for the implementation of a
97 -- high-resolution clock. Note that this routine does not change the base
98 -- monotonic values used by the monotonic clock.
100 -----------
101 -- Clock --
102 -----------
104 -- This implementation of clock provides high resolution timer values
105 -- using QueryPerformanceCounter. This call return a 64 bits values (based
106 -- on the 8253 16 bits counter). This counter is updated every 1/1_193_182
107 -- times per seconds. The call to QueryPerformanceCounter takes 6
108 -- microsecs to complete.
110 function Clock return Duration is
111 Max_Shift : constant Duration := 2.0;
112 Hundreds_Nano_In_Sec : constant Long_Long_Float := 1.0E7;
113 Current_Ticks : aliased LARGE_INTEGER;
114 Elap_Secs_Tick : Duration;
115 Elap_Secs_Sys : Duration;
116 Now : aliased Long_Long_Integer;
118 begin
119 if QueryPerformanceCounter (Current_Ticks'Access) = Win32.FALSE then
120 return 0.0;
121 end if;
123 GetSystemTimeAsFileTime (Now'Access);
125 Elap_Secs_Sys :=
126 Duration (Long_Long_Float (abs (Now - BTiA.all)) /
127 Hundreds_Nano_In_Sec);
129 Elap_Secs_Tick :=
130 Duration (Long_Long_Float (Current_Ticks - BTA.all) /
131 Long_Long_Float (TFA.all));
133 -- If we have a shift of more than Max_Shift seconds we resynchronize
134 -- the Clock. This is probably due to a manual Clock adjustment, an
135 -- DST adjustment or an NTP synchronisation. And we want to adjust the
136 -- time for this system (non-monotonic) clock.
138 if abs (Elap_Secs_Sys - Elap_Secs_Tick) > Max_Shift then
139 Get_Base_Time;
141 Elap_Secs_Tick :=
142 Duration (Long_Long_Float (Current_Ticks - BTA.all) /
143 Long_Long_Float (TFA.all));
144 end if;
146 return BCA.all + Elap_Secs_Tick;
147 end Clock;
149 -------------------
150 -- Get_Base_Time --
151 -------------------
153 procedure Get_Base_Time is
155 -- The resolution for GetSystemTime is 1 millisecond
157 -- The time to get both base times should take less than 1 millisecond.
158 -- Therefore, the elapsed time reported by GetSystemTime between both
159 -- actions should be null.
161 Max_Elapsed : constant := 0;
163 Test_Now : aliased Long_Long_Integer;
165 epoch_1970 : constant := 16#19D_B1DE_D53E_8000#; -- win32 UTC epoch
166 system_time_ns : constant := 100; -- 100 ns per tick
167 Sec_Unit : constant := 10#1#E9;
169 begin
170 -- Here we must be sure that both of these calls are done in a short
171 -- amount of time. Both are base time and should in theory be taken
172 -- at the very same time.
174 loop
175 GetSystemTimeAsFileTime (Base_Time'Access);
177 if QueryPerformanceCounter (Base_Ticks'Access) = Win32.FALSE then
178 pragma Assert
179 (Standard.False,
180 "Could not query high performance counter in Clock");
181 null;
182 end if;
184 GetSystemTimeAsFileTime (Test_Now'Access);
186 exit when Test_Now - Base_Time = Max_Elapsed;
187 end loop;
189 Base_Clock := Duration
190 (Long_Long_Float ((Base_Time - epoch_1970) * system_time_ns) /
191 Long_Long_Float (Sec_Unit));
192 end Get_Base_Time;
194 ---------------------
195 -- Monotonic_Clock --
196 ---------------------
198 function Monotonic_Clock return Duration is
199 Current_Ticks : aliased LARGE_INTEGER;
200 Elap_Secs_Tick : Duration;
202 begin
203 if QueryPerformanceCounter (Current_Ticks'Access) = Win32.FALSE then
204 return 0.0;
205 end if;
207 Elap_Secs_Tick :=
208 Duration (Long_Long_Float (Current_Ticks - BMTA.all) /
209 Long_Long_Float (TFA.all));
211 return BMCA.all + Elap_Secs_Tick;
212 end Monotonic_Clock;
214 -----------------
215 -- Timed_Delay --
216 -----------------
218 procedure Timed_Delay (Time : Duration; Mode : Integer) is
220 function Mode_Clock return Duration;
221 pragma Inline (Mode_Clock);
222 -- Return the current clock value using either the monotonic clock or
223 -- standard clock depending on the Mode value.
225 ----------------
226 -- Mode_Clock --
227 ----------------
229 function Mode_Clock return Duration is
230 begin
231 case Mode is
232 when Absolute_RT =>
233 return Monotonic_Clock;
234 when others =>
235 return Clock;
236 end case;
237 end Mode_Clock;
239 -- Local Variables
241 Base_Time : constant Duration := Mode_Clock;
242 -- Base_Time is used to detect clock set backward, in this case we
243 -- cannot ensure the delay accuracy.
245 Rel_Time : Duration;
246 Abs_Time : Duration;
247 Check_Time : Duration := Base_Time;
249 -- Start of processing for Timed Delay
251 begin
252 if Mode = Relative then
253 Rel_Time := Time;
254 Abs_Time := Time + Check_Time;
255 else
256 Rel_Time := Time - Check_Time;
257 Abs_Time := Time;
258 end if;
260 if Rel_Time > 0.0 then
261 loop
262 Sleep (DWORD (Rel_Time * 1000.0));
263 Check_Time := Mode_Clock;
265 exit when Abs_Time <= Check_Time or else Check_Time < Base_Time;
267 Rel_Time := Abs_Time - Check_Time;
268 end loop;
269 end if;
270 end Timed_Delay;
272 ----------------
273 -- Initialize --
274 ----------------
276 Initialized : Boolean := False;
278 procedure Initialize is
279 begin
280 if Initialized then
281 return;
282 end if;
284 Initialized := True;
286 -- Get starting time as base
288 if QueryPerformanceFrequency (Tick_Frequency'Access) = Win32.FALSE then
289 raise Program_Error with
290 "cannot get high performance counter frequency";
291 end if;
293 Get_Base_Time;
295 -- Keep base clock and ticks for the monotonic clock. These values
296 -- should never be changed to ensure proper behavior of the monotonic
297 -- clock.
299 Base_Monotonic_Clock := Base_Clock;
300 Base_Monotonic_Ticks := Base_Ticks;
301 end Initialize;
303 end System.OS_Primitives;