diff options
| author | Andrew Morton <akpm@digeo.com> | 2003-04-14 06:09:45 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@home.transmeta.com> | 2003-04-14 06:09:45 -0700 |
| commit | 92b817f8d42ef76fded6294554c3bd7fc94b955c (patch) | |
| tree | 6245c75ffde6e5a6622bcb683b7e16b83d2dcc28 /include/linux/workqueue.h | |
| parent | ec7708a234f332be15443b6fe953f55441b22814 (diff) | |
[PATCH] flush_work_queue() fixes
The workqueue code currently has a notion of a per-cpu queue being "busy".
flush_scheduled_work()'s responsibility is to wait for a queue to be not busy.
Problem is, flush_scheduled_work() can easily hang up.
- The workqueue is deemed "busy" when there are pending delayed
(timer-based) works. But if someone repeatedly schedules new delayed work
in the callback, the queue will never fall idle, and flush_scheduled_work()
will not terminate.
- If someone reschedules work (not delayed work) in the work function, that
too will cause the queue to never go idle, and flush_scheduled_work() will
not terminate.
So what this patch does is:
- Create a new "cancel_delayed_work()" which will try to kill off any
timer-based delayed works.
- Change flush_scheduled_work() so that it is immune to people re-adding
work in the work callout handler.
We can do this by recognising that the caller does *not* want to wait
until the workqueue is "empty". The caller merely wants to wait until all
works which were pending at the time flush_scheduled_work() was called have
completed.
The patch uses a couple of sequence numbers for that.
So now, if someone wants to reliably remove delayed work they should do:
/*
* Make sure that my work-callback will no longer schedule new work
*/
my_driver_is_shutting_down = 1;
/*
* Kill off any pending delayed work
*/
cancel_delayed_work(&my_work);
/*
* OK, there will be no new works scheduled. But there may be one
* currently queued or in progress. So wait for that to complete.
*/
flush_scheduled_work();
The patch also changes the flush_workqueue() sleep to be uninterruptible.
We cannot legally bale out if a signal is delivered anyway.
Diffstat (limited to 'include/linux/workqueue.h')
| -rw-r--r-- | include/linux/workqueue.h | 10 |
1 files changed, 10 insertions, 0 deletions
diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h index 47b1414738ec..096bca54cc77 100644 --- a/include/linux/workqueue.h +++ b/include/linux/workqueue.h @@ -63,5 +63,15 @@ extern int current_is_keventd(void); extern void init_workqueues(void); +/* + * Kill off a pending schedule_delayed_work(). Note that the work callback + * 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) +{ + return del_timer_sync(&work->timer); +} + #endif |
