mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 04:34:03 +02: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:
parent
1ad5dcee7c
commit
d070f2916a
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user