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