workqueue
workqueue作为中断下半部的一种实现方式,和tasklet不同点在于:
1、workqueue中的工作项的执行是在内核线程的上下文中进行的,因此可以执行长时间运行的任务,不会阻塞其他进程的执行。tasklet 在中断上下文中执行,因此不能执行可能会阻塞的操作或者长时间运行的任务。它们的执行时间应该非常短。
2、workqueue 适用于需要延迟执行且较长时间的任务,具有较低的优先级和较高的灵活性。tasklet 适用于需要立即执行且执行时间很短的任务,具有较高的优先级,但数量受限且只能在中断上下文中执行。
workqueue相关结构体:
1、work_struct:工作队列中要执行的工作项的结构体。它的定义如下:
struct work_struct { atomic_long_t data; struct list_head entry; work_func_t func; }; // 参数说明 data:传递给工作函数的参数。 entry:链表节点,用于将工作项连接到工作队列中。 func:指向实际工作函数的指针。
2、workqueue_struct:工作队列的结构体,表示一个工作队列。它的定义如下:
struct workqueue_struct { struct list_head list; const char *name; struct lock_class_key key; struct lockdep_map lockdep_map; }; // 参数说明 list:用于连接所有工作队列的链表节点。 name:工作队列的名称。 key:用于锁的类别关键字。 lockdep_map:用于锁依赖关系的映射。
workqueue相关函数:
1、INIT_WORK:用于初始化工作项结构体。它的原型如下:
void INIT_WORK(struct work_struct *work, work_func_t func); // 参数说明 work:指向要初始化的工作项结构体的指针。 func:指向实际工作函数的指针。
2、schedule_work:用于安排工作项在适当的时候执行。它的原型如下:
bool schedule_work(struct work_struct *work); // 参数说明 work:要安排执行的工作项。
3、flush_workqueue:用于刷新工作队列,确保队列中的所有工作项都被执行完毕。它的原型如下:
int flush_workqueue(struct workqueue_struct *wq); // 参数说明 wq:要刷新的工作队列。
4、create_workqueue:用于创建一个新的工作队列。在较新的内核版本中,该函数已被弃用,可以使用 alloc_workqueue 代替。它的原型如下:
struct workqueue_struct *create_workqueue(const char *name); // 参数说明 name:工作队列的名称。
5、alloc_workqueue:用于分配并初始化一个新的工作队列。它的原型如下:
struct workqueue_struct *alloc_workqueue(const char *fmt, unsigned int flags, int max_active); // 参数说明 fmt:工作队列名称的格式字符串。 flags:工作队列的标志。 max_active:工作队列中同时运行的最大工作项数。
6、destroy_workqueue:用于销毁一个工作队列,并释放其相关资源。它的原型如下:
void destroy_workqueue(struct workqueue_struct *wq); // 参数说明 wq:要销毁的工作队列。
workqueue driver demo如下:
#include <linux/module.h> #include <linux/kernel.h> #include <linux/interrupt.h> #include <linux/workqueue.h> #define WORK_QUEUE_NAME "my_workqueue" // 定义工作结构体 struct work_struct my_work; // 工作处理函数 void my_work_handler(struct work_struct *work) { printk(KERN_INFO "Executing work handler function\n"); // 在这里执行下半部处理的任务 } // 定义中断处理函数 irqreturn_t irq_handler(int irq, void *dev_id) { printk(KERN_INFO "Interrupt handler\n"); // 安排工作队列执行下半部处理 schedule_work(&my_work); return IRQ_HANDLED; } static int __init my_init(void) { int irq = 1; // 替换为实际的中断号 // 初始化工作队列 INIT_WORK(&my_work, my_work_handler); // 注册中断处理函数 if (request_irq(irq, irq_handler, IRQF_SHARED, "my_irq_handler", &irq_handler) < 0) { printk(KERN_INFO "Failed to register interrupt handler\n"); return -EFAULT; } printk(KERN_INFO "Interrupt handler registered\n"); return 0; } static void __exit my_exit(void) { int irq = 1; // 替换为实际的中断号 // 取消注册中断处理函数 free_irq(irq, &irq_handler); // 刷新工作队列,确保已经执行了所有排队的工作 flush_workqueue(system_long_wq); printk(KERN_INFO "Interrupt handler unregistered\n"); } module_init(my_init); module_exit(my_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("lethe1203");