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