1*3290c1c7Spooka /* $NetBSD: threads.c,v 1.22 2014/03/15 15:15:27 pooka Exp $ */ 2c03306bcSpooka 3c03306bcSpooka /* 4c03306bcSpooka * Copyright (c) 2007-2009 Antti Kantee. All Rights Reserved. 5c03306bcSpooka * 6c03306bcSpooka * Development of this software was supported by 7c03306bcSpooka * The Finnish Cultural Foundation. 8c03306bcSpooka * 9c03306bcSpooka * Redistribution and use in source and binary forms, with or without 10c03306bcSpooka * modification, are permitted provided that the following conditions 11c03306bcSpooka * are met: 12c03306bcSpooka * 1. Redistributions of source code must retain the above copyright 13c03306bcSpooka * notice, this list of conditions and the following disclaimer. 14c03306bcSpooka * 2. Redistributions in binary form must reproduce the above copyright 15c03306bcSpooka * notice, this list of conditions and the following disclaimer in the 16c03306bcSpooka * documentation and/or other materials provided with the distribution. 17c03306bcSpooka * 18c03306bcSpooka * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 19c03306bcSpooka * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20c03306bcSpooka * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21c03306bcSpooka * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22c03306bcSpooka * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23c03306bcSpooka * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24c03306bcSpooka * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25c03306bcSpooka * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26c03306bcSpooka * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27c03306bcSpooka * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28c03306bcSpooka * SUCH DAMAGE. 29c03306bcSpooka */ 30c03306bcSpooka 31c03306bcSpooka #include <sys/cdefs.h> 32*3290c1c7Spooka __KERNEL_RCSID(0, "$NetBSD: threads.c,v 1.22 2014/03/15 15:15:27 pooka Exp $"); 33c03306bcSpooka 34c03306bcSpooka #include <sys/param.h> 359970bb9eSpooka #include <sys/atomic.h> 36c03306bcSpooka #include <sys/kmem.h> 37c03306bcSpooka #include <sys/kthread.h> 38c91a5143Spooka #include <sys/malloc.h> 39c03306bcSpooka #include <sys/systm.h> 40c03306bcSpooka 41c03306bcSpooka #include <rump/rumpuser.h> 42c03306bcSpooka 43c03306bcSpooka #include "rump_private.h" 44c03306bcSpooka 45c03306bcSpooka struct kthdesc { 46c03306bcSpooka void (*f)(void *); 47c03306bcSpooka void *arg; 48c03306bcSpooka struct lwp *mylwp; 49c03306bcSpooka }; 50c03306bcSpooka 51b3ce1408Spooka static bool threads_are_go; 52b3ce1408Spooka static struct rumpuser_mtx *thrmtx; 53b3ce1408Spooka static struct rumpuser_cv *thrcv; 54b3ce1408Spooka 55c03306bcSpooka static void * 56c03306bcSpooka threadbouncer(void *arg) 57c03306bcSpooka { 58c03306bcSpooka struct kthdesc *k = arg; 591029997fSpooka struct lwp *l = k->mylwp; 60c03306bcSpooka void (*f)(void *); 61c03306bcSpooka void *thrarg; 62c03306bcSpooka 63c03306bcSpooka f = k->f; 64c03306bcSpooka thrarg = k->arg; 651029997fSpooka 66b3ce1408Spooka /* don't allow threads to run before all CPUs have fully attached */ 67b3ce1408Spooka if (!threads_are_go) { 68b3ce1408Spooka rumpuser_mutex_enter_nowrap(thrmtx); 69b3ce1408Spooka while (!threads_are_go) { 70b3ce1408Spooka rumpuser_cv_wait_nowrap(thrcv, thrmtx); 71b3ce1408Spooka } 72b3ce1408Spooka rumpuser_mutex_exit(thrmtx); 73b3ce1408Spooka } 74b3ce1408Spooka 7519cde6b5Spooka /* schedule ourselves */ 76*3290c1c7Spooka rump_lwproc_curlwp_set(l); 77c03306bcSpooka rump_schedule(); 78c03306bcSpooka 79c91a5143Spooka /* free dance struct */ 80c91a5143Spooka free(k, M_TEMP); 81c91a5143Spooka 82c03306bcSpooka if ((curlwp->l_pflag & LP_MPSAFE) == 0) 83c03306bcSpooka KERNEL_LOCK(1, NULL); 84c03306bcSpooka 85c03306bcSpooka f(thrarg); 86c03306bcSpooka 87c03306bcSpooka panic("unreachable, should kthread_exit()"); 88c03306bcSpooka } 89c03306bcSpooka 90b3ce1408Spooka void 91b3ce1408Spooka rump_thread_init(void) 92b3ce1408Spooka { 93b3ce1408Spooka 94e204757dSpooka rumpuser_mutex_init(&thrmtx, RUMPUSER_MTX_SPIN); 95b3ce1408Spooka rumpuser_cv_init(&thrcv); 96b3ce1408Spooka } 97b3ce1408Spooka 98b3ce1408Spooka void 99b3ce1408Spooka rump_thread_allow(void) 100b3ce1408Spooka { 101b3ce1408Spooka 102b3ce1408Spooka rumpuser_mutex_enter(thrmtx); 103b3ce1408Spooka threads_are_go = true; 104b3ce1408Spooka rumpuser_cv_broadcast(thrcv); 105b3ce1408Spooka rumpuser_mutex_exit(thrmtx); 106b3ce1408Spooka 107b3ce1408Spooka } 108b3ce1408Spooka 109bbdefb24Spooka static struct { 110bbdefb24Spooka const char *t_name; 111bbdefb24Spooka bool t_ncmp; 112bbdefb24Spooka } nothreads[] = { 113bbdefb24Spooka { "vrele", false }, 114350afea2Spooka { "vdrain", false }, 115bbdefb24Spooka { "cachegc", false }, 116bbdefb24Spooka { "nfssilly", false }, 117bbdefb24Spooka { "unpgc", false }, 118bbdefb24Spooka { "pmf", true }, 119bbdefb24Spooka { "xcall", true }, 120bbdefb24Spooka }; 121bbdefb24Spooka 122c03306bcSpooka int 123c03306bcSpooka kthread_create(pri_t pri, int flags, struct cpu_info *ci, 124c03306bcSpooka void (*func)(void *), void *arg, lwp_t **newlp, const char *fmt, ...) 125c03306bcSpooka { 126c03306bcSpooka char thrstore[MAXCOMLEN]; 127c03306bcSpooka const char *thrname = NULL; 128c03306bcSpooka va_list ap; 129c03306bcSpooka struct kthdesc *k; 130c03306bcSpooka struct lwp *l; 131c03306bcSpooka int rv; 132c03306bcSpooka 133c03306bcSpooka thrstore[0] = '\0'; 134c03306bcSpooka if (fmt) { 135c03306bcSpooka va_start(ap, fmt); 136c03306bcSpooka vsnprintf(thrstore, sizeof(thrstore), fmt, ap); 137c03306bcSpooka va_end(ap); 138c03306bcSpooka thrname = thrstore; 139c03306bcSpooka } 140c03306bcSpooka 141c03306bcSpooka /* 142c03306bcSpooka * We don't want a module unload thread. 143c03306bcSpooka * (XXX: yes, this is a kludge too, and the kernel should 144c03306bcSpooka * have a more flexible method for configuring which threads 145c03306bcSpooka * we want). 146c03306bcSpooka */ 147c03306bcSpooka if (strcmp(thrstore, "modunload") == 0) { 148c03306bcSpooka return 0; 149c03306bcSpooka } 150c03306bcSpooka 151c03306bcSpooka if (!rump_threads) { 152bbdefb24Spooka bool matched; 153bbdefb24Spooka int i; 154bbdefb24Spooka 155bbdefb24Spooka /* do we want to fake it? */ 156bbdefb24Spooka for (i = 0; i < __arraycount(nothreads); i++) { 157bbdefb24Spooka if (nothreads[i].t_ncmp) { 158bbdefb24Spooka matched = strncmp(thrstore, nothreads[i].t_name, 159bbdefb24Spooka strlen(nothreads[i].t_name)) == 0; 160bbdefb24Spooka } else { 161bbdefb24Spooka matched = strcmp(thrstore, 162bbdefb24Spooka nothreads[i].t_name) == 0; 163bbdefb24Spooka } 164bbdefb24Spooka if (matched) { 165bbdefb24Spooka aprint_error("rump kernel threads not enabled, " 166bbdefb24Spooka "%s not functional\n", nothreads[i].t_name); 167c03306bcSpooka return 0; 168bbdefb24Spooka } 169bbdefb24Spooka } 170bbdefb24Spooka panic("threads not available"); 171c03306bcSpooka } 172c03306bcSpooka KASSERT(fmt != NULL); 173c03306bcSpooka 174c91a5143Spooka k = malloc(sizeof(*k), M_TEMP, M_WAITOK); 175c03306bcSpooka k->f = func; 176c03306bcSpooka k->arg = arg; 17741a10084Spooka k->mylwp = l = rump__lwproc_alloclwp(&proc0); 178d11274ecSpooka l->l_flag |= LW_SYSTEM; 179c03306bcSpooka if (flags & KTHREAD_MPSAFE) 180c03306bcSpooka l->l_pflag |= LP_MPSAFE; 1811029997fSpooka if (flags & KTHREAD_INTR) 1821029997fSpooka l->l_pflag |= LP_INTR; 18362e84772Spooka if (ci) { 18462e84772Spooka l->l_pflag |= LP_BOUND; 185d11274ecSpooka l->l_target_cpu = ci; 18662e84772Spooka } 1872f3605b7Spooka if (thrname) { 1882f3605b7Spooka l->l_name = kmem_alloc(MAXCOMLEN, KM_SLEEP); 1892f3605b7Spooka strlcpy(l->l_name, thrname, MAXCOMLEN); 1902f3605b7Spooka } 1912f3605b7Spooka 1929970bb9eSpooka rv = rumpuser_thread_create(threadbouncer, k, thrname, 193e345c833Spooka (flags & KTHREAD_MUSTJOIN) == KTHREAD_MUSTJOIN, 194e345c833Spooka pri, ci ? ci->ci_index : -1, &l->l_ctxlink); 195c03306bcSpooka if (rv) 196c03306bcSpooka return rv; 197c03306bcSpooka 1989970bb9eSpooka if (newlp) { 199c03306bcSpooka *newlp = l; 2009970bb9eSpooka } else { 201000492e6Srmind KASSERT((flags & KTHREAD_MUSTJOIN) == 0); 2029970bb9eSpooka } 2039970bb9eSpooka 204c03306bcSpooka return 0; 205c03306bcSpooka } 206c03306bcSpooka 207c03306bcSpooka void 208c03306bcSpooka kthread_exit(int ecode) 209c03306bcSpooka { 210c03306bcSpooka 211c03306bcSpooka if ((curlwp->l_pflag & LP_MPSAFE) == 0) 212630dc3f6Spooka KERNEL_UNLOCK_LAST(NULL); 21311f8c2f9Spooka rump_lwproc_releaselwp(); 2149970bb9eSpooka /* unschedule includes membar */ 215c03306bcSpooka rump_unschedule(); 216c03306bcSpooka rumpuser_thread_exit(); 217c03306bcSpooka } 2189970bb9eSpooka 2199970bb9eSpooka int 2209970bb9eSpooka kthread_join(struct lwp *l) 2219970bb9eSpooka { 2229970bb9eSpooka int rv; 2239970bb9eSpooka 2249970bb9eSpooka KASSERT(l->l_ctxlink != NULL); 2259970bb9eSpooka rv = rumpuser_thread_join(l->l_ctxlink); 2269970bb9eSpooka membar_consumer(); 2279970bb9eSpooka 2289970bb9eSpooka return rv; 2299970bb9eSpooka } 230