1 ------------------------------------------------------------------------------
3 -- GNAT RUN-TIME LIBRARY (GNARL) COMPONENTS --
5 -- S Y S T E M . O S _ P R I M I T I V E S --
9 -- Copyright (C) 1998-2008, Free Software Foundation, Inc. --
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. --
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. --
29 -- GNARL was developed by the GNARL team at Florida State University. --
30 -- Extensive contributions were provided by Ada Core Technologies, Inc. --
32 ------------------------------------------------------------------------------
34 -- This is the NT version of this package
36 with System
.Win32
.Ext
;
38 package body System
.OS_Primitives
is
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
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.
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;
119 if QueryPerformanceCounter
(Current_Ticks
'Access) = Win32
.FALSE then
123 GetSystemTimeAsFileTime
(Now
'Access);
126 Duration (Long_Long_Float (abs (Now
- BTiA
.all)) /
127 Hundreds_Nano_In_Sec
);
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
142 Duration (Long_Long_Float (Current_Ticks
- BTA
.all) /
143 Long_Long_Float (TFA
.all));
146 return BCA
.all + Elap_Secs_Tick
;
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
;
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.
175 GetSystemTimeAsFileTime
(Base_Time
'Access);
177 if QueryPerformanceCounter
(Base_Ticks
'Access) = Win32
.FALSE then
180 "Could not query high performance counter in Clock");
184 GetSystemTimeAsFileTime
(Test_Now
'Access);
186 exit when Test_Now
- Base_Time
= Max_Elapsed
;
189 Base_Clock
:= Duration
190 (Long_Long_Float ((Base_Time
- epoch_1970
) * system_time_ns
) /
191 Long_Long_Float (Sec_Unit
));
194 ---------------------
195 -- Monotonic_Clock --
196 ---------------------
198 function Monotonic_Clock
return Duration is
199 Current_Ticks
: aliased LARGE_INTEGER
;
200 Elap_Secs_Tick
: Duration;
203 if QueryPerformanceCounter
(Current_Ticks
'Access) = Win32
.FALSE then
208 Duration (Long_Long_Float (Current_Ticks
- BMTA
.all) /
209 Long_Long_Float (TFA
.all));
211 return BMCA
.all + Elap_Secs_Tick
;
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.
229 function Mode_Clock
return Duration is
233 return Monotonic_Clock
;
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.
247 Check_Time
: Duration := Base_Time
;
249 -- Start of processing for Timed Delay
252 if Mode
= Relative
then
254 Abs_Time
:= Time
+ Check_Time
;
256 Rel_Time
:= Time
- Check_Time
;
260 if Rel_Time
> 0.0 then
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
;
276 Initialized
: Boolean := False;
278 procedure Initialize
is
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";
295 -- Keep base clock and ticks for the monotonic clock. These values
296 -- should never be changed to ensure proper behavior of the monotonic
299 Base_Monotonic_Clock
:= Base_Clock
;
300 Base_Monotonic_Ticks
:= Base_Ticks
;
303 end System
.OS_Primitives
;