微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > linux内核工作队列讲解和源码详细注释

linux内核工作队列讲解和源码详细注释

时间:10-08 来源:互联网 点击:

epth exceeded: %dn,__FUNCTION__, cwq->run_depth);dump_stack();} // 遍历工作链表while (!list_empty(cwq->worklist)) { // 获取的是next节点的struct work_struct *work = list_entry(cwq->worklist.next,struct work_struct, entry);void (*f) (void *) = work->func;void *data = work->data;// 删除节点, 同时节点中的list参数清空list_del_init(cwq->worklist.next);// 解锁// 现在在执行以下代码时可以中断,run_workqueue本身可能会重新被调用, 所以要判断递归深度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);}

4.2 释放工作队列

/** * destroy_workqueue - safely terminate a workqueue * @wq: target workqueue * * Safely destroy a workqueue. All work currently pending will be done first. */ void destroy_workqueue(struct workqueue_struct *wq)

{ int cpu;// 清除当前工作队列中的所有工作flush_workqueue(wq);/* We don't need the distraction of CPUs appearing and vanishing. */ mutex_lock(workqueue_mutex);// 结束该工作队列的线程if (is_single_threaded(wq))

cleanup_workqueue_thread(wq, singlethread_cpu);else { for_each_online_cpu(cpu)

cleanup_workqueue_thread(wq, cpu);list_del(wq->list);} mutex_unlock(workqueue_mutex);// 释放工作队列中对应每个CPU的工作队列数据free_percpu(wq->cpu_wq);kfree(wq);} EXPORT_SYMBOL_GPL(destroy_workqueue);

/** * flush_workqueue - ensure that any scheduled work has run to completion. * @wq: workqueue to flush * * Forces execution of the workqueue and blocks until its completion. * This is typically used in driver shutdown handlers. * * This function will sample each workqueue's current insert_sequence number and * will sleep until the head sequence is greater than or equal to that. This * means that we sleep until all works which were queued on entry have been * handled, but we are not livelocked by new incoming ones. * * This function used to run the workqueues itself. Now we just wait for the * helper threads to do it. */ void fastcall flush_workqueue(struct workqueue_struct *wq)

{ // 该进程可以睡眠might_sleep();// 清空每个CPU上的工作队列if (is_single_threaded(wq)) { /* Always use first cpu's area. */ flush_cpu_workqueue(per_cpu_ptr(wq->cpu_wq, singlethread_cpu));} else { int cpu;mutex_lock(workqueue_mutex);for_each_online_cpu(cpu)

flush_cpu_workqueue(per_cpu_ptr(wq->cpu_wq, cpu));mutex_unlock(workqueue_mutex);} EXPORT_SYMBOL_GPL(flush_workqueue);

flush_workqueue的核心处理函数为flush_cpu_workqueue:static void flush_cpu_workqueue(struct cpu_workqueue_struct *cwq)

{ if (cwq->thread == current) { // 如果是工作队列进程正在被调度/* * Probably keventd trying to flush its own queue. So simply run * it by hand rather than deadlocking. */ // 执行完该工作队列run_workqueue(cwq);} else { // 定义等待DEFINE_WAIT(wait);long sequence_needed;// 加锁spin_lock_irq(cwq->lock);// 最新工作结构序号sequence_needed = cwq->insert_sequence;// 该条件是判断队列中是否还有没有执行的工作结构while (sequence_needed - cwq->remove_sequence > 0) { // 有为执行的工作结构// 通过work_done等待队列等待prepare_to_wait(cwq->work_done, wait,TASK_UNINTERRUPTIBLE);// 解锁spin_unlock_irq(cwq->lock);// 睡眠, 由wake_up(cwq->work_done)来唤醒schedule();// 重新

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top