diff options
author | Lai Jiangshan <laijs@cn.fujitsu.com> | 2012-09-10 13:03:33 -0400 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2012-09-10 13:04:54 -0400 |
commit | 552a37e9360a293cd20e7f8ff1fb326a244c5f1e (patch) | |
tree | 00d89d5778d4ab8320f6bf24d81e33a290f9fcb1 /kernel | |
parent | ec58815ab0409a921a7c9744eb4ca44866b14d71 (diff) |
workqueue: restore POOL_MANAGING_WORKERS
This patch restores POOL_MANAGING_WORKERS which was replaced by
pool->manager_mutex by 6037315269 "workqueue: use mutex for global_cwq
manager exclusion".
There's a subtle idle worker depletion bug across CPU hotplug events
and we need to distinguish an actual manager and CPU hotplug
preventing management. POOL_MANAGING_WORKERS will be used for the
former and manager_mutex the later.
This patch just lays POOL_MANAGING_WORKERS on top of the existing
manager_mutex and doesn't introduce any synchronization changes. The
next patch will update it.
Note that this patch fixes a non-critical anomaly where
too_many_workers() may return %true spuriously while CPU hotplug is in
progress. While the issue could schedule idle timer spuriously, it
didn't trigger any actual misbehavior.
tj: Rewrote patch description.
Signed-off-by: Lai Jiangshan <laijs@cn.fujitsu.com>
Signed-off-by: Tejun Heo <tj@kernel.org>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/workqueue.c | 5 |
1 files changed, 4 insertions, 1 deletions
diff --git a/kernel/workqueue.c b/kernel/workqueue.c index dc7b8458e275..383548ed0b54 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c | |||
@@ -66,6 +66,7 @@ enum { | |||
66 | 66 | ||
67 | /* pool flags */ | 67 | /* pool flags */ |
68 | POOL_MANAGE_WORKERS = 1 << 0, /* need to manage workers */ | 68 | POOL_MANAGE_WORKERS = 1 << 0, /* need to manage workers */ |
69 | POOL_MANAGING_WORKERS = 1 << 1, /* managing workers */ | ||
69 | 70 | ||
70 | /* worker flags */ | 71 | /* worker flags */ |
71 | WORKER_STARTED = 1 << 0, /* started */ | 72 | WORKER_STARTED = 1 << 0, /* started */ |
@@ -652,7 +653,7 @@ static bool need_to_manage_workers(struct worker_pool *pool) | |||
652 | /* Do we have too many workers and should some go away? */ | 653 | /* Do we have too many workers and should some go away? */ |
653 | static bool too_many_workers(struct worker_pool *pool) | 654 | static bool too_many_workers(struct worker_pool *pool) |
654 | { | 655 | { |
655 | bool managing = mutex_is_locked(&pool->manager_mutex); | 656 | bool managing = pool->flags & POOL_MANAGING_WORKERS; |
656 | int nr_idle = pool->nr_idle + managing; /* manager is considered idle */ | 657 | int nr_idle = pool->nr_idle + managing; /* manager is considered idle */ |
657 | int nr_busy = pool->nr_workers - nr_idle; | 658 | int nr_busy = pool->nr_workers - nr_idle; |
658 | 659 | ||
@@ -1827,6 +1828,7 @@ static bool manage_workers(struct worker *worker) | |||
1827 | if (!mutex_trylock(&pool->manager_mutex)) | 1828 | if (!mutex_trylock(&pool->manager_mutex)) |
1828 | return ret; | 1829 | return ret; |
1829 | 1830 | ||
1831 | pool->flags |= POOL_MANAGING_WORKERS; | ||
1830 | pool->flags &= ~POOL_MANAGE_WORKERS; | 1832 | pool->flags &= ~POOL_MANAGE_WORKERS; |
1831 | 1833 | ||
1832 | /* | 1834 | /* |
@@ -1836,6 +1838,7 @@ static bool manage_workers(struct worker *worker) | |||
1836 | ret |= maybe_destroy_workers(pool); | 1838 | ret |= maybe_destroy_workers(pool); |
1837 | ret |= maybe_create_worker(pool); | 1839 | ret |= maybe_create_worker(pool); |
1838 | 1840 | ||
1841 | pool->flags &= ~POOL_MANAGING_WORKERS; | ||
1839 | mutex_unlock(&pool->manager_mutex); | 1842 | mutex_unlock(&pool->manager_mutex); |
1840 | return ret; | 1843 | return ret; |
1841 | } | 1844 | } |