|
|
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:
1.1.1.2 ! root 38: #include <kern/printf.h>
! 39: #include <string.h>
1.1 root 40:
41: #include <mach/machine.h>
42: #include <kern/ast.h>
1.1.1.2 ! root 43: #include <kern/debug.h>
1.1 root 44: #include "cpu_number.h"
45: #include <kern/lock.h>
46: #include <kern/processor.h>
47: #include <kern/queue.h>
48: #include <kern/sched.h>
49: #include <kern/sched_prim.h>
50: #include <kern/thread.h>
51:
52: #include <machine/machspl.h> /* For def'n of splsched() */
53:
54: #include <kern/eventcount.h>
55:
56:
57: #if NCPUS <= 1
58: void simpler_thread_setrun(
59: thread_t th,
60: boolean_t may_preempt); /* forward */
61: #endif
62:
63: #define MAX_EVCS 10 /* xxx for now */
64: evc_t all_eventcounters[MAX_EVCS];
65:
66: /*
67: * Initialization
68: */
69: void
70: evc_init(evc_t ev)
71: {
72: int i;
73:
1.1.1.2 ! root 74: memset(ev, 0, sizeof(*ev));
1.1 root 75:
76: /* keep track of who is who */
77: for (i = 0; i < MAX_EVCS; i++)
78: if (all_eventcounters[i] == 0) break;
79: if (i == MAX_EVCS) {
80: printf("Too many eventcounters\n");
81: return;
82: }
83:
84: all_eventcounters[i] = ev;
85: ev->ev_id = i;
86: ev->sanity = ev;
87: ev->waiting_thread = THREAD_NULL;
88: simple_lock_init(&ev->lock);
89: }
90:
91: /*
92: * Finalization
93: */
94: void
95: evc_destroy(evc_t ev)
96: {
97: evc_signal(ev);
98: ev->sanity = 0;
99: if (all_eventcounters[ev->ev_id] == ev)
100: all_eventcounters[ev->ev_id] = 0;
101: ev->ev_id = -1;
102: }
103:
104: /*
105: * Thread termination.
106: * HORRIBLE. This stuff needs to be fixed.
107: */
108: void evc_notify_abort(thread_t thread)
109: {
110: int i;
111: evc_t ev;
112: int s = splsched();
113: for (i = 0; i < MAX_EVCS; i++) {
114: ev = all_eventcounters[i];
115: if (ev) {
116: simple_lock(&ev->lock);
117: if (ev->waiting_thread == thread)
118: {
119: ev->waiting_thread = 0;
120: /* Removal of a waiting thread has to bump the count by one */
121: ev->count++;
122: }
123: simple_unlock(&ev->lock);
124: }
125: }
126: splx(s);
127: }
128:
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:
140: /*
141: * User-trappable
142: */
143: kern_return_t evc_wait(natural_t ev_id)
144: {
145: spl_t s;
146: kern_return_t ret;
147: evc_t ev;
148:
149: if ((ev_id >= MAX_EVCS) ||
150: ((ev = all_eventcounters[ev_id]) == 0) ||
151: (ev->ev_id != ev_id) || (ev->sanity != ev))
152: return KERN_INVALID_ARGUMENT;
153:
154: s = splsched();
155: simple_lock(&ev->lock);
156: /*
157: * The values assumed by the "count" field are
158: * as follows:
159: * 0 At initialization time, and with no
160: * waiting thread means no events pending;
161: * with waiting thread means the event
162: * was signalled and the thread not yet resumed
163: * -1 no events, there must be a waiting thread
164: * N>0 no waiting thread means N pending,
165: * with waiting thread N-1 pending.
166: *
167: */
168: if (ev->count > 0) {
169: ev->count--;
170: ret = KERN_SUCCESS;
171: } else {
172: if (ev->waiting_thread == THREAD_NULL) {
173: ev->count--;
174: ev->waiting_thread = current_thread();
175: assert_wait((event_t) 0, TRUE); /* ifnot race */
176: simple_unlock(&ev->lock);
177: thread_block(evc_continue);
178: return KERN_SUCCESS;
179: }
180: ret = KERN_NO_SPACE; /* XX */
181: }
182: simple_unlock(&ev->lock);
183: splx(s);
184: return ret;
185: }
186:
187: /*
188: * User-trappable
189: */
190: kern_return_t evc_wait_clear(natural_t ev_id)
191: {
192: spl_t s;
193: evc_t ev;
194:
195: if ((ev_id >= MAX_EVCS) ||
196: ((ev = all_eventcounters[ev_id]) == 0) ||
197: (ev->ev_id != ev_id) || (ev->sanity != ev))
198: return KERN_INVALID_ARGUMENT;
199:
200: s = splsched();
201: simple_lock(&ev->lock);
202:
203: /*
204: * The values assumed by the "count" field are
205: * as follows:
206: * 0 At initialization time, and with no
207: * waiting thread means no events pending;
208: * with waiting thread means the event
209: * was signalled and the thread not yet resumed
210: * -1 no events, there must be a waiting thread
211: * N>0 no waiting thread means N pending,
212: * with waiting thread N-1 pending.
213: *
214: */
215: /*
216: * Note that we always clear count before blocking.
217: */
218: if (ev->waiting_thread == THREAD_NULL) {
219: ev->count = -1;
220: ev->waiting_thread = current_thread();
221: assert_wait((event_t) 0, TRUE); /* ifnot race */
222: simple_unlock(&ev->lock);
223: thread_block(evc_continue);
224: /* NOTREACHED */
225: }
226:
227: simple_unlock(&ev->lock);
228: splx(s);
1.1.1.2 ! root 229: return KERN_NO_SPACE; /* XX */
1.1 root 230: }
231:
232: /*
233: * Called exclusively from interrupt context
234: */
235: void
236: evc_signal(evc_t ev)
237: {
238: register volatile thread_t thread;
239: register int state;
240: spl_t s;
241: if (ev->sanity != ev)
242: return;
243:
244: s = splsched();
245: simple_lock(&ev->lock);
246: ev->count++;
247: if (thread = ev->waiting_thread, thread != THREAD_NULL)
248: {
249: ev->waiting_thread = 0;
250:
251: #if (NCPUS > 1)
252: retry:
253: while((thread->state & TH_RUN) || thread->lock.lock_data)
254: ;
255: #endif
256: thread_lock(thread);
257:
258: /* make thread runnable on this processor */
259: /* taken from clear_wait */
260: switch ((state = thread->state) & TH_SCHED_STATE)
261: {
262: case TH_WAIT | TH_SUSP | TH_UNINT:
263: case TH_WAIT | TH_UNINT:
264: case TH_WAIT:
265: /*
266: * Sleeping and not suspendable - put
267: * on run queue.
268: */
269: thread->state = (state &~ TH_WAIT) | TH_RUN;
270: thread_unlock(thread);
271: #if NCPUS > 1
272: thread_setrun(thread, TRUE);
273: #else
274: simpler_thread_setrun(thread, TRUE);
275: #endif
276: break;
277:
278: case TH_RUN | TH_WAIT:
279: #if (NCPUS > 1)
280: /*
281: * Legal on MP: between assert_wait()
282: * and thread_block(), in evc_wait() above.
283: *
284: * Mmm. Maybe don't need now that the while(..) check is
285: * done before the thread lock is grabbed.....
286: */
287: thread_unlock(thread);
288: goto retry;
289: #else
290: /*FALLTHROUGH*/
291: #endif
292: case TH_WAIT | TH_SUSP:
293: case TH_RUN | TH_WAIT | TH_SUSP:
294: case TH_RUN | TH_WAIT | TH_UNINT:
295: case TH_RUN | TH_WAIT | TH_SUSP | TH_UNINT:
296:
297: /*
298: * Either already running, or suspended.
299: * Just clear the wait.
300: */
301: thread->state = state &~ TH_WAIT;
302: thread_unlock(thread);
303: break;
304:
305: default:
306: /*
307: * Not waiting.
308: */
309: panic("evc_signal.3");
310: thread_unlock(thread);
311: break;
312: }
313: }
314:
315: simple_unlock(&ev->lock);
316: splx(s);
317: }
318:
319: #if NCPUS <= 1
320: /*
321: * The scheduler is too messy for my old little brain
322: */
323: void
324: simpler_thread_setrun(
325: thread_t th,
326: boolean_t may_preempt)
327: {
328: register struct run_queue *rq;
1.1.1.2 ! root 329: register int whichq;
1.1 root 330:
331: /*
332: * XXX should replace queue with a boolean in this case.
333: */
334: if (default_pset.idle_count > 0) {
335: processor_t processor;
336:
337: processor = (processor_t) queue_first(&default_pset.idle_queue);
338: queue_remove(&default_pset.idle_queue, processor,
339: processor_t, processor_queue);
340: default_pset.idle_count--;
341: processor->next_thread = th;
342: processor->state = PROCESSOR_DISPATCHING;
343: return;
344: }
345: rq = &(master_processor->runq);
346: ast_on(cpu_number(), AST_BLOCK);
347:
348: whichq = (th)->sched_pri;
349: simple_lock(&(rq)->lock); /* lock the run queue */
350: enqueue_head(&(rq)->runq[whichq], (queue_entry_t) (th));
351:
352: if (whichq < (rq)->low || (rq)->count == 0)
353: (rq)->low = whichq; /* minimize */
354: (rq)->count++;
355: #ifdef MIGRATING_THREADS
356: (th)->shuttle.runq = (rq);
357: #else
358: (th)->runq = (rq);
359: #endif
360: simple_unlock(&(rq)->lock);
361:
362: /*
363: * Turn off first_quantum to allow context switch.
364: */
365: current_processor()->first_quantum = FALSE;
366: }
367: #endif /* NCPUS > 1 */
368:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.