Linux内核工作队列

Linux内核工作队列

Linux中的Workqueue机制就是为了简化内核线程的创建。通过调用workqueue的接口就能创建内核线程。并且可以根据当前系统CPU的个数创建线程的数量,使得线程处理的事务能够并行化。workqueue是内核中实现简单而有效的机制,他显然简化了内核daemon的创建,方便了用户的编程.

工作队列(workqueue)是另外一种将工作推后执行的形式.工作队列可以把工作推后,交由一个内核线程去执行,也就是说,这个下半部分可以在进程上下文中执行。最重要的就是工作队列允许被重新调度甚至是睡眠。

1.工作队列和软中断/tasklet中作出选择

  • 如果推后执行的任务需要睡眠,那么只能选择工作队列;
  • 如果推后执行的任务需要延时指定的时间再触发,那么使用工作队列,因为其可以利用timer延时
  • 如果推后执行的任务需要在一个tick之内处理,则使用软中断或tasklet,因为其可以抢占普通进程和内核线程
  • 如果推后执行的任务对延迟的时间没有任何要求,则使用工作队列,此时通常为无关紧要的任务

实际上,工作队列的本质就是将工作交给内核线程处理,因此其可以用内核线程替换。但是内核线程的创建和销毁对编程者的要求较高,而工作队列实现了内核线程的封装,不易出错,所以我们也推荐使用工作队列。

2.数据结构

//工作队列
struct workqueue_struct {
    struct list_head    pwqs;       /* WR: all pwqs of this wq */
    struct list_head    list;       /* PL: list of all workqueues */

    struct mutex        mutex;      /* protects this wq */
    int         work_color; /* WQ: current work color */
    int         flush_color;    /* WQ: current flush color */
    atomic_t        nr_pwqs_to_flush; /* flush in progress */
    struct wq_flusher   *first_flusher; /* WQ: first flusher */
    struct list_head    flusher_queue;  /* WQ: flush waiters */
    struct list_head    flusher_overflow; /* WQ: flush overflow list */

    struct list_head    maydays;    /* MD: pwqs requesting rescue */
    struct worker       *rescuer;   /* I: rescue worker */

    int         nr_drainers;    /* WQ: drain in progress */
    int         saved_max_active; /* WQ: saved pwq max_active */

    struct workqueue_attrs  *unbound_attrs; /* WQ: only for unbound wqs */
    struct pool_workqueue   *dfl_pwq;   /* WQ: only for unbound wqs */

#ifdef CONFIG_SYSFS
    struct wq_device    *wq_dev;    /* I: for sysfs interface */
#endif
#ifdef CONFIG_LOCKDEP
    struct lockdep_map  lockdep_map;
#endif
    char            name[WQ_NAME_LEN]; /* I: workqueue name */

    /* hot fields used during command issue, aligned to cacheline */
    unsigned int        flags ____cacheline_aligned; /* WQ: WQ_* flags */
    struct pool_workqueue __percpu *cpu_pwqs; /* I: per-cpu pwqs */
    struct pool_workqueue __rcu *numa_pwq_tbl[]; /* FR: unbound pwqs indexed by node */
};
//工作任务
struct work_struct {
    atomic_long_t data;
    struct list_head entry;
    work_func_t func;
#ifdef CONFIG_LOCKDEP
    struct lockdep_map lockdep_map;
#endif
};
//延时任务
struct delayed_work {
    struct work_struct work;
    struct timer_list timer;

    /* target workqueue and CPU ->timer uses to queue ->work */
    struct workqueue_struct *wq;
    int cpu;
};

3.创建与销毁workqueue_struct

