Skip to content

Commit 4cb1ef6

Browse files
committed
workqueue: Implement BH workqueues to eventually replace tasklets
The only generic interface to execute asynchronously in the BH context is tasklet; however, it's marked deprecated and has some design flaws such as the execution code accessing the tasklet item after the execution is complete which can lead to subtle use-after-free in certain usage scenarios and less-developed flush and cancel mechanisms. This patch implements BH workqueues which share the same semantics and features of regular workqueues but execute their work items in the softirq context. As there is always only one BH execution context per CPU, none of the concurrency management mechanisms applies and a BH workqueue can be thought of as a convenience wrapper around softirq. Except for the inability to sleep while executing and lack of max_active adjustments, BH workqueues and work items should behave the same as regular workqueues and work items. Currently, the execution is hooked to tasklet[_hi]. However, the goal is to convert all tasklet users over to BH workqueues. Once the conversion is complete, tasklet can be removed and BH workqueues can directly take over the tasklet softirqs. system_bh[_highpri]_wq are added. As queue-wide flushing doesn't exist in tasklet, all existing tasklet users should be able to use the system BH workqueues without creating their own workqueues. v3: - Add missing interrupt.h include. v2: - Instead of using tasklets, hook directly into its softirq action functions - tasklet[_hi]_action(). This is slightly cheaper and closer to the eventual code structure we want to arrive at. Suggested by Lai. - Lai also pointed out several places which need NULL worker->task handling or can use clarification. Updated. Signed-off-by: Tejun Heo <tj@kernel.org> Suggested-by: Linus Torvalds <torvalds@linux-foundation.org> Link: http://lkml.kernel.org/r/CAHk-=wjDW53w4-YcSmgKC5RruiRLHmJ1sXeYdp_ZgVoBw=5byA@mail.gmail.com Tested-by: Allen Pais <allen.lkml@gmail.com> Reviewed-by: Lai Jiangshan <jiangshanlai@gmail.com>
1 parent 2fcdb1b commit 4cb1ef6

File tree

5 files changed

+285
-60
lines changed

5 files changed

+285
-60
lines changed

Documentation/core-api/workqueue.rst

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,12 @@ wants a function to be executed asynchronously it has to set up a work
7777
item pointing to that function and queue that work item on a
7878
workqueue.
7979

80-
Special purpose threads, called worker threads, execute the functions
81-
off of the queue, one after the other. If no work is queued, the
82-
worker threads become idle. These worker threads are managed in so
83-
called worker-pools.
80+
A work item can be executed in either a thread or the BH (softirq) context.
81+
82+
For threaded workqueues, special purpose threads, called [k]workers, execute
83+
the functions off of the queue, one after the other. If no work is queued,
84+
the worker threads become idle. These worker threads are managed in
85+
worker-pools.
8486

8587
The cmwq design differentiates between the user-facing workqueues that
8688
subsystems and drivers queue work items on and the backend mechanism
@@ -91,6 +93,12 @@ for high priority ones, for each possible CPU and some extra
9193
worker-pools to serve work items queued on unbound workqueues - the
9294
number of these backing pools is dynamic.
9395

96+
BH workqueues use the same framework. However, as there can only be one
97+
concurrent execution context, there's no need to worry about concurrency.
98+
Each per-CPU BH worker pool contains only one pseudo worker which represents
99+
the BH execution context. A BH workqueue can be considered a convenience
100+
interface to softirq.
101+
94102
Subsystems and drivers can create and queue work items through special
95103
workqueue API functions as they see fit. They can influence some
96104
aspects of the way the work items are executed by setting flags on the
@@ -106,7 +114,7 @@ unless specifically overridden, a work item of a bound workqueue will
106114
be queued on the worklist of either normal or highpri worker-pool that
107115
is associated to the CPU the issuer is running on.
108116

109-
For any worker pool implementation, managing the concurrency level
117+
For any thread pool implementation, managing the concurrency level
110118
(how many execution contexts are active) is an important issue. cmwq
111119
tries to keep the concurrency at a minimal but sufficient level.
112120
Minimal to save resources and sufficient in that the system is used at
@@ -164,6 +172,17 @@ resources, scheduled and executed.
164172
``flags``
165173
---------
166174

