1aa2693a5SFrançois Tigeot /*
2aa2693a5SFrançois Tigeot * Copyright (c) 2019 François Tigeot <ftigeot@wolfpond.org>
3aa2693a5SFrançois Tigeot * All rights reserved.
4aa2693a5SFrançois Tigeot *
5aa2693a5SFrançois Tigeot * Redistribution and use in source and binary forms, with or without
6aa2693a5SFrançois Tigeot * modification, are permitted provided that the following conditions
7aa2693a5SFrançois Tigeot * are met:
8aa2693a5SFrançois Tigeot * 1. Redistributions of source code must retain the above copyright
9aa2693a5SFrançois Tigeot * notice unmodified, this list of conditions, and the following
10aa2693a5SFrançois Tigeot * disclaimer.
11aa2693a5SFrançois Tigeot * 2. Redistributions in binary form must reproduce the above copyright
12aa2693a5SFrançois Tigeot * notice, this list of conditions and the following disclaimer in the
13aa2693a5SFrançois Tigeot * documentation and/or other materials provided with the distribution.
14aa2693a5SFrançois Tigeot *
15aa2693a5SFrançois Tigeot * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16aa2693a5SFrançois Tigeot * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17aa2693a5SFrançois Tigeot * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18aa2693a5SFrançois Tigeot * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19aa2693a5SFrançois Tigeot * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20aa2693a5SFrançois Tigeot * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21aa2693a5SFrançois Tigeot * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22aa2693a5SFrançois Tigeot * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23aa2693a5SFrançois Tigeot * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24aa2693a5SFrançois Tigeot * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25aa2693a5SFrançois Tigeot */
26aa2693a5SFrançois Tigeot
27aa2693a5SFrançois Tigeot #include <linux/kthread.h>
28aa2693a5SFrançois Tigeot #include <linux/sched.h>
29aa2693a5SFrançois Tigeot #include <linux/slab.h>
30aa2693a5SFrançois Tigeot
31aa2693a5SFrançois Tigeot #include <sys/kthread.h>
32aa2693a5SFrançois Tigeot
33aa2693a5SFrançois Tigeot /*
34aa2693a5SFrançois Tigeot All Linux threads/processes have an associated task_struct
35aa2693a5SFrançois Tigeot a kthread is a pure kernel thread without userland context
36aa2693a5SFrançois Tigeot */
37aa2693a5SFrançois Tigeot
38aa2693a5SFrançois Tigeot static void
linux_ktfn_wrapper(void * arg)39aa2693a5SFrançois Tigeot linux_ktfn_wrapper(void *arg)
40aa2693a5SFrançois Tigeot {
41aa2693a5SFrançois Tigeot struct task_struct *task = arg;
42aa2693a5SFrançois Tigeot
43aa2693a5SFrançois Tigeot task->kt_exitvalue = task->kt_fn(task->kt_fndata);
44aa2693a5SFrançois Tigeot }
45aa2693a5SFrançois Tigeot
46aa2693a5SFrançois Tigeot struct task_struct *
kthread_run(int (* lfn)(void *),void * data,const char * namefmt,...)47aa2693a5SFrançois Tigeot kthread_run(int (*lfn)(void *), void *data, const char *namefmt, ...)
48aa2693a5SFrançois Tigeot {
49aa2693a5SFrançois Tigeot struct task_struct *task;
50aa2693a5SFrançois Tigeot struct thread *td;
51aa2693a5SFrançois Tigeot __va_list args;
52aa2693a5SFrançois Tigeot int ret;
53aa2693a5SFrançois Tigeot
54aa2693a5SFrançois Tigeot task = kzalloc(sizeof(*task), GFP_KERNEL);
55aa2693a5SFrançois Tigeot
56aa2693a5SFrançois Tigeot __va_start(args, namefmt);
57aa2693a5SFrançois Tigeot ret = kthread_alloc(linux_ktfn_wrapper, task, &td, namefmt, args);
58aa2693a5SFrançois Tigeot __va_end(args);
59aa2693a5SFrançois Tigeot if (ret) {
60aa2693a5SFrançois Tigeot kfree(task);
61aa2693a5SFrançois Tigeot return ERR_PTR(-ENOMEM);
62aa2693a5SFrançois Tigeot }
63aa2693a5SFrançois Tigeot
64aa2693a5SFrançois Tigeot task->dfly_td = td;
65aa2693a5SFrançois Tigeot td->td_linux_task = task;
66aa2693a5SFrançois Tigeot
67aa2693a5SFrançois Tigeot task->mm = NULL; /* kthreads have no userland address space */
68aa2693a5SFrançois Tigeot
69aa2693a5SFrançois Tigeot task->kt_fn = lfn;
70aa2693a5SFrançois Tigeot task->kt_fndata = data;
71*3f2dd94aSFrançois Tigeot spin_init(&task->kt_spin, "tspin1");
72aa2693a5SFrançois Tigeot
73aa2693a5SFrançois Tigeot /* Start the thread here */
74aa2693a5SFrançois Tigeot lwkt_schedule(td);
75aa2693a5SFrançois Tigeot
76aa2693a5SFrançois Tigeot return task;
77aa2693a5SFrançois Tigeot }
78aa2693a5SFrançois Tigeot
79aa2693a5SFrançois Tigeot #define KTHREAD_SHOULD_STOP 1
8079a4854cSFrançois Tigeot #define KTHREAD_SHOULD_PARK 2
81aa2693a5SFrançois Tigeot
82aa2693a5SFrançois Tigeot bool
kthread_should_stop(void)83aa2693a5SFrançois Tigeot kthread_should_stop(void)
84aa2693a5SFrançois Tigeot {
85aa2693a5SFrançois Tigeot return test_bit(KTHREAD_SHOULD_STOP, ¤t->kt_flags);
86aa2693a5SFrançois Tigeot }
87aa2693a5SFrançois Tigeot
88aa2693a5SFrançois Tigeot int
kthread_stop(struct task_struct * ts)89aa2693a5SFrançois Tigeot kthread_stop(struct task_struct *ts)
90aa2693a5SFrançois Tigeot {
91aa2693a5SFrançois Tigeot set_bit(KTHREAD_SHOULD_STOP, &ts->kt_flags);
92aa2693a5SFrançois Tigeot
93*3f2dd94aSFrançois Tigeot kthread_unpark(ts);
94aa2693a5SFrançois Tigeot wake_up_process(ts);
95aa2693a5SFrançois Tigeot
96*3f2dd94aSFrançois Tigeot /* XXX use a better mechanism to wait for the thread to finish running */
97*3f2dd94aSFrançois Tigeot tsleep(kthread_stop, 0, "kstop", hz);
98*3f2dd94aSFrançois Tigeot lwkt_free_thread(ts->dfly_td);
99*3f2dd94aSFrançois Tigeot
100aa2693a5SFrançois Tigeot return ts->kt_exitvalue;
101aa2693a5SFrançois Tigeot }
10279a4854cSFrançois Tigeot
10379a4854cSFrançois Tigeot int
kthread_park(struct task_struct * ts)10479a4854cSFrançois Tigeot kthread_park(struct task_struct *ts)
10579a4854cSFrançois Tigeot {
10679a4854cSFrançois Tigeot set_bit(KTHREAD_SHOULD_PARK, &ts->kt_flags);
10779a4854cSFrançois Tigeot wake_up_process(ts);
10879a4854cSFrançois Tigeot
10979a4854cSFrançois Tigeot return ts->kt_exitvalue;
11079a4854cSFrançois Tigeot }
11179a4854cSFrançois Tigeot
11279a4854cSFrançois Tigeot void
kthread_unpark(struct task_struct * ts)11379a4854cSFrançois Tigeot kthread_unpark(struct task_struct *ts)
11479a4854cSFrançois Tigeot {
11579a4854cSFrançois Tigeot clear_bit(KTHREAD_SHOULD_PARK, &ts->kt_flags);
11679a4854cSFrançois Tigeot lwkt_schedule(ts->dfly_td);
11779a4854cSFrançois Tigeot wake_up_process(ts);
11879a4854cSFrançois Tigeot }
11979a4854cSFrançois Tigeot
12079a4854cSFrançois Tigeot bool
kthread_should_park(void)12179a4854cSFrançois Tigeot kthread_should_park(void)
12279a4854cSFrançois Tigeot {
12379a4854cSFrançois Tigeot return test_bit(KTHREAD_SHOULD_PARK, ¤t->kt_flags);
12479a4854cSFrançois Tigeot }
12579a4854cSFrançois Tigeot
12679a4854cSFrançois Tigeot void
kthread_parkme(void)12779a4854cSFrançois Tigeot kthread_parkme(void)
12879a4854cSFrançois Tigeot {
12979a4854cSFrançois Tigeot if (test_bit(KTHREAD_SHOULD_PARK, ¤t->kt_flags) == 0)
13079a4854cSFrançois Tigeot return;
13179a4854cSFrançois Tigeot
13279a4854cSFrançois Tigeot lwkt_deschedule_self(curthread);
13379a4854cSFrançois Tigeot }
134