1c0b746e5SOllivier Robert /*
2c0b746e5SOllivier Robert * sht.c - Testprogram for shared memory refclock
3c0b746e5SOllivier Robert * read/write shared memory segment; see usage
4c0b746e5SOllivier Robert */
52b15cb3dSCy Schubert #include "config.h"
62b15cb3dSCy Schubert
7c0b746e5SOllivier Robert #ifndef SYS_WINNT
8c0b746e5SOllivier Robert #include <sys/types.h>
9c0b746e5SOllivier Robert #include <sys/ipc.h>
10c0b746e5SOllivier Robert #include <sys/shm.h>
11c0b746e5SOllivier Robert #include <stdio.h>
12c0b746e5SOllivier Robert #include <time.h>
13c0b746e5SOllivier Robert #include <unistd.h>
14c0b746e5SOllivier Robert #include <stdlib.h>
15c0b746e5SOllivier Robert #else
16c0b746e5SOllivier Robert #include <windows.h>
17c0b746e5SOllivier Robert #include <time.h>
18c0b746e5SOllivier Robert #include <stdlib.h>
19c0b746e5SOllivier Robert #include <stdio.h>
20c0b746e5SOllivier Robert #include <iostream.h>
21c0b746e5SOllivier Robert #define sleep(x) Sleep(x*1000)
22c0b746e5SOllivier Robert #endif
23c0b746e5SOllivier Robert #include <assert.h>
242b15cb3dSCy Schubert
25c0b746e5SOllivier Robert struct shmTime {
26c0b746e5SOllivier Robert int mode; /* 0 - if valid set
27c0b746e5SOllivier Robert * use values,
28c0b746e5SOllivier Robert * clear valid
29c0b746e5SOllivier Robert * 1 - if valid set
30c0b746e5SOllivier Robert * if count before and after read of values is equal,
31c0b746e5SOllivier Robert * use values
32c0b746e5SOllivier Robert * clear valid
33c0b746e5SOllivier Robert */
342b15cb3dSCy Schubert volatile int count;
35c0b746e5SOllivier Robert time_t clockTimeStampSec;
36c0b746e5SOllivier Robert int clockTimeStampUSec;
37c0b746e5SOllivier Robert time_t receiveTimeStampSec;
38c0b746e5SOllivier Robert int receiveTimeStampUSec;
39c0b746e5SOllivier Robert int leap;
40c0b746e5SOllivier Robert int precision;
41c0b746e5SOllivier Robert int nsamples;
422b15cb3dSCy Schubert volatile int valid;
432b15cb3dSCy Schubert unsigned clockTimeStampNSec; /* Unsigned ns timestamps */
442b15cb3dSCy Schubert unsigned receiveTimeStampNSec; /* Unsigned ns timestamps */
45c0b746e5SOllivier Robert };
46c0b746e5SOllivier Robert
472b15cb3dSCy Schubert static struct shmTime *
getShmTime(int unit)48c0b746e5SOllivier Robert getShmTime (
49c0b746e5SOllivier Robert int unit
50c0b746e5SOllivier Robert )
51c0b746e5SOllivier Robert {
52c0b746e5SOllivier Robert #ifndef SYS_WINNT
53c0b746e5SOllivier Robert int shmid=shmget (0x4e545030+unit, sizeof (struct shmTime), IPC_CREAT|0777);
54c0b746e5SOllivier Robert if (shmid==-1) {
55c0b746e5SOllivier Robert perror ("shmget");
56c0b746e5SOllivier Robert exit (1);
57c0b746e5SOllivier Robert }
58c0b746e5SOllivier Robert else {
59c0b746e5SOllivier Robert struct shmTime *p=(struct shmTime *)shmat (shmid, 0, 0);
60c0b746e5SOllivier Robert if ((int)(long)p==-1) {
61c0b746e5SOllivier Robert perror ("shmat");
62c0b746e5SOllivier Robert p=0;
63c0b746e5SOllivier Robert }
64c0b746e5SOllivier Robert assert (p!=0);
65c0b746e5SOllivier Robert return p;
66c0b746e5SOllivier Robert }
67c0b746e5SOllivier Robert #else
68c0b746e5SOllivier Robert char buf[10];
69c0b746e5SOllivier Robert LPSECURITY_ATTRIBUTES psec=0;
702b15cb3dSCy Schubert snprintf (buf, sizeof(buf), "NTP%d", unit);
71c0b746e5SOllivier Robert SECURITY_DESCRIPTOR sd;
72c0b746e5SOllivier Robert SECURITY_ATTRIBUTES sa;
73c0b746e5SOllivier Robert HANDLE shmid;
74c0b746e5SOllivier Robert
75c0b746e5SOllivier Robert assert (InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION));
76c0b746e5SOllivier Robert assert (SetSecurityDescriptorDacl(&sd,1,0,0));
77c0b746e5SOllivier Robert sa.nLength=sizeof (SECURITY_ATTRIBUTES);
78c0b746e5SOllivier Robert sa.lpSecurityDescriptor=&sd;
79c0b746e5SOllivier Robert sa.bInheritHandle=0;
80c0b746e5SOllivier Robert shmid=CreateFileMapping ((HANDLE)0xffffffff, 0, PAGE_READWRITE,
81c0b746e5SOllivier Robert psec, sizeof (struct shmTime),buf);
82c0b746e5SOllivier Robert if (!shmid) {
83c0b746e5SOllivier Robert shmid=CreateFileMapping ((HANDLE)0xffffffff, 0, PAGE_READWRITE,
84c0b746e5SOllivier Robert 0, sizeof (struct shmTime),buf);
85c0b746e5SOllivier Robert cout <<"CreateFileMapping with psec!=0 failed"<<endl;
86c0b746e5SOllivier Robert }
87c0b746e5SOllivier Robert
88c0b746e5SOllivier Robert if (!shmid) {
89c0b746e5SOllivier Robert char mbuf[1000];
90c0b746e5SOllivier Robert FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM,
91c0b746e5SOllivier Robert 0, GetLastError (), 0, mbuf, sizeof (mbuf), 0);
92c0b746e5SOllivier Robert int x=GetLastError ();
93c0b746e5SOllivier Robert cout <<"CreateFileMapping "<<buf<<":"<<mbuf<<endl;
94c0b746e5SOllivier Robert exit (1);
95c0b746e5SOllivier Robert }
96c0b746e5SOllivier Robert else {
97c0b746e5SOllivier Robert struct shmTime *p=(struct shmTime *) MapViewOfFile (shmid,
98c0b746e5SOllivier Robert FILE_MAP_WRITE, 0, 0, sizeof (struct shmTime));
99c0b746e5SOllivier Robert if (p==0) {
100c0b746e5SOllivier Robert char mbuf[1000];
101c0b746e5SOllivier Robert FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM,
102c0b746e5SOllivier Robert 0, GetLastError (), 0, mbuf, sizeof (mbuf), 0);
103c0b746e5SOllivier Robert cout <<"MapViewOfFile "<<buf<<":"<<mbuf<<endl;
104c0b746e5SOllivier Robert exit (1);
105c0b746e5SOllivier Robert }
106c0b746e5SOllivier Robert return p;
107c0b746e5SOllivier Robert }
108c0b746e5SOllivier Robert return 0;
109c0b746e5SOllivier Robert #endif
110c0b746e5SOllivier Robert }
111c0b746e5SOllivier Robert
112c0b746e5SOllivier Robert
113c0b746e5SOllivier Robert int
main(int argc,char * argv[])114c0b746e5SOllivier Robert main (
115c0b746e5SOllivier Robert int argc,
116c0b746e5SOllivier Robert char *argv[]
117c0b746e5SOllivier Robert )
118c0b746e5SOllivier Robert {
1192b15cb3dSCy Schubert volatile struct shmTime *p;
1202b15cb3dSCy Schubert int unit;
1212b15cb3dSCy Schubert char *argp;
1222b15cb3dSCy Schubert
123c0b746e5SOllivier Robert if (argc<=1) {
1242b15cb3dSCy Schubert usage:
1252b15cb3dSCy Schubert printf ("usage: %s [uu:]{r[c][l]|w|snnn}\n",argv[0]);
1262b15cb3dSCy Schubert printf (" uu use clock unit uu (default: 2)\n");
127c0b746e5SOllivier Robert printf (" r read shared memory\n");
128c0b746e5SOllivier Robert printf (" c clear valid-flag\n");
129c0b746e5SOllivier Robert printf (" l loop (so, rcl will read and clear in a loop\n");
130c0b746e5SOllivier Robert printf (" w write shared memory with current time\n");
131c0b746e5SOllivier Robert printf (" snnnn set nsamples to nnn\n");
132c0b746e5SOllivier Robert printf (" lnnnn set leap to nnn\n");
133c0b746e5SOllivier Robert printf (" pnnnn set precision to -nnn\n");
134c0b746e5SOllivier Robert exit (0);
135c0b746e5SOllivier Robert }
1362b15cb3dSCy Schubert
1372b15cb3dSCy Schubert srand(time(NULL));
1382b15cb3dSCy Schubert
1392b15cb3dSCy Schubert unit = strtoul(argv[1], &argp, 10);
1402b15cb3dSCy Schubert if (argp == argv[1])
1412b15cb3dSCy Schubert unit = 2;
1422b15cb3dSCy Schubert else if (*argp == ':')
1432b15cb3dSCy Schubert argp++;
1442b15cb3dSCy Schubert else
1452b15cb3dSCy Schubert goto usage;
1462b15cb3dSCy Schubert
1472b15cb3dSCy Schubert p=getShmTime(unit);
1482b15cb3dSCy Schubert switch (*argp) {
1492b15cb3dSCy Schubert case 's':
1502b15cb3dSCy Schubert p->nsamples=atoi(argp+1);
151c0b746e5SOllivier Robert break;
1522b15cb3dSCy Schubert
1532b15cb3dSCy Schubert case 'l':
1542b15cb3dSCy Schubert p->leap=atoi(argp+1);
155c0b746e5SOllivier Robert break;
1562b15cb3dSCy Schubert
1572b15cb3dSCy Schubert case 'p':
1582b15cb3dSCy Schubert p->precision=-atoi(argp+1);
159c0b746e5SOllivier Robert break;
1602b15cb3dSCy Schubert
161c0b746e5SOllivier Robert case 'r': {
162c0b746e5SOllivier Robert int clear=0;
163c0b746e5SOllivier Robert int loop=0;
164c0b746e5SOllivier Robert printf ("reader\n");
1652b15cb3dSCy Schubert while (*++argp) {
1662b15cb3dSCy Schubert switch (*argp) {
167c0b746e5SOllivier Robert case 'l': loop=1; break;
168c0b746e5SOllivier Robert case 'c': clear=1; break;
1692b15cb3dSCy Schubert default : goto usage;
170c0b746e5SOllivier Robert }
171c0b746e5SOllivier Robert }
1722b15cb3dSCy Schubert again:
1732b15cb3dSCy Schubert printf ("mode=%d, count=%d, clock=%ld.%09u, rec=%ld.%09u,\n",
1742b15cb3dSCy Schubert p->mode,p->count,
1752b15cb3dSCy Schubert (long)p->clockTimeStampSec,p->clockTimeStampNSec,
1762b15cb3dSCy Schubert (long)p->receiveTimeStampSec,p->receiveTimeStampNSec);
177c0b746e5SOllivier Robert printf (" leap=%d, precision=%d, nsamples=%d, valid=%d\n",
178c0b746e5SOllivier Robert p->leap, p->precision, p->nsamples, p->valid);
179c0b746e5SOllivier Robert if (!p->valid)
180c0b746e5SOllivier Robert printf ("***\n");
181c0b746e5SOllivier Robert if (clear) {
182c0b746e5SOllivier Robert p->valid=0;
183c0b746e5SOllivier Robert printf ("cleared\n");
184c0b746e5SOllivier Robert }
1852b15cb3dSCy Schubert if (loop) {
186c0b746e5SOllivier Robert sleep (1);
1872b15cb3dSCy Schubert goto again;
188c0b746e5SOllivier Robert }
189c0b746e5SOllivier Robert break;
1902b15cb3dSCy Schubert }
1912b15cb3dSCy Schubert
192c0b746e5SOllivier Robert case 'w': {
1932b15cb3dSCy Schubert /* To show some life action, we read the system
1942b15cb3dSCy Schubert * clock and use a bit of fuzz from 'random()' to get a
1952b15cb3dSCy Schubert * bit of wobbling into the values (so we can observe a
1962b15cb3dSCy Schubert * certain jitter!)
1972b15cb3dSCy Schubert */
1982b15cb3dSCy Schubert time_t clk_sec, rcv_sec;
199*4e1ef62aSXin LI u_int clk_frc, rcv_frc;
2002b15cb3dSCy Schubert
2012b15cb3dSCy Schubert #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_REALTIME)
2022b15cb3dSCy Schubert
2032b15cb3dSCy Schubert /* Here we have a high-resolution system clock, and
2042b15cb3dSCy Schubert * we're not afraid to use it!
2052b15cb3dSCy Schubert */
2062b15cb3dSCy Schubert struct timespec tmptime;
2072b15cb3dSCy Schubert if (0 == clock_gettime(CLOCK_REALTIME, &tmptime)) {
2082b15cb3dSCy Schubert rcv_sec = tmptime.tv_sec;
209*4e1ef62aSXin LI rcv_frc = (u_int)tmptime.tv_nsec;
2102b15cb3dSCy Schubert }
2112b15cb3dSCy Schubert else
2122b15cb3dSCy Schubert #endif
2132b15cb3dSCy Schubert {
2142b15cb3dSCy Schubert time(&rcv_sec);
215*4e1ef62aSXin LI rcv_frc = (u_int)random() % 1000000000u;
2162b15cb3dSCy Schubert }
2172b15cb3dSCy Schubert /* add a wobble of ~3.5msec to the clock time */
2182b15cb3dSCy Schubert clk_sec = rcv_sec;
219*4e1ef62aSXin LI clk_frc = rcv_frc + (u_int)(random()%7094713 - 3547356);
2202b15cb3dSCy Schubert /* normalise result -- the SHM driver is picky! */
2212b15cb3dSCy Schubert while ((int)clk_frc < 0) {
2222b15cb3dSCy Schubert clk_frc += 1000000000;
2232b15cb3dSCy Schubert clk_sec -= 1;
2242b15cb3dSCy Schubert }
2252b15cb3dSCy Schubert while ((int)clk_frc >= 1000000000) {
2262b15cb3dSCy Schubert clk_frc -= 1000000000;
2272b15cb3dSCy Schubert clk_sec += 1;
2282b15cb3dSCy Schubert }
2292b15cb3dSCy Schubert
2302b15cb3dSCy Schubert /* Most 'real' time sources would create a clock
2312b15cb3dSCy Schubert * (reference) time stamp where the fraction is zero,
2322b15cb3dSCy Schubert * but that's not an actual requirement. So we show how
2332b15cb3dSCy Schubert * to deal with the time stamps in general; changing the
2342b15cb3dSCy Schubert * behaviour for cases where the fraction of the
2352b15cb3dSCy Schubert * clock time is zero should be trivial.
2362b15cb3dSCy Schubert */
237c0b746e5SOllivier Robert printf ("writer\n");
238c0b746e5SOllivier Robert p->mode=0;
239c0b746e5SOllivier Robert if (!p->valid) {
2402b15cb3dSCy Schubert p->clockTimeStampSec = clk_sec;
2412b15cb3dSCy Schubert p->clockTimeStampUSec = clk_frc / 1000; /* truncate! */
2422b15cb3dSCy Schubert p->clockTimeStampNSec = clk_frc;
2432b15cb3dSCy Schubert p->receiveTimeStampSec = rcv_sec;
2442b15cb3dSCy Schubert p->receiveTimeStampUSec = rcv_frc / 1000; /* truncate! */
2452b15cb3dSCy Schubert p->receiveTimeStampNSec = rcv_frc;
2462b15cb3dSCy Schubert printf ("%ld.%09u %ld.%09u\n",
2472b15cb3dSCy Schubert (long)p->clockTimeStampSec , p->clockTimeStampNSec ,
2482b15cb3dSCy Schubert (long)p->receiveTimeStampSec, p->receiveTimeStampNSec);
249c0b746e5SOllivier Robert p->valid=1;
250c0b746e5SOllivier Robert }
251c0b746e5SOllivier Robert else {
2529c2daa00SOllivier Robert printf ("p->valid still set\n"); /* not an error! */
253c0b746e5SOllivier Robert }
254c0b746e5SOllivier Robert break;
255c0b746e5SOllivier Robert }
2562b15cb3dSCy Schubert default:
2572b15cb3dSCy Schubert break;
2582b15cb3dSCy Schubert }
2592b15cb3dSCy Schubert return 0;
260c0b746e5SOllivier Robert }
261