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
41int	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 */
47int
48kthread_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 */
83void
84kthread_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
100struct kthread_q {
101	SIMPLEQ_ENTRY(kthread_q) kq_q;
102	void (*kq_func)(void *);
103	void *kq_arg;
104};
105
106SIMPLEQ_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 */
113void
114kthread_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
133void
134kthread_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