175+
``WQ_BH``
176+
BH workqueues can be considered a convenience interface to softirq. BH
177+
workqueues are always per-CPU and all BH work items are executed in the
178+
queueing CPU's softirq context in the queueing order.
179+
180+
All BH workqueues must have 0 ``max_active`` and ``WQ_HIGHPRI`` is the
181+
only allowed additional flag.
182+
183+
BH work items cannot sleep. All other features such as delayed queueing,
184+
flushing and canceling are supported.
185+
167186
``WQ_UNBOUND``
168187
Work items queued to an unbound wq are served by the special
169188
worker-pools which host workers which are not bound to any

include/linux/workqueue.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,7 @@ static inline unsigned int work_static(struct work_struct *work) { return 0; }
353353
* Documentation/core-api/workqueue.rst.
354354
*/
355355
enum wq_flags {
356+
WQ_BH = 1 << 0, /* execute in bottom half (softirq) context */
356357
WQ_UNBOUND = 1 << 1, /* not bound to any cpu */
357358
WQ_FREEZABLE = 1 << 2, /* freeze during suspend */
358359
WQ_MEM_RECLAIM = 1 << 3, /* may be used for memory reclaim */
@@ -392,6 +393,9 @@ enum wq_flags {
392393
__WQ_ORDERED = 1 << 17, /* internal: workqueue is ordered */
393394
__WQ_LEGACY = 1 << 18, /* internal: create*_workqueue() */
394395
__WQ_ORDERED_EXPLICIT = 1 << 19, /* internal: alloc_ordered_workqueue() */
396+
397+
/* BH wq only allows the following flags */
398+
__WQ_BH_ALLOWS = WQ_BH | WQ_HIGHPRI,
395399
};
396400

397401
enum wq_consts {
@@ -434,6 +438,9 @@ enum wq_consts {
434438
* they are same as their non-power-efficient counterparts - e.g.
435439
* system_power_efficient_wq is identical to system_wq if
436440
* 'wq_power_efficient' is disabled. See WQ_POWER_EFFICIENT for more info.
441+
*
442+
* system_bh[_highpri]_wq are convenience interface to softirq. BH work items
443+
* are executed in the queueing CPU's BH context in the queueing order.
437444
*/
438445
extern struct workqueue_struct *system_wq;
439446
extern struct workqueue_struct *system_highpri_wq;
@@ -442,6 +449,10 @@ extern struct workqueue_struct *system_unbound_wq;
442449
extern struct workqueue_struct *system_freezable_wq;
443450
extern struct workqueue_struct *system_power_efficient_wq;
444451
extern struct workqueue_struct *system_freezable_power_efficient_wq;
452+
extern struct workqueue_struct *system_bh_wq;
453+
extern struct workqueue_struct *system_bh_highpri_wq;
454+
455+
void workqueue_softirq_action(bool highpri);
445456

446457
/**
447458
* alloc_workqueue - allocate a workqueue

kernel/softirq.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <linux/tick.h>
2828
#include <linux/irq.h>
2929
#include <linux/wait_bit.h>
30+
#include <linux/workqueue.h>
3031

3132
#include <asm/softirq_stack.h>
3233

@@ -802,11 +803,13 @@ static void tasklet_action_common(struct softirq_action *a,
802803

803804
static __latent_entropy void tasklet_action(struct softirq_action *a)
804805
{
806+
workqueue_softirq_action(false);
805807
tasklet_action_common(a, this_cpu_ptr(&tasklet_vec), TASKLET_SOFTIRQ);
806808
}
807809

808810
static __latent_entropy void tasklet_hi_action(struct softirq_action *a)
809811
{
812+
workqueue_softirq_action(true);
810813
tasklet_action_common(a, this_cpu_ptr(&tasklet_hi_vec), HI_SOFTIRQ);
811814
}
812815

0 commit comments

Comments
 (0)