|
@@ -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
|