Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Well, you know what they say about necessity being the mother of all invention (or research in this case). I really needed this answer and got it by digging through kernel/workqueue.c. Although the answer is mostly contained in the <a href="https://www.kernel.org/doc/htmldocs/device-drivers/ch01s06.html" rel="noreferrer">doc comments</a> combined with <a href="https://www.kernel.org/doc/Documentation/workqueue.txt" rel="noreferrer"><code>Documentation/workqueue.txt</code></a>, it isn't clearly spelled out without reading the whole spec on the Concurrency Managed Workqueue (cmwq) subsystem and even then, some of the information is out of date!</p> <p><strong>Short Answer</strong></p> <blockquote> <p>Will [your code] guarantee that the delayed_work will run as soon as possible?</p> </blockquote> <p>Yes (with the below caveat)</p> <blockquote> <p>What happens in a situation where the work is already running?</p> </blockquote> <p>It will run at some point <em>after</em> the currently running <code>delayed_work</code> function exits and on the same CPU as the last one, although any other work already queued on that workqueue (or delayed work that is due) will be run first. This is presuming that you have not re-initialized your <code>delayed_work</code> or <code>work_struct</code> object and that you have not changed the <code>work-&gt;func</code>tion pointer.</p> <p><strong>Long Answer</strong></p> <p>So first off, <a href="http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/linux/workqueue.h?id=9e895ace5d82df8929b16f58e9f515f6d54ab82d#n113" rel="noreferrer"><code>struct delayed_work</code></a> uses pseudo-inheritance to derive from <a href="http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/linux/workqueue.h?id=9e895ace5d82df8929b16f58e9f515f6d54ab82d#n113" rel="noreferrer"><code>struct work_struct</code></a> by embedding a <code>struct work_struct</code> as its first member. This subsystem uses some amazing atomic bit-frigging to have some serious concurrency. A <code>work_struct</code> is "owned" when it's <code>data</code> field has the <a href="http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/linux/workqueue.h?id=9e895ace5d82df8929b16f58e9f515f6d54ab82d#n42" rel="noreferrer"><code>WORK_STRUCT_PENDING</code></a> bit set. When a worker executes your work, it <a href="http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/kernel/workqueue.c?id=9e895ace5d82df8929b16f58e9f515f6d54ab82d#n2166" rel="noreferrer">releases ownership</a> and records the last work pool via the private <a href="http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/kernel/workqueue.c?id=9e895ace5d82df8929b16f58e9f515f6d54ab82d#n595" rel="noreferrer">set_work_pool_and_clear_pending()</a> function -- this is the last time the API modifies the <code>work_struct</code> object (until you re-schedule it, of course). Calling <a href="http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/kernel/workqueue.c?id=9e895ace5d82df8929b16f58e9f515f6d54ab82d#n2917" rel="noreferrer"><code>cancel_delayed_work()</code></a> does the exact same thing.</p> <p>So if you call <code>cancel_delayed_work()</code> when your work function has already begun executing, it returns <code>false</code> (as advertised) since it is no longer owned by anybody, even though it may still be running. However, when you try to re-add it with <code>schedule_delayed_work()</code>, it will <a href="http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/kernel/workqueue.c?id=9e895ace5d82df8929b16f58e9f515f6d54ab82d#n1324" rel="noreferrer">examine the work</a> to discover the last <code>pool_workqueue</code> and then find out if any of that <code>pool_workqueue</code>'s workers are currently running your work. If they are (and you haven't changed the <code>work-&gt;func</code> pointer), it simply appends the work to the queue of that <code>pool_workqueue</code> and that's how it avoids re-entrancy! Otherwise, it will queue it on the pool for the current CPU. (The reason for the <code>work-&gt;func</code> pointer check is to allow for reuse of the <code>work_struct</code> object.)</p> <p>Note however that simply calling <code>schedule_delayed_work()</code> without cancelling it first will result in <em>no</em> change if the work is still queued, so you definitely must cancel it first.</p> <p>EDIT: Oh yeah, if you are confused by the discussion in <code>Documentation/workqueue.txt</code> about <a href="http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/Documentation/workqueue.txt?id=9e895ace5d82df8929b16f58e9f515f6d54ab82d#n169" rel="noreferrer"><code>WQ_NON_REENTRANT</code></a>, ignore it. This flag is deprecated and ignored and all workqueues are now non-reetrant.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload