QNX Neutrino maintains two clocks in the system: one is a monotonic
count of time since the kernel was initialized (CLOCK_MONOTONIC),
and the other is a wall-clock time since January 1st, 1970 (CLOCK_REALTIME).
The OS actually just counts time since booting, and if asked for the
current time, adds an adjustment value
(SYSPAGE_ENTRY(qtime)->nsec_tod_adjust) to the monotonic time
to get the current time.
Any functions that change the current time simply modify the adjustment value.
There are several functions that you can use to determine the current time,
for use in timestamps or for calculating execution times, including:
- time()
- Return the current time in seconds.
- clock_gettime()
- Return the current or monotonic time in seconds and nanoseconds since the last second.
Note: The time value written by this function is not necessarily an integer multiple of the clock
period reported by
ClockPeriod*().
- ClockTime()
- Set or get the current or monotonic time in 64-bit nanoseconds
Note: The time value written by this function is not necessarily an integer multiple of the clock
period reported by
ClockPeriod*().
32-bit QNX uses an unsigned 32-bit value for seconds since January 1st, 1970, allowing for time
representations through approximately the year 2100.
64-bit QNX uses a signed 64-bit value for seconds since January 1st, 1970. This allows for
time representations that are beyond the foreseeable future.
All the above methods have a precision that's based on the system timer tick.
If you need more precision, you can use
ClockCycles().
This function is implemented differently for each processor architecture, so there are tradeoffs.
The implementation tries to be as quick as possible, so it tries to use a CPU register if possible.
CAUTION:
Don't use
SYSPAGE_ENTRY(qtime)->nsec to read the number of nanoseconds expired in
the current second. This 64-bit value is dangerous to use by 32-bit programs because race conditions
occur if you make two reads of 32 bits. You should instead call
clock_gettime(),
which reads the value in a safe manner and for
CLOCK_MONOTONIC and
CLOCK_REALTIME, without doing a kernel call.
Note:
In QNX Neutrino 7.0 or later, we require that the hardware underlying ClockCycles()
be synchronized across all processors on an SMP system.
If it isn't, you might encounter some unexpected behavior, such as drifting times and timers.
Using synchronized hardware means that you no longer have to use a runmask for threads to prevent them from
migrating to other processors between calls to ClockCycles().
Some information for each processor:
- x86_64
- Uses the RDTSC instruction.
- aarch64
- Reads from a 64-bit CNTVCT_EL0 register.
- ARMv7
- The call enters the kernel. In the system page's CPU information, the
clock_cycles field points to the target-specific function called by the
kernel. The clock_cycles field must be provided by startup to read and
return the value from a monotonically increasing hardware time source. The time source
shouldn't roll over when the target is in use.
To convert a
ClockCycles() delta to seconds, use
SYSPAGE_ENTRY(qtime)->cycles_per_sec.