From: Krishna Kumar <krkumar2@in.ibm.com>
To: linux-kernel@vger.kernel.org
Cc: Oleg Nesterov <oleg@tv-sign.ru>, Krishna Kumar <krkumar2@in.ibm.com>
Subject: [REV2: PATCH 1/2]: workqueue: Implement the kernel API
Date: Mon, 29 Sep 2008 12:33:14 +0530 [thread overview]
Message-ID: <20080929070314.7386.28163.sendpatchset@localhost.localdomain> (raw)
In-Reply-To: <20080929070302.7386.72726.sendpatchset@localhost.localdomain>
From: Krishna Kumar <krkumar2@in.ibm.com>
Implement two API's for quickly updating delayed works:
int schedule_update_delayed_work(struct delayed_work *dwork,
unsigned long delay);
int queue_update_delayed_work(struct workqueue_struct *wq,
struct delayed_work *dwork,
unsigned long delay);
These API's are useful to update an existing work entry more efficiently (but
can also be used to queue a new work entry) when the operation is done very
frequently. The rationale is to save time of first cancelling work/timer and
adding work/timer when the same work is added many times in quick succession.
Signed-off-by: Krishna Kumar <krkumar2@in.ibm.com>
---
include/linux/timer.h | 1
include/linux/workqueue.h | 4 +
kernel/timer.c | 22 ++++++
kernel/workqueue.c | 124 +++++++++++++++++++++++++++++++-----
4 files changed, 135 insertions(+), 16 deletions(-)
diff -ruNp 2.6.27-rc7-org/include/linux/timer.h 2.6.27-rc7-new/include/linux/timer.h
--- 2.6.27-rc7-org/include/linux/timer.h 2008-09-22 03:59:55.000000000 +0530
+++ 2.6.27-rc7-new/include/linux/timer.h 2008-09-29 12:06:17.000000000 +0530
@@ -88,6 +88,7 @@ extern void add_timer_on(struct timer_li
extern int del_timer(struct timer_list * timer);
extern int __mod_timer(struct timer_list *timer, unsigned long expires);
extern int mod_timer(struct timer_list *timer, unsigned long expires);
+extern int update_timer_expiry(struct timer_list *timer, unsigned long expires);
/*
* The jiffies value which is added to now, when there is no timer
diff -ruNp 2.6.27-rc7-org/include/linux/workqueue.h 2.6.27-rc7-new/include/linux/workqueue.h
--- 2.6.27-rc7-org/include/linux/workqueue.h 2008-09-22 03:59:55.000000000 +0530
+++ 2.6.27-rc7-new/include/linux/workqueue.h 2008-09-29 12:06:17.000000000 +0530
@@ -185,6 +185,8 @@ extern int queue_delayed_work(struct wor
struct delayed_work *work, unsigned long delay);
extern int queue_delayed_work_on(int cpu, struct workqueue_struct *wq,
struct delayed_work *work, unsigned long delay);
+extern int queue_update_delayed_work(struct workqueue_struct *wq,
+ struct delayed_work *dwork, unsigned long delay);
extern void flush_workqueue(struct workqueue_struct *wq);
extern void flush_scheduled_work(void);
@@ -194,6 +196,8 @@ extern int schedule_work_on(int cpu, str
extern int schedule_delayed_work(struct delayed_work *work, unsigned long delay);
extern int schedule_delayed_work_on(int cpu, struct delayed_work *work,
unsigned long delay);
+extern int schedule_update_delayed_work(struct delayed_work *work,
+ unsigned long delay);
extern int schedule_on_each_cpu(work_func_t func);
extern int current_is_keventd(void);
extern int keventd_up(void);
diff -ruNp 2.6.27-rc7-org/kernel/timer.c 2.6.27-rc7-new/kernel/timer.c
--- 2.6.27-rc7-org/kernel/timer.c 2008-09-22 03:59:55.000000000 +0530
+++ 2.6.27-rc7-new/kernel/timer.c 2008-09-29 12:06:29.000000000 +0530
@@ -520,6 +520,28 @@ static struct tvec_base *lock_timer_base
}
}
+/*
+ * update_timer: Quickly update the timer expiry if the timer is pending.
+ *
+ * Return 1 if the timer was successfully updated; otherwise return 0.
+ */
+int update_timer_expiry(struct timer_list *timer, unsigned long expires)
+{
+ struct tvec_base *base;
+ unsigned long flags;
+ int ret = 0;
+
+ base = lock_timer_base(timer, &flags);
+ if (likely(timer_pending(timer))) {
+ detach_timer(timer, 0);
+ timer->expires = expires;
+ internal_add_timer(base, timer);
+ ret = 1;
+ }
+ spin_unlock_irqrestore(&base->lock, flags);
+ return ret;
+}
+
int __mod_timer(struct timer_list *timer, unsigned long expires)
{
struct tvec_base *base, *new_base;
diff -ruNp 2.6.27-rc7-org/kernel/workqueue.c 2.6.27-rc7-new/kernel/workqueue.c
--- 2.6.27-rc7-org/kernel/workqueue.c 2008-09-22 03:59:55.000000000 +0530
+++ 2.6.27-rc7-new/kernel/workqueue.c 2008-09-29 12:20:27.000000000 +0530
@@ -202,6 +202,30 @@ static void delayed_work_timer_fn(unsign
__queue_work(wq_per_cpu(wq, smp_processor_id()), &dwork->work);
}
+static inline void __queue_delayed_work(int cpu, struct delayed_work *dwork,
+ struct work_struct *work,
+ struct workqueue_struct *wq,
+ unsigned long delay)
+{
+ struct timer_list *timer = &dwork->timer;
+
+ BUG_ON(timer_pending(timer));
+ BUG_ON(!list_empty(&work->entry));
+
+ timer_stats_timer_set_start_info(timer);
+
+ /* This stores cwq for the moment, for the timer_fn */
+ set_wq_data(work, wq_per_cpu(wq, raw_smp_processor_id()));
+ timer->expires = jiffies + delay;
+ timer->data = (unsigned long)dwork;
+ timer->function = delayed_work_timer_fn;
+
+ if (unlikely(cpu >= 0))
+ add_timer_on(timer, cpu);
+ else
+ add_timer(timer);
+}
+
/**
* queue_delayed_work - queue work on a workqueue after delay
* @wq: workqueue to use
@@ -233,31 +257,75 @@ int queue_delayed_work_on(int cpu, struc
struct delayed_work *dwork, unsigned long delay)
{
int ret = 0;
- struct timer_list *timer = &dwork->timer;
struct work_struct *work = &dwork->work;
if (!test_and_set_bit(WORK_STRUCT_PENDING, work_data_bits(work))) {
- BUG_ON(timer_pending(timer));
- BUG_ON(!list_empty(&work->entry));
-
- timer_stats_timer_set_start_info(&dwork->timer);
-
- /* This stores cwq for the moment, for the timer_fn */
- set_wq_data(work, wq_per_cpu(wq, raw_smp_processor_id()));
- timer->expires = jiffies + delay;
- timer->data = (unsigned long)dwork;
- timer->function = delayed_work_timer_fn;
-
- if (unlikely(cpu >= 0))
- add_timer_on(timer, cpu);
- else
- add_timer(timer);
+ __queue_delayed_work(cpu, dwork, work, wq, delay);
ret = 1;
}
return ret;
}
EXPORT_SYMBOL_GPL(queue_delayed_work_on);
+static int try_to_grab_pending(struct work_struct *work);
+static void wait_on_work(struct work_struct *work);
+
+/**
+ * queue_update_delayed_work - queue or update a work entry on a workqueue
+ * after delay
+ * @wq: workqueue to use
+ * @dwork: delayable work to queue
+ * @delay: number of jiffies to wait before queueing work
+ *
+ * This function is useful to update an existing delayed work without having
+ * to first cancel it. E.g. code snippets that can use this API:
+ * if (delayed_work_pending(&work))
+ * cancel_delayed_work(&work);
+ * queue_delayed_work(wq, &work, delay);
+ *
+ * Returns 0 if @work was already on a queue, non-zero otherwise.
+ */
+int queue_update_delayed_work(struct workqueue_struct *wq,
+ struct delayed_work *dwork, unsigned long delay)
+{
+ struct work_struct *work = &dwork->work;
+
+ if (!test_and_set_bit(WORK_STRUCT_PENDING, work_data_bits(work))) {
+ __queue_delayed_work(-1, dwork, work, wq, delay);
+ return 1;
+ } else {
+ struct timer_list *timer = &dwork->timer;
+ unsigned long when = jiffies + delay;
+ int ret;
+
+ /*
+ * Work is already scheduled. There is nothing to be done if
+ * the work is being modified to run at the same time.
+ */
+ if (timer->expires == when)
+ return 0;
+
+ do {
+ /*
+ * If the timer has been added and it has not fired,
+ * update_timer_expiry will update it with the correct
+ * expiry. Otherwise timer has either not yet been
+ * added or it has already fired - we need to try again.
+ */
+ if (likely(update_timer_expiry(timer, when)))
+ return 0;
+
+ ret = try_to_grab_pending(work);
+ if (ret < 0)
+ wait_on_work(work);
+ } while (ret < 0);
+
+ __queue_delayed_work(-1, dwork, work, wq, delay);
+ return 0;
+ }
+}
+EXPORT_SYMBOL_GPL(queue_update_delayed_work);
+
static void run_workqueue(struct cpu_workqueue_struct *cwq)
{
spin_lock_irq(&cwq->lock);
@@ -667,6 +735,30 @@ int schedule_delayed_work_on(int cpu,
EXPORT_SYMBOL(schedule_delayed_work_on);
/**
+ * schedule_update_delayed_work - queue or update a work entry in global
+ * workqueue after a delay
+ * @dwork: job to be done
+ * @delay: number of jiffies to wait before queueing work
+ *
+ * This function is useful to update an existing delayed work without having
+ * to first cancel it. E.g. code snippets that can use this API:
+ * if (delayed_work_pending(&work))
+ * cancel_delayed_work(&work);
+ * schedule_delayed_work(&work, delay);
+ *
+ * After waiting for a given time this puts a job in the kernel global
+ * workqueue.
+ *
+ * Returns 0 if @work was already on global workqueue, non-zero otherwise.
+ */
+int schedule_update_delayed_work(struct delayed_work *dwork,
+ unsigned long delay)
+{
+ return queue_update_delayed_work(keventd_wq, dwork, delay);
+}
+EXPORT_SYMBOL(schedule_update_delayed_work);
+
+/**
* schedule_on_each_cpu - call a function on each online CPU from keventd
* @func: the function to call
*
next prev parent reply other threads:[~2008-09-29 7:03 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-09-29 7:03 [REV2: PATCH 0/2] workqueue: Two API's to update delayed works quickly Krishna Kumar
2008-09-29 7:03 ` Krishna Kumar [this message]
2008-09-29 14:27 ` [REV2: PATCH 1/2]: workqueue: Implement the kernel API Oleg Nesterov
2008-09-30 11:08 ` Krishna Kumar2
2008-09-30 13:15 ` Oleg Nesterov
2008-09-29 7:03 ` [REV2: PATCH 2/2]: workqueue: Modify some users to use the new API Krishna Kumar
2008-09-29 14:45 ` Oleg Nesterov
-- strict thread matches above, loose matches on Subject: below --
2008-09-30 16:25 [REV2: PATCH 1/2]: workqueue: Implement the kernel API Krishna Kumar
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=20080929070314.7386.28163.sendpatchset@localhost.localdomain \
--to=krkumar2@in.ibm.com \
--cc=linux-kernel@vger.kernel.org \
--cc=oleg@tv-sign.ru \
/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.