port-linux.c 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. /* $Id: port-linux.c 1793 2007-01-28 20:55:08Z tg $ */
  2. /* part of the adjtime-linux patch */
  3. /*
  4. * Copyright (c) 2004 Darren Tucker <dtucker at zip com au>
  5. *
  6. * Permission to use, copy, modify, and distribute this software for any
  7. * purpose with or without fee is hereby granted, provided that the above
  8. * copyright notice and this permission notice appear in all copies.
  9. *
  10. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  11. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  12. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  13. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  14. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  15. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  16. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  17. */
  18. #include "includes.h"
  19. #ifdef USE_ADJTIMEX
  20. #include <sys/timex.h>
  21. #include <errno.h>
  22. #ifdef adjtime
  23. # undef adjtime
  24. #endif
  25. #include "ntpd.h"
  26. /* scale factor used by adjtimex freq param. 1 ppm = 65536 */
  27. #define ADJTIMEX_FREQ_SCALE 65536
  28. /* maximum change to skew per adjustment, in PPM */
  29. #define MAX_SKEW_DELTA 5.0
  30. int
  31. _compat_adjtime(const struct timeval *delta, struct timeval *olddelta)
  32. {
  33. static struct timeval tlast = {0,0};
  34. static double tskew = 0;
  35. static int synced = -1;
  36. struct timeval tnow, tdelta;
  37. double skew = 0, newskew, deltaskew, adjust, interval = 0;
  38. struct timex tmx;
  39. int result, saved_errno;
  40. gettimeofday(&tnow, NULL);
  41. adjust = (double)delta->tv_sec;
  42. adjust += (double)delta->tv_usec / 1000000;
  43. /* Even if the caller doesn't care about the olddelta, we do */
  44. if (olddelta == NULL)
  45. olddelta = &tdelta;
  46. result = adjtime(delta, olddelta);
  47. saved_errno = errno;
  48. if (olddelta->tv_sec == 0 && olddelta->tv_usec == 0 &&
  49. synced != INT_MAX)
  50. synced++;
  51. else
  52. synced = 0;
  53. /*
  54. * do skew calculations if we have synced
  55. */
  56. if (synced == 0 ) {
  57. tmx.modes = 0;
  58. if (adjtimex(&tmx) == -1)
  59. log_warn("adjtimex get failed");
  60. else
  61. tskew = (double)tmx.freq / ADJTIMEX_FREQ_SCALE;
  62. } else if (synced >= 1) {
  63. interval = (double)(tnow.tv_sec - tlast.tv_sec);
  64. interval += (double)(tnow.tv_usec - tlast.tv_usec) / 1000000;
  65. skew = (adjust * 1000000) / interval;
  66. newskew = ((tskew * synced) + skew) / synced;
  67. deltaskew = newskew - tskew;
  68. if (deltaskew > MAX_SKEW_DELTA) {
  69. log_info("skew change %0.3lf exceeds limit", deltaskew);
  70. tskew += MAX_SKEW_DELTA;
  71. } else if (deltaskew < -MAX_SKEW_DELTA) {
  72. log_info("skew change %0.3lf exceeds limit", deltaskew);
  73. tskew -= MAX_SKEW_DELTA;
  74. } else {
  75. tskew = newskew;
  76. }
  77. /* Adjust the kernel skew. */
  78. tmx.freq = (long)(tskew * ADJTIMEX_FREQ_SCALE);
  79. tmx.modes = ADJ_FREQUENCY;
  80. if (adjtimex(&tmx) == -1)
  81. log_warn("adjtimex set freq failed");
  82. }
  83. log_debug("interval %0.3lf skew %0.3lf total skew %0.3lf", interval,
  84. skew, tskew);
  85. tlast = tnow;
  86. errno = saved_errno;
  87. return result;
  88. }
  89. #endif