1 /* $NetBSD: sht.c,v 1.6 2020/05/25 20:47:37 christos Exp $ */
2
3 /*
4 * sht.c - Testprogram for shared memory refclock
5 * read/write shared memory segment; see usage
6 */
7 #include "config.h"
8
9 #ifndef SYS_WINNT
10 #include <sys/types.h>
11 #include <sys/ipc.h>
12 #include <sys/shm.h>
13 #include <stdio.h>
14 #include <time.h>
15 #include <unistd.h>
16 #include <stdlib.h>
17 #else
18 #include <windows.h>
19 #include <time.h>
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <iostream.h>
23 #define sleep(x) Sleep(x*1000)
24 #endif
25 #include <assert.h>
26
27 struct shmTime {
28 int mode; /* 0 - if valid set
29 * use values,
30 * clear valid
31 * 1 - if valid set
32 * if count before and after read of values is equal,
33 * use values
34 * clear valid
35 */
36 volatile int count;
37 time_t clockTimeStampSec;
38 int clockTimeStampUSec;
39 time_t receiveTimeStampSec;
40 int receiveTimeStampUSec;
41 int leap;
42 int precision;
43 int nsamples;
44 volatile int valid;
45 unsigned clockTimeStampNSec; /* Unsigned ns timestamps */
46 unsigned receiveTimeStampNSec; /* Unsigned ns timestamps */
47 };
48
49 static struct shmTime *
getShmTime(int unit)50 getShmTime (
51 int unit
52 )
53 {
54 #ifndef SYS_WINNT
55 int shmid=shmget (0x4e545030+unit, sizeof (struct shmTime), IPC_CREAT|0777);
56 if (shmid==-1) {
57 perror ("shmget");
58 exit (1);
59 }
60 else {
61 struct shmTime *p=(struct shmTime *)shmat (shmid, 0, 0);
62 if ((int)(long)p==-1) {
63 perror ("shmat");
64 p=0;
65 }
66 assert (p!=0);
67 return p;
68 }
69 #else
70 char buf[10];
71 LPSECURITY_ATTRIBUTES psec=0;
72 snprintf (buf, sizeof(buf), "NTP%d", unit);
73 SECURITY_DESCRIPTOR sd;
74 SECURITY_ATTRIBUTES sa;
75 HANDLE shmid;
76
77 assert (InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION));
78 assert (SetSecurityDescriptorDacl(&sd,1,0,0));
79 sa.nLength=sizeof (SECURITY_ATTRIBUTES);
80 sa.lpSecurityDescriptor=&sd;
81 sa.bInheritHandle=0;
82 shmid=CreateFileMapping ((HANDLE)0xffffffff, 0, PAGE_READWRITE,
83 psec, sizeof (struct shmTime),buf);
84 if (!shmid) {
85 shmid=CreateFileMapping ((HANDLE)0xffffffff, 0, PAGE_READWRITE,
86 0, sizeof (struct shmTime),buf);
87 cout <<"CreateFileMapping with psec!=0 failed"<<endl;
88 }
89
90 if (!shmid) {
91 char mbuf[1000];
92 FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM,
93 0, GetLastError (), 0, mbuf, sizeof (mbuf), 0);
94 int x=GetLastError ();
95 cout <<"CreateFileMapping "<<buf<<":"<<mbuf<<endl;
96 exit (1);
97 }
98 else {
99 struct shmTime *p=(struct shmTime *) MapViewOfFile (shmid,
100 FILE_MAP_WRITE, 0, 0, sizeof (struct shmTime));
101 if (p==0) {
102 char mbuf[1000];
103 FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM,
104 0, GetLastError (), 0, mbuf, sizeof (mbuf), 0);
105 cout <<"MapViewOfFile "<<buf<<":"<<mbuf<<endl;
106 exit (1);
107 }
108 return p;
109 }
110 return 0;
111 #endif
112 }
113
114
115 int
main(int argc,char * argv[])116 main (
117 int argc,
118 char *argv[]
119 )
120 {
121 volatile struct shmTime *p;
122 int unit;
123 char *argp;
124
125 if (argc<=1) {
126 usage:
127 printf ("usage: %s [uu:]{r[c][l]|w|snnn}\n",argv[0]);
128 printf (" uu use clock unit uu (default: 2)\n");
129 printf (" r read shared memory\n");
130 printf (" c clear valid-flag\n");
131 printf (" l loop (so, rcl will read and clear in a loop\n");
132 printf (" w write shared memory with current time\n");
133 printf (" snnnn set nsamples to nnn\n");
134 printf (" lnnnn set leap to nnn\n");
135 printf (" pnnnn set precision to -nnn\n");
136 exit (0);
137 }
138
139 srand(time(NULL));
140
141 unit = strtoul(argv[1], &argp, 10);
142 if (argp == argv[1])
143 unit = 2;
144 else if (*argp == ':')
145 argp++;
146 else
147 goto usage;
148
149 p=getShmTime(unit);
150 switch (*argp) {
151 case 's':
152 p->nsamples=atoi(argp+1);
153 break;
154
155 case 'l':
156 p->leap=atoi(argp+1);
157 break;
158
159 case 'p':
160 p->precision=-atoi(argp+1);
161 break;
162
163 case 'r': {
164 int clear=0;
165 int loop=0;
166 printf ("reader\n");
167 while (*++argp) {
168 switch (*argp) {
169 case 'l': loop=1; break;
170 case 'c': clear=1; break;
171 default : goto usage;
172 }
173 }
174 again:
175 printf ("mode=%d, count=%d, clock=%ld.%09u, rec=%ld.%09u,\n",
176 p->mode,p->count,
177 (long)p->clockTimeStampSec,p->clockTimeStampNSec,
178 (long)p->receiveTimeStampSec,p->receiveTimeStampNSec);
179 printf (" leap=%d, precision=%d, nsamples=%d, valid=%d\n",
180 p->leap, p->precision, p->nsamples, p->valid);
181 if (!p->valid)
182 printf ("***\n");
183 if (clear) {
184 p->valid=0;
185 printf ("cleared\n");
186 }
187 if (loop) {
188 sleep (1);
189 goto again;
190 }
191 break;
192 }
193
194 case 'w': {
195 /* To show some life action, we read the system
196 * clock and use a bit of fuzz from 'random()' to get a
197 * bit of wobbling into the values (so we can observe a
198 * certain jitter!)
199 */
200 time_t clk_sec, rcv_sec;
201 u_int clk_frc, rcv_frc;
202
203 #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_REALTIME)
204
205 /* Here we have a high-resolution system clock, and
206 * we're not afraid to use it!
207 */
208 struct timespec tmptime;
209 if (0 == clock_gettime(CLOCK_REALTIME, &tmptime)) {
210 rcv_sec = tmptime.tv_sec;
211 rcv_frc = (u_int)tmptime.tv_nsec;
212 }
213 else
214 #endif
215 {
216 time(&rcv_sec);
217 rcv_frc = (u_int)random() % 1000000000u;
218 }
219 /* add a wobble of ~3.5msec to the clock time */
220 clk_sec = rcv_sec;
221 clk_frc = rcv_frc + (u_int)(random()%7094713 - 3547356);
222 /* normalise result -- the SHM driver is picky! */
223 while ((int)clk_frc < 0) {
224 clk_frc += 1000000000;
225 clk_sec -= 1;
226 }
227 while ((int)clk_frc >= 1000000000) {
228 clk_frc -= 1000000000;
229 clk_sec += 1;
230 }
231
232 /* Most 'real' time sources would create a clock
233 * (reference) time stamp where the fraction is zero,
234 * but that's not an actual requirement. So we show how
235 * to deal with the time stamps in general; changing the
236 * behaviour for cases where the fraction of the
237 * clock time is zero should be trivial.
238 */
239 printf ("writer\n");
240 p->mode=0;
241 if (!p->valid) {
242 p->clockTimeStampSec = clk_sec;
243 p->clockTimeStampUSec = clk_frc / 1000; /* truncate! */
244 p->clockTimeStampNSec = clk_frc;
245 p->receiveTimeStampSec = rcv_sec;
246 p->receiveTimeStampUSec = rcv_frc / 1000; /* truncate! */
247 p->receiveTimeStampNSec = rcv_frc;
248 printf ("%ld.%09u %ld.%09u\n",
249 (long)p->clockTimeStampSec , p->clockTimeStampNSec ,
250 (long)p->receiveTimeStampSec, p->receiveTimeStampNSec);
251 p->valid=1;
252 }
253 else {
254 printf ("p->valid still set\n"); /* not an error! */
255 }
256 break;
257 }
258 default:
259 break;
260 }
261 return 0;
262 }
263