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 */ |
