5151
5252 /* pool flags */
5353 POOL_MANAGE_WORKERS = 1 << 0 , /* need to manage workers */
54- POOL_MANAGING_WORKERS = 1 << 1 , /* managing workers */
5554
5655 /* worker flags */
5756 WORKER_STARTED = 1 << 0 , /* started */
@@ -155,6 +154,7 @@ struct worker_pool {
155154 struct timer_list idle_timer ; /* L: worker idle timeout */
156155 struct timer_list mayday_timer ; /* L: SOS timer for workers */
157156
157+ struct mutex manager_mutex ; /* mutex manager should hold */
158158 struct ida worker_ida ; /* L: for worker IDs */
159159 struct worker * first_idle ; /* L: first idle worker */
160160};
@@ -644,7 +644,7 @@ static bool need_to_manage_workers(struct worker_pool *pool)
644644/* Do we have too many workers and should some go away? */
645645static bool too_many_workers (struct worker_pool * pool )
646646{
647- bool managing = pool -> flags & POOL_MANAGING_WORKERS ;
647+ bool managing = mutex_is_locked ( & pool -> manager_mutex ) ;
648648 int nr_idle = pool -> nr_idle + managing ; /* manager is considered idle */
649649 int nr_busy = pool -> nr_workers - nr_idle ;
650650
@@ -1655,14 +1655,12 @@ static bool maybe_destroy_workers(struct worker_pool *pool)
16551655static bool manage_workers (struct worker * worker )
16561656{
16571657 struct worker_pool * pool = worker -> pool ;
1658- struct global_cwq * gcwq = pool -> gcwq ;
16591658 bool ret = false;
16601659
1661- if (pool -> flags & POOL_MANAGING_WORKERS )
1660+ if (! mutex_trylock ( & pool -> manager_mutex ) )
16621661 return ret ;
16631662
16641663 pool -> flags &= ~POOL_MANAGE_WORKERS ;
1665- pool -> flags |= POOL_MANAGING_WORKERS ;
16661664
16671665 /*
16681666 * Destroy and then create so that may_start_working() is true
@@ -1671,15 +1669,7 @@ static bool manage_workers(struct worker *worker)
16711669 ret |= maybe_destroy_workers (pool );
16721670 ret |= maybe_create_worker (pool );
16731671
1674- pool -> flags &= ~POOL_MANAGING_WORKERS ;
1675-
1676- /*
1677- * The trustee might be waiting to take over the manager
1678- * position, tell it we're done.
1679- */
1680- if (unlikely (gcwq -> trustee ))
1681- wake_up_all (& gcwq -> trustee_wait );
1682-
1672+ mutex_unlock (& pool -> manager_mutex );
16831673 return ret ;
16841674}
16851675
@@ -3255,6 +3245,24 @@ EXPORT_SYMBOL_GPL(work_busy);
32553245 * ----------------> RELEASE --------------
32563246 */
32573247
3248+ /* claim manager positions of all pools */
3249+ static void gcwq_claim_management (struct global_cwq * gcwq )
3250+ {
3251+ struct worker_pool * pool ;
3252+
3253+ for_each_worker_pool (pool , gcwq )
3254+ mutex_lock_nested (& pool -> manager_mutex , pool - gcwq -> pools );
3255+ }
3256+
3257+ /* release manager positions */
3258+ static void gcwq_release_management (struct global_cwq * gcwq )
3259+ {
3260+ struct worker_pool * pool ;
3261+
3262+ for_each_worker_pool (pool , gcwq )
3263+ mutex_unlock (& pool -> manager_mutex );
3264+ }
3265+
32583266/**
32593267 * trustee_wait_event_timeout - timed event wait for trustee
32603268 * @cond: condition to wait for
@@ -3304,16 +3312,6 @@ EXPORT_SYMBOL_GPL(work_busy);
33043312 __ret1 < 0 ? -1 : 0; \
33053313})
33063314
3307- static bool gcwq_is_managing_workers (struct global_cwq * gcwq )
3308- {
3309- struct worker_pool * pool ;
3310-
3311- for_each_worker_pool (pool , gcwq )
3312- if (pool -> flags & POOL_MANAGING_WORKERS )
3313- return true;
3314- return false;
3315- }
3316-
33173315static bool gcwq_has_idle_workers (struct global_cwq * gcwq )
33183316{
33193317 struct worker_pool * pool ;
@@ -3336,28 +3334,18 @@ static int __cpuinit trustee_thread(void *__gcwq)
33363334
33373335 BUG_ON (gcwq -> cpu != smp_processor_id ());
33383336
3337+ gcwq_claim_management (gcwq );
33393338 spin_lock_irq (& gcwq -> lock );
3340- /*
3341- * Claim the manager position and make all workers rogue.
3342- * Trustee must be bound to the target cpu and can't be
3343- * cancelled.
3344- */
3345- BUG_ON (gcwq -> cpu != smp_processor_id ());
3346- rc = trustee_wait_event (!gcwq_is_managing_workers (gcwq ));
3347- BUG_ON (rc < 0 );
33483339
33493340 /*
33503341 * We've claimed all manager positions. Make all workers unbound
33513342 * and set DISASSOCIATED. Before this, all workers except for the
33523343 * ones which are still executing works from before the last CPU
33533344 * down must be on the cpu. After this, they may become diasporas.
33543345 */
3355- for_each_worker_pool (pool , gcwq ) {
3356- pool -> flags |= POOL_MANAGING_WORKERS ;
3357-
3346+ for_each_worker_pool (pool , gcwq )
33583347 list_for_each_entry (worker , & pool -> idle_list , entry )
33593348 worker -> flags |= WORKER_UNBOUND ;
3360- }
33613349
33623350 for_each_busy_worker (worker , i , pos , gcwq )
33633351 worker -> flags |= WORKER_UNBOUND ;
@@ -3497,9 +3485,7 @@ static int __cpuinit trustee_thread(void *__gcwq)
34973485 work_color_to_flags (WORK_NO_COLOR ));
34983486 }
34993487
3500- /* relinquish manager role */
3501- for_each_worker_pool (pool , gcwq )
3502- pool -> flags &= ~POOL_MANAGING_WORKERS ;
3488+ gcwq_release_management (gcwq );
35033489
35043490 /* notify completion */
35053491 gcwq -> trustee = NULL ;
@@ -3894,6 +3880,7 @@ static int __init init_workqueues(void)
38943880 setup_timer (& pool -> mayday_timer , gcwq_mayday_timeout ,
38953881 (unsigned long )pool );
38963882
3883+ mutex_init (& pool -> manager_mutex );
38973884 ida_init (& pool -> worker_ida );
38983885 }
38993886
0 commit comments