工作队列分析

 一、用法
struct cpu_workqueue_struct {

    spinlock_t lock;

    long remove_sequence;    /* Least-recently added (next to run) */
    long insert_sequence;    /* Next to add */

    struct list_head worklist;
    wait_queue_head_t more_work;
    wait_queue_head_t work_done;

    struct workqueue_struct *wq;
    struct task_struct *thread;

    int run_depth;        /* Detect run_workqueue() recursion depth */
} ____cacheline_aligned;

/*
* The externally visible workqueue abstraction is an array of
* per-CPU workqueues:
*/
struct workqueue_struct {
    struct cpu_workqueue_struct *cpu_wq;
    const char *name;
    struct list_head list;     /* Empty if single thread */
};

工作队列的使用很简单。
1.首先是建立一个工作队列:
    struct workqueue_struct *keventd_wq;
    keventd_wq = create_workqueue("events");
2.然后就是在这个队列中insert你所要做的“工作”:
    DECLARE_WORK(work, func, data)   
    queue_work(keventd_wq, work);

struct work_struct {
    unsigned long pending;
    struct list_head entry;
    void (*func)(void *);
    void *data;
    void *wq_data;
    struct timer_list timer;
};

初始化有两种方法。
一种为静态方法:
#define __WORK_INITIALIZER(n, f, d) {                /
        .entry    = { &(n).entry, &(n).entry },            /
    .func = (f),                        /
    .data = (d),                        /
    .timer = TIMER_INITIALIZER(NULL, 0, 0),            /
    }

#define DECLARE_WORK(n, f, d)                    /
    struct work_struct n = __WORK_INITIALIZER(n, f, d)

另一种为动态方法:
/*
* initialize all of a work-struct:
*/
#define INIT_WORK(_work, _func, _data)                /
    do {                            /
        INIT_LIST_HEAD(&(_work)->entry);        /
        (_work)->pending = 0;                /
        PREPARE_WORK((_work), (_func), (_data));    /
        init_timer(&(_work)->timer);            /
    } while (0)


二、执行过程
create_workqueue() -> __create_workqueue()

struct workqueue_struct *__create_workqueue(const char *name,
                        int singlethread)
{
    int cpu, destroy = 0;
    struct workqueue_struct *wq;
    struct task_struct *p;

    wq = kzalloc(sizeof(*wq), GFP_KERNEL);
    //为每个CPU建立一个结构
    wq->cpu_wq = alloc_percpu(struct cpu_workqueue_struct);
    ...
    wq->name = name;
    mutex_lock(&workqueue_mutex);
    if (singlethread) {
        ...
    } else {
        list_add(&wq->list, &workqueues);
        for_each_online_cpu(cpu) {
            //为每个CPU创建一个线程
            p = create_workqueue_thread(wq, cpu);
            if (p) {
                kthread_bind(p, cpu);
                //唤醒这个线程执行工作
                wake_up_process(p);
            } else
                destroy = 1;
        }
    }
    mutex_unlock(&workqueue_mutex);
    ...
    return wq;
}

create_workqueue() -> __create_workqueue() -> create_workqueue_thread()

static struct task_struct *create_workqueue_thread(struct workqueue_struct *wq,
                           int cpu)
{
    struct cpu_workqueue_struct *cwq = per_cpu_ptr(wq->cpu_wq, cpu);
    struct task_struct *p;

    spin_lock_init(&cwq->lock);
    cwq->wq = wq;
    cwq->thread = NULL;
    cwq->insert_sequence = 0;
    cwq->remove_sequence = 0;
    INIT_LIST_HEAD(&cwq->worklist);
    init_waitqueue_head(&cwq->more_work);
    init_waitqueue_head(&cwq->work_done);

    if (is_single_threaded(wq))
        p = kthread_create(worker_thread, cwq, "%s", wq->name);
    else
        //创建一个线程,这个线程以cwq为数据执行worker_thread这个函数
        p = kthread_create(worker_thread, cwq, "%s/%d", wq->name, cpu);
    if (IS_ERR(p))
        return NULL;
    cwq->thread = p; //
    return p;
}


create_workqueue() -> __create_workqueue() -> create_workqueue_thread() -> worker_thread()

