diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/workqueue.c | 47 |
1 files changed, 32 insertions, 15 deletions
diff --git a/kernel/workqueue.c b/kernel/workqueue.c index d7f1b7e2bba..4b3663b1c67 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c | |||
@@ -1004,15 +1004,33 @@ static void cwq_dec_nr_in_flight(struct cpu_workqueue_struct *cwq, int color, | |||
1004 | complete(&cwq->wq->first_flusher->done); | 1004 | complete(&cwq->wq->first_flusher->done); |
1005 | } | 1005 | } |
1006 | 1006 | ||
1007 | /* | 1007 | /** |
1008 | * Upon a successful return (>= 0), the caller "owns" WORK_STRUCT_PENDING bit, | 1008 | * try_to_grab_pending - steal work item from worklist |
1009 | * so this work can't be re-armed in any way. | 1009 | * @work: work item to steal |
1010 | * @is_dwork: @work is a delayed_work | ||
1011 | * | ||
1012 | * Try to grab PENDING bit of @work. This function can handle @work in any | ||
1013 | * stable state - idle, on timer or on worklist. Return values are | ||
1014 | * | ||
1015 | * 1 if @work was pending and we successfully stole PENDING | ||
1016 | * 0 if @work was idle and we claimed PENDING | ||
1017 | * -EAGAIN if PENDING couldn't be grabbed at the moment, safe to busy-retry | ||
1018 | * | ||
1019 | * On >= 0 return, the caller owns @work's PENDING bit. | ||
1010 | */ | 1020 | */ |
1011 | static int try_to_grab_pending(struct work_struct *work) | 1021 | static int try_to_grab_pending(struct work_struct *work, bool is_dwork) |
1012 | { | 1022 | { |
1013 | struct global_cwq *gcwq; | 1023 | struct global_cwq *gcwq; |
1014 | int ret = -1; | ||
1015 | 1024 | ||
1025 | /* try to steal the timer if it exists */ | ||
1026 | if (is_dwork) { | ||
1027 | struct delayed_work *dwork = to_delayed_work(work); | ||
1028 | |||
1029 | if (likely(del_timer(&dwork->timer))) | ||
1030 | return 1; | ||
1031 | } | ||
1032 | |||
1033 | /* try to claim PENDING the normal way */ | ||
1016 | if (!test_and_set_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(work))) | 1034 | if (!test_and_set_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(work))) |
1017 | return 0; | 1035 | return 0; |
1018 | 1036 | ||
@@ -1022,7 +1040,7 @@ static int try_to_grab_pending(struct work_struct *work) | |||
1022 | */ | 1040 | */ |
1023 | gcwq = get_work_gcwq(work); | 1041 | gcwq = get_work_gcwq(work); |
1024 | if (!gcwq) | 1042 | if (!gcwq) |
1025 | return ret; | 1043 | return -EAGAIN; |
1026 | 1044 | ||
1027 | spin_lock_irq(&gcwq->lock); | 1045 | spin_lock_irq(&gcwq->lock); |
1028 | if (!list_empty(&work->entry)) { | 1046 | if (!list_empty(&work->entry)) { |
@@ -1038,12 +1056,14 @@ static int try_to_grab_pending(struct work_struct *work) | |||
1038 | cwq_dec_nr_in_flight(get_work_cwq(work), | 1056 | cwq_dec_nr_in_flight(get_work_cwq(work), |
1039 | get_work_color(work), | 1057 | get_work_color(work), |
1040 | *work_data_bits(work) & WORK_STRUCT_DELAYED); | 1058 | *work_data_bits(work) & WORK_STRUCT_DELAYED); |
1041 | ret = 1; | 1059 | |
1060 | spin_unlock_irq(&gcwq->lock); | ||
1061 | return 1; | ||
1042 | } | 1062 | } |
1043 | } | 1063 | } |
1044 | spin_unlock_irq(&gcwq->lock); | 1064 | spin_unlock_irq(&gcwq->lock); |
1045 | 1065 | ||
1046 | return ret; | 1066 | return -EAGAIN; |
1047 | } | 1067 | } |
1048 | 1068 | ||
1049 | /** | 1069 | /** |
@@ -2817,15 +2837,12 @@ bool flush_work_sync(struct work_struct *work) | |||
2817 | } | 2837 | } |
2818 | EXPORT_SYMBOL_GPL(flush_work_sync); | 2838 | EXPORT_SYMBOL_GPL(flush_work_sync); |
2819 | 2839 | ||
2820 | static bool __cancel_work_timer(struct work_struct *work, | 2840 | static bool __cancel_work_timer(struct work_struct *work, bool is_dwork) |
2821 | struct timer_list* timer) | ||
2822 | { | 2841 | { |
2823 | int ret; | 2842 | int ret; |
2824 | 2843 | ||
2825 | do { | 2844 | do { |
2826 | ret = (timer && likely(del_timer(timer))); | 2845 | ret = try_to_grab_pending(work, is_dwork); |
2827 | if (!ret) | ||
2828 | ret = try_to_grab_pending(work); | ||
2829 | wait_on_work(work); | 2846 | wait_on_work(work); |
2830 | } while (unlikely(ret < 0)); | 2847 | } while (unlikely(ret < 0)); |
2831 | 2848 | ||
@@ -2853,7 +2870,7 @@ static bool __cancel_work_timer(struct work_struct *work, | |||
2853 | */ | 2870 | */ |
2854 | bool cancel_work_sync(struct work_struct *work) | 2871 | bool cancel_work_sync(struct work_struct *work) |
2855 | { | 2872 | { |
2856 | return __cancel_work_timer(work, NULL); | 2873 | return __cancel_work_timer(work, false); |
2857 | } | 2874 | } |
2858 | EXPORT_SYMBOL_GPL(cancel_work_sync); | 2875 | EXPORT_SYMBOL_GPL(cancel_work_sync); |
2859 | 2876 | ||
@@ -2914,7 +2931,7 @@ EXPORT_SYMBOL(flush_delayed_work_sync); | |||
2914 | */ | 2931 | */ |
2915 | bool cancel_delayed_work_sync(struct delayed_work *dwork) | 2932 | bool cancel_delayed_work_sync(struct delayed_work *dwork) |
2916 | { | 2933 | { |
2917 | return __cancel_work_timer(&dwork->work, &dwork->timer); | 2934 | return __cancel_work_timer(&dwork->work, true); |
2918 | } | 2935 | } |
2919 | EXPORT_SYMBOL(cancel_delayed_work_sync); | 2936 | EXPORT_SYMBOL(cancel_delayed_work_sync); |
2920 | 2937 | ||