History

workqueue: implement and use pwq_adjust_max_active()

Rename pwq_set_max_active() to pwq_adjust_max_active() and move pool_workqueue->max_active synchronization and max_active determination logic into it. The new function should be called with workqueue_lock held for stable workqueue->saved_max_active, determines the current max_active value the target pool_workqueue should be using from @wq->saved_max_active and the state of the associated pool, and applies it with proper synchronization. The current two users - workqueue_set_max_active() and thaw_workqueues() - are updated accordingly. In addition, the manual freezing handling in __alloc_workqueue_key() and freeze_workqueues_begin() are replaced with calls to pwq_adjust_max_active(). This centralizes max_active handling so that it's less error-prone.

Tejun Heo committed 13 years ago

Commit 699ce091 parent 0fbd95a1 file · +38 −45Browse files

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

Unified · Split

kernel/workqueue.c+38−45
@@ -3726,23 +3726,38 @@ static void pwq_unbound_release_workfn(struct work_struct *work) · 3725 unmodified lines
37263726 }
37273727
37283728 /**
3729− * pwq_set_max_active - adjust max_active of a pwq
3729+ * pwq_adjust_max_active - update a pwq's max_active to the current setting
37303730 * @pwq: target pool_workqueue
3731− * @max_active: new max_active value.
3732− *
3733− * Set @pwq->max_active to @max_active and activate delayed works if
3734− * increased.
37353731 *
3736− * CONTEXT:
3737− * spin_lock_irq(pool->lock).
3732+ * If @pwq isn't freezing, set @pwq->max_active to the associated
3733+ * workqueue's saved_max_active and activate delayed work items
3734+ * accordingly. If @pwq is freezing, clear @pwq->max_active to zero.
37383735 */
3739−static void pwq_set_max_active(struct pool_workqueue *pwq, int max_active)
3736+static void pwq_adjust_max_active(struct pool_workqueue *pwq)
37403737 {
3741− pwq->max_active = max_active;
3738+ struct workqueue_struct *wq = pwq->wq;
3739+ bool freezable = wq->flags & WQ_FREEZABLE;
3740+
3741+ /* for @wq->saved_max_active */
3742+ lockdep_assert_held(&workqueue_lock);
3743+
3744+ /* fast exit for non-freezable wqs */
3745+ if (!freezable && pwq->max_active == wq->saved_max_active)
3746+ return;
3747+
3748+ spin_lock(&pwq->pool->lock);
3749+
3750+ if (!freezable || !(pwq->pool->flags & POOL_FREEZING)) {
3751+ pwq->max_active = wq->saved_max_active;
37423752
3743− while (!list_empty(&pwq->delayed_works) &&
3744− pwq->nr_active < pwq->max_active)
3745− pwq_activate_first_delayed(pwq);
3753+ while (!list_empty(&pwq->delayed_works) &&
3754+ pwq->nr_active < pwq->max_active)
3755+ pwq_activate_first_delayed(pwq);
3756+ } else {
3757+ pwq->max_active = 0;
3758+ }
3759+
3760+ spin_unlock(&pwq->pool->lock);
37463761 }
37473762
37483763 static void init_and_link_pwq(struct pool_workqueue *pwq,
@@ -3932,15 +3947,14 @@ struct workqueue_struct *__alloc_workqueue_key(const char *fmt, · 183 unmodified lines
39323947 goto err_destroy;
39333948
39343949 /*
3935− * workqueue_lock protects global freeze state and workqueues
3936− * list. Grab it, set max_active accordingly and add the new
3937− * workqueue to workqueues list.
3950+ * workqueue_lock protects global freeze state and workqueues list.
3951+ * Grab it, adjust max_active and add the new workqueue to
3952+ * workqueues list.
39383953 */
39393954 spin_lock_irq(&workqueue_lock);
39403955
3941− if (workqueue_freezing && wq->flags & WQ_FREEZABLE)
3942− for_each_pwq(pwq, wq)
3943− pwq->max_active = 0;
3956+ for_each_pwq(pwq, wq)
3957+ pwq_adjust_max_active(pwq);
39443958
39453959 list_add(&wq->list, &workqueues);
39463960
@@ -4055,17 +4069,8 @@ void workqueue_set_max_active(struct workqueue_struct *wq, int max_active) · 108 unmodified lines
40554069
40564070 wq->saved_max_active = max_active;
40574071
4058− for_each_pwq(pwq, wq) {
4059− struct worker_pool *pool = pwq->pool;
4060−
4061− spin_lock(&pool->lock);
4062−
4063− if (!(wq->flags & WQ_FREEZABLE) ||
4064− !(pool->flags & POOL_FREEZING))
4065− pwq_set_max_active(pwq, max_active);
4066−
4067− spin_unlock(&pool->lock);
4068− }
4072+ for_each_pwq(pwq, wq)
4073+ pwq_adjust_max_active(pwq);
40694074
40704075 spin_unlock_irq(&workqueue_lock);
40714076 }
@@ -4358,14 +4363,8 @@ void freeze_workqueues_begin(void) · 286 unmodified lines
43584363
43594364 /* suppress further executions by setting max_active to zero */
43604365 list_for_each_entry(wq, &workqueues, list) {
4361− if (!(wq->flags & WQ_FREEZABLE))
4362− continue;
4363−
4364− for_each_pwq(pwq, wq) {
4365− spin_lock(&pwq->pool->lock);
4366− pwq->max_active = 0;
4367− spin_unlock(&pwq->pool->lock);
4368− }
4366+ for_each_pwq(pwq, wq)
4367+ pwq_adjust_max_active(pwq);
43694368 }
43704369
43714370 spin_unlock_irq(&workqueue_lock);
@@ -4445,14 +4444,8 @@ void thaw_workqueues(void) · 73 unmodified lines
44454444
44464445 /* restore max_active and repopulate worklist */
44474446 list_for_each_entry(wq, &workqueues, list) {
4448− if (!(wq->flags & WQ_FREEZABLE))
4449− continue;
4450−
4451− for_each_pwq(pwq, wq) {
4452− spin_lock(&pwq->pool->lock);
4453− pwq_set_max_active(pwq, wq->saved_max_active);
4454− spin_unlock(&pwq->pool->lock);
4455− }
4447+ for_each_pwq(pwq, wq)
4448+ pwq_adjust_max_active(pwq);
44564449 }
44574450
44584451 /* kick workers */