Commit b5490077274482efde57a50b060b99bc839acd45

Authored by Tejun Heo
1 parent bf4ede014e

workqueue: introduce WORK_OFFQ_FLAG_*

Low WORK_STRUCT_FLAG_BITS bits of work_struct->data contain
WORK_STRUCT_FLAG_* and flush color.  If the work item is queued, the
rest point to the cpu_workqueue with WORK_STRUCT_CWQ set; otherwise,
WORK_STRUCT_CWQ is clear and the bits contain the last CPU number -
either a real CPU number or one of WORK_CPU_*.

Scheduled addition of mod_delayed_work[_on]() requires an additional
flag, which is used only while a work item is off queue.  There are
more than enough bits to represent off-queue CPU number on both 32 and
64bits.  This patch introduces WORK_OFFQ_FLAG_* which occupy the lower
part of the @work->data high bits while off queue.  This patch doesn't
define any actual OFFQ flag yet.

Off-queue CPU number is now shifted by WORK_OFFQ_CPU_SHIFT, which adds
the number of bits used by OFFQ flags to WORK_STRUCT_FLAG_SHIFT, to
make room for OFFQ flags.

To avoid shift width warning with large WORK_OFFQ_FLAG_BITS, ulong
cast is added to WORK_STRUCT_NO_CPU and, just in case, BUILD_BUG_ON()
to check that there are enough bits to accomodate off-queue CPU number
is added.

This patch doesn't make any functional difference.

Signed-off-by: Tejun Heo <tj@kernel.org>

Showing 2 changed files with 16 additions and 6 deletions Side-by-side Diff

include/linux/workqueue.h
... ... @@ -68,9 +68,15 @@
68 68 WORK_STRUCT_FLAG_BITS = WORK_STRUCT_COLOR_SHIFT +
69 69 WORK_STRUCT_COLOR_BITS,
70 70  
  71 + /* data contains off-queue information when !WORK_STRUCT_CWQ */
  72 + WORK_OFFQ_FLAG_BASE = WORK_STRUCT_FLAG_BITS,
  73 + WORK_OFFQ_FLAG_BITS = 0,
  74 + WORK_OFFQ_CPU_SHIFT = WORK_OFFQ_FLAG_BASE + WORK_OFFQ_FLAG_BITS,
  75 +
  76 + /* convenience constants */
71 77 WORK_STRUCT_FLAG_MASK = (1UL << WORK_STRUCT_FLAG_BITS) - 1,
72 78 WORK_STRUCT_WQ_DATA_MASK = ~WORK_STRUCT_FLAG_MASK,
73   - WORK_STRUCT_NO_CPU = WORK_CPU_NONE << WORK_STRUCT_FLAG_BITS,
  79 + WORK_STRUCT_NO_CPU = (unsigned long)WORK_CPU_NONE << WORK_OFFQ_CPU_SHIFT,
74 80  
75 81 /* bit mask for work_busy() return values */
76 82 WORK_BUSY_PENDING = 1 << 0,
... ... @@ -533,9 +533,9 @@
533 533 }
534 534  
535 535 /*
536   - * A work's data points to the cwq with WORK_STRUCT_CWQ set while the
537   - * work is on queue. Once execution starts, WORK_STRUCT_CWQ is
538   - * cleared and the work data contains the cpu number it was last on.
  536 + * While queued, %WORK_STRUCT_CWQ is set and non flag bits of a work's data
  537 + * contain the pointer to the queued cwq. Once execution starts, the flag
  538 + * is cleared and the high bits contain OFFQ flags and CPU number.
539 539 *
540 540 * set_work_cwq(), set_work_cpu_and_clear_pending() and clear_work_data()
541 541 * can be used to set the cwq, cpu or clear work->data. These functions
... ... @@ -565,7 +565,7 @@
565 565 static void set_work_cpu_and_clear_pending(struct work_struct *work,
566 566 unsigned int cpu)
567 567 {
568   - set_work_data(work, cpu << WORK_STRUCT_FLAG_BITS, 0);
  568 + set_work_data(work, (unsigned long)cpu << WORK_OFFQ_CPU_SHIFT, 0);
569 569 }
570 570  
571 571 static void clear_work_data(struct work_struct *work)
... ... @@ -592,7 +592,7 @@
592 592 return ((struct cpu_workqueue_struct *)
593 593 (data & WORK_STRUCT_WQ_DATA_MASK))->pool->gcwq;
594 594  
595   - cpu = data >> WORK_STRUCT_FLAG_BITS;
  595 + cpu = data >> WORK_OFFQ_CPU_SHIFT;
596 596 if (cpu == WORK_CPU_NONE)
597 597 return NULL;
598 598  
... ... @@ -3723,6 +3723,10 @@
3723 3723 {
3724 3724 unsigned int cpu;
3725 3725 int i;
  3726 +
  3727 + /* make sure we have enough bits for OFFQ CPU number */
  3728 + BUILD_BUG_ON((1LU << (BITS_PER_LONG - WORK_OFFQ_CPU_SHIFT)) <
  3729 + WORK_CPU_LAST);
3726 3730  
3727 3731 cpu_notifier(workqueue_cpu_up_callback, CPU_PRI_WORKQUEUE_UP);
3728 3732 cpu_notifier(workqueue_cpu_down_callback, CPU_PRI_WORKQUEUE_DOWN);