Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* |
| 2 | * workqueue.h --- work queue handling for Linux. |
| 3 | */ |
| 4 | |
| 5 | #ifndef _LINUX_WORKQUEUE_H |
| 6 | #define _LINUX_WORKQUEUE_H |
| 7 | |
| 8 | #include <linux/timer.h> |
| 9 | #include <linux/linkage.h> |
| 10 | #include <linux/bitops.h> |
Linus Torvalds | a08727b | 2006-12-16 09:53:50 -0800 | [diff] [blame] | 11 | #include <asm/atomic.h> |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 12 | |
| 13 | struct workqueue_struct; |
| 14 | |
David Howells | 65f27f3 | 2006-11-22 14:55:48 +0000 | [diff] [blame] | 15 | struct work_struct; |
| 16 | typedef void (*work_func_t)(struct work_struct *work); |
David Howells | 6bb49e5 | 2006-11-22 14:54:45 +0000 | [diff] [blame] | 17 | |
Linus Torvalds | a08727b | 2006-12-16 09:53:50 -0800 | [diff] [blame] | 18 | /* |
| 19 | * The first word is the work queue pointer and the flags rolled into |
| 20 | * one |
| 21 | */ |
| 22 | #define work_data_bits(work) ((unsigned long *)(&(work)->data)) |
| 23 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 24 | struct work_struct { |
Linus Torvalds | a08727b | 2006-12-16 09:53:50 -0800 | [diff] [blame] | 25 | atomic_long_t data; |
David Howells | 365970a | 2006-11-22 14:54:49 +0000 | [diff] [blame] | 26 | #define WORK_STRUCT_PENDING 0 /* T if work item pending execution */ |
David Howells | 65f27f3 | 2006-11-22 14:55:48 +0000 | [diff] [blame] | 27 | #define WORK_STRUCT_NOAUTOREL 1 /* F if work item automatically released on exec */ |
David Howells | 365970a | 2006-11-22 14:54:49 +0000 | [diff] [blame] | 28 | #define WORK_STRUCT_FLAG_MASK (3UL) |
| 29 | #define WORK_STRUCT_WQ_DATA_MASK (~WORK_STRUCT_FLAG_MASK) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 30 | struct list_head entry; |
David Howells | 6bb49e5 | 2006-11-22 14:54:45 +0000 | [diff] [blame] | 31 | work_func_t func; |
David Howells | 52bad64 | 2006-11-22 14:54:01 +0000 | [diff] [blame] | 32 | }; |
| 33 | |
Linus Torvalds | a08727b | 2006-12-16 09:53:50 -0800 | [diff] [blame] | 34 | #define WORK_DATA_INIT(autorelease) \ |
| 35 | ATOMIC_LONG_INIT((autorelease) << WORK_STRUCT_NOAUTOREL) |
| 36 | |
David Howells | 52bad64 | 2006-11-22 14:54:01 +0000 | [diff] [blame] | 37 | struct delayed_work { |
| 38 | struct work_struct work; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 39 | struct timer_list timer; |
| 40 | }; |
| 41 | |
James Bottomley | 1fa44ec | 2006-02-23 12:43:43 -0600 | [diff] [blame] | 42 | struct execute_work { |
| 43 | struct work_struct work; |
| 44 | }; |
| 45 | |
David Howells | 65f27f3 | 2006-11-22 14:55:48 +0000 | [diff] [blame] | 46 | #define __WORK_INITIALIZER(n, f) { \ |
Linus Torvalds | a08727b | 2006-12-16 09:53:50 -0800 | [diff] [blame] | 47 | .data = WORK_DATA_INIT(0), \ |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 48 | .entry = { &(n).entry, &(n).entry }, \ |
| 49 | .func = (f), \ |
David Howells | 52bad64 | 2006-11-22 14:54:01 +0000 | [diff] [blame] | 50 | } |
| 51 | |
David Howells | 65f27f3 | 2006-11-22 14:55:48 +0000 | [diff] [blame] | 52 | #define __WORK_INITIALIZER_NAR(n, f) { \ |
Linus Torvalds | a08727b | 2006-12-16 09:53:50 -0800 | [diff] [blame] | 53 | .data = WORK_DATA_INIT(1), \ |
David Howells | 65f27f3 | 2006-11-22 14:55:48 +0000 | [diff] [blame] | 54 | .entry = { &(n).entry, &(n).entry }, \ |
| 55 | .func = (f), \ |
| 56 | } |
| 57 | |
| 58 | #define __DELAYED_WORK_INITIALIZER(n, f) { \ |
| 59 | .work = __WORK_INITIALIZER((n).work, (f)), \ |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 60 | .timer = TIMER_INITIALIZER(NULL, 0, 0), \ |
| 61 | } |
| 62 | |
David Howells | 65f27f3 | 2006-11-22 14:55:48 +0000 | [diff] [blame] | 63 | #define __DELAYED_WORK_INITIALIZER_NAR(n, f) { \ |
| 64 | .work = __WORK_INITIALIZER_NAR((n).work, (f)), \ |
| 65 | .timer = TIMER_INITIALIZER(NULL, 0, 0), \ |
| 66 | } |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 67 | |
David Howells | 65f27f3 | 2006-11-22 14:55:48 +0000 | [diff] [blame] | 68 | #define DECLARE_WORK(n, f) \ |
| 69 | struct work_struct n = __WORK_INITIALIZER(n, f) |
| 70 | |
| 71 | #define DECLARE_WORK_NAR(n, f) \ |
| 72 | struct work_struct n = __WORK_INITIALIZER_NAR(n, f) |
| 73 | |
| 74 | #define DECLARE_DELAYED_WORK(n, f) \ |
| 75 | struct delayed_work n = __DELAYED_WORK_INITIALIZER(n, f) |
| 76 | |
| 77 | #define DECLARE_DELAYED_WORK_NAR(n, f) \ |
| 78 | struct dwork_struct n = __DELAYED_WORK_INITIALIZER_NAR(n, f) |
David Howells | 52bad64 | 2006-11-22 14:54:01 +0000 | [diff] [blame] | 79 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 80 | /* |
David Howells | 65f27f3 | 2006-11-22 14:55:48 +0000 | [diff] [blame] | 81 | * initialize a work item's function pointer |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 82 | */ |
David Howells | 65f27f3 | 2006-11-22 14:55:48 +0000 | [diff] [blame] | 83 | #define PREPARE_WORK(_work, _func) \ |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 84 | do { \ |
David Howells | 52bad64 | 2006-11-22 14:54:01 +0000 | [diff] [blame] | 85 | (_work)->func = (_func); \ |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 86 | } while (0) |
| 87 | |
David Howells | 65f27f3 | 2006-11-22 14:55:48 +0000 | [diff] [blame] | 88 | #define PREPARE_DELAYED_WORK(_work, _func) \ |
| 89 | PREPARE_WORK(&(_work)->work, (_func)) |
David Howells | 52bad64 | 2006-11-22 14:54:01 +0000 | [diff] [blame] | 90 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 91 | /* |
David Howells | 52bad64 | 2006-11-22 14:54:01 +0000 | [diff] [blame] | 92 | * initialize all of a work item in one go |
Linus Torvalds | a08727b | 2006-12-16 09:53:50 -0800 | [diff] [blame] | 93 | * |
| 94 | * NOTE! No point in using "atomic_long_set()": useing a direct |
| 95 | * assignment of the work data initializer allows the compiler |
| 96 | * to generate better code. |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 97 | */ |
David Howells | 65f27f3 | 2006-11-22 14:55:48 +0000 | [diff] [blame] | 98 | #define INIT_WORK(_work, _func) \ |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 99 | do { \ |
Linus Torvalds | a08727b | 2006-12-16 09:53:50 -0800 | [diff] [blame] | 100 | (_work)->data = (atomic_long_t) WORK_DATA_INIT(0); \ |
David Howells | 65f27f3 | 2006-11-22 14:55:48 +0000 | [diff] [blame] | 101 | INIT_LIST_HEAD(&(_work)->entry); \ |
| 102 | PREPARE_WORK((_work), (_func)); \ |
David Howells | 52bad64 | 2006-11-22 14:54:01 +0000 | [diff] [blame] | 103 | } while (0) |
| 104 | |
David Howells | 65f27f3 | 2006-11-22 14:55:48 +0000 | [diff] [blame] | 105 | #define INIT_WORK_NAR(_work, _func) \ |
| 106 | do { \ |
Linus Torvalds | a08727b | 2006-12-16 09:53:50 -0800 | [diff] [blame] | 107 | (_work)->data = (atomic_long_t) WORK_DATA_INIT(1); \ |
David Howells | 65f27f3 | 2006-11-22 14:55:48 +0000 | [diff] [blame] | 108 | INIT_LIST_HEAD(&(_work)->entry); \ |
| 109 | PREPARE_WORK((_work), (_func)); \ |
| 110 | } while (0) |
| 111 | |
| 112 | #define INIT_DELAYED_WORK(_work, _func) \ |
David Howells | 52bad64 | 2006-11-22 14:54:01 +0000 | [diff] [blame] | 113 | do { \ |
David Howells | 65f27f3 | 2006-11-22 14:55:48 +0000 | [diff] [blame] | 114 | INIT_WORK(&(_work)->work, (_func)); \ |
| 115 | init_timer(&(_work)->timer); \ |
| 116 | } while (0) |
| 117 | |
| 118 | #define INIT_DELAYED_WORK_NAR(_work, _func) \ |
| 119 | do { \ |
| 120 | INIT_WORK_NAR(&(_work)->work, (_func)); \ |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 121 | init_timer(&(_work)->timer); \ |
| 122 | } while (0) |
| 123 | |
David Howells | 365970a | 2006-11-22 14:54:49 +0000 | [diff] [blame] | 124 | /** |
| 125 | * work_pending - Find out whether a work item is currently pending |
| 126 | * @work: The work item in question |
| 127 | */ |
| 128 | #define work_pending(work) \ |
Linus Torvalds | a08727b | 2006-12-16 09:53:50 -0800 | [diff] [blame] | 129 | test_bit(WORK_STRUCT_PENDING, work_data_bits(work)) |
David Howells | 365970a | 2006-11-22 14:54:49 +0000 | [diff] [blame] | 130 | |
| 131 | /** |
| 132 | * delayed_work_pending - Find out whether a delayable work item is currently |
| 133 | * pending |
| 134 | * @work: The work item in question |
| 135 | */ |
Linus Torvalds | 0221872 | 2006-12-15 14:13:51 -0800 | [diff] [blame] | 136 | #define delayed_work_pending(w) \ |
| 137 | work_pending(&(w)->work) |
David Howells | 365970a | 2006-11-22 14:54:49 +0000 | [diff] [blame] | 138 | |
David Howells | 65f27f3 | 2006-11-22 14:55:48 +0000 | [diff] [blame] | 139 | /** |
| 140 | * work_release - Release a work item under execution |
| 141 | * @work: The work item to release |
| 142 | * |
| 143 | * This is used to release a work item that has been initialised with automatic |
| 144 | * release mode disabled (WORK_STRUCT_NOAUTOREL is set). This gives the work |
| 145 | * function the opportunity to grab auxiliary data from the container of the |
| 146 | * work_struct before clearing the pending bit as the work_struct may be |
| 147 | * subject to deallocation the moment the pending bit is cleared. |
| 148 | * |
| 149 | * In such a case, this should be called in the work function after it has |
| 150 | * fetched any data it may require from the containter of the work_struct. |
| 151 | * After this function has been called, the work_struct may be scheduled for |
| 152 | * further execution or it may be deallocated unless other precautions are |
| 153 | * taken. |
| 154 | * |
| 155 | * This should also be used to release a delayed work item. |
| 156 | */ |
| 157 | #define work_release(work) \ |
Linus Torvalds | a08727b | 2006-12-16 09:53:50 -0800 | [diff] [blame] | 158 | clear_bit(WORK_STRUCT_PENDING, work_data_bits(work)) |
David Howells | 65f27f3 | 2006-11-22 14:55:48 +0000 | [diff] [blame] | 159 | |
David Howells | 52bad64 | 2006-11-22 14:54:01 +0000 | [diff] [blame] | 160 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 161 | extern struct workqueue_struct *__create_workqueue(const char *name, |
Rafael J. Wysocki | 341a595 | 2006-12-06 20:34:49 -0800 | [diff] [blame] | 162 | int singlethread, |
| 163 | int freezeable); |
| 164 | #define create_workqueue(name) __create_workqueue((name), 0, 0) |
| 165 | #define create_freezeable_workqueue(name) __create_workqueue((name), 0, 1) |
| 166 | #define create_singlethread_workqueue(name) __create_workqueue((name), 1, 0) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 167 | |
| 168 | extern void destroy_workqueue(struct workqueue_struct *wq); |
| 169 | |
| 170 | extern int FASTCALL(queue_work(struct workqueue_struct *wq, struct work_struct *work)); |
David Howells | 52bad64 | 2006-11-22 14:54:01 +0000 | [diff] [blame] | 171 | extern int FASTCALL(queue_delayed_work(struct workqueue_struct *wq, struct delayed_work *work, unsigned long delay)); |
Venkatesh Pallipadi | 7a6bc1c | 2006-06-28 13:50:33 -0700 | [diff] [blame] | 172 | extern int queue_delayed_work_on(int cpu, struct workqueue_struct *wq, |
David Howells | 52bad64 | 2006-11-22 14:54:01 +0000 | [diff] [blame] | 173 | struct delayed_work *work, unsigned long delay); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 174 | extern void FASTCALL(flush_workqueue(struct workqueue_struct *wq)); |
| 175 | |
| 176 | extern int FASTCALL(schedule_work(struct work_struct *work)); |
Linus Torvalds | 68380b5 | 2006-12-07 09:28:19 -0800 | [diff] [blame] | 177 | extern int FASTCALL(run_scheduled_work(struct work_struct *work)); |
David Howells | 52bad64 | 2006-11-22 14:54:01 +0000 | [diff] [blame] | 178 | extern int FASTCALL(schedule_delayed_work(struct delayed_work *work, unsigned long delay)); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 179 | |
David Howells | 52bad64 | 2006-11-22 14:54:01 +0000 | [diff] [blame] | 180 | extern int schedule_delayed_work_on(int cpu, struct delayed_work *work, unsigned long delay); |
David Howells | 65f27f3 | 2006-11-22 14:55:48 +0000 | [diff] [blame] | 181 | extern int schedule_on_each_cpu(work_func_t func); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 182 | extern void flush_scheduled_work(void); |
| 183 | extern int current_is_keventd(void); |
| 184 | extern int keventd_up(void); |
| 185 | |
| 186 | extern void init_workqueues(void); |
David Howells | 52bad64 | 2006-11-22 14:54:01 +0000 | [diff] [blame] | 187 | void cancel_rearming_delayed_work(struct delayed_work *work); |
James Bottomley | 81ddef7 | 2005-04-16 15:23:59 -0700 | [diff] [blame] | 188 | void cancel_rearming_delayed_workqueue(struct workqueue_struct *, |
David Howells | 52bad64 | 2006-11-22 14:54:01 +0000 | [diff] [blame] | 189 | struct delayed_work *); |
David Howells | 65f27f3 | 2006-11-22 14:55:48 +0000 | [diff] [blame] | 190 | int execute_in_process_context(work_func_t fn, struct execute_work *); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 191 | |
| 192 | /* |
| 193 | * Kill off a pending schedule_delayed_work(). Note that the work callback |
| 194 | * function may still be running on return from cancel_delayed_work(). Run |
| 195 | * flush_scheduled_work() to wait on it. |
| 196 | */ |
David Howells | 52bad64 | 2006-11-22 14:54:01 +0000 | [diff] [blame] | 197 | static inline int cancel_delayed_work(struct delayed_work *work) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 198 | { |
| 199 | int ret; |
| 200 | |
| 201 | ret = del_timer_sync(&work->timer); |
| 202 | if (ret) |
Linus Torvalds | a08727b | 2006-12-16 09:53:50 -0800 | [diff] [blame] | 203 | work_release(&work->work); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 204 | return ret; |
| 205 | } |
| 206 | |
| 207 | #endif |