LCOV - code coverage report
Current view: directory - src/shared/platform/win - nacl_time.c (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 205 136 66.3 %
Date: 2014-09-25 Functions: 0 0 -

       1                 : /*
       2                 :  * Copyright (c) 2012 The Native Client Authors. All rights reserved.
       3                 :  * Use of this source code is governed by a BSD-style license that can be
       4                 :  * found in the LICENSE file.
       5                 :  */
       6                 : 
       7                 : /*
       8                 :  * NaCl Server Runtime time abstraction layer.
       9                 :  * This is the host-OS-dependent implementation.
      10                 :  */
      11                 : 
      12                 : #include <windows.h>
      13                 : #include <mmsystem.h>
      14                 : #include <sys/timeb.h>
      15                 : #include <time.h>
      16                 : 
      17                 : #include "native_client/src/include/nacl_macros.h"
      18                 : #include "native_client/src/shared/platform/nacl_time.h"
      19                 : #include "native_client/src/shared/platform/win/nacl_time_types.h"
      20                 : 
      21                 : #include "native_client/src/shared/platform/nacl_log.h"
      22                 : #include "native_client/src/shared/platform/nacl_sync.h"
      23                 : #include "native_client/src/shared/platform/nacl_sync_checked.h"
      24                 : #include "native_client/src/shared/platform/win/xlate_system_error.h"
      25                 : 
      26                 : #define kMillisecondsPerSecond 1000
      27                 : #define kMicrosecondsPerMillisecond 1000
      28                 : #define kMicrosecondsPerSecond 1000000
      29                 : #define kCalibrateTimeoutMs 1000
      30                 : #define kCoarseMks 10
      31                 : 
      32                 : /*
      33                 :  * Here's some usefull links related to timing on Windows:
      34                 :  * http://svn.wildfiregames.com/public/ps/trunk/docs/timing_pitfalls.pdf
      35                 :  * Rob Arnold (mozilla) blog:
      36                 :  * http://robarnold.org/measuring-performance/
      37                 :  * https://bugzilla.mozilla.org/show_bug.cgi?id=563082
      38                 :  */
      39                 : 
      40                 : /*
      41                 :  * To get a 1ms resolution time-of-day clock, we have to jump thrugh
      42                 :  * some hoops.  This approach has the following defect: ntp
      43                 :  * adjustments will be nullified, until the difference is larger than
      44                 :  * a recalibration threshold (below), at which point time may jump
      45                 :  * (until we introduce a mechanism to slowly phase in time changes).
      46                 :  * A system suspend/resume will generate a clock recalibration with
      47                 :  * high probability.
      48                 :  *
      49                 :  * The algorithm is as follows:
      50                 :  *
      51                 :  * At start up, we sample the system time (coarse timer) via
      52                 :  * GetSystemTimeAsFileTime until it changes.  At the state transition,
      53                 :  * we record the value of the time-after-boot counter via timeGetTime.
      54                 :  *
      55                 :  * At subsequent gettimeofday syscall, we query the system time via
      56                 :  * GetSystemTimeAsFileTime.  This is converted to an
      57                 :  * expected/corresponding return value from timeGetTime.  The
      58                 :  * difference from the actual return value is the time that elapsed
      59                 :  * since the state transition of the system time counter, and we add
      60                 :  * that difference (assuming it is smaller than the max-drift
      61                 :  * threshold) to the system time and return that (minus the Unix
      62                 :  * epoch, etc), as the result of the gettimeofday syscall.  If the
      63                 :  * difference is larger than the max-drift threshold, we invoke the
      64                 :  * calibration function.
      65                 :  */
      66                 : 
      67                 : struct NaClTimeState g_NaCl_time_state;
      68                 : 
      69                 : static uint32_t const kMaxMillsecondDriftBeforeRecalibration = 60;
      70                 : static uint32_t const kMaxCalibrationDiff = 4;
      71                 : 
      72                 : /*
      73                 :  * Translate Windows system time to milliseconds.  Windows System time
      74                 :  * is in units of 100nS.  Windows time is in 100e-9s == 1e-7s, and we
      75                 :  * want units of 1e-3s, so ms/wt = 1e-4.
      76                 :  */
      77              18 : static uint64_t NaClFileTimeToMs(FILETIME *ftp) {
      78                 :   ULARGE_INTEGER t;
      79              18 :   t.u.HighPart = ftp->dwHighDateTime;
      80              18 :   t.u.LowPart = ftp->dwLowDateTime;
      81              18 :   return t.QuadPart / NACL_100_NANOS_PER_MILLI;
      82              18 : }
      83                 : 
      84                 : #define kCpuInfoPageSize 4  /* Not in bytes, but in sizeof(uint32_t). */
      85                 : 
      86              18 : static char* CPU_GetBrandString(void) {
      87              18 :   const int kBaseInfoPage = 0x80000000;
      88              18 :   const int kCpuBrandStringPage1 = 0x80000002;
      89              18 :   const int kCpuBrandStringPage2 = 0x80000003;
      90              18 :   const int kCpuBrandStringPage3 = 0x80000004;
      91                 : 
      92                 :   static int cpu_info[kCpuInfoPageSize * 4] = {0};
      93              18 :   __cpuid(cpu_info, kBaseInfoPage);
      94              18 :   if (cpu_info[0] < kCpuBrandStringPage3)
      95               0 :     return "";
      96                 : 
      97              18 :   __cpuid(&cpu_info[0], kCpuBrandStringPage1);
      98              18 :   __cpuid(&cpu_info[kCpuInfoPageSize], kCpuBrandStringPage2);
      99              18 :   __cpuid(&cpu_info[kCpuInfoPageSize * 2], kCpuBrandStringPage3);
     100              18 :   return (char*)cpu_info;
     101              18 : }
     102                 : 
     103               0 : static int CPU_GetFamily(void) {
     104               0 :   const int kFeaturesPage = 1;
     105                 :   int cpu_info[kCpuInfoPageSize];
     106               0 :   __cpuid(cpu_info, kFeaturesPage);
     107               0 :   return (cpu_info[0] >> 8) & 0xf;
     108               0 : }
     109                 : 
     110                 : /*
     111                 :  * Returns 1 if success, 0 in case of QueryPerformanceCounter is not supported.
     112                 :  *
     113                 :  * Calibration is done as described above.
     114                 :  *
     115                 :  * To ensure that the calibration is accurate, we interleave sampling
     116                 :  * the microsecond resolution counter via QueryPerformanceCounter with the 1
     117                 :  * millisecond resolution system clock via GetSystemTimeAsFileTime.
     118                 :  * When we see the edge transition where the system clock ticks, we
     119                 :  * compare the before and after microsecond counter values.  If it is
     120                 :  * within a calibration threshold (kMaxCalibrationDiff), then we
     121                 :  * record the instantaneous system time (1 msresolution) and the
     122                 :  * 64-bit counter value (~0.5 mks reslution).  Since we have a before and
     123                 :  * after counter value, we interpolate it to get the "average" counter
     124                 :  * value to associate with the system time.
     125                 :  */
     126              18 : static int NaClCalibrateWindowsClockQpc(struct NaClTimeState *ntsp) {
     127                 :   FILETIME  ft_start;
     128                 :   FILETIME  ft_prev;
     129                 :   FILETIME  ft_now;
     130                 :   LARGE_INTEGER  counter_before;
     131                 :   LARGE_INTEGER  counter_after;
     132                 :   int64_t  counter_diff;
     133                 :   int64_t  counter_diff_ms;
     134                 :   uint64_t end_of_calibrate;
     135                 :   int sys_time_changed;
     136              18 :   int calibration_success = 0;
     137                 : 
     138              18 :   NaClLog(5, "Entered NaClCalibrateWindowsClockQpc\n");
     139                 : 
     140              18 :   GetSystemTimeAsFileTime(&ft_start);
     141              18 :   ft_prev = ft_start;
     142              18 :   end_of_calibrate = NaClFileTimeToMs(&ft_start) + kCalibrateTimeoutMs;
     143                 : 
     144                 :   do {
     145              18 :     if (!QueryPerformanceCounter(&counter_before))
     146               0 :       return 0;
     147              18 :     GetSystemTimeAsFileTime(&ft_now);
     148              18 :     if (!QueryPerformanceCounter(&counter_after))
     149               0 :       return 0;
     150                 : 
     151              18 :     counter_diff = counter_after.QuadPart - counter_before.QuadPart;
     152                 :     counter_diff_ms =
     153              18 :         (counter_diff * kMillisecondsPerSecond) / ntsp->qpc_frequency;
     154                 :     sys_time_changed = (ft_now.dwHighDateTime != ft_prev.dwHighDateTime) ||
     155              18 :         (ft_now.dwLowDateTime != ft_prev.dwLowDateTime);
     156                 : 
     157                 :     if ((counter_diff >= 0) &&
     158                 :         (counter_diff_ms <= kMaxCalibrationDiff) &&
     159              18 :         sys_time_changed) {
     160              18 :       calibration_success = 1;
     161              18 :       break;
     162                 :     }
     163              18 :     if (sys_time_changed)
     164               0 :       ft_prev = ft_now;
     165              18 :   } while (NaClFileTimeToMs(&ft_now) < end_of_calibrate);
     166                 : 
     167              18 :   ntsp->system_time_start_ms = NaClFileTimeToMs(&ft_now);
     168              18 :   ntsp->qpc_start = counter_before.QuadPart + (counter_diff / 2);
     169              18 :   ntsp->last_qpc = counter_after.QuadPart;
     170                 : 
     171                 :   NaClLog(5,
     172                 :           "Leaving NaClCalibrateWindowsClockQpc : %d\n",
     173              18 :           calibration_success);
     174              18 :   return calibration_success;
     175              18 : }
     176                 : 
     177                 : /*
     178                 :  * Calibration is done as described above.
     179                 :  *
     180                 :  * To ensure that the calibration is accurate, we interleave sampling
     181                 :  * the millisecond resolution counter via timeGetTime with the 10-55
     182                 :  * millisecond resolution system clock via GetSystemTimeAsFileTime.
     183                 :  * When we see the edge transition where the system clock ticks, we
     184                 :  * compare the before and after millisecond counter values.  If it is
     185                 :  * within a calibration threshold (kMaxCalibrationDiff), then we
     186                 :  * record the instantaneous system time (10-55 msresolution) and the
     187                 :  * 32-bit counter value (1ms reslution).  Since we have a before and
     188                 :  * after counter value, we interpolate it to get the "average" counter
     189                 :  * value to associate with the system time.
     190                 :  */
     191               0 : static void NaClCalibrateWindowsClockMu(struct NaClTimeState *ntsp) {
     192                 :   FILETIME  ft_start;
     193                 :   FILETIME  ft_now;
     194                 :   DWORD     ms_counter_before;
     195                 :   DWORD     ms_counter_after;
     196                 :   uint32_t  ms_counter_diff;
     197                 : 
     198               0 :   NaClLog(5, "Entered NaClCalibrateWindowsClockMu\n");
     199               0 :   GetSystemTimeAsFileTime(&ft_start);
     200               0 :   ms_counter_before = timeGetTime();
     201                 :   for (;;) {
     202               0 :     GetSystemTimeAsFileTime(&ft_now);
     203               0 :     ms_counter_after = timeGetTime();
     204               0 :     ms_counter_diff = ms_counter_after - (uint32_t) ms_counter_before;
     205               0 :     NaClLog(5, "ms_counter_diff %u\n", ms_counter_diff);
     206                 :     if (ms_counter_diff <= kMaxCalibrationDiff &&
     207                 :         (ft_now.dwHighDateTime != ft_start.dwHighDateTime ||
     208               0 :          ft_now.dwLowDateTime != ft_start.dwLowDateTime)) {
     209               0 :       break;
     210                 :     }
     211               0 :     ms_counter_before = ms_counter_after;
     212               0 :   }
     213               0 :   ntsp->system_time_start_ms = NaClFileTimeToMs(&ft_now);
     214                 :   /*
     215                 :    * Average the counter values.  Note unsigned computation of
     216                 :    * ms_counter_diff, so that was mod 2**32 arithmetic, and the
     217                 :    * addition of half the difference is numerically correct, whereas
     218                 :    * (ms_counter_before + ms_counter_after)/2 is wrong due to
     219                 :    * overflow.
     220                 :    */
     221               0 :   ntsp->ms_counter_start = (DWORD) (ms_counter_before + (ms_counter_diff / 2));
     222                 : 
     223               0 :   NaClLog(5, "Leaving NaClCalibrateWindowsClockMu\n");
     224               0 : }
     225                 : 
     226               0 : void NaClAllowLowResolutionTimeOfDay(void) {
     227               0 :   g_NaCl_time_state.allow_low_resolution = 1;
     228               0 : }
     229                 : 
     230              18 : void NaClTimeInternalInit(struct NaClTimeState *ntsp) {
     231                 :   TIMECAPS    tc;
     232                 :   SYSTEMTIME  st;
     233                 :   FILETIME    ft;
     234                 :   LARGE_INTEGER qpc_freq;
     235                 : 
     236                 :   /*
     237                 :    * Maximize timer/Sleep resolution.
     238                 :    */
     239              18 :   timeGetDevCaps(&tc, sizeof tc);
     240                 : 
     241              18 :   if (ntsp->allow_low_resolution) {
     242                 :     /* Set resolution to max so we don't over-promise. */
     243               0 :     ntsp->wPeriodMin = tc.wPeriodMax;
     244               0 :   } else {
     245              18 :     ntsp->wPeriodMin = tc.wPeriodMin;
     246              18 :     timeBeginPeriod(ntsp->wPeriodMin);
     247              18 :     NaClLog(4, "NaClTimeInternalInit: timeBeginPeriod(%u)\n", ntsp->wPeriodMin);
     248                 :   }
     249              18 :   ntsp->time_resolution_ns = ntsp->wPeriodMin * NACL_NANOS_PER_MILLI;
     250                 : 
     251                 :   /*
     252                 :    * Compute Unix epoch start; calibrate high resolution clock.
     253                 :    */
     254              18 :   st.wYear = 1970;
     255              18 :   st.wMonth = 1;
     256              18 :   st.wDay = 1;
     257              18 :   st.wHour = 0;
     258              18 :   st.wMinute = 0;
     259              18 :   st.wSecond = 0;
     260              18 :   st.wMilliseconds = 0;
     261              18 :   SystemTimeToFileTime(&st, &ft);
     262              18 :   ntsp->epoch_start_ms = NaClFileTimeToMs(&ft);
     263                 :   NaClLog(4, "Unix epoch start is  %"NACL_PRIu64"ms in Windows epoch time\n",
     264              18 :           ntsp->epoch_start_ms);
     265                 : 
     266              18 :   NaClMutexCtor(&ntsp->mu);
     267                 : 
     268                 :   /*
     269                 :    * We don't actually grab the lock, since the module initializer
     270                 :    * should be called before going threaded.
     271                 :    */
     272              18 :   ntsp->can_use_qpc = 0;
     273              18 :   if (!ntsp->allow_low_resolution) {
     274              18 :     ntsp->can_use_qpc = QueryPerformanceFrequency(&qpc_freq);
     275                 :     /*
     276                 :      * On Athlon X2 CPUs (e.g. model 15) QueryPerformanceCounter is
     277                 :      * unreliable.  Fallback to low-res clock.
     278                 :      */
     279              18 :     if (strstr(CPU_GetBrandString(), "AuthenticAMD") && (CPU_GetFamily() == 15))
     280               0 :         ntsp->can_use_qpc = 0;
     281                 : 
     282                 :     NaClLog(4,
     283                 :             "CPU_GetBrandString->[%s] ntsp->can_use_qpc=%d\n",
     284                 :             CPU_GetBrandString(),
     285              18 :             ntsp->can_use_qpc);
     286                 : 
     287              18 :     if (ntsp->can_use_qpc) {
     288              18 :       ntsp->qpc_frequency = qpc_freq.QuadPart;
     289                 :       NaClLog(4, "qpc_frequency = %"NACL_PRId64" (counts/s)\n",
     290              18 :               ntsp->qpc_frequency);
     291              18 :       if (!NaClCalibrateWindowsClockQpc(ntsp))
     292               0 :         ntsp->can_use_qpc = 0;
     293                 :     }
     294              18 :     if (!ntsp->can_use_qpc)
     295               0 :       NaClCalibrateWindowsClockMu(ntsp);
     296                 :   }
     297              18 : }
     298                 : 
     299               4 : uint64_t NaClTimerResolutionNsInternal(struct NaClTimeState *ntsp) {
     300               4 :   return ntsp->time_resolution_ns;
     301               4 : }
     302                 : 
     303              13 : void NaClTimeInternalFini(struct NaClTimeState *ntsp) {
     304              13 :   NaClMutexDtor(&ntsp->mu);
     305              13 :   if (!ntsp->allow_low_resolution)
     306              13 :     timeEndPeriod(ntsp->wPeriodMin);
     307              13 : }
     308                 : 
     309              18 : void NaClTimeInit(void) {
     310              18 :   NaClTimeInternalInit(&g_NaCl_time_state);
     311              18 : }
     312                 : 
     313              13 : void NaClTimeFini(void) {
     314              13 :   NaClTimeInternalFini(&g_NaCl_time_state);
     315              13 : }
     316                 : 
     317               4 : uint64_t NaClTimerResolutionNanoseconds(void) {
     318               4 :   return NaClTimerResolutionNsInternal(&g_NaCl_time_state);
     319               4 : }
     320                 : 
     321                 : int NaClGetTimeOfDayInternQpc(struct nacl_abi_timeval *tv,
     322                 :                               struct NaClTimeState    *ntsp,
     323              16 :                               int allow_calibration) {
     324                 :   FILETIME  ft_now;
     325                 :   int64_t sys_now_mks;
     326                 :   LARGE_INTEGER qpc;
     327                 :   int64_t qpc_diff;
     328                 :   int64_t qpc_diff_mks;
     329                 :   int64_t qpc_now_mks;
     330                 :   int64_t drift_mks;
     331                 :   int64_t drift_ms;
     332                 : 
     333              16 :   NaClLog(5, "Entered NaClGetTimeOfDayInternQpc\n");
     334                 : 
     335              16 :   NaClXMutexLock(&ntsp->mu);
     336                 : 
     337              16 :   GetSystemTimeAsFileTime(&ft_now);
     338              16 :   QueryPerformanceCounter(&qpc);
     339              16 :   sys_now_mks = NaClFileTimeToMs(&ft_now) * kMicrosecondsPerMillisecond;
     340              16 :   NaClLog(5, " sys_now_mks = %"NACL_PRId64" (us)\n", sys_now_mks);
     341              16 :   qpc_diff = qpc.QuadPart - ntsp->qpc_start;
     342              16 :   NaClLog(5, " qpc_diff = %"NACL_PRId64" (counts)\n", qpc_diff);
     343                 :   /*
     344                 :    * Coarse qpc_now_mks to 10 microseconds resolution,
     345                 :    * to match the other platforms and not make a side-channel
     346                 :    * attack any easier than it needs to be.
     347                 :    */
     348                 :   qpc_diff_mks = ((qpc_diff * (kMicrosecondsPerSecond / kCoarseMks)) /
     349              16 :       ntsp->qpc_frequency) * kCoarseMks;
     350              16 :   NaClLog(5, " qpc_diff_mks = %"NACL_PRId64" (us)\n", qpc_diff_mks);
     351                 : 
     352                 :   qpc_now_mks = (ntsp->system_time_start_ms * kMicrosecondsPerMillisecond) +
     353              16 :       qpc_diff_mks;
     354                 :   NaClLog(5, " system_time_start_ms %"NACL_PRIu64"\n",
     355              16 :           ntsp->system_time_start_ms);
     356              16 :   NaClLog(5, " qpc_now_mks = %"NACL_PRId64" (us)\n", qpc_now_mks);
     357                 : 
     358              16 :   if ((qpc_diff < 0) || (qpc.QuadPart < ntsp->last_qpc)) {
     359               0 :     NaClLog(5, " need recalibration\n");
     360               0 :     if (allow_calibration) {
     361               0 :       NaClCalibrateWindowsClockQpc(ntsp);
     362               0 :       NaClXMutexUnlock(&ntsp->mu);
     363               0 :       return NaClGetTimeOfDayInternQpc(tv, ntsp, 0);
     364                 :     } else {
     365               0 :       NaClLog(5, " ... but using coarse, system time instead.\n");
     366                 :       /* use GetSystemTimeAsFileTime(), not QPC */
     367               0 :       qpc_now_mks = sys_now_mks;
     368                 :     }
     369                 :   }
     370              16 :   ntsp->last_qpc = qpc.QuadPart;
     371              16 :   drift_mks = sys_now_mks - qpc_now_mks;
     372              16 :   if (qpc_now_mks > sys_now_mks)
     373               6 :     drift_mks = qpc_now_mks - sys_now_mks;
     374                 : 
     375              16 :   drift_ms = drift_mks / kMicrosecondsPerMillisecond;
     376              16 :   NaClLog(5, " drift_ms = %"NACL_PRId64"\n", drift_ms);
     377                 : 
     378                 :   if (allow_calibration &&
     379              16 :       (drift_ms > kMaxMillsecondDriftBeforeRecalibration)) {
     380               0 :     NaClLog(5, "drift_ms recalibration\n");
     381               0 :     NaClCalibrateWindowsClockQpc(ntsp);
     382               0 :     NaClXMutexUnlock(&ntsp->mu);
     383               0 :     return NaClGetTimeOfDayInternQpc(tv, ntsp, 0);
     384                 :   }
     385                 : 
     386              16 :   NaClXMutexUnlock(&ntsp->mu);
     387                 : 
     388                 :   /* translate to unix time base */
     389                 :   qpc_now_mks = qpc_now_mks
     390              16 :       - ntsp->epoch_start_ms * kMicrosecondsPerMillisecond;
     391                 : 
     392                 :   tv->nacl_abi_tv_sec =
     393              16 :       (nacl_abi_time_t)(qpc_now_mks / kMicrosecondsPerSecond);
     394                 :   tv->nacl_abi_tv_usec =
     395              16 :       (nacl_abi_suseconds_t)(qpc_now_mks % kMicrosecondsPerSecond);
     396              16 :   return 0;
     397              16 : }
     398                 : 
     399                 : int NaClGetTimeOfDayIntern(struct nacl_abi_timeval *tv,
     400              16 :                            struct NaClTimeState    *ntsp) {
     401                 :   FILETIME  ft_now;
     402                 :   DWORD     ms_counter_now;
     403                 :   uint64_t  t_ms;
     404                 :   DWORD     ms_counter_at_ft_now;
     405                 :   uint32_t  ms_counter_diff;
     406                 :   uint64_t  unix_time_ms;
     407                 : 
     408              16 :   if (ntsp->can_use_qpc)
     409              16 :     return NaClGetTimeOfDayInternQpc(tv, ntsp, 1);
     410                 : 
     411               0 :   GetSystemTimeAsFileTime(&ft_now);
     412               0 :   ms_counter_now = timeGetTime();
     413               0 :   t_ms = NaClFileTimeToMs(&ft_now);
     414                 : 
     415               0 :   NaClXMutexLock(&ntsp->mu);
     416                 : 
     417               0 :   if (!ntsp->allow_low_resolution) {
     418                 :     NaClLog(5, "ms_counter_now       %"NACL_PRIu32"\n",
     419               0 :             (uint32_t) ms_counter_now);
     420               0 :     NaClLog(5, "t_ms                 %"NACL_PRId64"\n", t_ms);
     421                 :     NaClLog(5, "system_time_start_ms %"NACL_PRIu64"\n",
     422               0 :             ntsp->system_time_start_ms);
     423                 : 
     424                 :     ms_counter_at_ft_now = (DWORD)
     425                 :         (ntsp->ms_counter_start +
     426               0 :          (uint32_t) (t_ms - ntsp->system_time_start_ms));
     427                 : 
     428                 :     NaClLog(5, "ms_counter_at_ft_now %"NACL_PRIu32"\n",
     429               0 :             (uint32_t) ms_counter_at_ft_now);
     430                 : 
     431               0 :     ms_counter_diff = ms_counter_now - (uint32_t) ms_counter_at_ft_now;
     432                 : 
     433               0 :     NaClLog(5, "ms_counter_diff      %"NACL_PRIu32"\n", ms_counter_diff);
     434                 : 
     435               0 :     if (ms_counter_diff <= kMaxMillsecondDriftBeforeRecalibration) {
     436               0 :       t_ms = t_ms + ms_counter_diff;
     437               0 :     } else {
     438               0 :       NaClCalibrateWindowsClockMu(ntsp);
     439               0 :       t_ms = ntsp->system_time_start_ms;
     440                 :     }
     441                 : 
     442               0 :     NaClLog(5, "adjusted t_ms =      %"NACL_PRIu64"\n", t_ms);
     443                 :   }
     444                 : 
     445               0 :   unix_time_ms = t_ms - ntsp->epoch_start_ms;
     446                 : 
     447               0 :   NaClXMutexUnlock(&ntsp->mu);
     448                 : 
     449               0 :   NaClLog(5, "unix_time_ms  =      %"NACL_PRId64"\n", unix_time_ms);
     450                 :   /*
     451                 :    * Unix time is measured relative to a different epoch, Jan 1, 1970.
     452                 :    * See the module initialization for epoch_start_ms.
     453                 :    */
     454                 : 
     455               0 :   tv->nacl_abi_tv_sec = (nacl_abi_time_t) (unix_time_ms / 1000);
     456               0 :   tv->nacl_abi_tv_usec = (nacl_abi_suseconds_t) ((unix_time_ms % 1000) * 1000);
     457               0 :   return 0;
     458              16 : }
     459                 : 
     460              16 : int NaClGetTimeOfDay(struct nacl_abi_timeval *tv) {
     461              16 :   return NaClGetTimeOfDayIntern(tv, &g_NaCl_time_state);
     462              16 : }
     463                 : 
     464                 : int NaClNanosleep(struct nacl_abi_timespec const *req,
     465               4 :                   struct nacl_abi_timespec       *rem) {
     466                 :   DWORD                     sleep_ms;
     467                 :   uint64_t                  resolution;
     468               4 :   DWORD                     resolution_gap = 0;
     469                 : 
     470                 :   UNREFERENCED_PARAMETER(rem);
     471                 : 
     472                 :   /* round up from ns resolution to ms resolution */
     473                 :   /* TODO(bsy): report an error or loop if req->tv_sec does not fit in DWORD */
     474                 :   sleep_ms = ((DWORD) req->tv_sec * NACL_MILLIS_PER_UNIT +
     475               4 :               NACL_UNIT_CONVERT_ROUND(req->tv_nsec, NACL_NANOS_PER_MILLI));
     476                 : 
     477                 :   /* round up to minimum timer resolution */
     478               4 :   resolution = NaClTimerResolutionNanoseconds();
     479               4 :   NaClLog(4, "Resolution %"NACL_PRId64"\n", resolution);
     480               4 :   if (0 != resolution) {
     481               4 :     resolution = NACL_UNIT_CONVERT_ROUND(resolution, NACL_NANOS_PER_MILLI);
     482               4 :     resolution_gap = (DWORD) (sleep_ms % resolution);
     483               4 :     if (0 != resolution_gap) {
     484               0 :       resolution_gap = (DWORD) (resolution - resolution_gap);
     485                 :     }
     486                 :   }
     487               4 :   NaClLog(4, "Resolution gap %d\n", resolution_gap);
     488               4 :   sleep_ms += resolution_gap;
     489                 : 
     490               4 :   NaClLog(4, "Sleep(%d)\n", sleep_ms);
     491               4 :   Sleep(sleep_ms);
     492                 : 
     493               4 :   return 0;
     494               4 : }

Generated by: LCOV version 1.7