aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorPetr Mladek <pmladek@suse.com>2016-10-11 16:55:40 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-10-11 18:06:33 -0400
commit22597dc3d97b1ead2aca201397415a1a84bf2b26 (patch)
treecb2b8efb6f3181e963e9c3619c78f3d02c98226b /kernel
parent8197b3d43b250b8214b9913878e9227eef8bd85f (diff)
kthread: initial support for delayed kthread work
We are going to use kthread_worker more widely and delayed works will be pretty useful. The implementation is inspired by workqueues. It uses a timer to queue the work after the requested delay. If the delay is zero, the work is queued immediately. In compare with workqueues, each work is associated with a single worker (kthread). Therefore the implementation could be much easier. In particular, we use the worker->lock to synchronize all the operations with the work. We do not need any atomic operation with a flags variable. In fact, we do not need any state variable at all. Instead, we add a list of delayed works into the worker. Then the pending work is listed either in the list of queued or delayed works. And the existing check of pending works is the same even for the delayed ones. A work must not be assigned to another worker unless reinitialized. Therefore the timer handler might expect that dwork->work->worker is valid and it could simply take the lock. We just add some sanity checks to help with debugging a potential misuse. Link: http://lkml.kernel.org/r/1470754545-17632-9-git-send-email-pmladek@suse.com Signed-off-by: Petr Mladek <pmladek@suse.com> Acked-by: Tejun Heo <tj@kernel.org> Cc: Oleg Nesterov <oleg@redhat.com> Cc: Ingo Molnar <mingo@redhat.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: "Paul E. McKenney" <paulmck@linux.vnet.ibm.com> Cc: Josh Triplett <josh@joshtriplett.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Jiri Kosina <jkosina@suse.cz> Cc: Borislav Petkov <bp@suse.de> Cc: Michal Hocko <mhocko@suse.cz> Cc: Vlastimil Babka <vbabka@suse.cz> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/kthread.c102
1 files changed, 102 insertions, 0 deletions
diff --git a/kernel/kthread.c b/kernel/kthread.c
index 524dfc8247d7..a5c6d709349d 100644
--- a/kernel/kthread.c
+++ b/kernel/kthread.c
@@ -563,6 +563,7 @@ void __kthread_init_worker(struct kthread_worker *worker,
563 spin_lock_init(&worker->lock); 563 spin_lock_init(&worker->lock);
564 lockdep_set_class_and_name(&worker->lock, key, name); 564 lockdep_set_class_and_name(&worker->lock, key, name);
565 INIT_LIST_HEAD(&worker->work_list); 565 INIT_LIST_HEAD(&worker->work_list);
566 INIT_LIST_HEAD(&worker->delayed_work_list);
566 worker->task = NULL; 567 worker->task = NULL;
567} 568}
568EXPORT_SYMBOL_GPL(__kthread_init_worker); 569EXPORT_SYMBOL_GPL(__kthread_init_worker);
@@ -767,6 +768,107 @@ bool kthread_queue_work(struct kthread_worker *worker,
767} 768}
768EXPORT_SYMBOL_GPL(kthread_queue_work); 769EXPORT_SYMBOL_GPL(kthread_queue_work);
769 770
771/**
772 * kthread_delayed_work_timer_fn - callback that queues the associated kthread
773 * delayed work when the timer expires.
774 * @__data: pointer to the data associated with the timer
775 *
776 * The format of the function is defined by struct timer_list.
777 * It should have been called from irqsafe timer with irq already off.
778 */
779void kthread_delayed_work_timer_fn(unsigned long __data)
780{
781 struct kthread_delayed_work *dwork =
782 (struct kthread_delayed_work *)__data;
783 struct kthread_work *work = &dwork->work;
784 struct kthread_worker *worker = work->worker;
785
786 /*
787 * This might happen when a pending work is reinitialized.
788 * It means that it is used a wrong way.
789 */
790 if (WARN_ON_ONCE(!worker))
791 return;
792
793 spin_lock(&worker->lock);
794 /* Work must not be used with >1 worker, see kthread_queue_work(). */
795 WARN_ON_ONCE(work->worker != worker);
796
797 /* Move the work from worker->delayed_work_list. */
798 WARN_ON_ONCE(list_empty(&work->node));
799 list_del_init(&work->node);
800 kthread_insert_work(worker, work, &worker->work_list);
801
802 spin_unlock(&worker->lock);
803}
804EXPORT_SYMBOL(kthread_delayed_work_timer_fn);
805
806void __kthread_queue_delayed_work(struct kthread_worker *worker,
807 struct kthread_delayed_work *dwork,
808 unsigned long delay)
809{
810 struct timer_list *timer = &dwork->timer;
811 struct kthread_work *work = &dwork->work;
812
813 WARN_ON_ONCE(timer->function != kthread_delayed_work_timer_fn ||
814 timer->data != (unsigned long)dwork);
815
816 /*
817 * If @delay is 0, queue @dwork->work immediately. This is for
818 * both optimization and correctness. The earliest @timer can
819 * expire is on the closest next tick and delayed_work users depend
820 * on that there's no such delay when @delay is 0.
821 */
822 if (!delay) {
823 kthread_insert_work(worker, work, &worker->work_list);
824 return;
825 }
826
827 /* Be paranoid and try to detect possible races already now. */
828 kthread_insert_work_sanity_check(worker, work);
829
830 list_add(&work->node, &worker->delayed_work_list);
831 work->worker = worker;
832 timer_stats_timer_set_start_info(&dwork->timer);
833 timer->expires = jiffies + delay;
834 add_timer(timer);
835}
836
837/**
838 * kthread_queue_delayed_work - queue the associated kthread work
839 * after a delay.
840 * @worker: target kthread_worker
841 * @dwork: kthread_delayed_work to queue
842 * @delay: number of jiffies to wait before queuing
843 *
844 * If the work has not been pending it starts a timer that will queue
845 * the work after the given @delay. If @delay is zero, it queues the
846 * work immediately.
847 *
848 * Return: %false if the @work has already been pending. It means that
849 * either the timer was running or the work was queued. It returns %true
850 * otherwise.
851 */
852bool kthread_queue_delayed_work(struct kthread_worker *worker,
853 struct kthread_delayed_work *dwork,
854 unsigned long delay)
855{
856 struct kthread_work *work = &dwork->work;
857 unsigned long flags;
858 bool ret = false;
859
860 spin_lock_irqsave(&worker->lock, flags);
861
862 if (list_empty(&work->node)) {
863 __kthread_queue_delayed_work(worker, dwork, delay);
864 ret = true;
865 }
866
867 spin_unlock_irqrestore(&worker->lock, flags);
868 return ret;
869}
870EXPORT_SYMBOL_GPL(kthread_queue_delayed_work);
871
770struct kthread_flush_work { 872struct kthread_flush_work {
771 struct kthread_work work; 873 struct kthread_work work;
772 struct completion done; 874 struct completion done;