- Timestamp:
- Jul 2, 2009 1:46:41 PM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Additions/common/VBoxService/VBoxServiceTimeSync.cpp
r21158 r21160 124 124 /** @see pg_vboxservice_timesync */ 125 125 static uint32_t g_TimeSyncMaxLatency = 250; 126 /** The threshold at which we will just set the time instead of trying to 127 * adjust it. Milliseconds. */ 128 static 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. */ 131 static bool volatile g_fTimeSyncSetNext = false; 132 133 /** Current error count. Used to knowing when to bitch and when not to. */ 134 static uint32_t g_cTimeSyncErrors = 0; 126 135 127 136 /** The semaphore we're blocking on. */ … … 165 174 rc = VBoxServiceArgUInt32(argc, argv, "", pi, 166 175 &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 167 185 return rc; 168 186 } … … 243 261 244 262 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 */ 270 static 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 */ 343 static 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 */ 363 static 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 245 412 /** @copydoc VBOXSERVICE::pfnWorker */ 246 413 DECLCALLBACK(int) VBoxServiceTimeSyncWorker(bool volatile *pfShutdown) … … 258 425 * The Work Loop. 259 426 */ 260 unsigned cErrors = 0;261 427 for (;;) 262 428 { … … 273 439 if (RT_FAILURE(rc2)) 274 440 { 275 if ( cErrors++ < 10)441 if (g_cTimeSyncErrors++ < 10) 276 442 VBoxServiceError("VbglR3GetHostTime failed; rc2=%Rrc\n", rc2); 277 443 break; … … 307 473 } 308 474 309 /** @todo move the adjustment code into two new functions, too much code310 * here. */311 475 uint32_t AbsDriftMilli = RTTimeSpecGetMilli(&AbsDrift); 312 476 if (AbsDriftMilli > MinAdjust) 313 477 { 314 478 /* 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. 318 483 */ 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)) 324 488 { 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); 376 491 } 377 else378 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 else391 # endif392 {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 DEBUG404 if (g_cVerbosity >= 3)405 VBoxServiceVerbose(2, " new time %s\n",406 RTTimeToString(RTTimeExplode(&Time, RTTimeNow(&Tmp)), sz, sizeof(sz)));407 # endif408 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 */417 492 } 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(); 425 495 break; 426 496 } … … 428 498 RTThreadSleep(1000); 429 499 } while (--cTries > 0); 500 501 /* Clear the set-next/set-start flag. */ 502 g_fTimeSyncSetNext = false; 430 503 431 504 /* … … 499 572 /* pszUsage. */ 500 573 "[--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]" 502 576 , 503 577 /* pszOptions. */ … … 512 586 " --timesync-max-latency The max host timer query latency to accept.\n" 513 587 " 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" 514 593 , 515 594 /* methods */
Note:
See TracChangeset
for help on using the changeset viewer.