History

workqueue: make hotplug processing per-pool

Instead of holding locks from both pools and then processing the pools together, make hotplug processing per-pool - grab locks of one pool, process it, release it and then proceed to the next pool. rebind_workers() is updated to take and process @pool instead of @gcwq which results in a lot of de-indentation. gcwq_claim_assoc_and_lock() and its counterpart are replaced with in-line per-pool locking. While this patch changes processing order across pools, order within each pool remains the same. As each pool is independent, this shouldn't break anything. This is part of an effort to remove global_cwq and make worker_pool the top level abstraction, which in turn will help implementing worker pools with user-specified attributes.

Tejun Heo committed 13 years ago

Commit 94cf58b1 parent d565ed61 file · +62 −87Browse files

Showing the changes to kernel/workqueue.c (1 of 1 file). Show all

Unified · Split

kernel/workqueue.c+62−87
@@ -1670,10 +1670,10 @@ static void busy_worker_rebind_fn(struct work_struct *work) · 1669 unmodified lines
16701670 }
16711671
16721672 /**
1673− * rebind_workers - rebind all workers of a gcwq to the associated CPU
1674− * @gcwq: gcwq of interest
1673+ * rebind_workers - rebind all workers of a pool to the associated CPU
1674+ * @pool: pool of interest
16751675 *
1676− * @gcwq->cpu is coming online. Rebind all workers to the CPU. Rebinding
1676+ * @pool->cpu is coming online. Rebind all workers to the CPU. Rebinding
16771677 * is different for idle and busy ones.
16781678 *
16791679 * Idle ones will be removed from the idle_list and woken up. They will
@@ -1691,60 +1691,53 @@ static void busy_worker_rebind_fn(struct work_struct *work) · 11 unmodified lines
16911691 * including the manager will not appear on @idle_list until rebind is
16921692 * complete, making local wake-ups safe.
16931693 */
1694−static void rebind_workers(struct global_cwq *gcwq)
1694+static void rebind_workers(struct worker_pool *pool)
16951695 {
1696− struct worker_pool *pool;
16971696 struct worker *worker, *n;
16981697 struct hlist_node *pos;
16991698 int i;
17001699
1701− for_each_worker_pool(pool, gcwq) {
1702− lockdep_assert_held(&pool->assoc_mutex);
1703− lockdep_assert_held(&pool->lock);
1704− }
1700+ lockdep_assert_held(&pool->assoc_mutex);
1701+ lockdep_assert_held(&pool->lock);
17051702
17061703 /* dequeue and kick idle ones */
1707− for_each_worker_pool(pool, gcwq) {
1708− list_for_each_entry_safe(worker, n, &pool->idle_list, entry) {
1709− /*
1710− * idle workers should be off @pool->idle_list
1711− * until rebind is complete to avoid receiving
1712− * premature local wake-ups.
1713− */
1714− list_del_init(&worker->entry);
1704+ list_for_each_entry_safe(worker, n, &pool->idle_list, entry) {
1705+ /*
1706+ * idle workers should be off @pool->idle_list until rebind
1707+ * is complete to avoid receiving premature local wake-ups.
1708+ */
1709+ list_del_init(&worker->entry);
17151710
1716− /*
1717− * worker_thread() will see the above dequeuing
1718− * and call idle_worker_rebind().
1719− */
1720− wake_up_process(worker->task);
1721− }
1711+ /*
1712+ * worker_thread() will see the above dequeuing and call
1713+ * idle_worker_rebind().
1714+ */
1715+ wake_up_process(worker->task);
1716+ }
17221717
1723− /* rebind busy workers */
1724− for_each_busy_worker(worker, i, pos, pool) {
1725− struct work_struct *rebind_work = &worker->rebind_work;
1726− struct workqueue_struct *wq;
1718+ /* rebind busy workers */
1719+ for_each_busy_worker(worker, i, pos, pool) {
1720+ struct work_struct *rebind_work = &worker->rebind_work;
1721+ struct workqueue_struct *wq;
17271722
1728− if (test_and_set_bit(WORK_STRUCT_PENDING_BIT,
1729− work_data_bits(rebind_work)))
1730− continue;
1723+ if (test_and_set_bit(WORK_STRUCT_PENDING_BIT,
1724+ work_data_bits(rebind_work)))
1725+ continue;
17311726
1732− debug_work_activate(rebind_work);
1727+ debug_work_activate(rebind_work);
17331728
1734− /*
1735− * wq doesn't really matter but let's keep
1736− * @worker->pool and @cwq->pool consistent for
1737− * sanity.
1738− */
1739− if (std_worker_pool_pri(worker->pool))
1740− wq = system_highpri_wq;
1741− else
1742− wq = system_wq;
1743−
1744− insert_work(get_cwq(pool->cpu, wq), rebind_work,
1745− worker->scheduled.next,
1746− work_color_to_flags(WORK_NO_COLOR));
1747− }
1729+ /*
1730+ * wq doesn't really matter but let's keep @worker->pool
1731+ * and @cwq->pool consistent for sanity.
1732+ */
1733+ if (std_worker_pool_pri(worker->pool))
1734+ wq = system_highpri_wq;
1735+ else
1736+ wq = system_wq;
1737+
1738+ insert_work(get_cwq(pool->cpu, wq), rebind_work,
1739+ worker->scheduled.next,
1740+ work_color_to_flags(WORK_NO_COLOR));
17481741 }
17491742 }
17501743
@@ -3497,7 +3490,7 @@ EXPORT_SYMBOL_GPL(work_busy); · 1746 unmodified lines
34973490 * are a lot of assumptions on strong associations among work, cwq and
34983491 * gcwq which make migrating pending and scheduled works very
34993492 * difficult to implement without impacting hot paths. Secondly,
3500− * gcwqs serve mix of short, long and very long running works making
3493+ * worker pools serve mix of short, long and very long running works making
35013494 * blocked draining impractical.
35023495 *
35033496 * This is solved by allowing the pools to be disassociated from the CPU
@@ -3505,32 +3498,6 @@ EXPORT_SYMBOL_GPL(work_busy); · 1 unmodified line
35053498 * cpu comes back online.
35063499 */
35073500
3508−/* claim manager positions of all pools */
3509−static void gcwq_claim_assoc_and_lock(struct global_cwq *gcwq)
3510−{
3511− struct worker_pool *pool;
3512−
3513− for_each_worker_pool(pool, gcwq)
3514− mutex_lock_nested(&pool->assoc_mutex, pool - gcwq->pools);
3515−
3516− local_irq_disable();
3517− for_each_worker_pool(pool, gcwq)
3518− spin_lock_nested(&pool->lock, pool - gcwq->pools);
3519−}
3520−
3521−/* release manager positions */
3522−static void gcwq_release_assoc_and_unlock(struct global_cwq *gcwq)
3523−{
3524− struct worker_pool *pool;
3525−
3526− for_each_worker_pool(pool, gcwq)
3527− spin_unlock(&pool->lock);
3528− local_irq_enable();
3529−
3530− for_each_worker_pool(pool, gcwq)
3531− mutex_unlock(&pool->assoc_mutex);
3532−}
3533−
35343501 static void gcwq_unbind_fn(struct work_struct *work)
35353502 {
35363503 struct global_cwq *gcwq = get_gcwq(smp_processor_id());
@@ -3539,17 +3506,19 @@ static void gcwq_unbind_fn(struct work_struct *work) · 2 unmodified lines
35393506 struct hlist_node *pos;
35403507 int i;
35413508
3542− BUG_ON(gcwq->pools[0].cpu != smp_processor_id());
3509+ for_each_worker_pool(pool, gcwq) {
3510+ BUG_ON(pool->cpu != smp_processor_id());
35433511
3544− gcwq_claim_assoc_and_lock(gcwq);
3512+ mutex_lock(&pool->assoc_mutex);
3513+ spin_lock_irq(&pool->lock);
35453514
3546− /*
3547− * We've claimed all manager positions. Make all workers unbound
3548− * and set DISASSOCIATED. Before this, all workers except for the
3549− * ones which are still executing works from before the last CPU
3550− * down must be on the cpu. After this, they may become diasporas.
3551− */
3552− for_each_worker_pool(pool, gcwq) {
3515+ /*
3516+ * We've claimed all manager positions. Make all workers
3517+ * unbound and set DISASSOCIATED. Before this, all workers
3518+ * except for the ones which are still executing works from
3519+ * before the last CPU down must be on the cpu. After
3520+ * this, they may become diasporas.
3521+ */
35533522 list_for_each_entry(worker, &pool->idle_list, entry)
35543523 worker->flags |= WORKER_UNBOUND;
35553524
@@ -3557,9 +3526,10 @@ static void gcwq_unbind_fn(struct work_struct *work) · 1 unmodified line
35573526 worker->flags |= WORKER_UNBOUND;
35583527
35593528 pool->flags |= POOL_DISASSOCIATED;
3560− }
35613529
3562− gcwq_release_assoc_and_unlock(gcwq);
3530+ spin_unlock_irq(&pool->lock);
3531+ mutex_unlock(&pool->assoc_mutex);
3532+ }
35633533
35643534 /*
35653535 * Call schedule() so that we cross rq->lock and thus can guarantee
@@ -3615,11 +3585,16 @@ static int __cpuinit workqueue_cpu_up_callback(struct notifier_block *nfb, · 49 unmodified lines
36153585
36163586 case CPU_DOWN_FAILED:
36173587 case CPU_ONLINE:
3618− gcwq_claim_assoc_and_lock(gcwq);
3619− for_each_worker_pool(pool, gcwq)
3588+ for_each_worker_pool(pool, gcwq) {
3589+ mutex_lock(&pool->assoc_mutex);
3590+ spin_lock_irq(&pool->lock);
3591+
36203592 pool->flags &= ~POOL_DISASSOCIATED;
3621− rebind_workers(gcwq);
3622− gcwq_release_assoc_and_unlock(gcwq);
3593+ rebind_workers(pool);
3594+
3595+ spin_unlock_irq(&pool->lock);
3596+ mutex_unlock(&pool->assoc_mutex);
3597+ }
36233598 break;
36243599 }
36253600 return NOTIFY_OK;