Figure 1512 Overview of the data structures used to implement highresolution timers

A clock base is given by the following data structure:

<hrtimer.h>

struct hrtimer_clock_base {

struct hrtimer_cpu_base clockid_t struct struct ktime_t ktime t

*cpu_base; index;

rb_root active; rb_node *first; resolution; (*get_time)(void);

active first active first ktime_t (*get_softirq_time)(void);

ktime_t softirq_time; #ifdef CONFIG_HIGH_RES_TIMERS

ktime_t offset;

int (*reprogram)(struct hrtimer *t, struct hrtimer_clock_base *b, ktime_t n);

The meaning of the fields is as follows:

□ hrtimer_cpu_base points to the per-CPU basis to which the clock base belongs.

□ index distinguishes between clock_monotonic and clock_realtime.

□ rb_root is the root of a red-black tree on which all active timers are sorted.

□ first points to the timer that will expire first.

□ Processing high-res timers is initiated from the high-resolution timer softlRQ hrtimer_softirq as described in the next section. softirq_time stores the time at which the softlRQ was issued, and get_softirq_time is a function to obtain this time. If high-resolution mode is not active, then the stored time will be coarse-grained.

□ get_time reads the fine-grained time. This is simple for the monotonic clock (the value delivered by the current clock source can be directly used), but some straightforward arithmetic is required to convert the value into the real system time.

□ resolution denotes the resolution of the timer in nanoseconds.

□ When the real-time clock is adjusted, a discrepancy between the expiration values of timers stored on the clock_realtime clock base and the current real time will arise. The offset field helps to fix the situation by denoting an offset by which the timers needs to be corrected. Since this is only a temporary effect that happens only seldomly, the complications need not be discussed in more detail.

□ reprogram is a function that allows for reprogramming a given timer event, that is, changing the expiration time.

Two clock bases are established for each CPU using the following data structure: <hrtimer.h>

struct hrtimer_cpu_base {

struct hrtimer_clock_base clock_base[HRTIMER_MAX_CLOCK_BASES];

#ifdef CONFIG_HIGH_RES_TIMERS

ktime_t expires_next;

int hres_active;

struct list_head cb_pending;

unsigned long nr_events;

hrtimer_max_clock_bases is currently set to 2 because a monotonic and a real-time clock exist as discussed above. Note that the clock bases are directly embedded into hrtimer_cpu_base and not referenced via pointers! The remaining fields of the structure are used as follows:

□ expires_next contains the absolute time of the next event that is due for expiration.

□ hres_active is used as a Boolean variable to signal if high-resolution mode is active, or if only low-resolution is available.

□ When a timer expires, it is moved from the red-black tree to a list headed by cb_pending.15 Note that the timers on this list still need to be processed. This will take place in the softIRQ handler.

□ nr_events keeps track of the total number of timer interrupts.

he global per-CPU variable hrtimer_cpu_base contains an instance of struct hrtimer_base_cpu for each processor in the system. Initially it is equipped with the following contents:

kernel/hrtimer.c

DEFINE_PER_CPU(struct hrtimer_cpu_base, hrtimer_bases) = {

Since the system is initialized in low-resolution mode, the achievable resolution is only ktime_low_res. The pre-processor constant denotes the timer interval between periodic ticks with frequency HZ in nanoseconds. ktime_get and ktime_get_real both obtain the current time by using getnstimeofday, discussed in Section 15.3.

A very important component is still missing. How is a timer itself specified? The kernel provides the following data structure for this purpose:

<hrtimer.h>

struct hrtimer {

struct rb_node ktime_t int struct hrtimer_base unsigned long #ifdef CONFIG_HIGH_RES_TIMERS enum hrtimer_cb_mode struct list_head

15This requires that the timer is allowed to be executed in softIRQ context. Alternatively, timers are expired directly in the clock hardware IRQ without involving the detour via the expiration list.

.index = CLOCK_REALTIME, .get_time = &ktime_get_real, .resolution = KTIME_LOW_RES,

.index = CLOCK_MONOTONIC, .get_time = &ktime_get, .resolution = KTIME_LOW_RES, node; expires;

(*function)(struct hrtimer *);

state;

cb_mode; cb_entry;

node is used to keep the timer on the red-black tree as mentioned above, and base points to the timer base. The fields that are interesting for the timer's user are function and expires. While the latter denotes the expiration time, function is the callback employed when the timer expires. cb_entry is the list element that allows for keeping the timer on the callback list headed by hrtimer_cpu_base->cb_pending. Each timer may specify conditions under which it may or must be run. The following choices are possible:

<hrtimer.h>

* hrtimer callback modes:

* HRTIMER_CB_SOFTIRQ: Callback must run in softirq context

* HRTIMER_CB_IRQSAFE: Callback may run in hardirq context

* HRTIMER_CB_IRQSAFE_NO_RESTART: Callback may run in hardirq context and

* does not restart the timer

* HRTIMER_CB_IRQSAFE_NO_SOFTIRQ: Callback must run in hardirq context

* Special mode for tick emultation

enum hrtimer_cb_mode {

HRTIMER_CB_SOFTIRQ, HRTIMER_CB_IRQSAFE, HRTIMER_CB_IRQSAFE_NO_RESTART, HRTIMER_CB_IRQSAFE_NO_SOFTIRQ,

The comment explains the meaning of the individual constants well, and nothing need be added. The current state of a timer is kept in state. The following values are possible16:

□ hrtimer_state_inactive denotes an inactive timer.

□ A timer that is enqueued on a clock base and waiting for expiration is in state HRTIMER_STATE_ENQUEUED.

□ hrtimer_state_callback states that the callback is currently executing.

□ When the timer has expired and is waiting on the callback list to be executed, the state is HRTIMER STATE PENDING.

The callback function deserves some special consideration. Two return values are possible: <hrtimer.h>

enum hrtimer_restart {

HRTIMER_NORESTART, /* Timer is not restarted */ HRTIMER_RESTART, /* Timer must be restarted */

Usually, the callback will return hrtimer_norestart when it has finished executing. In this case, the timer will simply disappear from the system. However, the timer can also choose to be restarted. This requires two steps from the callback:

1. The result of the callback must be hrtimer_restart.

16In a rare corner case, it is also possible that a timer is both in the states HRTIMER_STATE_ENQUEUED and HRTIMER_STATE_CALLBACK. See the commentary in <hrtimer.h> for more information.

2. The expiration of the timer must be set to a future point in time. The callback function can perform this manipulation because it gets a pointer to the hrtimer instance for the currently running timer as function parameter. To simplify matters, the kernel provides an auxiliary function to forward the expiration time of a timer:

Continue reading here: Info

Was this article helpful?

0 0