• Lai Jiangshan's avatar
    workqueue: add delayed_work->wq to simplify reentrancy handling · 60c057bc
    Lai Jiangshan authored
    To avoid executing the same work item from multiple CPUs concurrently,
    a work_struct records the last pool it was on in its ->data so that,
    on the next queueing, the pool can be queried to determine whether the
    work item is still executing or not.
    
    A delayed_work goes through timer before actually being queued on the
    target workqueue and the timer needs to know the target workqueue and
    CPU.  This is currently achieved by modifying delayed_work->work.data
    such that it points to the cwq which points to the target workqueue
    and the last CPU the work item was on.  __queue_delayed_work()
    extracts the last CPU from delayed_work->work.data and then combines
    it with the target workqueue to create new work.data.
    
    The only thing this rather ugly hack achieves is encoding the target
    workqueue into delayed_work->work.data without using a separate field,
    which could be a trade off one can make; unfortunately, this entangles
    work->data management between regular workqueue and delayed_work code
    by setting cwq pointer before the work item is actually queued and
    becomes a hindrance for further improvements of work->data handling.
    
    This can be easily made sane by adding a target workqueue field to
    delayed_work.  While delayed_work is used widely in the kernel and
    this does make it a bit larger (<5%), I think this is the right
    trade-off especially given the prospect of much saner handling of
    work->data which currently involves quite tricky memory barrier
    dancing, and don't expect to see any measureable effect.
    
    Add delayed_work->wq and drop the delayed_work->work.data overloading.
    
    tj: Rewrote the description.
    Signed-off-by: default avatarLai Jiangshan <laijs@cn.fujitsu.com>
    Signed-off-by: default avatarTejun Heo <tj@kernel.org>
    60c057bc
workqueue.c 105 KB