diff options
author | Tejun Heo <tj@kernel.org> | 2013-03-13 19:51:35 -0400 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2013-03-13 19:51:35 -0400 |
commit | 699ce097efe8f45bc5c055e4f12cb1e271c270d9 (patch) | |
tree | db116c908ed97eaf621c4dc99a4896acd51e56a2 /kernel/workqueue.c | |
parent | 0fbd95aa8a056194933fba4ae78c50fc20f0704e (diff) |
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.
Signed-off-by: Tejun Heo <tj@kernel.org>
Diffstat (limited to 'kernel/workqueue.c')
-rw-r--r-- | kernel/workqueue.c | 83 |
1 files changed, 38 insertions, 45 deletions
diff --git a/kernel/workqueue.c b/kernel/workqueue.c index d51928981615..9e2ec4ca415a 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c | |||
@@ -3726,23 +3726,38 @@ static void pwq_unbound_release_workfn(struct work_struct *work) | |||
3726 | } | 3726 | } |
3727 | 3727 | ||
3728 | /** | 3728 | /** |
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 |
3730 | * @pwq: target pool_workqueue | 3730 | * @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 | */ |
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) |
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 | ||
3748 | static void init_and_link_pwq(struct pool_workqueue *pwq, | 3763 | static void init_and_link_pwq(struct pool_workqueue *pwq, |
@@ -3932,15 +3947,14 @@ struct workqueue_struct *__alloc_workqueue_key(const char *fmt, | |||
3932 | goto err_destroy; | 3947 | goto err_destroy; |
3933 | 3948 | ||
3934 | /* | 3949 | /* |
3935 | * workqueue_lock protects global freeze state and workqueues | 3950 | * workqueue_lock protects global freeze state and workqueues list. |
3936 | * list. Grab it, set max_active accordingly and add the new | 3951 | * 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) | |||
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) | |||
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) | |||
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 */ |