6/05/2012

Kernel timers API

From: IBM developerWorks Worldwide

Linux provides a simple API for the construction and management of timers. It consists of functions (and helper functions) for timer creation, cancellation, and management.
Timers are defined by the timer_list structure, which includes all of the data necessary to implement a timer (including list pointers and optional timer statistics that are configured at compile time). From a user's perspective, timer_list contains an expiration time, a callback function (when/if the timer expires), and a user-provided context. The user must then initialize the timer, which he or she can do in a few ways. The simplest method is a call to setup_timer, which initializes the timer and sets the user-provided callback function and context. Otherwise, the user can set these values (function and data) in the timer and simply call init_timer. Note that init_timer is called internally by setup_timer"

void init_timer( struct timer_list *timer );
void setup_timer( struct timer_list *timer,
void (*function)(unsigned long), unsigned long data );




With an initialized timer, the user now needs to set the expiration time, which is done through a call to mod_timer. As users commonly provide an expiration in the future, they typically add jiffies here to offset from the current time. Users can also delete a timer (if it has not expired) through a call to del_timer:

int mod_timer( struct timer_list *timer, unsigned long expires );
void del_timer( struct timer_list *timer );




Finally, users can determine whether the timer is pending (yet to fire) through a call to timer_pending (1 is returned if the timer is pending):

int timer_pending( const struct timer_list *timer );




You can learn more about the timer API in ./include/linux/timer.h. Although the simple timer API is easy and efficient, it does not offer the accuracy required for real-time applications. For that, let's look at a recent addition to Linux that supports higher-resolution timers.

High-resolution timers
High-resolution timers (or hrtimers) provide a high-precision framework for timer management independent of the previously discussed timer framework because of complexities in merging the two frameworks. Although timers operate on the granularity of jiffies, hrtimers operate at the granularity of nanoseconds.
The hrtimer framework is implemented differently from the traditional timer API. Instead of buckets and timer cascading, hrtimers maintain a time-ordered data structure of timers (timers are inserted in time order to minimize processing at activation time). The data structure used is a red-black tree, which is ideal for performance-focused applications (and happens to be available generically as a library within the kernel).
The hrtimer framework is available as an API within the kernel and is also used by user space applications through nanosleep,itimers, and the Portable Operating System Interface (POSIX)-timers interface. It was mainlined into the 2.6.21 kernel.
High-resolution timer API
The hrtimer API has some similarities to the traditional API as well as some fundamental differences to account for the additional timing control. The first thing you'll notice is that time is represented not in jiffies but in a special data type calledktime. This representation hides some of the details of efficiently managing time at this granularity. The API formalizes the distinction between absolute and relative times, requiring the caller to specify the type.
Like the traditional timer API, timers are represented by a structure―in this case, hrtimer. This structure defines the timer from a user perspective (callback function, expiration time, and so on) and also incorporates the management information (where the timer exists in the red-black tree, optional statistics, and so on).
The process begins with the initialization of a timer through hrtimer_init. This call includes the timer, clock definition, and timer mode (one-shot or restart). The clock to use is defined in ./include/linux/time.h and represents the various clocks that the system supports (such as the real-time clock or a monotonic clock that simply represents time from a starting point, such as system boot). Once a timer has been initialized, it can be started with hrtimer_start. This call includes the expiration time (in ktime_t) and the mode of the time value (absolute or relative value).

void hrtimer_init( struct hrtimer *time, clockid_t which_clock,
enum hrtimer_mode mode );
int hrtimer_start(struct hrtimer *timer, ktime_t time, const
enum hrtimer_mode mode);




Once an hrtimer has started, it can be cancelled through a call to hrtimer_cancel or hrtimer_try_to_cancel. Each function includes the hrtimer reference as the timer to be stopped. These functions differ in that the hrtimer_cancel function attempts to cancel the timer, but if it has already fired, it will wait for the callback function to finish. The hrtimer_try_to_cancel function differs in that it also attempts to cancel the timer but will return failure if the timer has fired.

int hrtimer_cancel(struct hrtimer *timer);
int hrtimer_try_to_cancel(struct hrtimer *timer);




You can check to see if the hrtimer has activated its callback through a call to hrtimer_callback_running. Note that this function is called internally by hrtimer_try_to_cancel in order to return an error if the timer's callback function was called.

int hrtimer_callback_running(struct hrtimer *timer);

No comments:

Post a Comment