Home | History | Annotate | Line # | Download | only in util
      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