mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-06-20 21:51:05 +00:00
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 8eab945c56
("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>
This commit is contained in:
parent
2bf1c05e3c
commit
dd6414b50f
3 changed files with 34 additions and 14 deletions
|
@ -48,6 +48,18 @@ extern struct tvec_base boot_tvec_bases;
|
||||||
#define __TIMER_LOCKDEP_MAP_INITIALIZER(_kn)
|
#define __TIMER_LOCKDEP_MAP_INITIALIZER(_kn)
|
||||||
#endif
|
#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) { \
|
#define TIMER_INITIALIZER(_function, _expires, _data) { \
|
||||||
.entry = { .prev = TIMER_ENTRY_STATIC }, \
|
.entry = { .prev = TIMER_ENTRY_STATIC }, \
|
||||||
.function = (_function), \
|
.function = (_function), \
|
||||||
|
@ -59,6 +71,19 @@ extern struct tvec_base boot_tvec_bases;
|
||||||
__FILE__ ":" __stringify(__LINE__)) \
|
__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) \
|
#define DEFINE_TIMER(_name, _function, _expires, _data) \
|
||||||
struct timer_list _name = \
|
struct timer_list _name = \
|
||||||
TIMER_INITIALIZER(_function, _expires, _data)
|
TIMER_INITIALIZER(_function, _expires, _data)
|
||||||
|
|
|
@ -127,12 +127,20 @@ struct execute_work {
|
||||||
.timer = TIMER_INITIALIZER(NULL, 0, 0), \
|
.timer = TIMER_INITIALIZER(NULL, 0, 0), \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define __DEFERRED_WORK_INITIALIZER(n, f) { \
|
||||||
|
.work = __WORK_INITIALIZER((n).work, (f)), \
|
||||||
|
.timer = TIMER_DEFERRED_INITIALIZER(NULL, 0, 0), \
|
||||||
|
}
|
||||||
|
|
||||||
#define DECLARE_WORK(n, f) \
|
#define DECLARE_WORK(n, f) \
|
||||||
struct work_struct n = __WORK_INITIALIZER(n, f)
|
struct work_struct n = __WORK_INITIALIZER(n, f)
|
||||||
|
|
||||||
#define DECLARE_DELAYED_WORK(n, f) \
|
#define DECLARE_DELAYED_WORK(n, f) \
|
||||||
struct delayed_work n = __DELAYED_WORK_INITIALIZER(n, f)
|
struct delayed_work n = __DELAYED_WORK_INITIALIZER(n, f)
|
||||||
|
|
||||||
|
#define DECLARE_DEFERRED_WORK(n, f) \
|
||||||
|
struct delayed_work n = __DEFERRED_WORK_INITIALIZER(n, f)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* initialize a work item's function pointer
|
* initialize a work item's function pointer
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -88,18 +88,6 @@ struct tvec_base boot_tvec_bases;
|
||||||
EXPORT_SYMBOL(boot_tvec_bases);
|
EXPORT_SYMBOL(boot_tvec_bases);
|
||||||
static DEFINE_PER_CPU(struct tvec_base *, tvec_bases) = &boot_tvec_bases;
|
static DEFINE_PER_CPU(struct tvec_base *, tvec_bases) = &boot_tvec_bases;
|
||||||
|
|
||||||
/*
|
|
||||||
* 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)
|
|
||||||
|
|
||||||
/* Functions below help us manage 'deferrable' flag */
|
/* Functions below help us manage 'deferrable' flag */
|
||||||
static inline unsigned int tbase_get_deferrable(struct tvec_base *base)
|
static inline unsigned int tbase_get_deferrable(struct tvec_base *base)
|
||||||
{
|
{
|
||||||
|
@ -113,8 +101,7 @@ static inline struct tvec_base *tbase_get_base(struct tvec_base *base)
|
||||||
|
|
||||||
static inline void timer_set_deferrable(struct timer_list *timer)
|
static inline void timer_set_deferrable(struct timer_list *timer)
|
||||||
{
|
{
|
||||||
timer->base = ((struct tvec_base *)((unsigned long)(timer->base) |
|
timer->base = TBASE_MAKE_DEFERRED(timer->base);
|
||||||
TBASE_DEFERRABLE_FLAG));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue