|
|
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) 1993, 1992,1991,1990 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 <cpus.h> ! 52: #include <mach_host.h> ! 53: ! 54: #include <mach/message.h> ! 55: #include <kern/counters.h> ! 56: #include <kern/cpu_number.h> ! 57: #include <kern/lock.h> ! 58: #include <kern/thread.h> ! 59: #include <kern/sched_prim.h> ! 60: #include <kern/processor.h> ! 61: #include <kern/time_out.h> ! 62: #include <kern/thread_swap.h> ! 63: #include <kern/ipc_sched.h> ! 64: #include <machine/machspl.h> /* for splsched/splx */ ! 65: #include <machine/pmap.h> ! 66: ! 67: #import <kern/assert.h> ! 68: ! 69: ! 70: /* ! 71: * These functions really belong in kern/sched_prim.c. ! 72: */ ! 73: ! 74: /* ! 75: * Routine: thread_go ! 76: * Purpose: ! 77: * Start a thread running. ! 78: * Conditions: ! 79: * IPC locks may be held. ! 80: */ ! 81: ! 82: void ! 83: thread_go( ! 84: thread_t thread) ! 85: { ! 86: int state; ! 87: spl_t s; ! 88: ! 89: s = splsched(); ! 90: thread_lock(thread); ! 91: ! 92: reset_timeout_check(&thread->timer); ! 93: ! 94: state = thread->state; ! 95: switch (state & TH_SCHED_STATE) { ! 96: ! 97: case TH_WAIT | TH_SUSP | TH_UNINT: ! 98: case TH_WAIT | TH_UNINT: ! 99: case TH_WAIT: ! 100: /* ! 101: * Sleeping and not suspendable - put ! 102: * on run queue. ! 103: */ ! 104: thread->state = (state &~ TH_WAIT) | TH_RUN; ! 105: thread->wait_result = THREAD_AWAKENED; ! 106: thread_setrun(thread, TRUE); ! 107: break; ! 108: ! 109: case TH_WAIT | TH_SUSP: ! 110: case TH_RUN | TH_WAIT: ! 111: case TH_RUN | TH_WAIT | TH_SUSP: ! 112: case TH_RUN | TH_WAIT | TH_UNINT: ! 113: case TH_RUN | TH_WAIT | TH_SUSP | TH_UNINT: ! 114: /* ! 115: * Either already running, or suspended. ! 116: */ ! 117: thread->state = state & ~TH_WAIT; ! 118: thread->wait_result = THREAD_AWAKENED; ! 119: break; ! 120: ! 121: default: ! 122: /* ! 123: * Not waiting. ! 124: */ ! 125: break; ! 126: } ! 127: ! 128: thread_unlock(thread); ! 129: splx(s); ! 130: } ! 131: ! 132: /* ! 133: * Routine: thread_go_and_switch ! 134: * Purpose: ! 135: * Start a thread running. ! 136: * Conditions: ! 137: * No IPC locks held. ! 138: */ ! 139: ! 140: void ! 141: thread_go_and_switch( ! 142: continuation_t continuation, ! 143: thread_t thread) ! 144: { ! 145: int state; ! 146: spl_t s; ! 147: ! 148: s = splsched(); ! 149: thread_lock(thread); ! 150: ! 151: reset_timeout_check(&thread->timer); ! 152: ! 153: state = thread->state; ! 154: switch (state & TH_SCHED_STATE) { ! 155: ! 156: case TH_WAIT | TH_SUSP | TH_UNINT: ! 157: case TH_WAIT | TH_UNINT: ! 158: case TH_WAIT: ! 159: /* ! 160: * Sleeping and not suspendable - put ! 161: * on run queue. ! 162: */ ! 163: thread->state = (state &~ TH_WAIT) | TH_RUN; ! 164: thread->wait_result = THREAD_AWAKENED; ! 165: if ((thread->processor_set->idle_count > 0) || ! 166: (thread->processor_set != ! 167: current_thread()->processor_set)) { ! 168: /* ! 169: * Other cpus can/must run thread. ! 170: * Put it on the run queues. ! 171: */ ! 172: thread_setrun(thread, TRUE); ! 173: break; ! 174: } ! 175: else { ! 176: /* ! 177: * Switch immediately to new thread. ! 178: */ ! 179: thread_unlock(thread); ! 180: thread_run(continuation, thread); ! 181: splx(s); ! 182: return; ! 183: } ! 184: break; ! 185: ! 186: case TH_WAIT | TH_SUSP: ! 187: case TH_RUN | TH_WAIT: ! 188: case TH_RUN | TH_WAIT | TH_SUSP: ! 189: case TH_RUN | TH_WAIT | TH_UNINT: ! 190: case TH_RUN | TH_WAIT | TH_SUSP | TH_UNINT: ! 191: /* ! 192: * Either already running, or suspended. ! 193: */ ! 194: thread->state = state & ~TH_WAIT; ! 195: thread->wait_result = THREAD_AWAKENED; ! 196: break; ! 197: ! 198: default: ! 199: /* ! 200: * Not waiting. ! 201: */ ! 202: break; ! 203: } ! 204: ! 205: thread_unlock(thread); ! 206: if (continuation != (void (*)()) 0) { ! 207: (void) spl0(); ! 208: call_continuation(continuation); ! 209: } ! 210: splx(s); ! 211: } ! 212: ! 213: /* ! 214: * Routine: thread_will_wait ! 215: * Purpose: ! 216: * Assert that the thread intends to block. ! 217: */ ! 218: ! 219: void ! 220: thread_will_wait( ! 221: thread_t thread) ! 222: { ! 223: spl_t s; ! 224: ! 225: s = splsched(); ! 226: thread_lock(thread); ! 227: ! 228: assert(thread->wait_result = -1); /* for later assertions */ ! 229: thread->state |= TH_WAIT; ! 230: ! 231: thread_unlock(thread); ! 232: splx(s); ! 233: } ! 234: ! 235: /* ! 236: * Routine: thread_will_wait_with_timeout ! 237: * Purpose: ! 238: * Assert that the thread intends to block, ! 239: * with a timeout. ! 240: */ ! 241: ! 242: void ! 243: thread_will_wait_with_timeout( ! 244: thread_t thread, ! 245: mach_msg_timeout_t msecs) ! 246: { ! 247: natural_t ticks = convert_ipc_timeout_to_ticks(msecs); ! 248: spl_t s; ! 249: ! 250: s = splsched(); ! 251: thread_lock(thread); ! 252: ! 253: assert(thread->wait_result = -1); /* for later assertions */ ! 254: thread->state |= TH_WAIT; ! 255: ! 256: if (ticks != 0 || msecs == 0) ! 257: set_timeout(&thread->timer, ticks); ! 258: ! 259: thread_unlock(thread); ! 260: splx(s); ! 261: } ! 262: ! 263: #if MACH_HOST ! 264: #define check_processor_set(thread) \ ! 265: (current_processor()->processor_set == (thread)->processor_set) ! 266: #else /* MACH_HOST */ ! 267: #define check_processor_set(thread) TRUE ! 268: #endif /* MACH_HOST */ ! 269: ! 270: #if NCPUS > 1 ! 271: #define check_bound_processor(thread) \ ! 272: ((thread)->bound_processor == PROCESSOR_NULL || \ ! 273: (thread)->bound_processor == current_processor()) ! 274: #else /* NCPUS > 1 */ ! 275: #define check_bound_processor(thread) TRUE ! 276: #endif /* NCPUS > 1 */ ! 277: ! 278: /* ! 279: * Routine: thread_handoff ! 280: * Purpose: ! 281: * Switch to a new thread (new), leaving the current ! 282: * thread (old) blocked. If successful, moves the ! 283: * kernel stack from old to new and returns as the ! 284: * new thread. An explicit continuation for the old thread ! 285: * must be supplied. ! 286: * ! 287: * NOTE: Although we wakeup new, we don't set new->wait_result. ! 288: * Returns: ! 289: * TRUE if the handoff happened. ! 290: */ ! 291: ! 292: boolean_t ! 293: thread_handoff( ! 294: register thread_t old, ! 295: register continuation_t continuation, ! 296: register thread_t new) ! 297: { ! 298: spl_t s; ! 299: ! 300: assert(current_thread() == old); ! 301: ! 302: /* ! 303: * XXX Dubious things here: ! 304: * I don't check the idle_count on the processor set. ! 305: * No scheduling priority or policy checks. ! 306: * I assume the new thread is interruptible. ! 307: */ ! 308: ! 309: s = splsched(); ! 310: thread_lock(new); ! 311: ! 312: /* ! 313: * The first thing we must do is check the state ! 314: * of the threads, to ensure we can handoff. ! 315: * This check uses current_processor()->processor_set, ! 316: * which we can read without locking. ! 317: */ ! 318: ! 319: if ((old->stack_privilege == current_stack()) || ! 320: (new->state != (TH_WAIT|TH_SWAPPED)) || ! 321: !check_processor_set(new) || ! 322: !check_bound_processor(new)) { ! 323: thread_unlock(new); ! 324: (void) splx(s); ! 325: ! 326: counter_always(c_thread_handoff_misses++); ! 327: return FALSE; ! 328: } ! 329: ! 330: reset_timeout_check(&new->timer); ! 331: ! 332: new->state = TH_RUN; ! 333: thread_unlock(new); ! 334: ! 335: #if NCPUS > 1 ! 336: new->last_processor = current_processor(); ! 337: #endif /* NCPUS > 1 */ ! 338: ! 339: ast_context(new, cpu_number()); ! 340: timer_switch(&new->system_timer); ! 341: ! 342: /* ! 343: * stack_handoff is machine-dependent. It does the ! 344: * machine-dependent components of a context-switch, like ! 345: * changing address spaces. It updates active_threads. ! 346: */ ! 347: ! 348: stack_handoff(old, new); ! 349: ! 350: /* ! 351: * Now we must dispose of the old thread. ! 352: * This is like thread_continue, except ! 353: * that the old thread isn't waiting yet. ! 354: */ ! 355: ! 356: thread_lock(old); ! 357: old->swap_func = continuation; ! 358: assert(old->wait_result = -1); /* for later assertions */ ! 359: ! 360: if (old->state == TH_RUN) { ! 361: /* ! 362: * This is our fast path. ! 363: */ ! 364: ! 365: old->state = TH_WAIT|TH_SWAPPED; ! 366: } ! 367: else if (old->state == (TH_RUN|TH_SUSP)) { ! 368: /* ! 369: * Somebody is trying to suspend the thread. ! 370: */ ! 371: ! 372: old->state = TH_WAIT|TH_SUSP|TH_SWAPPED; ! 373: if (old->wake_active) { ! 374: /* ! 375: * Someone wants to know when the thread ! 376: * really stops. ! 377: */ ! 378: old->wake_active = FALSE; ! 379: thread_unlock(old); ! 380: thread_wakeup((event_t)&old->wake_active); ! 381: goto after_old_thread; ! 382: } ! 383: } else ! 384: panic("thread_handoff"); ! 385: ! 386: thread_unlock(old); ! 387: after_old_thread: ! 388: (void) splx(s); ! 389: ! 390: counter_always(c_thread_handoff_hits++); ! 391: return TRUE; ! 392: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.