Linuxカーネルタイマーの実装と活用法

Linuxカーネルにおいて、周期的な処理を実行する必要がある場面ではタイマー機能が頻繁に利用される。カーネルタイマーはシステムクロック(arch timer)を基盤として動作し、timer_list構造体によって管理される。この構造体はinclude/linux/timer.hで定義されている。``` struct timer_list { struct hlist_node entry; unsigned long expires; /* タイムアウト時刻を示す(ティック単位) */ void (*function)(struct timer_list ); / タイムアウト時に呼ばれるコールバック */ u32 flags; ... };

`expires`メンバーはタイマーの満了時刻をティック数で指定する。例えば2秒周期のタイマーを設定したい場合、`jiffies + (2 * HZ)`を指定すればよい。`HZ`は1秒あたりのティック数を表すマクロである。コールバック関数にはタイマー満了時に実行したい処理を記述する。カーネルタイマーを操作するための主要なAPIは以下の通りである。```
void init_timer_key(struct timer_list *timer, ...)
/* タイマー構造体の初期化 */

void add_timer(struct timer_list *timer)
/* カーネルにタイマーを登録して有効化 */

int del_timer(struct timer_list *timer)
/* 登録されているタイマーを削除 */

int mod_timer(struct timer_list *timer, unsigned long expires)
/* タイマーの満了時刻を更新 */

以下に、カーネルタイマーを使用したサンプルドライバコードを示す。コールバック関数内で自身を再スケジュールすることで、周期タイマーを実現している。``` #include <linux/module.h> #include <linux/init.h> #include <linux/timer.h> #include <linux/jiffies.h>

#define INTERVAL_MS 3000

struct timer_ctx { struct timer_list tlist; unsigned int fired_cnt; };

static struct timer_ctx ctx;

static void on_timer_expire(struct timer_list *t) { struct timer_ctx *priv = from_timer(priv, t, tlist);

priv->fired_cnt++;
pr_info("timer fired: count=%u\n", priv->fired_cnt);

/* 次回の満了時刻を設定して周期実行を実現 */
mod_timer(&priv->tlist, jiffies + msecs_to_jiffies(INTERVAL_MS));

}

static int __init timer_sample_init(void) { pr_info("timer sample module loaded\n");

ctx.fired_cnt = 0;

/* timer_setupでコールバックを紐付けて初期化 */
timer_setup(&ctx.tlist, on_timer_expire, 0);

/* 初回の満了時刻を設定 */
mod_timer(&ctx.tlist, jiffies + msecs_to_jiffies(INTERVAL_MS));

return 0;

}

static void __exit timer_sample_exit(void) { /* モジュール解放時にタイマーを確実に削除 */ del_timer_sync(&ctx.tlist); pr_info("timer sample module unloaded\n"); }

module_init(timer_sample_init); module_exit(timer_sample_exit);

MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Linux kernel timer usage example");

タグ: Linuxカーネル timer_list カーネルモジュール デバイスドライバ jiffies

8月12日 10:54 投稿