From 52bad64d95bd89e08c49ec5a071fa6dcbe5a1a9c Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 22 Nov 2006 14:54:01 +0000 Subject: WorkStruct: Separate delayable and non-delayable events. Separate delayable work items from non-delayable work items be splitting them into a separate structure (delayed_work), which incorporates a work_struct and the timer_list removed from work_struct. The work_struct struct is huge, and this limits it's usefulness. On a 64-bit architecture it's nearly 100 bytes in size. This reduces that by half for the non-delayable type of event. Signed-Off-By: David Howells --- include/linux/workqueue.h | 44 ++++++++++++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 12 deletions(-) (limited to 'include/linux/workqueue.h') diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h index 9bca3539a1e..9faaccae570 100644 --- a/include/linux/workqueue.h +++ b/include/linux/workqueue.h @@ -17,6 +17,10 @@ struct work_struct { void (*func)(void *); void *data; void *wq_data; +}; + +struct delayed_work { + struct work_struct work; struct timer_list timer; }; @@ -28,32 +32,48 @@ struct execute_work { .entry = { &(n).entry, &(n).entry }, \ .func = (f), \ .data = (d), \ + } + +#define __DELAYED_WORK_INITIALIZER(n, f, d) { \ + .work = __WORK_INITIALIZER((n).work, (f), (d)), \ .timer = TIMER_INITIALIZER(NULL, 0, 0), \ } #define DECLARE_WORK(n, f, d) \ struct work_struct n = __WORK_INITIALIZER(n, f, d) +#define DECLARE_DELAYED_WORK(n, f, d) \ + struct delayed_work n = __DELAYED_WORK_INITIALIZER(n, f, d) + /* - * initialize a work-struct's func and data pointers: + * initialize a work item's function and data pointers */ #define PREPARE_WORK(_work, _func, _data) \ do { \ - (_work)->func = _func; \ - (_work)->data = _data; \ + (_work)->func = (_func); \ + (_work)->data = (_data); \ } while (0) +#define PREPARE_DELAYED_WORK(_work, _func, _data) \ + PREPARE_WORK(&(_work)->work, (_func), (_data)) + /* - * initialize all of a work-struct: + * initialize all of a work item in one go */ #define INIT_WORK(_work, _func, _data) \ do { \ INIT_LIST_HEAD(&(_work)->entry); \ (_work)->pending = 0; \ PREPARE_WORK((_work), (_func), (_data)); \ + } while (0) + +#define INIT_DELAYED_WORK(_work, _func, _data) \ + do { \ + INIT_WORK(&(_work)->work, (_func), (_data)); \ init_timer(&(_work)->timer); \ } while (0) + extern struct workqueue_struct *__create_workqueue(const char *name, int singlethread); #define create_workqueue(name) __create_workqueue((name), 0) @@ -62,24 +82,24 @@ extern struct workqueue_struct *__create_workqueue(const char *name, extern void destroy_workqueue(struct workqueue_struct *wq); extern int FASTCALL(queue_work(struct workqueue_struct *wq, struct work_struct *work)); -extern int FASTCALL(queue_delayed_work(struct workqueue_struct *wq, struct work_struct *work, unsigned long delay)); +extern int FASTCALL(queue_delayed_work(struct workqueue_struct *wq, struct delayed_work *work, unsigned long delay)); extern int queue_delayed_work_on(int cpu, struct workqueue_struct *wq, - struct work_struct *work, unsigned long delay); + struct delayed_work *work, unsigned long delay); extern void FASTCALL(flush_workqueue(struct workqueue_struct *wq)); extern int FASTCALL(schedule_work(struct work_struct *work)); -extern int FASTCALL(schedule_delayed_work(struct work_struct *work, unsigned long delay)); +extern int FASTCALL(schedule_delayed_work(struct delayed_work *work, unsigned long delay)); -extern int schedule_delayed_work_on(int cpu, struct work_struct *work, unsigned long delay); +extern int schedule_delayed_work_on(int cpu, struct delayed_work *work, unsigned long delay); extern int schedule_on_each_cpu(void (*func)(void *info), void *info); extern void flush_scheduled_work(void); extern int current_is_keventd(void); extern int keventd_up(void); extern void init_workqueues(void); -void cancel_rearming_delayed_work(struct work_struct *work); +void cancel_rearming_delayed_work(struct delayed_work *work); void cancel_rearming_delayed_workqueue(struct workqueue_struct *, - struct work_struct *); + struct delayed_work *); int execute_in_process_context(void (*fn)(void *), void *, struct execute_work *); @@ -88,13 +108,13 @@ int execute_in_process_context(void (*fn)(void *), void *, * function may still be running on return from cancel_delayed_work(). Run * flush_scheduled_work() to wait on it. */ -static inline int cancel_delayed_work(struct work_struct *work) +static inline int cancel_delayed_work(struct delayed_work *work) { int ret; ret = del_timer_sync(&work->timer); if (ret) - clear_bit(0, &work->pending); + clear_bit(0, &work->work.pending); return ret; } -- cgit v1.2.3 From 6bb49e5965c1fc399b4d3cd2b5cf2da535b330c0 Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 22 Nov 2006 14:54:45 +0000 Subject: WorkStruct: Typedef the work function prototype Define a type for the work function prototype. It's not only kept in the work_struct struct, it's also passed as an argument to several functions. This makes it easier to change it. Signed-Off-By: David Howells --- include/linux/workqueue.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'include/linux/workqueue.h') diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h index 9faaccae570..cef40b22ff9 100644 --- a/include/linux/workqueue.h +++ b/include/linux/workqueue.h @@ -11,10 +11,12 @@ struct workqueue_struct; +typedef void (*work_func_t)(void *data); + struct work_struct { unsigned long pending; struct list_head entry; - void (*func)(void *); + work_func_t func; void *data; void *wq_data; }; @@ -91,7 +93,7 @@ extern int FASTCALL(schedule_work(struct work_struct *work)); extern int FASTCALL(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_on_each_cpu(void (*func)(void *info), void *info); +extern int schedule_on_each_cpu(work_func_t func, void *info); extern void flush_scheduled_work(void); extern int current_is_keventd(void); extern int keventd_up(void); @@ -100,8 +102,7 @@ extern void init_workqueues(void); void cancel_rearming_delayed_work(struct delayed_work *work); void cancel_rearming_delayed_workqueue(struct workqueue_struct *, struct delayed_work *); -int execute_in_process_context(void (*fn)(void *), void *, - struct execute_work *); +int execute_in_process_context(work_func_t fn, void *, struct execute_work *); /* * Kill off a pending schedule_delayed_work(). Note that the work callback -- cgit v1.2.3 From 365970a1ea76d81cb1ad2f652acb605f06dae256 Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 22 Nov 2006 14:54:49 +0000 Subject: WorkStruct: Merge the pending bit into the wq_data pointer Reclaim a word from the size of the work_struct by folding the pending bit and the wq_data pointer together. This shouldn't cause misalignment problems as all pointers should be at least 4-byte aligned. Signed-Off-By: David Howells --- include/linux/workqueue.h | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) (limited to 'include/linux/workqueue.h') diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h index cef40b22ff9..ecc017d24cf 100644 --- a/include/linux/workqueue.h +++ b/include/linux/workqueue.h @@ -14,11 +14,15 @@ struct workqueue_struct; typedef void (*work_func_t)(void *data); struct work_struct { - unsigned long pending; + /* the first word is the work queue pointer and the pending flag + * rolled into one */ + unsigned long management; +#define WORK_STRUCT_PENDING 0 /* T if work item pending execution */ +#define WORK_STRUCT_FLAG_MASK (3UL) +#define WORK_STRUCT_WQ_DATA_MASK (~WORK_STRUCT_FLAG_MASK) struct list_head entry; work_func_t func; void *data; - void *wq_data; }; struct delayed_work { @@ -65,7 +69,7 @@ struct execute_work { #define INIT_WORK(_work, _func, _data) \ do { \ INIT_LIST_HEAD(&(_work)->entry); \ - (_work)->pending = 0; \ + (_work)->management = 0; \ PREPARE_WORK((_work), (_func), (_data)); \ } while (0) @@ -75,6 +79,21 @@ struct execute_work { init_timer(&(_work)->timer); \ } while (0) +/** + * work_pending - Find out whether a work item is currently pending + * @work: The work item in question + */ +#define work_pending(work) \ + test_bit(WORK_STRUCT_PENDING, &(work)->management) + +/** + * delayed_work_pending - Find out whether a delayable work item is currently + * pending + * @work: The work item in question + */ +#define delayed_work_pending(work) \ + test_bit(WORK_STRUCT_PENDING, &(work)->work.management) + extern struct workqueue_struct *__create_workqueue(const char *name, int singlethread); @@ -115,7 +134,7 @@ static inline int cancel_delayed_work(struct delayed_work *work) ret = del_timer_sync(&work->timer); if (ret) - clear_bit(0, &work->work.pending); + clear_bit(WORK_STRUCT_PENDING, &work->work.management); return ret; } -- cgit v1.2.3 From 65f27f38446e1976cc98fd3004b110fedcddd189 Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 22 Nov 2006 14:55:48 +0000 Subject: WorkStruct: Pass the work_struct pointer instead of context data Pass the work_struct pointer to the work function rather than context data. The work function can use container_of() to work out the data. For the cases where the container of the work_struct may go away the moment the pending bit is cleared, it is made possible to defer the release of the structure by deferring the clearing of the pending bit. To make this work, an extra flag is introduced into the management side of the work_struct. This governs auto-release of the structure upon execution. Ordinarily, the work queue executor would release the work_struct for further scheduling or deallocation by clearing the pending bit prior to jumping to the work function. This means that, unless the driver makes some guarantee itself that the work_struct won't go away, the work function may not access anything else in the work_struct or its container lest they be deallocated.. This is a problem if the auxiliary data is taken away (as done by the last patch). However, if the pending bit is *not* cleared before jumping to the work function, then the work function *may* access the work_struct and its container with no problems. But then the work function must itself release the work_struct by calling work_release(). In most cases, automatic release is fine, so this is the default. Special initiators exist for the non-auto-release case (ending in _NAR). Signed-Off-By: David Howells --- include/linux/workqueue.h | 99 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 75 insertions(+), 24 deletions(-) (limited to 'include/linux/workqueue.h') diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h index ecc017d24cf..4a3ea83c6d1 100644 --- a/include/linux/workqueue.h +++ b/include/linux/workqueue.h @@ -11,18 +11,19 @@ struct workqueue_struct; -typedef void (*work_func_t)(void *data); +struct work_struct; +typedef void (*work_func_t)(struct work_struct *work); struct work_struct { - /* the first word is the work queue pointer and the pending flag - * rolled into one */ + /* the first word is the work queue pointer and the flags rolled into + * one */ unsigned long management; #define WORK_STRUCT_PENDING 0 /* T if work item pending execution */ +#define WORK_STRUCT_NOAUTOREL 1 /* F if work item automatically released on exec */ #define WORK_STRUCT_FLAG_MASK (3UL) #define WORK_STRUCT_WQ_DATA_MASK (~WORK_STRUCT_FLAG_MASK) struct list_head entry; work_func_t func; - void *data; }; struct delayed_work { @@ -34,48 +35,77 @@ struct execute_work { struct work_struct work; }; -#define __WORK_INITIALIZER(n, f, d) { \ +#define __WORK_INITIALIZER(n, f) { \ + .management = 0, \ .entry = { &(n).entry, &(n).entry }, \ .func = (f), \ - .data = (d), \ } -#define __DELAYED_WORK_INITIALIZER(n, f, d) { \ - .work = __WORK_INITIALIZER((n).work, (f), (d)), \ +#define __WORK_INITIALIZER_NAR(n, f) { \ + .management = (1 << WORK_STRUCT_NOAUTOREL), \ + .entry = { &(n).entry, &(n).entry }, \ + .func = (f), \ + } + +#define __DELAYED_WORK_INITIALIZER(n, f) { \ + .work = __WORK_INITIALIZER((n).work, (f)), \ + .timer = TIMER_INITIALIZER(NULL, 0, 0), \ + } + +#define __DELAYED_WORK_INITIALIZER_NAR(n, f) { \ + .work = __WORK_INITIALIZER_NAR((n).work, (f)), \ .timer = TIMER_INITIALIZER(NULL, 0, 0), \ } -#define DECLARE_WORK(n, f, d) \ - struct work_struct n = __WORK_INITIALIZER(n, f, d) +#define DECLARE_WORK(n, f) \ + struct work_struct n = __WORK_INITIALIZER(n, f) + +#define DECLARE_WORK_NAR(n, f) \ + struct work_struct n = __WORK_INITIALIZER_NAR(n, f) -#define DECLARE_DELAYED_WORK(n, f, d) \ - struct delayed_work n = __DELAYED_WORK_INITIALIZER(n, f, d) +#define DECLARE_DELAYED_WORK(n, f) \ + struct delayed_work n = __DELAYED_WORK_INITIALIZER(n, f) + +#define DECLARE_DELAYED_WORK_NAR(n, f) \ + struct dwork_struct n = __DELAYED_WORK_INITIALIZER_NAR(n, f) /* - * initialize a work item's function and data pointers + * initialize a work item's function pointer */ -#define PREPARE_WORK(_work, _func, _data) \ +#define PREPARE_WORK(_work, _func) \ do { \ (_work)->func = (_func); \ - (_work)->data = (_data); \ } while (0) -#define PREPARE_DELAYED_WORK(_work, _func, _data) \ - PREPARE_WORK(&(_work)->work, (_func), (_data)) +#define PREPARE_DELAYED_WORK(_work, _func) \ + PREPARE_WORK(&(_work)->work, (_func)) /* * initialize all of a work item in one go */ -#define INIT_WORK(_work, _func, _data) \ +#define INIT_WORK(_work, _func) \ do { \ - INIT_LIST_HEAD(&(_work)->entry); \ (_work)->management = 0; \ - PREPARE_WORK((_work), (_func), (_data)); \ + INIT_LIST_HEAD(&(_work)->entry); \ + PREPARE_WORK((_work), (_func)); \ + } while (0) + +#define INIT_WORK_NAR(_work, _func) \ + do { \ + (_work)->management = (1 << WORK_STRUCT_NOAUTOREL); \ + INIT_LIST_HEAD(&(_work)->entry); \ + PREPARE_WORK((_work), (_func)); \ + } while (0) + +#define INIT_DELAYED_WORK(_work, _func) \ + do { \ + INIT_WORK(&(_work)->work, (_func)); \ + init_timer(&(_work)->timer); \ } while (0) -#define INIT_DELAYED_WORK(_work, _func, _data) \ +#define INIT_DELAYED_WORK_NAR(_work, _func) \ do { \ - INIT_WORK(&(_work)->work, (_func), (_data)); \ + INIT_WORK_NAR(&(_work)->work, (_func)); \ init_timer(&(_work)->timer); \ } while (0) @@ -94,6 +124,27 @@ struct execute_work { #define delayed_work_pending(work) \ test_bit(WORK_STRUCT_PENDING, &(work)->work.management) +/** + * work_release - Release a work item under execution + * @work: The work item to release + * + * This is used to release a work item that has been initialised with automatic + * release mode disabled (WORK_STRUCT_NOAUTOREL is set). This gives the work + * function the opportunity to grab auxiliary data from the container of the + * work_struct before clearing the pending bit as the work_struct may be + * subject to deallocation the moment the pending bit is cleared. + * + * In such a case, this should be called in the work function after it has + * fetched any data it may require from the containter of the work_struct. + * After this function has been called, the work_struct may be scheduled for + * further execution or it may be deallocated unless other precautions are + * taken. + * + * This should also be used to release a delayed work item. + */ +#define work_release(work) \ + clear_bit(WORK_STRUCT_PENDING, &(work)->management) + extern struct workqueue_struct *__create_workqueue(const char *name, int singlethread); @@ -112,7 +163,7 @@ extern int FASTCALL(schedule_work(struct work_struct *work)); extern int FASTCALL(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_on_each_cpu(work_func_t func, void *info); +extern int schedule_on_each_cpu(work_func_t func); extern void flush_scheduled_work(void); extern int current_is_keventd(void); extern int keventd_up(void); @@ -121,7 +172,7 @@ extern void init_workqueues(void); void cancel_rearming_delayed_work(struct delayed_work *work); void cancel_rearming_delayed_workqueue(struct workqueue_struct *, struct delayed_work *); -int execute_in_process_context(work_func_t fn, void *, struct execute_work *); +int execute_in_process_context(work_func_t fn, struct execute_work *); /* * Kill off a pending schedule_delayed_work(). Note that the work callback -- cgit v1.2.3 From 341a595850dac1b0503df34260257d71b4fdf72c Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 6 Dec 2006 20:34:49 -0800 Subject: [PATCH] Support for freezeable workqueues Make it possible to create a workqueue the worker thread of which will be frozen during suspend, along with other kernel threads. Signed-off-by: Rafael J. Wysocki Acked-by: Pavel Machek Cc: Nigel Cunningham Cc: David Chinner Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/workqueue.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'include/linux/workqueue.h') diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h index 4a3ea83c6d1..f0cb1df7b47 100644 --- a/include/linux/workqueue.h +++ b/include/linux/workqueue.h @@ -147,9 +147,11 @@ struct execute_work { extern struct workqueue_struct *__create_workqueue(const char *name, - int singlethread); -#define create_workqueue(name) __create_workqueue((name), 0) -#define create_singlethread_workqueue(name) __create_workqueue((name), 1) + int singlethread, + int freezeable); +#define create_workqueue(name) __create_workqueue((name), 0, 0) +#define create_freezeable_workqueue(name) __create_workqueue((name), 0, 1) +#define create_singlethread_workqueue(name) __create_workqueue((name), 1, 0) extern void destroy_workqueue(struct workqueue_struct *wq); -- cgit v1.2.3 From 68380b581383c028830f79ec2670f4a193854aa6 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 7 Dec 2006 09:28:19 -0800 Subject: Add "run_scheduled_work()" workqueue function This allows workqueue users to run just their own pending work, rather than wait for the whole workqueue to finish running. This solves the deadlock with networking libphy that was due to other workqueue entries possibly needing a lock that was held by the routine that wanted to flush its own work. It's not wonderful: if you absolutely need to synchronize with the work function having been executed, any user strictly speaking should have its own completion tracking logic, since when we run things explicitly by hand, the generic workqueue layer can no longer help us synchronize. Also, this is strictly only usable for work that has been scheduled without any delayed timers. You can not mix the new interface with schedule_delayed_work(). But it's better than what we had currently. Acked-by: Maciej W. Rozycki Signed-off-by: Linus Torvalds --- include/linux/workqueue.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/linux/workqueue.h') diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h index f0cb1df7b47..edef8d50b26 100644 --- a/include/linux/workqueue.h +++ b/include/linux/workqueue.h @@ -162,6 +162,7 @@ extern int queue_delayed_work_on(int cpu, struct workqueue_struct *wq, extern void FASTCALL(flush_workqueue(struct workqueue_struct *wq)); extern int FASTCALL(schedule_work(struct work_struct *work)); +extern int FASTCALL(run_scheduled_work(struct work_struct *work)); extern int FASTCALL(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); -- cgit v1.2.3 From 0221872a3b0aa2fa2f3fa60affcbaebd662c4a90 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 15 Dec 2006 14:13:51 -0800 Subject: Fix "delayed_work_pending()" macro expansion Nobody uses it, but it was still wrong. Using the macro argument name 'work' meant that when we used 'work' as a member name, that would also get replaced by the macro argument. Signed-off-by: Linus Torvalds --- include/linux/workqueue.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include/linux/workqueue.h') diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h index edef8d50b26..5b13dcf0271 100644 --- a/include/linux/workqueue.h +++ b/include/linux/workqueue.h @@ -121,8 +121,8 @@ struct execute_work { * pending * @work: The work item in question */ -#define delayed_work_pending(work) \ - test_bit(WORK_STRUCT_PENDING, &(work)->work.management) +#define delayed_work_pending(w) \ + work_pending(&(w)->work) /** * work_release - Release a work item under execution -- cgit v1.2.3 From a08727bae727fc2ca3a6ee9506d77786b71070b3 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sat, 16 Dec 2006 09:53:50 -0800 Subject: Make workqueue bit operations work on "atomic_long_t" On architectures where the atomicity of the bit operations is handled by external means (ie a separate spinlock to protect concurrent accesses), just doing a direct assignment on the workqueue data field (as done by commit 4594bf159f1962cec3b727954b7c598b07e2e737) can cause the assignment to be lost due to lack of serialization with the bitops on the same word. So we need to serialize the assignment with the locks on those architectures (notably older ARM chips, PA-RISC and sparc32). So rather than using an "unsigned long", let's use "atomic_long_t", which already has a safe assignment operation (atomic_long_set()) on such architectures. This requires that the atomic operations use the same atomicity locks as the bit operations do, but that is largely the case anyway. Sparc32 will probably need fixing. Architectures (including modern ARM with LL/SC) that implement sane atomic operations for SMP won't see any of this matter. Cc: Russell King Cc: David Howells Cc: David Miller Cc: Matthew Wilcox Cc: Linux Arch Maintainers Cc: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/workqueue.h | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) (limited to 'include/linux/workqueue.h') diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h index 5b13dcf0271..2a7b38d8701 100644 --- a/include/linux/workqueue.h +++ b/include/linux/workqueue.h @@ -8,16 +8,21 @@ #include #include #include +#include struct workqueue_struct; struct work_struct; typedef void (*work_func_t)(struct work_struct *work); +/* + * The first word is the work queue pointer and the flags rolled into + * one + */ +#define work_data_bits(work) ((unsigned long *)(&(work)->data)) + struct work_struct { - /* the first word is the work queue pointer and the flags rolled into - * one */ - unsigned long management; + atomic_long_t data; #define WORK_STRUCT_PENDING 0 /* T if work item pending execution */ #define WORK_STRUCT_NOAUTOREL 1 /* F if work item automatically released on exec */ #define WORK_STRUCT_FLAG_MASK (3UL) @@ -26,6 +31,9 @@ struct work_struct { work_func_t func; }; +#define WORK_DATA_INIT(autorelease) \ + ATOMIC_LONG_INIT((autorelease) << WORK_STRUCT_NOAUTOREL) + struct delayed_work { struct work_struct work; struct timer_list timer; @@ -36,13 +44,13 @@ struct execute_work { }; #define __WORK_INITIALIZER(n, f) { \ - .management = 0, \ + .data = WORK_DATA_INIT(0), \ .entry = { &(n).entry, &(n).entry }, \ .func = (f), \ } #define __WORK_INITIALIZER_NAR(n, f) { \ - .management = (1 << WORK_STRUCT_NOAUTOREL), \ + .data = WORK_DATA_INIT(1), \ .entry = { &(n).entry, &(n).entry }, \ .func = (f), \ } @@ -82,17 +90,21 @@ struct execute_work { /* * initialize all of a work item in one go + * + * NOTE! No point in using "atomic_long_set()": useing a direct + * assignment of the work data initializer allows the compiler + * to generate better code. */ #define INIT_WORK(_work, _func) \ do { \ - (_work)->management = 0; \ + (_work)->data = (atomic_long_t) WORK_DATA_INIT(0); \ INIT_LIST_HEAD(&(_work)->entry); \ PREPARE_WORK((_work), (_func)); \ } while (0) #define INIT_WORK_NAR(_work, _func) \ do { \ - (_work)->management = (1 << WORK_STRUCT_NOAUTOREL); \ + (_work)->data = (atomic_long_t) WORK_DATA_INIT(1); \ INIT_LIST_HEAD(&(_work)->entry); \ PREPARE_WORK((_work), (_func)); \ } while (0) @@ -114,7 +126,7 @@ struct execute_work { * @work: The work item in question */ #define work_pending(work) \ - test_bit(WORK_STRUCT_PENDING, &(work)->management) + test_bit(WORK_STRUCT_PENDING, work_data_bits(work)) /** * delayed_work_pending - Find out whether a delayable work item is currently @@ -143,7 +155,7 @@ struct execute_work { * This should also be used to release a delayed work item. */ #define work_release(work) \ - clear_bit(WORK_STRUCT_PENDING, &(work)->management) + clear_bit(WORK_STRUCT_PENDING, work_data_bits(work)) extern struct workqueue_struct *__create_workqueue(const char *name, @@ -188,7 +200,7 @@ static inline int cancel_delayed_work(struct delayed_work *work) ret = del_timer_sync(&work->timer); if (ret) - clear_bit(WORK_STRUCT_PENDING, &work->work.management); + work_release(&work->work); return ret; } -- cgit v1.2.3