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");

 

 
 
 
 
 
 
posted @ 2024-04-01 01:49  lethe1203  阅读(46)  评论(0编辑  收藏  举报