//创建
#define alloc_ordered_workqueue(fmt, flags, args...)            \
    alloc_workqueue(fmt, WQ_UNBOUND | __WQ_ORDERED | (flags), 1, ##args)
//多处理器时会为每个cpu创建一个工作者线程
#define create_workqueue(name)                      \
    alloc_workqueue((name), WQ_MEM_RECLAIM, 1)
//只创建一个工作者线程,系统挂起,线程也挂起
#define create_freezable_workqueue(name)                \
    alloc_workqueue((name), WQ_FREEZABLE | WQ_UNBOUND | WQ_MEM_RECLAIM, 1)
//单核还是多核,都只在其中一个CPU上创建线程
#define create_singlethread_workqueue(name)             \
    alloc_workqueue((name), WQ_UNBOUND | WQ_MEM_RECLAIM, 1)

//释放创建的工作列队资源
extern void destroy_workqueue(struct workqueue_struct *wq);

//保证workqueue上的work都处理完了
extern void flush_workqueue(struct workqueue_struct *wq);

4.初始化work_struct

//工作队列待执行函数原型
typedef void (*work_func_t)(struct work_struct *work);

/* 静态初始化 */
//定义初始化工作任务work_struct
DECLARE_WORK(n,f); 
//定义初始化延时执行工作任务delayed_work
DECLARE_DELAYED_WORK(n,f);
//定义初始化延时执行工作任务delayed_work,如果处理器繁忙允许延后执行
DECLARE_DEFERRABLE_WORK(n, f)

/* 动态初始化 */
//初始化工作任务work_struct
INIT_WORK(_work, _func)
//初始化延时工作任务delayed_work
INIT_DELAYED_WORK(_work, _func)
//初始化延时执行工作任务delayed_work,如果处理器繁忙允许延后执行
INIT_DEFERRABLE_WORK(_work, _func)

INIT_DELAYED_WORK_ONSTACK(_work, _func)
INIT_DEFERRABLE_WORK_ONSTACK(_work, _func)
//修改_func    
PREPARE_WORK(_work, _func)  

//例如
void func(struct work_struct *work){}
void funca(struct work_struct *work){}
struct work_struct wo;
INIT_WORK(&wo,func);
PREPARE_WORK(&wo,funca);

5.调度work

//将工作加入工作列队进行调度
static inline bool queue_work(struct workqueue_struct *wq,struct work_struct *work)
//延时调用指定工作列队的工作
static inline bool queue_delayed_work(struct workqueue_struct *wq,struct delayed_work                                           *dwork,unsigned long delay)

static inline bool mod_delayed_work(struct workqueue_struct *wq,struct delayed_work                                             *dwork,unsigned long delay)

6.取消work

extern bool cancel_work_sync(struct work_struct *work);

extern bool cancel_delayed_work(struct delayed_work *dwork);
extern bool cancel_delayed_work_sync(struct delayed_work *dwork);

7.等待work完成

//等待工作完成返回true,工作已经完成返回false
extern bool flush_work(struct work_struct *work);
extern bool flush_delayed_work(struct delayed_work *dwork);

8.共享队列

共享队列,就是系统创建了默认的workqueue,只需要定义初始化work,调用接口就完成。

8.1 共享队列的调度

bool schedule_work(struct work_struct *work);
bool schedule_delayed_work(struct delayed_work *dwork,unsigned long delay);

8.2 取消work

bool cancel_work_sync(struct work_struct *work);

bool cancel_delayed_work(struct delayed_work *dwork);
bool cancel_delayed_work_sync(struct delayed_work *dwork);

8.3 等待work完成

extern void flush_scheduled_work(void);

9.驱动实例

delayed_work和work_struct操作是一样的根据work_struct的demo举一反三

9.1 demo1(INIT_WORK)

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/workqueue.h>

#define err(msg)                printk(KERN_ERR "%s: " msg "\n", DRIVER_NAME)
#define __debug(fmt, arg...)     printk(KERN_INFO fmt, ##arg)

struct timer_list timer;
struct workqueue_struct *wq; 
struct work_struct work;

void work_queue_fun(struct work_struct *work)
{
    //mdelay(5000);
    msleep(5000);
    __debug("==========work_queue_fun==========\n");
}

void work_queue_timer(unsigned long arg)
{  
    __debug("==========work_queue_timer==========\n");
    queue_work(wq ,&work);
}

static int __init work_queue_init(void)
{
    init_timer(&timer);
    timer.function = work_queue_timer;

    add_timer(&timer);
    mod_timer(&timer, jiffies + HZ * 3);

    wq = create_workqueue("wq_test");  //初始化工作对列
    INIT_WORK(&work, work_queue_fun);  //初始化任务

    __debug("\n===================work_queue_init====================\n");
    return 0;
}

static void __exit work_queue_exit(void)
{
    flush_work(&work);     //刷新任务
    flush_workqueue(wq);   //刷新工作队列
    destroy_workqueue(wq); //注销工作队列
    del_timer(&timer);

    __debug("\n===================work_queue_exit====================\n");
    return;
}

module_init(work_queue_init);
module_exit(work_queue_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("wyy");

9.2 demo2(DECLARE_WORK)

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/workqueue.h>

#define err(msg)                printk(KERN_ERR "%s: " msg "\n", DRIVER_NAME)
#define __debug(fmt, arg...)     printk(KERN_INFO fmt, ##arg)

struct timer_list timer;
struct workqueue_struct *wq; 

void work_queue_fun(struct work_struct *work)
{
    //mdelay(5000);
    msleep(5000);
    __debug("==========work_queue_fun==========\n");
}
DECLARE_WORK(work,work_queue_fun);


void work_queue_timer(unsigned long arg)
{  
    __debug("==========work_queue_timer==========\n");
    queue_work(wq ,&work);
}

static int __init work_queue_init(void)
{
    init_timer(&timer);
    timer.function = work_queue_timer;

    add_timer(&timer);
    mod_timer(&timer, jiffies + HZ * 3);

    wq = create_workqueue("wq_test");  //初始化工作对列

    __debug("\n===================work_queue_init====================\n");
    return 0;
}

static void __exit work_queue_exit(void)
{
    flush_work(&work);     //刷新任务
    flush_workqueue(wq);   //刷新工作队列
    destroy_workqueue(wq); //注销工作队列
    del_timer(&timer);

    __debug("\n===================work_queue_exit====================\n");
    return;
}

module_init(work_queue_init);
module_exit(work_queue_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("wyy");

9.3 demo3(delay_work)

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/workqueue.h>

#define err(msg)                printk(KERN_ERR "%s: " msg "\n", DRIVER_NAME)
#define __debug(fmt, arg...)     printk(KERN_INFO fmt, ##arg)

struct timer_list timer;
struct workqueue_struct *wq; 
struct delayed_work work;

void work_queue_fun(struct work_struct *work)
{
    __debug("==========work_queue_fun==========\n");
}

void work_queue_timer(unsigned long arg)
{  
    __debug("==========work_queue_timer==========\n");
    queue_delayed_work(wq ,&work,5 * HZ);
}

static int __init work_queue_init(void)
{
    init_timer(&timer);
    timer.function = work_queue_timer;

    add_timer(&timer);
    mod_timer(&timer, jiffies + HZ * 3);

    wq = create_workqueue("wq_test");  //初始化工作对列
    INIT_DELAYED_WORK(&work, work_queue_fun);  //初始化任务

    __debug("\n===================work_queue_init====================\n");
    return 0;
}

static void __exit work_queue_exit(void)
{
    flush_delayed_work(&work);     //刷新任务
    flush_workqueue(wq);   //刷新工作队列
    destroy_workqueue(wq); //注销工作队列
    del_timer(&timer);

    __debug("\n===================work_queue_exit====================\n");
    return;
}

module_init(work_queue_init);
module_exit(work_queue_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("wyy");

9.4 demo4(共享队列)

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/workqueue.h>

#define err(msg)                printk(KERN_ERR "%s: " msg "\n", DRIVER_NAME)
#define __debug(fmt, arg...)     printk(KERN_INFO fmt, ##arg)

struct timer_list timer;
struct work_struct work;

void work_queue_fun(struct work_struct *work)
{
    //mdelay(5000);
    msleep(5000);
    __debug("==========work_queue_fun==========\n");
}

void work_queue_timer(unsigned long arg)
{  
    __debug("==========work_queue_timer==========\n");
    schedule_work(&work);
}

static int __init work_queue_init(void)
{
    init_timer(&timer);
    timer.function = work_queue_timer;

    add_timer(&timer);
    mod_timer(&timer, jiffies + HZ * 3);

    INIT_WORK(&work, work_queue_fun);  //初始化任务

    __debug("\n===================work_queue_init====================\n");
    return 0;
}

static void __exit work_queue_exit(void)
{
    flush_work(&work);     //刷新任务
    cancel_work_sync(&work);
    del_timer(&timer);

    __debug("\n===================work_queue_exit====================\n");
    return;
}

module_init(work_queue_init);
module_exit(work_queue_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("wyy");

猜你喜欢

转载自blog.csdn.net/wyy626562203/article/details/81290282