FreeBSD/Linux Kernel Cross Reference
sys/kern/eventcount.c
1 /*
2 * Mach Operating System
3 * Copyright (c) 1993-1987 Carnegie Mellon University
4 * All Rights Reserved.
5 *
6 * Permission to use, copy, modify and distribute this software and its
7 * documentation is hereby granted, provided that both the copyright
8 * notice and this permission notice appear in all copies of the
9 * software, derivative works or modified versions, and any portions
10 * thereof, and that both notices appear in supporting documentation.
11 *
12 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15 *
16 * Carnegie Mellon requests users of this software to return to
17 *
18 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
19 * School of Computer Science
20 * Carnegie Mellon University
21 * Pittsburgh PA 15213-3890
22 *
23 * any improvements or extensions that they make and grant Carnegie Mellon
24 * the rights to redistribute these changes.
25 */
26 /*
27 * HISTORY
28 * $Log: eventcount.c,v $
29 * Revision 2.13 93/11/17 17:08:47 dbg
30 * Changed evc_notify_abort to evc_wait_interrupt, since it is only
31 * used by thread_halt (to 'interrupt' an evc_wait). It knows
32 * about the evc_wait continuation.
33 * [93/08/20 dbg]
34 *
35 * Break up thread lock. Use thread_will_wait and thread_go
36 * to change thread state.
37 * [93/05/26 dbg]
38 *
39 * Declare contination functions as returning 'no_return'.
40 *
41 * Added return code to evc_init. Fixed locking in evc_signal.
42 *
43 * Removed include of kern/sched.h. Added ANSI prototypes.
44 * Removed simpler_thread_setrun: we'll fix thread_setrun
45 * instead.
46 * [93/05/21 dbg]
47 *
48 * Revision 2.12 93/08/10 15:11:22 mrt
49 * Added evc_wait_clear. Always clears count before blocking.
50 * [93/03/22 cmaeda]
51 *
52 * Revision 2.11 93/05/15 18:54:40 mrt
53 * machparam.h -> machspl.h
54 *
55 * Revision 2.10 93/02/01 09:50:07 danner
56 * Remove evc_signal panic for suspension case.
57 * [93/01/28 danner]
58 *
59 * Revision 2.9 93/01/24 13:18:45 danner
60 * rename notify routines; prototypes.
61 * [93/01/22 danner]
62 *
63 * Revision 2.8 93/01/21 12:21:49 danner
64 * Added evc_notify_thread_destroy_bkpt and
65 * evc_notify_thread_destroy.
66 * [93/01/20 bershad]
67 *
68 * Revision 2.7 93/01/14 17:33:59 danner
69 * Typecast assert_wait arguments.
70 * [93/01/12 danner]
71 * Fixes for multiprocessor usage.
72 * [92/11/16 jfriedl]
73 * Fixed two-for-one bug in evc_wait, per jcb's report.
74 * See comments in code.
75 * [92/12/15 af]
76 * Proper spl typing.
77 * [92/11/30 af]
78 *
79 * Revision 2.6 92/08/03 17:36:55 jfriedl
80 * removed silly prototypes
81 * [92/08/02 jfriedl]
82 *
83 * Revision 2.5 92/05/21 17:13:12 jfriedl
84 * Added void type to functions that needed it.
85 * [92/05/16 jfriedl]
86 *
87 * Revision 2.4 92/01/03 20:40:02 dbg
88 * Made user-safe with a small translation table.
89 * This all will be refined at a later time.
90 * [91/12/27 af]
91 *
92 * Revision 2.3 91/12/14 14:31:43 jsb
93 * Replaced gimmeabreak calls with panics.
94 *
95 * Revision 2.2 91/12/13 14:54:44 jsb
96 * Created.
97 * [91/11/01 af]
98 *
99 */
100 /*
101 * File: eventcount.c
102 * Author: Alessandro Forin
103 * Date: 10/91
104 *
105 * Eventcounters, for user-level drivers synchronization
106 *
107 */
108
109
110 #include <cpus.h>
111
112 #include <mach/machine.h>
113 #include <kern/ast.h>
114 #include <kern/cpu_number.h>
115 #include <kern/lock.h>
116 #include <kern/memory.h>
117 #include <kern/processor.h>
118 #include <kern/queue.h>
119 #include <kern/sched_policy.h>
120 #include <kern/sched_prim.h>
121 #include <kern/thread.h>
122 #include <machine/machspl.h> /* For def'n of splsched() */
123
124 #include <kern/eventcount.h>
125
126 #define MAX_EVCS 10 /* xxx for now */
127 evc_t all_eventcounters[MAX_EVCS];
128
129 /*
130 * Initialization
131 */
132 kern_return_t
133 evc_init(evc_t ev)
134 {
135 int i;
136
137 bzero(ev, sizeof(*ev));
138
139 /* keep track of who is who */
140 for (i = 0; i < MAX_EVCS; i++)
141 if (all_eventcounters[i] == 0) break;
142 if (i == MAX_EVCS) {
143 #if 0
144 printf("Too many eventcounters\n");
145 #endif
146 return KERN_RESOURCE_SHORTAGE;
147 }
148
149 all_eventcounters[i] = ev;
150 ev->ev_id = i;
151 ev->sanity = ev;
152 ev->waiting_thread = THREAD_NULL;
153 simple_lock_init(&ev->lock);
154
155 return KERN_SUCCESS;
156 }
157
158 /*
159 * Finalization
160 */
161 void
162 evc_destroy(evc_t ev)
163 {
164 evc_signal(ev);
165 ev->sanity = 0;
166 if (all_eventcounters[ev->ev_id] == ev)
167 all_eventcounters[ev->ev_id] = 0;
168 ev->ev_id = -1;
169 }
170
171 /*
172 * Just so that we return success, and give
173 * up the stack while blocked
174 */
175 no_return
176 evc_continue(void)
177 {
178 thread_syscall_return(KERN_SUCCESS);
179 /* NOTREACHED */
180 }
181
182 /*
183 * User-trappable
184 */
185 kern_return_t evc_wait(natural_t ev_id)
186 {
187 spl_t s;
188 kern_return_t ret;
189 evc_t ev;
190
191 if ((ev_id >= MAX_EVCS) ||
192 ((ev = all_eventcounters[ev_id]) == 0) ||
193 (ev->ev_id != ev_id) || (ev->sanity != ev))
194 return KERN_INVALID_ARGUMENT;
195
196 s = splsched();
197 simple_lock(&ev->lock);
198 /*
199 * The values assumed by the "count" field are
200 * as follows:
201 * 0 At initialization time, and with no
202 * waiting thread means no events pending;
203 * with waiting thread means the event
204 * was signalled and the thread not yet resumed
205 * -1 no events, there must be a waiting thread
206 * N>0 no waiting thread means N pending,
207 * with waiting thread N-1 pending.
208 *
209 */
210 if (ev->count > 0) {
211 ev->count--;
212 ret = KERN_SUCCESS;
213 } else {
214 if (ev->waiting_thread == THREAD_NULL) {
215 thread_t thread = current_thread();
216 ev->count--;
217 ev->waiting_thread = thread;
218 thread_will_wait(thread);
219 simple_unlock(&ev->lock);
220 thread_block(evc_continue);
221 /* NOTREACHED */
222 }
223 ret = KERN_NO_SPACE; /* XX */
224 }
225 simple_unlock(&ev->lock);
226 splx(s);
227 return ret;
228 }
229
230 /*
231 * User-trappable
232 */
233 kern_return_t evc_wait_clear(natural_t ev_id)
234 {
235 spl_t s;
236 evc_t ev;
237
238 if ((ev_id >= MAX_EVCS) ||
239 ((ev = all_eventcounters[ev_id]) == 0) ||
240 (ev->ev_id != ev_id) || (ev->sanity != ev))
241 return KERN_INVALID_ARGUMENT;
242
243 s = splsched();
244 simple_lock(&ev->lock);
245
246 /*
247 * The values assumed by the "count" field are
248 * as follows:
249 * 0 At initialization time, and with no
250 * waiting thread means no events pending;
251 * with waiting thread means the event
252 * was signalled and the thread not yet resumed
253 * -1 no events, there must be a waiting thread
254 * N>0 no waiting thread means N pending,
255 * with waiting thread N-1 pending.
256 *
257 */
258 /*
259 * Note that we always clear count before blocking.
260 */
261 if (ev->waiting_thread == THREAD_NULL) {
262 thread_t thread = current_thread();
263 ev->count = -1;
264 ev->waiting_thread = thread;
265 thread_will_wait(thread);
266 simple_unlock(&ev->lock);
267 thread_block(evc_continue);
268 /* NOTREACHED */
269 }
270
271 simple_unlock(&ev->lock);
272 splx(s);
273 return KERN_NO_SPACE; /* XX */
274 }
275
276 /*
277 * Called exclusively from interrupt context
278 */
279 void
280 evc_signal(evc_t ev)
281 {
282 thread_t thread;
283 spl_t s;
284
285 if (ev->sanity != ev)
286 return;
287
288 s = splsched();
289 simple_lock(&ev->lock);
290 ev->count++;
291 thread = ev->waiting_thread;
292 if (thread != THREAD_NULL)
293 {
294 ev->waiting_thread = 0;
295 thread_go(thread);
296 }
297
298 simple_unlock(&ev->lock);
299 splx(s);
300 }
301
302 /*
303 * Interrupt an evc_wait. Called by thread_abort.
304 * Returns TRUE if the thread was waiting.
305 *
306 * Thread is suspended on entry.
307 *
308 * (This stuff needs to be fixed.)
309 */
310 boolean_t evc_wait_interrupt(thread_t thread)
311 {
312 int i;
313 evc_t ev;
314 spl_t s;
315
316 if (thread->swap_func != evc_continue)
317 return FALSE;
318
319 s = splsched();
320 for (i = 0; i < MAX_EVCS; i++) {
321 ev = all_eventcounters[i];
322 if (ev) {
323 simple_lock(&ev->lock);
324 if (ev->waiting_thread == thread)
325 {
326 ev->waiting_thread = 0;
327 /* Removal of a waiting thread has to bump the count by one */
328 ev->count++;
329 }
330 simple_unlock(&ev->lock);
331 }
332 }
333 splx(s);
334
335 thread->swap_func = thread_exception_return;
336 thread_set_syscall_return(thread, KERN_ABORTED);
337 return TRUE;
338 }
339
Cache object: e61b0c68fc17df876e299fe64ad38fe1
|