1 /* $NetBSD: threads.c,v 1.12 2010/09/01 19:37:59 pooka Exp $ */ 2 3 /* 4 * Copyright (c) 2007-2009 Antti Kantee. All Rights Reserved. 5 * 6 * Development of this software was supported by 7 * The Finnish Cultural Foundation. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 19 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31 #include <sys/cdefs.h> 32 __KERNEL_RCSID(0, "$NetBSD: threads.c,v 1.12 2010/09/01 19:37:59 pooka Exp $"); 33 34 #include <sys/param.h> 35 #include <sys/atomic.h> 36 #include <sys/kmem.h> 37 #include <sys/kthread.h> 38 #include <sys/malloc.h> 39 #include <sys/systm.h> 40 41 #include <machine/stdarg.h> 42 43 #include <rump/rumpuser.h> 44 45 #include "rump_private.h" 46 47 struct kthdesc { 48 void (*f)(void *); 49 void *arg; 50 struct lwp *mylwp; 51 }; 52 53 static void * 54 threadbouncer(void *arg) 55 { 56 struct kthdesc *k = arg; 57 struct lwp *l = k->mylwp; 58 void (*f)(void *); 59 void *thrarg; 60 61 f = k->f; 62 thrarg = k->arg; 63 64 /* schedule ourselves */ 65 rumpuser_set_curlwp(l); 66 rump_schedule(); 67 68 /* free dance struct */ 69 free(k, M_TEMP); 70 71 if ((curlwp->l_pflag & LP_MPSAFE) == 0) 72 KERNEL_LOCK(1, NULL); 73 74 f(thrarg); 75 76 panic("unreachable, should kthread_exit()"); 77 } 78 79 int 80 kthread_create(pri_t pri, int flags, struct cpu_info *ci, 81 void (*func)(void *), void *arg, lwp_t **newlp, const char *fmt, ...) 82 { 83 char thrstore[MAXCOMLEN]; 84 const char *thrname = NULL; 85 va_list ap; 86 struct kthdesc *k; 87 struct lwp *l; 88 int rv; 89 90 thrstore[0] = '\0'; 91 if (fmt) { 92 va_start(ap, fmt); 93 vsnprintf(thrstore, sizeof(thrstore), fmt, ap); 94 va_end(ap); 95 thrname = thrstore; 96 } 97 98 /* 99 * We don't want a module unload thread. 100 * (XXX: yes, this is a kludge too, and the kernel should 101 * have a more flexible method for configuring which threads 102 * we want). 103 */ 104 if (strcmp(thrstore, "modunload") == 0) { 105 return 0; 106 } 107 108 if (!rump_threads) { 109 /* fake them */ 110 if (strcmp(thrstore, "vrele") == 0) { 111 printf("rump warning: threads not enabled, not starting" 112 " vrele thread\n"); 113 return 0; 114 } else if (strcmp(thrstore, "cachegc") == 0) { 115 printf("rump warning: threads not enabled, not starting" 116 " namecache g/c thread\n"); 117 return 0; 118 } else if (strcmp(thrstore, "nfssilly") == 0) { 119 printf("rump warning: threads not enabled, not enabling" 120 " nfs silly rename\n"); 121 return 0; 122 } else if (strcmp(thrstore, "unpgc") == 0) { 123 printf("rump warning: threads not enabled, not enabling" 124 " UNP garbage collection\n"); 125 return 0; 126 } else if (strncmp(thrstore, "pmf", sizeof("pmf")-1) == 0) { 127 printf("rump warning: threads not enabled, not enabling" 128 " pmf thread\n"); 129 return 0; 130 } else if (strncmp(thrstore, "xcall", sizeof("xcall")-1) == 0) { 131 printf("rump warning: threads not enabled, CPU xcall" 132 " not functional\n"); 133 return 0; 134 } else 135 panic("threads not available, setenv RUMP_THREADS 1"); 136 } 137 KASSERT(fmt != NULL); 138 139 k = malloc(sizeof(*k), M_TEMP, M_WAITOK); 140 k->f = func; 141 k->arg = arg; 142 k->mylwp = l = rump__lwproc_allockernlwp(); 143 l->l_flag |= LW_SYSTEM; 144 if (flags & KTHREAD_MPSAFE) 145 l->l_pflag |= LP_MPSAFE; 146 if (flags & KTHREAD_INTR) 147 l->l_pflag |= LP_INTR; 148 if (ci) { 149 l->l_pflag |= LP_BOUND; 150 l->l_target_cpu = ci; 151 } 152 if (thrname) { 153 l->l_name = kmem_alloc(MAXCOMLEN, KM_SLEEP); 154 strlcpy(l->l_name, thrname, MAXCOMLEN); 155 } 156 157 rv = rumpuser_thread_create(threadbouncer, k, thrname, 158 (flags & KTHREAD_JOINABLE) == KTHREAD_JOINABLE, &l->l_ctxlink); 159 if (rv) 160 return rv; 161 162 if (newlp) { 163 *newlp = l; 164 } else { 165 KASSERT((flags & KTHREAD_JOINABLE) == 0); 166 } 167 168 return 0; 169 } 170 171 void 172 kthread_exit(int ecode) 173 { 174 175 if ((curlwp->l_pflag & LP_MPSAFE) == 0) 176 KERNEL_UNLOCK_LAST(NULL); 177 rump_lwproc_releaselwp(); 178 /* unschedule includes membar */ 179 rump_unschedule(); 180 rumpuser_thread_exit(); 181 } 182 183 int 184 kthread_join(struct lwp *l) 185 { 186 int rv; 187 188 KASSERT(l->l_ctxlink != NULL); 189 rv = rumpuser_thread_join(l->l_ctxlink); 190 membar_consumer(); 191 192 return rv; 193 } 194