|
|
1.1 root 1: /*
2: * Mach Operating System
3: * Copyright (c) 1993, 1992,1991,1990 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 [email protected]
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: #include <cpus.h>
28: #include <mach_host.h>
29:
30: #include <mach/message.h>
31: #include <kern/counters.h>
32: #include "cpu_number.h"
33: #include <kern/lock.h>
34: #include <kern/thread.h>
35: #include <kern/sched_prim.h>
36: #include <kern/processor.h>
37: #include <kern/time_out.h>
38: #include <kern/thread_swap.h>
39: #include <kern/ipc_sched.h>
40: #include <machine/machspl.h> /* for splsched/splx */
41: #include <machine/pmap.h>
42:
43:
44:
45: /*
46: * These functions really belong in kern/sched_prim.c.
47: */
48:
49: /*
50: * Routine: thread_go
51: * Purpose:
52: * Start a thread running.
53: * Conditions:
54: * IPC locks may be held.
55: */
56:
57: void
58: thread_go(
59: thread_t thread)
60: {
61: int state;
62: spl_t s;
63:
64: s = splsched();
65: thread_lock(thread);
66:
67: reset_timeout_check(&thread->timer);
68:
69: state = thread->state;
70: switch (state & TH_SCHED_STATE) {
71:
72: case TH_WAIT | TH_SUSP | TH_UNINT:
73: case TH_WAIT | TH_UNINT:
74: case TH_WAIT:
75: /*
76: * Sleeping and not suspendable - put
77: * on run queue.
78: */
79: thread->state = (state &~ TH_WAIT) | TH_RUN;
80: thread->wait_result = THREAD_AWAKENED;
81: thread_setrun(thread, TRUE);
82: break;
83:
84: case TH_WAIT | TH_SUSP:
85: case TH_RUN | TH_WAIT:
86: case TH_RUN | TH_WAIT | TH_SUSP:
87: case TH_RUN | TH_WAIT | TH_UNINT:
88: case TH_RUN | TH_WAIT | TH_SUSP | TH_UNINT:
89: /*
90: * Either already running, or suspended.
91: */
92: thread->state = state & ~TH_WAIT;
93: thread->wait_result = THREAD_AWAKENED;
94: break;
95:
96: default:
97: /*
98: * Not waiting.
99: */
100: break;
101: }
102:
103: thread_unlock(thread);
104: splx(s);
105: }
106:
107: /*
108: * Routine: thread_will_wait
109: * Purpose:
110: * Assert that the thread intends to block.
111: */
112:
113: void
114: thread_will_wait(
115: thread_t thread)
116: {
117: spl_t s;
118:
119: s = splsched();
120: thread_lock(thread);
121:
122: assert(thread->wait_result = -1); /* for later assertions */
123: thread->state |= TH_WAIT;
124:
125: thread_unlock(thread);
126: splx(s);
127: }
128:
129: /*
130: * Routine: thread_will_wait_with_timeout
131: * Purpose:
132: * Assert that the thread intends to block,
133: * with a timeout.
134: */
135:
136: void
137: thread_will_wait_with_timeout(
138: thread_t thread,
139: mach_msg_timeout_t msecs)
140: {
141: natural_t ticks = convert_ipc_timeout_to_ticks(msecs);
142: spl_t s;
143:
144: s = splsched();
145: thread_lock(thread);
146:
147: assert(thread->wait_result = -1); /* for later assertions */
148: thread->state |= TH_WAIT;
149:
150: set_timeout(&thread->timer, ticks);
151:
152: thread_unlock(thread);
153: splx(s);
154: }
155:
156: #if MACH_HOST
157: #define check_processor_set(thread) \
158: (current_processor()->processor_set == (thread)->processor_set)
159: #else /* MACH_HOST */
160: #define check_processor_set(thread) TRUE
161: #endif /* MACH_HOST */
162:
163: #if NCPUS > 1
164: #define check_bound_processor(thread) \
165: ((thread)->bound_processor == PROCESSOR_NULL || \
166: (thread)->bound_processor == current_processor())
167: #else /* NCPUS > 1 */
168: #define check_bound_processor(thread) TRUE
169: #endif /* NCPUS > 1 */
170:
171: #ifdef CONTINUATIONS
172: /*
173: * Routine: thread_handoff
174: * Purpose:
175: * Switch to a new thread (new), leaving the current
176: * thread (old) blocked. If successful, moves the
177: * kernel stack from old to new and returns as the
178: * new thread. An explicit continuation for the old thread
179: * must be supplied.
180: *
181: * NOTE: Although we wakeup new, we don't set new->wait_result.
182: * Returns:
183: * TRUE if the handoff happened.
184: */
185:
186: boolean_t
187: thread_handoff(
188: register thread_t old,
189: register continuation_t continuation,
190: register thread_t new)
191: {
192: spl_t s;
193:
194: assert(current_thread() == old);
195:
196: /*
197: * XXX Dubious things here:
198: * I don't check the idle_count on the processor set.
199: * No scheduling priority or policy checks.
200: * I assume the new thread is interruptible.
201: */
202:
203: s = splsched();
204: thread_lock(new);
205:
206: /*
207: * The first thing we must do is check the state
208: * of the threads, to ensure we can handoff.
209: * This check uses current_processor()->processor_set,
210: * which we can read without locking.
211: */
212:
213: if ((old->stack_privilege == current_stack()) ||
214: (new->state != (TH_WAIT|TH_SWAPPED)) ||
215: !check_processor_set(new) ||
216: !check_bound_processor(new)) {
217: thread_unlock(new);
218: (void) splx(s);
219:
220: counter_always(c_thread_handoff_misses++);
221: return FALSE;
222: }
223:
224: reset_timeout_check(&new->timer);
225:
226: new->state = TH_RUN;
227: thread_unlock(new);
228:
229: #if NCPUS > 1
230: new->last_processor = current_processor();
231: #endif /* NCPUS > 1 */
232:
233: ast_context(new, cpu_number());
234: timer_switch(&new->system_timer);
235:
236: /*
237: * stack_handoff is machine-dependent. It does the
238: * machine-dependent components of a context-switch, like
239: * changing address spaces. It updates active_threads.
240: */
241:
242: stack_handoff(old, new);
243:
244: /*
245: * Now we must dispose of the old thread.
246: * This is like thread_continue, except
247: * that the old thread isn't waiting yet.
248: */
249:
250: thread_lock(old);
251: old->swap_func = continuation;
252: assert(old->wait_result = -1); /* for later assertions */
253:
254: if (old->state == TH_RUN) {
255: /*
256: * This is our fast path.
257: */
258:
259: old->state = TH_WAIT|TH_SWAPPED;
260: }
261: else if (old->state == (TH_RUN|TH_SUSP)) {
262: /*
263: * Somebody is trying to suspend the thread.
264: */
265:
266: old->state = TH_WAIT|TH_SUSP|TH_SWAPPED;
267: if (old->wake_active) {
268: /*
269: * Someone wants to know when the thread
270: * really stops.
271: */
272: old->wake_active = FALSE;
273: thread_unlock(old);
274: thread_wakeup((event_t)&old->wake_active);
275: goto after_old_thread;
276: }
277: } else
278: panic("thread_handoff");
279:
280: thread_unlock(old);
281: after_old_thread:
282: (void) splx(s);
283:
284: counter_always(c_thread_handoff_hits++);
285: return TRUE;
286: }
287: #endif /* CONTINUATIONS */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.