Рано или поздно наступает необходимость выполнения в модуля ядра полезных операций. И наверное самым полезным в этом плане инструментом являются потоки ядра.
В качестве примера создания потока в модуле ядра я решил написать модуль, который будет каждую секунду вываливать в dmesg сообщение. Такой себе флудо-модуль ядра.
Для работы с потоками (их кстати в ядре linux зовут kthread) необходимо заинклудить linux/kthread.h.
В функции инициализации модуля необходимо запустить новый поток при помощи функции kthread_run. Ей нужно передать указатель функции потока, указатель на данные, которые будут переданы функции и название.
static int __init blablamod_init( void ) { printk(KERN_NOTICE "Blablamod: %s():\n", __func__); printk(KERN_NOTICE "Blablamod: HS: %d.\n", HZ); task = kthread_run(&thread_function,(void *)data,"Blablathread"); return 0; }
В ответ функция вернет нам указатель на созданный поток, который я объявил так:
static struct task_struct *task;
По обычаю при выгрузке модуля нужно вернуть все как было (остановить поток).
static void __exit blablamod_exit( void ) { kthread_stop(task); printk(KERN_NOTICE "Blablamod unloaded!\n" ); }
В функции потока реализован бесконечный цикл, который и флудит. В нем при помощи jiffies организована задержка.
int thread_function(void *data) { unsigned long tm = jiffies + msecs_to_jiffies(1000); printk(KERN_NOTICE "Blablamod: %s(): data = %d.\n", __func__, (int)data); while(!kthread_should_stop()){ if (time_after(jiffies, tm)) { tm = jiffies + msecs_to_jiffies(1000); printk(KERN_NOTICE "Blablamod: %s(): %lu.\n", __func__, jiffies); } schedule(); } return 0; }
Данная функция выводит полученные в качестве переменной данные, после чего выполняет цикл, пока не получит сигнал о завершении при помощи функции kthread_should_stop(). Вывод в консоль осуществляется примерно через секунду, если же время еще не настало управление отдается планировщику.
Задержка организована при помощи функции time_after, которая проверяет больше ли текущее время в jiffies чем заданное во втором параметре. Если больше то изменяем значение в переменной tm и выводим привет в dmesg.
Скомпилируйте и загрузите модуль. Теперь можно проверить создан ли поток.
$ dmesg .... [ 3477.526076] Blablamod: blablamod_init(): [ 3477.526119] Blablamod: HS: 100. [ 3477.530524] Blablamod: thread_function(): data = 85. [ 3478.537524] Blablamod: thread_function(): 317821. [ 3479.547541] Blablamod: thread_function(): 317922. [ 3480.557670] Blablamod: thread_function(): 318023.
Если не доверяем выводу:
$ ps -ef | grep bla root 8514 2 98 20:28 ? 00:00:09 [Blablathread]
Не забываем выгрузить модуль. Ато в логе будет ад.
Исходники на GitHub.