X-Git-Url: http://www.lcore.org/git/lcore.git/blobdiff_plain/b3b93191002f92b19c069b9815a8261d6edbc5ec..71f094bad8c68b2a3d096b436dc74cf4d9e2895a:/btime.pas

diff --git a/btime.pas b/btime.pas
index 2a4b267..8826a4d 100644
--- a/btime.pas
+++ b/btime.pas
@@ -9,10 +9,15 @@ works on windows/delphi, and on freepascal on unix.
 
 
 unit btime;
+{$ifdef fpc}
+  {$mode delphi}
+{$endif}
+
+{$include lcoreconfig.inc}
 
 interface
 
-{$ifdef win32}
+{$ifdef mswindows}
 uses
   ltimevalstuff;
 {$endif}  
@@ -31,6 +36,7 @@ var
   tickcount:integer;
   settimebias:tunixtimeint;
   performancecountfreq:extended;
+  btimenowin8:boolean;
 
 function irctimefloat:float;
 function irctimeint:tunixtimeint;
@@ -55,7 +61,10 @@ function timestrshort(i:tunixtimeint):string;    // Wed Aug 15 16:21:09 2012
 function timestriso(i:tunixtimeint):string;      // 2012-08-15 16:21:09
 function timestrisoutc(i:float):string;          // 2012-08-15T14:21:09.255553Z
 
-{$ifdef win32}
+procedure beginhightimerrate;
+procedure endhightimerrate;
+
+{$ifdef mswindows}
 function unixtimefloat_systemtime:float;
 {$endif}
 
@@ -63,12 +72,12 @@ function oletounixfloat(t:float):float;
 function oletounix(t:tdatetime):tunixtimeint;
 function unixtoole(i:float):tdatetime;
 
-{$ifdef win32}
+{$ifdef mswindows}
 function mmtimefloat:float;
 function qpctimefloat:float;
 {$endif}
 
-{$ifdef win32}
+{$ifdef mswindows}
 procedure gettimeofday(var tv:ttimeval);
 {$endif}
 
@@ -105,20 +114,17 @@ var
 
 implementation
 
-{$ifdef fpc}
-  {$mode delphi}
-{$endif}
+
 
 uses
   {$ifdef UNIX}
     {$ifdef VER1_0}
       linux,
     {$else}
+      {$ifdef linux}linux,{$endif} //for clock_gettime
+      {$ifdef freebsd}freebsd,{$endif} //for clock_gettime
       baseunix,unix,unixutil,sockets, {unixutil and sockets needed by unixstuff.inc on some compiler versions}
     {$endif}
-    {$ifdef linux}
-      dl,
-    {$endif}
   {$else}
     windows,unitsettc,mmsystem,
   {$endif}
@@ -138,7 +144,7 @@ end;
 
 function oletounix(t:tdatetime):tunixtimeint;
 begin
-  result := trunc(oletounixfloat(t));
+  result := round(oletounixfloat(t));
 end;
 
 function unixtoole(i:float):tdatetime;
@@ -169,49 +175,37 @@ end;
 function unixtimefloat:float;
 var
   tv:ttimeval;
+  sec:tunixtimeint;
 begin
   gettimeofday(tv);
-  result := tv.tv_sec+(tv.tv_usec/1000000);
+  sec := tv.tv_sec;
+  {$ifndef cpu64}
+  if (sec < -1) then inc(sec,$100000000); //tv_sec is 32 bits. allow -1 for invalid result
+  {$endif}
+  result := sec+(tv.tv_usec/1000000);
 end;
 
-{$ifdef linux}
-  {$define monotimefloat_implemented}
-  const
-    CLOCK_MONOTONIC = 1;
-  type 
-    ptimeval = ^ttimeval;
-    tclock_gettime = function(clk_id: integer; tp: ptimeval): integer; cdecl;
+{$ifdef linux}{$define have_clock_gettime}{$endif}
+{$ifdef freebsd}{$define have_clock_gettime}{$endif}
 
-  var
-    librt_handle:pointer;
-    librt_inited:boolean;
-    clock_gettime: tclock_gettime;
+{$ifdef have_clock_gettime}
+  {$define monotimefloat_implemented}
 
   function monotimefloat:float;
   var
