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