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