1 1.6 christos /* $NetBSD: sht.c,v 1.6 2020/05/25 20:47:37 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