VirtualBox

Changeset 21160 in vbox for trunk


Ignore:
Timestamp:
Jul 2, 2009 1:46:41 PM (16 years ago)
Author:
vboxsync
Message:

VBoxServiceTimeSync.cpp: Split up the code doing the platform specific adjusting. Added the missing time adjustment cancellation when falling back on SetSystemTime. Added --timesync-set-start and --timesync-set-threshold.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Additions/common/VBoxService/VBoxServiceTimeSync.cpp

    r21158 r21160  
    124124/** @see pg_vboxservice_timesync */
    125125static uint32_t g_TimeSyncMaxLatency = 250;
     126/** The threshold at which we will just set the time instead of trying to
     127 *  adjust it. Milliseconds. */
     128static uint32_t g_TimeSyncSetThreshold = 20*60*1000;
     129/** Whether the next adjustment should just set the time instead of trying to
     130 * adjust it. This is used to implement --timesync-set-start.  */
     131static bool volatile g_fTimeSyncSetNext = false;
     132
     133/** Current error count. Used to knowing when to bitch and when not to. */
     134static uint32_t g_cTimeSyncErrors = 0;
    126135
    127136/** The semaphore we're blocking on. */
     
    165174        rc = VBoxServiceArgUInt32(argc, argv, "", pi,
    166175                                  &g_TimeSyncMaxLatency, 1, 3600000);
     176    else if (!strcmp(argv[*pi], "--timesync-set-threshold"))
     177        rc = VBoxServiceArgUInt32(argc, argv, "", pi,
     178                                  &g_TimeSyncSetThreshold, 0, 7*24*60*1000); /* a week */
     179    else if (!strcmp(argv[*pi], "--timesync-set-start"))
     180    {
     181        g_fTimeSyncSetNext = true;
     182        rc = VINF_SUCCESS;
     183    }
     184
    167185    return rc;
    168186}
     
    243261
    244262
     263/**
     264 * Try adjust the time using adjtime or similar.
     265 *
     266 * @returns true on success, false on failure.
     267 *
     268 * @param   pDrift          The time adjustment.
     269 */
     270static bool VBoxServiceTimeSyncAdjust(PCRTTIMESPEC pDrift)
     271{
     272#ifdef RT_OS_WINDOWS
     273/** @todo r=bird: NT4 doesn't have GetSystemTimeAdjustment. */
     274    DWORD dwWinTimeAdjustment, dwWinNewTimeAdjustment, dwWinTimeIncrement;
     275    BOOL  fWinTimeAdjustmentDisabled;
     276    if (GetSystemTimeAdjustment(&dwWinTimeAdjustment, &dwWinTimeIncrement, &fWinTimeAdjustmentDisabled))
     277    {
     278        DWORD dwDiffMax = g_dwWinTimeAdjustment * 0.50;
     279        DWORD dwDiffNew =   dwWinTimeAdjustment * 0.10;
     280
     281        if (RTTimeSpecGetMilli(pDrift) > 0)
     282        {
     283            dwWinNewTimeAdjustment = dwWinTimeAdjustment + dwDiffNew;
     284            if (dwWinNewTimeAdjustment > (g_dwWinTimeAdjustment + dwDiffMax))
     285            {
     286                dwWinNewTimeAdjustment = g_dwWinTimeAdjustment + dwDiffMax;
     287                dwDiffNew = dwDiffMax;
     288            }
     289        }
     290        else
     291        {
     292            dwWinNewTimeAdjustment = dwWinTimeAdjustment - dwDiffNew;
     293            if (dwWinNewTimeAdjustment < (g_dwWinTimeAdjustment - dwDiffMax))
     294            {
     295                dwWinNewTimeAdjustment = g_dwWinTimeAdjustment - dwDiffMax;
     296                dwDiffNew = dwDiffMax;
     297            }
     298        }
     299
     300        VBoxServiceVerbose(3, "Windows time adjustment: Drift=%lldms\n", RTTimeSpecGetMilli(pDrift));
     301        VBoxServiceVerbose(3, "Windows time adjustment: OrgTA=%ld, CurTA=%ld, NewTA=%ld, DiffNew=%ld, DiffMax=%ld\n",
     302                           g_dwWinTimeAdjustment, dwWinTimeAdjustment, dwWinNewTimeAdjustment, dwDiffNew, dwDiffMax);
     303        if (SetSystemTimeAdjustment(dwWinNewTimeAdjustment, FALSE /* Periodic adjustments enabled. */))
     304        {
     305            g_cTimeSyncErrors = 0;
     306            return true;
     307        }
     308
     309        if (g_cTimeSyncErrors++ < 10)
     310             VBoxServiceError("SetSystemTimeAdjustment failed, error=%u\n", GetLastError());
     311    }
     312    else if (g_cTimeSyncErrors++ < 10)
     313        VBoxServiceError("GetSystemTimeAdjustment failed, error=%ld\n", GetLastError());
     314
     315#elif defined(RT_OS_OS2)
     316    /* No API for doing gradual time adjustments. */
     317
     318#else /* PORTME */
     319    /*
     320     * Try use adjtime(), most unix-like systems have this.
     321     */
     322    struct timeval tv;
     323    RTTimeSpecGetTimeval(pDrift, &tv);
     324    if (adjtime(&tv, NULL) == 0)
     325    {
     326        if (g_cVerbosity >= 1)
     327            VBoxServiceVerbose(1, "adjtime by %RDtimespec\n", pDrift);
     328        g_cTimeSyncErrors = 0;
     329        return true;
     330    }
     331#endif
     332
     333    /* failed */
     334    return false;
     335}
     336
     337
     338/**
     339 * Cancels any pending time adjustment.
     340 *
     341 * Called when we've caught up and before calls to VBoxServiceTimeSyncSet.
     342 */
     343static void VBoxServiceTimeSyncCancelAdjust(void)
     344{
     345#ifdef RT_OS_WINDOWS
     346    if (SetSystemTimeAdjustment(0, TRUE /* Periodic adjustments disabled. */))
     347        VBoxServiceVerbose(3, "Windows Time Adjustment is now disabled.\n");
     348    else if (g_cTimeSyncErrors++ < 10)
     349        VBoxServiceError("SetSystemTimeAdjustment(,disable) failed, error=%u\n", GetLastError());
     350#endif /* !RT_OS_WINDOWS */
     351}
     352
     353
     354/**
     355 * Try adjust the time using adjtime or similar.
     356 *
     357 * @returns true on success, false on failure.
     358 *
     359 * @param   pDrift              The time adjustment.
     360 * @param   pHostNow            The host time at the time of the host query.
     361 *                              REMOVE THIS ARGUMENT!
     362 */
     363static void VBoxServiceTimeSyncSet(PCRTTIMESPEC pDrift, PCRTTIMESPEC pHostNow)
     364{
     365    /*
     366     * Query the current time, add the adjustment, then try it.
     367     */
     368#ifdef RT_OS_WINDOWS
     369/** @todo r=bird: Get current time and add the adjustment, the host time is
     370 *                stale by now. */
     371    FILETIME ft;
     372    RTTimeSpecGetNtFileTime(pHostNow, &ft);
     373    SYSTEMTIME st;
     374    if (FileTimeToSystemTime(&ft, &st))
     375    {
     376        if (!SetSystemTime(&st))
     377            VBoxServiceError("SetSystemTime failed, error=%u\n", GetLastError());
     378    }
     379    else
     380        VBoxServiceError("Cannot convert system times, error=%u\n", GetLastError());
     381
     382#else  /* !RT_OS_WINDOWS */
     383    struct timeval tv;
     384    errno = 0;
     385    if (!gettimeofday(&tv, NULL))
     386    {
     387        RTTIMESPEC Tmp;
     388        RTTimeSpecAdd(RTTimeSpecSetTimeval(&Tmp, &tv), pDrift);
     389        if (!settimeofday(RTTimeSpecGetTimeval(&Tmp, &tv), NULL))
     390        {
     391            char    sz[64];
     392            RTTIME  Time;
     393            if (g_cVerbosity >= 1)
     394                VBoxServiceVerbose(1, "settimeofday to %s\n",
     395                                   RTTimeToString(RTTimeExplode(&Time, &Tmp), sz, sizeof(sz)));
     396# ifdef DEBUG
     397            if (g_cVerbosity >= 3)
     398                VBoxServiceVerbose(2, "       new time %s\n",
     399                                   RTTimeToString(RTTimeExplode(&Time, RTTimeNow(&Tmp)), sz, sizeof(sz)));
     400# endif
     401            g_cTimeSyncErrors = 0;
     402        }
     403        else if (g_cTimeSyncErrors++ < 10)
     404            VBoxServiceError("settimeofday failed; errno=%d: %s\n", errno, strerror(errno));
     405    }
     406    else if (g_cTimeSyncErrors++ < 10)
     407        VBoxServiceError("gettimeofday failed; errno=%d: %s\n", errno, strerror(errno));
     408#endif /* !RT_OS_WINDOWS */
     409}
     410
     411
    245412/** @copydoc VBOXSERVICE::pfnWorker */
    246413DECLCALLBACK(int) VBoxServiceTimeSyncWorker(bool volatile *pfShutdown)
     
    258425     * The Work Loop.
    259426     */
    260     unsigned cErrors = 0;
    261427    for (;;)
    262428    {
     
    273439            if (RT_FAILURE(rc2))
    274440            {
    275                 if (cErrors++ < 10)
     441                if (g_cTimeSyncErrors++ < 10)
    276442                    VBoxServiceError("VbglR3GetHostTime failed; rc2=%Rrc\n", rc2);
    277443                break;
     
    307473                }
    308474
    309 /** @todo move the adjustment code into two new functions, too much code
    310  *        here. */
    311475                uint32_t AbsDriftMilli = RTTimeSpecGetMilli(&AbsDrift);
    312476                if (AbsDriftMilli > MinAdjust)
    313477                {
    314478                    /*
    315                      * The drift is too big, we have to make adjustments. :-/
    316                      * If we've got adjtime around, try that first - most
    317                      * *NIX systems have it. Fall back on settimeofday.
     479                     * Ok, the drift is above the threshold.
     480                     *
     481                     * Try a gradual adjustment first, if that fails or the drift is
     482                     * too big, fall back on just setting the time.
    318483                     */
    319 #ifdef RT_OS_WINDOWS
    320                     DWORD dwWinTimeAdjustment, dwWinNewTimeAdjustment, dwWinTimeIncrement;
    321                     BOOL  fWinTimeAdjustmentDisabled;
    322 /** @todo r=bird: NT4 doesn't have GetSystemTimeAdjustment. */
    323                     if (GetSystemTimeAdjustment(&dwWinTimeAdjustment, &dwWinTimeIncrement, &fWinTimeAdjustmentDisabled))
     484
     485                    if (    AbsDriftMilli > g_TimeSyncSetThreshold
     486                        ||  g_fTimeSyncSetNext
     487                        ||  !VBoxServiceTimeSyncAdjust(&Drift))
    324488                    {
    325                         DWORD dwDiffMax = g_dwWinTimeAdjustment * 0.50;
    326                         DWORD dwDiffNew =   dwWinTimeAdjustment * 0.10;
    327 
    328                         if (RTTimeSpecGetMilli(&Drift) > 0)
    329                         {
    330                             dwWinNewTimeAdjustment = dwWinTimeAdjustment + dwDiffNew;
    331                             if (dwWinNewTimeAdjustment > (g_dwWinTimeAdjustment + dwDiffMax))
    332                             {
    333                                 dwWinNewTimeAdjustment = g_dwWinTimeAdjustment + dwDiffMax;
    334                                 dwDiffNew = dwDiffMax;
    335                             }
    336                         }
    337                         else
    338                         {
    339                             dwWinNewTimeAdjustment = dwWinTimeAdjustment - dwDiffNew;
    340                             if (dwWinNewTimeAdjustment < (g_dwWinTimeAdjustment - dwDiffMax))
    341                             {
    342                                 dwWinNewTimeAdjustment = g_dwWinTimeAdjustment - dwDiffMax;
    343                                 dwDiffNew = dwDiffMax;
    344                             }
    345                         }
    346 
    347                         VBoxServiceVerbose(3, "Windows time adjustment: Drift=%lldms\n", RTTimeSpecGetMilli(&Drift));
    348                         VBoxServiceVerbose(3, "Windows time adjustment: OrgTA=%ld, CurTA=%ld, NewTA=%ld, DiffNew=%ld, DiffMax=%ld\n",
    349                                            g_dwWinTimeAdjustment, dwWinTimeAdjustment, dwWinNewTimeAdjustment, dwDiffNew, dwDiffMax);
    350 
    351                         /* Is AbsDrift way too big? Then a minimum adjustment via SetSystemTimeAdjustment() would take ages.
    352                            So set the time in a hard manner. */
    353                         if (AbsDriftMilli > (60 * 1000 * 20)) /** @todo 20 minutes here hardcoded here. Needs configurable parameter later. */
    354                         {
    355                             VBoxServiceVerbose(3, "Windows time adjustment: Setting system time directly.\n");
    356 
    357 /** @todo r=bird: What about canceling any pending time adjustment? */
    358 /** @todo r=bird: Get current time and add the adjustment, the host time is
    359  *                stale by now. */
    360                             FILETIME ft;
    361                             RTTimeSpecGetNtFileTime(&HostNow, &ft);
    362                             SYSTEMTIME st;
    363                             if (FileTimeToSystemTime(&ft, &st))
    364                             {
    365                                 if (!SetSystemTime(&st))
    366                                     VBoxServiceError("SetSystemTime failed, error=%u\n", GetLastError());
    367                             }
    368                             else
    369                                 VBoxServiceError("Cannot convert system times, error=%u\n", GetLastError());
    370                         }
    371                         else
    372                         {
    373                             if (!SetSystemTimeAdjustment(dwWinNewTimeAdjustment, FALSE /* Periodic adjustments enabled. */))
    374                                 VBoxServiceError("SetSystemTimeAdjustment failed, error=%u\n", GetLastError());
    375                         }
     489                        VBoxServiceTimeSyncCancelAdjust();
     490                        VBoxServiceTimeSyncSet(&Drift, &HostNow);
    376491                    }
    377                     else
    378                         VBoxServiceError("GetSystemTimeAdjustment failed, error=%ld\n", GetLastError());
    379 
    380 #else  /* !RT_OS_WINDOWS */
    381                     struct timeval tv;
    382 # if !defined(RT_OS_OS2) /* PORTME */
    383                     RTTimeSpecGetTimeval(&Drift, &tv);
    384                     if (adjtime(&tv, NULL) == 0)
    385                     {
    386                         if (g_cVerbosity >= 1)
    387                             VBoxServiceVerbose(1, "adjtime by %RDtimespec\n", &Drift);
    388                         cErrors = 0;
    389                     }
    390                     else
    391 # endif
    392                     {
    393                         errno = 0;
    394                         if (!gettimeofday(&tv, NULL))
    395                         {
    396                             RTTIMESPEC Tmp;
    397                             RTTimeSpecAdd(RTTimeSpecSetTimeval(&Tmp, &tv), &Drift);
    398                             if (!settimeofday(RTTimeSpecGetTimeval(&Tmp, &tv), NULL))
    399                             {
    400                                 if (g_cVerbosity >= 1)
    401                                     VBoxServiceVerbose(1, "settimeofday to %s\n",
    402                                                        RTTimeToString(RTTimeExplode(&Time, &Tmp), sz, sizeof(sz)));
    403 # ifdef DEBUG
    404                                 if (g_cVerbosity >= 3)
    405                                     VBoxServiceVerbose(2, "       new time %s\n",
    406                                                        RTTimeToString(RTTimeExplode(&Time, RTTimeNow(&Tmp)), sz, sizeof(sz)));
    407 # endif
    408                                 cErrors = 0;
    409                             }
    410                             else if (cErrors++ < 10)
    411                                 VBoxServiceError("settimeofday failed; errno=%d: %s\n", errno, strerror(errno));
    412                         }
    413                         else if (cErrors++ < 10)
    414                             VBoxServiceError("gettimeofday failed; errno=%d: %s\n", errno, strerror(errno));
    415                     }
    416 #endif /* !RT_OS_WINDOWS */
    417492                }
    418                 else /* The time delta is <= MinAdjust, so don't do anything here (anymore). */
    419                 {
    420 #ifdef RT_OS_WINDOWS
    421                     if (SetSystemTimeAdjustment(0, TRUE /* Periodic adjustments disabled. */))
    422                         VBoxServiceVerbose(3, "Windows Time Adjustment is now disabled.\n");
    423 #endif /* !RT_OS_WINDOWS */
    424                 }
     493                else
     494                    VBoxServiceTimeSyncCancelAdjust();
    425495                break;
    426496            }
     
    428498            RTThreadSleep(1000);
    429499        } while (--cTries > 0);
     500
     501        /* Clear the set-next/set-start flag. */
     502        g_fTimeSyncSetNext = false;
    430503
    431504        /*
     
    499572    /* pszUsage. */
    500573    "[--timesync-interval <ms>] [--timesync-min-adjust <ms>] "
    501     "[--timesync-latency-factor <x>] [--time-sync-max-latency <ms>]"
     574    "[--timesync-latency-factor <x>] [--timesync-max-latency <ms>]"
     575    "[--timesync-set-threshold <ms>] [--timesync-set-start]"
    502576    ,
    503577    /* pszOptions. */
     
    512586    "    --timesync-max-latency     The max host timer query latency to accept.\n"
    513587    "                        The default is 250 ms.\n"
     588    "    --timesync-set-threshold   The absolute drift threshold, given as\n"
     589    "                        milliseconds, where to start setting the time instead\n"
     590    "                        of trying to adjust it. The default is 20 min.\n"
     591    "    --timesync-set-start       Set the time when starting the time sync\n"
     592    "                        service.\n"
    514593    ,
    515594    /* methods */
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette