adjtime() and QNX v4.25G, how to emulate? (+)

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) {

int rc;
long c, d;

QSSL recommends to have skew rate not exceeding 10%,

so I’ll set it to 10 - fastest of allowed.

rc = qnx_adj_time((delta->tv_usec), 10, &c, &d);
qnx_adj_time(0, 0, &c, &d);
olddelta->tv_seconds = 0;
olddelta->tv_usec = c * d;
return (rc)
}

Will this construct work as expected? I’m afraid of overflow in “c * d”…
Please comment.

Tony.

Thinking on it more:

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.

Tony <mts.spb.suxx@mail.ru> wrote:

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

First my concern is: what if someone asks adjtime() to advance the time not
by mere microseconds but, say, five and a half hours?!

I would choose to implement such a test – qnx_adj_time() is intended
for minor synchronisations of a system clock, not for setting it to
a “new” time value. I’d pick some value, both 1s and 10s might be
reasonable (depending on syncrhonisation frequency, and rate of
clock drift), and if the “jump” is more than that amount of time,
use clock_settime() to change the time in a “jump” rather than
a drift.

-David

David Gibbs
dagibbs@qnx.com

On 26 Apr 2004 15:16:12 GMT, David Gibbs <dagibbs@qnx.com> wrote:

Tony <> mts.spb.suxx@mail.ru> > wrote:
Trying to fugure out how to emulate unix’s “adjtime()” with QNX v4.25G
“qnx_adj_time()”.

First my concern is: what if someone asks adjtime() to advance the time
not by mere microseconds but, say, five and a half hours?!

I would choose to implement such a test – qnx_adj_time() is intended
for minor synchronisations of a system clock, not for setting it to
a “new” time value. I’d pick some value, both 1s and 10s might be
reasonable (depending on syncrhonisation frequency, and rate of
clock drift), and if the “jump” is more than that amount of time,
use clock_settime() to change the time in a “jump” rather than
a drift.

-David

Actually I’m trying to polish the NTP v1 port to QNX v4
(ftp://ftp.qnx.com/usr/free/qnx4/tcpip/utils/qnx-ntp.tgz). Seems it is
made when QNX was lacking any sort of time slewing at all.

In that environment adjtime() does not try to SET new time - it deals
with corrections as small as ~2ms. All significant time jumps are
accomplished as you are suggesting.

The “polished” port seems to work though I see a different reports
regarding the time differences between my system and the NTP servers. The
original port reports very little deltas whereas “polished” one - a set of
much larger positive and negative offsets from the same set of servers…

Well, in general, does your reply mean that there is no error in my
understanding of both adjtime() and qnx_adj_time()?

Tony.

Using it for quite a time shows, that the larger the “rate” passed to
qnx_adj_time() the more stable and accurate the system time is set by ntp
v1. I use it with rate == 2048 and get ~2ms offsets now:

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 2048 - a good choice.

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), 2048, NULL, NULL));
}

Please comment.
Tony.

Sure, increaing the allowed delta, per adjustment will result in
“faster” update. I don’t see how this is surprising?

-Adam

Tony wrote:

Using it for quite a time shows, that the larger the “rate” passed to
qnx_adj_time() the more stable and accurate the system time is set by
ntp v1. I use it with rate == 2048 and get ~2ms offsets now:

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 2048 - a good choice.

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), 2048, NULL, NULL));
}

Please comment.
Tony.


Cheers,
Adam

QNX Software Systems Ltd.
[ amallory@qnx.com ]

With a PC, I always felt limited by the software available.
On Unix, I am limited only by my knowledge.
–Peter J. Schoenster <pschon@baste.magibox.net>

On Fri, 11 Jun 2004 14:57:30 -0400, Adam Mallory <amallory@qnx.com> wrote:

Sure, increaing the allowed delta, per adjustment will result in
“faster” update. I don’t see how this is surprising?
Actually I missed the thread…

Well, it’s no surprize at all, I was using the ntp v1 port (from QSSL’s
ftp) and noticed that system time was “oscillating” around the reference
server’s.

With this value of “rate” (and this implementation of adjtime) it cleanly
approaches and stays there wihout any overshoots.

I’ve read a lot of messages where people regretted the lack of adjtime()
in QNX4 - that’s why I ask if I’m missing something…

Tony.

This is what got submitted into OpenNTPd project for QNX4:

/* $Id$ */

/*

  • Copyright (c) 2004 Anthony O.Zabelin
  • Permission to use, copy, modify, and distribute this software for any
  • purpose with or without fee is hereby granted, provided that the above
  • copyright notice and this permission notice appear in all copies.
  • THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  • WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  • MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  • ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  • WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
  • IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
  • OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    */

#if defined(QNX) && !defined(HAVE_ADJTIME)

/*

  • Ajustment rate as a fraction of tick size. Speeds or slows clock by
  • 1/rate per clock tick.
    */
    #define ADJUST_RATE 128

#include <stdlib.h>
#include <sys/time.h>

int
adjtime(const struct timeval *delta, struct timeval *olddelta)
{
long c, d, usec;
div_t sec_usec;

if (olddelta != NULL) {
if (!qnx_adj_time(0, 0, &c, &d)) {
sec_usec = div(((c / 1000L) * d), 1000000L);
olddelta->tv_sec = sec_usec.quot;
olddelta->tv_usec = sec_usec.rem;
} else {
olddelta->tv_sec = 0;
olddelta->tv_usec = 0;
}
}
usec = delta->tv_sec * 1000000L + delta->tv_usec;
return(qnx_adj_time(usec, ADJUST_RATE, NULL, NULL));
}
#endif


Now I try inventing the “adjtimex()”…

Tony.