//本函数在一个死循环等待工作的到来,这一般在睡眠状态中,等待被唤醒执行工作
//当有工作到来时queue_work()会将这个线程唤醒
static int worker_thread(void *__cwq)
{
    struct cpu_workqueue_struct *cwq = __cwq;
    DECLARE_WAITQUEUE(wait, current);
    ...

    current->flags |= PF_NOFREEZE;

    //设置优先级
    set_user_nice(current, -5);
    ...
    set_current_state(TASK_INTERRUPTIBLE);
    while (!kthread_should_stop()) {
        //将本线程加入睡眠队列,用于睡眠后可以被唤醒
        add_wait_queue(&cwq->more_work, &wait);

        //如果没用被执行的“工作”,则将自己切换出去,进入睡眠状态
        if (list_empty(&cwq->worklist))
            schedule();
        else //否则或是被唤醒
            __set_current_state(TASK_RUNNING);
        remove_wait_queue(&cwq->more_work, &wait);
       
        //工作队列非空,执行工作
        if (!list_empty(&cwq->worklist))
            run_workqueue(cwq);
        set_current_state(TASK_INTERRUPTIBLE);
    }
    __set_current_state(TASK_RUNNING);
    return 0;
}


    create_workqueue() -> __create_workqueue() -> create_workqueue_thread() -> worker_thread()
-> run_workqueue()
//该函数执行真正的工作
static void run_workqueue(struct cpu_workqueue_struct *cwq)
{
    unsigned long flags;

    spin_lock_irqsave(&cwq->lock, flags);
    ...
    //顺次执行队列中的所有工作
    while (!list_empty(&cwq->worklist)) {
        struct work_struct *work = list_entry(cwq->worklist.next,
                        struct work_struct, entry);
        void (*f) (void *) = work->func;
        void *data = work->data;

        //从队列中删除待执行的任务
        list_del_init(cwq->worklist.next);
        spin_unlock_irqrestore(&cwq->lock, flags);

        BUG_ON(work->wq_data != cwq);
        clear_bit(0, &work->pending);

        //执行“工作”
        f(data);

        spin_lock_irqsave(&cwq->lock, flags);
        cwq->remove_sequence++;
        wake_up(&cwq->work_done); //
    }
    cwq->run_depth--;
    spin_unlock_irqrestore(&cwq->lock, flags);
}

三、工作线程创建的详细过程
create_workqueue() -> __create_workqueue() -> create_workqueue_thread() -> kthread_create()

struct task_struct *kthread_create(int (*threadfn)(void *data),
                   void *data,
                   const char namefmt[],
                   ...)
{
    //初始化用于创建线程的辅助结构
    struct kthread_create_info create;
    DECLARE_WORK(work, keventd_create_kthread, &create);
    create.threadfn = threadfn;
    create.data = data;
    init_completion(&create.started);
    init_completion(&create.done);

    if (!helper_wq) //首先创建辅助工作队列
        work.func(work.data);
    else {
        //注意,“创建一个工作队列”这个工作本身又是属于helper_wq工作队列
        //的一项工作,所以,将这个工作加入的辅助工作队列中等待执行。
        queue_work(helper_wq, &work);
        wait_for_completion(&create.done);
    }
    ...
    return create.result;
}


    create_workqueue() -> __create_workqueue() -> create_workqueue_thread() -> kthread_create()
-> keventd_create_kthread()
//最终会调用kernel_thread为每个工作队列创建一个线程
//这样,被创建的线程会以create为数据执行kthread(如下),而kthread中则执行create中的threadfn(data),
//即为create_workqueue_thread中的worker_thread(cwq),即为我们工作队列要执行的函数了。

static void keventd_create_kthread(void *_create)
{
    struct kthread_create_info *create = _create;
    int pid;

    /* We want our own signal handler (we take no signals by default). */
    pid = kernel_thread(kthread, create, CLONE_FS | CLONE_FILES | SIGCHLD);
    if (pid < 0) {
        create->result = ERR_PTR(pid);
    } else {
        wait_for_completion(&create->started);
        read_lock(&tasklist_lock);
        create->result = find_task_by_pid(pid);
        read_unlock(&tasklist_lock);
    }
    complete(&create->done);
}

static int kthread(void *_create)
{
    struct kthread_create_info *create = _create;
    int (*threadfn)(void *data);
    void *data;
    ...
    threadfn = create->threadfn;
    data = create->data;
    ...
    if (!kthread_should_stop())
        ret = threadfn(data);
    ...
    return 0;
}

四、插入“工作”
/* Preempt must be disabled. */
static void __queue_work(struct cpu_workqueue_struct *cwq,
            struct work_struct *work)
{
    unsigned long flags;

    spin_lock_irqsave(&cwq->lock, flags);
    work->wq_data = cwq;
    //将当前工作插入到工作队列中待待执行
    list_add_tail(&work->entry, &cwq->worklist);
    cwq->insert_sequence++;
    wake_up(&cwq->more_work); //唤醒相应线程
    spin_unlock_irqrestore(&cwq->lock, flags);
}


int fastcall queue_work(struct workqueue_struct *wq, struct work_struct *work)
{
    int ret = 0, cpu = get_cpu();

    //如里当前工作未在队列中才插入
    if (!test_and_set_bit(0, &work->pending)) {
        ...
        __queue_work(per_cpu_ptr(wq->cpu_wq, cpu), work);
        ret = 1;
    }
    put_cpu();
    return ret;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值