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