aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/kthread.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/kthread.c')
-rw-r--r--kernel/kthread.c149
1 files changed, 149 insertions, 0 deletions
diff --git a/kernel/kthread.c b/kernel/kthread.c
index 83911c780175..8b63c7fee73b 100644
--- a/kernel/kthread.c
+++ b/kernel/kthread.c
@@ -14,6 +14,8 @@
14#include <linux/file.h> 14#include <linux/file.h>
15#include <linux/module.h> 15#include <linux/module.h>
16#include <linux/mutex.h> 16#include <linux/mutex.h>
17#include <linux/slab.h>
18#include <linux/freezer.h>
17#include <trace/events/sched.h> 19#include <trace/events/sched.h>
18 20
19static DEFINE_SPINLOCK(kthread_create_lock); 21static DEFINE_SPINLOCK(kthread_create_lock);
@@ -247,3 +249,150 @@ int kthreadd(void *unused)
247 249
248 return 0; 250 return 0;
249} 251}
252
253/**
254 * kthread_worker_fn - kthread function to process kthread_worker
255 * @worker_ptr: pointer to initialized kthread_worker
256 *
257 * This function can be used as @threadfn to kthread_create() or
258 * kthread_run() with @worker_ptr argument pointing to an initialized
259 * kthread_worker. The started kthread will process work_list until
260 * the it is stopped with kthread_stop(). A kthread can also call
261 * this function directly after extra initialization.
262 *
263 * Different kthreads can be used for the same kthread_worker as long
264 * as there's only one kthread attached to it at any given time. A
265 * kthread_worker without an attached kthread simply collects queued
266 * kthread_works.
267 */
268int kthread_worker_fn(void *worker_ptr)
269{
270 struct kthread_worker *worker = worker_ptr;
271 struct kthread_work *work;
272
273 WARN_ON(worker->task);
274 worker->task = current;
275repeat:
276 set_current_state(TASK_INTERRUPTIBLE); /* mb paired w/ kthread_stop */
277
278 if (kthread_should_stop()) {
279 __set_current_state(TASK_RUNNING);
280 spin_lock_irq(&worker->lock);
281 worker->task = NULL;
282 spin_unlock_irq(&worker->lock);
283 return 0;
284 }
285
286 work = NULL;
287 spin_lock_irq(&worker->lock);
288 if (!list_empty(&worker->work_list)) {
289 work = list_first_entry(&worker->work_list,
290 struct kthread_work, node);
291 list_del_init(&work->node);
292 }
293 spin_unlock_irq(&worker->lock);
294
295 if (work) {
296 __set_current_state(TASK_RUNNING);
297 work->func(work);
298 smp_wmb(); /* wmb worker-b0 paired with flush-b1 */
299 work->done_seq = work->queue_seq;
300 smp_mb(); /* mb worker-b1 paired with flush-b0 */
301 if (atomic_read(&work->flushing))
302 wake_up_all(&work->done);
303 } else if (!freezing(current))
304 schedule();
305
306 try_to_freeze();
307 goto repeat;
308}
309EXPORT_SYMBOL_GPL(kthread_worker_fn);
310
311/**
312 * queue_kthread_work - queue a kthread_work
313 * @worker: target kthread_worker
314 * @work: kthread_work to queue
315 *
316 * Queue @work to work processor @task for async execution. @task
317 * must have been created with kthread_worker_create(). Returns %true
318 * if @work was successfully queued, %false if it was already pending.
319 */
320bool queue_kthread_work(struct kthread_worker *worker,
321 struct kthread_work *work)
322{
323 bool ret = false;
324 unsigned long flags;
325
326 spin_lock_irqsave(&worker->lock, flags);
327 if (list_empty(&work->node)) {
328 list_add_tail(&work->node, &worker->work_list);
329 work->queue_seq++;
330 if (likely(worker->task))
331 wake_up_process(worker->task);
332 ret = true;
333 }
334 spin_unlock_irqrestore(&worker->lock, flags);
335 return ret;
336}
337EXPORT_SYMBOL_GPL(queue_kthread_work);
338
339/**
340 * flush_kthread_work - flush a kthread_work
341 * @work: work to flush
342 *
343 * If @work is queued or executing, wait for it to finish execution.
344 */
345void flush_kthread_work(struct kthread_work *work)
346{
347 int seq = work->queue_seq;
348
349 atomic_inc(&work->flushing);
350
351 /*
352 * mb flush-b0 paired with worker-b1, to make sure either
353 * worker sees the above increment or we see done_seq update.
354 */
355 smp_mb__after_atomic_inc();
356
357 /* A - B <= 0 tests whether B is in front of A regardless of overflow */
358 wait_event(work->done, seq - work->done_seq <= 0);
359 atomic_dec(&work->flushing);
360
361 /*
362 * rmb flush-b1 paired with worker-b0, to make sure our caller
363 * sees every change made by work->func().
364 */
365 smp_mb__after_atomic_dec();
366}
367EXPORT_SYMBOL_GPL(flush_kthread_work);
368
369struct kthread_flush_work {
370 struct kthread_work work;
371 struct completion done;
372};
373
374static void kthread_flush_work_fn(struct kthread_work *work)
375{
376 struct kthread_flush_work *fwork =
377 container_of(work, struct kthread_flush_work, work);
378 complete(&fwork->done);
379}
380
381/**
382 * flush_kthread_worker - flush all current works on a kthread_worker
383 * @worker: worker to flush
384 *
385 * Wait until all currently executing or pending works on @worker are
386 * finished.
387 */
388void flush_kthread_worker(struct kthread_worker *worker)
389{
390 struct kthread_flush_work fwork = {
391 KTHREAD_WORK_INIT(fwork.work, kthread_flush_work_fn),
392 COMPLETION_INITIALIZER_ONSTACK(fwork.done),
393 };
394
395 queue_kthread_work(worker, &fwork.work);
396 wait_for_completion(&fwork.done);
397}
398EXPORT_SYMBOL_GPL(flush_kthread_worker);