threads.c revision 1.10 1 /* $NetBSD: threads.c,v 1.10 2010/05/31 23:09:29 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.10 2010/05/31 23:09:29 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/systm.h>
39
40 #include <machine/stdarg.h>
41
42 #include <rump/rumpuser.h>
43
44 #include "rump_private.h"
45
46 struct kthdesc {
47 void (*f)(void *);
48 void *arg;
49 struct lwp *mylwp;
50 };
51
52 static void *
53 threadbouncer(void *arg)
54 {
55 struct kthdesc *k = arg;
56 struct lwp *l = k->mylwp;
57 void (*f)(void *);
58 void *thrarg;
59
60 f = k->f;
61 thrarg = k->arg;
62 rumpuser_free(k);
63
64 /* schedule ourselves */
65 rumpuser_set_curlwp(l);
66 rump_schedule();
67
68 if ((curlwp->l_pflag & LP_MPSAFE) == 0)
69 KERNEL_LOCK(1, NULL);
70
71 f(thrarg);
72
73 panic("unreachable, should kthread_exit()");
74 }
75
76 int
77 kthread_create(pri_t pri, int flags, struct cpu_info *ci,
78 void (*func)(void *), void *arg, lwp_t **newlp, const char *fmt, ...)
79 {
80 char thrstore[MAXCOMLEN];
81 const char *thrname = NULL;
82 va_list ap;
83 struct kthdesc *k;
84 struct lwp *l;
85 int rv;
86
87 thrstore[0] = '\0';
88 if (fmt) {
89 va_start(ap, fmt);
90 vsnprintf(thrstore, sizeof(thrstore), fmt, ap);
91 va_end(ap);
92 thrname = thrstore;
93 }
94
95 /*
96 * We don't want a module unload thread.
97 * (XXX: yes, this is a kludge too, and the kernel should
98 * have a more flexible method for configuring which threads
99 * we want).
100 */
101 if (strcmp(thrstore, "modunload") == 0) {
102 return 0;
103 }
104
105 if (!rump_threads) {
106 /* fake them */
107 if (strcmp(thrstore, "vrele") == 0) {
108 printf("rump warning: threads not enabled, not starting"
109 " vrele thread\n");
110 return 0;
111 } else if (strcmp(thrstore, "cachegc") == 0) {
112 printf("rump warning: threads not enabled, not starting"
113 " namecache g/c thread\n");
114 return 0;
115 } else if (strcmp(thrstore, "nfssilly") == 0) {
116 printf("rump warning: threads not enabled, not enabling"
117 " nfs silly rename\n");
118 return 0;
119 } else if (strcmp(thrstore, "unpgc") == 0) {
120 printf("rump warning: threads not enabled, not enabling"
121 " UNP garbage collection\n");
122 return 0;
123 } else if (strncmp(thrstore, "pmf", sizeof("pmf")-1) == 0) {
124 printf("rump warning: threads not enabled, not enabling"
125 " pmf thread\n");
126 return 0;
127 } else if (strncmp(thrstore, "xcall", sizeof("xcall")-1) == 0) {
128 printf("rump warning: threads not enabled, CPU xcall"
129 " not functional\n");
130 return 0;
131 } else
132 panic("threads not available, setenv RUMP_THREADS 1");
133 }
134 KASSERT(fmt != NULL);
135
136 k = rumpuser_malloc(sizeof(struct kthdesc), 0);
137 k->f = func;
138 k->arg = arg;
139 k->mylwp = l = rump_lwp_alloc(0, rump_nextlid());
140 l->l_flag |= LW_SYSTEM;
141 if (flags & KTHREAD_MPSAFE)
142 l->l_pflag |= LP_MPSAFE;
143 if (flags & KTHREAD_INTR)
144 l->l_pflag |= LP_INTR;
145 if (ci) {
146 l->l_pflag |= LP_BOUND;
147 l->l_target_cpu = ci;
148 }
149 if (thrname) {
150 l->l_name = kmem_alloc(MAXCOMLEN, KM_SLEEP);
151 strlcpy(l->l_name, thrname, MAXCOMLEN);
152 }
153
154 rv = rumpuser_thread_create(threadbouncer, k, thrname,
155 (flags & KTHREAD_JOINABLE) == KTHREAD_JOINABLE, &l->l_ctxlink);
156 if (rv)
157 return rv;
158
159 if (newlp) {
160 *newlp = l;
161 } else {
162 KASSERT((flags & KTHREAD_JOINABLE) == 0);
163 }
164
165 return 0;
166 }
167
168 void
169 kthread_exit(int ecode)
170 {
171
172 if ((curlwp->l_pflag & LP_MPSAFE) == 0)
173 KERNEL_UNLOCK_LAST(NULL);
174 rump_lwp_release(curlwp);
175 /* unschedule includes membar */
176 rump_unschedule();
177 rumpuser_thread_exit();
178 }
179
180 int
181 kthread_join(struct lwp *l)
182 {
183 int rv;
184
185 KASSERT(l->l_ctxlink != NULL);
186 rv = rumpuser_thread_join(l->l_ctxlink);
187 membar_consumer();
188
189 return rv;
190 }
191