replace internal uses of gettimeofday with monotonic time where appropriate. make...
[lcore.git] / btime.pas
index 8218e6415a97bf63f25a278f6c75ceb0ad95280c..a3428e8546c6e39d0a52e1b2d92ee0e1d352df8e 100644 (file)
--- a/btime.pas
+++ b/btime.pas
@@ -12,6 +12,9 @@ unit btime;
 {$ifdef fpc}\r
   {$mode delphi}\r
 {$endif}\r
+\r
+{$include lcoreconfig.inc}\r
+\r
 interface\r
 \r
 {$ifdef mswindows}\r
@@ -33,6 +36,7 @@ var
   tickcount:integer;\r
   settimebias:tunixtimeint;\r
   performancecountfreq:extended;\r
+  btimenowin8:boolean;\r
 \r
 function irctimefloat:float;\r
 function irctimeint:tunixtimeint;\r
@@ -57,6 +61,9 @@ function timestrshort(i:tunixtimeint):string;    // Wed Aug 15 16:21:09 2012
 function timestriso(i:tunixtimeint):string;      // 2012-08-15 16:21:09\r
 function timestrisoutc(i:float):string;          // 2012-08-15T14:21:09.255553Z\r
 \r
+procedure beginhightimerrate;\r
+procedure endhightimerrate;\r
+\r
 {$ifdef mswindows}\r
 function unixtimefloat_systemtime:float;\r
 {$endif}\r
@@ -114,11 +121,10 @@ uses
     {$ifdef VER1_0}\r
       linux,\r
     {$else}\r
+      {$ifdef linux}linux,{$endif} //for clock_gettime\r
+      {$ifdef freebsd}freebsd,{$endif} //for clock_gettime\r
       baseunix,unix,unixutil,sockets, {unixutil and sockets needed by unixstuff.inc on some compiler versions}\r
     {$endif}\r
-    {$ifdef linux}\r
-      dl,\r
-    {$endif}\r
   {$else}\r
     windows,unitsettc,mmsystem,\r
   {$endif}\r
@@ -169,49 +175,37 @@ end;
 function unixtimefloat:float;\r
 var\r
   tv:ttimeval;\r
+  sec:tunixtimeint;\r
 begin\r
   gettimeofday(tv);\r
-  result := tv.tv_sec+(tv.tv_usec/1000000);\r
+  sec := tv.tv_sec;\r
+  {$ifndef cpu64}\r
+  if (sec < -1) then inc(sec,$100000000); //tv_sec is 32 bits. allow -1 for invalid result\r
+  {$endif}\r
+  result := sec+(tv.tv_usec/1000000);\r
 end;\r
 \r
-{$ifdef linux}\r
-  {$define monotimefloat_implemented}\r
-  const\r
-    CLOCK_MONOTONIC = 1;\r
-  type \r
-    ptimeval = ^ttimeval;\r
-    tclock_gettime = function(clk_id: integer; tp: ptimeval): integer; cdecl;\r
+{$ifdef linux}{$define have_clock_gettime}{$endif}\r
+{$ifdef freebsd}{$define have_clock_gettime}{$endif}\r
 \r
-  var\r
-    librt_handle:pointer;\r
-    librt_inited:boolean;\r
-    clock_gettime: tclock_gettime;\r
+{$ifdef have_clock_gettime}\r
+  {$define monotimefloat_implemented}\r
 \r
   function monotimefloat:float;\r
   var\r
-    ts: ttimeval;\r
+    ts: ttimespec;\r
   begin\r
-    if not librt_inited then begin\r
-      librt_inited := true;\r
-      clock_gettime := nil;\r
-      librt_handle := dlopen('librt.so', RTLD_LAZY);\r
-      if assigned(librt_handle) then begin\r
-        clock_gettime := dlsym(librt_handle, 'clock_gettime');\r
-      end;\r
-    end;\r
-    if assigned(clock_gettime) then begin\r
-      if clock_gettime(CLOCK_MONOTONIC, @ts) = 0 then begin\r
-        //note this really returns nanoseconds\r
-        result := ts.tv_sec + ts.tv_usec / 1000000000.0;\r
-        exit;\r
-      end;\r
+    if clock_gettime(CLOCK_MONOTONIC, @ts) = 0 then begin\r
+      //note this really returns nanoseconds\r
+      result := ts.tv_sec + ts.tv_nsec / 1000000000.0;\r
+      exit;\r
     end;\r
     //fallback\r
     result := unixtimefloat;\r
   end;\r
 \r
 \r
-{$endif} {linux}\r
+{$endif}\r
 \r
 {$ifdef darwin} {mac OS X}\r
 {$define monotimefloat_implemented}\r
@@ -256,9 +250,14 @@ end;
 function unixtimeint:tunixtimeint;\r
 var\r
   tv:ttimeval;\r
+  sec:tunixtimeint;\r
 begin\r
   gettimeofday(tv);\r
-  result := tv.tv_sec;\r
+  sec := tv.tv_sec;\r
+  {$ifndef cpu64}\r
+  if (sec < 0) then inc(sec,$100000000); //tv_sec is 32 bits\r
+  {$endif}\r
+  result := sec;\r
 end;\r
 \r
 {------------------------------ end of *nix/freepascal section}\r
@@ -592,10 +591,12 @@ const
 var\r
   f,g,h:float;\r
 begin\r
-  if not win8inited then initwin8;\r
-  if assigned(@GetSystemTimePreciseAsFileTime) then begin\r
-    result := unixtimefloat_win8;\r
-    exit;\r
+  if not btimenowin8 then begin\r
+    if not win8inited then initwin8;\r
+    if assigned(@GetSystemTimePreciseAsFileTime) then begin\r
+      result := unixtimefloat_win8;\r
+      exit;\r
+    end;  \r
   end;\r
 \r
   result := monotimefloat+timefloatbias;\r
@@ -762,10 +763,19 @@ begin
 \r
 end;\r
 \r
+procedure beginhightimerrate;\r
+begin\r
+  {$ifdef mswindows}timebeginperiod(1);{$endif}\r
+end;\r
+\r
+procedure endhightimerrate;\r
+begin\r
+  {$ifdef mswindows}timeendperiod(1);{$endif}\r
+end;\r
 \r
 procedure init;\r
 begin\r
-  {$ifdef mswindows}timebeginperiod(1);{$endif} //ensure stable unchanging clock\r
+  {$ifdef btimehighrate}beginhightimerrate;{$endif}\r
   fillchar(mmtime_driftavg,sizeof(mmtime_driftavg),0);\r
   settimebias := 0;\r
   gettimezone;\r