-    ts: ttimeval;
+    ts: ttimespec;
   begin
-    if not librt_inited then begin
-      librt_inited := true;
-      clock_gettime := nil;
-      librt_handle := dlopen('librt.so', RTLD_LAZY);
-      if assigned(librt_handle) then begin
-        clock_gettime := dlsym(librt_handle, 'clock_gettime');
-      end;
-    end;
-    if assigned(clock_gettime) then begin
-      if clock_gettime(CLOCK_MONOTONIC, @ts) = 0 then begin
-        //note this really returns nanoseconds
-        result := ts.tv_sec + ts.tv_usec / 1000000000.0;
-        exit;
-      end;
+    if clock_gettime(CLOCK_MONOTONIC, @ts) = 0 then begin
+      //note this really returns nanoseconds
+      result := ts.tv_sec + ts.tv_nsec / 1000000000.0;
+      exit;
     end;
     //fallback
     result := unixtimefloat;
   end;
 
 
-{$endif} {linux}
+{$endif}
 
 {$ifdef darwin} {mac OS X}
 {$define monotimefloat_implemented}
@@ -256,9 +250,14 @@ end;
 function unixtimeint:tunixtimeint;
 var
   tv:ttimeval;
+  sec:tunixtimeint;
 begin
   gettimeofday(tv);
-  result := tv.tv_sec;
+  sec := tv.tv_sec;
+  {$ifndef cpu64}
+  if (sec < -1) then inc(sec,$100000000); //tv_sec is 32 bits. allow -1 for invalid result
+  {$endif}
+  result := sec;
 end;
 
 {------------------------------ end of *nix/freepascal section}
@@ -494,7 +493,7 @@ begin
   mmtime_lastresult := result;
 end;
 
-{ free pascals tsystemtime is incomaptible with windows api calls
+{ free pascals tsystemtime is incompatible with windows api calls
  so we declare it ourselves - plugwash
 }
 {$ifdef fpc}
@@ -553,12 +552,53 @@ begin
   result := mmqpctimefloat;
 end;
 
+
+
+var
+  GetSystemTimePreciseAsFileTime:procedure(var v:tfiletime); stdcall;
+  win8inited:boolean;
+
+procedure initwin8;
+var
+  dllhandle:thandle;
+
+begin
+  win8inited := true;
+  dllhandle := loadlibrary('kernel32.dll');
+  if (dllhandle <> 0) then begin
+    GetSystemTimePreciseAsFileTime := getprocaddress(dllhandle,'GetSystemTimePreciseAsFileTime');
+  end;
+end;
+
+
+function unixtimefloat_win8:float;
+var
+  ft:tfiletime;
+  i:int64 absolute ft;
+begin
+  GetSystemTimePreciseAsFileTime(ft);
+  {change from windows 1601-01-01 to unix 1970-01-01.
+  use integer math for this, to preserve precision}
+  dec(i, 116444736000000000);
+  result := (i / 10000000);
+end;
+
+
+
 function unixtimefloat:float;
 const
   margin = 0.0012;
 var
   f,g,h:float;
 begin
+  if not btimenowin8 then begin
+    if not win8inited then initwin8;
+    if assigned(@GetSystemTimePreciseAsFileTime) then begin
+      result := unixtimefloat_win8;
+      exit;
+    end;  
+  end;
+
   result := monotimefloat+timefloatbias;
   f := result-unixtimefloat_systemtime;
   if ((f > ticks_freq2+margin) or (f < -margin)) or (timefloatbias = 0) then begin
@@ -723,10 +763,19 @@ begin
 
 end;
 
+procedure beginhightimerrate;
+begin
+  {$ifdef mswindows}timebeginperiod(1);{$endif}
+end;
+
+procedure endhightimerrate;
+begin
+  {$ifdef mswindows}timeendperiod(1);{$endif}
+end;
 
 procedure init;
 begin
-  {$ifdef win32}timebeginperiod(1);{$endif} //ensure stable unchanging clock
+  {$ifdef btimehighrate}beginhightimerrate;{$endif}
   fillchar(mmtime_driftavg,sizeof(mmtime_driftavg),0);
   settimebias := 0;
   gettimezone;