linux kernel 工程师
全部博文(99)
分类: LINUX
2014-02-05 17:58:05
/**
* worker_thread - the worker thread function
* @__worker: self
*
* The gcwq worker thread function. There's a single dynamic pool of
* these per each cpu. These workers process all works regardless of
* their specific target workqueue. The only exception is works which
* belong to workqueues with a rescuer which will be explained in
* rescuer_thread().
*/
static int worker_thread(void *__worker)
{
struct worker *worker = __worker;
struct global_cwq *gcwq = worker->gcwq;
/* tell the scheduler that this is a workqueue worker */
worker->task->flags |= PF_WQ_WORKER;
woke_up:
spin_lock_irq(&gcwq->lock);
/* DIE can be set only while we're idle, checking here is enough */
if (worker->flags & WORKER_DIE) {
spin_unlock_irq(&gcwq->lock);
worker->task->flags &= ~PF_WQ_WORKER;
return 0;
}
worker_leave_idle(worker); /* 该worker离开idle状态, 从idle的list上摘下来,idle的worker数减1 */
recheck:
/* no more worker necessary? */
if (!need_more_worker(gcwq)) /* need_more_worker 含义: work list 上有work,但nr_running ==0 */
goto sleep;
/* do we need to manage? */
if (unlikely(!may_start_working(gcwq)) /* may_start_working返回idle 的workers,如果idle的worker数等于0, (!may_start_working(gcwq)返回true */
&& manage_workers(worker) /* 创建workers 成功 后,idle的worker数就会加1*/ )
goto recheck;
/* 线程x创建了线程y。
1. 线程y被唤醒后,如果获得在cpu上运行权,判断标号001, 由于work list 上有work,且nr_running ==0 ,所以 need_more_worker
返回true,(!need_more_worker(gcwq) 为false, 所以不会跳转到sleep 。在判断may_start_working(gcwq),idle 的workers==1, (!may_start_working(gcwq) 为false,
所以开始往下走。
2. 假如x继续占据cpu,判断标号001, 由于work list 上有work,切nr_running ==0 ,所以 need_more_worker
返回true,(!need_more_worker(gcwq) 为false, 所以不会跳转到sleep 。在判断may_start_working(gcwq),idle 的workers==1, (!may_start_working(gcwq) 为false,
所以开始往下走。
所以无论原线程x还是新创建的线程y获得cpu的运行权,执行的结果是一致的。
*/
/*
* ->scheduled list can only be filled while a worker is
* preparing to process a work or actually processing it.
* Make sure nobody diddled with it while I was sleeping.
*/
BUG_ON(!list_empty(&worker->scheduled));
/*
* When control reaches this point, we're guaranteed to have
* at least one idle worker or that someone else has already
* assumed the manager role.
*/
worker_clr_flags(worker, WORKER_PREP); /* nr_running 加1,如果一个workerA 执行到这一步,另外一个worker B在判断need_more_worker(gcwq)函数时, 就会得到false的结论,workerB sleep*/
/* 遍历global cpu work queue, work都在gcwq->worklist上 */
do {
struct work_struct *work =
list_first_entry(&gcwq->worklist,
struct work_struct, entry);
/* WORK_STRUCT_LINKED表示下一个工作与当前工作有联系,这样做保证这些有联系的工作按顺序执行,我自己的理解 */
if (likely(!(*work_data_bits(work) & WORK_STRUCT_LINKED))) {
/* optimization path, not strictly necessary */
process_one_work(worker, work); /* 一次一个的处理work*/
if (unlikely(!list_empty(&worker->scheduled)))
process_scheduled_works(worker);
} else {
move_linked_works(work, &worker->scheduled, NULL);
process_scheduled_works(worker);
}
} while (keep_working(gcwq));
worker_set_flags(worker, WORKER_PREP, false); /* nr_running 减1 */
sleep:
if (unlikely(need_to_manage_workers(gcwq)) && manage_workers(worker))
goto recheck;
/*
* gcwq->lock is held and there's no work to process and no
* need to manage, sleep. Workers are woken up only while
* holding gcwq->lock or from local cpu, so setting the
* current state before releasing gcwq->lock is enough to
* prevent losing any event.
*/
worker_enter_idle(worker); /* 该worker进入idle状态,加入idle的list上,idle的worker数加1 */
__set_current_state(TASK_INTERRUPTIBLE);
spin_unlock_irq(&gcwq->lock);
schedule();
goto woke_up;
}
-------------------------------------------------------------------------------
/* Do I need to keep working? Called from currently running workers. */
static bool keep_working(struct global_cwq *gcwq)
{
atomic_t *nr_running = get_gcwq_nr_running(gcwq->cpu);
return !list_empty(&gcwq->worklist) && /* worklist上还有工作要处理 */
(atomic_read(nr_running) <= 1 || /* 本cpu上的最后一个执行worker */
gcwq->flags & GCWQ_HIGHPRI_PENDING); /* 有高优先级work待处理 */
}