Timer処理とは
Timer処理は、特定の処理を一定の時間経過後に実行する為の仕組みです。前章の 遅延処理 は、急ぎでない処理を実行する為の処理で、こちらは特定のタイミングで処理を実行する為の処理になります。繰り返しTimer処理を行うことによって、定期的な処理を実現する為にも使用されます。Linuxカーネルで使用可能なTimerには、代表的な物としてHZ Timer、High-Resolution Timer、Alarm Timerの3つがあり、それぞれについて説明します。
HZ Timer の使い方
HZ Timerは、LinuxカーネルのTimerで最も基本的な仕組みです。前章の 遅延処理 で説明したjiffiesに基づいてTimerを設定します。Timer満了時に、登録したコールバック関数が呼び出されます。
照度センサデバイスドライバでは、以下に使用箇所があります。
kernel/mediatek/4.4/drivers/misc/mediatek/sensors-1.0/alsps/alsps.c
init_timer(&obj->timer_als);
このinit_timerは、Timerを初期化する為の関数です。現在は、より簡単に初期化可能なsetup_timer関数があり、以下に定義されていますので、こちらを説明します。
kernel/mediatek/4.4/include/linux/timer.h
kernel/mediatek/4.4/kernel/time/timer.c
#define setup_timer(timer, fn, data) \
__setup_timer((timer), (fn), (data), 0)
setup_timerの第1引数には、struct timer_list型のポインタを指定します。第2引数には実行するコールバック関数を指定します。第3引数にはコールバック関数に引き渡すデータ、無ければ0を指定します。その他の主要な関数には、以下のようなものがあります。
/**
* mod_timer - modify a timer's timeout
* @timer: the timer to be modified
* @expires: new timeout in jiffies
*
* mod_timer() is a more efficient way to update the expire field of an
* active timer (if the timer is inactive it will be activated)
*
* mod_timer(timer, expires) is equivalent to:
*
* del_timer(timer); timer->expires = expires; add_timer(timer);
*
* Note that if there are multiple unserialized concurrent users of the
* same timer, then mod_timer() is the only safe way to modify the timeout,
* since add_timer() cannot modify an already running timer.
*
* The function returns whether it has modified a pending timer or not.
* (ie. mod_timer() of an inactive timer returns 0, mod_timer() of an
* active timer returns 1.)
*/
int mod_timer(struct timer_list *timer, unsigned long expires)
実際にTimerを設定する関数です。既に設定されている場合は変更し、指定された時間後にコールバック関数を呼び出します。第1引数にはsetup_timerでも指定したstruct timer_list型のポインタを指定します。第2引数にはTimerの満了時間を示すjiffiesを指定します。
/**
* del_timer - deactive a timer.
* @timer: the timer to be deactivated
*
* del_timer() deactivates a timer - this works on both active and inactive
* timers.
*
* The function returns whether it has deactivated a pending timer or not.
* (ie. del_timer() of an inactive timer returns 0, del_timer() of an
* active timer returns 1.)
*/
int del_timer(struct timer_list *timer)
設定したTimerを削除する関数です。引数にはsetup_timerでも指定したstruct timer_list型のポインタを指定します。mod_timerの英文の説明文にもある通り、このdel_timerとadd_timerを合わせた物が前述のmod_timerとなります。
High-Resolution Timer の使い方
High-Resolution Timerは、HZ Timerよりも高精度で、より細かい時間単位で処理を行うことができる仕組みです。特に、リアルタイム性が必要な処理で使われます。主要な関数には、以下のようなものがあります。
kernel/mediatek/4.4/kernel/time/hrtimer.c
/**
* hrtimer_init - initialize a timer to the given clock
* @timer: the timer to be initialized
* @clock_id: the clock to be used
* @mode: timer mode abs/rel
*/
void hrtimer_init(struct hrtimer *timer, clockid_t clock_id,
enum hrtimer_mode mode)
hrtimer_initはTimerを初期化する為の関数です。第1引数には、struct hrtimer型のポインタを指定します。第2引数のclock_idには、補正される場合がある現在時刻に基づいたCLOCK_REALTIME、単調増加のCLOCK_MONOTONIC、CLOCK_MONOTONICにLinuxがsuspend状態に入っている時の増加も含めるCLOCK_BOOTTIME等を指定します。第3引数には相対的な時間を意味するHRTIMER_MODE_RELか、絶対的な時間を意味するHRTIMER_MODE_ABSを指定します。
/**
* hrtimer_start - (re)start an hrtimer on the current CPU
* @timer: the timer to be added
* @tim: expiry time
* @mode: expiry mode: absolute (HRTIMER_MODE_ABS) or
* relative (HRTIMER_MODE_REL)
*/
static inline void hrtimer_start(struct hrtimer *timer, ktime_t tim,
const enum hrtimer_mode mode)
Timerを開始する関数で、指定された時間後にコールバック関数を呼び出します。第1引数には、hrtimer_initでも指定したstruct hrtimer型のポインタを指定します。第2引数にはTimerの満了時間を示すktime_tを指定します。第3引数に基づき、相対的な時間か絶対的な時間を入れるかが決まり、ktime_getでMONOTONICな、ktime_get_realでREALTIMEなktime_tが取得できます。第3引数にはhrtimer_init同様に相対的な時間を意味するHRTIMER_MODE_RELか、絶対的な時間を意味するHRTIMER_MODE_ABSを指定します。
High-Resolution Timerのコールバック関数の戻り値は、enum hrtimer_restart型になります。HRTIMER_RESTARTを返却するとTimerが再設定し繰り返し処理を行う事ができます。再設定しない場合はHRTIMER_NORESTARTを返却します。
尚、このコールバック関数は割込みコンテキストで呼び出されるので注意が必要です。
/**
* hrtimer_cancel - cancel a timer and wait for the handler to finish.
* @timer: the timer to be cancelled
*
* Returns:
* 0 when the timer was not active
* 1 when the timer was active
*/
int hrtimer_cancel(struct hrtimer *timer)
設定したTimerを削除する関数です。第1引数には、hrtimer_initでも指定したstruct hrtimer型のポインタを指定します。
Alarm Timer の使い方
Alarm Timerは、システムのリアルタイムクロック(RTC)を使用したTimerです。CPUがsuspend状態でもTimerを継続し、suspend状態から復帰させることが必要な処理で使用されます。主要な関数には、以下のようなものがあります。
kernel/mediatek/4.4/kernel/time/alarmtimer.c
/**
* alarm_init - Initialize an alarm structure
* @alarm: ptr to alarm to be initialized
* @type: the type of the alarm
* @function: callback that is run when the alarm fires
*/
void alarm_init(struct alarm *alarm, enum alarmtimer_type type,
enum alarmtimer_restart (*function)(struct alarm *, ktime_t))
alarm_initはTimerを初期化する為の関数です。第1引数には、struct alarm型のポインタを指定します。第2引数には、補正される場合がある現在時刻に基づいたALARM_REALTIMEか、単調増加のALARM_BOOTTIMEを指定します。第3引数には、コールバック関数を指定します。
/**
* alarm_start - Sets an absolute alarm to fire
* @alarm: ptr to alarm to set
* @start: time to run the alarm
*/
void alarm_start(struct alarm *alarm, ktime_t start)
Timerを開始する関数で、指定された時間後にコールバック関数を呼び出します。第1引数には、alarm_initでも指定したstruct alarm型のポインタを指定します。第2引数にはhrtimer_startでも使用したTimerの満了時間を示すktime_tを指定します。
/**
* alarm_cancel - Spins trying to cancel an alarm timer until it is done
* @alarm: ptr to alarm to be canceled
*
* Returns 1 if the timer was canceled, 0 if it was not active.
*/
int alarm_cancel(struct alarm *alarm)
設定したTimerを削除する関数です。第1引数には、alarm_initでも指定したstruct alarm型のポインタを指定します。
最後に
HZ Timerが基本となりますが、数10msec程度以下の精度が必要となる場合は、High-Resolution Timerを使用する必要があります。コールバック関数が割込みコンテキストで実行されるようになり、単純な置き換えはできないケースがあるので注意が必要です。
CPUのsuspend状態を解除したい場合はAlarm Timerを使います。ただし、むやみに使うとsuspendを妨害し、消費電流が増加するので、注意が必要です。
コメント