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