adjtime() emulation in QNX4: how to? (+)

Trying to fugure out how to emulate unix’s “adjtime()” with QNX v4.25G “qnx_adj_time()”.

As far as I could get the idea, adjtime() accepts two parameters: the pointer to the timeval structure where the desired time change (called “delta”) is stored and the pointer to the timeval structure where to put the remaining difference (“olddelta”) since the previous call.

adjtime() has no control of the rate for the time skew. So, if we call it too often (or with too big “delta”) it will return non-zero “olddelta” content.

qnx_adj_time() has very different prototype.
It accepts “long” of microseconds, “long” skew rate and two “long” counters where it puts the calculated value of “systime_change_per_tick” and the amount of ticks left till the system time will be changed by the desired value.

First my concern is: what if someone asks adjtime() to advance the time not by mere microseconds but, say, five and a half hours?! timeval structure may well contain even “till the next New Year” lot of time… Yes, this will take LONG to wait for, but it’s possible. Should there be a sanity check?
Or it’s generally accepted to have “seconds since EPOCH” == 0 when calling adjtime()? Hope so…

So, to my mind the QNX v4.25G (Watcom C v10.6 patch B + security patch) realisation of adjtime() might look like this:

int adjtime(const struct timeval *delta, struct timeval *olddelta) {
long c, d;
 
 #
 # QSSL recommends to have skew rate not exceeding 10%,
 # so I'll set it to 10 - fastest of allowed.
 #
 
 if (olddelta != NULL) {
   if (!qnx_adj_time(0, 0, &c, &d)) {
     olddelta->tv_seconds = 0;
     olddelta->tv_usec = ((c  / 1000L) * d);
   }
 }
 return (qnx_adj_time((delta->tv_usec), 10, NULL, NULL));
}

Please comment.
Tony.

maybe you can take a look at the QNX 4 patched source code of ntp at ftp.qnx.com:/usr/free …

:slight_smile:

That is exactly what I’m lookin at!

Seems that port ov NTP v1 was done very long time ago…
Here is it’s adjtime() realisation:

int
adjtime(delta, olddelta)
struct timeval *delta;
struct timeval *olddelta;
{

	int oldpolicy, status;
	struct timespec dtm;
	struct sched_param oldparam, newparam;

	if (olddelta != NULL) {
		olddelta->tv_sec = 0;
		olddelta->tv_usec = 0;
	}

	/*
	 * Since QNX lacks an adjtime() system call, we have to cheat
	 * by using clock_gettime and clock_settime.  This causes a race
	 * condition as the clock may tick between the get/set calls.
	 * We try to work around this by elevating our priority and doing
	 * a delay() so we run the critical code just after a clock
	 * tick, hopefully finishing before the next tick.
	 */

	(void) sched_getparam((pid_t) 0, &oldparam);
	newparam = oldparam;
	newparam.sched_priority = PRIO_FIFO_MAX;
	oldpolicy = sched_setscheduler((pid_t) 0, SCHED_FIFO, &newparam);
	(void) delay((unsigned int) 1);

	clock_gettime(CLOCK_REALTIME, &dtm);
	dtm.tv_sec += delta->tv_sec;
	dtm.tv_nsec += delta->tv_usec * 1000L;
	if (dtm.tv_nsec >= 1000000000L) {
		dtm.tv_sec++;
	dtm.tv_nsec -= 1000000000L;
	} else if (dtm.tv_nsec <= -1000000000L) {
		dtm.tv_sec--;
		dtm.tv_nsec += 1000000000L;
	}
	status = clock_settime(CLOCK_REALTIME, &dtm);

	(void) sched_setscheduler((pid_t) 0, oldpolicy, &oldparam);

	return status;
}

One can see - the delta is just very intricatelly rammed-in.
I don’t like those games with scheduling schemes, shifting the priority back and forth…
Definatelly this was done because there was no proper functions at the time of porting it to QNX.

Currently I do compare the two ntpd’s with the same set of reference servers. When I learn about it - I’ll report my findings.
The first impression is - it (my realisation of adjtime() via qnx_adj_time()) works.
I was trying to use the ntp v3.5f port - it’s syslog is full of “sync lost!” records, actually I could not make it to work.