kernel - add kthread_create_cpu()
[dragonfly.git] / sys / kern / kern_kthread.c
CommitLineData
984263bc
MD
1/*
2 * Copyright (c) 1999 Peter Wemm <peter@FreeBSD.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, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: src/sys/kern/kern_kthread.c,v 1.5.2.3 2001/12/25 01:51:14 dillon Exp $
379210cb 27 * $DragonFly: src/sys/kern/kern_kthread.c,v 1.13 2006/12/18 20:41:01 dillon Exp $
984263bc
MD
28 */
29
30#include <sys/param.h>
31#include <sys/systm.h>
32#include <sys/proc.h>
33#include <sys/kthread.h>
34#include <sys/ptrace.h>
35#include <sys/resourcevar.h>
36#include <sys/signalvar.h>
37#include <sys/unistd.h>
38#include <sys/wait.h>
39
40#include <machine/stdarg.h>
41
496907b0
MD
42/*
43 * Create a kernel process/thread/whatever. It shares it's address space
44 * with proc0 - ie: kernel only. 5.x compatible.
45 *
46 * NOTE! By default kthreads are created with the MP lock held. A
47 * thread which does not require the MP lock should release it by calling
48 * rel_mplock() at the start of the new thread.
49 */
50int
51kthread_create(void (*func)(void *), void *arg,
be13c473 52 struct thread **tdp, const char *fmt, ...)
496907b0
MD
53{
54 thread_t td;
55 __va_list ap;
56
d3d32139 57 td = lwkt_alloc_thread(NULL, LWKT_THREAD_STACK, -1, TDF_VERBOSE);
496907b0
MD
58 if (tdp)
59 *tdp = td;
60 cpu_set_thread_handler(td, kthread_exit, func, arg);
496907b0 61#ifdef SMP
d3d32139 62 KKASSERT(td->td_mpcount == 1);
496907b0
MD
63#endif
64
65 /*
66 * Set up arg0 for 'ps' etc
67 */
68 __va_start(ap, fmt);
379210cb 69 kvsnprintf(td->td_comm, sizeof(td->td_comm), fmt, ap);
496907b0
MD
70 __va_end(ap);
71
60055ede
SG
72 td->td_ucred = crhold(proc0.p_ucred);
73
496907b0
MD
74 /*
75 * Schedule the thread to run
76 */
77 lwkt_schedule(td);
78 return 0;
79}
80
be13c473
MD
81int
82kthread_create_cpu(void (*func)(void *), void *arg,
83 struct thread **tdp, int cpu, const char *fmt, ...)
84{
85 thread_t td;
86 __va_list ap;
87
88 td = lwkt_alloc_thread(NULL, LWKT_THREAD_STACK, cpu, TDF_VERBOSE);
89 if (tdp)
90 *tdp = td;
91 cpu_set_thread_handler(td, kthread_exit, func, arg);
92#ifdef SMP
93 KKASSERT(td->td_mpcount == 1);
94#endif
95
96 /*
97 * Set up arg0 for 'ps' etc
98 */
99 __va_start(ap, fmt);
100 kvsnprintf(td->td_comm, sizeof(td->td_comm), fmt, ap);
101 __va_end(ap);
102
103 td->td_ucred = crhold(proc0.p_ucred);
104
105 /*
106 * Schedule the thread to run
107 */
108 lwkt_schedule(td);
109 return 0;
110}
111
496907b0
MD
112/*
113 * Same as kthread_create() but you can specify a custom stack size.
114 */
115int
116kthread_create_stk(void (*func)(void *), void *arg,
be13c473 117 struct thread **tdp, int stksize, const char *fmt, ...)
496907b0
MD
118{
119 thread_t td;
120 __va_list ap;
121
d3d32139 122 td = lwkt_alloc_thread(NULL, stksize, -1, TDF_VERBOSE);
496907b0
MD
123 if (tdp)
124 *tdp = td;
125 cpu_set_thread_handler(td, kthread_exit, func, arg);
496907b0 126#ifdef SMP
d3d32139 127 KKASSERT(td->td_mpcount == 1);
496907b0
MD
128#endif
129 __va_start(ap, fmt);
379210cb 130 kvsnprintf(td->td_comm, sizeof(td->td_comm), fmt, ap);
496907b0
MD
131 __va_end(ap);
132
133 lwkt_schedule(td);
134 return 0;
135}
136
137/*
138 * Destroy an LWKT thread. Warning! This function is not called when
139 * a process exits, cpu_proc_exit() directly calls cpu_thread_exit() and
140 * uses a different reaping mechanism.
141 *
142 * XXX duplicates lwkt_exit()
143 */
144void
145kthread_exit(void)
146{
147 lwkt_exit();
148}
149
984263bc
MD
150/*
151 * Start a kernel process. This is called after a fork() call in
152 * mi_startup() in the file kern/init_main.c.
153 *
154 * This function is used to start "internal" daemons and intended
155 * to be called from SYSINIT().
156 */
157void
77153250 158kproc_start(const void *udata)
984263bc
MD
159{
160 const struct kproc_desc *kp = udata;
161 int error;
162
163 error = kthread_create((void (*)(void *))kp->func, NULL,
be13c473 164 kp->global_threadpp, kp->arg0);
26a0694b 165 lwkt_setpri(*kp->global_threadpp, TDPRI_KERN_DAEMON);
984263bc
MD
166 if (error)
167 panic("kproc_start: %s: error %d", kp->arg0, error);
168}
169
984263bc
MD
170/*
171 * Advise a kernel process to suspend (or resume) in its main loop.
172 * Participation is voluntary.
173 */
174int
bc6dffab 175suspend_kproc(struct thread *td, int timo)
984263bc 176{
0cfcada1 177 if (td->td_proc == NULL) {
99df837e 178 td->td_flags |= TDF_STOPREQ; /* request thread pause */
0cfcada1
MD
179 wakeup(td);
180 while (td->td_flags & TDF_STOPREQ) {
377d4740 181 int error = tsleep(td, 0, "suspkp", timo);
0cfcada1
MD
182 if (error == EWOULDBLOCK)
183 break;
184 }
185 td->td_flags &= ~TDF_STOPREQ;
186 return(0);
187 } else {
188 return(EINVAL); /* not a kernel thread */
189 }
984263bc
MD
190}
191
192void
0cfcada1 193kproc_suspend_loop(void)
984263bc 194{
0cfcada1
MD
195 struct thread *td = curthread;
196
197 if (td->td_flags & TDF_STOPREQ) {
198 td->td_flags &= ~TDF_STOPREQ;
199 while ((td->td_flags & TDF_WAKEREQ) == 0) {
200 wakeup(td);
377d4740 201 tsleep(td, 0, "kpsusp", 0);
0cfcada1
MD
202 }
203 td->td_flags &= ~TDF_WAKEREQ;
204 wakeup(td);
984263bc
MD
205 }
206}
0cfcada1 207