1 /* $OpenBSD: kern_kthread.c,v 1.46 2021/11/26 04:42:13 visa Exp $ */
2 /* $NetBSD: kern_kthread.c,v 1.3 1998/12/22 21:21:36 kleink Exp $ */
3
4 /*-
5 * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to The NetBSD Foundation
9 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
10 * NASA Ames Research Center.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/kthread.h>
37 #include <sys/proc.h>
38 #include <sys/malloc.h>
39 #include <sys/queue.h>
40
41 int kthread_create_now;
42
43 /*
44 * Fork a kernel thread. Any process can request this to be done.
45 * The VM space and limits, etc. will be shared with proc0.
46 */
47 int
kthread_create(void (* func)(void *),void * arg,struct proc ** newpp,const char * name)48 kthread_create(void (*func)(void *), void *arg,
49 struct proc **newpp, const char *name)
50 {
51 struct proc *p;
52 int error;
53
54 KERNEL_LOCK();
55
56 /*
57 * First, create the new process. Share the memory, file
58 * descriptors and don't leave the exit status around for the
59 * parent to wait for.
60 */
61 error = fork1(&proc0, FORK_SHAREVM|FORK_SHAREFILES|FORK_NOZOMBIE|
62 FORK_SYSTEM, func, arg, NULL, &p);
63 if (error) {
64 KERNEL_UNLOCK();
65 return (error);
66 }
67
68 /* Name it as specified. */
69 strlcpy(p->p_p->ps_comm, name, sizeof p->p_p->ps_comm);
70
71 KERNEL_UNLOCK();
72
73 /* All done! */
74 if (newpp != NULL)
75 *newpp = p;
76 return (0);
77 }
78
79 /*
80 * Cause a kernel thread to exit. Assumes the exiting thread is the
81 * current context.
82 */
83 void
kthread_exit(int ecode)84 kthread_exit(int ecode)
85 {
86
87 /*
88 * XXX What do we do with the exit code? Should we even bother
89 * XXX with it? The parent (proc0) isn't going to do much with
90 * XXX it.
91 */
92 if (ecode != 0)
93 printf("WARNING: thread `%s' (%d) exits with status %d\n",
94 curproc->p_p->ps_comm, curproc->p_tid, ecode);
95
96 exit1(curproc, ecode, 0, EXIT_NORMAL);
97 /* NOTREACHED */
98 }
99
100 struct kthread_q {
101 SIMPLEQ_ENTRY(kthread_q) kq_q;
102 void (*kq_func)(void *);
103 void *kq_arg;
104 };
105
106 SIMPLEQ_HEAD(, kthread_q) kthread_q = SIMPLEQ_HEAD_INITIALIZER(kthread_q);
107
108 /*
109 * Defer the creation of a kernel thread. Once the standard kernel threads
110 * and processes have been created, this queue will be run to callback to
111 * the caller to create threads for e.g. file systems and device drivers.
112 */
113 void
kthread_create_deferred(void (* func)(void *),void * arg)114 kthread_create_deferred(void (*func)(void *), void *arg)
115 {
116 struct kthread_q *kq;
117
118 if (kthread_create_now) {
119 (*func)(arg);
120 return;
121 }
122
123 kq = malloc(sizeof *kq, M_TEMP, M_NOWAIT|M_ZERO);
124 if (kq == NULL)
125 panic("unable to allocate kthread_q");
126
127 kq->kq_func = func;
128 kq->kq_arg = arg;
129
130 SIMPLEQ_INSERT_TAIL(&kthread_q, kq, kq_q);
131 }
132
133 void
kthread_run_deferred_queue(void)134 kthread_run_deferred_queue(void)
135 {
136 struct kthread_q *kq;
137
138 /* No longer need to defer kthread creation. */
139 kthread_create_now = 1;
140
141 while ((kq = SIMPLEQ_FIRST(&kthread_q)) != NULL) {
142 SIMPLEQ_REMOVE_HEAD(&kthread_q, kq_q);
143 (*kq->kq_func)(kq->kq_arg);
144 free(kq, M_TEMP, sizeof(*kq));
145 }
146 }
147