Про очереди задач.
Выполнение функции в контексте прерывания должно происходить максимально быстро. Поэтому если требуется драйверу в момент прерывания выполнить какой-то большой объем работы, то имеет смысл поместить функцию в очередь задач (workqueue), для её отложенного выполнения. После помещения функции в очередь (schedule_work), она будет выполнена в ближайшее время в контексте ядра.
Пример модуля с вызовом отложенной функции. Структура создаётся статически на этапе компиляции.
/* * stat_queue.c - статическая workqueue */ #include <linux/module.h> #include <linux/workqueue.h> #define DRIVER_AUTHOR "noname author" #define DRIVER_DESC "static queue" /* функция, которую требуется вызвать в отложенном режиме */ static void my_function(struct work_struct *work){ printk("call function from queue\n"); } /* создание статической структуры на этапе компиляции * первый аргумент - имя для структуры struct work_struct, которая будет создана * второй аргумент - имя функции которую нужно отложенно выполнить */ static DECLARE_WORK(tst_queue_struct, my_function); /* функция, которая вызывается при загрузке модуля */ static int __init init_stat_queue(void){ printk(KERN_ALERT "Hello, static queue\n"); /* помещение функции в очередь задач ядра */ schedule_work(&tst_queue_struct); return 0; } static void __exit cleanup_stat_queue(void){ printk(KERN_ALERT "Goodbye, static queue\n"); } module_init(init_stat_queue); module_exit(cleanup_stat_queue); MODULE_LICENSE("GPL"); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC);
Makefile для сборки модуля:
obj-m += stat_queue.o all: make -C /usr/src/linux-headers-`uname -r` M=$(PWD) modules clean: rm -rf *.o *.ko
Структуру struct work_struct можно создавать динамически.
Пример отложенного выполнения функции (workqueue) с динамическим созданием структуры:
/* * dynam_queue.c - динамически отложенное действие */ #include <linux/module.h> #include <linux/workqueue.h> #include <linux/slab.h> #define DRIVER_AUTHOR "noname author" #define DRIVER_DESC "dynamic queue" /* функция, которую требуется вызвать в отложенном режиме */ static void my_function(struct work_struct *work){ printk("call function from queue\n"); } /* функция, которая вызывается при загрузке модуля */ static int __init init_dynam_queue(void){ printk(KERN_ALERT "Hello, dynamic queue\n"); /* указатель на структуру work_struct */ struct work_struct *tst_queue_struct; /* динамически выделяется область памяти под структуру */ tst_queue_struct = kmalloc( sizeof(struct work_struct), GFP_KERNEL ); /* динамически инициализируем структуру work_struct. * первый аргумент - имя для структуры struct work_struct для инициализации * второй аргумент - имя функции, которую нужно отложенно выполнить */ INIT_WORK(tst_queue_struct, my_function); /* помещение функции в очередь задач ядра */ schedule_work(tst_queue_struct); return 0; } static void __exit cleanup_dynam_queue(void){ printk(KERN_ALERT "Goodbye, dynamic queue\n"); } module_init(init_dynam_queue); module_exit(cleanup_dynam_queue); MODULE_LICENSE("GPL"); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC);
Если требуется передать какие-либо данные в отложенную функцию, то нужно создать свою структуру, где обязательным членом должно быть поле struct work_struct.
А затем уже в отложенной функции через макрос container_of получить доступ к
своим данным.
Пример использования отложенной функции (workqueue) с передачей параметров
/* * dynam_queue_2.c - динамически отложенное действие, * с передачей параметров в отложенную функцию * */ #include <linux/module.h> #include <linux/workqueue.h> #include <linux/slab.h> #define DRIVER_AUTHOR "noname author" #define DRIVER_DESC "dynamic queue with param" struct queue_data_struct { struct work_struct queue_work; /* необходимая структура */ int data; /* данные для передачи в функцию */ }; /* функция, которую требуется вызвать в отложенном режиме */ static void my_function(struct work_struct *work){ printk("call function from queue\n"); struct queue_data_struct *tst_queue_struct = container_of(work, struct queue_data_struct, queue_work); printk( "function param: data=%d\n", tst_queue_struct->data ); kfree(tst_queue_struct); } /* функция, которая вызывается при загрузке модуля */ static int __init init_dynam_queue(void){ printk(KERN_ALERT "Hello, dynamic queue\n"); /* указатель на структуру work_struct */ struct queue_data_struct *tst_queue_struct; /* динамически выделяется область памяти под структуру */ tst_queue_struct = kmalloc( sizeof(struct queue_data_struct), GFP_KERNEL ); /* динамически инициализируем структуру work_struct. * первый аргумент - имя для структуры struct work_struct для инициализации * второй аргумент - имя функции которую нужно отложенно выполнить */ INIT_WORK(&(tst_queue_struct->queue_work), my_function); /* данные для передачи в отложенную функцию */ tst_queue_struct->data = 99; /* помещение функции в очередь задач ядра */ schedule_work(&(tst_queue_struct->queue_work)); return 0; } static void __exit cleanup_dynam_queue(void){ printk(KERN_ALERT "Goodbye, dynamic queue\n"); } module_init(init_dynam_queue); module_exit(cleanup_dynam_queue); MODULE_LICENSE("GPL"); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC);