|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* ! 23: * @OSF_FREE_COPYRIGHT@ ! 24: */ ! 25: /* ! 26: * Copyright (c) 1993 The University of Utah and ! 27: * the Center for Software Science (CSS). All rights reserved. ! 28: * ! 29: * Permission to use, copy, modify and distribute this software and its ! 30: * documentation is hereby granted, provided that both the copyright ! 31: * notice and this permission notice appear in all copies of the ! 32: * software, derivative works or modified versions, and any portions ! 33: * thereof, and that both notices appear in supporting documentation. ! 34: * ! 35: * THE UNIVERSITY OF UTAH AND CSS ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS ! 36: * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSS DISCLAIM ANY LIABILITY OF ! 37: * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ! 38: * ! 39: * CSS requests users of this software to return to [email protected] any ! 40: * improvements that they make and grant CSS redistribution rights. ! 41: * ! 42: * Author: Bryan Ford, University of Utah CSS ! 43: * ! 44: * Thread_Activation management routines ! 45: */ ! 46: ! 47: #include <cpus.h> ! 48: #include <task_swapper.h> ! 49: #include <mach/kern_return.h> ! 50: #include <mach/alert.h> ! 51: #include <kern/etap_macros.h> ! 52: #include <kern/mach_param.h> ! 53: #include <kern/zalloc.h> ! 54: #include <kern/thread.h> ! 55: #include <kern/thread_swap.h> ! 56: #include <kern/task.h> ! 57: #include <kern/task_swap.h> ! 58: #include <kern/thread_act.h> ! 59: #include <kern/thread_pool.h> ! 60: #include <kern/sched_prim.h> ! 61: #include <kern/misc_protos.h> ! 62: #include <kern/assert.h> ! 63: #include <kern/exception.h> ! 64: #include <kern/ipc_mig.h> ! 65: #include <kern/ipc_tt.h> ! 66: #include <kern/profile.h> ! 67: #include <kern/machine.h> ! 68: #include <kern/spl.h> ! 69: #include <kern/syscall_subr.h> ! 70: #include <kern/sync_lock.h> ! 71: #include <kern/sf.h> ! 72: #include <kern/mk_sp.h> /*** ??? fix so this can be removed ***/ ! 73: #include <mach_prof.h> ! 74: #include <mach/rpc.h> ! 75: ! 76: /* ! 77: * Debugging printf control ! 78: */ ! 79: #if MACH_ASSERT ! 80: unsigned int watchacts = 0 /* WA_ALL */ ! 81: ; /* Do-it-yourself & patchable */ ! 82: #endif ! 83: ! 84: /* ! 85: * Track the number of times we need to swapin a thread to deallocate it. ! 86: */ ! 87: int act_free_swapin = 0; ! 88: extern boolean_t thread_swap_unwire_stack; ! 89: ! 90: #if THREAD_SWAP_UNWIRE_USER_STACK ! 91: extern boolean_t thread_swap_unwire_user_stack; ! 92: #else /* THREAD_SWAP_UNWIRE_USER_STACK */ ! 93: #define thread_swap_unwire_user_stack FALSE ! 94: #endif /* THREAD_SWAP_UNWIRE_USER_STACK */ ! 95: ! 96: /* ! 97: * Forward declarations for functions local to this file. ! 98: */ ! 99: kern_return_t act_abort( thread_act_t, int); ! 100: void special_handler(ReturnHandler *, thread_act_t); ! 101: void nudge(thread_act_t); ! 102: kern_return_t act_set_state_locked(thread_act_t, int, ! 103: thread_state_t, ! 104: mach_msg_type_number_t); ! 105: kern_return_t act_get_state_locked(thread_act_t, int, ! 106: thread_state_t, ! 107: mach_msg_type_number_t *); ! 108: void act_set_apc(thread_act_t); ! 109: void act_clr_apc(thread_act_t); ! 110: void act_user_to_kernel(thread_act_t); ! 111: void act_ulock_release_all(thread_act_t thr_act); ! 112: ! 113: kern_return_t terminate_empty_act(thread_act_t); ! 114: void install_special_handler_locked(thread_act_t); ! 115: ! 116: static zone_t thr_act_zone; ! 117: ! 118: /* ! 119: * Thread interfaces accessed via a thread_activation: ! 120: */ ! 121: ! 122: /* ! 123: * Terminate a thread. Called with nothing locked. ! 124: * Returns same way. ! 125: */ ! 126: kern_return_t ! 127: thread_terminate( ! 128: register thread_act_t thr_act) ! 129: { ! 130: thread_t thread; ! 131: task_t task; ! 132: struct ipc_port *iplock; ! 133: kern_return_t ret = KERN_INVALID_ARGUMENT; ! 134: #if NCPUS > 1 ! 135: boolean_t held; ! 136: #endif /* NCPUS > 1 */ ! 137: ! 138: if (thr_act == THR_ACT_NULL) ! 139: return(ret); ! 140: ! 141: if (((thr_act->task == kernel_task) || (thr_act->kernel_loaded == TRUE)) ! 142: && (current_act() != thr_act)) { ! 143: return(KERN_FAILURE); ! 144: } ! 145: ! 146: #if THREAD_SWAPPER ! 147: thread_swap_disable(thr_act); ! 148: #endif /* THREAD_SWAPPER */ ! 149: ! 150: /* ! 151: * Lock task containing target thread before (really) ! 152: * getting thread locks. ! 153: */ ! 154: act_lock(thr_act); ! 155: task = thr_act->task; ! 156: act_unlock(thr_act); ! 157: task_lock(task); ! 158: ! 159: thread = act_lock_thread(thr_act); ! 160: if (!thr_act->active) { ! 161: act_unlock_thread(thr_act); ! 162: task_unlock(task); ! 163: return(KERN_TERMINATED); ! 164: } ! 165: ! 166: /* ! 167: * Break IPC control over the thread. ! 168: */ ! 169: ipc_thr_act_disable_act_locked(thr_act); ! 170: ! 171: #if NCPUS > 1 ! 172: /* ! 173: * Make sure this thread enters the kernel ! 174: */ ! 175: if (thread != THREAD_NULL && thread != current_thread()) { ! 176: thread_hold(thr_act); ! 177: act_unlock_thread(thr_act); ! 178: #if 1 /* Grenoble */ ! 179: if (!thread_stop_wait(thread)) { ! 180: ret = KERN_ABORTED; ! 181: (void)act_lock_thread(thr_act); ! 182: thread_release(thr_act); ! 183: act_unlock_thread(thr_act); ! 184: task_unlock(task); ! 185: return (ret); ! 186: } ! 187: #else ! 188: thread_stop_wait(thread); ! 189: #endif ! 190: held = TRUE; ! 191: (void)act_lock_thread(thr_act); ! 192: } else { ! 193: held = FALSE; ! 194: } ! 195: #endif /* NCPUS > 1 */ ! 196: ! 197: #if 0 /* Grenoble */ ! 198: /* ! 199: * Lock task containing target. ! 200: * Use mutex_try to respect lock ordering. ! 201: */ ! 202: ! 203: task = thr_act->task; ! 204: if (!mutex_try(&task->lock)) { ! 205: act_unlock_thread(thr_act); ! 206: task_lock(task); ! 207: thread = act_lock_thread(thr_act); ! 208: } ! 209: ! 210: ! 211: if (!thr_act->active) { ! 212: act_unlock_thread(thr_act); ! 213: task_unlock(task); ! 214: ret = KERN_TERMINATED; ! 215: goto out; ! 216: } ! 217: ! 218: /* ! 219: * Break IPC control over the thread. ! 220: */ ! 221: ipc_thr_act_disable_act_locked(thr_act); ! 222: ! 223: #endif ! 224: /* ! 225: * Check for terminating an empty thread_act -- detach it from ! 226: * its task, then deallocate its remaining refs here. ! 227: */ ! 228: if (thr_act->thread == THREAD_NULL) { ! 229: iplock = thr_act->pool_port; /* remember for unlock call */ ! 230: ret = terminate_empty_act( thr_act ); ! 231: ! 232: /* ! 233: * Release locks individually. (`act_unlock_thread()' ! 234: * will not work since `pool_port' field has changed.) ! 235: */ ! 236: ip_unlock(iplock); ! 237: act_unlock(thr_act); ! 238: } ! 239: else { ! 240: assert(thr_act->active); ! 241: act_disable_task_locked(thr_act); ! 242: ret = act_abort(thr_act,FALSE); ! 243: act_unlock_thread(thr_act); ! 244: } ! 245: ! 246: task_unlock(task); ! 247: ! 248: if (((thr_act->task == kernel_task) || (thr_act->kernel_loaded == TRUE)) ! 249: && (current_act() == thr_act)) { ! 250: ast_taken(FALSE, AST_APC, 0); ! 251: panic("thread_terminate(): returning from ast_taken() for %x kernel activation\n", thr_act); ! 252: } ! 253: ! 254: #if 0 /* Grenoble */ ! 255: out: ! 256: #endif ! 257: ! 258: #if NCPUS > 1 ! 259: if (held) { ! 260: thread_unstop(thread); ! 261: (void)act_lock_thread(thr_act); ! 262: thread_release(thr_act); ! 263: act_unlock_thread(thr_act); ! 264: } ! 265: #endif /* NCPUS > 1 */ ! 266: return(ret); ! 267: } ! 268: ! 269: /* ! 270: * Called with empty thread activation and its pool port locked. ! 271: * Activation is currently "active." ! 272: * Task containing activation is also locked. ! 273: * Returns the same way. ! 274: */ ! 275: kern_return_t ! 276: terminate_empty_act( thread_act_t thr_act ) { ! 277: /* ! 278: * remove the activation from the pool port ! 279: * (this prevents it from being used) ! 280: */ ! 281: if (thr_act->pool_port) { ! 282: act_locked_act_set_thread_pool(thr_act, IP_NULL); ! 283: } ! 284: ! 285: /* ! 286: * disassociate the thread from the task ! 287: */ ! 288: assert(thr_act->active); ! 289: act_disable_task_locked( thr_act ); ! 290: ! 291: return KERN_SUCCESS; ! 292: } ! 293: ! 294: /* ! 295: * thread_hold: ! 296: * ! 297: * Suspend execution of the specified thread. ! 298: * This is a recursive-style suspension of the thread, a count of ! 299: * suspends is maintained. ! 300: * ! 301: * Called with thr_act locked "appropriately" for synchrony with ! 302: * RPC (see act_lock_thread()). Returns same way. ! 303: */ ! 304: void ! 305: thread_hold( ! 306: register thread_act_t thr_act) ! 307: { ! 308: if (thr_act->suspend_count++ == 0) { ! 309: install_special_handler(thr_act); ! 310: nudge(thr_act); ! 311: } ! 312: } ! 313: ! 314: /* ! 315: * Decrement internal suspension count for thr_act, setting thread ! 316: * runnable when count falls to zero. ! 317: * ! 318: * Called with thr_act locked "appropriately" for synchrony ! 319: * with RPC (see act_lock_thread()). ! 320: */ ! 321: void ! 322: thread_release( ! 323: register thread_act_t thr_act) ! 324: { ! 325: if( thr_act->suspend_count && ! 326: (--thr_act->suspend_count == 0) ) ! 327: nudge( thr_act ); ! 328: } ! 329: ! 330: kern_return_t ! 331: thread_suspend( ! 332: register thread_act_t thr_act) ! 333: { ! 334: thread_t thread; ! 335: ! 336: if (thr_act == THR_ACT_NULL) { ! 337: return(KERN_INVALID_ARGUMENT); ! 338: } ! 339: thread = act_lock_thread(thr_act); ! 340: if (!thr_act->active) { ! 341: act_unlock_thread(thr_act); ! 342: return(KERN_TERMINATED); ! 343: } ! 344: if (thr_act->user_stop_count++ == 0 && ! 345: thr_act->suspend_count++ == 0 ) { ! 346: install_special_handler(thr_act); ! 347: if (thread && ! 348: thr_act == thread->top_act && thread != current_thread()) { ! 349: nudge(thr_act); ! 350: act_unlock_thread(thr_act); ! 351: (void)thread_wait(thread); ! 352: } ! 353: else { ! 354: /* ! 355: * No need to wait for target thread ! 356: */ ! 357: act_unlock_thread(thr_act); ! 358: } ! 359: } ! 360: else { ! 361: /* ! 362: * Thread is already suspended ! 363: */ ! 364: act_unlock_thread(thr_act); ! 365: } ! 366: return(KERN_SUCCESS); ! 367: } ! 368: ! 369: kern_return_t ! 370: thread_resume( ! 371: register thread_act_t thr_act) ! 372: { ! 373: register kern_return_t ret; ! 374: spl_t s; ! 375: thread_t thread; ! 376: ! 377: if (thr_act == THR_ACT_NULL) ! 378: return(KERN_INVALID_ARGUMENT); ! 379: thread = act_lock_thread(thr_act); ! 380: ret = KERN_SUCCESS; ! 381: ! 382: if (thr_act->active) { ! 383: if (thr_act->user_stop_count > 0) { ! 384: if( --thr_act->user_stop_count == 0 ) { ! 385: --thr_act->suspend_count; ! 386: nudge( thr_act ); ! 387: } ! 388: } ! 389: else ! 390: ret = KERN_FAILURE; ! 391: } ! 392: else ! 393: ret = KERN_TERMINATED; ! 394: act_unlock_thread( thr_act ); ! 395: return ret; ! 396: } ! 397: ! 398: /* ! 399: * This routine walks toward the head of an RPC chain starting at ! 400: * a specified thread activation. An alert bit is set and a special ! 401: * handler is installed for each thread it encounters. ! 402: * ! 403: * The target thread act and thread shuttle are already locked. ! 404: */ ! 405: kern_return_t ! 406: post_alert( ! 407: register thread_act_t thr_act, ! 408: unsigned alert_bits ) ! 409: { ! 410: thread_act_t next; ! 411: thread_t thread; ! 412: ! 413: /* ! 414: * Chase the chain, setting alert bits and installing ! 415: * special handlers for each thread act. ! 416: */ ! 417: /*** Not yet SMP safe ***/ ! 418: /*** Worse, where's the activation locking as the chain is walked? ***/ ! 419: for (next = thr_act; next != THR_ACT_NULL; next = next->higher) { ! 420: next->alerts |= alert_bits; ! 421: install_special_handler_locked(next); ! 422: } ! 423: ! 424: return(KERN_SUCCESS); ! 425: } ! 426: ! 427: /* ! 428: * thread_depress_abort: ! 429: * ! 430: * Prematurely abort priority depression if there is one. ! 431: */ ! 432: kern_return_t ! 433: thread_depress_abort( ! 434: register thread_act_t thr_act) ! 435: { ! 436: register thread_t thread; ! 437: kern_return_t result; ! 438: sched_policy_t *policy; ! 439: spl_t s; ! 440: ! 441: if (thr_act == THR_ACT_NULL) ! 442: return (KERN_INVALID_ARGUMENT); ! 443: ! 444: thread = act_lock_thread(thr_act); ! 445: /* if activation is terminating, this operation is not meaningful */ ! 446: if (!thr_act->active) { ! 447: act_unlock_thread(thr_act); ! 448: ! 449: return (KERN_TERMINATED); ! 450: } ! 451: ! 452: if (thread == THREAD_NULL) { ! 453: act_unlock_thread(thr_act); ! 454: ! 455: return (KERN_INVALID_ARGUMENT); ! 456: } ! 457: ! 458: s = splsched(); ! 459: thread_lock(thread); ! 460: policy = &sched_policy[thread->policy]; ! 461: thread_unlock(thread); ! 462: splx(s); ! 463: ! 464: result = policy->sp_ops.sp_thread_depress_abort(policy, thread); ! 465: ! 466: act_unlock_thread(thr_act); ! 467: ! 468: return (result); ! 469: } ! 470: ! 471: ! 472: /* ! 473: * Already locked: all RPC-related locks for thr_act (see ! 474: * act_lock_thread()). ! 475: */ ! 476: kern_return_t ! 477: act_abort( thread_act_t thr_act, int chain_break ) ! 478: { ! 479: spl_t spl; ! 480: thread_t thread; ! 481: struct ipc_port *iplock = thr_act->pool_port; ! 482: thread_act_t orphan; ! 483: kern_return_t kr; ! 484: etap_data_t probe_data; ! 485: ! 486: /* ! 487: * mark the activation for abort, ! 488: * update the suspend count, ! 489: * always install the special handler ! 490: */ ! 491: install_special_handler(thr_act); ! 492: ! 493: ETAP_DATA_LOAD(probe_data[0], thr_act); ! 494: ETAP_DATA_LOAD(probe_data[1], thr_act->thread); ! 495: ETAP_PROBE_DATA(ETAP_P_ACT_ABORT, ! 496: 0, ! 497: current_thread(), ! 498: &probe_data, ! 499: ETAP_DATA_ENTRY*2); ! 500: ! 501: spl = splsched(); ! 502: thread_lock( thr_act->thread ); ! 503: ! 504: /* ! 505: * If the target thread activation is not the head... ! 506: */ ! 507: if ( thr_act->thread->top_act != thr_act ) { ! 508: #ifdef AGRESSIVE_ABORT ! 509: /* release state buffer for target's outstanding invocation */ ! 510: if (unwind_invoke_state(thr_act) != KERN_SUCCESS) { ! 511: panic("unwind_invoke_state failure"); ! 512: } ! 513: ! 514: /* release state buffer for target's incoming invocation */ ! 515: if (thr_act->lower != THR_ACT_NULL) { ! 516: if (unwind_invoke_state(thr_act->lower) ! 517: != KERN_SUCCESS) { ! 518: panic("unwind_invoke_state failure"); ! 519: } ! 520: } ! 521: ! 522: /* unlink target thread activation from shuttle chain */ ! 523: if ( thr_act->lower == THR_ACT_NULL ) { ! 524: /* ! 525: * This is the root thread activation of the chain. ! 526: * Unlink the root thread act from the bottom of ! 527: * the chain. ! 528: */ ! 529: thr_act->higher->lower = THR_ACT_NULL; ! 530: } else { ! 531: /* ! 532: * This thread act is in the middle of the chain. ! 533: * Unlink the thread act from the middle of the chain. ! 534: */ ! 535: thr_act->higher->lower = thr_act->lower; ! 536: thr_act->lower->higher = thr_act->higher; ! 537: ! 538: /* set the terminated bit for RPC return processing */ ! 539: thr_act->lower->alerts |= SERVER_TERMINATED; ! 540: } ! 541: ! 542: orphan = thr_act->higher; ! 543: ! 544: /* remove the activation from its thread pool */ ! 545: /* (note: this is okay for "rooted threads," too) */ ! 546: act_locked_act_set_thread_pool(thr_act, IP_NULL); ! 547: ! 548: /* (just to be thorough) release the IP lock */ ! 549: if (iplock != IP_NULL) ip_unlock(iplock); ! 550: ! 551: /* release one more reference for a rooted thread */ ! 552: if (iplock == IP_NULL) act_locked_act_deallocate(thr_act); ! 553: ! 554: /* Presumably, the only reference to this activation is ! 555: * now held by the caller of this routine. */ ! 556: assert(thr_act->ref_count == 1); ! 557: #else /*AGRESSIVE_ABORT*/ ! 558: /* If there is a lower activation in the RPC chain... */ ! 559: if (thr_act->lower != THR_ACT_NULL) { ! 560: /* ...indicate the server activation was terminated */ ! 561: thr_act->lower->alerts |= SERVER_TERMINATED; ! 562: } ! 563: /* Mark (and process) any orphaned activations */ ! 564: orphan = thr_act->higher; ! 565: #endif /*AGRESSIVE_ABORT*/ ! 566: ! 567: /* indicate client of orphaned chain has been terminated */ ! 568: orphan->alerts |= CLIENT_TERMINATED; ! 569: ! 570: /* ! 571: * Set up posting of alert to headward portion of ! 572: * the RPC chain. ! 573: */ ! 574: /*** fix me -- orphan act is not locked ***/ ! 575: post_alert(orphan, ORPHANED); ! 576: ! 577: /* ! 578: * Get attention of head of RPC chain. ! 579: */ ! 580: thread_unlock(thr_act->thread); ! 581: nudge(thr_act->thread->top_act); ! 582: splx(spl); ! 583: return (KERN_SUCCESS); ! 584: } ! 585: ! 586: /* ! 587: * If the target thread is the end of the chain, the thread ! 588: * has to be marked for abort and rip it out of any wait. ! 589: */ ! 590: if (thr_act->thread->top_act == thr_act) { ! 591: thr_act->thread->state |= TH_ABORT; ! 592: thread_unlock(thr_act->thread); ! 593: install_special_handler(thr_act); ! 594: nudge( thr_act ); ! 595: ! 596: /* ! 597: * if it's waiting, clear it. ! 598: */ ! 599: if( thr_act->thread->state & TH_WAIT ){ ! 600: clear_wait(thr_act->thread, THREAD_INTERRUPTED, TRUE); ! 601: splx(spl); ! 602: return KERN_SUCCESS; ! 603: } ! 604: } ! 605: else { ! 606: thread_unlock(thr_act->thread); ! 607: } ! 608: splx(spl); ! 609: return KERN_SUCCESS; ! 610: } ! 611: ! 612: kern_return_t ! 613: thread_abort( ! 614: register thread_act_t thr_act) ! 615: { ! 616: int ret; ! 617: thread_t thread; ! 618: ! 619: if (thr_act == THR_ACT_NULL || thr_act == current_act()) ! 620: return (KERN_INVALID_ARGUMENT); ! 621: /* ! 622: * Lock the target thread and the current thread now, ! 623: * in case thread_halt() ends up being called below. ! 624: */ ! 625: thread = act_lock_thread(thr_act); ! 626: if (!thr_act->active) { ! 627: act_unlock_thread(thr_act); ! 628: return(KERN_TERMINATED); ! 629: } ! 630: ! 631: if( thread == THREAD_NULL ) { ! 632: act_unlock_thread(thr_act); ! 633: return KERN_NO_THREAD; ! 634: } ! 635: ! 636: ret = act_abort( thr_act, FALSE ); ! 637: act_unlock_thread( thr_act ); ! 638: return ret; ! 639: } ! 640: ! 641: kern_return_t ! 642: thread_abort_safely( ! 643: register thread_act_t thr_act) ! 644: { ! 645: boolean_t r; ! 646: thread_t cur_thr = current_thread(); ! 647: thread_t thread, othread; ! 648: thread_act_t cur_thr_act = current_act(); ! 649: spl_t spl; ! 650: ! 651: if (thr_act == THR_ACT_NULL || thr_act == current_act()) ! 652: return(KERN_INVALID_ARGUMENT); ! 653: ! 654: othread = act_lock_thread(thr_act); ! 655: if (othread == THREAD_NULL) { ! 656: act_unlock_thread(thr_act); ! 657: return(KERN_INVALID_ARGUMENT); ! 658: } ! 659: if (!thr_act->active) { ! 660: act_unlock_thread(thr_act); ! 661: return(KERN_TERMINATED); ! 662: } ! 663: if (othread->top_act != thr_act) { ! 664: act_unlock_thread(thr_act); ! 665: return(KERN_FAILURE); ! 666: } ! 667: ! 668: /* ! 669: * This is the head of the chain. Stop it and check to see if ! 670: * it's in a condition which can be interrupted and restarted and, ! 671: * if so, clear the wait. ! 672: */ ! 673: thread_hold(thr_act); ! 674: act_unlock_thread(thr_act); ! 675: r = thread_stop_wait(othread); ! 676: if ((thread = act_lock_thread(thr_act)) != othread || !r) { ! 677: thread_release(thr_act); ! 678: act_unlock_thread(thr_act); ! 679: if (r) { ! 680: thread_unstop(othread); ! 681: return (KERN_FAILURE); ! 682: } ! 683: else ! 684: return(KERN_ABORTED); ! 685: } ! 686: ! 687: assert(thread == thr_act->thread); ! 688: ! 689: spl = splsched(); ! 690: thread_lock(thread); ! 691: ! 692: if( (thread->state&(TH_RUN|TH_UNINT|TH_WAIT)) == TH_WAIT ){ ! 693: if ( thread->at_safe_point ) { ! 694: /* ! 695: * It's an interruptible wait, clear it, then ! 696: * let the thread go and return successfully. ! 697: */ ! 698: thread_unlock(thread); ! 699: splx(spl); ! 700: clear_wait(thread, THREAD_INTERRUPTED, TRUE); ! 701: thread_unstop(thread); ! 702: thread_release(thr_act); ! 703: act_unlock_thread(thr_act); ! 704: return KERN_SUCCESS; ! 705: } ! 706: } ! 707: /* ! 708: * if not stopped at a safepoint, just let it go and return failure. ! 709: */ ! 710: thread_unlock(thread); ! 711: splx(spl); ! 712: thread_unstop(thread); ! 713: thread_release(thr_act); ! 714: act_unlock_thread(thr_act); ! 715: return KERN_FAILURE; ! 716: } ! 717: ! 718: /*** backward compatibility hacks ***/ ! 719: #include <mach/thread_info.h> ! 720: #include <mach/thread_special_ports.h> ! 721: #include <ipc/ipc_port.h> ! 722: #include <mach/thread_act_server.h> ! 723: ! 724: kern_return_t ! 725: thread_info( ! 726: thread_act_t thr_act, ! 727: thread_flavor_t flavor, ! 728: thread_info_t thread_info_out, ! 729: mach_msg_type_number_t *thread_info_count) ! 730: { ! 731: register thread_t thread; ! 732: kern_return_t result; ! 733: ! 734: if (thr_act == THR_ACT_NULL) ! 735: return (KERN_INVALID_ARGUMENT); ! 736: ! 737: thread = act_lock_thread(thr_act); ! 738: if (!thr_act->active) { ! 739: act_unlock_thread(thr_act); ! 740: ! 741: return (KERN_TERMINATED); ! 742: } ! 743: ! 744: if (thread == THREAD_NULL) { ! 745: act_unlock_thread(thr_act); ! 746: ! 747: return (KERN_NO_THREAD); ! 748: } ! 749: ! 750: result = thread_info_shuttle(thr_act, flavor, ! 751: thread_info_out, thread_info_count); ! 752: ! 753: act_unlock_thread(thr_act); ! 754: ! 755: return (result); ! 756: } ! 757: ! 758: /* ! 759: * Routine: thread_get_special_port [kernel call] ! 760: * Purpose: ! 761: * Clones a send right for one of the thread's ! 762: * special ports. ! 763: * Conditions: ! 764: * Nothing locked. ! 765: * Returns: ! 766: * KERN_SUCCESS Extracted a send right. ! 767: * KERN_INVALID_ARGUMENT The thread is null. ! 768: * KERN_FAILURE The thread is dead. ! 769: * KERN_INVALID_ARGUMENT Invalid special port. ! 770: */ ! 771: ! 772: kern_return_t ! 773: thread_get_special_port( ! 774: thread_act_t thr_act, ! 775: int which, ! 776: ipc_port_t *portp) ! 777: { ! 778: ipc_port_t *whichp; ! 779: ipc_port_t port; ! 780: thread_t thread; ! 781: ! 782: #if MACH_ASSERT ! 783: if (watchacts & WA_PORT) ! 784: printf("thread_get_special_port(thr_act=%x, which=%x port@%x=%x\n", ! 785: thr_act, which, portp, (portp ? *portp : 0)); ! 786: #endif /* MACH_ASSERT */ ! 787: ! 788: if (!thr_act) ! 789: return KERN_INVALID_ARGUMENT; ! 790: thread = act_lock_thread(thr_act); ! 791: switch (which) { ! 792: case THREAD_KERNEL_PORT: ! 793: whichp = &thr_act->ith_sself; ! 794: break; ! 795: ! 796: default: ! 797: act_unlock_thread(thr_act); ! 798: return KERN_INVALID_ARGUMENT; ! 799: } ! 800: ! 801: if (!thr_act->active) { ! 802: act_unlock_thread(thr_act); ! 803: return KERN_FAILURE; ! 804: } ! 805: ! 806: port = ipc_port_copy_send(*whichp); ! 807: act_unlock_thread(thr_act); ! 808: ! 809: *portp = port; ! 810: return KERN_SUCCESS; ! 811: } ! 812: ! 813: /* ! 814: * Routine: thread_set_special_port [kernel call] ! 815: * Purpose: ! 816: * Changes one of the thread's special ports, ! 817: * setting it to the supplied send right. ! 818: * Conditions: ! 819: * Nothing locked. If successful, consumes ! 820: * the supplied send right. ! 821: * Returns: ! 822: * KERN_SUCCESS Changed the special port. ! 823: * KERN_INVALID_ARGUMENT The thread is null. ! 824: * KERN_FAILURE The thread is dead. ! 825: * KERN_INVALID_ARGUMENT Invalid special port. ! 826: */ ! 827: ! 828: kern_return_t ! 829: thread_set_special_port( ! 830: thread_act_t thr_act, ! 831: int which, ! 832: ipc_port_t port) ! 833: { ! 834: ipc_port_t *whichp; ! 835: ipc_port_t old; ! 836: thread_t thread; ! 837: ! 838: #if MACH_ASSERT ! 839: if (watchacts & WA_PORT) ! 840: printf("thread_set_special_port(thr_act=%x,which=%x,port=%x\n", ! 841: thr_act, which, port); ! 842: #endif /* MACH_ASSERT */ ! 843: ! 844: if (thr_act == 0) ! 845: return KERN_INVALID_ARGUMENT; ! 846: ! 847: thread = act_lock_thread(thr_act); ! 848: switch (which) { ! 849: case THREAD_KERNEL_PORT: ! 850: whichp = &thr_act->ith_self; ! 851: break; ! 852: ! 853: default: ! 854: act_unlock_thread(thr_act); ! 855: return KERN_INVALID_ARGUMENT; ! 856: } ! 857: ! 858: if (!thr_act->active) { ! 859: act_unlock_thread(thr_act); ! 860: return KERN_FAILURE; ! 861: } ! 862: ! 863: old = *whichp; ! 864: *whichp = port; ! 865: act_unlock_thread(thr_act); ! 866: ! 867: if (IP_VALID(old)) ! 868: ipc_port_release_send(old); ! 869: return KERN_SUCCESS; ! 870: } ! 871: ! 872: /* ! 873: * thread state should always be accessible by locking the thread ! 874: * and copying it. The activation messes things up so for right ! 875: * now if it's not the top of the chain, use a special handler to ! 876: * get the information when the shuttle returns to the activation. ! 877: */ ! 878: kern_return_t ! 879: thread_get_state( ! 880: register thread_act_t thr_act, ! 881: int flavor, ! 882: thread_state_t state, /* pointer to OUT array */ ! 883: mach_msg_type_number_t *state_count) /*IN/OUT*/ ! 884: { ! 885: kern_return_t ret; ! 886: thread_t thread, nthread; ! 887: ! 888: #if 0 /* Grenoble - why?? */ ! 889: if (thr_act == THR_ACT_NULL || thr_act == current_act()) ! 890: #else ! 891: if (thr_act == THR_ACT_NULL) ! 892: #endif ! 893: return (KERN_INVALID_ARGUMENT); ! 894: ! 895: thread = act_lock_thread(thr_act); ! 896: if (!thr_act->active) { ! 897: act_unlock_thread(thr_act); ! 898: return(KERN_TERMINATED); ! 899: } ! 900: ! 901: thread_hold(thr_act); ! 902: while (1) { ! 903: if (!thread || thr_act != thread->top_act) ! 904: break; ! 905: act_unlock_thread(thr_act); ! 906: (void)thread_stop_wait(thread); ! 907: nthread = act_lock_thread(thr_act); ! 908: if (nthread == thread) ! 909: break; ! 910: thread_unstop(thread); ! 911: thread = nthread; ! 912: } ! 913: ret = act_machine_get_state(thr_act, flavor, ! 914: state, state_count); ! 915: if (thread && thr_act == thread->top_act) ! 916: thread_unstop(thread); ! 917: thread_release(thr_act); ! 918: act_unlock_thread(thr_act); ! 919: ! 920: return(ret); ! 921: } ! 922: ! 923: /* ! 924: * Change thread's machine-dependent state. Called with nothing ! 925: * locked. Returns same way. ! 926: */ ! 927: kern_return_t ! 928: thread_set_state( ! 929: register thread_act_t thr_act, ! 930: int flavor, ! 931: thread_state_t state, ! 932: mach_msg_type_number_t state_count) ! 933: { ! 934: kern_return_t ret; ! 935: thread_t thread, nthread; ! 936: ! 937: #if 0 /* Grenoble - why?? */ ! 938: if (thr_act == THR_ACT_NULL || thr_act == current_act()) ! 939: #else ! 940: if (thr_act == THR_ACT_NULL) ! 941: #endif ! 942: return (KERN_INVALID_ARGUMENT); ! 943: /* ! 944: * We have no kernel activations, so Utah's MO fails for signals etc. ! 945: * ! 946: * If we're blocked in the kernel, use non-blocking method, else ! 947: * pass locked thr_act+thread in to "normal" act_[gs]et_state(). ! 948: */ ! 949: ! 950: thread = act_lock_thread(thr_act); ! 951: if (!thr_act->active) { ! 952: act_unlock_thread(thr_act); ! 953: return(KERN_TERMINATED); ! 954: } ! 955: ! 956: thread_hold(thr_act); ! 957: while (1) { ! 958: if (!thread || thr_act != thread->top_act) ! 959: break; ! 960: act_unlock_thread(thr_act); ! 961: (void)thread_stop_wait(thread); ! 962: nthread = act_lock_thread(thr_act); ! 963: if (nthread == thread) ! 964: break; ! 965: thread_unstop(thread); ! 966: thread = nthread; ! 967: } ! 968: ret = act_machine_set_state(thr_act, flavor, ! 969: state, state_count); ! 970: if (thread && thr_act == thread->top_act) ! 971: thread_unstop(thread); ! 972: thread_release(thr_act); ! 973: act_unlock_thread(thr_act); ! 974: ! 975: return(ret); ! 976: } ! 977: ! 978: /* ! 979: * Kernel-internal "thread" interfaces used outside this file: ! 980: */ ! 981: ! 982: kern_return_t ! 983: thread_dup( ! 984: thread_act_t source_thr_act, ! 985: thread_act_t target_thr_act) ! 986: { ! 987: kern_return_t ret; ! 988: thread_t thread, nthread; ! 989: ! 990: if (target_thr_act == THR_ACT_NULL || target_thr_act == current_act()) ! 991: return (KERN_INVALID_ARGUMENT); ! 992: ! 993: thread = act_lock_thread(target_thr_act); ! 994: if (!target_thr_act->active) { ! 995: act_unlock_thread(target_thr_act); ! 996: return(KERN_TERMINATED); ! 997: } ! 998: ! 999: thread_hold(target_thr_act); ! 1000: while (1) { ! 1001: if (!thread || target_thr_act != thread->top_act) ! 1002: break; ! 1003: act_unlock_thread(target_thr_act); ! 1004: (void)thread_stop_wait(thread); ! 1005: nthread = act_lock_thread(target_thr_act); ! 1006: if (nthread == thread) ! 1007: break; ! 1008: thread_unstop(thread); ! 1009: thread = nthread; ! 1010: } ! 1011: ret = act_thread_dup(source_thr_act, target_thr_act); ! 1012: if (thread && target_thr_act == thread->top_act) ! 1013: thread_unstop(thread); ! 1014: thread_release(target_thr_act); ! 1015: act_unlock_thread(target_thr_act); ! 1016: ! 1017: return(ret); ! 1018: } ! 1019: ! 1020: ! 1021: /* ! 1022: * thread_setstatus: ! 1023: * ! 1024: * Set the status of the specified thread. ! 1025: * Called with (and returns with) no locks held. ! 1026: */ ! 1027: kern_return_t ! 1028: thread_setstatus( ! 1029: thread_act_t thr_act, ! 1030: int flavor, ! 1031: thread_state_t tstate, ! 1032: mach_msg_type_number_t count) ! 1033: { ! 1034: kern_return_t kr; ! 1035: thread_t thread; ! 1036: ! 1037: thread = act_lock_thread(thr_act); ! 1038: assert(thread); ! 1039: assert(thread->top_act == thr_act); ! 1040: kr = act_machine_set_state(thr_act, flavor, tstate, count); ! 1041: act_unlock_thread(thr_act); ! 1042: return(kr); ! 1043: } ! 1044: ! 1045: /* ! 1046: * thread_getstatus: ! 1047: * ! 1048: * Get the status of the specified thread. ! 1049: */ ! 1050: kern_return_t ! 1051: thread_getstatus( ! 1052: thread_act_t thr_act, ! 1053: int flavor, ! 1054: thread_state_t tstate, ! 1055: mach_msg_type_number_t *count) ! 1056: { ! 1057: kern_return_t kr; ! 1058: thread_t thread; ! 1059: ! 1060: thread = act_lock_thread(thr_act); ! 1061: assert(thread); ! 1062: assert(thread->top_act == thr_act); ! 1063: kr = act_machine_get_state(thr_act, flavor, tstate, count); ! 1064: act_unlock_thread(thr_act); ! 1065: return(kr); ! 1066: } ! 1067: ! 1068: /* ! 1069: * Kernel-internal thread_activation interfaces used outside this file: ! 1070: */ ! 1071: ! 1072: /* ! 1073: * act_init() - Initialize activation handling code ! 1074: */ ! 1075: void ! 1076: act_init() ! 1077: { ! 1078: thr_act_zone = zinit( ! 1079: sizeof(struct thread_activation), ! 1080: ACT_MAX * sizeof(struct thread_activation), /* XXX */ ! 1081: ACT_CHUNK * sizeof(struct thread_activation), ! 1082: "activations"); ! 1083: act_machine_init(); ! 1084: } ! 1085: ! 1086: ! 1087: /* ! 1088: * act_create - Create a new activation in a specific task. ! 1089: */ ! 1090: kern_return_t ! 1091: act_create(task_t task, ! 1092: thread_act_params_t params, ! 1093: thread_act_t *new_act) ! 1094: { ! 1095: thread_act_t thr_act; ! 1096: int rc; ! 1097: vm_map_t map; ! 1098: ! 1099: thr_act = (thread_act_t)zalloc(thr_act_zone); ! 1100: if (thr_act == 0) ! 1101: return(KERN_RESOURCE_SHORTAGE); ! 1102: ! 1103: #if MACH_ASSERT ! 1104: if (watchacts & WA_ACT_LNK) ! 1105: printf("act_create(task=%x,stk=%x,thr_act@%x=%x)\n", ! 1106: task, params ? params->stack : 0, new_act, thr_act); ! 1107: #endif /* MACH_ASSERT */ ! 1108: ! 1109: /* Start by zeroing everything; then init non-zero items only */ ! 1110: bzero((char *)thr_act, sizeof(*thr_act)); ! 1111: ! 1112: /* Start with one reference for being active, another for the caller */ ! 1113: act_lock_init(thr_act); ! 1114: thr_act->ref_count = 2; ! 1115: ! 1116: /* Latch onto the task. */ ! 1117: thr_act->task = task; ! 1118: task_reference(task); ! 1119: thr_act->active = 1; ! 1120: ! 1121: /* Initialize sigbufp for High-Watermark buffer allocation */ ! 1122: thr_act->r_sigbufp = (routine_descriptor_t) &thr_act->r_sigbuf; ! 1123: thr_act->r_sigbuf_size = sizeof(thr_act->r_sigbuf); ! 1124: ! 1125: /* Initialize thread stack */ ! 1126: if (params) ! 1127: { ! 1128: thr_act->user_stack = params->stack; ! 1129: thr_act->user_stack_size = params->stack_size; ! 1130: thr_act->user_entry = params->entry_func; ! 1131: } ! 1132: else ! 1133: { ! 1134: thr_act->user_stack = 0; ! 1135: thr_act->user_stack_size = 0; ! 1136: thr_act->user_entry = 0; ! 1137: } ! 1138: ! 1139: #if THREAD_SWAPPER ! 1140: thr_act->swap_state = TH_SW_IN; ! 1141: #if MACH_ASSERT ! 1142: thr_act->kernel_stack_swapped_in = TRUE; ! 1143: #if THREAD_SWAP_UNWIRE_USER_STACK ! 1144: thr_act->user_stack_swapped_in = TRUE; ! 1145: #endif /* THREAD_SWAP_UNWIRE_USER_STACK */ ! 1146: #endif /* MACH_ASSERT */ ! 1147: #endif /* THREAD_SWAPPER */ ! 1148: ! 1149: /* special_handler will always be last on the returnhandlers list. */ ! 1150: thr_act->special_handler.next = 0; ! 1151: thr_act->special_handler.handler = special_handler; ! 1152: ! 1153: #if MACH_PROF ! 1154: thr_act->act_profiled = FALSE; ! 1155: thr_act->act_profiled_own = FALSE; ! 1156: thr_act->profil_buffer = NULLPROFDATA; ! 1157: #endif ! 1158: ! 1159: /* Initialize the held_ulocks queue as empty */ ! 1160: queue_init(&thr_act->held_ulocks); ! 1161: ! 1162: /* Inherit the profiling status of the parent task */ ! 1163: act_prof_init(thr_act, task); ! 1164: ! 1165: ipc_thr_act_init(task, thr_act); ! 1166: act_machine_create(task, thr_act); ! 1167: ! 1168: /* ! 1169: * If thr_act created in kernel-loaded task, alter its saved ! 1170: * state to so indicate ! 1171: */ ! 1172: if (task->kernel_loaded) { ! 1173: act_user_to_kernel(thr_act); ! 1174: /* ! 1175: * If a user_stack was given, assume this is not a "base" ! 1176: * activation -- assert that it's fully kernel-loaded ! 1177: * already. ! 1178: */ ! 1179: if (thr_act->user_stack != 0) { ! 1180: thr_act->kernel_loading = FALSE; ! 1181: thr_act->kernel_loaded = TRUE; ! 1182: } ! 1183: } ! 1184: ! 1185: task_lock(task); ! 1186: ! 1187: /* Chain the thr_act onto the task's list */ ! 1188: mutex_lock(&task->act_list_lock); ! 1189: queue_enter(&task->thr_acts, thr_act, thread_act_t, thr_acts); ! 1190: task->thr_act_count++; ! 1191: /* no need to check for transition from 0 -> 1 here */ ! 1192: task->res_act_count++; ! 1193: mutex_unlock(&task->act_list_lock); ! 1194: ! 1195: task_unlock(task); ! 1196: ! 1197: /* Cache the task's map and take a reference to it */ ! 1198: thr_act->map = task->map; ! 1199: ! 1200: /* Inline vm_map_reference cause we don't want to increment res_count */ ! 1201: map = task->map; ! 1202: mutex_lock(&map->s_lock); ! 1203: #if TASK_SWAPPER ! 1204: assert(map->res_count > 0); ! 1205: assert(map->ref_count >= map->res_count); ! 1206: #endif /* TASK_SWAPPER */ ! 1207: map->ref_count++; ! 1208: mutex_unlock(&map->s_lock); ! 1209: ! 1210: *new_act = thr_act; ! 1211: return KERN_SUCCESS; ! 1212: } ! 1213: ! 1214: /* ! 1215: * act_free - called when an thr_act's ref_count drops to zero. ! 1216: * ! 1217: * This can only happen when thread is zero (not in use), ! 1218: * thread_pool is zero (not attached to any thread_pool), ! 1219: * and active is false (terminated). Called with act locked, ! 1220: * so that its shuttle pointer can be zeroed atomically. ! 1221: */ ! 1222: #if MACH_ASSERT ! 1223: int dangerous_bzero = 1; /* paranoia & safety */ ! 1224: #endif ! 1225: ! 1226: void ! 1227: act_free(thread_act_t thr_act) ! 1228: { ! 1229: thread_t thr; ! 1230: vm_map_t map; ! 1231: unsigned int ref; ! 1232: ! 1233: #if MACH_ASSERT ! 1234: if (watchacts & WA_EXIT) ! 1235: printf("act_free(%x(%d)) thr=%x tsk=%x(%d) pport=%x%sactive\n", ! 1236: thr_act, thr_act->ref_count, thr_act->thread, ! 1237: thr_act->task, ! 1238: thr_act->task ? thr_act->task->ref_count : 0, ! 1239: thr_act->pool_port, ! 1240: thr_act->active ? " " : " !"); ! 1241: #endif /* MACH_ASSERT */ ! 1242: ! 1243: /* Drop final ref to shuttle (not really ours, but we're ! 1244: * allowed to handle it). */ ! 1245: if (thr = thr_act->thread) { ! 1246: thr_act->thread = 0; ! 1247: act_unlock(thr_act); ! 1248: thread_deallocate(thr); ! 1249: } ! 1250: else ! 1251: act_unlock(thr_act); ! 1252: ! 1253: #if THREAD_SWAPPER ! 1254: thread_swap_disable(thr_act); ! 1255: assert(thr_act->kernel_stack_swapped_in); ! 1256: #endif /* THREAD_SWAPPER */ ! 1257: ! 1258: assert(!thr_act->active); ! 1259: assert(!thr_act->pool_port); ! 1260: ! 1261: act_machine_destroy(thr_act); ! 1262: ipc_thr_act_disable(thr_act); ! 1263: ipc_thr_act_terminate(thr_act); ! 1264: ! 1265: act_prof_deallocate(thr_act); ! 1266: ! 1267: /* ! 1268: * Drop the cached map reference. ! 1269: * Inline version of vm_map_deallocate() because we ! 1270: * don't want to decrement the map's residence count here. ! 1271: */ ! 1272: map = thr_act->map; ! 1273: mutex_lock(&map->s_lock); ! 1274: #if TASK_SWAPPER ! 1275: assert(map->res_count >= 0); ! 1276: assert(map->ref_count > map->res_count); ! 1277: #endif /* TASK_SWAPPER */ ! 1278: ref = --map->ref_count; ! 1279: mutex_unlock(&map->s_lock); ! 1280: ! 1281: /* ! 1282: * The task must still have a reference on the map. Also, if ! 1283: * the reference count drops to two (one remaining act and the ! 1284: * task itself), then someone may be waiting in task_halt_wait. ! 1285: * Wake them up, if needed. ! 1286: */ ! 1287: if (ref == 0) ! 1288: panic("thread_deallocate: released last reference on map"); ! 1289: else if (ref == 2) ! 1290: thread_wakeup(&map->ref_count); ! 1291: ! 1292: /* Drop the task reference. */ ! 1293: task_deallocate(thr_act->task); ! 1294: ! 1295: #if MACH_ASSERT ! 1296: if (dangerous_bzero) /* dangerous if we're still using it! */ ! 1297: bzero((char *)thr_act, sizeof(*thr_act)); ! 1298: #endif /* MACH_ASSERT */ ! 1299: /* Put the thr_act back on the thr_act zone */ ! 1300: zfree(thr_act_zone, (vm_offset_t)thr_act); ! 1301: } ! 1302: ! 1303: ! 1304: /* ! 1305: * act_attach - Attach an thr_act to the top of a thread ("push the stack"). ! 1306: * ! 1307: * The thread_shuttle must be either the current one or a brand-new one. ! 1308: * Assumes the thr_act is active but not in use, also, that if it is ! 1309: * attached to an thread_pool (i.e. the thread_pool pointer is nonzero), ! 1310: * the thr_act has already been taken off the thread_pool's list. ! 1311: * ! 1312: * Already locked: thr_act plus "appropriate" thread-related locks ! 1313: * (see act_lock_thread()). ! 1314: */ ! 1315: void ! 1316: act_attach( ! 1317: thread_act_t thr_act, ! 1318: thread_t thread, ! 1319: unsigned init_alert_mask) ! 1320: { ! 1321: thread_act_t lower; ! 1322: ! 1323: #if MACH_ASSERT ! 1324: assert(thread == current_thread() || thread->top_act == THR_ACT_NULL); ! 1325: if (watchacts & WA_ACT_LNK) ! 1326: printf("act_attach(thr_act %x(%d) thread %x(%d) mask %d)\n", ! 1327: thr_act, thr_act->ref_count, thread, thread->ref_count, ! 1328: init_alert_mask); ! 1329: #endif /* MACH_ASSERT */ ! 1330: ! 1331: /* ! 1332: * Chain the thr_act onto the thread's thr_act stack. ! 1333: * Set mask and auto-propagate alerts from below. ! 1334: */ ! 1335: thr_act->thread = thread; ! 1336: thr_act->higher = THR_ACT_NULL; /*safety*/ ! 1337: thr_act->alerts = 0; ! 1338: thr_act->alert_mask = init_alert_mask; ! 1339: lower = thr_act->lower = thread->top_act; ! 1340: ! 1341: if (lower != THR_ACT_NULL) { ! 1342: lower->higher = thr_act; ! 1343: thr_act->alerts = (lower->alerts & init_alert_mask); ! 1344: } ! 1345: ! 1346: thread->top_act = thr_act; ! 1347: } ! 1348: ! 1349: /* ! 1350: * act_detach ! 1351: * ! 1352: * Remove the current thr_act from the top of the current thread, i.e. ! 1353: * "pop the stack". Assumes already locked: thr_act plus "appropriate" ! 1354: * thread-related locks (see act_lock_thread). ! 1355: */ ! 1356: void ! 1357: act_detach( ! 1358: thread_act_t cur_act) ! 1359: { ! 1360: thread_t cur_thread = cur_act->thread; ! 1361: ! 1362: #if MACH_ASSERT ! 1363: if (watchacts & (WA_EXIT|WA_ACT_LNK)) ! 1364: printf("act_detach: thr_act %x(%d), thrd %x(%d) task=%x(%d)\n", ! 1365: cur_act, cur_act->ref_count, ! 1366: cur_thread, cur_thread->ref_count, ! 1367: cur_act->task, ! 1368: cur_act->task ? cur_act->task->ref_count : 0); ! 1369: #endif /* MACH_ASSERT */ ! 1370: ! 1371: /* Unlink the thr_act from the thread's thr_act stack */ ! 1372: cur_thread->top_act = cur_act->lower; ! 1373: cur_act->thread = 0; ! 1374: ! 1375: thread_pool_put_act(cur_act); ! 1376: ! 1377: #if MACH_ASSERT ! 1378: cur_act->lower = cur_act->higher = THR_ACT_NULL; ! 1379: if (cur_thread->top_act) ! 1380: cur_thread->top_act->higher = THR_ACT_NULL; ! 1381: #endif /* MACH_ASSERT */ ! 1382: ! 1383: return; ! 1384: } ! 1385: ! 1386: ! 1387: /* ! 1388: * Synchronize a thread operation with RPC. Called with nothing ! 1389: * locked. Returns with thr_act locked, plus one of four ! 1390: * combinations of other locks held: ! 1391: * none - for new activation not yet associated with thread_pool ! 1392: * or shuttle ! 1393: * rpc_lock(thr_act->thread) only - for base activation (one ! 1394: * without pool_port) ! 1395: * ip_lock(thr_act->pool_port) only - for empty activation (one ! 1396: * with no associated shuttle) ! 1397: * both locks - for "active" activation (has shuttle, lives ! 1398: * on thread_pool) ! 1399: * If thr_act has an associated shuttle, this function returns ! 1400: * its address. Otherwise it returns zero. ! 1401: */ ! 1402: thread_t ! 1403: act_lock_thread( ! 1404: thread_act_t thr_act) ! 1405: { ! 1406: ipc_port_t pport; ! 1407: ! 1408: /* ! 1409: * Allow the shuttle cloning code (q.v., when it ! 1410: * exists :-}) to obtain ip_lock()'s while holding ! 1411: * an rpc_lock(). ! 1412: */ ! 1413: while (1) { ! 1414: act_lock(thr_act); ! 1415: pport = thr_act->pool_port; ! 1416: if (!pport || ip_lock_try(pport)) { ! 1417: if (!thr_act->thread) ! 1418: break; ! 1419: if (rpc_lock_try(thr_act->thread)) ! 1420: break; ! 1421: if (pport) ! 1422: ip_unlock(pport); ! 1423: } ! 1424: act_unlock(thr_act); ! 1425: mutex_pause(); ! 1426: } ! 1427: return (thr_act->thread); ! 1428: } ! 1429: ! 1430: /* ! 1431: * Unsynchronize with RPC (i.e., undo an act_lock_thread() call). ! 1432: * Called with thr_act locked, plus thread locks held that are ! 1433: * "correct" for thr_act's state. Returns with nothing locked. ! 1434: */ ! 1435: void ! 1436: act_unlock_thread(thread_act_t thr_act) ! 1437: { ! 1438: if (thr_act->thread) ! 1439: rpc_unlock(thr_act->thread); ! 1440: if (thr_act->pool_port) ! 1441: ip_unlock(thr_act->pool_port); ! 1442: act_unlock(thr_act); ! 1443: } ! 1444: ! 1445: /* ! 1446: * Synchronize with RPC given a pointer to a shuttle (instead of an ! 1447: * activation). Called with nothing locked; returns with all ! 1448: * "appropriate" thread-related locks held (see act_lock_thread()). ! 1449: */ ! 1450: thread_act_t ! 1451: thread_lock_act( ! 1452: thread_t thread) ! 1453: { ! 1454: thread_act_t thr_act; ! 1455: ! 1456: while (1) { ! 1457: rpc_lock(thread); ! 1458: thr_act = thread->top_act; ! 1459: if (!thr_act) ! 1460: break; ! 1461: if (!act_lock_try(thr_act)) { ! 1462: rpc_unlock(thread); ! 1463: mutex_pause(); ! 1464: continue; ! 1465: } ! 1466: if (thr_act->pool_port && ! 1467: !ip_lock_try(thr_act->pool_port)) { ! 1468: rpc_unlock(thread); ! 1469: act_unlock(thr_act); ! 1470: mutex_pause(); ! 1471: continue; ! 1472: } ! 1473: break; ! 1474: } ! 1475: return (thr_act); ! 1476: } ! 1477: ! 1478: /* ! 1479: * Unsynchronize with RPC starting from a pointer to a shuttle. ! 1480: * Called with RPC-related locks held that are appropriate to ! 1481: * shuttle's state; any activation is also locked. ! 1482: */ ! 1483: void ! 1484: thread_unlock_act( ! 1485: thread_t thread) ! 1486: { ! 1487: thread_act_t thr_act; ! 1488: ! 1489: if (thr_act = thread->top_act) { ! 1490: if (thr_act->pool_port) ! 1491: ip_unlock(thr_act->pool_port); ! 1492: act_unlock(thr_act); ! 1493: } ! 1494: rpc_unlock(thread); ! 1495: } ! 1496: ! 1497: /* ! 1498: * switch_act ! 1499: * ! 1500: * If a new activation is given, switch to it. If not, ! 1501: * switch to the lower activation (pop). Returns the old ! 1502: * activation. This is for RPC support. ! 1503: */ ! 1504: thread_act_t ! 1505: switch_act( ! 1506: thread_act_t act) ! 1507: { ! 1508: thread_t thread; ! 1509: thread_act_t old, new; ! 1510: unsigned cpu; ! 1511: spl_t spl; ! 1512: ! 1513: ! 1514: disable_preemption(); ! 1515: ! 1516: cpu = cpu_number(); ! 1517: thread = current_thread(); ! 1518: ! 1519: /* ! 1520: * Find the old and new activation for switch. ! 1521: */ ! 1522: old = thread->top_act; ! 1523: ! 1524: if (act) { ! 1525: new = act; ! 1526: new->thread = thread; ! 1527: } ! 1528: else { ! 1529: new = old->lower; ! 1530: } ! 1531: ! 1532: assert(new != THR_ACT_NULL); ! 1533: #if THREAD_SWAPPER ! 1534: assert(new->swap_state != TH_SW_OUT && ! 1535: new->swap_state != TH_SW_COMING_IN); ! 1536: #endif /* THREAD_SWAPPER */ ! 1537: ! 1538: assert(cpu_data[cpu].active_thread == thread); ! 1539: active_kloaded[cpu] = (new->kernel_loaded) ? new : 0; ! 1540: ! 1541: /* This is where all the work happens */ ! 1542: machine_switch_act(thread, old, new, cpu); ! 1543: ! 1544: /* ! 1545: * Push or pop an activation on the chain. ! 1546: */ ! 1547: if (act) { ! 1548: act_attach(new, thread, 0); ! 1549: } ! 1550: else { ! 1551: act_detach(old); ! 1552: } ! 1553: ! 1554: enable_preemption(); ! 1555: ! 1556: return(old); ! 1557: } ! 1558: ! 1559: /* ! 1560: * install_special_handler ! 1561: * Install the special returnhandler that handles suspension and ! 1562: * termination, if it hasn't been installed already. ! 1563: * ! 1564: * Already locked: RPC-related locks for thr_act, but not ! 1565: * scheduling lock (thread_lock()) of the associated thread. ! 1566: */ ! 1567: void ! 1568: install_special_handler( ! 1569: thread_act_t thr_act) ! 1570: { ! 1571: spl_t spl; ! 1572: thread_t thread = thr_act->thread; ! 1573: ! 1574: #if MACH_ASSERT ! 1575: if (watchacts & WA_ACT_HDLR) ! 1576: printf("act_%x: install_special_hdlr(%x)\n",current_act(),thr_act); ! 1577: #endif /* MACH_ASSERT */ ! 1578: ! 1579: spl = splsched(); ! 1580: if (thread) ! 1581: thread_lock(thread); ! 1582: install_special_handler_locked(thr_act); ! 1583: act_set_apc(thr_act); ! 1584: if (thread) ! 1585: thread_unlock(thread); ! 1586: splx(spl); ! 1587: } ! 1588: ! 1589: /* ! 1590: * install_special_handler_locked ! 1591: * Do the work of installing the special_handler. ! 1592: * ! 1593: * Already locked: RPC-related locks for thr_act, plus the ! 1594: * scheduling lock (thread_lock()) of the associated thread. ! 1595: */ ! 1596: void ! 1597: install_special_handler_locked( ! 1598: thread_act_t thr_act) ! 1599: { ! 1600: ReturnHandler **rh; ! 1601: thread_t thread = thr_act->thread; ! 1602: ! 1603: /* The work handler must always be the last ReturnHandler on the list, ! 1604: because it can do tricky things like detach the thr_act. */ ! 1605: for (rh = &thr_act->handlers; *rh; rh = &(*rh)->next) ! 1606: /* */ ; ! 1607: if (rh != &thr_act->special_handler.next) { ! 1608: *rh = &thr_act->special_handler; ! 1609: } ! 1610: if (thread && thr_act == thread->top_act) { ! 1611: /* ! 1612: * Temporarily undepress, so target has ! 1613: * a chance to do locking required to ! 1614: * block itself in special_handler(). ! 1615: */ ! 1616: /*** ??? fix me ***/ ! 1617: assert(thread->sp_info != SP_INFO_NULL); ! 1618: if (((thread->policy == POLICY_TIMESHARE) || ! 1619: (thread->policy == POLICY_RR) || ! 1620: (thread->policy == POLICY_FIFO)) && ! 1621: ((mk_sp_info_t)thread->sp_info)->depress_priority >= 0) { ! 1622: ((mk_sp_info_t)thread->sp_info)->priority = ((mk_sp_info_t)thread->sp_info)->depress_priority; ! 1623: /* Use special value -2 to indicate need ! 1624: * to redepress priority in special_handler ! 1625: * as thread blocks ! 1626: */ ! 1627: ((mk_sp_info_t)thread->sp_info)->depress_priority = -2; ! 1628: compute_priority(thread, FALSE); ! 1629: } ! 1630: } ! 1631: act_set_apc(thr_act); ! 1632: } ! 1633: ! 1634: /* ! 1635: * JMM - ! 1636: * These two routines will be enhanced over time to call the general handler registration ! 1637: * mechanism used by special handlers and alerts. They are hack in for now to avoid ! 1638: * having to export the gory details of ASTs to the BSD code right now. ! 1639: */ ! 1640: extern thread_apc_handler_t bsd_ast; ! 1641: ! 1642: kern_return_t ! 1643: thread_apc_set( ! 1644: thread_act_t thr_act, ! 1645: thread_apc_handler_t apc) ! 1646: { ! 1647: assert(apc == bsd_ast); ! 1648: thread_ast_set(thr_act, AST_BSD); ! 1649: if (thr_act == current_act()) ! 1650: ast_propagate(thr_act->ast); ! 1651: return KERN_SUCCESS; ! 1652: } ! 1653: ! 1654: kern_return_t ! 1655: thread_apc_clear( ! 1656: thread_act_t thr_act, ! 1657: thread_apc_handler_t apc) ! 1658: { ! 1659: assert(apc == bsd_ast); ! 1660: thread_ast_clear(thr_act, AST_BSD); ! 1661: if (thr_act == current_act()) ! 1662: ast_off(AST_BSD); ! 1663: return KERN_SUCCESS; ! 1664: } ! 1665: ! 1666: /* ! 1667: * act_set_thread_pool - Assign an activation to a specific thread_pool. ! 1668: * Fails if the activation is already assigned to another pool. ! 1669: * If thread_pool == 0, we remove the thr_act from its thread_pool. ! 1670: * ! 1671: * Called the port containing thread_pool already locked. ! 1672: * Returns the same way. ! 1673: */ ! 1674: kern_return_t act_set_thread_pool( ! 1675: thread_act_t thr_act, ! 1676: ipc_port_t pool_port) ! 1677: { ! 1678: thread_pool_t thread_pool; ! 1679: ! 1680: #if MACH_ASSERT ! 1681: if (watchacts & WA_ACT_LNK) ! 1682: printf("act_set_thread_pool: %x(%d) -> %x\n", ! 1683: thr_act, thr_act->ref_count, thread_pool); ! 1684: #endif /* MACH_ASSERT */ ! 1685: ! 1686: if (pool_port == 0) { ! 1687: thread_act_t *lact; ! 1688: ! 1689: if (thr_act->pool_port == 0) ! 1690: return KERN_SUCCESS; ! 1691: thread_pool = &thr_act->pool_port->ip_thread_pool; ! 1692: ! 1693: for (lact = &thread_pool->thr_acts; *lact; ! 1694: lact = &((*lact)->thread_pool_next)) { ! 1695: if (thr_act == *lact) { ! 1696: *lact = thr_act->thread_pool_next; ! 1697: break; ! 1698: } ! 1699: } ! 1700: act_lock(thr_act); ! 1701: thr_act->pool_port = 0; ! 1702: thr_act->thread_pool_next = 0; ! 1703: act_unlock(thr_act); ! 1704: act_deallocate(thr_act); ! 1705: return KERN_SUCCESS; ! 1706: } ! 1707: if (thr_act->pool_port != pool_port) { ! 1708: thread_pool = &pool_port->ip_thread_pool; ! 1709: if (thr_act->pool_port != 0) { ! 1710: #if MACH_ASSERT ! 1711: if (watchacts & WA_ACT_LNK) ! 1712: printf("act_set_thread_pool found %x!\n", ! 1713: thr_act->pool_port); ! 1714: #endif /* MACH_ASSERT */ ! 1715: return(KERN_FAILURE); ! 1716: } ! 1717: act_lock(thr_act); ! 1718: thr_act->pool_port = pool_port; ! 1719: ! 1720: /* The pool gets a ref to the activation -- have ! 1721: * to inline operation because thr_act is already ! 1722: * locked. ! 1723: */ ! 1724: act_locked_act_reference(thr_act); ! 1725: ! 1726: /* If it is available, ! 1727: * add it to the thread_pool's available-activation list. ! 1728: */ ! 1729: if ((thr_act->thread == 0) && (thr_act->suspend_count == 0)) { ! 1730: thr_act->thread_pool_next = thread_pool->thr_acts; ! 1731: pool_port->ip_thread_pool.thr_acts = thr_act; ! 1732: if (thread_pool->waiting) ! 1733: thread_pool_wakeup(thread_pool); ! 1734: } ! 1735: act_unlock(thr_act); ! 1736: } ! 1737: ! 1738: return KERN_SUCCESS; ! 1739: } ! 1740: ! 1741: /* ! 1742: * act_locked_act_set_thread_pool- Assign activation to a specific thread_pool. ! 1743: * Fails if the activation is already assigned to another pool. ! 1744: * If thread_pool == 0, we remove the thr_act from its thread_pool. ! 1745: * ! 1746: * Called the port containing thread_pool already locked. ! 1747: * Also called with the thread activation locked. ! 1748: * Returns the same way. ! 1749: * ! 1750: * This routine is the same as `act_set_thread_pool()' except that it does ! 1751: * not call `act_deallocate(),' which unconditionally tries to obtain the ! 1752: * thread activation lock. ! 1753: */ ! 1754: kern_return_t act_locked_act_set_thread_pool( ! 1755: thread_act_t thr_act, ! 1756: ipc_port_t pool_port) ! 1757: { ! 1758: thread_pool_t thread_pool; ! 1759: ! 1760: #if MACH_ASSERT ! 1761: if (watchacts & WA_ACT_LNK) ! 1762: printf("act_set_thread_pool: %x(%d) -> %x\n", ! 1763: thr_act, thr_act->ref_count, thread_pool); ! 1764: #endif /* MACH_ASSERT */ ! 1765: ! 1766: if (pool_port == 0) { ! 1767: thread_act_t *lact; ! 1768: ! 1769: if (thr_act->pool_port == 0) ! 1770: return KERN_SUCCESS; ! 1771: thread_pool = &thr_act->pool_port->ip_thread_pool; ! 1772: ! 1773: for (lact = &thread_pool->thr_acts; *lact; ! 1774: lact = &((*lact)->thread_pool_next)) { ! 1775: if (thr_act == *lact) { ! 1776: *lact = thr_act->thread_pool_next; ! 1777: break; ! 1778: } ! 1779: } ! 1780: ! 1781: thr_act->pool_port = 0; ! 1782: thr_act->thread_pool_next = 0; ! 1783: act_locked_act_deallocate(thr_act); ! 1784: return KERN_SUCCESS; ! 1785: } ! 1786: if (thr_act->pool_port != pool_port) { ! 1787: thread_pool = &pool_port->ip_thread_pool; ! 1788: if (thr_act->pool_port != 0) { ! 1789: #if MACH_ASSERT ! 1790: if (watchacts & WA_ACT_LNK) ! 1791: printf("act_set_thread_pool found %x!\n", ! 1792: thr_act->pool_port); ! 1793: #endif /* MACH_ASSERT */ ! 1794: return(KERN_FAILURE); ! 1795: } ! 1796: thr_act->pool_port = pool_port; ! 1797: ! 1798: /* The pool gets a ref to the activation -- have ! 1799: * to inline operation because thr_act is already ! 1800: * locked. ! 1801: */ ! 1802: act_locked_act_reference(thr_act); ! 1803: ! 1804: /* If it is available, ! 1805: * add it to the thread_pool's available-activation list. ! 1806: */ ! 1807: if ((thr_act->thread == 0) && (thr_act->suspend_count == 0)) { ! 1808: thr_act->thread_pool_next = thread_pool->thr_acts; ! 1809: pool_port->ip_thread_pool.thr_acts = thr_act; ! 1810: if (thread_pool->waiting) ! 1811: thread_pool_wakeup(thread_pool); ! 1812: } ! 1813: } ! 1814: ! 1815: return KERN_SUCCESS; ! 1816: } ! 1817: ! 1818: /* ! 1819: * Activation control support routines internal to this file: ! 1820: */ ! 1821: ! 1822: /* ! 1823: * act_execute_returnhandlers() - does just what the name says ! 1824: * ! 1825: * This is called by system-dependent code when it detects that ! 1826: * thr_act->handlers is non-null while returning into user mode. ! 1827: * Activations linked onto an thread_pool always have null thr_act->handlers, ! 1828: * so RPC entry paths need not check it. ! 1829: */ ! 1830: void act_execute_returnhandlers( ! 1831: void) ! 1832: { ! 1833: spl_t s; ! 1834: thread_t thread; ! 1835: thread_act_t thr_act = current_act(); ! 1836: ! 1837: #if MACH_ASSERT ! 1838: if (watchacts & WA_ACT_HDLR) ! 1839: printf("execute_rtn_hdlrs: thr_act=%x\n", thr_act); ! 1840: #endif /* MACH_ASSERT */ ! 1841: ! 1842: s = splsched(); ! 1843: act_clr_apc(thr_act); ! 1844: spllo(); ! 1845: while (1) { ! 1846: ReturnHandler *rh; ! 1847: ! 1848: /* Grab the next returnhandler */ ! 1849: thread = act_lock_thread(thr_act); ! 1850: (void)splsched(); ! 1851: thread_lock(thread); ! 1852: rh = thr_act->handlers; ! 1853: if (!rh) { ! 1854: thread_unlock(thread); ! 1855: splx(s); ! 1856: act_unlock_thread(thr_act); ! 1857: return; ! 1858: } ! 1859: thr_act->handlers = rh->next; ! 1860: thread_unlock(thread); ! 1861: spllo(); ! 1862: act_unlock_thread(thr_act); ! 1863: ! 1864: #if MACH_ASSERT ! 1865: if (watchacts & WA_ACT_HDLR) ! 1866: printf( (rh == &thr_act->special_handler) ? ! 1867: "\tspecial_handler\n" : "\thandler=%x\n", ! 1868: rh->handler); ! 1869: #endif /* MACH_ASSERT */ ! 1870: ! 1871: /* Execute it */ ! 1872: (*rh->handler)(rh, thr_act); ! 1873: } ! 1874: } ! 1875: ! 1876: /* ! 1877: * special_handler - handles suspension, termination. Called ! 1878: * with nothing locked. Returns (if it returns) the same way. ! 1879: */ ! 1880: void ! 1881: special_handler( ! 1882: ReturnHandler *rh, ! 1883: thread_act_t cur_act) ! 1884: { ! 1885: spl_t s; ! 1886: thread_t lthread; ! 1887: thread_t thread = act_lock_thread(cur_act); ! 1888: unsigned alert_bits; ! 1889: exception_data_type_t ! 1890: codes[EXCEPTION_CODE_MAX]; ! 1891: kern_return_t kr; ! 1892: kern_return_t exc_kr; ! 1893: ! 1894: assert(thread != THREAD_NULL); ! 1895: #if MACH_ASSERT ! 1896: if (watchacts & WA_ACT_HDLR) ! 1897: printf("\t\tspecial_handler(thr_act=%x(%d))\n", cur_act, ! 1898: (cur_act ? cur_act->ref_count : 0)); ! 1899: #endif /* MACH_ASSERT */ ! 1900: ! 1901: s = splsched(); ! 1902: ! 1903: thread_lock(thread); ! 1904: thread->state &= ~TH_ABORT; /* clear any aborts */ ! 1905: thread_unlock(thread); ! 1906: ! 1907: /* ! 1908: * If someone has killed this invocation, ! 1909: * invoke the return path with a terminated exception. ! 1910: */ ! 1911: if (!cur_act->active) { ! 1912: splx(s); ! 1913: act_unlock_thread(cur_act); ! 1914: act_machine_return(KERN_TERMINATED); ! 1915: } ! 1916: ! 1917: splx(s); ! 1918: ! 1919: /* strip server terminated bit */ ! 1920: alert_bits = cur_act->alerts & (~SERVER_TERMINATED); ! 1921: ! 1922: /* clear server terminated bit */ ! 1923: cur_act->alerts &= ~SERVER_TERMINATED; ! 1924: ! 1925: if ( alert_bits ) { ! 1926: /* ! 1927: * currently necessary to coordinate with the exception ! 1928: * code -fdr ! 1929: */ ! 1930: act_unlock_thread(cur_act); ! 1931: ! 1932: /* upcall exception/alert port */ ! 1933: codes[0] = alert_bits; ! 1934: ! 1935: /* ! 1936: * Exception makes a lot of assumptions. If there is no ! 1937: * exception handler or the exception reply is broken, the ! 1938: * thread will be terminated and exception will not return. If ! 1939: * we decide we don't like that behavior, we need to check ! 1940: * for the existence of an exception port before we call ! 1941: * exception. ! 1942: */ ! 1943: exc_kr = alert_exception( EXC_RPC_ALERT, codes, 1 ); ! 1944: ! 1945: /* clear the orphaned and time constraint indications */ ! 1946: cur_act->alerts &= ~(ORPHANED | TIME_CONSTRAINT_UNSATISFIED); ! 1947: ! 1948: /* if this orphaned activation should be terminated... */ ! 1949: if (exc_kr == KERN_RPC_TERMINATE_ORPHAN) { ! 1950: /* ! 1951: * ... terminate the activation ! 1952: * ! 1953: * This is done in two steps. First, the activation is ! 1954: * disabled (prepared for termination); second, the ! 1955: * `special_handler()' is executed again -- this time ! 1956: * to terminate the activation. ! 1957: * (`act_disable_task_locked()' arranges for the ! 1958: * additional execution of the `special_handler().') ! 1959: */ ! 1960: ! 1961: #if THREAD_SWAPPER ! 1962: thread_swap_disable(cur_act); ! 1963: #endif /* THREAD_SWAPPER */ ! 1964: ! 1965: /* acquire appropriate locks */ ! 1966: task_lock(cur_act->task); ! 1967: act_lock_thread(cur_act); ! 1968: ! 1969: /* detach the activation from its task */ ! 1970: kr = act_disable_task_locked(cur_act); ! 1971: assert( kr == KERN_SUCCESS ); ! 1972: ! 1973: /* release locks */ ! 1974: task_unlock(cur_act->task); ! 1975: } ! 1976: else { ! 1977: /* acquire activation lock again (released below) */ ! 1978: act_lock_thread(cur_act); ! 1979: s = splsched(); ! 1980: thread_lock(thread); ! 1981: /*** ??? fix me ***/ ! 1982: assert(thread->sp_info != SP_INFO_NULL); ! 1983: if (((thread->policy == POLICY_TIMESHARE) || ! 1984: (thread->policy == POLICY_RR) || ! 1985: (thread->policy == POLICY_FIFO)) && ! 1986: ((mk_sp_info_t)thread->sp_info)->depress_priority == -2) { ! 1987: /* We were temporarily undepressed by ! 1988: * install_special_handler; restore priority ! 1989: * depression. ! 1990: */ ! 1991: ((mk_sp_info_t)thread->sp_info)->depress_priority = ((mk_sp_info_t)thread->sp_info)->priority; ! 1992: ((mk_sp_info_t)thread->sp_info)->priority = DEPRESSPRI; ! 1993: thread->sched_pri = DEPRESSPRI; ! 1994: } ! 1995: thread_unlock(thread); ! 1996: splx(s); ! 1997: } ! 1998: } ! 1999: ! 2000: /* ! 2001: * If we're suspended, go to sleep and wait for someone to wake us up. ! 2002: */ ! 2003: if (cur_act->suspend_count) { ! 2004: if( cur_act->handlers == NULL ) { ! 2005: assert_wait((event_t)&cur_act->suspend_count, ! 2006: THREAD_ABORTSAFE); ! 2007: act_unlock_thread(cur_act); ! 2008: thread_block((void (*)(void))0); ! 2009: act_lock_thread(cur_act); ! 2010: } ! 2011: ! 2012: /* ! 2013: * If we're still (or again) suspended, go to sleep again ! 2014: * after executing any new handlers that may have appeared. ! 2015: */ ! 2016: if (cur_act->suspend_count) ! 2017: install_special_handler(cur_act); ! 2018: else { ! 2019: s = splsched(); ! 2020: thread_lock(thread); ! 2021: /*** ??? fix me ***/ ! 2022: assert(thread->sp_info != SP_INFO_NULL); ! 2023: if (((thread->policy == POLICY_TIMESHARE) || ! 2024: (thread->policy == POLICY_RR) || ! 2025: (thread->policy == POLICY_FIFO)) && ! 2026: ((mk_sp_info_t)thread->sp_info)->depress_priority == -2) { ! 2027: /* We were temporarily undepressed by ! 2028: * install_special_handler; restore priority ! 2029: * depression. ! 2030: */ ! 2031: ((mk_sp_info_t)thread->sp_info)->depress_priority = ((mk_sp_info_t)thread->sp_info)->priority; ! 2032: ((mk_sp_info_t)thread->sp_info)->priority = DEPRESSPRI; ! 2033: thread->sched_pri = DEPRESSPRI; ! 2034: } ! 2035: thread_unlock(thread); ! 2036: splx(s); ! 2037: } ! 2038: } ! 2039: ! 2040: act_unlock_thread(cur_act); ! 2041: } ! 2042: ! 2043: /* ! 2044: * Try to nudge a thr_act into executing its returnhandler chain. ! 2045: * Ensures that the activation will execute its returnhandlers ! 2046: * before it next executes any of its user-level code. ! 2047: * ! 2048: * Called with thr_act's act_lock() and "appropriate" thread-related ! 2049: * locks held. (See act_lock_thread().) Returns same way. ! 2050: */ ! 2051: void ! 2052: nudge(thread_act_t thr_act) ! 2053: { ! 2054: #if MACH_ASSERT ! 2055: if (watchacts & WA_ACT_HDLR) ! 2056: printf("\tact_%x: nudge(%x)\n", current_act(), thr_act); ! 2057: #endif /* MACH_ASSERT */ ! 2058: ! 2059: /* ! 2060: * Don't need to do anything at all if this thr_act isn't the topmost. ! 2061: */ ! 2062: if (thr_act->thread && thr_act->thread->top_act == thr_act) { ! 2063: /* ! 2064: * If it's suspended, wake it up. ! 2065: * This should nudge it even on another CPU. ! 2066: */ ! 2067: thread_wakeup((event_t)&thr_act->suspend_count); ! 2068: } ! 2069: } ! 2070: ! 2071: /* ! 2072: * Update activation that belongs to a task created via kernel_task_create(). ! 2073: */ ! 2074: void ! 2075: act_user_to_kernel( ! 2076: thread_act_t thr_act) ! 2077: { ! 2078: pcb_user_to_kernel(thr_act); ! 2079: thr_act->kernel_loading = TRUE; ! 2080: } ! 2081: ! 2082: /* ! 2083: * Already locked: thr_act->task, RPC-related locks for thr_act ! 2084: * ! 2085: * Detach an activation from its task, and prepare it to terminate ! 2086: * itself. ! 2087: */ ! 2088: kern_return_t ! 2089: act_disable_task_locked( ! 2090: thread_act_t thr_act) ! 2091: { ! 2092: thread_t thread = thr_act->thread; ! 2093: task_t task = thr_act->task; ! 2094: ! 2095: #if MACH_ASSERT ! 2096: if (watchacts & WA_EXIT) { ! 2097: printf("act_%x: act_disable_tl(thr_act=%x(%d))%sactive task=%x(%d)", ! 2098: current_act(), thr_act, thr_act->ref_count, ! 2099: (thr_act->active ? " " : " !"), ! 2100: thr_act->task, thr_act->task? thr_act->task->ref_count : 0); ! 2101: if (thr_act->pool_port) ! 2102: printf(", pool_port %x", thr_act->pool_port); ! 2103: printf("\n"); ! 2104: (void) dump_act(thr_act); ! 2105: } ! 2106: #endif /* MACH_ASSERT */ ! 2107: if (thr_act->thr_acts.next) { ! 2108: /* Unlink the thr_act from the task's thr_act list, ! 2109: * so it doesn't appear in calls to task_threads and such. ! 2110: * The thr_act still keeps its ref on the task, however. ! 2111: */ ! 2112: #ifdef NOTEVER ! 2113: mutex_lock(&task->act_list_lock); ! 2114: #if 1 ! 2115: queue_remove(&task->thr_acts, thr_act, thread_act_t, thr_acts); ! 2116: #else ! 2117: thr_act->thr_acts.next->prev = thr_act->thr_acts.prev; ! 2118: thr_act->thr_acts.prev->next = thr_act->thr_acts.next; ! 2119: #endif /* 1 */ ! 2120: thr_act->thr_acts.next = 0; ! 2121: task->thr_act_count--; ! 2122: #if THREAD_SWAPPER ! 2123: /* ! 2124: * Thread is supposed to be unswappable by now... ! 2125: */ ! 2126: assert(thr_act->swap_state == TH_SW_UNSWAPPABLE || ! 2127: !(thread_swap_unwire_stack || ! 2128: thread_swap_unwire_user_stack)); ! 2129: #endif /* THREAD_SWAPPER */ ! 2130: task->res_act_count--; ! 2131: mutex_unlock(&task->act_list_lock); ! 2132: #endif /* NOTEVER */ ! 2133: ! 2134: /* This will allow no more control ops on this thr_act. */ ! 2135: thr_act->active = 0; ! 2136: ! 2137: /* Clean-up any ulocks that are still owned by the thread ! 2138: * activation (acquired but not released or handed-off). ! 2139: */ ! 2140: act_ulock_release_all(thr_act); ! 2141: ! 2142: /* If not an empty activation, install special handler */ ! 2143: if (thr_act->thread != THREAD_NULL) { ! 2144: ! 2145: /* When the special_handler gets executed, ! 2146: * it will see the terminated condition and exit ! 2147: * immediately. ! 2148: */ ! 2149: install_special_handler(thr_act); ! 2150: } ! 2151: ! 2152: /* If the target happens to be suspended, ! 2153: * give it a nudge so it can exit. ! 2154: */ ! 2155: if (thr_act->suspend_count) ! 2156: nudge(thr_act); ! 2157: /* Drop the thr_act reference taken for being active. ! 2158: * (There is still at least one reference left: ! 2159: * the one we were passed.) ! 2160: * Inline the deallocate because thr_act is locked. ! 2161: */ ! 2162: act_locked_act_deallocate(thr_act); ! 2163: } ! 2164: ! 2165: return(KERN_SUCCESS); ! 2166: } ! 2167: ! 2168: /* ! 2169: * act_alert - Register an alert from this activation. ! 2170: * ! 2171: * Each set bit is propagated upward from (but not including) this activation, ! 2172: * until the top of the chain is reached or the bit is masked. ! 2173: */ ! 2174: kern_return_t ! 2175: act_alert(thread_act_t thr_act, unsigned alerts) ! 2176: { ! 2177: thread_t thread = act_lock_thread(thr_act); ! 2178: ! 2179: #if MACH_ASSERT ! 2180: if (watchacts & WA_ACT_LNK) ! 2181: printf("act_alert %x: %x\n", thr_act, alerts); ! 2182: #endif /* MACH_ASSERT */ ! 2183: ! 2184: if (thread) { ! 2185: thread_act_t act_up = thr_act; ! 2186: while ((alerts) && (act_up != thread->top_act)) { ! 2187: act_up = act_up->higher; ! 2188: alerts &= act_up->alert_mask; ! 2189: act_up->alerts |= alerts; ! 2190: } ! 2191: /* ! 2192: * XXXX If we reach the top, and it is blocked in glue ! 2193: * code, do something to kick it. XXXX ! 2194: */ ! 2195: } ! 2196: act_unlock_thread(thr_act); ! 2197: ! 2198: return KERN_SUCCESS; ! 2199: } ! 2200: ! 2201: kern_return_t act_alert_mask(thread_act_t thr_act, unsigned alert_mask) ! 2202: { ! 2203: panic("act_alert_mask NOT YET IMPLEMENTED\n"); ! 2204: return KERN_SUCCESS; ! 2205: } ! 2206: ! 2207: typedef struct GetSetState { ! 2208: struct ReturnHandler rh; ! 2209: int flavor; ! 2210: void *state; ! 2211: int *pcount; ! 2212: int result; ! 2213: } GetSetState; ! 2214: ! 2215: /* Local Forward decls */ ! 2216: kern_return_t get_set_state( ! 2217: thread_act_t thr_act, int flavor, ! 2218: thread_state_t state, int *pcount, ! 2219: void (*handler)(ReturnHandler *rh, thread_act_t thr_act)); ! 2220: void get_state_handler(ReturnHandler *rh, thread_act_t thr_act); ! 2221: void set_state_handler(ReturnHandler *rh, thread_act_t thr_act); ! 2222: ! 2223: /* ! 2224: * get_set_state(thr_act ...) ! 2225: * ! 2226: * General code to install g/set_state handler. ! 2227: * Called with thr_act's act_lock() and "appropriate" ! 2228: * thread-related locks held. (See act_lock_thread().) ! 2229: */ ! 2230: kern_return_t ! 2231: get_set_state(thread_act_t thr_act, int flavor, thread_state_t state, int *pcount, ! 2232: void (*handler)(ReturnHandler *rh, thread_act_t thr_act)) ! 2233: { ! 2234: GetSetState gss; ! 2235: spl_t s; ! 2236: ! 2237: /* Initialize a small parameter structure */ ! 2238: gss.rh.handler = handler; ! 2239: gss.flavor = flavor; ! 2240: gss.state = state; ! 2241: gss.pcount = pcount; ! 2242: gss.result = KERN_ABORTED; /* iff wait below is interrupted */ ! 2243: ! 2244: /* Add it to the thr_act's return handler list */ ! 2245: gss.rh.next = thr_act->handlers; ! 2246: thr_act->handlers = &gss.rh; ! 2247: ! 2248: s = splsched(); ! 2249: act_set_apc(thr_act); ! 2250: splx(s); ! 2251: ! 2252: #if MACH_ASSERT ! 2253: if (watchacts & WA_ACT_HDLR) { ! 2254: printf("act_%x: get_set_state(thr_act=%x flv=%x state=%x ptr@%x=%x)", ! 2255: current_act(), thr_act, flavor, state, ! 2256: pcount, (pcount ? *pcount : 0)); ! 2257: printf((handler == get_state_handler ? "get_state_hdlr\n" : ! 2258: (handler == set_state_handler ? "set_state_hdlr\n" : ! 2259: "hndler=%x\n")), handler); ! 2260: } ! 2261: #endif /* MACH_ASSERT */ ! 2262: ! 2263: assert(thr_act->thread); /* Callers must ensure these */ ! 2264: assert(thr_act != current_act()); ! 2265: for (;;) { ! 2266: nudge(thr_act); ! 2267: /* ! 2268: * Wait must be interruptible to avoid deadlock (e.g.) with ! 2269: * task_suspend() when caller and target of get_set_state() ! 2270: * are in same task. ! 2271: */ ! 2272: assert_wait((event_t)&gss, THREAD_ABORTSAFE); ! 2273: act_unlock_thread(thr_act); ! 2274: thread_block((void (*)(void))0); ! 2275: if (gss.result != KERN_ABORTED) ! 2276: break; ! 2277: if (current_act()->handlers) ! 2278: act_execute_returnhandlers(); ! 2279: act_lock_thread(thr_act); ! 2280: } ! 2281: ! 2282: #if MACH_ASSERT ! 2283: if (watchacts & WA_ACT_HDLR) ! 2284: printf("act_%x: get_set_state returns %x\n", ! 2285: current_act(), gss.result); ! 2286: #endif /* MACH_ASSERT */ ! 2287: ! 2288: return gss.result; ! 2289: } ! 2290: ! 2291: void ! 2292: set_state_handler(ReturnHandler *rh, thread_act_t thr_act) ! 2293: { ! 2294: GetSetState *gss = (GetSetState*)rh; ! 2295: ! 2296: #if MACH_ASSERT ! 2297: if (watchacts & WA_ACT_HDLR) ! 2298: printf("act_%x: set_state_handler(rh=%x,thr_act=%x)\n", ! 2299: current_act(), rh, thr_act); ! 2300: #endif /* MACH_ASSERT */ ! 2301: ! 2302: gss->result = act_machine_set_state(thr_act, gss->flavor, ! 2303: gss->state, *gss->pcount); ! 2304: thread_wakeup((event_t)gss); ! 2305: } ! 2306: ! 2307: void ! 2308: get_state_handler(ReturnHandler *rh, thread_act_t thr_act) ! 2309: { ! 2310: GetSetState *gss = (GetSetState*)rh; ! 2311: ! 2312: #if MACH_ASSERT ! 2313: if (watchacts & WA_ACT_HDLR) ! 2314: printf("act_%x: get_state_handler(rh=%x,thr_act=%x)\n", ! 2315: current_act(), rh, thr_act); ! 2316: #endif /* MACH_ASSERT */ ! 2317: ! 2318: gss->result = act_machine_get_state(thr_act, gss->flavor, ! 2319: gss->state, ! 2320: (mach_msg_type_number_t *) gss->pcount); ! 2321: thread_wakeup((event_t)gss); ! 2322: } ! 2323: ! 2324: kern_return_t ! 2325: act_get_state_locked(thread_act_t thr_act, int flavor, thread_state_t state, ! 2326: mach_msg_type_number_t *pcount) ! 2327: { ! 2328: #if MACH_ASSERT ! 2329: if (watchacts & WA_ACT_HDLR) ! 2330: printf("act_%x: act_get_state_L(thr_act=%x,flav=%x,st=%x,pcnt@%x=%x)\n", ! 2331: current_act(), thr_act, flavor, state, pcount, ! 2332: (pcount? *pcount : 0)); ! 2333: #endif /* MACH_ASSERT */ ! 2334: ! 2335: return(get_set_state(thr_act, flavor, state, (int*)pcount, get_state_handler)); ! 2336: } ! 2337: ! 2338: kern_return_t ! 2339: act_set_state_locked(thread_act_t thr_act, int flavor, thread_state_t state, ! 2340: mach_msg_type_number_t count) ! 2341: { ! 2342: #if MACH_ASSERT ! 2343: if (watchacts & WA_ACT_HDLR) ! 2344: printf("act_%x: act_set_state_L(thr_act=%x,flav=%x,st=%x,pcnt@%x=%x)\n", ! 2345: current_act(), thr_act, flavor, state, count, count); ! 2346: #endif /* MACH_ASSERT */ ! 2347: ! 2348: return(get_set_state(thr_act, flavor, state, (int*)&count, set_state_handler)); ! 2349: } ! 2350: ! 2351: kern_return_t ! 2352: act_set_state(thread_act_t thr_act, int flavor, thread_state_t state, ! 2353: mach_msg_type_number_t count) ! 2354: { ! 2355: if (thr_act == THR_ACT_NULL || thr_act == current_act()) ! 2356: return(KERN_INVALID_ARGUMENT); ! 2357: ! 2358: if (act_lock_thread(thr_act) == THREAD_NULL) { ! 2359: act_unlock(thr_act); ! 2360: return(KERN_INVALID_ARGUMENT); ! 2361: } ! 2362: return(act_set_state_locked(thr_act, flavor, state, count)); ! 2363: ! 2364: } ! 2365: ! 2366: kern_return_t ! 2367: act_get_state(thread_act_t thr_act, int flavor, thread_state_t state, ! 2368: mach_msg_type_number_t *pcount) ! 2369: { ! 2370: if (thr_act == THR_ACT_NULL || thr_act == current_act()) ! 2371: return(KERN_INVALID_ARGUMENT); ! 2372: ! 2373: if (act_lock_thread(thr_act) == THREAD_NULL) { ! 2374: act_unlock(thr_act); ! 2375: return(KERN_INVALID_ARGUMENT); ! 2376: } ! 2377: return(act_get_state_locked(thr_act, flavor, state, pcount)); ! 2378: } ! 2379: ! 2380: /* ! 2381: * These two should be called at splsched() ! 2382: * Set/clear indicator to run APC (layered on ASTs) ! 2383: */ ! 2384: void ! 2385: act_set_apc(thread_act_t thr_act) ! 2386: { ! 2387: thread_ast_set(thr_act, AST_APC); ! 2388: if (thr_act == current_act()) { ! 2389: mp_disable_preemption(); ! 2390: ast_propagate(thr_act->ast); ! 2391: mp_enable_preemption(); ! 2392: } ! 2393: } ! 2394: ! 2395: void ! 2396: act_clr_apc(thread_act_t thr_act) ! 2397: { ! 2398: thread_ast_clear(thr_act, AST_APC); ! 2399: } ! 2400: ! 2401: void ! 2402: act_ulock_release_all(thread_act_t thr_act) ! 2403: { ! 2404: ulock_t ulock; ! 2405: ! 2406: while (!queue_empty(&thr_act->held_ulocks)) { ! 2407: ulock = (ulock_t) queue_first(&thr_act->held_ulocks); ! 2408: (void) lock_make_unstable(ulock, thr_act); ! 2409: (void) lock_release_internal(ulock, thr_act); ! 2410: } ! 2411: } ! 2412: ! 2413: /* ! 2414: * Provide routines (for export to other components) of things that ! 2415: * are implemented as macros insternally. ! 2416: */ ! 2417: #undef current_act ! 2418: thread_act_t ! 2419: current_act(void) ! 2420: { ! 2421: return(current_act_fast()); ! 2422: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.