1 /* $OpenBSD: kern_kthread.c,v 1.44 2020/02/21 11:10:23 claudio 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 42 /* 43 * note that stdarg.h and the ansi style va_start macro is used for both 44 * ansi and traditional c compilers. 45 * XXX: this requires that stdarg.h define: va_alist and va_dcl 46 */ 47 #include <sys/stdarg.h> 48 49 int kthread_create_now; 50 51 /* 52 * Fork a kernel thread. Any process can request this to be done. 53 * The VM space and limits, etc. will be shared with proc0. 54 */ 55 int 56 kthread_create(void (*func)(void *), void *arg, 57 struct proc **newpp, const char *name) 58 { 59 struct proc *p; 60 int error; 61 62 KERNEL_LOCK(); 63 64 /* 65 * First, create the new process. Share the memory, file 66 * descriptors and don't leave the exit status around for the 67 * parent to wait for. 68 */ 69 error = fork1(&proc0, FORK_SHAREVM|FORK_SHAREFILES|FORK_NOZOMBIE| 70 FORK_SYSTEM, func, arg, NULL, &p); 71 if (error) { 72 KERNEL_UNLOCK(); 73 return (error); 74 } 75 76 /* Name it as specified. */ 77 strlcpy(p->p_p->ps_comm, name, sizeof p->p_p->ps_comm); 78 79 KERNEL_UNLOCK(); 80 81 /* All done! */ 82 if (newpp != NULL) 83 *newpp = p; 84 return (0); 85 } 86 87 /* 88 * Cause a kernel thread to exit. Assumes the exiting thread is the 89 * current context. 90 */ 91 void 92 kthread_exit(int ecode) 93 { 94 95 /* 96 * XXX What do we do with the exit code? Should we even bother 97 * XXX with it? The parent (proc0) isn't going to do much with 98 * XXX it. 99 */ 100 if (ecode != 0) 101 printf("WARNING: thread `%s' (%d) exits with status %d\n", 102 curproc->p_p->ps_comm, curproc->p_tid, ecode); 103 104 exit1(curproc, ecode, 0, EXIT_NORMAL); 105 106 /* 107 * XXX Fool the compiler. Making exit1() __dead is a can 108 * XXX of worms right now. 109 */ 110 for (;;); 111 } 112 113 struct kthread_q { 114 SIMPLEQ_ENTRY(kthread_q) kq_q; 115 void (*kq_func)(void *); 116 void *kq_arg; 117 }; 118 119 SIMPLEQ_HEAD(, kthread_q) kthread_q = SIMPLEQ_HEAD_INITIALIZER(kthread_q); 120 121 /* 122 * Defer the creation of a kernel thread. Once the standard kernel threads 123 * and processes have been created, this queue will be run to callback to 124 * the caller to create threads for e.g. file systems and device drivers. 125 */ 126 void 127 kthread_create_deferred(void (*func)(void *), void *arg) 128 { 129 struct kthread_q *kq; 130 131 if (kthread_create_now) { 132 (*func)(arg); 133 return; 134 } 135 136 kq = malloc(sizeof *kq, M_TEMP, M_NOWAIT|M_ZERO); 137 if (kq == NULL) 138 panic("unable to allocate kthread_q"); 139 140 kq->kq_func = func; 141 kq->kq_arg = arg; 142 143 SIMPLEQ_INSERT_TAIL(&kthread_q, kq, kq_q); 144 } 145 146 void 147 kthread_run_deferred_queue(void) 148 { 149 struct kthread_q *kq; 150 151 /* No longer need to defer kthread creation. */ 152 kthread_create_now = 1; 153 154 while ((kq = SIMPLEQ_FIRST(&kthread_q)) != NULL) { 155 SIMPLEQ_REMOVE_HEAD(&kthread_q, kq_q); 156 (*kq->kq_func)(kq->kq_arg); 157 free(kq, M_TEMP, sizeof(*kq)); 158 } 159 } 160