Information about the system's timebase, and other time-related information
The startup library's
init_qtime() function
fills in the
qtime data structures, which contain the following fields:
- cycles_per_sec
- For ClockCycles().
- nsec_tod_adjust
- When added to the value in nsec, gives the number of
nanoseconds from the start of the epoch (1970).
- nsec
- The number of nanoseconds since the system was booted.
- nsec_inc
- The number of nanoseconds deemed to have elapsed each time the clock triggers an interrupt.
- boot_time
- The time when the system was booted, in seconds since Jan 1 1970 00:00:00 GMT.
- If you call ClockTime()
to set the time of day, the kernel checks to see if this field is zero. If so, the kernel sets the field
to the appropriate value. All startup programs support a -T option that prevents the setting of
this field, so the kernel can set it the first time you call ClockTime().
This feature is useful if the RTC hardware isn't in UTC.
- adjust
- Set to zero at startup. Contains any current timebase adjustment runtime parameters
(as specified by the kernel call ClockAdjust()).
- timer_rate
- Used with timer_scale and timer_load (see below).
- timer_scale
- Used with timer_rate and timer_load (see below).
- timer_load
- Timer chip divisor value. The startup program leaves this as zero, and the kernel sets it based on the last
ClockPeriod(),
timer_rate, and timer_scale values to a certain number, which is then put
into the timer chip by the timer_load and timer_reload kernel callouts. For more details, see
timer_rate and timer_scale
below.
- intr
- Contains the interrupt vector that the clock chip uses to interrupt the processor.
- epoch
- Currently set to 1970, but not used.
- flags
- Properties of the timer hardware (see flags below).
- rr_interval_mul
- Reserved.
- timer_load_hi
- Used by the kernel to store the high portion of timer_load
(i.e., the portion greater than 32 bits) for 64-bit systems.
- nsec_stable
- Reserved.
- timer_load_max
- The maximum value that can be programmed into the hardware timer for system ticks.
- timer_prog_time
- (QNX Neutrino 7.1 or later)
Delay, in nanoseconds, for the initialization of high-resolution timers by the OS.
- spare
- Not used.
nsec and nsec_tod_adjust
The nsec field is always increasing monotonically. It is
never affected by setting the current time of day via
ClockTime() or ClockAdjust().
Because both
nsec and
nsec_tod_adjust are
modified in the kernel's timer interrupt handler and are too big to load in an
atomic read operation, to inspect them you must either:
- disable interrupts
or:
- get the value(s) twice and make sure that they haven't changed between the first
and second read.
timer_rate and timer_scale
The values in the timer_rate and timer_scale
fields relate to the external counter chip's input frequency, in Hz, as follows:

Yes, this relationship does imply that timer_scale is a negative
number. The goal when expressing the relationship is to make
timer_rate as large as possible in order to maximize the
number of significant digits available during calculations.
For example, on an x86 system the values might be 838095345UL for
timer_rate and -15 for timer_scale.
This indicates that the timer value is specified in femtoseconds (the -15
means ten to the power of negative fifteen); the actual value is
838,095,345 femtoseconds (or approximately 838 nanoseconds).
If the clock on your system drifts, you should make sure that the startup code
specifies the correct clock frequency. To override the setting in the code,
use the -f option in the startup command.
Image configuration best practices
You should verify time synchronization between
QNX Neutrino and the external hardware source when
configuring your boot image. You can do this by using
sleep()
and confirming that the external and internal time sources are synchronized. For example, you could pass in 60 seconds to the
sleep function and verify that both the internal clock and external hardware match.
Note: If you are using
ClockCycles() to synchronize
with external hardware, you should use this same function to perform testing.
For example, you could call this same function for the number of clock cycles in 60
seconds and verify this against the external hardware.
flags
This bit: |
Means that: |
QTIME_FLAG_TIMER_ON_CPU0 |
Timer hardware is specific to CPU0. This flag is passed by the startup code to the kernel to indicate that any interaction
with the hardware timer that is used to generate the system tick (see ClockPeriod()) must be made on CPU0.
For more information, see the explanation of the kernel callout timer_load() in the Timer and clock
topic of the Building Embedded Systems guide. |
QTIME_FLAG_CHECK_STABLE |
Set by the kernel if it is required to sample not only qtime::nsec
but also qtime::nsec_stable to acquire a stable current time value.
However, clock_gettime() should be called with a clock_id of CLOCK_MONOTONIC. |
QTIME_FLAG_TICKLESS |
Tickless operation is supported. For more information, see Clocks, timers, and power management
in the Tick, Tock: Understanding the Microkernel's Concept of Time chapter of the
Programmer's Guide. This flag is passed by the startup code to the kernel to indicate that tickless operation is desired when appropriate.
See startup-* and the -Z flag. |
QTIME_FLAG_TIMECC |
Set by the kernel if the libmod_timecc.a module is in use. See the
Tracking time
page for more information on the libmod_timecc.a module.
|
QTIME_FLAG_GLOBAL_CLOCKCYCLES |
ClockCycles() is synchronized between all processors on the system.
This flag is passed by the startup code to the kernel to indicate that the hardware timer
used by ClockCycles() is synchronized across all CPUs.
Sampling ClockCycles() twice should never result
in time flowing backward, even in the presence of thread migration.
As of QNX SDP 7.0, this is a requirement, but some startups have not yet been modified to reflect this. |