aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2012-08-03 13:30:46 -0400
committerTejun Heo <tj@kernel.org>2012-08-03 13:30:46 -0400
commit36e227d242f9ec7cb4a8e968561b3b26e3d8b5d1 (patch)
treea35f1711123a22e90e6c06217cead66933404a3d /kernel
parent7beb2edf44b4dea820c733046ad7666d092bb4b6 (diff)
workqueue: reorganize try_to_grab_pending() and __cancel_timer_work()
* Use bool @is_dwork instead of @timer and let try_to_grab_pending() use to_delayed_work() to determine the delayed_work address. * Move timer handling from __cancel_work_timer() to try_to_grab_pending(). * Make try_to_grab_pending() use -EAGAIN instead of -1 for busy-looping and drop the ret local variable. * Add proper function comment to try_to_grab_pending(). This makes the code a bit easier to understand and will ease further changes. This patch doesn't make any functional change. v2: Use @is_dwork instead of @timer. Signed-off-by: Tejun Heo <tj@kernel.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/workqueue.c47
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 */
1011static int try_to_grab_pending(struct work_struct *work) 1021static 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}
2818EXPORT_SYMBOL_GPL(flush_work_sync); 2838EXPORT_SYMBOL_GPL(flush_work_sync);
2819 2839
2820static bool __cancel_work_timer(struct work_struct *work, 2840static 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 */
2854bool cancel_work_sync(struct work_struct *work) 2871bool 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}
2858EXPORT_SYMBOL_GPL(cancel_work_sync); 2875EXPORT_SYMBOL_GPL(cancel_work_sync);
2859 2876
@@ -2914,7 +2931,7 @@ EXPORT_SYMBOL(flush_delayed_work_sync);
2914 */ 2931 */
2915bool cancel_delayed_work_sync(struct delayed_work *dwork) 2932bool 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}
2919EXPORT_SYMBOL(cancel_delayed_work_sync); 2936EXPORT_SYMBOL(cancel_delayed_work_sync);
2920 2937