Home | History | Annotate | Line # | Download | only in util
sht.c revision 1.5
      1 /*	$NetBSD: sht.c,v 1.5 2018/09/29 21:52:35 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 
     27 struct 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 
     49 static struct shmTime *
     50 getShmTime (
     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 
    115 int
    116 main (
    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 		}
    174 again:
    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