|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1993,1994 The University of Utah and ! 3: * the Computer Systems Laboratory (CSL). All rights reserved. ! 4: * ! 5: * Permission to use, copy, modify and distribute this software and its ! 6: * documentation is hereby granted, provided that both the copyright ! 7: * notice and this permission notice appear in all copies of the ! 8: * software, derivative works or modified versions, and any portions ! 9: * thereof, and that both notices appear in supporting documentation. ! 10: * ! 11: * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS ! 12: * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF ! 13: * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ! 14: * ! 15: * CSL requests users of this software to return to [email protected] any ! 16: * improvements that they make and grant CSL redistribution rights. ! 17: * ! 18: * Author: Bryan Ford, University of Utah CSL ! 19: */ ! 20: /* ! 21: * File: act.c ! 22: * ! 23: * Activation management routines ! 24: * ! 25: */ ! 26: ! 27: #ifdef MIGRATING_THREADS ! 28: ! 29: #include <mach_ipc_compat.h> /* XXX */ ! 30: #include <mach/kern_return.h> ! 31: #include <mach/alert.h> ! 32: #include <kern/mach_param.h> /* XXX INCALL_... */ ! 33: #include <kern/zalloc.h> ! 34: #include <kern/thread.h> ! 35: #include <kern/task.h> ! 36: #include <kern/act.h> ! 37: #include <kern/current.h> ! 38: #include "ipc_target.h" ! 39: ! 40: static void special_handler(ReturnHandler *rh, struct Act *act); ! 41: ! 42: #ifdef ACT_STATIC_KLUDGE ! 43: #undef ACT_STATIC_KLUDGE ! 44: #define ACT_STATIC_KLUDGE 300 ! 45: #endif ! 46: ! 47: #ifndef ACT_STATIC_KLUDGE ! 48: static zone_t act_zone; ! 49: #else ! 50: static Act *act_freelist; ! 51: static Act free_acts[ACT_STATIC_KLUDGE]; ! 52: #endif ! 53: ! 54: /* This is a rather special activation ! 55: which resides at the top and bottom of every thread. ! 56: When the last "real" activation on a thread is destroyed, ! 57: the null_act on the bottom gets invoked, destroying the thread. ! 58: At the top, the null_act acts as an "invalid" cached activation, ! 59: which will always fail the cached-activation test on RPC paths. ! 60: ! 61: As you might expect, most of its members have no particular value. ! 62: alerts is zero. */ ! 63: Act null_act; ! 64: ! 65: void ! 66: global_act_init() ! 67: { ! 68: #ifndef ACT_STATIC_KLUDGE ! 69: act_zone = zinit( ! 70: sizeof(struct Act), ! 71: ACT_MAX * sizeof(struct Act), /* XXX */ ! 72: ACT_CHUNK * sizeof(struct Act), ! 73: 0, "activations"); ! 74: #else ! 75: int i; ! 76: ! 77: printf("activations: [%x-%x]\n", &free_acts[0], &free_acts[ACT_STATIC_KLUDGE]); ! 78: act_freelist = &free_acts[0]; ! 79: free_acts[0].ipt_next = 0; ! 80: for (i = 1; i < ACT_STATIC_KLUDGE; i++) { ! 81: free_acts[i].ipt_next = act_freelist; ! 82: act_freelist = &free_acts[i]; ! 83: } ! 84: /* XXX simple_lock_init(&act_freelist->lock); */ ! 85: #endif ! 86: ! 87: #if 0 ! 88: simple_lock_init(&null_act.lock); ! 89: refcount_init(&null_act.ref_count, 1); ! 90: #endif ! 91: ! 92: act_machine_init(); ! 93: } ! 94: ! 95: /* Create a new activation in a specific task. ! 96: Locking: Task */ ! 97: kern_return_t act_create(task_t task, vm_offset_t user_stack, ! 98: vm_offset_t user_rbuf, vm_size_t user_rbuf_size, ! 99: struct Act **new_act) ! 100: { ! 101: Act *act; ! 102: int rc; ! 103: ! 104: #ifndef ACT_STATIC_KLUDGE ! 105: act = (Act*)zalloc(act_zone); ! 106: if (act == 0) ! 107: return(KERN_RESOURCE_SHORTAGE); ! 108: #else ! 109: /* XXX ipt_lock(act_freelist); */ ! 110: act = act_freelist; ! 111: if (act == 0) panic("out of activations"); ! 112: act_freelist = act->ipt_next; ! 113: /* XXX ipt_unlock(act_freelist); */ ! 114: act->ipt_next = 0; ! 115: #endif ! 116: bzero(act, sizeof(*act)); /*XXX shouldn't be needed */ ! 117: ! 118: #ifdef DEBUG ! 119: act->lower = act->higher = 0; ! 120: #endif ! 121: ! 122: /* Start with one reference for being active, another for the caller */ ! 123: simple_lock_init(&act->lock); ! 124: refcount_init(&act->ref_count, 2); ! 125: ! 126: /* Latch onto the task. */ ! 127: act->task = task; ! 128: task_reference(task); ! 129: ! 130: /* Other simple setup */ ! 131: act->ipt = 0; ! 132: act->thread = 0; ! 133: act->suspend_count = 0; ! 134: act->active = 1; ! 135: act->handlers = 0; ! 136: ! 137: /* The special_handler will always be last on the returnhandlers list. */ ! 138: act->special_handler.next = 0; ! 139: act->special_handler.handler = special_handler; ! 140: ! 141: ipc_act_init(task, act); ! 142: act_machine_create(task, act, user_stack, user_rbuf, user_rbuf_size); ! 143: ! 144: task_lock(task); ! 145: ! 146: /* Chain the act onto the task's list */ ! 147: act->task_links.next = task->acts.next; ! 148: act->task_links.prev = &task->acts; ! 149: task->acts.next->prev = &act->task_links; ! 150: task->acts.next = &act->task_links; ! 151: task->act_count++; ! 152: ! 153: task_unlock(task); ! 154: ! 155: *new_act = act; ! 156: return KERN_SUCCESS; ! 157: } ! 158: ! 159: /* This is called when an act's ref_count drops to zero. ! 160: This can only happen when thread is zero (not in use), ! 161: ipt is zero (not attached to any ipt), ! 162: and active is false (terminated). */ ! 163: static void act_free(Act *inc) ! 164: { ! 165: act_machine_destroy(inc); ! 166: ipc_act_destroy(inc); ! 167: ! 168: /* Drop the task reference. */ ! 169: task_deallocate(inc->task); ! 170: ! 171: /* Put the act back on the act zone */ ! 172: #ifndef ACT_STATIC_KLUDGE ! 173: zfree(act_zone, (vm_offset_t)inc); ! 174: #else ! 175: /* XXX ipt_lock(act_freelist); */ ! 176: inc->ipt_next = act_freelist; ! 177: act_freelist = inc; ! 178: /* XXX ipt_unlock(act_freelist); */ ! 179: #endif ! 180: } ! 181: ! 182: void act_deallocate(Act *inc) ! 183: { ! 184: refcount_drop(&inc->ref_count, act_free(inc)); ! 185: } ! 186: ! 187: /* Attach an act to the top of a thread ("push the stack"). ! 188: The thread must be either the current one or a brand-new one. ! 189: Assumes the act is active but not in use. ! 190: Assumes that if it is attached to an ipt (i.e. the ipt pointer is nonzero), ! 191: the act has already been taken off the ipt's list. ! 192: ! 193: Already locked: cur_thread, act */ ! 194: void act_attach(Act *act, thread_t thread, unsigned init_alert_mask) ! 195: { ! 196: Act *lower; ! 197: ! 198: act->thread = thread; ! 199: ! 200: /* The thread holds a reference to the activation while using it. */ ! 201: refcount_take(&act->ref_count); ! 202: ! 203: /* XXX detach any cached activations from above the target */ ! 204: ! 205: /* Chain the act onto the thread's act stack. */ ! 206: lower = thread->top_act; ! 207: act->lower = lower; ! 208: lower->higher = act; ! 209: thread->top_act = act; ! 210: ! 211: act->alert_mask = init_alert_mask; ! 212: act->alerts = lower->alerts & init_alert_mask; ! 213: } ! 214: ! 215: /* Remove the current act from the top of the current thread ("pop the stack"). ! 216: Return it to the ipt it lives on, if any. ! 217: Locking: Thread > Act(not on ipt) > ipc_target */ ! 218: void act_detach(Act *cur_act) ! 219: { ! 220: thread_t cur_thread = cur_act->thread; ! 221: ! 222: thread_lock(cur_thread); ! 223: act_lock(cur_act); ! 224: ! 225: /* Unlink the act from the thread's act stack */ ! 226: cur_thread->top_act = cur_act->lower; ! 227: cur_act->thread = 0; ! 228: #ifdef DEBUG ! 229: cur_act->lower = cur_act->higher = 0; ! 230: #endif ! 231: ! 232: thread_unlock(cur_thread); ! 233: ! 234: /* Return it to the ipt's list */ ! 235: if (cur_act->ipt) ! 236: { ! 237: ipt_lock(cur_act->ipt); ! 238: cur_act->ipt_next = cur_act->ipt->ipt_acts; ! 239: cur_act->ipt->ipt_acts = cur_act; ! 240: ipt_unlock(cur_act->ipt); ! 241: #if 0 ! 242: printf(" return to ipt %x\n", cur_act->ipt); ! 243: #endif ! 244: } ! 245: ! 246: act_unlock(cur_act); ! 247: ! 248: /* Drop the act reference taken for being in use. */ ! 249: refcount_drop(&cur_act->ref_count, act_free(cur_act)); ! 250: } ! 251: ! 252: ! 253: ! 254: /*** Activation control support routines ***/ ! 255: ! 256: /* This is called by system-dependent code ! 257: when it detects that act->handlers is non-null ! 258: while returning into user mode. ! 259: Activations linked onto an ipt always have null act->handlers, ! 260: so RPC entry paths need not check it. ! 261: ! 262: Locking: Act */ ! 263: void act_execute_returnhandlers() ! 264: { ! 265: Act *act = current_act(); ! 266: ! 267: #if 0 ! 268: printf("execute_returnhandlers\n"); ! 269: #endif ! 270: while (1) { ! 271: ReturnHandler *rh; ! 272: ! 273: /* Grab the next returnhandler */ ! 274: act_lock(act); ! 275: rh = act->handlers; ! 276: if (!rh) { ! 277: act_unlock(act); ! 278: return; ! 279: } ! 280: act->handlers = rh->next; ! 281: act_unlock(act); ! 282: ! 283: /* Execute it */ ! 284: (*rh->handler)(rh, act); ! 285: } ! 286: } ! 287: ! 288: /* Try to nudge an act into executing its returnhandler chain. ! 289: Ensures that the activation will execute its returnhandlers ! 290: before it next executes any of its user-level code. ! 291: Also ensures that it is safe to break the thread's activation chain ! 292: immediately above this activation, ! 293: by rolling out of any outstanding two-way-optimized RPC. ! 294: ! 295: The target activation is not necessarily active ! 296: or even in use by a thread. ! 297: If it isn't, this routine does nothing. ! 298: ! 299: Already locked: Act */ ! 300: static void act_nudge(struct Act *act) ! 301: { ! 302: /* If it's suspended, wake it up. */ ! 303: thread_wakeup(&act->suspend_count); ! 304: ! 305: /* Do a machine-dependent low-level nudge. ! 306: If we're on a multiprocessor, ! 307: this may mean sending an interprocessor interrupt. ! 308: In any case, it means rolling out of two-way-optimized RPC paths. */ ! 309: act_machine_nudge(act); ! 310: } ! 311: ! 312: /* Install the special returnhandler that handles suspension and termination, ! 313: if it hasn't been installed already. ! 314: ! 315: Already locked: Act */ ! 316: static void install_special_handler(struct Act *act) ! 317: { ! 318: ReturnHandler **rh; ! 319: ! 320: /* The work handler must always be the last ReturnHandler on the list, ! 321: because it can do tricky things like detach the act. */ ! 322: for (rh = &act->handlers; *rh; rh = &(*rh)->next); ! 323: if (rh != &act->special_handler.next) { ! 324: *rh = &act->special_handler; ! 325: } ! 326: ! 327: /* Nudge the target activation, ! 328: to ensure that it will see the returnhandler we're adding. */ ! 329: act_nudge(act); ! 330: } ! 331: ! 332: /* Locking: Act */ ! 333: static void special_handler(ReturnHandler *rh, struct Act *cur_act) ! 334: { ! 335: retry: ! 336: ! 337: act_lock(cur_act); ! 338: ! 339: /* If someone has killed this invocation, ! 340: invoke the return path with a terminated exception. */ ! 341: if (!cur_act->active) { ! 342: act_unlock(cur_act); ! 343: act_machine_return(KERN_TERMINATED); ! 344: /* XXX should just set the activation's reentry_routine ! 345: and then return from special_handler(). ! 346: The magic reentry_routine should just pop its own activation ! 347: and chain to the reentry_routine of the _lower_ activation. ! 348: If that lower activation is the null_act, ! 349: the thread will then be terminated. */ ! 350: } ! 351: ! 352: /* If we're suspended, go to sleep and wait for someone to wake us up. */ ! 353: if (cur_act->suspend_count) { ! 354: act_unlock(cur_act); ! 355: /* XXX mp unsafe */ ! 356: thread_wait((int)&cur_act->suspend_count, FALSE); ! 357: ! 358: act_lock(cur_act); ! 359: ! 360: /* If we're still (or again) suspended, ! 361: go to sleep again after executing any new returnhandlers that may have appeared. */ ! 362: if (cur_act->suspend_count) ! 363: install_special_handler(cur_act); ! 364: } ! 365: ! 366: act_unlock(cur_act); ! 367: } ! 368: ! 369: #if 0 /************************ OLD SEMI-OBSOLETE CODE *********************/ ! 370: static __dead void act_throughcall_return(Act *act) ! 371: { ! 372: /* Done - destroy the act and return */ ! 373: act_detach(act); ! 374: act_terminate(act); ! 375: act_deallocate(act); ! 376: ! 377: /* XXX */ ! 378: thread_terminate_self(); ! 379: } ! 380: ! 381: __dead void act_throughcall(task_t task, void (*infunc)()) ! 382: { ! 383: thread_t thread = current_thread(); ! 384: Act *act; ! 385: ReturnHandler rh; ! 386: int rc; ! 387: ! 388: rc = act_create(task, 0, 0, 0, &act); ! 389: if (rc) return rc; ! 390: ! 391: act->return_routine = act_throughcall_return; ! 392: ! 393: thread_lock(thread); ! 394: act_lock(act); ! 395: ! 396: act_attach(thread, act, 0); ! 397: ! 398: rh.handler = infunc; ! 399: rh.next = act->handlers; ! 400: act->handlers = &rh; ! 401: ! 402: act_unlock(act); ! 403: thread_unlock(thread); ! 404: ! 405: /* Call through the act into the returnhandler list */ ! 406: act_machine_throughcall(act); ! 407: } ! 408: ! 409: ! 410: /* Grab an act from the specified pool, to pass to act_upcall. ! 411: Returns with the act locked, since it's in an inconsistent state ! 412: (not on its ipt but not on a thread either). ! 413: Returns null if no acts are available on the ipt. ! 414: ! 415: Locking: ipc_target > Act(on ipt) */ ! 416: Act *act_grab(struct ipc_target *ipt) ! 417: { ! 418: Act *act; ! 419: ! 420: ipt_lock(ipt); ! 421: ! 422: retry: ! 423: ! 424: /* Pull an act off the ipt's list. */ ! 425: act = ipt->acts; ! 426: if (!act) ! 427: goto none_avail; ! 428: ipt->acts = act->ipt_next; ! 429: ! 430: act_lock(act); ! 431: ! 432: /* If it's been terminated, drop it and get another one. */ ! 433: if (!act->active) { ! 434: #if 0 ! 435: printf("dropping terminated act %08x\n", act); ! 436: #endif ! 437: /* XXX ipt_deallocate(ipt); */ ! 438: act->ipt = 0; ! 439: act_unlock(act); ! 440: act_deallocate(act); ! 441: goto retry; ! 442: } ! 443: ! 444: none_avail: ! 445: ipt_unlock(ipt); ! 446: ! 447: return act; ! 448: } ! 449: ! 450: /* Try to make an upcall with an act on the specified ipt. ! 451: If the ipt is empty, returns KERN_RESOURCE_SHORTAGE. XXX??? ! 452: ! 453: Locking: ipc_target > Act > Thread */ ! 454: kern_return_t act_upcall(struct Act *act, unsigned init_alert_mask, ! 455: vm_offset_t user_entrypoint, vm_offset_t user_data) ! 456: { ! 457: thread_t cur_thread = current_thread(); ! 458: int rc; ! 459: ! 460: /* XXX locking */ ! 461: ! 462: act_attach(cur_thread, act, init_alert_mask); ! 463: ! 464: /* Make the upcall into the destination task */ ! 465: rc = act_machine_upcall(act, user_entrypoint, user_data); ! 466: ! 467: /* Done - detach the act and return */ ! 468: act_detach(act); ! 469: ! 470: return rc; ! 471: } ! 472: #endif /************************ END OF OLD SEMI-OBSOLETE CODE *********************/ ! 473: ! 474: ! 475: ! 476: ! 477: /*** Act service routines ***/ ! 478: ! 479: /* Lock this act and its current thread. ! 480: We can only find the thread from the act ! 481: and the thread must be locked before the act, ! 482: requiring a little icky juggling. ! 483: ! 484: If the thread is not currently on any thread, ! 485: returns with only the act locked. ! 486: ! 487: Note that this routine is not called on any performance-critical path. ! 488: It is only for explicit act operations ! 489: which don't happen often. ! 490: ! 491: Locking: Thread > Act */ ! 492: static thread_t act_lock_thread(Act *act) ! 493: { ! 494: thread_t thread; ! 495: ! 496: retry: ! 497: ! 498: /* Find the thread */ ! 499: act_lock(act); ! 500: thread = act->thread; ! 501: if (thread == 0) ! 502: { ! 503: act_unlock(act); ! 504: return 0; ! 505: } ! 506: thread_reference(thread); ! 507: act_unlock(act); ! 508: ! 509: /* Lock the thread and re-lock the act, ! 510: and make sure the thread didn't change. */ ! 511: thread_lock(thread); ! 512: act_lock(act); ! 513: if (act->thread != thread) ! 514: { ! 515: act_unlock(act); ! 516: thread_unlock(thread); ! 517: thread_deallocate(thread); ! 518: goto retry; ! 519: } ! 520: ! 521: thread_deallocate(thread); ! 522: ! 523: return thread; ! 524: } ! 525: ! 526: /* Already locked: act->task ! 527: Locking: Task > Act */ ! 528: kern_return_t act_terminate_task_locked(struct Act *act) ! 529: { ! 530: act_lock(act); ! 531: ! 532: if (act->active) ! 533: { ! 534: /* Unlink the act from the task's act list, ! 535: so it doesn't appear in calls to task_acts and such. ! 536: The act still keeps its ref on the task, however, ! 537: until it loses all its own references and is freed. */ ! 538: act->task_links.next->prev = act->task_links.prev; ! 539: act->task_links.prev->next = act->task_links.next; ! 540: act->task->act_count--; ! 541: ! 542: /* Remove it from any ipc_target. XXX is this right? */ ! 543: act_set_target(act, 0); ! 544: ! 545: /* This will allow no more control operations on this act. */ ! 546: act->active = 0; ! 547: ! 548: /* When the special_handler gets executed, ! 549: it will see the terminated condition and exit immediately. */ ! 550: install_special_handler(act); ! 551: ! 552: /* Drop the act reference taken for being active. ! 553: (There is still at least one reference left: the one we were passed.) */ ! 554: act_deallocate(act); ! 555: } ! 556: ! 557: act_unlock(act); ! 558: ! 559: return KERN_SUCCESS; ! 560: } ! 561: ! 562: /* Locking: Task > Act */ ! 563: kern_return_t act_terminate(struct Act *act) ! 564: { ! 565: task_t task = act->task; ! 566: kern_return_t rc; ! 567: ! 568: /* act->task never changes, ! 569: so we can read it before locking the act. */ ! 570: task_lock(act->task); ! 571: ! 572: rc = act_terminate_task_locked(act); ! 573: ! 574: task_unlock(act->task); ! 575: ! 576: return rc; ! 577: } ! 578: ! 579: /* If this Act is on a Thread and is not the topmost, ! 580: yank it and everything below it off of the thread's stack ! 581: and put it all on a new thread forked from the original one. ! 582: May fail due to resource shortage, but can always be retried. ! 583: ! 584: Locking: Thread > Act */ ! 585: kern_return_t act_yank(Act *act) ! 586: { ! 587: thread_t thread = act_lock_thread(act); ! 588: ! 589: #if 0 ! 590: printf("act_yank inc %08x thread %08x\n", act, thread); ! 591: #endif ! 592: if (thread) ! 593: { ! 594: if (thread->top_act != act) ! 595: { ! 596: printf("detaching act %08x from thread %08x\n", act, thread); ! 597: ! 598: /* Nudge the activation into a clean point for detachment. */ ! 599: act_nudge(act); ! 600: ! 601: /* Now detach the activation ! 602: and give the orphan its own flow of control. */ ! 603: /*XXX*/ ! 604: } ! 605: ! 606: thread_unlock(thread); ! 607: } ! 608: act_unlock(act); ! 609: ! 610: /* Ask the thread to return as quickly as possible, ! 611: because its results are now useless. */ ! 612: act_abort(act); ! 613: ! 614: return KERN_SUCCESS; ! 615: } ! 616: ! 617: /* Assign an activation to a specific ipc_target. ! 618: Fails if the activation is already assigned to another pool. ! 619: If ipt == 0, we remove the from its ipt. ! 620: ! 621: Locking: Act(not on ipt) > ipc_target > Act(on ipt) */ ! 622: kern_return_t act_set_target(Act *act, struct ipc_target *ipt) ! 623: { ! 624: act_lock(act); ! 625: ! 626: if (ipt == 0) ! 627: { ! 628: Act **lact; ! 629: ! 630: ipt = act->ipt; ! 631: if (ipt == 0) ! 632: return; ! 633: ! 634: /* XXX This is a violation of the locking order. */ ! 635: ipt_lock(ipt); ! 636: for (lact = &ipt->ipt_acts; *lact; lact = &((*lact)->ipt_next)) ! 637: if (act == *lact) ! 638: { ! 639: *lact = act->ipt_next; ! 640: break; ! 641: } ! 642: ipt_unlock(ipt); ! 643: ! 644: act->ipt = 0; ! 645: /* XXX ipt_deallocate(ipt); */ ! 646: act_deallocate(act); ! 647: return; ! 648: } ! 649: if (act->ipt != ipt) ! 650: { ! 651: if (act->ipt != 0) ! 652: { ! 653: act_unlock(act); ! 654: return KERN_FAILURE; /*XXX*/ ! 655: } ! 656: act->ipt = ipt; ! 657: ipt->ipt_type |= IPT_TYPE_MIGRATE_RPC; ! 658: ! 659: /* They get references to each other. */ ! 660: act_reference(act); ! 661: ipt_reference(ipt); ! 662: ! 663: /* If it is available, ! 664: add it to the ipt's available-activation list. */ ! 665: if ((act->thread == 0) && (act->suspend_count == 0)) ! 666: { ! 667: ipt_lock(ipt); ! 668: act->ipt_next = ipt->ipt_acts; ! 669: act->ipt->ipt_acts = act; ! 670: ipt_unlock(ipt); ! 671: } ! 672: } ! 673: act_unlock(act); ! 674: ! 675: return KERN_SUCCESS; ! 676: } ! 677: ! 678: /* Register an alert from this activation. ! 679: Each set bit is propagated upward from (but not including) this activation, ! 680: until the top of the chain is reached or the bit is masked. ! 681: ! 682: Locking: Thread > Act */ ! 683: kern_return_t act_alert(struct Act *act, unsigned alerts) ! 684: { ! 685: thread_t thread = act_lock_thread(act); ! 686: ! 687: #if 0 ! 688: printf("act_alert %08x: %08x\n", act, alerts); ! 689: #endif ! 690: if (thread) ! 691: { ! 692: struct Act *act_up = act; ! 693: while ((alerts) && (act_up != thread->top_act)) ! 694: { ! 695: act_up = act_up->higher; ! 696: alerts &= act_up->alert_mask; ! 697: act_up->alerts |= alerts; ! 698: } ! 699: ! 700: /* XXX If we reach the top, and it is blocked in glue code, do something. */ ! 701: ! 702: thread_unlock(thread); ! 703: } ! 704: act_unlock(act); ! 705: ! 706: return KERN_SUCCESS; ! 707: } ! 708: ! 709: /* Locking: Thread > Act */ ! 710: kern_return_t act_abort(struct Act *act) ! 711: { ! 712: return act_alert(act, ALERT_ABORT_STRONG); ! 713: } ! 714: ! 715: /* Locking: Thread > Act */ ! 716: kern_return_t act_abort_safely(struct Act *act) ! 717: { ! 718: return act_alert(act, ALERT_ABORT_SAFE); ! 719: } ! 720: ! 721: /* Locking: Thread > Act */ ! 722: kern_return_t act_alert_mask(struct Act *act, unsigned alert_mask) ! 723: { ! 724: panic("act_alert_mask\n"); ! 725: return KERN_SUCCESS; ! 726: } ! 727: ! 728: /* Locking: Thread > Act */ ! 729: kern_return_t act_suspend(struct Act *act) ! 730: { ! 731: thread_t thread = act_lock_thread(act); ! 732: kern_return_t rc = KERN_SUCCESS; ! 733: ! 734: #if 0 ! 735: printf("act_suspend %08x\n", act); ! 736: #endif ! 737: if (act->active) ! 738: { ! 739: if (act->suspend_count++ == 0) ! 740: { ! 741: /* XXX remove from ipt */ ! 742: install_special_handler(act); ! 743: act_nudge(act); ! 744: } ! 745: } ! 746: else ! 747: rc = KERN_TERMINATED; ! 748: ! 749: if (thread) ! 750: thread_unlock(thread); ! 751: act_unlock(act); ! 752: ! 753: return rc; ! 754: } ! 755: ! 756: /* Locking: Act */ ! 757: kern_return_t act_resume(struct Act *act) ! 758: { ! 759: #if 0 ! 760: printf("act_resume %08x from %d\n", act, act->suspend_count); ! 761: #endif ! 762: ! 763: act_lock(act); ! 764: if (!act->active) ! 765: { ! 766: act_unlock(act); ! 767: return KERN_TERMINATED; ! 768: } ! 769: ! 770: if (act->suspend_count > 0) { ! 771: if (--act->suspend_count == 0) { ! 772: thread_wakeup(&act->suspend_count); ! 773: /* XXX return to ipt */ ! 774: } ! 775: } ! 776: ! 777: act_unlock(act); ! 778: ! 779: return KERN_SUCCESS; ! 780: } ! 781: ! 782: typedef struct GetSetState { ! 783: struct ReturnHandler rh; ! 784: int flavor; ! 785: void *state; ! 786: int *pcount; ! 787: int result; ! 788: } GetSetState; ! 789: ! 790: /* Locking: Thread */ ! 791: kern_return_t get_set_state(struct Act *act, int flavor, void *state, int *pcount, ! 792: void (*handler)(ReturnHandler *rh, struct Act *act)) ! 793: { ! 794: GetSetState gss; ! 795: ! 796: /* Initialize a small parameter structure */ ! 797: gss.rh.handler = handler; ! 798: gss.flavor = flavor; ! 799: gss.state = state; ! 800: gss.pcount = pcount; ! 801: ! 802: /* Add it to the act's return handler list */ ! 803: act_lock(act); ! 804: gss.rh.next = act->handlers; ! 805: act->handlers = &gss.rh; ! 806: ! 807: act_nudge(act); ! 808: ! 809: act_unlock(act); ! 810: /* XXX mp unsafe */ ! 811: thread_wait((int)&gss, 0); /* XXX could be interruptible */ ! 812: ! 813: return gss.result; ! 814: } ! 815: ! 816: static void get_state_handler(ReturnHandler *rh, struct Act *act) ! 817: { ! 818: GetSetState *gss = (GetSetState*)rh; ! 819: ! 820: gss->result = act_machine_get_state(act, gss->flavor, gss->state, gss->pcount); ! 821: thread_wakeup((int)gss); ! 822: } ! 823: ! 824: /* Locking: Thread */ ! 825: kern_return_t act_get_state(struct Act *act, int flavor, natural_t *state, natural_t *pcount) ! 826: { ! 827: return get_set_state(act, flavor, state, pcount, get_state_handler); ! 828: } ! 829: ! 830: static void set_state_handler(ReturnHandler *rh, struct Act *act) ! 831: { ! 832: GetSetState *gss = (GetSetState*)rh; ! 833: ! 834: gss->result = act_machine_set_state(act, gss->flavor, gss->state, *gss->pcount); ! 835: thread_wakeup((int)gss); ! 836: } ! 837: ! 838: /* Locking: Thread */ ! 839: kern_return_t act_set_state(struct Act *act, int flavor, natural_t *state, natural_t count) ! 840: { ! 841: return get_set_state(act, flavor, state, &count, set_state_handler); ! 842: } ! 843: ! 844: ! 845: ! 846: /*** backward compatibility hacks ***/ ! 847: ! 848: #include <mach/thread_info.h> ! 849: #include <mach/thread_special_ports.h> ! 850: #include <ipc/ipc_port.h> ! 851: ! 852: kern_return_t act_thread_info(Act *act, int flavor, ! 853: thread_info_t thread_info_out, unsigned *thread_info_count) ! 854: { ! 855: return thread_info(act->thread, flavor, thread_info_out, thread_info_count); ! 856: } ! 857: ! 858: kern_return_t ! 859: act_thread_assign(Act *act, processor_set_t new_pset) ! 860: { ! 861: return thread_assign(act->thread, new_pset); ! 862: } ! 863: ! 864: kern_return_t ! 865: act_thread_assign_default(Act *act) ! 866: { ! 867: return thread_assign_default(act->thread); ! 868: } ! 869: ! 870: kern_return_t ! 871: act_thread_get_assignment(Act *act, processor_set_t *pset) ! 872: { ! 873: return thread_get_assignment(act->thread, pset); ! 874: } ! 875: ! 876: kern_return_t ! 877: act_thread_priority(Act *act, int priority, boolean_t set_max) ! 878: { ! 879: return thread_priority(act->thread, priority, set_max); ! 880: } ! 881: ! 882: kern_return_t ! 883: act_thread_max_priority(Act *act, processor_set_t *pset, int max_priority) ! 884: { ! 885: return thread_max_priority(act->thread, pset, max_priority); ! 886: } ! 887: ! 888: kern_return_t ! 889: act_thread_policy(Act *act, int policy, int data) ! 890: { ! 891: return thread_policy(act->thread, policy, data); ! 892: } ! 893: ! 894: kern_return_t ! 895: act_thread_wire(struct host *host, Act *act, boolean_t wired) ! 896: { ! 897: return thread_wire(host, act->thread, wired); ! 898: } ! 899: ! 900: kern_return_t ! 901: act_thread_depress_abort(Act *act) ! 902: { ! 903: return thread_depress_abort(act->thread); ! 904: } ! 905: ! 906: /* ! 907: * Routine: act_get_special_port [kernel call] ! 908: * Purpose: ! 909: * Clones a send right for one of the thread's ! 910: * special ports. ! 911: * Conditions: ! 912: * Nothing locked. ! 913: * Returns: ! 914: * KERN_SUCCESS Extracted a send right. ! 915: * KERN_INVALID_ARGUMENT The thread is null. ! 916: * KERN_FAILURE The thread is dead. ! 917: * KERN_INVALID_ARGUMENT Invalid special port. ! 918: */ ! 919: ! 920: kern_return_t ! 921: act_get_special_port(Act *act, int which, ipc_port_t *portp) ! 922: { ! 923: ipc_port_t *whichp; ! 924: ipc_port_t port; ! 925: ! 926: #if 0 ! 927: printf("act_get_special_port\n"); ! 928: #endif ! 929: if (act == 0) ! 930: return KERN_INVALID_ARGUMENT; ! 931: ! 932: switch (which) { ! 933: #if MACH_IPC_COMPAT ! 934: case THREAD_REPLY_PORT: ! 935: whichp = &act->reply_port; ! 936: break; ! 937: #endif /* MACH_IPC_COMPAT */ ! 938: ! 939: case THREAD_KERNEL_PORT: ! 940: whichp = &act->self_port; ! 941: break; ! 942: ! 943: case THREAD_EXCEPTION_PORT: ! 944: whichp = &act->exception_port; ! 945: break; ! 946: ! 947: default: ! 948: return KERN_INVALID_ARGUMENT; ! 949: } ! 950: ! 951: thread_lock(act->thread); ! 952: ! 953: if (act->self_port == IP_NULL) { ! 954: thread_unlock(act->thread); ! 955: return KERN_FAILURE; ! 956: } ! 957: ! 958: port = ipc_port_copy_send(*whichp); ! 959: thread_unlock(act->thread); ! 960: ! 961: *portp = port; ! 962: return KERN_SUCCESS; ! 963: } ! 964: ! 965: /* ! 966: * Routine: act_set_special_port [kernel call] ! 967: * Purpose: ! 968: * Changes one of the thread's special ports, ! 969: * setting it to the supplied send right. ! 970: * Conditions: ! 971: * Nothing locked. If successful, consumes ! 972: * the supplied send right. ! 973: * Returns: ! 974: * KERN_SUCCESS Changed the special port. ! 975: * KERN_INVALID_ARGUMENT The thread is null. ! 976: * KERN_FAILURE The thread is dead. ! 977: * KERN_INVALID_ARGUMENT Invalid special port. ! 978: */ ! 979: ! 980: kern_return_t ! 981: act_set_special_port(Act *act, int which, ipc_port_t port) ! 982: { ! 983: ipc_port_t *whichp; ! 984: ipc_port_t old; ! 985: ! 986: #if 0 ! 987: printf("act_set_special_port\n"); ! 988: #endif ! 989: if (act == 0) ! 990: return KERN_INVALID_ARGUMENT; ! 991: ! 992: switch (which) { ! 993: #if MACH_IPC_COMPAT ! 994: case THREAD_REPLY_PORT: ! 995: whichp = &act->reply_port; ! 996: break; ! 997: #endif /* MACH_IPC_COMPAT */ ! 998: ! 999: case THREAD_KERNEL_PORT: ! 1000: whichp = &act->self_port; ! 1001: break; ! 1002: ! 1003: case THREAD_EXCEPTION_PORT: ! 1004: whichp = &act->exception_port; ! 1005: break; ! 1006: ! 1007: default: ! 1008: return KERN_INVALID_ARGUMENT; ! 1009: } ! 1010: ! 1011: thread_lock(act->thread); ! 1012: if (act->self_port == IP_NULL) { ! 1013: thread_unlock(act->thread); ! 1014: return KERN_FAILURE; ! 1015: } ! 1016: ! 1017: old = *whichp; ! 1018: *whichp = port; ! 1019: thread_unlock(act->thread); ! 1020: ! 1021: if (IP_VALID(old)) ! 1022: ipc_port_release_send(old); ! 1023: return KERN_SUCCESS; ! 1024: } ! 1025: ! 1026: /* ! 1027: * XXX lame, non-blocking ways to get/set state. ! 1028: * Return thread's machine-dependent state. ! 1029: */ ! 1030: kern_return_t ! 1031: act_get_state_immediate(act, flavor, old_state, old_state_count) ! 1032: register Act *act; ! 1033: int flavor; ! 1034: void *old_state; /* pointer to OUT array */ ! 1035: unsigned int *old_state_count; /*IN/OUT*/ ! 1036: { ! 1037: kern_return_t ret; ! 1038: ! 1039: act_lock(act); ! 1040: /* not the top activation, return current state */ ! 1041: if (act->thread && act->thread->top_act != act) { ! 1042: ret = act_machine_get_state(act, flavor, ! 1043: old_state, old_state_count); ! 1044: act_unlock(act); ! 1045: return ret; ! 1046: } ! 1047: act_unlock(act); ! 1048: ! 1049: /* not sure this makes sense */ ! 1050: return act_get_state(act, flavor, old_state, old_state_count); ! 1051: } ! 1052: ! 1053: /* ! 1054: * Change thread's machine-dependent state. ! 1055: */ ! 1056: kern_return_t ! 1057: act_set_state_immediate(act, flavor, new_state, new_state_count) ! 1058: register Act *act; ! 1059: int flavor; ! 1060: void *new_state; ! 1061: unsigned int new_state_count; ! 1062: { ! 1063: kern_return_t ret; ! 1064: ! 1065: act_lock(act); ! 1066: /* not the top activation, set it now */ ! 1067: if (act->thread && act->thread->top_act != act) { ! 1068: ret = act_machine_set_state(act, flavor, ! 1069: new_state, new_state_count); ! 1070: act_unlock(act); ! 1071: return ret; ! 1072: } ! 1073: act_unlock(act); ! 1074: ! 1075: /* not sure this makes sense */ ! 1076: return act_set_state(act, flavor, new_state, new_state_count); ! 1077: } ! 1078: ! 1079: void act_count() ! 1080: { ! 1081: int i; ! 1082: Act *act; ! 1083: static int amin = ACT_STATIC_KLUDGE; ! 1084: ! 1085: i = 0; ! 1086: for (act = act_freelist; act; act = act->ipt_next) ! 1087: i++; ! 1088: if (i < amin) ! 1089: amin = i; ! 1090: printf("%d of %d activations in use, %d max\n", ! 1091: ACT_STATIC_KLUDGE-i, ACT_STATIC_KLUDGE, ACT_STATIC_KLUDGE-amin); ! 1092: } ! 1093: ! 1094: dump_act(act) ! 1095: Act *act; ! 1096: { ! 1097: act_count(); ! 1098: kact_count(); ! 1099: while (act) { ! 1100: printf("%08.8x: thread=%x, task=%x, hi=%x, lo=%x, ref=%x\n", ! 1101: act, act->thread, act->task, ! 1102: act->higher, act->lower, act->ref_count); ! 1103: printf("\talerts=%x, mask=%x, susp=%x, active=%x\n", ! 1104: act->alerts, act->alert_mask, ! 1105: act->suspend_count, act->active); ! 1106: machine_dump_act(&act->mact); ! 1107: if (act == act->lower) ! 1108: break; ! 1109: act = act->lower; ! 1110: } ! 1111: } ! 1112: ! 1113: #ifdef ACTWATCH ! 1114: Act * ! 1115: get_next_act(sp) ! 1116: int sp; ! 1117: { ! 1118: static int i; ! 1119: Act *act; ! 1120: ! 1121: while (1) { ! 1122: if (i == ACT_STATIC_KLUDGE) { ! 1123: i = 0; ! 1124: return 0; ! 1125: } ! 1126: act = &free_acts[i]; ! 1127: i++; ! 1128: if (act->mact.space == sp) ! 1129: return act; ! 1130: } ! 1131: } ! 1132: #endif ! 1133: ! 1134: #endif /* MIGRATING_THREADS */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.