Devuan fork of gpsd
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ntpshmread.c 5.0 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. /* ntpshmread.c -- monitor the inner end of an ntpshmwrite.connection
  2. *
  3. * This file is Copyright (c) 2010-2018 by the GPSD project
  4. * SPDX-License-Identifier: BSD-2-clause
  5. *
  6. * Some of this was swiped from the NTPD distribution.
  7. */
  8. #include "gpsd_config.h" /* must be before all includes */
  9. #include <string.h>
  10. #include <stdbool.h>
  11. #include <math.h>
  12. #include <errno.h>
  13. #include <sys/types.h>
  14. #include <sys/stat.h>
  15. #include <assert.h>
  16. #include <stdio.h>
  17. #include <stdint.h>
  18. #include <unistd.h>
  19. #include "ntpshm.h"
  20. #include "compiler.h"
  21. struct shmTime *shm_get(const int unit, const bool create, const bool forall)
  22. /* initialize a SHM segment */
  23. {
  24. struct shmTime *p = NULL;
  25. int shmid;
  26. /*
  27. * Big units will give non-ASCII but that's OK
  28. * as long as everybody does it the same way.
  29. */
  30. shmid = shmget((key_t)(NTPD_BASE + unit), sizeof(struct shmTime),
  31. (create ? IPC_CREAT : 0) | (forall ? 0666 : 0600));
  32. if (shmid == -1) { /* error */
  33. return NULL;
  34. }
  35. p = (struct shmTime *)shmat (shmid, 0, 0);
  36. if (p == (struct shmTime *)-1) { /* error */
  37. return NULL;
  38. }
  39. return p;
  40. }
  41. char *ntp_name(const int unit)
  42. /* return the name of a specified segment */
  43. {
  44. static char name[5] = "NTP\0";
  45. name[3] = (char)('0' + unit);
  46. return name;
  47. }
  48. enum segstat_t ntp_read(struct shmTime *shm_in, struct shm_stat_t *shm_stat, const bool consume)
  49. /* try to grab a sample from the specified SHM segment */
  50. {
  51. volatile struct shmTime shmcopy, *shm = shm_in;
  52. volatile int cnt;
  53. unsigned int cns_new, rns_new;
  54. if (shm == NULL) {
  55. shm_stat->status = NO_SEGMENT;
  56. return NO_SEGMENT;
  57. }
  58. shm_stat->tvc.tv_sec = shm_stat->tvc.tv_nsec = 0;
  59. /* relying on word access to be atomic here */
  60. if (shm->valid == 0) {
  61. shm_stat->status = NOT_READY;
  62. return NOT_READY;
  63. }
  64. cnt = shm->count;
  65. /*
  66. * This is proof against concurrency issues if either (a) the
  67. * memory_barrier() call works on this host, or (b) memset
  68. * compiles to an uninterruptible single-instruction bitblt (this
  69. * will probably cease to be true if the structure exceeds your VM
  70. * page size).
  71. */
  72. memory_barrier();
  73. memcpy((void *)&shmcopy, (void *)shm, sizeof(struct shmTime));
  74. /*
  75. * An update consumer such as ntpd should zero the valid flag at this point.
  76. * A program snooping the updates to collect statistics should not, lest
  77. * it make the data unavailable for consumers.
  78. */
  79. if (consume)
  80. shm->valid = 0;
  81. memory_barrier();
  82. /*
  83. * Clash detection in case neither (a) nor (b) was true.
  84. * Not supported in mode 0, and word access to the count field
  85. * must be atomic for this to work.
  86. */
  87. if (shmcopy.mode > 0 && cnt != shm->count) {
  88. shm_stat->status = CLASH;
  89. return shm_stat->status;
  90. }
  91. shm_stat->status = OK;
  92. switch (shmcopy.mode) {
  93. case 0:
  94. shm_stat->tvr.tv_sec = shmcopy.receiveTimeStampSec;
  95. shm_stat->tvr.tv_nsec = shmcopy.receiveTimeStampUSec * 1000;
  96. rns_new = shmcopy.receiveTimeStampNSec;
  97. shm_stat->tvt.tv_sec = shmcopy.clockTimeStampSec;
  98. shm_stat->tvt.tv_nsec = shmcopy.clockTimeStampUSec * 1000;
  99. cns_new = shmcopy.clockTimeStampNSec;
  100. /* Since the following comparisons are between unsigned
  101. ** variables they are always well defined, and any
  102. ** (signed) underflow will turn into very large unsigned
  103. ** values, well above the 1000 cutoff.
  104. **
  105. ** Note: The usecs *must* be a *truncated*
  106. ** representation of the nsecs. This code will fail for
  107. ** *rounded* usecs, and the logic to deal with
  108. ** wrap-arounds in the presence of rounded values is
  109. ** much more convoluted.
  110. */
  111. if (((cns_new - (unsigned)shm_stat->tvt.tv_nsec) < 1000)
  112. && ((rns_new - (unsigned)shm_stat->tvr.tv_nsec) < 1000)) {
  113. shm_stat->tvt.tv_nsec = cns_new;
  114. shm_stat->tvr.tv_nsec = rns_new;
  115. }
  116. /* At this point shm_stat->tvr and shm_stat->tvt contain valid ns-level
  117. ** timestamps, possibly generated by extending the old
  118. ** us-level timestamps
  119. */
  120. break;
  121. case 1:
  122. shm_stat->tvr.tv_sec = shmcopy.receiveTimeStampSec;
  123. shm_stat->tvr.tv_nsec = shmcopy.receiveTimeStampUSec * 1000;
  124. rns_new = shmcopy.receiveTimeStampNSec;
  125. shm_stat->tvt.tv_sec = shmcopy.clockTimeStampSec;
  126. shm_stat->tvt.tv_nsec = shmcopy.clockTimeStampUSec * 1000;
  127. cns_new = shmcopy.clockTimeStampNSec;
  128. /* See the case above for an explanation of the
  129. ** following test.
  130. */
  131. if (((cns_new - (unsigned)shm_stat->tvt.tv_nsec) < 1000)
  132. && ((rns_new - (unsigned)shm_stat->tvr.tv_nsec) < 1000)) {
  133. shm_stat->tvt.tv_nsec = cns_new;
  134. shm_stat->tvr.tv_nsec = rns_new;
  135. }
  136. /* At this point shm_stat->tvr and shm_stat->tvt contains valid ns-level
  137. ** timestamps, possibly generated by extending the old
  138. ** us-level timestamps
  139. */
  140. break;
  141. default:
  142. shm_stat->status = BAD_MODE;
  143. break;
  144. }
  145. /*
  146. * leap field is not a leap offset but a leap notification code.
  147. * The values are magic numbers used by NTP and set by GPSD, if at all, in
  148. * the subframe code.
  149. */
  150. shm_stat->leap = shmcopy.leap;
  151. shm_stat->precision = shmcopy.precision;
  152. return shm_stat->status;
  153. }
  154. /* end */