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 27struct 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 49static struct shmTime * 50getShmTime ( 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 115int 116main ( 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 } 174again: 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