OSDN Git Service

2007-03-01 Paul Brook <paul@codesourcery.com>
[pf3gnuchains/gcc-fork.git] / gcc / ada / s-osprim-mingw.adb
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-2005 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 ------------------------------------------------------------------------------
33
34 --  This is the NT version of this package
35
36 with Interfaces.C;
37
38 package body System.OS_Primitives is
39
40    ---------------------------
41    -- Win32 API Definitions --
42    ---------------------------
43
44    --  These definitions are copied from System.OS_Interface because we do not
45    --  want to depend on gnarl here.
46
47    type DWORD is new Interfaces.C.unsigned_long;
48
49    type LARGE_INTEGER is delta 1.0 range -2.0**63 .. 2.0**63 - 1.0;
50
51    type BOOL is new Boolean;
52    for BOOL'Size use Interfaces.C.unsigned_long'Size;
53
54    procedure GetSystemTimeAsFileTime (lpFileTime : access Long_Long_Integer);
55    pragma Import (Stdcall, GetSystemTimeAsFileTime, "GetSystemTimeAsFileTime");
56
57    function QueryPerformanceCounter
58      (lpPerformanceCount : access LARGE_INTEGER) return BOOL;
59    pragma Import
60      (Stdcall, QueryPerformanceCounter, "QueryPerformanceCounter");
61
62    function QueryPerformanceFrequency
63      (lpFrequency : access LARGE_INTEGER) return BOOL;
64    pragma Import
65      (Stdcall, QueryPerformanceFrequency, "QueryPerformanceFrequency");
66
67    procedure Sleep (dwMilliseconds : DWORD);
68    pragma Import (Stdcall, Sleep, External_Name => "Sleep");
69
70    ----------------------------------------
71    -- Data for the high resolution clock --
72    ----------------------------------------
73
74    --  Declare some pointers to access multi-word data above. This is needed
75    --  to workaround a limitation in the GNU/Linker auto-import feature used
76    --  to build the GNAT runtime DLLs. In fact the Clock and Monotonic_Clock
77    --  routines are inlined and they are using some multi-word variables.
78    --  GNU/Linker will fail to auto-import those variables when building
79    --  libgnarl.dll. The indirection level introduced here has no measurable
80    --  penalties.
81    --
82    --  Note that access variables below must not be declared as constant
83    --  otherwise the compiler optimization will remove this indirect access.
84
85    type DA is access all Duration;
86    --  Use to have indirect access to multi-word variables
87
88    type LIA is access all LARGE_INTEGER;
89    --  Use to have indirect access to multi-word variables
90
91    type LLIA is access all Long_Long_Integer;
92    --  Use to have indirect access to multi-word variables
93
94    Tick_Frequency : aliased LARGE_INTEGER;
95    TFA : constant LIA := Tick_Frequency'Access;
96    --  Holds frequency of high-performance counter used by Clock
97    --  Windows NT uses a 1_193_182 Hz counter on PCs.
98
99    Base_Ticks : aliased LARGE_INTEGER;
100    BTA : constant LIA := Base_Ticks'Access;
101    --  Holds the Tick count for the base time.
102
103    Base_Monotonic_Ticks : aliased LARGE_INTEGER;
104    BMTA : constant LIA := Base_Monotonic_Ticks'Access;
105    --  Holds the Tick count for the base monotonic time
106
107    Base_Clock : aliased Duration;
108    BCA : constant DA := Base_Clock'Access;
109    --  Holds the current clock for the standard clock's base time
110
111    Base_Monotonic_Clock : aliased Duration;
112    BMCA : constant DA := Base_Monotonic_Clock'Access;
113    --  Holds the current clock for monotonic clock's base time
114
115    Base_Time : aliased Long_Long_Integer;
116    BTiA : constant LLIA := Base_Time'Access;
117    --  Holds the base time used to check for system time change, used with
118    --  the standard clock.
119
120    procedure Get_Base_Time;
121    --  Retrieve the base time and base ticks. These values will be used by
122    --  clock to compute the current time by adding to it a fraction of the
123    --  performance counter. This is for the implementation of a
124    --  high-resolution clock. Note that this routine does not change the base
125    --  monotonic values used by the monotonic clock.
126
127    -----------
128    -- Clock --
129    -----------
130
131    --  This implementation of clock provides high resolution timer values
132    --  using QueryPerformanceCounter. This call return a 64 bits values (based
133    --  on the 8253 16 bits counter). This counter is updated every 1/1_193_182
134    --  times per seconds. The call to QueryPerformanceCounter takes 6
135    --  microsecs to complete.
136
137    function Clock return Duration is
138       Max_Shift            : constant Duration        := 2.0;
139       Hundreds_Nano_In_Sec : constant Long_Long_Float := 1.0E7;
140       Current_Ticks        : aliased LARGE_INTEGER;
141       Elap_Secs_Tick       : Duration;
142       Elap_Secs_Sys        : Duration;
143       Now                  : aliased Long_Long_Integer;
144
145    begin
146       if not QueryPerformanceCounter (Current_Ticks'Access) then
147          return 0.0;
148       end if;
149
150       GetSystemTimeAsFileTime (Now'Access);
151
152       Elap_Secs_Sys :=
153         Duration (Long_Long_Float (abs (Now - BTiA.all)) /
154                     Hundreds_Nano_In_Sec);
155
156       Elap_Secs_Tick :=
157         Duration (Long_Long_Float (Current_Ticks - BTA.all) /
158                   Long_Long_Float (TFA.all));
159
160       --  If we have a shift of more than Max_Shift seconds we resynchonize the
161       --  Clock. This is probably due to a manual Clock adjustment, an DST
162       --  adjustment or an NTP synchronisation. And we want to adjust the
163       --  time for this system (non-monotonic) clock.
164
165       if abs (Elap_Secs_Sys - Elap_Secs_Tick) > Max_Shift then
166          Get_Base_Time;
167
168          Elap_Secs_Tick :=
169            Duration (Long_Long_Float (Current_Ticks - BTA.all) /
170                      Long_Long_Float (TFA.all));
171       end if;
172
173       return BCA.all + Elap_Secs_Tick;
174    end Clock;
175
176    -------------------
177    -- Get_Base_Time --
178    -------------------
179
180    procedure Get_Base_Time is
181       --  The resolution for GetSystemTime is 1 millisecond.
182
183       --  The time to get both base times should take less than 1 millisecond.
184       --  Therefore, the elapsed time reported by GetSystemTime between both
185       --  actions should be null.
186
187       Max_Elapsed    : constant := 0;
188
189       Test_Now       : aliased Long_Long_Integer;
190
191       epoch_1970     : constant := 16#19D_B1DE_D53E_8000#; -- win32 UTC epoch
192       system_time_ns : constant := 100;                    -- 100 ns per tick
193       Sec_Unit       : constant := 10#1#E9;
194
195    begin
196       --  Here we must be sure that both of these calls are done in a short
197       --  amount of time. Both are base time and should in theory be taken
198       --  at the very same time.
199
200       loop
201          GetSystemTimeAsFileTime (Base_Time'Access);
202
203          if not QueryPerformanceCounter (Base_Ticks'Access) then
204             pragma Assert
205               (Standard.False,
206                "Could not query high performance counter in Clock");
207             null;
208          end if;
209
210          GetSystemTimeAsFileTime (Test_Now'Access);
211
212          exit when Test_Now - Base_Time = Max_Elapsed;
213       end loop;
214
215       Base_Clock := Duration
216         (Long_Long_Float ((Base_Time - epoch_1970) * system_time_ns) /
217          Long_Long_Float (Sec_Unit));
218    end Get_Base_Time;
219
220    ---------------------
221    -- Monotonic_Clock --
222    ---------------------
223
224    function Monotonic_Clock return Duration is
225       Current_Ticks  : aliased LARGE_INTEGER;
226       Elap_Secs_Tick : Duration;
227    begin
228       if not QueryPerformanceCounter (Current_Ticks'Access) then
229          return 0.0;
230       end if;
231
232       Elap_Secs_Tick :=
233         Duration (Long_Long_Float (Current_Ticks - BMTA.all) /
234                   Long_Long_Float (TFA.all));
235
236       return BMCA.all + Elap_Secs_Tick;
237    end Monotonic_Clock;
238
239    -----------------
240    -- Timed_Delay --
241    -----------------
242
243    procedure Timed_Delay (Time : Duration; Mode : Integer) is
244       Rel_Time   : Duration;
245       Abs_Time   : Duration;
246       Check_Time : Duration := Monotonic_Clock;
247
248    begin
249       if Mode = Relative then
250          Rel_Time := Time;
251          Abs_Time := Time + Check_Time;
252       else
253          Rel_Time := Time - Check_Time;
254          Abs_Time := Time;
255       end if;
256
257       if Rel_Time > 0.0 then
258          loop
259             Sleep (DWORD (Rel_Time * 1000.0));
260             Check_Time := Monotonic_Clock;
261
262             exit when Abs_Time <= Check_Time;
263
264             Rel_Time := Abs_Time - Check_Time;
265          end loop;
266       end if;
267    end Timed_Delay;
268
269    ----------------
270    -- Initialize --
271    ----------------
272
273    Initialized : Boolean := False;
274
275    procedure Initialize is
276    begin
277       if Initialized then
278          return;
279       end if;
280
281       Initialized := True;
282
283       --  Get starting time as base
284
285       if not QueryPerformanceFrequency (Tick_Frequency'Access) then
286          raise Program_Error
287            with "cannot get high performance counter frequency";
288       end if;
289
290       Get_Base_Time;
291
292       --  Keep base clock and ticks for the monotonic clock. These values
293       --  should never be changed to ensure proper behavior of the monotonic
294       --  clock.
295
296       Base_Monotonic_Clock := Base_Clock;
297       Base_Monotonic_Ticks := Base_Ticks;
298    end Initialize;
299
300 end System.OS_Primitives;