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
3726}3726}
3727 3727
3728/**3728/**
3729 * pwq_set_max_active - adjust max_active of a pwq3729 * pwq_adjust_max_active - update a pwq's max_active to the current setting
3730 * @pwq: target pool_workqueue3730 * @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.
3735 *3731 *
3736 * CONTEXT:3732 * If @pwq isn't freezing, set @pwq->max_active to the associated
3737 * spin_lock_irq(pool->lock).3733 * workqueue's saved_max_active and activate delayed work items
3734 * accordingly. If @pwq is freezing, clear @pwq->max_active to zero.
3738 */3735 */
3739static void pwq_set_max_active(struct pool_workqueue *pwq, int max_active)3736static void pwq_adjust_max_active(struct pool_workqueue *pwq)
3740{3737{
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;
3742 3752
3743 while (!list_empty(&pwq->delayed_works) &&3753 while (!list_empty(&pwq->delayed_works) &&
3744 pwq->nr_active < pwq->max_active)3754 pwq->nr_active < pwq->max_active)
3745 pwq_activate_first_delayed(pwq);3755 pwq_activate_first_delayed(pwq);
3756 } else {
3757 pwq->max_active = 0;
3758 }
3759
3760 spin_unlock(&pwq->pool->lock);
3746}3761}
3747 3762
3748static void init_and_link_pwq(struct pool_workqueue *pwq,3763static 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
3932 goto err_destroy;3947 goto err_destroy;
3933 3948
3934 /*3949 /*
3935 * workqueue_lock protects global freeze state and workqueues3950 * workqueue_lock protects global freeze state and workqueues list.
3936 * list. Grab it, set max_active accordingly and add the new3951 * Grab it, adjust max_active and add the new workqueue to
3937 * workqueue to workqueues list.3952 * workqueues list.
3938 */3953 */
3939 spin_lock_irq(&workqueue_lock);3954 spin_lock_irq(&workqueue_lock);
3940 3955
3941 if (workqueue_freezing && wq->flags & WQ_FREEZABLE)3956 for_each_pwq(pwq, wq)
3942 for_each_pwq(pwq, wq)3957 pwq_adjust_max_active(pwq);
3943 pwq->max_active = 0;
3944 3958
3945 list_add(&wq->list, &workqueues);3959 list_add(&wq->list, &workqueues);
3946 3960
@@ -4055,17 +4069,8 @@ void workqueue_set_max_active(struct workqueue_struct *wq, int max_active) · 108 unmodified lines
4055 4069
4056 wq->saved_max_active = max_active;4070 wq->saved_max_active = max_active;
4057 4071
4058 for_each_pwq(pwq, wq) {4072 for_each_pwq(pwq, wq)
4059 struct worker_pool *pool = pwq->pool;4073 pwq_adjust_max_active(pwq);
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 }
4069 4074
4070 spin_unlock_irq(&workqueue_lock);4075 spin_unlock_irq(&workqueue_lock);
4071}4076}
@@ -4358,14 +4363,8 @@ void freeze_workqueues_begin(void) · 286 unmodified lines
4358 4363
4359 /* suppress further executions by setting max_active to zero */4364 /* suppress further executions by setting max_active to zero */
4360 list_for_each_entry(wq, &workqueues, list) {4365 list_for_each_entry(wq, &workqueues, list) {
4361 if (!(wq->flags & WQ_FREEZABLE))4366 for_each_pwq(pwq, wq)
4362 continue;4367 pwq_adjust_max_active(pwq);
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 }
4369 }4368 }
4370 4369
4371 spin_unlock_irq(&workqueue_lock);4370 spin_unlock_irq(&workqueue_lock);
@@ -4445,14 +4444,8 @@ void thaw_workqueues(void) · 73 unmodified lines
4445 4444
4446 /* restore max_active and repopulate worklist */4445 /* restore max_active and repopulate worklist */
4447 list_for_each_entry(wq, &workqueues, list) {4446 list_for_each_entry(wq, &workqueues, list) {
4448 if (!(wq->flags & WQ_FREEZABLE))4447 for_each_pwq(pwq, wq)
4449 continue;4448 pwq_adjust_max_active(pwq);
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 }
4456 }4449 }
4457 4450
4458 /* kick workers */4451 /* kick workers */