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.12 93/08/10 15:11:22 mrt
30 * Added evc_wait_clear. Always clears count before blocking.
31 * [93/03/22 cmaeda]
32 *
33 * Revision 2.11 93/05/15 18:54:40 mrt
34 * machparam.h -> machspl.h
35 *
36 * Revision 2.10 93/02/01 09:50:07 danner
37 * Remove evc_signal panic for suspension case.
38 * [93/01/28 danner]
39 *
40 * Revision 2.9 93/01/24 13:18:45 danner
41 * rename notify routines; prototypes.
42 * [93/01/22 danner]
43 *
44 * Revision 2.8 93/01/21 12:21:49 danner
45 * Added evc_notify_thread_destroy_bkpt and
46 * evc_notify_thread_destroy.
47 * [93/01/20 bershad]
48 *
49 * Revision 2.7 93/01/14 17:33:59 danner
50 * Typecast assert_wait arguments.
51 * [93/01/12 danner]
52 * Fixes for multiprocessor usage.
53 * [92/11/16 jfriedl]
54 * Fixed two-for-one bug in evc_wait, per jcb's report.
55 * See comments in code.
56 * [92/12/15 af]
57 * Proper spl typing.
58 * [92/11/30 af]
59 *
60 * Revision 2.6 92/08/03 17:36:55 jfriedl
61 * removed silly prototypes
62 * [92/08/02 jfriedl]
63 *
64 * Revision 2.5 92/05/21 17:13:12 jfriedl
65 * Added void type to functions that needed it.
66 * [92/05/16 jfriedl]
67 *
68 * Revision 2.4 92/01/03 20:40:02 dbg
69 * Made user-safe with a small translation table.
70 * This all will be refined at a later time.
71 * [91/12/27 af]
72 *
73 * Revision 2.3 91/12/14 14:31:43 jsb
74 * Replaced gimmeabreak calls with panics.
75 *
76 * Revision 2.2 91/12/13 14:54:44 jsb
77 * Created.
78 * [91/11/01 af]
79 *
80 */
81 /*
82 * File: eventcount.c
83 * Author: Alessandro Forin
84 * Date: 10/91
85 *
86 * Eventcounters, for user-level drivers synchronization
87 *
88 */
89
90
91 #include <cpus.h>
92
93 #include <mach/machine.h>
94 #include <kern/ast.h>
95 #include <kern/cpu_number.h>
96 #include <kern/lock.h>
97 #include <kern/processor.h>
98 #include <kern/queue.h>
99 #include <kern/sched.h>
100 #include <kern/sched_prim.h>
101 #include <kern/thread.h>
102 #include <machine/machspl.h> /* For def'n of splsched() */
103
104 #include <kern/eventcount.h>
105
106
107 #if NCPUS <= 1
108 void simpler_thread_setrun(
109 thread_t th,
110 boolean_t may_preempt); /* forward */
111 #endif
112
113 #define MAX_EVCS 10 /* xxx for now */
114 evc_t all_eventcounters[MAX_EVCS];
115
116 /*
117 * Initialization
118 */
119 void
120 evc_init(evc_t ev)
121 {
122 int i;
123
124 bzero((char*)ev, sizeof(*ev));
125
126 /* keep track of who is who */
127 for (i = 0; i < MAX_EVCS; i++)
128 if (all_eventcounters[i] == 0) break;
129 if (i == MAX_EVCS) {
130 printf("Too many eventcounters\n");
131 return;
132 }
133
134 all_eventcounters[i] = ev;
135 ev->ev_id = i;
136 ev->sanity = ev;
137 ev->waiting_thread = THREAD_NULL;
138 simple_lock_init(&ev->lock);
139 }
140
141 /*
142 * Finalization
143 */
144 void
145 evc_destroy(evc_t ev)
146 {
147 evc_signal(ev);
148 ev->sanity = 0;
149 if (all_eventcounters[ev->ev_id] == ev)
150 all_eventcounters[ev->ev_id] = 0;
151 ev->ev_id = -1;
152 }
153
154 /*
155 * Thread termination.
156 * HORRIBLE. This stuff needs to be fixed.
157 */
158 void evc_notify_abort(thread_t thread)
159 {
160 int i;
161 evc_t ev;
162 int s = splsched();
163 for (i = 0; i < MAX_EVCS; i++) {
164 ev = all_eventcounters[i];
165 if (ev) {
166 simple_lock(&ev->lock);
167 if (ev->waiting_thread == thread)
168 {
169 ev->waiting_thread = 0;
170 /* Removal of a waiting thread has to bump the count by one */
171 ev->count++;
172 }
173 simple_unlock(&ev->lock);
174 }
175 }
176 splx(s);
177 }
178
179 /*
180 * Just so that we return success, and give
181 * up the stack while blocked
182 */
183 static void
184 evc_continue(void)
185 {
186 thread_syscall_return(KERN_SUCCESS);
187 /* NOTREACHED */
188 }
189
190 /*
191 * User-trappable
192 */
193 kern_return_t evc_wait(natural_t ev_id)
194 {
195 spl_t s;
196 kern_return_t ret;
197 evc_t ev;
198
199 if ((ev_id >= MAX_EVCS) ||
200 ((ev = all_eventcounters[ev_id]) == 0) ||
201 (ev->ev_id != ev_id) || (ev->sanity != ev))
202 return KERN_INVALID_ARGUMENT;
203
204 s = splsched();
205 simple_lock(&ev->lock);
206 /*
207 * The values assumed by the "count" field are
208 * as follows:
209 * 0 At initialization time, and with no
210 * waiting thread means no events pending;
211 * with waiting thread means the event
212 * was signalled and the thread not yet resumed
213 * -1 no events, there must be a waiting thread
214 * N>0 no waiting thread means N pending,
215 * with waiting thread N-1 pending.
216 *
217 */
218 if (ev->count > 0) {
219 ev->count--;
220 ret = KERN_SUCCESS;
221 } else {
222 if (ev->waiting_thread == THREAD_NULL) {
223 ev->count--;
224 ev->waiting_thread = current_thread();
225 assert_wait((event_t) 0, TRUE); /* ifnot race */
226 simple_unlock(&ev->lock);
227 thread_block(evc_continue);
228 /* NOTREACHED */
229 }
230 ret = KERN_NO_SPACE; /* XX */
231 }
232 simple_unlock(&ev->lock);
233 splx(s);
234 return ret;
235 }
236
237 /*
238 * User-trappable
239 */
240 kern_return_t evc_wait_clear(natural_t ev_id)
241 {
242 spl_t s;
243 kern_return_t ret;
244 evc_t ev;
245
246 if ((ev_id >= MAX_EVCS) ||
247 ((ev = all_eventcounters[ev_id]) == 0) ||
248 (ev->ev_id != ev_id) || (ev->sanity != ev))
249 return KERN_INVALID_ARGUMENT;
250
251 s = splsched();
252 simple_lock(&ev->lock);
253
254 /*
255 * The values assumed by the "count" field are
256 * as follows:
257 * 0 At initialization time, and with no
258 * waiting thread means no events pending;
259 * with waiting thread means the event
260 * was signalled and the thread not yet resumed
261 * -1 no events, there must be a waiting thread
262 * N>0 no waiting thread means N pending,
263 * with waiting thread N-1 pending.
264 *
265 */
266 /*
267 * Note that we always clear count before blocking.
268 */
269 if (ev->waiting_thread == THREAD_NULL) {
270 ev->count = -1;
271 ev->waiting_thread = current_thread();
272 assert_wait((event_t) 0, TRUE); /* ifnot race */
273 simple_unlock(&ev->lock);
274 thread_block(evc_continue);
275 /* NOTREACHED */
276 }
277
278 simple_unlock(&ev->lock);
279 splx(s);
280 ret = KERN_NO_SPACE; /* XX */
281 }
282
283 /*
284 * Called exclusively from interrupt context
285 */
286 void
287 evc_signal(evc_t ev)
288 {
289 register volatile thread_t thread;
290 register int state;
291 spl_t s;
292 if (ev->sanity != ev)
293 return;
294
295 s = splsched();
296 simple_lock(&ev->lock);
297 ev->count++;
298 if (thread = ev->waiting_thread, thread != THREAD_NULL)
299 {
300 ev->waiting_thread = 0;
301
302 #if (NCPUS > 1)
303 retry:
304 while((thread->state & TH_RUN) || thread->lock.lock_data)
305 ;
306 #endif
307 thread_lock(thread);
308
309 /* make thread runnable on this processor */
310 /* taken from clear_wait */
311 switch ((state = thread->state) & TH_SCHED_STATE)
312 {
313 case TH_WAIT | TH_SUSP | TH_UNINT:
314 case TH_WAIT | TH_UNINT:
315 case TH_WAIT:
316 /*
317 * Sleeping and not suspendable - put
318 * on run queue.
319 */
320 thread->state = (state &~ TH_WAIT) | TH_RUN;
321 thread_unlock(thread);
322 #if NCPUS > 1
323 thread_setrun(thread, TRUE);
324 #else
325 simpler_thread_setrun(thread, TRUE);
326 #endif
327 break;
328
329 case TH_RUN | TH_WAIT:
330 #if (NCPUS > 1)
331 /*
332 * Legal on MP: between assert_wait()
333 * and thread_block(), in evc_wait() above.
334 *
335 * Mmm. Maybe don't need now that the while(..) check is
336 * done before the thread lock is grabbed.....
337 */
338 thread_unlock(thread);
339 goto retry;
340 #else
341 /*FALLTHROUGH*/
342 #endif
343 case TH_WAIT | TH_SUSP:
344 case TH_RUN | TH_WAIT | TH_SUSP:
345 case TH_RUN | TH_WAIT | TH_UNINT:
346 case TH_RUN | TH_WAIT | TH_SUSP | TH_UNINT:
347
348 /*
349 * Either already running, or suspended.
350 * Just clear the wait.
351 */
352 thread->state = state &~ TH_WAIT;
353 thread_unlock(thread);
354 break;
355
356 default:
357 /*
358 * Not waiting.
359 */
360 panic("evc_signal.3");
361 thread_unlock(thread);
362 break;
363 }
364 }
365
366 simple_unlock(&ev->lock);
367 splx(s);
368 }
369
370 #if NCPUS <= 1
371 /*
372 * The scheduler is too messy for my old little brain
373 */
374 void
375 simpler_thread_setrun(
376 thread_t th,
377 boolean_t may_preempt)
378 {
379 register struct run_queue *rq;
380 register whichq;
381
382 /*
383 * XXX should replace queue with a boolean in this case.
384 */
385 if (default_pset.idle_count > 0) {
386 processor_t processor;
387
388 processor = (processor_t) queue_first(&default_pset.idle_queue);
389 queue_remove(&default_pset.idle_queue, processor,
390 processor_t, processor_queue);
391 default_pset.idle_count--;
392 processor->next_thread = th;
393 processor->state = PROCESSOR_DISPATCHING;
394 return;
395 }
396 rq = &(master_processor->runq);
397 ast_on(cpu_number(), AST_BLOCK);
398
399 whichq = (th)->sched_pri;
400 simple_lock(&(rq)->lock); /* lock the run queue */
401 enqueue_head(&(rq)->runq[whichq], (queue_entry_t) (th));
402
403 if (whichq < (rq)->low || (rq)->count == 0)
404 (rq)->low = whichq; /* minimize */
405 (rq)->count++;
406 (th)->runq = (rq);
407 simple_unlock(&(rq)->lock);
408
409 /*
410 * Turn off first_quantum to allow context switch.
411 */
412 current_processor()->first_quantum = FALSE;
413 }
414 #endif /* NCPUS > 1 */
415
Cache object: e8604ffdcc9f18d9380d0830ab4c585a
|