diff options
| -rw-r--r-- | include/linux/workqueue.h | 16 | ||||
| -rw-r--r-- | kernel/workqueue.c | 30 | 
2 files changed, 29 insertions, 17 deletions
| diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h index c959666eafca..f11100f96482 100644 --- a/include/linux/workqueue.h +++ b/include/linux/workqueue.h | |||
| @@ -25,18 +25,20 @@ typedef void (*work_func_t)(struct work_struct *work); | |||
| 25 | 25 | ||
| 26 | enum { | 26 | enum { | 
| 27 | WORK_STRUCT_PENDING_BIT = 0, /* work item is pending execution */ | 27 | WORK_STRUCT_PENDING_BIT = 0, /* work item is pending execution */ | 
| 28 | WORK_STRUCT_CWQ_BIT = 1, /* data points to cwq */ | 28 | WORK_STRUCT_DELAYED_BIT = 1, /* work item is delayed */ | 
| 29 | WORK_STRUCT_LINKED_BIT = 2, /* next work is linked to this one */ | 29 | WORK_STRUCT_CWQ_BIT = 2, /* data points to cwq */ | 
| 30 | WORK_STRUCT_LINKED_BIT = 3, /* next work is linked to this one */ | ||
| 30 | #ifdef CONFIG_DEBUG_OBJECTS_WORK | 31 | #ifdef CONFIG_DEBUG_OBJECTS_WORK | 
| 31 | WORK_STRUCT_STATIC_BIT = 3, /* static initializer (debugobjects) */ | 32 | WORK_STRUCT_STATIC_BIT = 4, /* static initializer (debugobjects) */ | 
| 32 | WORK_STRUCT_COLOR_SHIFT = 4, /* color for workqueue flushing */ | 33 | WORK_STRUCT_COLOR_SHIFT = 5, /* color for workqueue flushing */ | 
| 33 | #else | 34 | #else | 
| 34 | WORK_STRUCT_COLOR_SHIFT = 3, /* color for workqueue flushing */ | 35 | WORK_STRUCT_COLOR_SHIFT = 4, /* color for workqueue flushing */ | 
| 35 | #endif | 36 | #endif | 
| 36 | 37 | ||
| 37 | WORK_STRUCT_COLOR_BITS = 4, | 38 | WORK_STRUCT_COLOR_BITS = 4, | 
| 38 | 39 | ||
| 39 | WORK_STRUCT_PENDING = 1 << WORK_STRUCT_PENDING_BIT, | 40 | WORK_STRUCT_PENDING = 1 << WORK_STRUCT_PENDING_BIT, | 
| 41 | WORK_STRUCT_DELAYED = 1 << WORK_STRUCT_DELAYED_BIT, | ||
| 40 | WORK_STRUCT_CWQ = 1 << WORK_STRUCT_CWQ_BIT, | 42 | WORK_STRUCT_CWQ = 1 << WORK_STRUCT_CWQ_BIT, | 
| 41 | WORK_STRUCT_LINKED = 1 << WORK_STRUCT_LINKED_BIT, | 43 | WORK_STRUCT_LINKED = 1 << WORK_STRUCT_LINKED_BIT, | 
| 42 | #ifdef CONFIG_DEBUG_OBJECTS_WORK | 44 | #ifdef CONFIG_DEBUG_OBJECTS_WORK | 
| @@ -59,8 +61,8 @@ enum { | |||
| 59 | 61 | ||
| 60 | /* | 62 | /* | 
| 61 | * Reserve 7 bits off of cwq pointer w/ debugobjects turned | 63 | * Reserve 7 bits off of cwq pointer w/ debugobjects turned | 
| 62 | * off. This makes cwqs aligned to 128 bytes which isn't too | 64 | * off. This makes cwqs aligned to 256 bytes and allows 15 | 
| 63 | * excessive while allowing 15 workqueue flush colors. | 65 | * workqueue flush colors. | 
| 64 | */ | 66 | */ | 
| 65 | WORK_STRUCT_FLAG_BITS = WORK_STRUCT_COLOR_SHIFT + | 67 | WORK_STRUCT_FLAG_BITS = WORK_STRUCT_COLOR_SHIFT + | 
| 66 | WORK_STRUCT_COLOR_BITS, | 68 | WORK_STRUCT_COLOR_BITS, | 
| diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 362b50d092e2..a2dccfca03ba 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c | |||
| @@ -941,6 +941,7 @@ static void __queue_work(unsigned int cpu, struct workqueue_struct *wq, | |||
| 941 | struct global_cwq *gcwq; | 941 | struct global_cwq *gcwq; | 
| 942 | struct cpu_workqueue_struct *cwq; | 942 | struct cpu_workqueue_struct *cwq; | 
| 943 | struct list_head *worklist; | 943 | struct list_head *worklist; | 
| 944 | unsigned int work_flags; | ||
| 944 | unsigned long flags; | 945 | unsigned long flags; | 
| 945 | 946 | ||
| 946 | debug_work_activate(work); | 947 | debug_work_activate(work); | 
| @@ -990,14 +991,17 @@ static void __queue_work(unsigned int cpu, struct workqueue_struct *wq, | |||
| 990 | BUG_ON(!list_empty(&work->entry)); | 991 | BUG_ON(!list_empty(&work->entry)); | 
| 991 | 992 | ||
| 992 | cwq->nr_in_flight[cwq->work_color]++; | 993 | cwq->nr_in_flight[cwq->work_color]++; | 
| 994 | work_flags = work_color_to_flags(cwq->work_color); | ||
| 993 | 995 | ||
| 994 | if (likely(cwq->nr_active < cwq->max_active)) { | 996 | if (likely(cwq->nr_active < cwq->max_active)) { | 
| 995 | cwq->nr_active++; | 997 | cwq->nr_active++; | 
| 996 | worklist = gcwq_determine_ins_pos(gcwq, cwq); | 998 | worklist = gcwq_determine_ins_pos(gcwq, cwq); | 
| 997 | } else | 999 | } else { | 
| 1000 | work_flags |= WORK_STRUCT_DELAYED; | ||
| 998 | worklist = &cwq->delayed_works; | 1001 | worklist = &cwq->delayed_works; | 
| 1002 | } | ||
| 999 | 1003 | ||
| 1000 | insert_work(cwq, work, worklist, work_color_to_flags(cwq->work_color)); | 1004 | insert_work(cwq, work, worklist, work_flags); | 
| 1001 | 1005 | ||
| 1002 | spin_unlock_irqrestore(&gcwq->lock, flags); | 1006 | spin_unlock_irqrestore(&gcwq->lock, flags); | 
| 1003 | } | 1007 | } | 
| @@ -1666,6 +1670,7 @@ static void cwq_activate_first_delayed(struct cpu_workqueue_struct *cwq) | |||
| 1666 | struct list_head *pos = gcwq_determine_ins_pos(cwq->gcwq, cwq); | 1670 | struct list_head *pos = gcwq_determine_ins_pos(cwq->gcwq, cwq); | 
| 1667 | 1671 | ||
| 1668 | move_linked_works(work, pos, NULL); | 1672 | move_linked_works(work, pos, NULL); | 
| 1673 | __clear_bit(WORK_STRUCT_DELAYED_BIT, work_data_bits(work)); | ||
| 1669 | cwq->nr_active++; | 1674 | cwq->nr_active++; | 
| 1670 | } | 1675 | } | 
| 1671 | 1676 | ||
| @@ -1673,6 +1678,7 @@ static void cwq_activate_first_delayed(struct cpu_workqueue_struct *cwq) | |||
| 1673 | * cwq_dec_nr_in_flight - decrement cwq's nr_in_flight | 1678 | * cwq_dec_nr_in_flight - decrement cwq's nr_in_flight | 
| 1674 | * @cwq: cwq of interest | 1679 | * @cwq: cwq of interest | 
| 1675 | * @color: color of work which left the queue | 1680 | * @color: color of work which left the queue | 
| 1681 | * @delayed: for a delayed work | ||
| 1676 | * | 1682 | * | 
| 1677 | * A work either has completed or is removed from pending queue, | 1683 | * A work either has completed or is removed from pending queue, | 
| 1678 | * decrement nr_in_flight of its cwq and handle workqueue flushing. | 1684 | * decrement nr_in_flight of its cwq and handle workqueue flushing. | 
| @@ -1680,19 +1686,22 @@ static void cwq_activate_first_delayed(struct cpu_workqueue_struct *cwq) | |||
| 1680 | * CONTEXT: | 1686 | * CONTEXT: | 
| 1681 | * spin_lock_irq(gcwq->lock). | 1687 | * spin_lock_irq(gcwq->lock). | 
| 1682 | */ | 1688 | */ | 
| 1683 | static void cwq_dec_nr_in_flight(struct cpu_workqueue_struct *cwq, int color) | 1689 | static void cwq_dec_nr_in_flight(struct cpu_workqueue_struct *cwq, int color, | 
| 1690 | bool delayed) | ||
| 1684 | { | 1691 | { | 
| 1685 | /* ignore uncolored works */ | 1692 | /* ignore uncolored works */ | 
| 1686 | if (color == WORK_NO_COLOR) | 1693 | if (color == WORK_NO_COLOR) | 
| 1687 | return; | 1694 | return; | 
| 1688 | 1695 | ||
| 1689 | cwq->nr_in_flight[color]--; | 1696 | cwq->nr_in_flight[color]--; | 
| 1690 | cwq->nr_active--; | ||
| 1691 | 1697 | ||
| 1692 | if (!list_empty(&cwq->delayed_works)) { | 1698 | if (!delayed) { | 
| 1693 | /* one down, submit a delayed one */ | 1699 | cwq->nr_active--; | 
| 1694 | if (cwq->nr_active < cwq->max_active) | 1700 | if (!list_empty(&cwq->delayed_works)) { | 
| 1695 | cwq_activate_first_delayed(cwq); | 1701 | /* one down, submit a delayed one */ | 
| 1702 | if (cwq->nr_active < cwq->max_active) | ||
| 1703 | cwq_activate_first_delayed(cwq); | ||
| 1704 | } | ||
| 1696 | } | 1705 | } | 
| 1697 | 1706 | ||
| 1698 | /* is flush in progress and are we at the flushing tip? */ | 1707 | /* is flush in progress and are we at the flushing tip? */ | 
| @@ -1823,7 +1832,7 @@ __acquires(&gcwq->lock) | |||
| 1823 | hlist_del_init(&worker->hentry); | 1832 | hlist_del_init(&worker->hentry); | 
| 1824 | worker->current_work = NULL; | 1833 | worker->current_work = NULL; | 
| 1825 | worker->current_cwq = NULL; | 1834 | worker->current_cwq = NULL; | 
| 1826 | cwq_dec_nr_in_flight(cwq, work_color); | 1835 | cwq_dec_nr_in_flight(cwq, work_color, false); | 
| 1827 | } | 1836 | } | 
| 1828 | 1837 | ||
| 1829 | /** | 1838 | /** | 
| @@ -2388,7 +2397,8 @@ static int try_to_grab_pending(struct work_struct *work) | |||
| 2388 | debug_work_deactivate(work); | 2397 | debug_work_deactivate(work); | 
| 2389 | list_del_init(&work->entry); | 2398 | list_del_init(&work->entry); | 
| 2390 | cwq_dec_nr_in_flight(get_work_cwq(work), | 2399 | cwq_dec_nr_in_flight(get_work_cwq(work), | 
| 2391 | get_work_color(work)); | 2400 | get_work_color(work), | 
| 2401 | *work_data_bits(work) & WORK_STRUCT_DELAYED); | ||
| 2392 | ret = 1; | 2402 | ret = 1; | 
| 2393 | } | 2403 | } | 
| 2394 | } | 2404 | } | 
