• Andrew Morton's avatar
    [PATCH] flush_work_queue() fixes · 92b817f8
    Andrew Morton authored
    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.
    92b817f8
workqueue.c 8.82 KB