mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-09-10 21:40:07 -04:00
workqueue: defer the worker wakeup outside pool->lock in __queue_work()
__queue_work() is the enqueue hot path: it inserts the work item and calls kick_pool() while holding pool->lock. kick_pool() ends in a wakeup, which takes the target task's rq->lock, so rq->lock nests under pool->lock on every enqueue that wakes a worker on a contended unbound pool. Use kick_pool_pick() to select and claim the worker under pool->lock and issue the wakeup with wake_up_process() right after dropping the lock. Signed-off-by: Breno Leitao <leitao@debian.org> Signed-off-by: Tejun Heo <tj@kernel.org>
This commit is contained in:
@@ -2302,6 +2302,7 @@ static void __queue_work(int cpu, struct workqueue_struct *wq,
|
||||
{
|
||||
struct pool_workqueue *pwq;
|
||||
struct worker_pool *last_pool, *pool;
|
||||
struct task_struct *wake_task = NULL;
|
||||
unsigned int work_flags;
|
||||
unsigned int req_cpu = cpu;
|
||||
|
||||
@@ -2424,7 +2425,7 @@ static void __queue_work(int cpu, struct workqueue_struct *wq,
|
||||
|
||||
trace_workqueue_activate_work(work);
|
||||
insert_work(pwq, work, &pool->worklist, work_flags);
|
||||
kick_pool(pool);
|
||||
kick_pool_pick(pool, &wake_task);
|
||||
} else {
|
||||
work_flags |= WORK_STRUCT_INACTIVE;
|
||||
insert_work(pwq, work, &pwq->inactive_works, work_flags);
|
||||
@@ -2432,6 +2433,8 @@ static void __queue_work(int cpu, struct workqueue_struct *wq,
|
||||
|
||||
out:
|
||||
raw_spin_unlock(&pool->lock);
|
||||
if (wake_task)
|
||||
wake_up_process(wake_task);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user