|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: /*
26: * Mach Operating System
27: * Copyright (c) 1993, 1992,1991,1990 Carnegie Mellon University
28: * All Rights Reserved.
29: *
30: * Permission to use, copy, modify and distribute this software and its
31: * documentation is hereby granted, provided that both the copyright
32: * notice and this permission notice appear in all copies of the
33: * software, derivative works or modified versions, and any portions
34: * thereof, and that both notices appear in supporting documentation.
35: *
36: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
37: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
38: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
39: *
40: * Carnegie Mellon requests users of this software to return to
41: *
42: * Software Distribution Coordinator or [email protected]
43: * School of Computer Science
44: * Carnegie Mellon University
45: * Pittsburgh PA 15213-3890
46: *
47: * any improvements or extensions that they make and grant Carnegie Mellon
48: * the rights to redistribute these changes.
49: */
50:
51: #include <cpus.h>
52: #include <mach_host.h>
53:
54: #include <mach/message.h>
55: #include <kern/counters.h>
56: #include <kern/cpu_number.h>
57: #include <kern/lock.h>
58: #include <kern/thread.h>
59: #include <kern/sched_prim.h>
60: #include <kern/processor.h>
61: #include <kern/time_out.h>
62: #include <kern/thread_swap.h>
63: #include <kern/ipc_sched.h>
64: #include <machine/machspl.h> /* for splsched/splx */
65: #include <machine/pmap.h>
66:
67: #import <kern/assert.h>
68:
69:
70: /*
71: * These functions really belong in kern/sched_prim.c.
72: */
73:
74: /*
75: * Routine: thread_go
76: * Purpose:
77: * Start a thread running.
78: * Conditions:
79: * IPC locks may be held.
80: */
81:
82: void
83: thread_go(
84: thread_t thread)
85: {
86: int state;
87: spl_t s;
88:
89: s = splsched();
90: thread_lock(thread);
91:
92: reset_timeout_check(&thread->timer);
93:
94: state = thread->state;
95: switch (state & TH_SCHED_STATE) {
96:
97: case TH_WAIT | TH_SUSP | TH_UNINT:
98: case TH_WAIT | TH_UNINT:
99: case TH_WAIT:
100: /*
101: * Sleeping and not suspendable - put
102: * on run queue.
103: */
104: thread->state = (state &~ TH_WAIT) | TH_RUN;
105: thread->wait_result = THREAD_AWAKENED;
106: thread_setrun(thread, TRUE);
107: break;
108:
109: case TH_WAIT | TH_SUSP:
110: case TH_RUN | TH_WAIT:
111: case TH_RUN | TH_WAIT | TH_SUSP:
112: case TH_RUN | TH_WAIT | TH_UNINT:
113: case TH_RUN | TH_WAIT | TH_SUSP | TH_UNINT:
114: /*
115: * Either already running, or suspended.
116: */
117: thread->state = state & ~TH_WAIT;
118: thread->wait_result = THREAD_AWAKENED;
119: break;
120:
121: default:
122: /*
123: * Not waiting.
124: */
125: break;
126: }
127:
128: thread_unlock(thread);
129: splx(s);
130: }
131:
132: /*
133: * Routine: thread_go_and_switch
134: * Purpose:
135: * Start a thread running.
136: * Conditions:
137: * No IPC locks held.
138: */
139:
140: void
141: thread_go_and_switch(
142: continuation_t continuation,
143: thread_t thread)
144: {
145: int state;
146: spl_t s;
147:
148: s = splsched();
149: thread_lock(thread);
150:
151: reset_timeout_check(&thread->timer);
152:
153: state = thread->state;
154: switch (state & TH_SCHED_STATE) {
155:
156: case TH_WAIT | TH_SUSP | TH_UNINT:
157: case TH_WAIT | TH_UNINT:
158: case TH_WAIT:
159: /*
160: * Sleeping and not suspendable - put
161: * on run queue.
162: */
163: thread->state = (state &~ TH_WAIT) | TH_RUN;
164: thread->wait_result = THREAD_AWAKENED;
165: if ((thread->processor_set->idle_count > 0) ||
166: (thread->processor_set !=
167: current_thread()->processor_set)) {
168: /*
169: * Other cpus can/must run thread.
170: * Put it on the run queues.
171: */
172: thread_setrun(thread, TRUE);
173: break;
174: }
175: else {
176: /*
177: * Switch immediately to new thread.
178: */
179: thread_unlock(thread);
180: thread_run(continuation, thread);
181: splx(s);
182: return;
183: }
184: break;
185:
186: case TH_WAIT | TH_SUSP:
187: case TH_RUN | TH_WAIT:
188: case TH_RUN | TH_WAIT | TH_SUSP:
189: case TH_RUN | TH_WAIT | TH_UNINT:
190: case TH_RUN | TH_WAIT | TH_SUSP | TH_UNINT:
191: /*
192: * Either already running, or suspended.
193: */
194: thread->state = state & ~TH_WAIT;
195: thread->wait_result = THREAD_AWAKENED;
196: break;
197:
198: default:
199: /*
200: * Not waiting.
201: */
202: break;
203: }
204:
205: thread_unlock(thread);
206: if (continuation != (void (*)()) 0) {
207: (void) spl0();
208: call_continuation(continuation);
209: }
210: splx(s);
211: }
212:
213: /*
214: * Routine: thread_will_wait
215: * Purpose:
216: * Assert that the thread intends to block.
217: */
218:
219: void
220: thread_will_wait(
221: thread_t thread)
222: {
223: spl_t s;
224:
225: s = splsched();
226: thread_lock(thread);
227:
228: assert(thread->wait_result = -1); /* for later assertions */
229: thread->state |= TH_WAIT;
230:
231: thread_unlock(thread);
232: splx(s);
233: }
234:
235: /*
236: * Routine: thread_will_wait_with_timeout
237: * Purpose:
238: * Assert that the thread intends to block,
239: * with a timeout.
240: */
241:
242: void
243: thread_will_wait_with_timeout(
244: thread_t thread,
245: mach_msg_timeout_t msecs)
246: {
247: natural_t ticks = convert_ipc_timeout_to_ticks(msecs);
248: spl_t s;
249:
250: s = splsched();
251: thread_lock(thread);
252:
253: assert(thread->wait_result = -1); /* for later assertions */
254: thread->state |= TH_WAIT;
255:
256: if (ticks != 0 || msecs == 0)
257: set_timeout(&thread->timer, ticks);
258:
259: thread_unlock(thread);
260: splx(s);
261: }
262:
263: #if MACH_HOST
264: #define check_processor_set(thread) \
265: (current_processor()->processor_set == (thread)->processor_set)
266: #else /* MACH_HOST */
267: #define check_processor_set(thread) TRUE
268: #endif /* MACH_HOST */
269:
270: #if NCPUS > 1
271: #define check_bound_processor(thread) \
272: ((thread)->bound_processor == PROCESSOR_NULL || \
273: (thread)->bound_processor == current_processor())
274: #else /* NCPUS > 1 */
275: #define check_bound_processor(thread) TRUE
276: #endif /* NCPUS > 1 */
277:
278: /*
279: * Routine: thread_handoff
280: * Purpose:
281: * Switch to a new thread (new), leaving the current
282: * thread (old) blocked. If successful, moves the
283: * kernel stack from old to new and returns as the
284: * new thread. An explicit continuation for the old thread
285: * must be supplied.
286: *
287: * NOTE: Although we wakeup new, we don't set new->wait_result.
288: * Returns:
289: * TRUE if the handoff happened.
290: */
291:
292: boolean_t
293: thread_handoff(
294: register thread_t old,
295: register continuation_t continuation,
296: register thread_t new)
297: {
298: spl_t s;
299:
300: assert(current_thread() == old);
301:
302: /*
303: * XXX Dubious things here:
304: * I don't check the idle_count on the processor set.
305: * No scheduling priority or policy checks.
306: * I assume the new thread is interruptible.
307: */
308:
309: s = splsched();
310: thread_lock(new);
311:
312: /*
313: * The first thing we must do is check the state
314: * of the threads, to ensure we can handoff.
315: * This check uses current_processor()->processor_set,
316: * which we can read without locking.
317: */
318:
319: if ((old->stack_privilege == current_stack()) ||
320: (new->state != (TH_WAIT|TH_SWAPPED)) ||
321: !check_processor_set(new) ||
322: !check_bound_processor(new)) {
323: thread_unlock(new);
324: (void) splx(s);
325:
326: counter_always(c_thread_handoff_misses++);
327: return FALSE;
328: }
329:
330: reset_timeout_check(&new->timer);
331:
332: new->state = TH_RUN;
333: thread_unlock(new);
334:
335: #if NCPUS > 1
336: new->last_processor = current_processor();
337: #endif /* NCPUS > 1 */
338:
339: ast_context(new, cpu_number());
340: timer_switch(&new->system_timer);
341:
342: /*
343: * stack_handoff is machine-dependent. It does the
344: * machine-dependent components of a context-switch, like
345: * changing address spaces. It updates active_threads.
346: */
347:
348: stack_handoff(old, new);
349:
350: /*
351: * Now we must dispose of the old thread.
352: * This is like thread_continue, except
353: * that the old thread isn't waiting yet.
354: */
355:
356: thread_lock(old);
357: old->swap_func = continuation;
358: assert(old->wait_result = -1); /* for later assertions */
359:
360: if (old->state == TH_RUN) {
361: /*
362: * This is our fast path.
363: */
364:
365: old->state = TH_WAIT|TH_SWAPPED;
366: }
367: else if (old->state == (TH_RUN|TH_SUSP)) {
368: /*
369: * Somebody is trying to suspend the thread.
370: */
371:
372: old->state = TH_WAIT|TH_SUSP|TH_SWAPPED;
373: if (old->wake_active) {
374: /*
375: * Someone wants to know when the thread
376: * really stops.
377: */
378: old->wake_active = FALSE;
379: thread_unlock(old);
380: thread_wakeup((event_t)&old->wake_active);
381: goto after_old_thread;
382: }
383: } else
384: panic("thread_handoff");
385:
386: thread_unlock(old);
387: after_old_thread:
388: (void) splx(s);
389:
390: counter_always(c_thread_handoff_hits++);
391: return TRUE;
392: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.