Pemasa kernel LINUX ialah mekanisme yang digunakan oleh kernel untuk mengawal penjadualan dan pelaksanaan fungsi tertentu pada masa tertentu pada masa hadapan (berdasarkan jiffies). Pelaksanaan mekanisme ini terletak dalam fail
Fungsi berjadual mesti dilaksanakan secara tak segerak Ia serupa dengan "gangguan perisian" dan berada dalam konteks bukan proses. Oleh itu, fungsi penjadualan mesti mematuhi peraturan berikut:
Sebaik sahaja fungsi penjadualan pemasa kernel dijalankan sekali, ia tidak akan dijalankan lagi (bersamaan dengan log keluar automatik). Walau bagaimanapun, adalah mungkin untuk dijalankan secara berkala dengan menjadualkan semula dirinya dalam fungsi yang dijadualkan.
Dalam sistem SMP, fungsi penjadualan sentiasa berjalan pada CPU yang sama di mana ia didaftarkan untuk mendapatkan lokaliti cache sebanyak mungkin.
Struktur data pemasa kernel
struct timer_list { struct list_head entry; unsigned long expires; void (*function)(unsigned long); unsigned long data; struct tvec_base *base; /* ... */ };
Medan tamat tempoh mewakili nilai jiffies yang pemasa dijangka akan laksanakan Apabila nilai jiffies dicapai, fungsi fungsi akan dipanggil dan data akan dihantar sebagai parameter. Apabila pemasa didaftarkan pada kernel, medan entri digunakan untuk menyambung pemasa ke senarai terpaut kernel. Medan asas digunakan secara dalaman oleh pelaksanaan kernel.
Ambil perhatian bahawa nilai tamat tempoh ialah 32 bit, kerana pemasa kernel tidak digunakan untuk titik masa hadapan yang panjang.
Sebelum menggunakan struct timer_list, anda perlu memulakan struktur data untuk memastikan semua medan ditetapkan dengan betul. Terdapat dua kaedah permulaan.
Kaedah 1:
DEFINE_TIMER(nama_pemasa, nama_fungsi, nilai_luput, data);
Makro ini secara statik akan mencipta pemasa kernel bernama timer_name dan memulakan fungsinya, tamat tempoh, nama dan medan asas.
Kaedah 2:
struct timer_list mytimer; setup_timer(&mytimer, (*function)(unsigned long), unsigned long data); mytimer.expires = jiffies + 5*HZ; 方法3: struct timer_list mytimer; init_timer(&mytimer); mytimer ->timer.expires = jiffies + 5*HZ; mytimer ->timer.data = (unsigned long) dev; mytimer ->timer.function = &corkscrew_timer; /* timer handler */
Tentukan pemasa secara dinamik melalui init_timer(), dan kemudian ikat alamat dan parameter fungsi pemprosesan ke senarai_pemasa,
Ambil perhatian bahawa tidak kira kaedah mana yang digunakan untuk memulakan, intipatinya hanyalah untuk memberikan nilai kepada medan, jadi medan tamat tempoh, fungsi dan data boleh diubah suai terus sebelum menjalankan add_timer().
Untuk definisi makro dan fungsi di atas, lihat include/linux/timer.h.
Untuk pemasa berkuat kuasa, ia mesti disambungkan ke senarai terpaut khusus dalam kernel Ini boleh dicapai melalui add_timer(struct timer_list *timer).
Untuk mengubah suai masa penjadualan pemasa, anda boleh memanggil mod_timer(struct timer_list *timer, unsigned long expired). mod_timer() akan mendaftarkan semula pemasa kepada kernel tanpa mengira sama ada fungsi pemasa telah dijalankan.
Untuk menyahdaftar pemasa, anda boleh menggunakan del_timer(struct timer_list *timer) atau del_timer_sync(struct timer_list *timer). Antaranya, del_timer_sync digunakan pada sistem SMP (pada sistem bukan SMP, ia sama dengan del_timer Apabila fungsi pemasa untuk dilog keluar berjalan pada CPU lain, del_timer_sync() akan menunggu sehingga ia selesai berjalan, jadi ini). fungsi akan hibernate. Di samping itu, ia juga harus dielakkan daripada bersaing untuk kunci yang sama dengan fungsi yang dijadualkan. Untuk pemasa yang telah dijalankan dan belum mendaftar semula dirinya, fungsi nyahdaftar sebenarnya tiada kaitan.
int timer_pending(const struct timer_list *timer)
Fungsi ini digunakan untuk menentukan sama ada pemasa telah ditambahkan pada senarai kernel menunggu untuk dijadualkan untuk dijalankan. Ambil perhatian bahawa apabila fungsi pemasa akan dijalankan, kernel akan memadam pemasa yang sepadan daripada senarai dipautkan kernel (bersamaan dengan log keluar)
#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");
Atas ialah kandungan terperinci Penjelasan terperinci tentang penggunaan pemasa kernel Linux. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!