Clock services are used to maintain the time of day, which is in turn used by the kernel timer calls to implement interval timers.
The ClockTime() kernel call allows you to get or set the system clock specified by an ID (CLOCK_REALTIME), which maintains the system time. Once set, the system time increments by some number of nanoseconds based on the resolution of the system clock. This resolution can be queried or changed using the ClockPeriod() call.
Within the system page, an in-memory data structure, there's a 64-bit field (nsec) that holds the number of nanoseconds since the system was booted. The nsec field is always monotonically increasing and is never affected by setting the current time of day via ClockTime() or ClockAdjust().
The ClockCycles() function returns the current value of a free-running 64-bit cycle counter. This is implemented on each processor as a high-performance mechanism for timing short intervals. For example, on Intel x86 processors, an opcode that reads the processor's time-stamp counter is used. Other CPU architectures have similar instructions.
On processors that don't implement such an instruction in hardware, the kernel will emulate one. This will provide a lower time resolution than if the instruction is provided (838.095345 nanoseconds on an IBM PC-compatible system).
In all cases, the SYSPAGE_ENTRY(qtime)->cycles_per_sec field gives the number of ClockCycles() increments in one second.
The ClockPeriod() function allows a thread to set the system timer to some multiple of nanoseconds; the OS kernel will do the best it can to satisfy the precision of the request with the hardware available.
The interval selected is always rounded down to an integral of the precision of the underlying hardware timer. Of course, setting it to an extremely low value can result in a significant portion of CPU performance being consumed servicing timer interrupts.
The ClockId() function returns a special clock ID that you can use to track the CPU time that a process or thread uses. For more information, see Monitoring execution times in the Understanding the Microkernel's Concept of Time chapter of the QNX Neutrino Programmer's Guide.
Microkernel call | POSIX call | Description |
---|---|---|
ClockTime() | clock_gettime(), clock_settime() | Get or set the time of day (using a 64-bit value in nanoseconds ranging from 1970 to 2554) |
ClockAdjust() | N/A | Apply small time adjustments to synchronize clocks. |
ClockCycles() | N/A | Read a 64-bit free-running high-precision counter |
ClockPeriod() | clock_getres() | Get or set the period of the clock |
ClockId() | clock_getcpuclockid(), pthread_getcpuclockid() | Get a clock ID for a process or thread CPU-time clock |
The kernel can run in a tickless mode in order to reduce power consumption, but this is a bit of a misnomer. The system still has clock ticks, and everything runs as normal unless the system is idle. Only when the system goes completely idle does the kernel turn off clock ticks, and in reality what it does is slow down the clock so that the next tick interrupt occurs just after the next active timer is to fire, so that the timer will fire immediately. To enable tickless operation, specify the -Z option for the startup-* code.