intr.c revision 1.6 1 /* $NetBSD: intr.c,v 1.6 2008/10/10 13:14:41 pooka Exp $ */
2
3 /*
4 * Copyright (c) 2008 Antti Kantee. All Rights Reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28 #include <sys/param.h>
29 #include <sys/cpu.h>
30 #include <sys/kthread.h>
31 #include <sys/intr.h>
32
33 #include <rump/rumpuser.h>
34
35 #include "rump_private.h"
36
37 /*
38 * Interrupt simulator. It executes hardclock() and softintrs.
39 */
40
41 struct softint {
42 void (*si_func)(void *);
43 void *si_arg;
44 bool si_onlist;
45 bool si_mpsafe;
46
47 LIST_ENTRY(softint) si_entries;
48 };
49 static LIST_HEAD(, softint) si_pending = LIST_HEAD_INITIALIZER(si_pending);
50 static kmutex_t si_mtx;
51 static kcondvar_t si_cv;
52
53 static void
54 intr_worker(void *arg)
55 {
56 struct softint *si;
57 void (*func)(void *) = NULL;
58 void *funarg = NULL; /* XXX gcc */
59 bool mpsafe = false; /* XXX gcc */
60
61 rump_setup_curlwp(0, rump_nextlid(), 1);
62
63 for (;;) {
64 /*
65 * XXX: not exactly executed once per tick, but without
66 * a proper timer ticktocking we don't really care.
67 */
68 callout_hardclock();
69
70 mutex_enter(&si_mtx);
71 if (LIST_EMPTY(&si_pending)) {
72 cv_timedwait(&si_cv, &si_mtx, 1);
73 } else {
74 si = LIST_FIRST(&si_pending);
75 func = si->si_func;
76 funarg = si->si_arg;
77 mpsafe = si->si_mpsafe;
78
79 si->si_onlist = false;
80 LIST_REMOVE(si, si_entries);
81 }
82 mutex_exit(&si_mtx);
83
84 if (func) {
85 if (!mpsafe)
86 KERNEL_LOCK(1, curlwp);
87 func(funarg);
88 func = NULL;
89 if (!mpsafe)
90 KERNEL_UNLOCK_ONE(curlwp);
91 }
92 }
93 }
94
95 void
96 softint_init(struct cpu_info *ci)
97 {
98 int rv;
99
100 mutex_init(&si_mtx, MUTEX_DEFAULT, IPL_NONE);
101 cv_init(&si_cv, "intrw8");
102
103 /* XXX: should have separate "wanttimer" control */
104 if (rump_threads) {
105 rv = kthread_create(PRI_NONE, 0, NULL, intr_worker, NULL, NULL,
106 "rumpmtr");
107 if (rv)
108 panic("timer thread creation failed %d", rv);
109 }
110 }
111
112 /*
113 * Soft interrupts bring two choices. If we are running with thread
114 * support enabled, defer execution, otherwise execute in place.
115 * See softint_schedule().
116 *
117 * As there is currently no clear concept of when a thread finishes
118 * work (although rump_clear_curlwp() is close), simply execute all
119 * softints in the timer thread. This is probably not the most
120 * efficient method, but good enough for now.
121 */
122 void *
123 softint_establish(u_int flags, void (*func)(void *), void *arg)
124 {
125 struct softint *si;
126
127 si = kmem_alloc(sizeof(*si), KM_SLEEP);
128 si->si_func = func;
129 si->si_arg = arg;
130 si->si_onlist = false;
131 si->si_mpsafe = flags & SOFTINT_MPSAFE;
132
133 return si;
134 }
135
136 void
137 softint_schedule(void *arg)
138 {
139 struct softint *si = arg;
140
141 if (!rump_threads) {
142 si->si_func(si->si_arg);
143 } else {
144 mutex_enter(&si_mtx);
145 if (!si->si_onlist) {
146 LIST_INSERT_HEAD(&si_pending, si, si_entries);
147 si->si_onlist = true;
148 }
149 cv_signal(&si_cv);
150 mutex_exit(&si_mtx);
151 }
152 }
153
154 bool
155 cpu_intr_p()
156 {
157
158 return false;
159 }
160