xref: /dflybsd-src/sys/dev/drm/linux_kthread.c (revision 3f2dd94a569761201b5b0a18b2f697f97fe1b9dc)
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, &current->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, &current->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, &current->kt_flags) == 0)
13079a4854cSFrançois Tigeot 		return;
13179a4854cSFrançois Tigeot 
13279a4854cSFrançois Tigeot 	lwkt_deschedule_self(curthread);
13379a4854cSFrançois Tigeot }
134