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