X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;ds=sidebyside;f=datapath%2Flinux%2Fcompat%2Finclude%2Flinux%2Fworkqueue.h;h=cb488638882ea41a6d60603b2f710e57d237ac3c;hb=476a0e9e7c0aae41f5b3bd093b5b5d666142f630;hp=01c6345e9370d3e57986e33dfd9781c1c218d590;hpb=22bcc0e70becd88bf895c44885d63704affe4284;p=openvswitch diff --git a/datapath/linux/compat/include/linux/workqueue.h b/datapath/linux/compat/include/linux/workqueue.h index 01c6345e..cb488638 100644 --- a/datapath/linux/compat/include/linux/workqueue.h +++ b/datapath/linux/compat/include/linux/workqueue.h @@ -1,41 +1,72 @@ #ifndef __LINUX_WORKQUEUE_WRAPPER_H #define __LINUX_WORKQUEUE_WRAPPER_H 1 -#include_next +#include -#include -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) +int __init ovs_workqueues_init(void); +void ovs_workqueues_exit(void); /* 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. + * free, etc. Therefore we implement simple ovs specific work queue using + * single worker thread. work-queue API are kept similar for compatibility. + * It seems it is useful even on newer kernel. As it can avoid system wide + * freeze in event of softlockup due to workq blocked on genl_lock. */ -#include +struct work_struct; -#undef DECLARE_DELAYED_WORK -#define DECLARE_DELAYED_WORK(n, f) \ - struct timer_list n = TIMER_INITIALIZER((void (*)(unsigned long))f, 0, 0) +typedef void (*work_func_t)(struct work_struct *work); -#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; +#define work_data_bits(work) ((unsigned long *)(&(work)->data)) + +struct work_struct { +#define WORK_STRUCT_PENDING 0 /* T if work item pending execution */ + atomic_long_t data; + struct list_head entry; + work_func_t func; +#ifdef CONFIG_LOCKDEP + struct lockdep_map lockdep_map; +#endif +}; + +#define WORK_DATA_INIT() ATOMIC_LONG_INIT(0) + +#define work_clear_pending(work) \ + clear_bit(WORK_STRUCT_PENDING, work_data_bits(work)) + +struct delayed_work { + struct work_struct work; + struct timer_list timer; +}; - mod_timer(timer, jiffies + delay); - return 1; +#define __WORK_INITIALIZER(n, f) { \ + .data = WORK_DATA_INIT(), \ + .entry = { &(n).entry, &(n).entry }, \ + .func = (f), \ } -#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); +#define __DELAYED_WORK_INITIALIZER(n, f) { \ + .work = __WORK_INITIALIZER((n).work, (f)), \ + .timer = TIMER_INITIALIZER(NULL, 0, 0), \ } -#endif /* kernel version < 2.6.23 */ +#define DECLARE_DELAYED_WORK(n, f) \ + struct delayed_work n = __DELAYED_WORK_INITIALIZER(n, f) + +#define schedule_delayed_work rpl_schedule_delayed_work +int schedule_delayed_work(struct delayed_work *dwork, unsigned long delay); + +#define cancel_delayed_work_sync rpl_cancel_delayed_work_sync +int cancel_delayed_work_sync(struct delayed_work *dwork); + +#define INIT_WORK(_work, _func) \ + do { \ + (_work)->data = (atomic_long_t) WORK_DATA_INIT(); \ + INIT_LIST_HEAD(&(_work)->entry); \ + (_work)->func = (_func); \ + } while (0) + +extern void flush_scheduled_work(void); #endif