intr.c revision 1.3.6.2 1 /* $NetBSD: intr.c,v 1.3.6.2 2008/12/13 01:15:34 haad 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 time_t time_uptime = 1;
42
43 struct softint {
44 void (*si_func)(void *);
45 void *si_arg;
46 bool si_onlist;
47 bool si_mpsafe;
48
49 LIST_ENTRY(softint) si_entries;
50 };
51 static LIST_HEAD(, softint) si_pending = LIST_HEAD_INITIALIZER(si_pending);
52 static kmutex_t si_mtx;
53 static kcondvar_t si_cv;
54
55 static void
56 intr_worker(void *arg)
57 {
58 struct softint *si;
59 void (*func)(void *) = NULL;
60 void *funarg = NULL; /* XXX gcc */
61 bool mpsafe = false; /* XXX gcc */
62 int ticks;
63
64 for (ticks = 0;;ticks++) {
65 /*
66 * XXX: not exactly executed once per tick, but without
67 * a proper timer ticktocking we don't really care.
68 */
69 callout_hardclock();
70
71 /* advance uptime with the same leisurely attitude */
72 if (ticks & 0x80) {
73 time_uptime++;
74 ticks = 0;
75 }
76
77 mutex_enter(&si_mtx);
78 if (LIST_EMPTY(&si_pending)) {
79 cv_timedwait(&si_cv, &si_mtx, 1);
80 } else {
81 si = LIST_FIRST(&si_pending);
82 func = si->si_func;
83 funarg = si->si_arg;
84 mpsafe = si->si_mpsafe;
85
86 si->si_onlist = false;
87 LIST_REMOVE(si, si_entries);
88 }
89 mutex_exit(&si_mtx);
90
91 if (func) {
92 if (!mpsafe)
93 KERNEL_LOCK(1, curlwp);
94 func(funarg);
95 func = NULL;
96 if (!mpsafe)
97 KERNEL_UNLOCK_ONE(curlwp);
98 }
99 }
100 }
101
102 void
103 softint_init(struct cpu_info *ci)
104 {
105 int rv;
106
107 mutex_init(&si_mtx, MUTEX_DEFAULT, IPL_NONE);
108 cv_init(&si_cv, "intrw8");
109
110 /* XXX: should have separate "wanttimer" control */
111 if (rump_threads) {
112 rv = kthread_create(PRI_NONE, 0, NULL, intr_worker, NULL, NULL,
113 "rumpmtr");
114 if (rv)
115 panic("timer thread creation failed %d", rv);
116 }
117 }
118
119 /*
120 * Soft interrupts bring two choices. If we are running with thread
121 * support enabled, defer execution, otherwise execute in place.
122 * See softint_schedule().
123 *
124 * As there is currently no clear concept of when a thread finishes
125 * work (although rump_clear_curlwp() is close), simply execute all
126 * softints in the timer thread. This is probably not the most
127 * efficient method, but good enough for now.
128 */
129 void *
130 softint_establish(u_int flags, void (*func)(void *), void *arg)
131 {
132 struct softint *si;
133
134 si = kmem_alloc(sizeof(*si), KM_SLEEP);
135 si->si_func = func;
136 si->si_arg = arg;
137 si->si_onlist = false;
138 si->si_mpsafe = flags & SOFTINT_MPSAFE;
139
140 return si;
141 }
142
143 void
144 softint_schedule(void *arg)
145 {
146 struct softint *si = arg;
147
148 if (!rump_threads) {
149 si->si_func(si->si_arg);
150 } else {
151 mutex_enter(&si_mtx);
152 if (!si->si_onlist) {
153 LIST_INSERT_HEAD(&si_pending, si, si_entries);
154 si->si_onlist = true;
155 }
156 cv_signal(&si_cv);
157 mutex_exit(&si_mtx);
158 }
159 }
160
161 bool
162 cpu_intr_p(void)
163 {
164
165 return false;
166 }
167