Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 27922b4260f65d317aabda37e42bbbff > files > 2143

kernel-2.6.18-238.el5.src.rpm

From: Oleg Nesterov <oleg@redhat.com>
Date: Sun, 30 May 2010 16:21:50 -0400
Subject: [misc] workqueue: implement cancel_work_sync
Message-id: <20100530162150.GH9577@redhat.com>
Patchwork-id: 25910
O-Subject: [RHEL5 PATCH 7/7] bz#596626:  workqueues: implement cancel_work_sync()
Bugzilla: 596626
RH-Acked-by: Stanislaw Gruszka <sgruszka@redhat.com>
RH-Acked-by: Prarit Bhargava <prarit@redhat.com>

Finally we can implement cancel_work_sync().

Note that, unlike in upstream, we do not need a separate logic for
cancel_delayed_work_sync(). Every work (delayed or not) has work->timer,
and INIT_WORK/DECLARE_WORK initializes this timer correctly. This means
that cancel_delayed_work_sync() will be a trivial wrapper on top of
cancel_work_sync().

Note: the patch do not change include/linux/workqueue.h to avoid the
conflicts with Prarit's compat work, we we all the necessary declarations
later.

Signed-off-by: Oleg Nesterov <oleg@redhat.com>

diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 6d91710..fb1fc3f 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -461,6 +461,22 @@ static void wait_on_work(struct work_struct *work)
 	}
 }
 
+int cancel_work_sync(struct work_struct *work)
+{
+	int ret;
+
+	do {
+		ret = del_timer(&work->timer);
+		if (!ret)
+			ret = try_to_grab_pending(work);
+		wait_on_work(work);
+	} while (unlikely(ret < 0));
+
+	work->pending = 0; /* clears both "pending" and "valid" bits */
+	return ret;
+}
+EXPORT_SYMBOL(cancel_work_sync);
+
 static inline void cwq_basic_init(struct workqueue_struct *wq, int cpu)
 {
 	struct cpu_workqueue_struct *cwq = per_cpu_ptr(wq->cpu_wq, cpu);