Chapter 189. Overview

189.1. Introduction

The Common Clock package (CYGPKG_CLOCK_COMMON) provides a centralized management interface for system time, also known as calendar time, which corresponds to the real time of day. System time is distinct from other clock-related concepts such as the kernel "real time clock" which drives the kernel scheduler, or hardware timers.

The purpose of this package is primarily to keep system time management and related functionality focused in a central location to ensure a consistent and coherent approach to time management across all eCos packages, and to avoid duplication. It is used by the C library and by the POSIX compatibility layer for underlying time support, and also provides interfaces to manipulate time which may be used by services such as NTP, as well as to the user. It encapsulates the underlying eCos wallclock driver layer.

At the present time, it only operates when using the eCos kernel package, as it uses a dedicated thread to perform time management functions.

It has been verified safe for use past year 2038 - the so-called Year 2038 problem refers to the overflow of signed 32-bit representations of time in seconds since 1970-01-01 00:00:00 UTC.

189.2. Functionality

The package provides an API which presents functions to the user or higher layers to:

  • Get the system time;
  • Set the system time;
  • Adjust the system time by a small amount, manage such adjustments, and potentially manage other aspects of clock discipline;
  • Receive notifications of changes to system time;
  • Instruct the package to update a wallclock (RTC) device configured into eCos with the current system time;
  • Provide a kernel C API clock handle linked to the clock which is driving system time (which may or may not be the same as the real time clock driving the kernel scheduler). This can in turn be used to set alarms associated with ticks of that clock;
  • Convert between system time clock ticks and calendar time, both in the form of relative time offsets, or absolute timestamps.

189.3. Concepts and structure

The main focus of the architecture of this package is the clock management thread. This thread acts as a central processing point in the system to: asynchronously initialize the clocks at system startup time; update the wallclock time either if directed by the user, or if required to by configuration settings (at regular periods, or whenever time is updated); and notify registered modules when the system time has been set or updated.

This thread should be a high priority thread as it is inherently time-sensitive, and the behaviour may not be as expected if pre-empted. For example, after the time has been changed, registered modules will be notified, but a higher priority thread could pre-empt and run before the notification has taken place, with the potential for different parts of the system to have different understandings of what the current time is. Although be aware there is a chance this can happen anyway as a potential consequence of the notification process, as obviously only one module can be notified at a time, meaning there can be a lag between the time change and notification.

The API functions of this package represent time using the POSIX standard defined structure struct timespec. This offers the most flexible and high resolution representation. The type is defined in the header file <time.h> and the standard mandates its definition as follows:

struct timespec {
    time_t tv_sec;    /* Seconds */
    long   tv_nsec;   /* Nanoseconds */
}

All uses of absolute time values are expressed using time as a struct timespec with an "epoch" (reference start date) of 1970-01-01 00:00:00 UTC. All time is based in the UTC time frame - no support for timezones is provided, which is instead left to higher layers.

Overall, the system time is maintained by reading a high resolution HAL clock, and maintaining a fixed relationship between that clock value and the set time. Global variables are used within the common clock package to allow for this, and are protected from simultaneous access, thus making the package thread safe. However no functions in this package can be considered safe to call from either an ISR or a DSR. At the beginning of system operation, interlocks are used to ensure that it is not possible to retrieve the system time until the common clock package has been initialized.

Time can be adjusted by a small amount - the maximum allowable range being a parameter set in the package configuration. When this happens, the clock is not set to the new time immediately ("stepped") but instead it gradually converges towards the new time base. It will still increase monotonically. Making changes to time in this way can be much less disruptive to applications, however it is not appropriate for large changes, as it would take either take too long to converge, or spend a significant duration with the time being significantly inaccurate. Time can be adjusted both forwards and backwards.

Conversion functions are available to convert between real time and tick counts for the kernel clock object associated with the clock which is driving system time. These use the clock converter functions provided in the eCos kernel.