154359Sroberto/* 254359Sroberto * sht.c - Testprogram for shared memory refclock 354359Sroberto * read/write shared memory segment; see usage 454359Sroberto */ 5285612Sdelphij#include "config.h" 6285612Sdelphij 754359Sroberto#ifndef SYS_WINNT 854359Sroberto#include <sys/types.h> 954359Sroberto#include <sys/ipc.h> 1054359Sroberto#include <sys/shm.h> 1154359Sroberto#include <stdio.h> 1254359Sroberto#include <time.h> 1354359Sroberto#include <unistd.h> 1454359Sroberto#include <stdlib.h> 1554359Sroberto#else 1654359Sroberto#include <windows.h> 1754359Sroberto#include <time.h> 1854359Sroberto#include <stdlib.h> 1954359Sroberto#include <stdio.h> 2054359Sroberto#include <iostream.h> 2154359Sroberto#define sleep(x) Sleep(x*1000) 2254359Sroberto#endif 2354359Sroberto#include <assert.h> 24285612Sdelphij 2554359Srobertostruct shmTime { 2654359Sroberto int mode; /* 0 - if valid set 2754359Sroberto * use values, 2854359Sroberto * clear valid 2954359Sroberto * 1 - if valid set 3054359Sroberto * if count before and after read of values is equal, 3154359Sroberto * use values 3254359Sroberto * clear valid 3354359Sroberto */ 34285612Sdelphij volatile int count; 35285612Sdelphij time_t clockTimeStampSec; 36285612Sdelphij int clockTimeStampUSec; 37285612Sdelphij time_t receiveTimeStampSec; 38285612Sdelphij int receiveTimeStampUSec; 39285612Sdelphij int leap; 40285612Sdelphij int precision; 41285612Sdelphij int nsamples; 42285612Sdelphij volatile int valid; 43285612Sdelphij unsigned clockTimeStampNSec; /* Unsigned ns timestamps */ 44285612Sdelphij unsigned receiveTimeStampNSec; /* Unsigned ns timestamps */ 4554359Sroberto}; 4654359Sroberto 47285612Sdelphijstatic struct shmTime * 4854359SrobertogetShmTime ( 4954359Sroberto int unit 5054359Sroberto ) 5154359Sroberto{ 5254359Sroberto#ifndef SYS_WINNT 5354359Sroberto int shmid=shmget (0x4e545030+unit, sizeof (struct shmTime), IPC_CREAT|0777); 5454359Sroberto if (shmid==-1) { 5554359Sroberto perror ("shmget"); 5654359Sroberto exit (1); 5754359Sroberto } 5854359Sroberto else { 5954359Sroberto struct shmTime *p=(struct shmTime *)shmat (shmid, 0, 0); 6054359Sroberto if ((int)(long)p==-1) { 6154359Sroberto perror ("shmat"); 6254359Sroberto p=0; 6354359Sroberto } 6454359Sroberto assert (p!=0); 6554359Sroberto return p; 6654359Sroberto } 6754359Sroberto#else 6854359Sroberto char buf[10]; 6954359Sroberto LPSECURITY_ATTRIBUTES psec=0; 70285612Sdelphij snprintf (buf, sizeof(buf), "NTP%d", unit); 7154359Sroberto SECURITY_DESCRIPTOR sd; 7254359Sroberto SECURITY_ATTRIBUTES sa; 7354359Sroberto HANDLE shmid; 7454359Sroberto 7554359Sroberto assert (InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)); 7654359Sroberto assert (SetSecurityDescriptorDacl(&sd,1,0,0)); 7754359Sroberto sa.nLength=sizeof (SECURITY_ATTRIBUTES); 7854359Sroberto sa.lpSecurityDescriptor=&sd; 7954359Sroberto sa.bInheritHandle=0; 8054359Sroberto shmid=CreateFileMapping ((HANDLE)0xffffffff, 0, PAGE_READWRITE, 8154359Sroberto psec, sizeof (struct shmTime),buf); 8254359Sroberto if (!shmid) { 8354359Sroberto shmid=CreateFileMapping ((HANDLE)0xffffffff, 0, PAGE_READWRITE, 8454359Sroberto 0, sizeof (struct shmTime),buf); 8554359Sroberto cout <<"CreateFileMapping with psec!=0 failed"<<endl; 8654359Sroberto } 8754359Sroberto 8854359Sroberto if (!shmid) { 8954359Sroberto char mbuf[1000]; 9054359Sroberto FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, 9154359Sroberto 0, GetLastError (), 0, mbuf, sizeof (mbuf), 0); 9254359Sroberto int x=GetLastError (); 9354359Sroberto cout <<"CreateFileMapping "<<buf<<":"<<mbuf<<endl; 9454359Sroberto exit (1); 9554359Sroberto } 9654359Sroberto else { 9754359Sroberto struct shmTime *p=(struct shmTime *) MapViewOfFile (shmid, 9854359Sroberto FILE_MAP_WRITE, 0, 0, sizeof (struct shmTime)); 9954359Sroberto if (p==0) { 10054359Sroberto char mbuf[1000]; 10154359Sroberto FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, 10254359Sroberto 0, GetLastError (), 0, mbuf, sizeof (mbuf), 0); 10354359Sroberto cout <<"MapViewOfFile "<<buf<<":"<<mbuf<<endl; 10454359Sroberto exit (1); 10554359Sroberto } 10654359Sroberto return p; 10754359Sroberto } 10854359Sroberto return 0; 10954359Sroberto#endif 11054359Sroberto} 11154359Sroberto 11254359Sroberto 11354359Srobertoint 11454359Srobertomain ( 11554359Sroberto int argc, 11654359Sroberto char *argv[] 11754359Sroberto ) 11854359Sroberto{ 119285612Sdelphij volatile struct shmTime *p; 120285612Sdelphij int unit; 121285612Sdelphij char *argp; 122285612Sdelphij 12354359Sroberto if (argc<=1) { 124285612Sdelphij usage: 125285612Sdelphij printf ("usage: %s [uu:]{r[c][l]|w|snnn}\n",argv[0]); 126285612Sdelphij printf (" uu use clock unit uu (default: 2)\n"); 12754359Sroberto printf (" r read shared memory\n"); 128285612Sdelphij printf (" c clear valid-flag\n"); 129285612Sdelphij printf (" l loop (so, rcl will read and clear in a loop\n"); 13054359Sroberto printf (" w write shared memory with current time\n"); 13154359Sroberto printf (" snnnn set nsamples to nnn\n"); 13254359Sroberto printf (" lnnnn set leap to nnn\n"); 13354359Sroberto printf (" pnnnn set precision to -nnn\n"); 13454359Sroberto exit (0); 13554359Sroberto } 136285612Sdelphij 137285612Sdelphij srand(time(NULL)); 138285612Sdelphij 139285612Sdelphij unit = strtoul(argv[1], &argp, 10); 140285612Sdelphij if (argp == argv[1]) 141285612Sdelphij unit = 2; 142285612Sdelphij else if (*argp == ':') 143285612Sdelphij argp++; 144285612Sdelphij else 145285612Sdelphij goto usage; 146285612Sdelphij 147285612Sdelphij p=getShmTime(unit); 148285612Sdelphij switch (*argp) { 149285612Sdelphij case 's': 150285612Sdelphij p->nsamples=atoi(argp+1); 151285612Sdelphij break; 152285612Sdelphij 153285612Sdelphij case 'l': 154285612Sdelphij p->leap=atoi(argp+1); 155285612Sdelphij break; 156285612Sdelphij 157285612Sdelphij case 'p': 158285612Sdelphij p->precision=-atoi(argp+1); 159285612Sdelphij break; 160285612Sdelphij 161285612Sdelphij case 'r': { 162285612Sdelphij int clear=0; 163285612Sdelphij int loop=0; 164285612Sdelphij printf ("reader\n"); 165285612Sdelphij while (*++argp) { 166285612Sdelphij switch (*argp) { 167285612Sdelphij case 'l': loop=1; break; 168285612Sdelphij case 'c': clear=1; break; 169285612Sdelphij default : goto usage; 170285612Sdelphij } 171285612Sdelphij } 172285612Sdelphijagain: 173285612Sdelphij printf ("mode=%d, count=%d, clock=%ld.%09u, rec=%ld.%09u,\n", 174285612Sdelphij p->mode,p->count, 175285612Sdelphij (long)p->clockTimeStampSec,p->clockTimeStampNSec, 176285612Sdelphij (long)p->receiveTimeStampSec,p->receiveTimeStampNSec); 177285612Sdelphij printf (" leap=%d, precision=%d, nsamples=%d, valid=%d\n", 178285612Sdelphij p->leap, p->precision, p->nsamples, p->valid); 179285612Sdelphij if (!p->valid) 180285612Sdelphij printf ("***\n"); 181285612Sdelphij if (clear) { 182285612Sdelphij p->valid=0; 183285612Sdelphij printf ("cleared\n"); 184285612Sdelphij } 185285612Sdelphij if (loop) { 186285612Sdelphij sleep (1); 187285612Sdelphij goto again; 188285612Sdelphij } 189285612Sdelphij break; 19054359Sroberto } 191285612Sdelphij 192285612Sdelphij case 'w': { 193285612Sdelphij /* To show some life action, we read the system 194285612Sdelphij * clock and use a bit of fuzz from 'random()' to get a 195285612Sdelphij * bit of wobbling into the values (so we can observe a 196285612Sdelphij * certain jitter!) 197285612Sdelphij */ 198285612Sdelphij time_t clk_sec, rcv_sec; 199338531Sdelphij u_int clk_frc, rcv_frc; 200285612Sdelphij 201285612Sdelphij#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_REALTIME) 202285612Sdelphij 203285612Sdelphij /* Here we have a high-resolution system clock, and 204285612Sdelphij * we're not afraid to use it! 205285612Sdelphij */ 206285612Sdelphij struct timespec tmptime; 207285612Sdelphij if (0 == clock_gettime(CLOCK_REALTIME, &tmptime)) { 208285612Sdelphij rcv_sec = tmptime.tv_sec; 209338531Sdelphij rcv_frc = (u_int)tmptime.tv_nsec; 210285612Sdelphij } 211285612Sdelphij else 212285612Sdelphij#endif 213285612Sdelphij { 214285612Sdelphij time(&rcv_sec); 215338531Sdelphij rcv_frc = (u_int)random() % 1000000000u; 216285612Sdelphij } 217285612Sdelphij /* add a wobble of ~3.5msec to the clock time */ 218285612Sdelphij clk_sec = rcv_sec; 219338531Sdelphij clk_frc = rcv_frc + (u_int)(random()%7094713 - 3547356); 220285612Sdelphij /* normalise result -- the SHM driver is picky! */ 221285612Sdelphij while ((int)clk_frc < 0) { 222285612Sdelphij clk_frc += 1000000000; 223285612Sdelphij clk_sec -= 1; 224285612Sdelphij } 225285612Sdelphij while ((int)clk_frc >= 1000000000) { 226285612Sdelphij clk_frc -= 1000000000; 227285612Sdelphij clk_sec += 1; 228285612Sdelphij } 229285612Sdelphij 230285612Sdelphij /* Most 'real' time sources would create a clock 231285612Sdelphij * (reference) time stamp where the fraction is zero, 232285612Sdelphij * but that's not an actual requirement. So we show how 233285612Sdelphij * to deal with the time stamps in general; changing the 234285612Sdelphij * behaviour for cases where the fraction of the 235285612Sdelphij * clock time is zero should be trivial. 236285612Sdelphij */ 237285612Sdelphij printf ("writer\n"); 238285612Sdelphij p->mode=0; 239285612Sdelphij if (!p->valid) { 240285612Sdelphij p->clockTimeStampSec = clk_sec; 241285612Sdelphij p->clockTimeStampUSec = clk_frc / 1000; /* truncate! */ 242285612Sdelphij p->clockTimeStampNSec = clk_frc; 243285612Sdelphij p->receiveTimeStampSec = rcv_sec; 244285612Sdelphij p->receiveTimeStampUSec = rcv_frc / 1000; /* truncate! */ 245285612Sdelphij p->receiveTimeStampNSec = rcv_frc; 246285612Sdelphij printf ("%ld.%09u %ld.%09u\n", 247285612Sdelphij (long)p->clockTimeStampSec , p->clockTimeStampNSec , 248285612Sdelphij (long)p->receiveTimeStampSec, p->receiveTimeStampNSec); 249285612Sdelphij p->valid=1; 250285612Sdelphij } 251285612Sdelphij else { 252285612Sdelphij printf ("p->valid still set\n"); /* not an error! */ 253285612Sdelphij } 254285612Sdelphij break; 255285612Sdelphij } 256285612Sdelphij default: 257285612Sdelphij break; 258285612Sdelphij } 259285612Sdelphij return 0; 26054359Sroberto} 261