Skip to content

Commit 1c270b7

Browse files
committed
workqueue: Move nr_active handling into helpers
__queue_work(), pwq_dec_nr_in_flight() and wq_adjust_max_active() were open-coding nr_active handling, which is fine given that the operations are trivial. However, the planned unbound nr_active update will make them more complicated, so let's move them into helpers. - pwq_tryinc_nr_active() is added. It increments nr_active if under max_active limit and return a boolean indicating whether inc was successful. Note that the function is structured to accommodate future changes. __queue_work() is updated to use the new helper. - pwq_activate_first_inactive() is updated to use pwq_tryinc_nr_active() and thus no longer assumes that nr_active is under max_active and returns a boolean to indicate whether a work item has been activated. - wq_adjust_max_active() no longer tests directly whether a work item can be activated. Instead, it's updated to use the return value of pwq_activate_first_inactive() to tell whether a work item has been activated. - nr_active decrement and activating the first inactive work item is factored into pwq_dec_nr_active(). v3: - WARN_ON_ONCE(!WORK_STRUCT_INACTIVE) added to __pwq_activate_work() as now we're calling the function unconditionally from pwq_activate_first_inactive(). v2: - wq->max_active now uses WRITE/READ_ONCE() as suggested by Lai. Signed-off-by: Tejun Heo <tj@kernel.org> Reviewed-by: Lai Jiangshan <jiangshanlai@gmail.com>
1 parent 4c63803 commit 1c270b7

1 file changed

Lines changed: 67 additions & 19 deletions

File tree

kernel/workqueue.c

Lines changed: 67 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1468,11 +1468,14 @@ static bool pwq_is_empty(struct pool_workqueue *pwq)
14681468
static void __pwq_activate_work(struct pool_workqueue *pwq,
14691469
struct work_struct *work)
14701470
{
1471+
unsigned long *wdb = work_data_bits(work);
1472+
1473+
WARN_ON_ONCE(!(*wdb & WORK_STRUCT_INACTIVE));
14711474
trace_workqueue_activate_work(work);
14721475
if (list_empty(&pwq->pool->worklist))
14731476
pwq->pool->watchdog_ts = jiffies;
14741477
move_linked_works(work, &pwq->pool->worklist, NULL);
1475-
__clear_bit(WORK_STRUCT_INACTIVE_BIT, work_data_bits(work));
1478+
__clear_bit(WORK_STRUCT_INACTIVE_BIT, wdb);
14761479
}
14771480

14781481
/**
@@ -1497,12 +1500,66 @@ static bool pwq_activate_work(struct pool_workqueue *pwq,
14971500
return true;
14981501
}
14991502

1500-
static void pwq_activate_first_inactive(struct pool_workqueue *pwq)
1503+
/**
1504+
* pwq_tryinc_nr_active - Try to increment nr_active for a pwq
1505+
* @pwq: pool_workqueue of interest
1506+
*
1507+
* Try to increment nr_active for @pwq. Returns %true if an nr_active count is
1508+
* successfully obtained. %false otherwise.
1509+
*/
1510+
static bool pwq_tryinc_nr_active(struct pool_workqueue *pwq)
1511+
{
1512+
struct workqueue_struct *wq = pwq->wq;
1513+
struct worker_pool *pool = pwq->pool;
1514+
bool obtained;
1515+
1516+
lockdep_assert_held(&pool->lock);
1517+
1518+
obtained = pwq->nr_active < READ_ONCE(wq->max_active);
1519+
1520+
if (obtained)
1521+
pwq->nr_active++;
1522+
return obtained;
1523+
}
1524+
1525+
/**
1526+
* pwq_activate_first_inactive - Activate the first inactive work item on a pwq
1527+
* @pwq: pool_workqueue of interest
1528+
*
1529+
* Activate the first inactive work item of @pwq if available and allowed by
1530+
* max_active limit.
1531+
*
1532+
* Returns %true if an inactive work item has been activated. %false if no
1533+
* inactive work item is found or max_active limit is reached.
1534+
*/
1535+
static bool pwq_activate_first_inactive(struct pool_workqueue *pwq)
1536+
{
1537+
struct work_struct *work =
1538+
list_first_entry_or_null(&pwq->inactive_works,
1539+
struct work_struct, entry);
1540+
1541+
if (work && pwq_tryinc_nr_active(pwq)) {
1542+
__pwq_activate_work(pwq, work);
1543+
return true;
1544+
} else {
1545+
return false;
1546+
}
1547+
}
1548+
1549+
/**
1550+
* pwq_dec_nr_active - Retire an active count
1551+
* @pwq: pool_workqueue of interest
1552+
*
1553+
* Decrement @pwq's nr_active and try to activate the first inactive work item.
1554+
*/
1555+
static void pwq_dec_nr_active(struct pool_workqueue *pwq)
15011556
{
1502-
struct work_struct *work = list_first_entry(&pwq->inactive_works,
1503-
struct work_struct, entry);
1557+
struct worker_pool *pool = pwq->pool;
15041558

1505-
pwq_activate_work(pwq, work);
1559+
lockdep_assert_held(&pool->lock);
1560+
1561+
pwq->nr_active--;
1562+
pwq_activate_first_inactive(pwq);
15061563
}
15071564

15081565
/**
@@ -1520,14 +1577,8 @@ static void pwq_dec_nr_in_flight(struct pool_workqueue *pwq, unsigned long work_
15201577
{
15211578
int color = get_work_color(work_data);
15221579

1523-
if (!(work_data & WORK_STRUCT_INACTIVE)) {
1524-
pwq->nr_active--;
1525-
if (!list_empty(&pwq->inactive_works)) {
1526-
/* one down, submit an inactive one */
1527-
if (pwq->nr_active < READ_ONCE(pwq->wq->max_active))
1528-
pwq_activate_first_inactive(pwq);
1529-
}
1530-
}
1580+
if (!(work_data & WORK_STRUCT_INACTIVE))
1581+
pwq_dec_nr_active(pwq);
15311582

15321583
pwq->nr_in_flight[color]--;
15331584

@@ -1829,13 +1880,11 @@ static void __queue_work(int cpu, struct workqueue_struct *wq,
18291880
* @work must also queue behind existing inactive work items to maintain
18301881
* ordering when max_active changes. See wq_adjust_max_active().
18311882
*/
1832-
if (list_empty(&pwq->inactive_works) &&
1833-
pwq->nr_active < READ_ONCE(pwq->wq->max_active)) {
1883+
if (list_empty(&pwq->inactive_works) && pwq_tryinc_nr_active(pwq)) {
18341884
if (list_empty(&pool->worklist))
18351885
pool->watchdog_ts = jiffies;
18361886

18371887
trace_workqueue_activate_work(work);
1838-
pwq->nr_active++;
18391888
insert_work(pwq, work, &pool->worklist, work_flags);
18401889
kick_pool(pool);
18411890
} else {
@@ -4687,9 +4736,8 @@ static void wq_adjust_max_active(struct workqueue_struct *wq)
46874736
/* this function can be called during early boot w/ irq disabled */
46884737
raw_spin_lock_irqsave(&pwq->pool->lock, flags);
46894738

4690-
while (!list_empty(&pwq->inactive_works) &&
4691-
pwq->nr_active < wq->max_active)
4692-
pwq_activate_first_inactive(pwq);
4739+
while (pwq_activate_first_inactive(pwq))
4740+
;
46934741

46944742
kick_pool(pwq->pool);
46954743

0 commit comments

Comments
 (0)