|
|
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: #include <mach_fixpri.h>
31: #include <cpus.h>
32:
33: #include <mach/boolean.h>
34: #include <mach/thread_switch.h>
35: #include <ipc/ipc_port.h>
36: #include <ipc/ipc_space.h>
37: #include <kern/counters.h>
38: #include <kern/ipc_kobject.h>
39: #include <kern/processor.h>
40: #include <kern/sched.h>
41: #include <kern/sched_prim.h>
42: #include <kern/ipc_sched.h>
43: #include <kern/task.h>
44: #include <kern/thread.h>
45: #include <kern/time_out.h>
46: #include <machine/machspl.h> /* for splsched */
47:
48: #if MACH_FIXPRI
49: #include <mach/policy.h>
50: #endif /* MACH_FIXPRI */
51:
52:
53:
54: /*
55: * swtch and swtch_pri both attempt to context switch (logic in
56: * thread_block no-ops the context switch if nothing would happen).
57: * A boolean is returned that indicates whether there is anything
58: * else runnable.
59: *
60: * This boolean can be used by a thread waiting on a
61: * lock or condition: If FALSE is returned, the thread is justified
62: * in becoming a resource hog by continuing to spin because there's
63: * nothing else useful that the processor could do. If TRUE is
64: * returned, the thread should make one more check on the
65: * lock and then be a good citizen and really suspend.
66: */
67:
68: extern void thread_depress_priority();
69: extern kern_return_t thread_depress_abort();
70:
71: #ifdef CONTINUATIONS
72: void swtch_continue()
73: {
74: register processor_t myprocessor;
75:
76: myprocessor = current_processor();
77: thread_syscall_return(myprocessor->runq.count > 0 ||
78: myprocessor->processor_set->runq.count > 0);
79: /*NOTREACHED*/
80: }
81: #else /* not CONTINUATIONS */
82: #define swtch_continue 0
83: #endif /* not CONTINUATIONS */
84:
85: boolean_t swtch()
86: {
87: register processor_t myprocessor;
88:
89: #if NCPUS > 1
90: myprocessor = current_processor();
91: if (myprocessor->runq.count == 0 &&
92: myprocessor->processor_set->runq.count == 0)
93: return(FALSE);
94: #endif /* NCPUS > 1 */
95:
96: counter(c_swtch_block++);
97: thread_block(swtch_continue);
98: myprocessor = current_processor();
99: return(myprocessor->runq.count > 0 ||
100: myprocessor->processor_set->runq.count > 0);
101: }
102:
103: #ifdef CONTINUATIONS
104: void swtch_pri_continue()
105: {
106: register thread_t thread = current_thread();
107: register processor_t myprocessor;
108:
109: if (thread->depress_priority >= 0)
110: (void) thread_depress_abort(thread);
111: myprocessor = current_processor();
112: thread_syscall_return(myprocessor->runq.count > 0 ||
113: myprocessor->processor_set->runq.count > 0);
114: /*NOTREACHED*/
115: }
116: #else /* not CONTINUATIONS */
117: #define swtch_pri_continue 0
118: #endif /* not CONTINUATIONS */
119:
120: boolean_t swtch_pri(pri)
121: int pri;
122: {
123: register thread_t thread = current_thread();
124: register processor_t myprocessor;
125:
126: #ifdef lint
127: pri++;
128: #endif /* lint */
129:
130: #if NCPUS > 1
131: myprocessor = current_processor();
132: if (myprocessor->runq.count == 0 &&
133: myprocessor->processor_set->runq.count == 0)
134: return(FALSE);
135: #endif /* NCPUS > 1 */
136:
137: /*
138: * XXX need to think about depression duration.
139: * XXX currently using min quantum.
140: */
141: thread_depress_priority(thread, min_quantum);
142:
143: counter(c_swtch_pri_block++);
144: thread_block(swtch_pri_continue);
145:
146: if (thread->depress_priority >= 0)
147: (void) thread_depress_abort(thread);
148: myprocessor = current_processor();
149: return(myprocessor->runq.count > 0 ||
150: myprocessor->processor_set->runq.count > 0);
151: }
152:
153: extern int hz;
154:
155: #ifdef CONTINUATIONS
156: void thread_switch_continue()
157: {
158: register thread_t cur_thread = current_thread();
159:
160: /*
161: * Restore depressed priority
162: */
163: if (cur_thread->depress_priority >= 0)
164: (void) thread_depress_abort(cur_thread);
165: thread_syscall_return(KERN_SUCCESS);
166: /*NOTREACHED*/
167: }
168: #else /* not CONTINUATIONS */
169: #define thread_switch_continue 0
170: #endif /* not CONTINUATIONS */
171:
172: /*
173: * thread_switch:
174: *
175: * Context switch. User may supply thread hint.
176: *
177: * Fixed priority threads that call this get what they asked for
178: * even if that violates priority order.
179: */
180: kern_return_t thread_switch(thread_name, option, option_time)
181: mach_port_t thread_name;
182: int option;
183: mach_msg_timeout_t option_time;
184: {
185: register thread_t cur_thread = current_thread();
186: register processor_t myprocessor;
187: ipc_port_t port;
188:
189: /*
190: * Process option.
191: */
192: switch (option) {
193: case SWITCH_OPTION_NONE:
194: /*
195: * Nothing to do.
196: */
197: break;
198:
199: case SWITCH_OPTION_DEPRESS:
200: /*
201: * Depress priority for given time.
202: */
203: thread_depress_priority(cur_thread, option_time);
204: break;
205:
206: case SWITCH_OPTION_WAIT:
207: thread_will_wait_with_timeout(cur_thread, option_time);
208: break;
209:
210: default:
211: return(KERN_INVALID_ARGUMENT);
212: }
213:
214: #ifndef MIGRATING_THREADS /* XXX thread_run defunct */
215: /*
216: * Check and act on thread hint if appropriate.
217: */
218: if ((thread_name != 0) &&
219: (ipc_port_translate_send(cur_thread->task->itk_space,
220: thread_name, &port) == KERN_SUCCESS)) {
221: /* port is locked, but it might not be active */
222:
223: /*
224: * Get corresponding thread.
225: */
226: if (ip_active(port) && (ip_kotype(port) == IKOT_THREAD)) {
227: register thread_t thread;
228: register spl_t s;
229:
230: thread = (thread_t) port->ip_kobject;
231: /*
232: * Check if the thread is in the right pset. Then
233: * pull it off its run queue. If it
234: * doesn't come, then it's not eligible.
235: */
236: s = splsched();
237: thread_lock(thread);
238: if ((thread->processor_set == cur_thread->processor_set)
239: && (rem_runq(thread) != RUN_QUEUE_NULL)) {
240: /*
241: * Hah, got it!!
242: */
243: thread_unlock(thread);
244: (void) splx(s);
245: ip_unlock(port);
246: /* XXX thread might disappear on us now? */
247: #if MACH_FIXPRI
248: if (thread->policy == POLICY_FIXEDPRI) {
249: myprocessor = current_processor();
250: myprocessor->quantum = thread->sched_data;
251: myprocessor->first_quantum = TRUE;
252: }
253: #endif /* MACH_FIXPRI */
254: counter(c_thread_switch_handoff++);
255: thread_run(thread_switch_continue, thread);
256: /*
257: * Restore depressed priority
258: */
259: if (cur_thread->depress_priority >= 0)
260: (void) thread_depress_abort(cur_thread);
261:
262: return(KERN_SUCCESS);
263: }
264: thread_unlock(thread);
265: (void) splx(s);
266: }
267: ip_unlock(port);
268: }
269: #endif /* not MIGRATING_THREADS */
270:
271: /*
272: * No handoff hint supplied, or hint was wrong. Call thread_block() in
273: * hopes of running something else. If nothing else is runnable,
274: * thread_block will detect this. WARNING: thread_switch with no
275: * option will not do anything useful if the thread calling it is the
276: * highest priority thread (can easily happen with a collection
277: * of timesharing threads).
278: */
279: #if NCPUS > 1
280: myprocessor = current_processor();
281: if (myprocessor->processor_set->runq.count > 0 ||
282: myprocessor->runq.count > 0)
283: #endif /* NCPUS > 1 */
284: {
285: counter(c_thread_switch_block++);
286: thread_block(thread_switch_continue);
287: }
288:
289: /*
290: * Restore depressed priority
291: */
292: if (cur_thread->depress_priority >= 0)
293: (void) thread_depress_abort(cur_thread);
294: return(KERN_SUCCESS);
295: }
296:
297: /*
298: * thread_depress_priority
299: *
300: * Depress thread's priority to lowest possible for specified period.
301: * Intended for use when thread wants a lock but doesn't know which
302: * other thread is holding it. As with thread_switch, fixed
303: * priority threads get exactly what they asked for. Users access
304: * this by the SWITCH_OPTION_DEPRESS option to thread_switch. A Time
305: * of zero will result in no timeout being scheduled.
306: */
307: void
308: thread_depress_priority(thread, depress_time)
309: register thread_t thread;
310: mach_msg_timeout_t depress_time;
311: {
312: unsigned int ticks;
313: spl_t s;
314:
315: /* convert from milliseconds to ticks */
316: ticks = convert_ipc_timeout_to_ticks(depress_time);
317:
318: s = splsched();
319: thread_lock(thread);
320:
321: /*
322: * If thread is already depressed, override previous depression.
323: */
324: reset_timeout_check(&thread->depress_timer);
325:
326: /*
327: * Save current priority, then set priority and
328: * sched_pri to their lowest possible values.
329: */
330: thread->depress_priority = thread->priority;
331: thread->priority = 31;
332: thread->sched_pri = 31;
333: if (ticks != 0)
334: set_timeout(&thread->depress_timer, ticks);
335:
336: thread_unlock(thread);
337: (void) splx(s);
338: }
339:
340: /*
341: * thread_depress_timeout:
342: *
343: * Timeout routine for priority depression.
344: */
345: void
346: thread_depress_timeout(thread)
347: register thread_t thread;
348: {
349: spl_t s;
350:
351: s = splsched();
352: thread_lock(thread);
353:
354: /*
355: * If we lose a race with thread_depress_abort,
356: * then depress_priority might be -1.
357: */
358:
359: if (thread->depress_priority >= 0) {
360: thread->priority = thread->depress_priority;
361: thread->depress_priority = -1;
362: compute_priority(thread, FALSE);
363: }
364:
365: thread_unlock(thread);
366: (void) splx(s);
367: }
368:
369: /*
370: * thread_depress_abort:
371: *
372: * Prematurely abort priority depression if there is one.
373: */
374: kern_return_t
375: thread_depress_abort(thread)
376: register thread_t thread;
377: {
378: spl_t s;
379:
380: if (thread == THREAD_NULL)
381: return(KERN_INVALID_ARGUMENT);
382:
383: s = splsched();
384: thread_lock(thread);
385:
386: /*
387: * Only restore priority if thread is depressed.
388: */
389: if (thread->depress_priority >= 0) {
390: reset_timeout_check(&thread->depress_timer);
391: thread->priority = thread->depress_priority;
392: thread->depress_priority = -1;
393: compute_priority(thread, FALSE);
394: }
395:
396: thread_unlock(thread);
397: (void) splx(s);
398: return(KERN_SUCCESS);
399: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.