summaryrefslogtreecommitdiffstats
path: root/include/linux/timer.h
diff options
context:
space:
mode:
authorPhil Carmody <ext-phil.2.carmody@nokia.com>2010-10-20 15:57:33 -0700
committerThomas Gleixner <tglx@linutronix.de>2010-10-21 17:30:06 +0200
commitdd6414b50fa2b1cd247a8aa8f8bd42414b7453e1 (patch)
treed6572c35cf1997e2d18e451cb44742c89723d804 /include/linux/timer.h
parent2bf1c05e3c406925e498d06da66b4828f0209ea6 (diff)
downloadlinux-dd6414b50fa2b1cd247a8aa8f8bd42414b7453e1.tar.gz
linux-dd6414b50fa2b1cd247a8aa8f8bd42414b7453e1.tar.bz2
linux-dd6414b50fa2b1cd247a8aa8f8bd42414b7453e1.zip
timer: Permit statically-declared work with deferrable timers
Currently, you have to just define a delayed_work uninitialised, and then initialise it before first use. That's a tad clumsy. At risk of playing mind-games with the compiler, fooling it into doing pointer arithmetic with compile-time-constants, this lets clients properly initialise delayed work with deferrable timers statically. This patch was inspired by the issues which lead Artem Bityutskiy to commit 8eab945c5616fc984 ("sunrpc: make the cache cleaner workqueue deferrable"). Signed-off-by: Phil Carmody <ext-phil.2.carmody@nokia.com> Acked-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com> Cc: Arjan van de Ven <arjan@infradead.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'include/linux/timer.h')
-rw-r--r--include/linux/timer.h25
1 files changed, 25 insertions, 0 deletions
diff --git a/include/linux/timer.h b/include/linux/timer.h
index 1794674c1a52..cbfb7a355d30 100644
--- a/include/linux/timer.h
+++ b/include/linux/timer.h
@@ -48,6 +48,18 @@ extern struct tvec_base boot_tvec_bases;
#define __TIMER_LOCKDEP_MAP_INITIALIZER(_kn)
#endif
+/*
+ * Note that all tvec_bases are 2 byte aligned and lower bit of
+ * base in timer_list is guaranteed to be zero. Use the LSB to
+ * indicate whether the timer is deferrable.
+ *
+ * A deferrable timer will work normally when the system is busy, but
+ * will not cause a CPU to come out of idle just to service it; instead,
+ * the timer will be serviced when the CPU eventually wakes up with a
+ * subsequent non-deferrable timer.
+ */
+#define TBASE_DEFERRABLE_FLAG (0x1)
+
#define TIMER_INITIALIZER(_function, _expires, _data) { \
.entry = { .prev = TIMER_ENTRY_STATIC }, \
.function = (_function), \
@@ -59,6 +71,19 @@ extern struct tvec_base boot_tvec_bases;
__FILE__ ":" __stringify(__LINE__)) \
}
+#define TBASE_MAKE_DEFERRED(ptr) ((struct tvec_base *) \
+ ((unsigned char *)(ptr) + TBASE_DEFERRABLE_FLAG))
+
+#define TIMER_DEFERRED_INITIALIZER(_function, _expires, _data) {\
+ .entry = { .prev = TIMER_ENTRY_STATIC }, \
+ .function = (_function), \
+ .expires = (_expires), \
+ .data = (_data), \
+ .base = TBASE_MAKE_DEFERRED(&boot_tvec_bases), \
+ __TIMER_LOCKDEP_MAP_INITIALIZER( \
+ __FILE__ ":" __stringify(__LINE__)) \
+ }
+
#define DEFINE_TIMER(_name, _function, _expires, _data) \
struct timer_list _name = \
TIMER_INITIALIZER(_function, _expires, _data)