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