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 25 struct 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 47 static struct shmTime * 48 getShmTime ( 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 113 int 114 main ( 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 } 172 again: 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 u_int 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 = (u_int)tmptime.tv_nsec; 210 } 211 else 212 #endif 213 { 214 time(&rcv_sec); 215 rcv_frc = (u_int)random() % 1000000000u; 216 } 217 /* add a wobble of ~3.5msec to the clock time */ 218 clk_sec = rcv_sec; 219 clk_frc = rcv_frc + (u_int)(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