1 /*
2   chronyd/chronyc - Programs for keeping computer clocks accurate.
3 
4  **********************************************************************
5  * Copyright (C) Miroslav Lichvar  2009
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of version 2 of the GNU General Public License as
9  * published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19  *
20  **********************************************************************
21 
22   =======================================================================
23 
24   SHM refclock driver.
25 
26   */
27 
28 #include "config.h"
29 
30 #include "sysincl.h"
31 
32 #include "refclock.h"
33 #include "logging.h"
34 #include "util.h"
35 
36 #define SHMKEY 0x4e545030
37 
38 struct shmTime {
39   int    mode; /* 0 - if valid set
40                 *       use values,
41                 *       clear valid
42                 * 1 - if valid set
43                 *       if count before and after read of values is equal,
44                 *         use values
45                 *       clear valid
46                 */
47   volatile int count;
48   time_t clockTimeStampSec;
49   int    clockTimeStampUSec;
50   time_t receiveTimeStampSec;
51   int    receiveTimeStampUSec;
52   int    leap;
53   int    precision;
54   int    nsamples;
55   volatile int valid;
56   int    clockTimeStampNSec;
57   int    receiveTimeStampNSec;
58   int    dummy[8];
59 };
60 
shm_initialise(RCL_Instance instance)61 static int shm_initialise(RCL_Instance instance) {
62   const char *options[] = {"perm", NULL};
63   int id, param, perm;
64   char *s;
65   struct shmTime *shm;
66 
67   RCL_CheckDriverOptions(instance, options);
68 
69   param = atoi(RCL_GetDriverParameter(instance));
70   s = RCL_GetDriverOption(instance, "perm");
71   perm = s ? strtol(s, NULL, 8) & 0777 : 0600;
72 
73   id = shmget(SHMKEY + param, sizeof (struct shmTime), IPC_CREAT | perm);
74   if (id == -1) {
75     LOG_FATAL("shmget() failed : %s", strerror(errno));
76     return 0;
77   }
78 
79   shm = (struct shmTime *)shmat(id, 0, 0);
80   if ((long)shm == -1) {
81     LOG_FATAL("shmat() failed : %s", strerror(errno));
82     return 0;
83   }
84 
85   RCL_SetDriverData(instance, shm);
86   return 1;
87 }
88 
shm_finalise(RCL_Instance instance)89 static void shm_finalise(RCL_Instance instance)
90 {
91   shmdt(RCL_GetDriverData(instance));
92 }
93 
shm_poll(RCL_Instance instance)94 static int shm_poll(RCL_Instance instance)
95 {
96   struct timespec receive_ts, clock_ts;
97   struct shmTime t, *shm;
98   double offset;
99 
100   shm = (struct shmTime *)RCL_GetDriverData(instance);
101 
102   t = *shm;
103 
104   if ((t.mode == 1 && t.count != shm->count) ||
105     !(t.mode == 0 || t.mode == 1) || !t.valid) {
106     DEBUG_LOG("SHM sample ignored mode=%d count=%d valid=%d",
107         t.mode, t.count, t.valid);
108     return 0;
109   }
110 
111   shm->valid = 0;
112 
113   receive_ts.tv_sec = t.receiveTimeStampSec;
114   clock_ts.tv_sec = t.clockTimeStampSec;
115 
116   if (t.clockTimeStampNSec / 1000 == t.clockTimeStampUSec &&
117       t.receiveTimeStampNSec / 1000 == t.receiveTimeStampUSec) {
118     receive_ts.tv_nsec = t.receiveTimeStampNSec;
119     clock_ts.tv_nsec = t.clockTimeStampNSec;
120   } else {
121     receive_ts.tv_nsec = 1000 * t.receiveTimeStampUSec;
122     clock_ts.tv_nsec = 1000 * t.clockTimeStampUSec;
123   }
124 
125   UTI_NormaliseTimespec(&clock_ts);
126   UTI_NormaliseTimespec(&receive_ts);
127   offset = UTI_DiffTimespecsToDouble(&clock_ts, &receive_ts);
128 
129   return RCL_AddSample(instance, &receive_ts, offset, t.leap);
130 }
131 
132 RefclockDriver RCL_SHM_driver = {
133   shm_initialise,
134   shm_finalise,
135   shm_poll
136 };
137