All of lore.kernel.org
 help / color / mirror / Atom feed
From: James Bottomley <James.Bottomley@SteelEye.com>
To: Linux Kernel <linux-kernel@vger.kernel.org>
Cc: mingo@elte.hu
Subject: [PATCH] add unschedule_delayed_work to the workqueue API
Date: 18 Oct 2004 11:31:00 -0500	[thread overview]
Message-ID: <1098117067.2011.64.camel@mulgrave> (raw)

I'm in the process of moving some of our scsi timers which do more work
than just a few lines of code into schedule_work() instead.  The problem
is that the workqueue API lacks the equivalent of del_timer_sync(). 
This patch adds it as unschedule_delayed_work() (and also adds the
unschedule_work() API---it's probably much less useful, but
unschedule_delayed_work() is best constructed on top of it).

The idea is that unschedule_delayed_work() will return 0 if the work has
already executed and 1 if it hasn't.  It is guaranteed that either the
work was removed or has been executed by the time
unschedule_delayed_work() returns (and thus it needs process context to
wait for the work function if necessary).

Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

James

===== include/linux/workqueue.h 1.9 vs edited =====
--- 1.9/include/linux/workqueue.h	2004-08-23 03:14:58 -05:00
+++ edited/include/linux/workqueue.h	2004-10-18 10:01:54 -05:00
@@ -69,6 +69,11 @@
 extern int current_is_keventd(void);
 extern int keventd_up(void);
 
+extern int remove_work(struct workqueue_struct *wq, struct work_struct *work);
+extern int remove_delayed_work(struct workqueue_struct *wq, struct work_struct *work);
+extern int unschedule_work(struct work_struct *work);
+extern int unschedule_delayed_work(struct work_struct *work);
+
 extern void init_workqueues(void);
 
 /*
===== kernel/workqueue.c 1.28 vs edited =====
--- 1.28/kernel/workqueue.c	2004-09-08 01:33:10 -05:00
+++ edited/kernel/workqueue.c	2004-10-18 09:55:09 -05:00
@@ -81,6 +81,7 @@
 
 	spin_lock_irqsave(&cwq->lock, flags);
 	work->wq_data = cwq;
+	clear_bit(1, &work->pending);
 	list_add_tail(&work->entry, &cwq->worklist);
 	cwq->insert_sequence++;
 	wake_up(&cwq->more_work);
@@ -170,6 +171,7 @@
 		BUG_ON(work->wq_data != cwq);
 		clear_bit(0, &work->pending);
 		f(data);
+		set_bit(1, &work->pending);
 
 		spin_lock_irqsave(&cwq->lock, flags);
 		cwq->remove_sequence++;
@@ -517,13 +519,94 @@
 	BUG_ON(!keventd_wq);
 }
 
+/**
+ * remove_work - try to remove a piece of queued work from a workqueue
+ * @wq:		the workqueue to remove it from
+ * @work:	the item of work queued on the workqueue
+ *
+ * Tries to remove the work before it is executed.  Guarantees that
+ * when it returns either the work is removed or it has been executed.
+ * Requires process context since it may sleep if the work function is
+ * executing.
+ *
+ * Returns 1 if work was successfully removed without executing and 0
+ * if the work was executed.
+ */
+int remove_work(struct workqueue_struct *wq, struct work_struct *work)
+{
+	int ret = 1, cpu = get_cpu();
+	struct cpu_workqueue_struct *cwq;
+	unsigned long flags;
+
+	if (unlikely(is_single_threaded(wq)))
+		cpu = 0;
+
+	cwq = &wq->cpu_wq[cpu];
+
+	spin_lock_irqsave(&cwq->lock, flags);
+	list_del_init(&work->entry);
+	if (test_and_clear_bit(0, &work->pending))
+		goto out_unlock;
+	/* work is not pending.  It has either executed or is in the
+	 * process of executing */
+	ret = 0;
+	while (!test_bit(1, &work->pending)) {
+		DEFINE_WAIT(wait);
+		prepare_to_wait(&cwq->work_done, &wait,
+				TASK_UNINTERRUPTIBLE);
+		spin_unlock_irq(&cwq->lock);
+		schedule();
+		spin_lock_irq(&cwq->lock);
+		finish_wait(&cwq->work_done, &wait);
+	}
+
+ out_unlock:
+	spin_unlock_irqrestore(&cwq->lock, flags);
+
+	put_cpu();
+	return ret;
+}
+
+/**
+ * remove_delayed_work - try to remove a piece of queued work from a workqueue
+ * @wq:		the workqueue to remove it from
+ * @work:	the item of work queued on the workqueue
+ *
+ * Tries to remove the work before it is executed.  Guarantees that
+ * when it returns either the work is removed or it has been executed.
+ * Requires process context since it may sleep if the work function is
+ * executing.
+ *
+ * Returns 1 if work was successfully removed without executing and 0
+ * if the work was executed.
+ */
+int remove_delayed_work(struct workqueue_struct *wq, struct work_struct *work)
+{
+	if (del_timer_sync(&work->timer))
+		return 1;
+	return remove_work(wq, work);
+}
+
+int unschedule_work(struct work_struct *work)
+{
+	return remove_work(keventd_wq, work);
+}
+
+int unschedule_delayed_work(struct work_struct *work)
+{
+	return remove_delayed_work(keventd_wq, work);
+}
+
 EXPORT_SYMBOL_GPL(__create_workqueue);
 EXPORT_SYMBOL_GPL(queue_work);
 EXPORT_SYMBOL_GPL(queue_delayed_work);
 EXPORT_SYMBOL_GPL(flush_workqueue);
 EXPORT_SYMBOL_GPL(destroy_workqueue);
+EXPORT_SYMBOL_GPL(remove_work);
 
 EXPORT_SYMBOL(schedule_work);
 EXPORT_SYMBOL(schedule_delayed_work);
 EXPORT_SYMBOL(schedule_delayed_work_on);
 EXPORT_SYMBOL(flush_scheduled_work);
+EXPORT_SYMBOL(unschedule_work);
+EXPORT_SYMBOL(unschedule_delayed_work);


             reply	other threads:[~2004-10-18 16:31 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2004-10-18 16:31 James Bottomley [this message]
2004-10-18 21:25 ` [PATCH] add unschedule_delayed_work to the workqueue API Andrew Morton
2004-10-18 21:26   ` James Bottomley
2004-10-18 21:29     ` James Bottomley
2004-10-18 21:43       ` Andrew Morton
2004-10-18 21:47         ` James Bottomley
2004-10-18 22:02           ` Andrew Morton
2004-10-18 22:15             ` James Bottomley
2004-10-18 22:57               ` Andrew Morton
2004-10-18 23:24                 ` James Bottomley

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1098117067.2011.64.camel@mulgrave \
    --to=james.bottomley@steeleye.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mingo@elte.hu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.