VirtualBox

source: vbox/trunk/src/VBox/Additions/common/VBoxService/VBoxServiceTimeSync.cpp@ 22586

Last change on this file since 22586 was 21218, checked in by vboxsync, 16 years ago

Additions: Use VBoxGuestLib.h instead of VBoxGuest.h where applicable.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 22.3 KB
Line 
1/** $Id: VBoxServiceTimeSync.cpp 21218 2009-07-05 13:31:56Z vboxsync $ */
2/** @file
3 * VBoxService - Guest Additions TimeSync Service.
4 */
5
6/*
7 * Copyright (C) 2007 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22
23/** @page pg_vboxservice_timesync The Time Sync Service
24 *
25 * The time sync service plays along with the Time Manager (TM) in the VMM
26 * to keep the guest time accurate using the host machine as reference.
27 * TM will try its best to make sure all timer ticks gets delivered so that
28 * there isn't normally any need to adjust the guest time.
29 *
30 * There are three normal (= acceptable) cases:
31 * -# When the service starts up. This is because ticks and such might
32 * be lost during VM and OS startup. (Need to figure out exactly why!)
33 * -# When the TM is unable to deliver all the ticks and swallows a
34 * backlog of ticks. The threshold for this is configurable with
35 * a default of 60 seconds.
36 * -# The time is adjusted on the host. This can be caused manually by
37 * the user or by some time sync daemon (NTP, LAN server, etc.).
38 *
39 * There are a number of very odd case where adjusting is needed. Here
40 * are some of them:
41 * -# Timer device emulation inaccurancies (like rounding).
42 * -# Inaccurancies in time source VirtualBox uses.
43 * -# The Guest and/or Host OS doesn't perform proper time keeping. This
44 * come about as a result of OS and/or hardware issues.
45 *
46 * The TM is our source for the host time and will make adjustments for
47 * current timer delivery lag. The simplistic approach taken by TM is to
48 * adjust the host time by the current guest timer delivery lag, meaning that
49 * if the guest is behind 1 second with PIT/RTC/++ ticks this should be reflected
50 * in the guest wall time as well.
51 *
52 * Now, there is any amount of trouble we can cause by changing the time.
53 * Most applications probably uses the wall time when they need to measure
54 * things. A walltime that is being juggled about every so often, even if just
55 * a little bit, could occationally upset these measurements by for instance
56 * yielding negative results.
57 *
58 * This bottom line here is that the time sync service isn't really supposed
59 * to do anything and will try avoid having to do anything when possible.
60 *
61 * The implementation uses the latency it takes to query host time as the
62 * absolute maximum precision to avoid messing up under timer tick catchup
63 * and/or heavy host/guest load. (Rational is that a *lot* of stuff may happen
64 * on our way back from ring-3 and TM/VMMDev since we're taking the route
65 * thru the inner EM loop with it's force action processing.)
66 *
67 * But this latency has to be measured from our perspective, which means it
68 * could just as easily come out as 0. (OS/2 and Windows guest only updates
69 * the current time when the timer ticks for instance.) The good thing is
70 * that this isn't really a problem since we won't ever do anything unless
71 * the drift is noticable.
72 *
73 * It now boils down to these three (configuration) factors:
74 * -# g_TimesyncMinAdjust - The minimum drift we will ever bother with.
75 * -# g_TimesyncLatencyFactor - The factor we multiply the latency by to
76 * calculate the dynamic minimum adjust factor.
77 * -# g_TimesyncMaxLatency - When to start discarding the data as utterly
78 * useless and take a rest (someone is too busy to give us good data).
79 * -# g_TimeSyncSetThreshold - The threshold at which we will just set the time
80 * instead of trying to adjust it (milliseconds).
81 */
82
83/*******************************************************************************
84* Header Files *
85*******************************************************************************/
86#ifdef RT_OS_WINDOWS
87# include <Windows.h>
88# include <winbase.h> /** @todo r=bird: Why is this here? Windows.h should include winbase.h... */
89#else
90# include <unistd.h>
91# include <errno.h>
92# include <time.h>
93# include <sys/time.h>
94#endif
95
96#include <iprt/thread.h>
97#include <iprt/string.h>
98#include <iprt/semaphore.h>
99#include <iprt/time.h>
100#include <iprt/assert.h>
101#include <VBox/VBoxGuestLib.h>
102#include "VBoxServiceInternal.h"
103
104
105/*******************************************************************************
106* Global Variables *
107*******************************************************************************/
108/** The timesync interval (millseconds). */
109uint32_t g_TimeSyncInterval = 0;
110/**
111 * @see pg_vboxservice_timesync
112 *
113 * @remark OS/2: There is either a 1 second resolution on the DosSetDateTime
114 * API or a but in the settimeofday implementation. Thus, don't
115 * bother unless there is at least a 1 second drift.
116 */
117#ifdef RT_OS_OS2
118static uint32_t g_TimeSyncMinAdjust = 1000;
119#else
120static uint32_t g_TimeSyncMinAdjust = 100;
121#endif
122/** @see pg_vboxservice_timesync */
123static uint32_t g_TimeSyncLatencyFactor = 8;
124/** @see pg_vboxservice_timesync */
125static uint32_t g_TimeSyncMaxLatency = 250;
126/** @see pg_vboxservice_timesync */
127static uint32_t g_TimeSyncSetThreshold = 20*60*1000;
128/** Whether the next adjustment should just set the time instead of trying to
129 * adjust it. This is used to implement --timesync-set-start. */
130static bool volatile g_fTimeSyncSetNext = false;
131
132/** Current error count. Used to knowing when to bitch and when not to. */
133static uint32_t g_cTimeSyncErrors = 0;
134
135/** The semaphore we're blocking on. */
136static RTSEMEVENTMULTI g_TimeSyncEvent = NIL_RTSEMEVENTMULTI;
137
138#ifdef RT_OS_WINDOWS
139/** Process token. */
140static HANDLE g_hTokenProcess = NULL;
141/** Old token privileges. */
142static TOKEN_PRIVILEGES g_TkOldPrivileges;
143/** Backup values for time adjustment. */
144static DWORD g_dwWinTimeAdjustment;
145static DWORD g_dwWinTimeIncrement;
146static BOOL g_bWinTimeAdjustmentDisabled;
147#endif
148
149
150/** @copydoc VBOXSERVICE::pfnPreInit */
151static DECLCALLBACK(int) VBoxServiceTimeSyncPreInit(void)
152{
153 return VINF_SUCCESS;
154}
155
156
157/** @copydoc VBOXSERVICE::pfnOption */
158static DECLCALLBACK(int) VBoxServiceTimeSyncOption(const char **ppszShort, int argc, char **argv, int *pi)
159{
160 int rc = -1;
161 if (ppszShort)
162 /* no short options */;
163 else if (!strcmp(argv[*pi], "--timesync-interval"))
164 rc = VBoxServiceArgUInt32(argc, argv, "", pi,
165 &g_TimeSyncInterval, 1, UINT32_MAX - 1);
166 else if (!strcmp(argv[*pi], "--timesync-min-adjust"))
167 rc = VBoxServiceArgUInt32(argc, argv, "", pi,
168 &g_TimeSyncMinAdjust, 0, 3600000);
169 else if (!strcmp(argv[*pi], "--timesync-latency-factor"))
170 rc = VBoxServiceArgUInt32(argc, argv, "", pi,
171 &g_TimeSyncLatencyFactor, 1, 1024);
172 else if (!strcmp(argv[*pi], "--timesync-max-latency"))
173 rc = VBoxServiceArgUInt32(argc, argv, "", pi,
174 &g_TimeSyncMaxLatency, 1, 3600000);
175 else if (!strcmp(argv[*pi], "--timesync-set-threshold"))
176 rc = VBoxServiceArgUInt32(argc, argv, "", pi,
177 &g_TimeSyncSetThreshold, 0, 7*24*60*1000); /* a week */
178 else if (!strcmp(argv[*pi], "--timesync-set-start"))
179 {
180 g_fTimeSyncSetNext = true;
181 rc = VINF_SUCCESS;
182 }
183
184 return rc;
185}
186
187
188/** @copydoc VBOXSERVICE::pfnInit */
189static DECLCALLBACK(int) VBoxServiceTimeSyncInit(void)
190{
191 /*
192 * If not specified, find the right interval default.
193 * Then create the event sem to block on.
194 */
195 if (!g_TimeSyncInterval)
196 g_TimeSyncInterval = g_DefaultInterval * 1000;
197 if (!g_TimeSyncInterval)
198 g_TimeSyncInterval = 10 * 1000;
199
200 int rc = RTSemEventMultiCreate(&g_TimeSyncEvent);
201 AssertRC(rc);
202#ifdef RT_OS_WINDOWS
203 if (RT_SUCCESS(rc))
204 {
205 /*
206 * Adjust priviledges of this process so we can make system time adjustments.
207 */
208 if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &g_hTokenProcess))
209 {
210 TOKEN_PRIVILEGES tkPriv;
211 RT_ZERO(tkPriv);
212 tkPriv.PrivilegeCount = 1;
213 tkPriv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
214 if (LookupPrivilegeValue(NULL, SE_SYSTEMTIME_NAME, &tkPriv.Privileges[0].Luid))
215 {
216 DWORD cbRet = sizeof(g_TkOldPrivileges);
217 if (AdjustTokenPrivileges(g_hTokenProcess, FALSE, &tkPriv, sizeof(TOKEN_PRIVILEGES), &g_TkOldPrivileges, &cbRet))
218 rc = VINF_SUCCESS;
219 else
220 {
221 DWORD dwErr = GetLastError();
222 rc = RTErrConvertFromWin32(dwErr);
223 VBoxServiceError("Adjusting token privileges (SE_SYSTEMTIME_NAME) failed with status code %u/%Rrc!\n", dwErr, rc);
224 }
225 }
226 else
227 {
228 DWORD dwErr = GetLastError();
229 rc = RTErrConvertFromWin32(dwErr);
230 VBoxServiceError("Looking up token privileges (SE_SYSTEMTIME_NAME) failed with status code %u/%Rrc!\n", dwErr, rc);
231 }
232 if (RT_FAILURE(rc))
233 {
234 CloseHandle(g_hTokenProcess);
235 g_hTokenProcess = NULL;
236 }
237 }
238 else
239 {
240 DWORD dwErr = GetLastError();
241 rc = RTErrConvertFromWin32(dwErr);
242 VBoxServiceError("Opening process token (SE_SYSTEMTIME_NAME) failed with status code %u/%Rrc!\n", dwErr, rc);
243 g_hTokenProcess = NULL;
244 }
245 }
246
247 if (GetSystemTimeAdjustment(&g_dwWinTimeAdjustment, &g_dwWinTimeIncrement, &g_bWinTimeAdjustmentDisabled))
248 VBoxServiceVerbose(3, "Windows time adjustment: Initially %ld (100ns) units per %ld (100 ns) units interval, disabled=%d\n",
249 g_dwWinTimeAdjustment, g_dwWinTimeIncrement, g_bWinTimeAdjustmentDisabled ? 1 : 0);
250 else
251 {
252 DWORD dwErr = GetLastError();
253 rc = RTErrConvertFromWin32(dwErr);
254 VBoxServiceError("Could not get time adjustment values! Last error: %ld!\n", dwErr);
255 }
256#endif /* RT_OS_WINDOWS */
257
258 return rc;
259}
260
261
262/**
263 * Try adjust the time using adjtime or similar.
264 *
265 * @returns true on success, false on failure.
266 *
267 * @param pDrift The time adjustment.
268 */
269static bool VBoxServiceTimeSyncAdjust(PCRTTIMESPEC pDrift)
270{
271#ifdef RT_OS_WINDOWS
272/** @todo r=bird: NT4 doesn't have GetSystemTimeAdjustment. */
273 DWORD dwWinTimeAdjustment, dwWinNewTimeAdjustment, dwWinTimeIncrement;
274 BOOL fWinTimeAdjustmentDisabled;
275 if (GetSystemTimeAdjustment(&dwWinTimeAdjustment, &dwWinTimeIncrement, &fWinTimeAdjustmentDisabled))
276 {
277 DWORD dwDiffMax = g_dwWinTimeAdjustment * 0.50;
278 DWORD dwDiffNew = dwWinTimeAdjustment * 0.10;
279
280 if (RTTimeSpecGetMilli(pDrift) > 0)
281 {
282 dwWinNewTimeAdjustment = dwWinTimeAdjustment + dwDiffNew;
283 if (dwWinNewTimeAdjustment > (g_dwWinTimeAdjustment + dwDiffMax))
284 {
285 dwWinNewTimeAdjustment = g_dwWinTimeAdjustment + dwDiffMax;
286 dwDiffNew = dwDiffMax;
287 }
288 }
289 else
290 {
291 dwWinNewTimeAdjustment = dwWinTimeAdjustment - dwDiffNew;
292 if (dwWinNewTimeAdjustment < (g_dwWinTimeAdjustment - dwDiffMax))
293 {
294 dwWinNewTimeAdjustment = g_dwWinTimeAdjustment - dwDiffMax;
295 dwDiffNew = dwDiffMax;
296 }
297 }
298
299 VBoxServiceVerbose(3, "Windows time adjustment: Drift=%lldms\n", RTTimeSpecGetMilli(pDrift));
300 VBoxServiceVerbose(3, "Windows time adjustment: OrgTA=%ld, CurTA=%ld, NewTA=%ld, DiffNew=%ld, DiffMax=%ld\n",
301 g_dwWinTimeAdjustment, dwWinTimeAdjustment, dwWinNewTimeAdjustment, dwDiffNew, dwDiffMax);
302 if (SetSystemTimeAdjustment(dwWinNewTimeAdjustment, FALSE /* Periodic adjustments enabled. */))
303 {
304 g_cTimeSyncErrors = 0;
305 return true;
306 }
307
308 if (g_cTimeSyncErrors++ < 10)
309 VBoxServiceError("SetSystemTimeAdjustment failed, error=%u\n", GetLastError());
310 }
311 else if (g_cTimeSyncErrors++ < 10)
312 VBoxServiceError("GetSystemTimeAdjustment failed, error=%ld\n", GetLastError());
313
314#elif defined(RT_OS_OS2)
315 /* No API for doing gradual time adjustments. */
316
317#else /* PORTME */
318 /*
319 * Try use adjtime(), most unix-like systems have this.
320 */
321 struct timeval tv;
322 RTTimeSpecGetTimeval(pDrift, &tv);
323 if (adjtime(&tv, NULL) == 0)
324 {
325 if (g_cVerbosity >= 1)
326 VBoxServiceVerbose(1, "adjtime by %RDtimespec\n", pDrift);
327 g_cTimeSyncErrors = 0;
328 return true;
329 }
330#endif
331
332 /* failed */
333 return false;
334}
335
336
337/**
338 * Cancels any pending time adjustment.
339 *
340 * Called when we've caught up and before calls to VBoxServiceTimeSyncSet.
341 */
342static void VBoxServiceTimeSyncCancelAdjust(void)
343{
344#ifdef RT_OS_WINDOWS
345 if (SetSystemTimeAdjustment(0, TRUE /* Periodic adjustments disabled. */))
346 VBoxServiceVerbose(3, "Windows Time Adjustment is now disabled.\n");
347 else if (g_cTimeSyncErrors++ < 10)
348 VBoxServiceError("SetSystemTimeAdjustment(,disable) failed, error=%u\n", GetLastError());
349#endif /* !RT_OS_WINDOWS */
350}
351
352
353/**
354 * Try adjust the time using adjtime or similar.
355 *
356 * @returns true on success, false on failure.
357 *
358 * @param pDrift The time adjustment.
359 * @param pHostNow The host time at the time of the host query.
360 * REMOVE THIS ARGUMENT!
361 */
362static void VBoxServiceTimeSyncSet(PCRTTIMESPEC pDrift, PCRTTIMESPEC pHostNow)
363{
364 /*
365 * Query the current time, add the adjustment, then try it.
366 */
367#ifdef RT_OS_WINDOWS
368/** @todo r=bird: Get current time and add the adjustment, the host time is
369 * stale by now. */
370 FILETIME ft;
371 RTTimeSpecGetNtFileTime(pHostNow, &ft);
372 SYSTEMTIME st;
373 if (FileTimeToSystemTime(&ft, &st))
374 {
375 if (!SetSystemTime(&st))
376 VBoxServiceError("SetSystemTime failed, error=%u\n", GetLastError());
377 }
378 else
379 VBoxServiceError("Cannot convert system times, error=%u\n", GetLastError());
380
381#else /* !RT_OS_WINDOWS */
382 struct timeval tv;
383 errno = 0;
384 if (!gettimeofday(&tv, NULL))
385 {
386 RTTIMESPEC Tmp;
387 RTTimeSpecAdd(RTTimeSpecSetTimeval(&Tmp, &tv), pDrift);
388 if (!settimeofday(RTTimeSpecGetTimeval(&Tmp, &tv), NULL))
389 {
390 char sz[64];
391 RTTIME Time;
392 if (g_cVerbosity >= 1)
393 VBoxServiceVerbose(1, "settimeofday to %s\n",
394 RTTimeToString(RTTimeExplode(&Time, &Tmp), sz, sizeof(sz)));
395# ifdef DEBUG
396 if (g_cVerbosity >= 3)
397 VBoxServiceVerbose(2, " new time %s\n",
398 RTTimeToString(RTTimeExplode(&Time, RTTimeNow(&Tmp)), sz, sizeof(sz)));
399# endif
400 g_cTimeSyncErrors = 0;
401 }
402 else if (g_cTimeSyncErrors++ < 10)
403 VBoxServiceError("settimeofday failed; errno=%d: %s\n", errno, strerror(errno));
404 }
405 else if (g_cTimeSyncErrors++ < 10)
406 VBoxServiceError("gettimeofday failed; errno=%d: %s\n", errno, strerror(errno));
407#endif /* !RT_OS_WINDOWS */
408}
409
410
411/** @copydoc VBOXSERVICE::pfnWorker */
412DECLCALLBACK(int) VBoxServiceTimeSyncWorker(bool volatile *pfShutdown)
413{
414 RTTIME Time;
415 char sz[64];
416 int rc = VINF_SUCCESS;
417
418 /*
419 * Tell the control thread that it can continue spawning services.
420 */
421 RTThreadUserSignal(RTThreadSelf());
422
423 /*
424 * The Work Loop.
425 */
426 for (;;)
427 {
428 /*
429 * Try get a reliable time reading.
430 */
431 int cTries = 3;
432 do
433 {
434 /* query it. */
435 RTTIMESPEC GuestNow0, GuestNow, HostNow;
436 RTTimeNow(&GuestNow0);
437 int rc2 = VbglR3GetHostTime(&HostNow);
438 if (RT_FAILURE(rc2))
439 {
440 if (g_cTimeSyncErrors++ < 10)
441 VBoxServiceError("VbglR3GetHostTime failed; rc2=%Rrc\n", rc2);
442 break;
443 }
444 RTTimeNow(&GuestNow);
445
446 /* calc latency and check if it's ok. */
447 RTTIMESPEC GuestElapsed = GuestNow;
448 RTTimeSpecSub(&GuestElapsed, &GuestNow0);
449 if ((uint32_t)RTTimeSpecGetMilli(&GuestElapsed) < g_TimeSyncMaxLatency)
450 {
451 /*
452 * Calculate the adjustment threshold and the current drift.
453 */
454 uint32_t MinAdjust = RTTimeSpecGetMilli(&GuestElapsed) * g_TimeSyncLatencyFactor;
455 if (MinAdjust < g_TimeSyncMinAdjust)
456 MinAdjust = g_TimeSyncMinAdjust;
457
458 RTTIMESPEC Drift = HostNow;
459 RTTimeSpecSub(&Drift, &GuestNow);
460 if (RTTimeSpecGetMilli(&Drift) < 0)
461 MinAdjust += g_TimeSyncMinAdjust; /* extra buffer against moving time backwards. */
462
463 RTTIMESPEC AbsDrift = Drift;
464 RTTimeSpecAbsolute(&AbsDrift);
465 if (g_cVerbosity >= 3)
466 {
467 VBoxServiceVerbose(3, "Host: %s (MinAdjust: %RU32 ms)\n",
468 RTTimeToString(RTTimeExplode(&Time, &HostNow), sz, sizeof(sz)), MinAdjust);
469 VBoxServiceVerbose(3, "Guest: - %s => %RDtimespec drift\n",
470 RTTimeToString(RTTimeExplode(&Time, &GuestNow), sz, sizeof(sz)),
471 &Drift);
472 }
473
474 uint32_t AbsDriftMilli = RTTimeSpecGetMilli(&AbsDrift);
475 if (AbsDriftMilli > MinAdjust)
476 {
477 /*
478 * Ok, the drift is above the threshold.
479 *
480 * Try a gradual adjustment first, if that fails or the drift is
481 * too big, fall back on just setting the time.
482 */
483
484 if ( AbsDriftMilli > g_TimeSyncSetThreshold
485 || g_fTimeSyncSetNext
486 || !VBoxServiceTimeSyncAdjust(&Drift))
487 {
488 VBoxServiceTimeSyncCancelAdjust();
489 VBoxServiceTimeSyncSet(&Drift, &HostNow);
490 }
491 }
492 else
493 VBoxServiceTimeSyncCancelAdjust();
494 break;
495 }
496 VBoxServiceVerbose(3, "%RDtimespec: latency too high (%RDtimespec) sleeping 1s\n", GuestElapsed);
497 RTThreadSleep(1000);
498 } while (--cTries > 0);
499
500 /* Clear the set-next/set-start flag. */
501 g_fTimeSyncSetNext = false;
502
503 /*
504 * Block for a while.
505 *
506 * The event semaphore takes care of ignoring interruptions and it
507 * allows us to implement service wakeup later.
508 */
509 if (*pfShutdown)
510 break;
511 int rc2 = RTSemEventMultiWait(g_TimeSyncEvent, g_TimeSyncInterval);
512 if (*pfShutdown)
513 break;
514 if (rc2 != VERR_TIMEOUT && RT_FAILURE(rc2))
515 {
516 VBoxServiceError("RTSemEventMultiWait failed; rc2=%Rrc\n", rc2);
517 rc = rc2;
518 break;
519 }
520 }
521
522 RTSemEventMultiDestroy(g_TimeSyncEvent);
523 g_TimeSyncEvent = NIL_RTSEMEVENTMULTI;
524 return rc;
525}
526
527
528/** @copydoc VBOXSERVICE::pfnStop */
529static DECLCALLBACK(void) VBoxServiceTimeSyncStop(void)
530{
531 RTSemEventMultiSignal(g_TimeSyncEvent);
532}
533
534
535/** @copydoc VBOXSERVICE::pfnTerm */
536static DECLCALLBACK(void) VBoxServiceTimeSyncTerm(void)
537{
538#ifdef RT_OS_WINDOWS
539 /*
540 * Restore the SE_SYSTEMTIME_NAME token privileges (if init succeeded).
541 */
542 if (g_hTokenProcess)
543 {
544 if (!AdjustTokenPrivileges(g_hTokenProcess, FALSE, &g_TkOldPrivileges, sizeof(TOKEN_PRIVILEGES), NULL, NULL))
545 {
546 DWORD dwErr = GetLastError();
547 VBoxServiceError("Restoring token privileges (SE_SYSTEMTIME_NAME) failed with code %u!\n", dwErr);
548 }
549 CloseHandle(g_hTokenProcess);
550 g_hTokenProcess = NULL;
551 }
552#endif /* !RT_OS_WINDOWS */
553
554 if (g_TimeSyncEvent != NIL_RTSEMEVENTMULTI)
555 {
556 RTSemEventMultiDestroy(g_TimeSyncEvent);
557 g_TimeSyncEvent = NIL_RTSEMEVENTMULTI;
558 }
559}
560
561
562/**
563 * The 'timesync' service description.
564 */
565VBOXSERVICE g_TimeSync =
566{
567 /* pszName. */
568 "timesync",
569 /* pszDescription. */
570 "Time synchronization",
571 /* pszUsage. */
572 "[--timesync-interval <ms>] [--timesync-min-adjust <ms>] "
573 "[--timesync-latency-factor <x>] [--timesync-max-latency <ms>]"
574 "[--timesync-set-threshold <ms>] [--timesync-set-start]"
575 ,
576 /* pszOptions. */
577 " --timesync-interval Specifies the interval at which to synchronize the\n"
578 " time with the host. The default is 10000 ms.\n"
579 " --timesync-min-adjust\n"
580 " The minimum absolute drift value measured in\n"
581 " milliseconds to make adjustments for.\n"
582 " The default is 1000 ms on OS/2 and 100 ms elsewhere.\n"
583 " --timesync-latency-factor\n"
584 " The factor to multiply the time query latency with to\n"
585 " calculate the dynamic minimum adjust time.\n"
586 " The default is 8 times.\n"
587 " --timesync-max-latency\n"
588 " The max host timer query latency to accept.\n"
589 " The default is 250 ms.\n"
590 " --timesync-set-threshold\n"
591 " The absolute drift threshold, given as milliseconds,\n"
592 " where to start setting the time instead of trying to\n"
593 " adjust it. The default is 20 min.\n"
594 " --timesync-set-start\n"
595 " Set the time when starting the time sync service.\n"
596 ,
597 /* methods */
598 VBoxServiceTimeSyncPreInit,
599 VBoxServiceTimeSyncOption,
600 VBoxServiceTimeSyncInit,
601 VBoxServiceTimeSyncWorker,
602 VBoxServiceTimeSyncStop,
603 VBoxServiceTimeSyncTerm
604};
605
Note: See TracBrowser for help on using the repository browser.

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