OSDN Git Service

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