~ubuntu-branches/ubuntu/quantal/open-vm-tools/quantal-201210021442

« back to all changes in this revision

Viewing changes to services/plugins/timeSync/timeSync.c

  • Committer: Bazaar Package Importer
  • Author(s): Serge Hallyn
  • Date: 2011-03-31 14:20:05 UTC
  • mfrom: (1.4.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20110331142005-3n9red91p7ogkweo
Tags: 2011.03.28-387002-0ubuntu1
* Merge latest upstream git tag.  This has the unlocked_ioctl change
  needed to fix dkms build failures (LP: #727342)
* Changes in debian/rules:
  - work around a bug in toolbox/Makefile, where install-exec-hook is
    not happening.  This needs to get fixed the right way.
  - don't install 'vmware-user' which seems to no longer exist
  - move /etc/xdg into open-vm-toolbox (which should be done using .install)
* debian/open-vm-tools.init: add 'modprobe [-r] vmblock'. (LP: #332323)
* debian/rules and debian/open-vm-toolbox.lintian-overrides:
  - Make vmware-user-suid-wrapper suid-root (LP: #332323)

Show diffs side-by-side

added added

removed removed

Lines of Context:
115
115
#define TIMESYNC_MAX_SAMPLES 4
116
116
#define TIMESYNC_GOOD_SAMPLE_THRESHOLD 2000
117
117
 
 
118
/* Once the error drops below TIMESYNC_PLL_ACTIVATE, activate the PLL.
 
119
 * 500ppm error acumulated over a 60 second interval can produce 30ms of
 
120
 * error. */
 
121
#define TIMESYNC_PLL_ACTIVATE (30 * 1000) /* 30ms. */
 
122
/* If the error goes above TIMESYNC_PLL_UNSYNC, deactivate the PLL. */
 
123
#define TIMESYNC_PLL_UNSYNC (2 * TIMESYNC_PLL_ACTIVATE)
 
124
/* Period during which the frequency error of guest time is measured. */
 
125
#define TIMESYNC_CALIBRATION_DURATION (15 * 60 * US_PER_SEC) /* 15min. */
 
126
 
118
127
typedef enum TimeSyncState {
119
128
   TIMESYNC_INITIALIZING,
120
129
   TIMESYNC_STOPPED,
121
130
   TIMESYNC_RUNNING,
122
131
} TimeSyncState;
123
132
 
 
133
typedef enum TimeSyncSlewState {
 
134
   TimeSyncUncalibrated,
 
135
   TimeSyncCalibrating,
 
136
   TimeSyncPLL,
 
137
} TimeSyncSlewState;
 
138
 
124
139
typedef struct TimeSyncData {
125
 
   gboolean       slewActive;
126
 
   gboolean       slewCorrection;
127
 
   uint32         slewPercentCorrection;
128
 
   uint32         timeSyncPeriod;         /* In seconds. */
129
 
   TimeSyncState  state;
130
 
   GSource        *timer;
 
140
   gboolean           slewActive;
 
141
   gboolean           slewCorrection;
 
142
   uint32             slewPercentCorrection;
 
143
   uint32             timeSyncPeriod;         /* In seconds. */
 
144
   TimeSyncState      state;
 
145
   TimeSyncSlewState  slewState;
 
146
   GSource           *timer;
131
147
} TimeSyncData;
132
148
 
133
149
 
134
150
static void TimeSyncSetSlewState(TimeSyncData *data, gboolean active);
 
151
static void TimeSyncResetSlew(TimeSyncData *data);
135
152
 
136
153
/**
137
154
 * Read the time reported by the Host OS.
371
388
 
372
389
 
373
390
/**
374
 
 * Slew the guest OS time advancement to correct the time.  Only correct a
375
 
 * portion of the error to avoid overcorrection.
 
391
 * Slew the guest OS time advancement to correct the time.
 
392
 *
 
393
 * In addition to standard slewing (implemented via TimeSync_Slew), we
 
394
 * also support using an NTP style PLL to slew the time.  The PLL can take
 
395
 * a while to end up with an accurate measurement of the frequency error,
 
396
 * so before entering PLL mode we calibrate the frequency error over a
 
397
 * period of TIMESYNC_PLL_ACTIVATE seconds.  
 
398
 *
 
399
 * When using standard slewing, only correct slewPercentCorrection of the
 
400
 * error.  This is to avoid overcorrection when the error is mis-measured,
 
401
 * or overcorrection caused by the daemon waking up later than it is
 
402
 * supposed to leaving the slew in place for longer than anticpiated.
376
403
 *
377
404
 * @param[in]  data              Structure tracking time sync state.
378
405
 * @param[in]  adjustment        Amount to correct the guest time.
381
408
static gboolean
382
409
TimeSyncSlewTime(TimeSyncData *data, int64 adjustment)
383
410
{
 
411
   static int64 calibrationStart;
 
412
   static int64 calibrationAdjustment;
 
413
 
 
414
   int64 now;
 
415
   int64 remaining = 0;
384
416
   int64 timeSyncPeriodUS = data->timeSyncPeriod * US_PER_SEC;
385
417
   int64 slewDiff = (adjustment * data->slewPercentCorrection) / 100;
386
418
   
387
 
   return TimeSync_EnableTimeSlew(slewDiff, timeSyncPeriodUS);
 
419
   if (!TimeSync_GetCurrentTime(&now)) {
 
420
      return FALSE;
 
421
   }
 
422
 
 
423
   if (adjustment > TIMESYNC_PLL_UNSYNC && 
 
424
       data->slewState != TimeSyncUncalibrated) {
 
425
      g_debug("Adjustment too large (%"FMT64"d), resetting PLL state.\n", 
 
426
              adjustment);
 
427
      data->slewState = TimeSyncUncalibrated;
 
428
   }
 
429
 
 
430
   if (data->slewState == TimeSyncUncalibrated) {
 
431
      g_debug("Slewing time: adjustment %"FMT64"d\n", adjustment);
 
432
      if (!TimeSync_Slew(slewDiff, timeSyncPeriodUS, &remaining)) {
 
433
         data->slewState = TimeSyncUncalibrated;
 
434
         return FALSE;
 
435
      }
 
436
      if (adjustment < TIMESYNC_PLL_ACTIVATE && TimeSync_PLLSupported()) {
 
437
         g_debug("Starting PLL calibration.\n");
 
438
         calibrationStart = now;
 
439
         /* Starting out the calibration period we are adjustment behind,
 
440
          * but have already requested to correct slewDiff of that. */
 
441
         calibrationAdjustment = slewDiff - adjustment;
 
442
         data->slewState = TimeSyncCalibrating;
 
443
      }
 
444
   } else if (data->slewState == TimeSyncCalibrating) {
 
445
      if (now > calibrationStart + TIMESYNC_CALIBRATION_DURATION) {
 
446
         int64 ppmErr;
 
447
         /* Reset slewing to nominal and find out remaining slew. */
 
448
         TimeSync_Slew(0, timeSyncPeriodUS, &remaining);
 
449
         calibrationAdjustment += adjustment;
 
450
         calibrationAdjustment -= remaining;
 
451
         ppmErr = ((1000000 * calibrationAdjustment) << 16) / 
 
452
                   (now - calibrationStart);
 
453
         if (ppmErr >> 16 < 500 && ppmErr >> 16 > -500) {
 
454
            g_debug("Activating PLL ppmEst=%"FMT64"d (%"FMT64"d)\n", 
 
455
                    ppmErr >> 16, ppmErr);
 
456
            TimeSync_PLLUpdate(adjustment);
 
457
            TimeSync_PLLSetFrequency(ppmErr);
 
458
            data->slewState = TimeSyncPLL;
 
459
         } else {
 
460
            /* PPM error is too large to try the PLL. */
 
461
            g_debug("PPM error too large: %"FMT64"d (%"FMT64"d) "
 
462
                    "not activating PLL\n", ppmErr >> 16, ppmErr);
 
463
            data->slewState = TimeSyncUncalibrated;
 
464
         }
 
465
      } else {
 
466
         g_debug("Calibrating error: adjustment %"FMT64"d\n", adjustment);
 
467
         if (!TimeSync_Slew(slewDiff, timeSyncPeriodUS, &remaining)) {
 
468
            return FALSE;
 
469
         }
 
470
         calibrationAdjustment += slewDiff;
 
471
         calibrationAdjustment -= remaining;
 
472
      }
 
473
   } else {
 
474
      ASSERT(data->slewState == TimeSyncPLL);
 
475
      g_debug("Updating PLL: adjustment %"FMT64"d\n", adjustment);
 
476
      if (!TimeSync_PLLUpdate(adjustment)) {
 
477
         TimeSyncResetSlew(data);
 
478
      }
 
479
   }
 
480
   return TRUE;
388
481
}
389
482
 
390
483
 
397
490
static void
398
491
TimeSyncResetSlew(TimeSyncData *data)
399
492
{
400
 
   TimeSyncSlewTime(data, 0);
 
493
   int64 remaining;
 
494
   int64 timeSyncPeriodUS = data->timeSyncPeriod * US_PER_SEC;
 
495
   data->slewState = TimeSyncUncalibrated;
 
496
   TimeSync_Slew(0, timeSyncPeriodUS, &remaining);
 
497
   if (TimeSync_PLLSupported()) {
 
498
      TimeSync_PLLUpdate(0);
 
499
      TimeSync_PLLSetFrequency(0);
 
500
   }
401
501
}
402
502
 
403
503
 
584
684
   TimeSync_DisableTimeSlew();
585
685
 
586
686
   g_source_destroy(data->timer);
 
687
   g_source_unref(data->timer);
587
688
   data->timer = NULL;
588
689
 
589
690
   data->state = TIMESYNC_STOPPED;
817
918
   data->slewCorrection = FALSE;
818
919
   data->slewPercentCorrection = TIMESYNC_PERCENT_CORRECTION;
819
920
   data->state = TIMESYNC_INITIALIZING;
 
921
   data->slewState = TimeSyncUncalibrated;
820
922
   data->timeSyncPeriod = TIMESYNC_TIME;
821
923
   data->timer = NULL;
822
924