ホームページ > 記事 > システムチュートリアル > Linux カーネル タイマーの使用方法の詳細な説明
LINUX カーネル タイマーは、(jiffies に基づいて) 将来の特定の時点での特定の関数のスケジューリングと実行を制御するためにカーネルによって使用されるメカニズムです。このメカニズムの実装は、
スケジュールされた関数は非同期で実行する必要があります。これは「ソフトウェア割り込み」に似ており、非プロセス コンテキストにあります。したがって、スケジューリング関数は次の規則に従う必要があります:
カーネル タイマー スケジューリング機能は、一度実行されると、再度実行されることはありません (自動ログアウトに相当)。ただし、スケジュールされた機能内でそれ自体を再スケジュールすることで、定期的に実行することができます。
SMP システムでは、キャッシュの局所性を可能な限り確保するために、スケジューリング機能は常に登録されているのと同じ CPU 上で実行されます。
カーネルタイマーのデータ構造
リーリーexpires フィールドは、タイマーが実行すると予想される jiffies 値を示します。jiffies 値に達すると、関数 function が呼び出され、データがパラメータとして渡されます。タイマーがカーネルに登録されるとき、入力フィールドはタイマーをカーネルのリンクされたリストに接続するために使用されます。基本フィールドは、カーネル実装によって内部的に使用されます。
カーネル タイマーは将来の長い時点には適用されないため、有効期限の値は 32 ビットであることに注意してください。
struct timer_list を使用する前に、データ構造を初期化して、すべてのフィールドが正しく設定されていることを確認する必要があります。初期化には 2 つの方法があります。
方法 1:
DEFINE_TIMER(タイマー名、関数名、期限切れ値、データ);
このマクロは、timer_name という名前のカーネル タイマーを静的に作成し、その関数、有効期限、名前、および基本フィールドを初期化します。
方法 2:
リーリー init_timer() を通じてタイマーを動的に定義し、処理関数のアドレスとパラメーターを timer_list にバインドします。
初期化にどのメソッドが使用されるかに関係なく、本質はフィールドに値を割り当てることだけなので、expires、関数、およびデータのフィールドは add_timer() を実行する前に直接変更できることに注意してください。
上記のマクロと関数の定義については、include/linux/timer.h を参照してください。
int timer_pending(const struct timer_list *timer)
この関数は、実行のスケジュールを待機しているタイマーがカーネル リストに追加されているかどうかを判断するために使用されます。タイマー関数が実行されようとすると、カーネルは対応するタイマーをカーネルのリンク リストから削除することに注意してください (ログアウトと同等)#include \#include \#include struct timer_list mytimer; static void myfunc(unsigned long data) { printk("%s/n", (char *)data); mod_timer(&mytimer, jiffies + 2*HZ); } static int __init mytimer_init(void) { setup_timer(&mytimer, myfunc, (unsigned long)"Hello, world!"); mytimer.expires = jiffies + HZ; add_timer(&mytimer); return 0; } static void __exit mytimer_exit(void) { del_timer(&mytimer); } module_init(mytimer_init); module_exit(mytimer_exit); 例子2 static struct timer_list power_button_poll_timer; static void power_button_poll(unsigned long dummy) { if (gpio_line_get(N2100_POWER_BUTTON) == 0) { ctrl_alt_del(); return; } power_button_poll_timer.expires = jiffies + (HZ / 10); add_timer(&power_button_poll_timer); } static void __init n2100_init_machine(void) { ; ; init_timer(&power_button_poll_timer); power_button_poll_timer.function = power_button_poll; power_button_poll_timer.expires = jiffies + (HZ / 10); add_timer(&power_button_poll_timer); }
设备open时初始化和注册定时器
static int corkscrew_open(struct net_device *dev) { ; ; init_timer(&vp->timer); vp->timer.expires = jiffies + media_tbl[dev->if_port].wait; vp->timer.data = (unsigned long) dev; vp->timer.function = &corkscrew_timer; /* timer handler */ add_timer(&vp->timer); : ; } 定时器超时处理函数,对定时器的超时时间重新赋值 static void corkscrew_timer(unsigned long data) { ; ; vp->timer.expires = jiffies + media_tbl[dev->if_port].wait; add_timer(&vp->timer); ; ; } 设备close时删除定时器 static int corkscrew_close(struct net_device *dev) { ; ; del_timer(&vp->timer); ; ; } 例子4 本例子用DEFINE_TIMER静态创建定时器 \#include \#include \#include \#include \#include \#include static void ledtrig_ide_timerfunc(unsigned long data); DEFINE_LED_TRIGGER(ledtrig_ide); static DEFINE_TIMER(ledtrig_ide_timer, ledtrig_ide_timerfunc, 0, 0); static int ide_activity; static int ide_lastactivity; void ledtrig_ide_activity(void) { ide_activity++; if (!timer_pending(&ledtrig_ide_timer)) mod_timer(&ledtrig_ide_timer, jiffies + msecs_to_jiffies(10)); } EXPORT_SYMBOL(ledtrig_ide_activity); static void ledtrig_ide_timerfunc(unsigned long data) { if (ide_lastactivity != ide_activity) { ide_lastactivity = ide_activity; led_trigger_event(ledtrig_ide, LED_FULL); mod_timer(&ledtrig_ide_timer, jiffies + msecs_to_jiffies(10)); } else { led_trigger_event(ledtrig_ide, LED_OFF); } } static int __init ledtrig_ide_init(void) { led_trigger_register_simple("ide-disk", &ledtrig_ide); return 0; } static void __exit ledtrig_ide_exit(void) { led_trigger_unregister_simple(ledtrig_ide); } module_init(ledtrig_ide_init); module_exit(ledtrig_ide_exit); MODULE_AUTHOR("Richard Purdie "); MODULE_DESCRIPTION("LED IDE Disk Activity Trigger"); MODULE_LICENSE("GPL");
以上がLinux カーネル タイマーの使用方法の詳細な説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。