|
|
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.