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