diff options
Diffstat (limited to 'datapath/linux-2.6/compat-2.6/include/linux/workqueue.h')
-rw-r--r-- | datapath/linux-2.6/compat-2.6/include/linux/workqueue.h | 65 |
1 files changed, 32 insertions, 33 deletions
diff --git a/datapath/linux-2.6/compat-2.6/include/linux/workqueue.h b/datapath/linux-2.6/compat-2.6/include/linux/workqueue.h index 1ac3b6ecb..01c6345e9 100644 --- a/datapath/linux-2.6/compat-2.6/include/linux/workqueue.h +++ b/datapath/linux-2.6/compat-2.6/include/linux/workqueue.h @@ -4,39 +4,38 @@ #include_next <linux/workqueue.h> #include <linux/version.h> -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) - -#ifdef __KERNEL__ -/* - * initialize a work-struct's func and data pointers: - */ -#undef PREPARE_WORK -#define PREPARE_WORK(_work, _func) \ - do { \ - (_work)->func = (void(*)(void*)) _func; \ - (_work)->data = _work; \ - } while (0) - -/* - * initialize all of a work-struct: +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) + +/* Older kernels have an implementation of work queues with some very bad + * characteristics when trying to cancel work (potential deadlocks, use after + * free, etc. Here we directly use timers instead for delayed work. It's not + * optimal but it is better than the alternative. Note that work queues + * normally run in process context but this will cause them to operate in + * softirq context. */ -#undef INIT_WORK -#define INIT_WORK(_work, _func) \ - do { \ - INIT_LIST_HEAD(&(_work)->entry); \ - (_work)->pending = 0; \ - PREPARE_WORK((_work), (_func)); \ - init_timer(&(_work)->timer); \ - } while (0) - -#endif /* __KERNEL__ */ - -#endif /* linux kernel < 2.6.20 */ - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) -/* There is no equivalent to cancel_work_sync() so just flush all - * pending work. */ -#define cancel_work_sync(_work) flush_scheduled_work() -#endif + +#include <linux/timer.h> + +#undef DECLARE_DELAYED_WORK +#define DECLARE_DELAYED_WORK(n, f) \ + struct timer_list n = TIMER_INITIALIZER((void (*)(unsigned long))f, 0, 0) + +#define schedule_delayed_work rpl_schedule_delayed_work +static inline int schedule_delayed_work(struct timer_list *timer, unsigned long delay) +{ + if (timer_pending(timer)) + return 0; + + mod_timer(timer, jiffies + delay); + return 1; +} + +#define cancel_delayed_work_sync rpl_cancel_delayed_work_sync +static inline int cancel_delayed_work_sync(struct timer_list *timer) +{ + return del_timer_sync(timer); +} + +#endif /* kernel version < 2.6.23 */ #endif |