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