|
|
1.1 ! root 1: /* ! 2: * Mach Operating System ! 3: * Copyright (c) 1993, 1992,1991,1990 Carnegie Mellon University ! 4: * All Rights Reserved. ! 5: * ! 6: * Permission to use, copy, modify and distribute this software and its ! 7: * documentation is hereby granted, provided that both the copyright ! 8: * notice and this permission notice appear in all copies of the ! 9: * software, derivative works or modified versions, and any portions ! 10: * thereof, and that both notices appear in supporting documentation. ! 11: * ! 12: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" ! 13: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR ! 14: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ! 15: * ! 16: * Carnegie Mellon requests users of this software to return to ! 17: * ! 18: * Software Distribution Coordinator or [email protected] ! 19: * School of Computer Science ! 20: * Carnegie Mellon University ! 21: * Pittsburgh PA 15213-3890 ! 22: * ! 23: * any improvements or extensions that they make and grant Carnegie Mellon ! 24: * the rights to redistribute these changes. ! 25: */ ! 26: ! 27: #include <cpus.h> ! 28: #include <mach_host.h> ! 29: ! 30: #include <mach/message.h> ! 31: #include <kern/counters.h> ! 32: #include "cpu_number.h" ! 33: #include <kern/lock.h> ! 34: #include <kern/thread.h> ! 35: #include <kern/sched_prim.h> ! 36: #include <kern/processor.h> ! 37: #include <kern/time_out.h> ! 38: #include <kern/thread_swap.h> ! 39: #include <kern/ipc_sched.h> ! 40: #include <machine/machspl.h> /* for splsched/splx */ ! 41: #include <machine/pmap.h> ! 42: ! 43: ! 44: ! 45: /* ! 46: * These functions really belong in kern/sched_prim.c. ! 47: */ ! 48: ! 49: /* ! 50: * Routine: thread_go ! 51: * Purpose: ! 52: * Start a thread running. ! 53: * Conditions: ! 54: * IPC locks may be held. ! 55: */ ! 56: ! 57: void ! 58: thread_go( ! 59: thread_t thread) ! 60: { ! 61: int state; ! 62: spl_t s; ! 63: ! 64: s = splsched(); ! 65: thread_lock(thread); ! 66: ! 67: reset_timeout_check(&thread->timer); ! 68: ! 69: state = thread->state; ! 70: switch (state & TH_SCHED_STATE) { ! 71: ! 72: case TH_WAIT | TH_SUSP | TH_UNINT: ! 73: case TH_WAIT | TH_UNINT: ! 74: case TH_WAIT: ! 75: /* ! 76: * Sleeping and not suspendable - put ! 77: * on run queue. ! 78: */ ! 79: thread->state = (state &~ TH_WAIT) | TH_RUN; ! 80: thread->wait_result = THREAD_AWAKENED; ! 81: thread_setrun(thread, TRUE); ! 82: break; ! 83: ! 84: case TH_WAIT | TH_SUSP: ! 85: case TH_RUN | TH_WAIT: ! 86: case TH_RUN | TH_WAIT | TH_SUSP: ! 87: case TH_RUN | TH_WAIT | TH_UNINT: ! 88: case TH_RUN | TH_WAIT | TH_SUSP | TH_UNINT: ! 89: /* ! 90: * Either already running, or suspended. ! 91: */ ! 92: thread->state = state & ~TH_WAIT; ! 93: thread->wait_result = THREAD_AWAKENED; ! 94: break; ! 95: ! 96: default: ! 97: /* ! 98: * Not waiting. ! 99: */ ! 100: break; ! 101: } ! 102: ! 103: thread_unlock(thread); ! 104: splx(s); ! 105: } ! 106: ! 107: /* ! 108: * Routine: thread_will_wait ! 109: * Purpose: ! 110: * Assert that the thread intends to block. ! 111: */ ! 112: ! 113: void ! 114: thread_will_wait( ! 115: thread_t thread) ! 116: { ! 117: spl_t s; ! 118: ! 119: s = splsched(); ! 120: thread_lock(thread); ! 121: ! 122: assert(thread->wait_result = -1); /* for later assertions */ ! 123: thread->state |= TH_WAIT; ! 124: ! 125: thread_unlock(thread); ! 126: splx(s); ! 127: } ! 128: ! 129: /* ! 130: * Routine: thread_will_wait_with_timeout ! 131: * Purpose: ! 132: * Assert that the thread intends to block, ! 133: * with a timeout. ! 134: */ ! 135: ! 136: void ! 137: thread_will_wait_with_timeout( ! 138: thread_t thread, ! 139: mach_msg_timeout_t msecs) ! 140: { ! 141: natural_t ticks = convert_ipc_timeout_to_ticks(msecs); ! 142: spl_t s; ! 143: ! 144: s = splsched(); ! 145: thread_lock(thread); ! 146: ! 147: assert(thread->wait_result = -1); /* for later assertions */ ! 148: thread->state |= TH_WAIT; ! 149: ! 150: set_timeout(&thread->timer, ticks); ! 151: ! 152: thread_unlock(thread); ! 153: splx(s); ! 154: } ! 155: ! 156: #if MACH_HOST ! 157: #define check_processor_set(thread) \ ! 158: (current_processor()->processor_set == (thread)->processor_set) ! 159: #else /* MACH_HOST */ ! 160: #define check_processor_set(thread) TRUE ! 161: #endif /* MACH_HOST */ ! 162: ! 163: #if NCPUS > 1 ! 164: #define check_bound_processor(thread) \ ! 165: ((thread)->bound_processor == PROCESSOR_NULL || \ ! 166: (thread)->bound_processor == current_processor()) ! 167: #else /* NCPUS > 1 */ ! 168: #define check_bound_processor(thread) TRUE ! 169: #endif /* NCPUS > 1 */ ! 170: ! 171: #ifdef CONTINUATIONS ! 172: /* ! 173: * Routine: thread_handoff ! 174: * Purpose: ! 175: * Switch to a new thread (new), leaving the current ! 176: * thread (old) blocked. If successful, moves the ! 177: * kernel stack from old to new and returns as the ! 178: * new thread. An explicit continuation for the old thread ! 179: * must be supplied. ! 180: * ! 181: * NOTE: Although we wakeup new, we don't set new->wait_result. ! 182: * Returns: ! 183: * TRUE if the handoff happened. ! 184: */ ! 185: ! 186: boolean_t ! 187: thread_handoff( ! 188: register thread_t old, ! 189: register continuation_t continuation, ! 190: register thread_t new) ! 191: { ! 192: spl_t s; ! 193: ! 194: assert(current_thread() == old); ! 195: ! 196: /* ! 197: * XXX Dubious things here: ! 198: * I don't check the idle_count on the processor set. ! 199: * No scheduling priority or policy checks. ! 200: * I assume the new thread is interruptible. ! 201: */ ! 202: ! 203: s = splsched(); ! 204: thread_lock(new); ! 205: ! 206: /* ! 207: * The first thing we must do is check the state ! 208: * of the threads, to ensure we can handoff. ! 209: * This check uses current_processor()->processor_set, ! 210: * which we can read without locking. ! 211: */ ! 212: ! 213: if ((old->stack_privilege == current_stack()) || ! 214: (new->state != (TH_WAIT|TH_SWAPPED)) || ! 215: !check_processor_set(new) || ! 216: !check_bound_processor(new)) { ! 217: thread_unlock(new); ! 218: (void) splx(s); ! 219: ! 220: counter_always(c_thread_handoff_misses++); ! 221: return FALSE; ! 222: } ! 223: ! 224: reset_timeout_check(&new->timer); ! 225: ! 226: new->state = TH_RUN; ! 227: thread_unlock(new); ! 228: ! 229: #if NCPUS > 1 ! 230: new->last_processor = current_processor(); ! 231: #endif /* NCPUS > 1 */ ! 232: ! 233: ast_context(new, cpu_number()); ! 234: timer_switch(&new->system_timer); ! 235: ! 236: /* ! 237: * stack_handoff is machine-dependent. It does the ! 238: * machine-dependent components of a context-switch, like ! 239: * changing address spaces. It updates active_threads. ! 240: */ ! 241: ! 242: stack_handoff(old, new); ! 243: ! 244: /* ! 245: * Now we must dispose of the old thread. ! 246: * This is like thread_continue, except ! 247: * that the old thread isn't waiting yet. ! 248: */ ! 249: ! 250: thread_lock(old); ! 251: old->swap_func = continuation; ! 252: assert(old->wait_result = -1); /* for later assertions */ ! 253: ! 254: if (old->state == TH_RUN) { ! 255: /* ! 256: * This is our fast path. ! 257: */ ! 258: ! 259: old->state = TH_WAIT|TH_SWAPPED; ! 260: } ! 261: else if (old->state == (TH_RUN|TH_SUSP)) { ! 262: /* ! 263: * Somebody is trying to suspend the thread. ! 264: */ ! 265: ! 266: old->state = TH_WAIT|TH_SUSP|TH_SWAPPED; ! 267: if (old->wake_active) { ! 268: /* ! 269: * Someone wants to know when the thread ! 270: * really stops. ! 271: */ ! 272: old->wake_active = FALSE; ! 273: thread_unlock(old); ! 274: thread_wakeup((event_t)&old->wake_active); ! 275: goto after_old_thread; ! 276: } ! 277: } else ! 278: panic("thread_handoff"); ! 279: ! 280: thread_unlock(old); ! 281: after_old_thread: ! 282: (void) splx(s); ! 283: ! 284: counter_always(c_thread_handoff_hits++); ! 285: return TRUE; ! 286: } ! 287: #endif /* CONTINUATIONS */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.