|
|
1.1 root 1: /*
2: * Mach Operating System
3: * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University.
4: * Copyright (c) 1993,1994 The University of Utah and
5: * the Computer Systems Laboratory (CSL).
6: * All rights reserved.
7: *
8: * Permission to use, copy, modify and distribute this software and its
9: * documentation is hereby granted, provided that both the copyright
10: * notice and this permission notice appear in all copies of the
11: * software, derivative works or modified versions, and any portions
12: * thereof, and that both notices appear in supporting documentation.
13: *
14: * CARNEGIE MELLON, THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF
15: * THIS SOFTWARE IN ITS "AS IS" CONDITION, AND DISCLAIM ANY LIABILITY
16: * OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF
17: * THIS SOFTWARE.
18: *
19: * Carnegie Mellon requests users of this software to return to
20: *
21: * Software Distribution Coordinator or [email protected]
22: * School of Computer Science
23: * Carnegie Mellon University
24: * Pittsburgh PA 15213-3890
25: *
26: * any improvements or extensions that they make and grant Carnegie Mellon
27: * the rights to redistribute these changes.
28: */
29: /*
30: * File: eventcount.c
31: * Author: Alessandro Forin
32: * Date: 10/91
33: *
34: * Eventcounters, for user-level drivers synchronization
35: *
36: */
37:
38:
39: #include <cpus.h>
40:
41: #include <mach/machine.h>
42: #include <kern/ast.h>
43: #include "cpu_number.h"
44: #include <kern/lock.h>
45: #include <kern/processor.h>
46: #include <kern/queue.h>
47: #include <kern/sched.h>
48: #include <kern/sched_prim.h>
49: #include <kern/thread.h>
50:
51: #include <machine/machspl.h> /* For def'n of splsched() */
52:
53: #include <kern/eventcount.h>
54:
55:
56: #if NCPUS <= 1
57: void simpler_thread_setrun(
58: thread_t th,
59: boolean_t may_preempt); /* forward */
60: #endif
61:
62: #define MAX_EVCS 10 /* xxx for now */
63: evc_t all_eventcounters[MAX_EVCS];
64:
65: /*
66: * Initialization
67: */
68: void
69: evc_init(evc_t ev)
70: {
71: int i;
72:
73: bzero((char*)ev, sizeof(*ev));
74:
75: /* keep track of who is who */
76: for (i = 0; i < MAX_EVCS; i++)
77: if (all_eventcounters[i] == 0) break;
78: if (i == MAX_EVCS) {
79: printf("Too many eventcounters\n");
80: return;
81: }
82:
83: all_eventcounters[i] = ev;
84: ev->ev_id = i;
85: ev->sanity = ev;
86: ev->waiting_thread = THREAD_NULL;
87: simple_lock_init(&ev->lock);
88: }
89:
90: /*
91: * Finalization
92: */
93: void
94: evc_destroy(evc_t ev)
95: {
96: evc_signal(ev);
97: ev->sanity = 0;
98: if (all_eventcounters[ev->ev_id] == ev)
99: all_eventcounters[ev->ev_id] = 0;
100: ev->ev_id = -1;
101: }
102:
103: /*
104: * Thread termination.
105: * HORRIBLE. This stuff needs to be fixed.
106: */
107: void evc_notify_abort(thread_t thread)
108: {
109: int i;
110: evc_t ev;
111: int s = splsched();
112: for (i = 0; i < MAX_EVCS; i++) {
113: ev = all_eventcounters[i];
114: if (ev) {
115: simple_lock(&ev->lock);
116: if (ev->waiting_thread == thread)
117: {
118: ev->waiting_thread = 0;
119: /* Removal of a waiting thread has to bump the count by one */
120: ev->count++;
121: }
122: simple_unlock(&ev->lock);
123: }
124: }
125: splx(s);
126: }
127:
128: #ifdef CONTINUATIONS
129: /*
130: * Just so that we return success, and give
131: * up the stack while blocked
132: */
133: static void
134: evc_continue(void)
135: {
136: thread_syscall_return(KERN_SUCCESS);
137: /* NOTREACHED */
138: }
139: #else /* not CONTINUATIONS */
140: #define evc_continue 0
141: #endif /* not CONTINUATIONS */
142:
143: /*
144: * User-trappable
145: */
146: kern_return_t evc_wait(natural_t ev_id)
147: {
148: spl_t s;
149: kern_return_t ret;
150: evc_t ev;
151:
152: if ((ev_id >= MAX_EVCS) ||
153: ((ev = all_eventcounters[ev_id]) == 0) ||
154: (ev->ev_id != ev_id) || (ev->sanity != ev))
155: return KERN_INVALID_ARGUMENT;
156:
157: s = splsched();
158: simple_lock(&ev->lock);
159: /*
160: * The values assumed by the "count" field are
161: * as follows:
162: * 0 At initialization time, and with no
163: * waiting thread means no events pending;
164: * with waiting thread means the event
165: * was signalled and the thread not yet resumed
166: * -1 no events, there must be a waiting thread
167: * N>0 no waiting thread means N pending,
168: * with waiting thread N-1 pending.
169: *
170: */
171: if (ev->count > 0) {
172: ev->count--;
173: ret = KERN_SUCCESS;
174: } else {
175: if (ev->waiting_thread == THREAD_NULL) {
176: ev->count--;
177: ev->waiting_thread = current_thread();
178: assert_wait((event_t) 0, TRUE); /* ifnot race */
179: simple_unlock(&ev->lock);
180: thread_block(evc_continue);
181: return KERN_SUCCESS;
182: }
183: ret = KERN_NO_SPACE; /* XX */
184: }
185: simple_unlock(&ev->lock);
186: splx(s);
187: return ret;
188: }
189:
190: /*
191: * User-trappable
192: */
193: kern_return_t evc_wait_clear(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: /*
208: * The values assumed by the "count" field are
209: * as follows:
210: * 0 At initialization time, and with no
211: * waiting thread means no events pending;
212: * with waiting thread means the event
213: * was signalled and the thread not yet resumed
214: * -1 no events, there must be a waiting thread
215: * N>0 no waiting thread means N pending,
216: * with waiting thread N-1 pending.
217: *
218: */
219: /*
220: * Note that we always clear count before blocking.
221: */
222: if (ev->waiting_thread == THREAD_NULL) {
223: ev->count = -1;
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:
231: simple_unlock(&ev->lock);
232: splx(s);
233: ret = KERN_NO_SPACE; /* XX */
234: }
235:
236: /*
237: * Called exclusively from interrupt context
238: */
239: void
240: evc_signal(evc_t ev)
241: {
242: register volatile thread_t thread;
243: register int state;
244: spl_t s;
245: if (ev->sanity != ev)
246: return;
247:
248: s = splsched();
249: simple_lock(&ev->lock);
250: ev->count++;
251: if (thread = ev->waiting_thread, thread != THREAD_NULL)
252: {
253: ev->waiting_thread = 0;
254:
255: #if (NCPUS > 1)
256: retry:
257: while((thread->state & TH_RUN) || thread->lock.lock_data)
258: ;
259: #endif
260: thread_lock(thread);
261:
262: /* make thread runnable on this processor */
263: /* taken from clear_wait */
264: switch ((state = thread->state) & TH_SCHED_STATE)
265: {
266: case TH_WAIT | TH_SUSP | TH_UNINT:
267: case TH_WAIT | TH_UNINT:
268: case TH_WAIT:
269: /*
270: * Sleeping and not suspendable - put
271: * on run queue.
272: */
273: thread->state = (state &~ TH_WAIT) | TH_RUN;
274: thread_unlock(thread);
275: #if NCPUS > 1
276: thread_setrun(thread, TRUE);
277: #else
278: simpler_thread_setrun(thread, TRUE);
279: #endif
280: break;
281:
282: case TH_RUN | TH_WAIT:
283: #if (NCPUS > 1)
284: /*
285: * Legal on MP: between assert_wait()
286: * and thread_block(), in evc_wait() above.
287: *
288: * Mmm. Maybe don't need now that the while(..) check is
289: * done before the thread lock is grabbed.....
290: */
291: thread_unlock(thread);
292: goto retry;
293: #else
294: /*FALLTHROUGH*/
295: #endif
296: case TH_WAIT | TH_SUSP:
297: case TH_RUN | TH_WAIT | TH_SUSP:
298: case TH_RUN | TH_WAIT | TH_UNINT:
299: case TH_RUN | TH_WAIT | TH_SUSP | TH_UNINT:
300:
301: /*
302: * Either already running, or suspended.
303: * Just clear the wait.
304: */
305: thread->state = state &~ TH_WAIT;
306: thread_unlock(thread);
307: break;
308:
309: default:
310: /*
311: * Not waiting.
312: */
313: panic("evc_signal.3");
314: thread_unlock(thread);
315: break;
316: }
317: }
318:
319: simple_unlock(&ev->lock);
320: splx(s);
321: }
322:
323: #if NCPUS <= 1
324: /*
325: * The scheduler is too messy for my old little brain
326: */
327: void
328: simpler_thread_setrun(
329: thread_t th,
330: boolean_t may_preempt)
331: {
332: register struct run_queue *rq;
333: register whichq;
334:
335: /*
336: * XXX should replace queue with a boolean in this case.
337: */
338: if (default_pset.idle_count > 0) {
339: processor_t processor;
340:
341: processor = (processor_t) queue_first(&default_pset.idle_queue);
342: queue_remove(&default_pset.idle_queue, processor,
343: processor_t, processor_queue);
344: default_pset.idle_count--;
345: processor->next_thread = th;
346: processor->state = PROCESSOR_DISPATCHING;
347: return;
348: }
349: rq = &(master_processor->runq);
350: ast_on(cpu_number(), AST_BLOCK);
351:
352: whichq = (th)->sched_pri;
353: simple_lock(&(rq)->lock); /* lock the run queue */
354: enqueue_head(&(rq)->runq[whichq], (queue_entry_t) (th));
355:
356: if (whichq < (rq)->low || (rq)->count == 0)
357: (rq)->low = whichq; /* minimize */
358: (rq)->count++;
359: #ifdef MIGRATING_THREADS
360: (th)->shuttle.runq = (rq);
361: #else
362: (th)->runq = (rq);
363: #endif
364: simple_unlock(&(rq)->lock);
365:
366: /*
367: * Turn off first_quantum to allow context switch.
368: */
369: current_processor()->first_quantum = FALSE;
370: }
371: #endif /* NCPUS > 1 */
372:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.