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