|
|
1.1 ! root 1: /* ! 2: * Mach Operating System ! 3: * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University ! 4: * All Rights Reserved. ! 5: * ! 6: * Permission to use, copy, modify and distribute this software and its ! 7: * documentation is hereby granted, provided that both the copyright ! 8: * notice and this permission notice appear in all copies of the ! 9: * software, derivative works or modified versions, and any portions ! 10: * thereof, and that both notices appear in supporting documentation. ! 11: * ! 12: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" ! 13: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR ! 14: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ! 15: * ! 16: * Carnegie Mellon requests users of this software to return to ! 17: * ! 18: * Software Distribution Coordinator or [email protected] ! 19: * School of Computer Science ! 20: * Carnegie Mellon University ! 21: * Pittsburgh PA 15213-3890 ! 22: * ! 23: * any improvements or extensions that they make and grant Carnegie Mellon ! 24: * the rights to redistribute these changes. ! 25: */ ! 26: /* ! 27: * File: ipc_tt.c ! 28: * Purpose: ! 29: * Task and thread related IPC functions. ! 30: */ ! 31: ! 32: #include <mach_ipc_compat.h> ! 33: ! 34: #include <mach/boolean.h> ! 35: #include <mach/kern_return.h> ! 36: #include <mach/mach_param.h> ! 37: #include <mach/task_special_ports.h> ! 38: #include <mach/thread_special_ports.h> ! 39: #include <vm/vm_kern.h> ! 40: #include <kern/task.h> ! 41: #include <kern/thread.h> ! 42: #include <kern/ipc_kobject.h> ! 43: #include <kern/ipc_tt.h> ! 44: #include <ipc/ipc_space.h> ! 45: #include <ipc/ipc_table.h> ! 46: #include <ipc/ipc_port.h> ! 47: #include <ipc/ipc_right.h> ! 48: #include <ipc/ipc_entry.h> ! 49: #include <ipc/ipc_object.h> ! 50: ! 51: ! 52: ! 53: /* ! 54: * Routine: ipc_task_init ! 55: * Purpose: ! 56: * Initialize a task's IPC state. ! 57: * ! 58: * If non-null, some state will be inherited from the parent. ! 59: * The parent must be appropriately initialized. ! 60: * Conditions: ! 61: * Nothing locked. ! 62: */ ! 63: ! 64: void ! 65: ipc_task_init( ! 66: task_t task, ! 67: task_t parent) ! 68: { ! 69: ipc_space_t space; ! 70: ipc_port_t kport; ! 71: kern_return_t kr; ! 72: int i; ! 73: ! 74: ! 75: kr = ipc_space_create(&ipc_table_entries[0], &space); ! 76: if (kr != KERN_SUCCESS) ! 77: panic("ipc_task_init"); ! 78: ! 79: ! 80: kport = ipc_port_alloc_kernel(); ! 81: if (kport == IP_NULL) ! 82: panic("ipc_task_init"); ! 83: ! 84: itk_lock_init(task); ! 85: task->itk_self = kport; ! 86: task->itk_sself = ipc_port_make_send(kport); ! 87: task->itk_space = space; ! 88: ! 89: if (parent == TASK_NULL) { ! 90: task->itk_exception = IP_NULL; ! 91: task->itk_bootstrap = IP_NULL; ! 92: for (i = 0; i < TASK_PORT_REGISTER_MAX; i++) ! 93: task->itk_registered[i] = IP_NULL; ! 94: } else { ! 95: itk_lock(parent); ! 96: assert(parent->itk_self != IP_NULL); ! 97: ! 98: /* inherit registered ports */ ! 99: ! 100: for (i = 0; i < TASK_PORT_REGISTER_MAX; i++) ! 101: task->itk_registered[i] = ! 102: ipc_port_copy_send(parent->itk_registered[i]); ! 103: ! 104: /* inherit exception and bootstrap ports */ ! 105: ! 106: task->itk_exception = ! 107: ipc_port_copy_send(parent->itk_exception); ! 108: task->itk_bootstrap = ! 109: ipc_port_copy_send(parent->itk_bootstrap); ! 110: ! 111: itk_unlock(parent); ! 112: } ! 113: } ! 114: ! 115: /* ! 116: * Routine: ipc_task_enable ! 117: * Purpose: ! 118: * Enable a task for IPC access. ! 119: * Conditions: ! 120: * Nothing locked. ! 121: */ ! 122: ! 123: void ! 124: ipc_task_enable( ! 125: task_t task) ! 126: { ! 127: ipc_port_t kport; ! 128: ! 129: itk_lock(task); ! 130: kport = task->itk_self; ! 131: if (kport != IP_NULL) ! 132: ipc_kobject_set(kport, (ipc_kobject_t) task, IKOT_TASK); ! 133: itk_unlock(task); ! 134: } ! 135: ! 136: /* ! 137: * Routine: ipc_task_disable ! 138: * Purpose: ! 139: * Disable IPC access to a task. ! 140: * Conditions: ! 141: * Nothing locked. ! 142: */ ! 143: ! 144: void ! 145: ipc_task_disable( ! 146: task_t task) ! 147: { ! 148: ipc_port_t kport; ! 149: ! 150: itk_lock(task); ! 151: kport = task->itk_self; ! 152: if (kport != IP_NULL) ! 153: ipc_kobject_set(kport, IKO_NULL, IKOT_NONE); ! 154: itk_unlock(task); ! 155: } ! 156: ! 157: /* ! 158: * Routine: ipc_task_terminate ! 159: * Purpose: ! 160: * Clean up and destroy a task's IPC state. ! 161: * Conditions: ! 162: * Nothing locked. The task must be suspended. ! 163: * (Or the current thread must be in the task.) ! 164: */ ! 165: ! 166: void ! 167: ipc_task_terminate( ! 168: task_t task) ! 169: { ! 170: ipc_port_t kport; ! 171: int i; ! 172: ! 173: itk_lock(task); ! 174: kport = task->itk_self; ! 175: ! 176: if (kport == IP_NULL) { ! 177: /* the task is already terminated (can this happen?) */ ! 178: itk_unlock(task); ! 179: return; ! 180: } ! 181: ! 182: task->itk_self = IP_NULL; ! 183: itk_unlock(task); ! 184: ! 185: /* release the naked send rights */ ! 186: ! 187: if (IP_VALID(task->itk_sself)) ! 188: ipc_port_release_send(task->itk_sself); ! 189: if (IP_VALID(task->itk_exception)) ! 190: ipc_port_release_send(task->itk_exception); ! 191: if (IP_VALID(task->itk_bootstrap)) ! 192: ipc_port_release_send(task->itk_bootstrap); ! 193: ! 194: for (i = 0; i < TASK_PORT_REGISTER_MAX; i++) ! 195: if (IP_VALID(task->itk_registered[i])) ! 196: ipc_port_release_send(task->itk_registered[i]); ! 197: ! 198: /* destroy the space, leaving just a reference for it */ ! 199: ! 200: ipc_space_destroy(task->itk_space); ! 201: ! 202: /* destroy the kernel port */ ! 203: ! 204: ipc_port_dealloc_kernel(kport); ! 205: } ! 206: ! 207: /* ! 208: * Routine: ipc_thread_init ! 209: * Purpose: ! 210: * Initialize a thread's IPC state. ! 211: * Conditions: ! 212: * Nothing locked. ! 213: */ ! 214: ! 215: void ! 216: ipc_thread_init(thread) ! 217: thread_t thread; ! 218: { ! 219: ipc_port_t kport; ! 220: ! 221: kport = ipc_port_alloc_kernel(); ! 222: if (kport == IP_NULL) ! 223: panic("ipc_thread_init"); ! 224: ! 225: ipc_thread_links_init(thread); ! 226: ipc_kmsg_queue_init(&thread->ith_messages); ! 227: ! 228: ith_lock_init(thread); ! 229: thread->ith_self = kport; ! 230: thread->ith_sself = ipc_port_make_send(kport); ! 231: thread->ith_exception = IP_NULL; ! 232: ! 233: thread->ith_mig_reply = MACH_PORT_NULL; ! 234: thread->ith_rpc_reply = IP_NULL; ! 235: ! 236: #if MACH_IPC_COMPAT ! 237: { ! 238: ipc_space_t space = thread->task->itk_space; ! 239: ipc_port_t port; ! 240: mach_port_t name; ! 241: kern_return_t kr; ! 242: ! 243: kr = ipc_port_alloc_compat(space, &name, &port); ! 244: if (kr != KERN_SUCCESS) ! 245: panic("ipc_thread_init"); ! 246: /* port is locked and active */ ! 247: ! 248: /* ! 249: * Now we have a reply port. We need to make a naked ! 250: * send right to stash in ith_reply. We can't use ! 251: * ipc_port_make_send, because we can't unlock the port ! 252: * before making the right. Also we don't want to ! 253: * increment ip_mscount. The net effect of all this ! 254: * is the same as doing ! 255: * ipc_port_alloc_kernel get the port ! 256: * ipc_port_make_send make the send right ! 257: * ipc_object_copyin_from_kernel grab receive right ! 258: * ipc_object_copyout_compat and give to user ! 259: */ ! 260: ! 261: port->ip_srights++; ! 262: ip_reference(port); ! 263: ip_unlock(port); ! 264: ! 265: thread->ith_reply = port; ! 266: } ! 267: #endif /* MACH_IPC_COMPAT */ ! 268: } ! 269: ! 270: /* ! 271: * Routine: ipc_thread_enable ! 272: * Purpose: ! 273: * Enable a thread for IPC access. ! 274: * Conditions: ! 275: * Nothing locked. ! 276: */ ! 277: ! 278: void ! 279: ipc_thread_enable(thread) ! 280: thread_t thread; ! 281: { ! 282: ipc_port_t kport; ! 283: ! 284: ith_lock(thread); ! 285: kport = thread->ith_self; ! 286: if (kport != IP_NULL) ! 287: ipc_kobject_set(kport, (ipc_kobject_t) thread, IKOT_THREAD); ! 288: ith_unlock(thread); ! 289: } ! 290: ! 291: /* ! 292: * Routine: ipc_thread_disable ! 293: * Purpose: ! 294: * Disable IPC access to a thread. ! 295: * Conditions: ! 296: * Nothing locked. ! 297: */ ! 298: ! 299: void ! 300: ipc_thread_disable(thread) ! 301: thread_t thread; ! 302: { ! 303: ipc_port_t kport; ! 304: ! 305: ith_lock(thread); ! 306: kport = thread->ith_self; ! 307: if (kport != IP_NULL) ! 308: ipc_kobject_set(kport, IKO_NULL, IKOT_NONE); ! 309: ith_unlock(thread); ! 310: } ! 311: ! 312: /* ! 313: * Routine: ipc_thread_terminate ! 314: * Purpose: ! 315: * Clean up and destroy a thread's IPC state. ! 316: * Conditions: ! 317: * Nothing locked. The thread must be suspended. ! 318: * (Or be the current thread.) ! 319: */ ! 320: ! 321: void ! 322: ipc_thread_terminate(thread) ! 323: thread_t thread; ! 324: { ! 325: ipc_port_t kport; ! 326: ! 327: ith_lock(thread); ! 328: kport = thread->ith_self; ! 329: ! 330: if (kport == IP_NULL) { ! 331: /* the thread is already terminated (can this happen?) */ ! 332: ith_unlock(thread); ! 333: return; ! 334: } ! 335: ! 336: thread->ith_self = IP_NULL; ! 337: ith_unlock(thread); ! 338: ! 339: assert(ipc_kmsg_queue_empty(&thread->ith_messages)); ! 340: ! 341: /* release the naked send rights */ ! 342: ! 343: if (IP_VALID(thread->ith_sself)) ! 344: ipc_port_release_send(thread->ith_sself); ! 345: if (IP_VALID(thread->ith_exception)) ! 346: ipc_port_release_send(thread->ith_exception); ! 347: ! 348: #if MACH_IPC_COMPAT ! 349: if (IP_VALID(thread->ith_reply)) { ! 350: ipc_space_t space = thread->task->itk_space; ! 351: ipc_port_t port = thread->ith_reply; ! 352: ipc_entry_t entry; ! 353: mach_port_t name; ! 354: ! 355: /* destroy any rights the task may have for the port */ ! 356: ! 357: is_write_lock(space); ! 358: if (space->is_active && ! 359: ipc_right_reverse(space, (ipc_object_t) port, ! 360: &name, &entry)) { ! 361: /* reply port is locked and active */ ! 362: ip_unlock(port); ! 363: ! 364: (void) ipc_right_destroy(space, name, entry); ! 365: /* space is unlocked */ ! 366: } else ! 367: is_write_unlock(space); ! 368: ! 369: ipc_port_release_send(port); ! 370: } ! 371: ! 372: /* ! 373: * Note we do *not* destroy any rights the space may have ! 374: * for the thread's kernel port. The old IPC code did this, ! 375: * to avoid generating a notification when the port is ! 376: * destroyed. However, this isn't a good idea when ! 377: * the kernel port is interposed, because then it doesn't ! 378: * happen, exposing the interposition to the task. ! 379: * Because we don't need the efficiency hack, I flushed ! 380: * this behaviour, introducing a small incompatibility ! 381: * with the old IPC code. ! 382: */ ! 383: #endif /* MACH_IPC_COMPAT */ ! 384: ! 385: /* destroy the kernel port */ ! 386: ! 387: ipc_port_dealloc_kernel(kport); ! 388: } ! 389: ! 390: #if 0 ! 391: /* ! 392: * Routine: retrieve_task_self ! 393: * Purpose: ! 394: * Return a send right (possibly null/dead) ! 395: * for the task's user-visible self port. ! 396: * Conditions: ! 397: * Nothing locked. ! 398: */ ! 399: ! 400: ipc_port_t ! 401: retrieve_task_self(task) ! 402: task_t task; ! 403: { ! 404: ipc_port_t port; ! 405: ! 406: assert(task != TASK_NULL); ! 407: ! 408: itk_lock(task); ! 409: if (task->itk_self != IP_NULL) ! 410: port = ipc_port_copy_send(task->itk_sself); ! 411: else ! 412: port = IP_NULL; ! 413: itk_unlock(task); ! 414: ! 415: return port; ! 416: } ! 417: ! 418: /* ! 419: * Routine: retrieve_thread_self ! 420: * Purpose: ! 421: * Return a send right (possibly null/dead) ! 422: * for the thread's user-visible self port. ! 423: * Conditions: ! 424: * Nothing locked. ! 425: */ ! 426: ! 427: ipc_port_t ! 428: retrieve_thread_self(thread) ! 429: thread_t thread; ! 430: { ! 431: ipc_port_t port; ! 432: ! 433: assert(thread != ITH_NULL); ! 434: ! 435: ith_lock(thread); ! 436: if (thread->ith_self != IP_NULL) ! 437: port = ipc_port_copy_send(thread->ith_sself); ! 438: else ! 439: port = IP_NULL; ! 440: ith_unlock(thread); ! 441: ! 442: return port; ! 443: } ! 444: #endif /* 0 */ ! 445: ! 446: /* ! 447: * Routine: retrieve_task_self_fast ! 448: * Purpose: ! 449: * Optimized version of retrieve_task_self, ! 450: * that only works for the current task. ! 451: * ! 452: * Return a send right (possibly null/dead) ! 453: * for the task's user-visible self port. ! 454: * Conditions: ! 455: * Nothing locked. ! 456: */ ! 457: ! 458: ipc_port_t ! 459: retrieve_task_self_fast( ! 460: register task_t task) ! 461: { ! 462: register ipc_port_t port; ! 463: ! 464: assert(task == current_task()); ! 465: ! 466: itk_lock(task); ! 467: assert(task->itk_self != IP_NULL); ! 468: ! 469: if ((port = task->itk_sself) == task->itk_self) { ! 470: /* no interposing */ ! 471: ! 472: ip_lock(port); ! 473: assert(ip_active(port)); ! 474: ip_reference(port); ! 475: port->ip_srights++; ! 476: ip_unlock(port); ! 477: } else ! 478: port = ipc_port_copy_send(port); ! 479: itk_unlock(task); ! 480: ! 481: return port; ! 482: } ! 483: ! 484: /* ! 485: * Routine: retrieve_thread_self_fast ! 486: * Purpose: ! 487: * Optimized version of retrieve_thread_self, ! 488: * that only works for the current thread. ! 489: * ! 490: * Return a send right (possibly null/dead) ! 491: * for the thread's user-visible self port. ! 492: * Conditions: ! 493: * Nothing locked. ! 494: */ ! 495: ! 496: ipc_port_t ! 497: retrieve_thread_self_fast(thread) ! 498: register thread_t thread; ! 499: { ! 500: register ipc_port_t port; ! 501: ! 502: assert(thread == current_thread()); ! 503: ! 504: ith_lock(thread); ! 505: assert(thread->ith_self != IP_NULL); ! 506: ! 507: if ((port = thread->ith_sself) == thread->ith_self) { ! 508: /* no interposing */ ! 509: ! 510: ip_lock(port); ! 511: assert(ip_active(port)); ! 512: ip_reference(port); ! 513: port->ip_srights++; ! 514: ip_unlock(port); ! 515: } else ! 516: port = ipc_port_copy_send(port); ! 517: ith_unlock(thread); ! 518: ! 519: return port; ! 520: } ! 521: ! 522: #if 0 ! 523: /* ! 524: * Routine: retrieve_task_exception ! 525: * Purpose: ! 526: * Return a send right (possibly null/dead) ! 527: * for the task's exception port. ! 528: * Conditions: ! 529: * Nothing locked. ! 530: */ ! 531: ! 532: ipc_port_t ! 533: retrieve_task_exception(task) ! 534: task_t task; ! 535: { ! 536: ipc_port_t port; ! 537: ! 538: assert(task != TASK_NULL); ! 539: ! 540: itk_lock(task); ! 541: if (task->itk_self != IP_NULL) ! 542: port = ipc_port_copy_send(task->itk_exception); ! 543: else ! 544: port = IP_NULL; ! 545: itk_unlock(task); ! 546: ! 547: return port; ! 548: } ! 549: ! 550: /* ! 551: * Routine: retrieve_thread_exception ! 552: * Purpose: ! 553: * Return a send right (possibly null/dead) ! 554: * for the thread's exception port. ! 555: * Conditions: ! 556: * Nothing locked. ! 557: */ ! 558: ! 559: ipc_port_t ! 560: retrieve_thread_exception(thread) ! 561: thread_t thread; ! 562: { ! 563: ipc_port_t port; ! 564: ! 565: assert(thread != ITH_NULL); ! 566: ! 567: ith_lock(thread); ! 568: if (thread->ith_self != IP_NULL) ! 569: port = ipc_port_copy_send(thread->ith_exception); ! 570: else ! 571: port = IP_NULL; ! 572: ith_unlock(thread); ! 573: ! 574: return port; ! 575: } ! 576: #endif /* 0 */ ! 577: ! 578: /* ! 579: * Routine: mach_task_self [mach trap] ! 580: * Purpose: ! 581: * Give the caller send rights for his own task port. ! 582: * Conditions: ! 583: * Nothing locked. ! 584: * Returns: ! 585: * MACH_PORT_NULL if there are any resource failures ! 586: * or other errors. ! 587: */ ! 588: ! 589: mach_port_t ! 590: mach_task_self(void) ! 591: { ! 592: task_t task = current_task(); ! 593: ipc_port_t sright; ! 594: ! 595: sright = retrieve_task_self_fast(task); ! 596: return ipc_port_copyout_send(sright, task->itk_space); ! 597: } ! 598: ! 599: /* ! 600: * Routine: mach_thread_self [mach trap] ! 601: * Purpose: ! 602: * Give the caller send rights for his own thread port. ! 603: * Conditions: ! 604: * Nothing locked. ! 605: * Returns: ! 606: * MACH_PORT_NULL if there are any resource failures ! 607: * or other errors. ! 608: */ ! 609: ! 610: mach_port_t ! 611: mach_thread_self() ! 612: { ! 613: thread_t thread = current_thread(); ! 614: task_t task = thread->task; ! 615: ipc_port_t sright; ! 616: ! 617: sright = retrieve_thread_self_fast(thread); ! 618: return ipc_port_copyout_send(sright, task->itk_space); ! 619: } ! 620: ! 621: /* ! 622: * Routine: mach_reply_port [mach trap] ! 623: * Purpose: ! 624: * Allocate a port for the caller. ! 625: * Conditions: ! 626: * Nothing locked. ! 627: * Returns: ! 628: * MACH_PORT_NULL if there are any resource failures ! 629: * or other errors. ! 630: */ ! 631: ! 632: mach_port_t ! 633: mach_reply_port(void) ! 634: { ! 635: ipc_port_t port; ! 636: mach_port_t name; ! 637: kern_return_t kr; ! 638: ! 639: kr = ipc_port_alloc(current_task()->itk_space, &name, &port); ! 640: if (kr == KERN_SUCCESS) ! 641: ip_unlock(port); ! 642: else ! 643: name = MACH_PORT_NULL; ! 644: ! 645: return name; ! 646: } ! 647: ! 648: #if MACH_IPC_COMPAT ! 649: ! 650: /* ! 651: * Routine: retrieve_task_notify ! 652: * Purpose: ! 653: * Return a reference (or null) for ! 654: * the task's notify port. ! 655: * Conditions: ! 656: * Nothing locked. ! 657: */ ! 658: ! 659: ipc_port_t ! 660: retrieve_task_notify(task) ! 661: task_t task; ! 662: { ! 663: ipc_space_t space = task->itk_space; ! 664: ipc_port_t port; ! 665: ! 666: is_read_lock(space); ! 667: if (space->is_active) { ! 668: port = space->is_notify; ! 669: if (IP_VALID(port)) ! 670: ipc_port_reference(port); ! 671: } else ! 672: port = IP_NULL; ! 673: is_read_unlock(space); ! 674: ! 675: return port; ! 676: } ! 677: ! 678: /* ! 679: * Routine: retrieve_thread_reply ! 680: * Purpose: ! 681: * Return a reference (or null) for ! 682: * the thread's reply port. ! 683: * Conditions: ! 684: * Nothing locked. ! 685: */ ! 686: ! 687: ipc_port_t ! 688: retrieve_thread_reply(thread) ! 689: thread_t thread; ! 690: { ! 691: ipc_port_t port; ! 692: ! 693: ith_lock(thread); ! 694: if (thread->ith_self != IP_NULL) { ! 695: port = thread->ith_reply; ! 696: if (IP_VALID(port)) ! 697: ipc_port_reference(port); ! 698: } else ! 699: port = IP_NULL; ! 700: ith_unlock(thread); ! 701: ! 702: return port; ! 703: } ! 704: ! 705: /* ! 706: * Routine: task_self [mach trap] ! 707: * Purpose: ! 708: * Give the caller send rights for his task port. ! 709: * If new, the send right is marked with IE_BITS_COMPAT. ! 710: * Conditions: ! 711: * Nothing locked. ! 712: * Returns: ! 713: * MACH_PORT_NULL if there are any resource failures ! 714: * or other errors. ! 715: */ ! 716: ! 717: port_name_t ! 718: task_self() ! 719: { ! 720: task_t task = current_task(); ! 721: ipc_port_t sright; ! 722: mach_port_t name; ! 723: ! 724: sright = retrieve_task_self_fast(task); ! 725: name = ipc_port_copyout_send_compat(sright, task->itk_space); ! 726: return (port_name_t) name; ! 727: } ! 728: ! 729: /* ! 730: * Routine: task_notify [mach trap] ! 731: * Purpose: ! 732: * Give the caller the name of his own notify port. ! 733: * Conditions: ! 734: * Nothing locked. ! 735: * Returns: ! 736: * MACH_PORT_NULL if there isn't a notify port, ! 737: * if it is dead, or if the caller doesn't hold ! 738: * receive rights for it. ! 739: */ ! 740: ! 741: port_name_t ! 742: task_notify() ! 743: { ! 744: task_t task = current_task(); ! 745: ipc_port_t notify; ! 746: mach_port_t name; ! 747: ! 748: notify = retrieve_task_notify(task); ! 749: name = ipc_port_copyout_receiver(notify, task->itk_space); ! 750: return (port_name_t) name; ! 751: } ! 752: ! 753: /* ! 754: * Routine: thread_self [mach trap] ! 755: * Purpose: ! 756: * Give the caller send rights for his own thread port. ! 757: * If new, the send right is marked with IE_BITS_COMPAT. ! 758: * Conditions: ! 759: * Nothing locked. ! 760: * Returns: ! 761: * MACH_PORT_NULL if there are any resource failures ! 762: * or other errors. ! 763: */ ! 764: ! 765: port_name_t ! 766: thread_self() ! 767: { ! 768: thread_t thread = current_thread(); ! 769: task_t task = thread->task; ! 770: ipc_port_t sright; ! 771: mach_port_t name; ! 772: ! 773: sright = retrieve_thread_self_fast(thread); ! 774: name = ipc_port_copyout_send_compat(sright, task->itk_space); ! 775: return (port_name_t) name; ! 776: } ! 777: ! 778: /* ! 779: * Routine: thread_reply [mach trap] ! 780: * Purpose: ! 781: * Give the caller the name of his own reply port. ! 782: * Conditions: ! 783: * Nothing locked. ! 784: * Returns: ! 785: * MACH_PORT_NULL if there isn't a reply port, ! 786: * if it is dead, or if the caller doesn't hold ! 787: * receive rights for it. ! 788: */ ! 789: ! 790: port_name_t ! 791: thread_reply() ! 792: { ! 793: task_t task = current_task(); ! 794: thread_t thread = current_thread(); ! 795: ipc_port_t reply; ! 796: mach_port_t name; ! 797: ! 798: reply = retrieve_thread_reply(thread); ! 799: name = ipc_port_copyout_receiver(reply, task->itk_space); ! 800: return (port_name_t) name; ! 801: } ! 802: ! 803: #endif /* MACH_IPC_COMPAT */ ! 804: ! 805: /* ! 806: * Routine: task_get_special_port [kernel call] ! 807: * Purpose: ! 808: * Clones a send right for one of the task's ! 809: * special ports. ! 810: * Conditions: ! 811: * Nothing locked. ! 812: * Returns: ! 813: * KERN_SUCCESS Extracted a send right. ! 814: * KERN_INVALID_ARGUMENT The task is null. ! 815: * KERN_FAILURE The task/space is dead. ! 816: * KERN_INVALID_ARGUMENT Invalid special port. ! 817: */ ! 818: ! 819: kern_return_t ! 820: task_get_special_port( ! 821: task_t task, ! 822: int which, ! 823: ipc_port_t *portp) ! 824: { ! 825: ipc_port_t *whichp; ! 826: ipc_port_t port; ! 827: ! 828: if (task == TASK_NULL) ! 829: return KERN_INVALID_ARGUMENT; ! 830: ! 831: switch (which) { ! 832: #if MACH_IPC_COMPAT ! 833: case TASK_NOTIFY_PORT: { ! 834: ipc_space_t space = task->itk_space; ! 835: ! 836: is_read_lock(space); ! 837: if (!space->is_active) { ! 838: is_read_unlock(space); ! 839: return KERN_FAILURE; ! 840: } ! 841: ! 842: port = ipc_port_copy_send(space->is_notify); ! 843: is_read_unlock(space); ! 844: ! 845: *portp = port; ! 846: return KERN_SUCCESS; ! 847: } ! 848: #endif /* MACH_IPC_COMPAT */ ! 849: ! 850: case TASK_KERNEL_PORT: ! 851: whichp = &task->itk_sself; ! 852: break; ! 853: ! 854: case TASK_EXCEPTION_PORT: ! 855: whichp = &task->itk_exception; ! 856: break; ! 857: ! 858: case TASK_BOOTSTRAP_PORT: ! 859: whichp = &task->itk_bootstrap; ! 860: break; ! 861: ! 862: default: ! 863: return KERN_INVALID_ARGUMENT; ! 864: } ! 865: ! 866: itk_lock(task); ! 867: if (task->itk_self == IP_NULL) { ! 868: itk_unlock(task); ! 869: return KERN_FAILURE; ! 870: } ! 871: ! 872: port = ipc_port_copy_send(*whichp); ! 873: itk_unlock(task); ! 874: ! 875: *portp = port; ! 876: return KERN_SUCCESS; ! 877: } ! 878: ! 879: /* ! 880: * Routine: task_set_special_port [kernel call] ! 881: * Purpose: ! 882: * Changes one of the task's special ports, ! 883: * setting it to the supplied send right. ! 884: * Conditions: ! 885: * Nothing locked. If successful, consumes ! 886: * the supplied send right. ! 887: * Returns: ! 888: * KERN_SUCCESS Changed the special port. ! 889: * KERN_INVALID_ARGUMENT The task is null. ! 890: * KERN_FAILURE The task/space is dead. ! 891: * KERN_INVALID_ARGUMENT Invalid special port. ! 892: */ ! 893: ! 894: kern_return_t ! 895: task_set_special_port( ! 896: task_t task, ! 897: int which, ! 898: ipc_port_t port) ! 899: { ! 900: ipc_port_t *whichp; ! 901: ipc_port_t old; ! 902: ! 903: if (task == TASK_NULL) ! 904: return KERN_INVALID_ARGUMENT; ! 905: ! 906: switch (which) { ! 907: #if MACH_IPC_COMPAT ! 908: case TASK_NOTIFY_PORT: { ! 909: ipc_space_t space = task->itk_space; ! 910: ! 911: is_write_lock(space); ! 912: if (!space->is_active) { ! 913: is_write_unlock(space); ! 914: return KERN_FAILURE; ! 915: } ! 916: ! 917: old = space->is_notify; ! 918: space->is_notify = port; ! 919: is_write_unlock(space); ! 920: ! 921: if (IP_VALID(old)) ! 922: ipc_port_release_send(old); ! 923: return KERN_SUCCESS; ! 924: } ! 925: #endif /* MACH_IPC_COMPAT */ ! 926: ! 927: case TASK_KERNEL_PORT: ! 928: whichp = &task->itk_sself; ! 929: break; ! 930: ! 931: case TASK_EXCEPTION_PORT: ! 932: whichp = &task->itk_exception; ! 933: break; ! 934: ! 935: case TASK_BOOTSTRAP_PORT: ! 936: whichp = &task->itk_bootstrap; ! 937: break; ! 938: ! 939: default: ! 940: return KERN_INVALID_ARGUMENT; ! 941: } ! 942: ! 943: itk_lock(task); ! 944: if (task->itk_self == IP_NULL) { ! 945: itk_unlock(task); ! 946: return KERN_FAILURE; ! 947: } ! 948: ! 949: old = *whichp; ! 950: *whichp = port; ! 951: itk_unlock(task); ! 952: ! 953: if (IP_VALID(old)) ! 954: ipc_port_release_send(old); ! 955: return KERN_SUCCESS; ! 956: } ! 957: ! 958: /* ! 959: * Routine: thread_get_special_port [kernel call] ! 960: * Purpose: ! 961: * Clones a send right for one of the thread's ! 962: * special ports. ! 963: * Conditions: ! 964: * Nothing locked. ! 965: * Returns: ! 966: * KERN_SUCCESS Extracted a send right. ! 967: * KERN_INVALID_ARGUMENT The thread is null. ! 968: * KERN_FAILURE The thread is dead. ! 969: * KERN_INVALID_ARGUMENT Invalid special port. ! 970: */ ! 971: ! 972: kern_return_t ! 973: thread_get_special_port(thread, which, portp) ! 974: thread_t thread; ! 975: int which; ! 976: ipc_port_t *portp; ! 977: { ! 978: ipc_port_t *whichp; ! 979: ipc_port_t port; ! 980: ! 981: if (thread == ITH_NULL) ! 982: return KERN_INVALID_ARGUMENT; ! 983: ! 984: switch (which) { ! 985: #if MACH_IPC_COMPAT ! 986: case THREAD_REPLY_PORT: ! 987: whichp = &thread->ith_reply; ! 988: break; ! 989: #endif /* MACH_IPC_COMPAT */ ! 990: ! 991: case THREAD_KERNEL_PORT: ! 992: whichp = &thread->ith_sself; ! 993: break; ! 994: ! 995: case THREAD_EXCEPTION_PORT: ! 996: whichp = &thread->ith_exception; ! 997: break; ! 998: ! 999: default: ! 1000: return KERN_INVALID_ARGUMENT; ! 1001: } ! 1002: ! 1003: ith_lock(thread); ! 1004: if (thread->ith_self == IP_NULL) { ! 1005: ith_unlock(thread); ! 1006: return KERN_FAILURE; ! 1007: } ! 1008: ! 1009: port = ipc_port_copy_send(*whichp); ! 1010: ith_unlock(thread); ! 1011: ! 1012: *portp = port; ! 1013: return KERN_SUCCESS; ! 1014: } ! 1015: ! 1016: /* ! 1017: * Routine: thread_set_special_port [kernel call] ! 1018: * Purpose: ! 1019: * Changes one of the thread's special ports, ! 1020: * setting it to the supplied send right. ! 1021: * Conditions: ! 1022: * Nothing locked. If successful, consumes ! 1023: * the supplied send right. ! 1024: * Returns: ! 1025: * KERN_SUCCESS Changed the special port. ! 1026: * KERN_INVALID_ARGUMENT The thread is null. ! 1027: * KERN_FAILURE The thread is dead. ! 1028: * KERN_INVALID_ARGUMENT Invalid special port. ! 1029: */ ! 1030: ! 1031: kern_return_t ! 1032: thread_set_special_port(thread, which, port) ! 1033: thread_t thread; ! 1034: int which; ! 1035: ipc_port_t port; ! 1036: { ! 1037: ipc_port_t *whichp; ! 1038: ipc_port_t old; ! 1039: ! 1040: if (thread == ITH_NULL) ! 1041: return KERN_INVALID_ARGUMENT; ! 1042: ! 1043: switch (which) { ! 1044: #if MACH_IPC_COMPAT ! 1045: case THREAD_REPLY_PORT: ! 1046: whichp = &thread->ith_reply; ! 1047: break; ! 1048: #endif /* MACH_IPC_COMPAT */ ! 1049: ! 1050: case THREAD_KERNEL_PORT: ! 1051: whichp = &thread->ith_sself; ! 1052: break; ! 1053: ! 1054: case THREAD_EXCEPTION_PORT: ! 1055: whichp = &thread->ith_exception; ! 1056: break; ! 1057: ! 1058: default: ! 1059: return KERN_INVALID_ARGUMENT; ! 1060: } ! 1061: ! 1062: ith_lock(thread); ! 1063: if (thread->ith_self == IP_NULL) { ! 1064: ith_unlock(thread); ! 1065: return KERN_FAILURE; ! 1066: } ! 1067: ! 1068: old = *whichp; ! 1069: *whichp = port; ! 1070: ith_unlock(thread); ! 1071: ! 1072: if (IP_VALID(old)) ! 1073: ipc_port_release_send(old); ! 1074: return KERN_SUCCESS; ! 1075: } ! 1076: ! 1077: /* ! 1078: * Routine: mach_ports_register [kernel call] ! 1079: * Purpose: ! 1080: * Stash a handful of port send rights in the task. ! 1081: * Child tasks will inherit these rights, but they ! 1082: * must use mach_ports_lookup to acquire them. ! 1083: * ! 1084: * The rights are supplied in a (wired) kalloc'd segment. ! 1085: * Rights which aren't supplied are assumed to be null. ! 1086: * Conditions: ! 1087: * Nothing locked. If successful, consumes ! 1088: * the supplied rights and memory. ! 1089: * Returns: ! 1090: * KERN_SUCCESS Stashed the port rights. ! 1091: * KERN_INVALID_ARGUMENT The task is null. ! 1092: * KERN_INVALID_ARGUMENT The task is dead. ! 1093: * KERN_INVALID_ARGUMENT Too many port rights supplied. ! 1094: */ ! 1095: ! 1096: kern_return_t ! 1097: mach_ports_register( ! 1098: task_t task, ! 1099: mach_port_array_t memory, ! 1100: mach_msg_type_number_t portsCnt) ! 1101: { ! 1102: ipc_port_t ports[TASK_PORT_REGISTER_MAX]; ! 1103: int i; ! 1104: ! 1105: if ((task == TASK_NULL) || ! 1106: (portsCnt > TASK_PORT_REGISTER_MAX)) ! 1107: return KERN_INVALID_ARGUMENT; ! 1108: ! 1109: /* ! 1110: * Pad the port rights with nulls. ! 1111: */ ! 1112: ! 1113: for (i = 0; i < portsCnt; i++) ! 1114: ports[i] = (ipc_port_t) memory[i]; ! 1115: for (; i < TASK_PORT_REGISTER_MAX; i++) ! 1116: ports[i] = IP_NULL; ! 1117: ! 1118: itk_lock(task); ! 1119: if (task->itk_self == IP_NULL) { ! 1120: itk_unlock(task); ! 1121: return KERN_INVALID_ARGUMENT; ! 1122: } ! 1123: ! 1124: /* ! 1125: * Replace the old send rights with the new. ! 1126: * Release the old rights after unlocking. ! 1127: */ ! 1128: ! 1129: for (i = 0; i < TASK_PORT_REGISTER_MAX; i++) { ! 1130: ipc_port_t old; ! 1131: ! 1132: old = task->itk_registered[i]; ! 1133: task->itk_registered[i] = ports[i]; ! 1134: ports[i] = old; ! 1135: } ! 1136: ! 1137: itk_unlock(task); ! 1138: ! 1139: for (i = 0; i < TASK_PORT_REGISTER_MAX; i++) ! 1140: if (IP_VALID(ports[i])) ! 1141: ipc_port_release_send(ports[i]); ! 1142: ! 1143: /* ! 1144: * Now that the operation is known to be successful, ! 1145: * we can free the memory. ! 1146: */ ! 1147: ! 1148: if (portsCnt != 0) ! 1149: kfree((vm_offset_t) memory, ! 1150: (vm_size_t) (portsCnt * sizeof(mach_port_t))); ! 1151: ! 1152: return KERN_SUCCESS; ! 1153: } ! 1154: ! 1155: /* ! 1156: * Routine: mach_ports_lookup [kernel call] ! 1157: * Purpose: ! 1158: * Retrieves (clones) the stashed port send rights. ! 1159: * Conditions: ! 1160: * Nothing locked. If successful, the caller gets ! 1161: * rights and memory. ! 1162: * Returns: ! 1163: * KERN_SUCCESS Retrieved the send rights. ! 1164: * KERN_INVALID_ARGUMENT The task is null. ! 1165: * KERN_INVALID_ARGUMENT The task is dead. ! 1166: * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. ! 1167: */ ! 1168: ! 1169: kern_return_t ! 1170: mach_ports_lookup(task, portsp, portsCnt) ! 1171: task_t task; ! 1172: ipc_port_t **portsp; ! 1173: mach_msg_type_number_t *portsCnt; ! 1174: { ! 1175: vm_offset_t memory; ! 1176: vm_size_t size; ! 1177: ipc_port_t *ports; ! 1178: int i; ! 1179: ! 1180: if (task == TASK_NULL) ! 1181: return KERN_INVALID_ARGUMENT; ! 1182: ! 1183: size = (vm_size_t) (TASK_PORT_REGISTER_MAX * sizeof(ipc_port_t)); ! 1184: ! 1185: memory = kalloc(size); ! 1186: if (memory == 0) ! 1187: return KERN_RESOURCE_SHORTAGE; ! 1188: ! 1189: itk_lock(task); ! 1190: if (task->itk_self == IP_NULL) { ! 1191: itk_unlock(task); ! 1192: ! 1193: kfree(memory, size); ! 1194: return KERN_INVALID_ARGUMENT; ! 1195: } ! 1196: ! 1197: ports = (ipc_port_t *) memory; ! 1198: ! 1199: /* ! 1200: * Clone port rights. Because kalloc'd memory ! 1201: * is wired, we won't fault while holding the task lock. ! 1202: */ ! 1203: ! 1204: for (i = 0; i < TASK_PORT_REGISTER_MAX; i++) ! 1205: ports[i] = ipc_port_copy_send(task->itk_registered[i]); ! 1206: ! 1207: itk_unlock(task); ! 1208: ! 1209: *portsp = ports; ! 1210: *portsCnt = TASK_PORT_REGISTER_MAX; ! 1211: return KERN_SUCCESS; ! 1212: } ! 1213: ! 1214: /* ! 1215: * Routine: convert_port_to_task ! 1216: * Purpose: ! 1217: * Convert from a port to a task. ! 1218: * Doesn't consume the port ref; produces a task ref, ! 1219: * which may be null. ! 1220: * Conditions: ! 1221: * Nothing locked. ! 1222: */ ! 1223: ! 1224: task_t ! 1225: convert_port_to_task( ! 1226: ipc_port_t port) ! 1227: { ! 1228: task_t task = TASK_NULL; ! 1229: ! 1230: if (IP_VALID(port)) { ! 1231: ip_lock(port); ! 1232: if (ip_active(port) && ! 1233: (ip_kotype(port) == IKOT_TASK)) { ! 1234: task = (task_t) port->ip_kobject; ! 1235: task_reference(task); ! 1236: } ! 1237: ip_unlock(port); ! 1238: } ! 1239: ! 1240: return task; ! 1241: } ! 1242: ! 1243: /* ! 1244: * Routine: convert_port_to_space ! 1245: * Purpose: ! 1246: * Convert from a port to a space. ! 1247: * Doesn't consume the port ref; produces a space ref, ! 1248: * which may be null. ! 1249: * Conditions: ! 1250: * Nothing locked. ! 1251: */ ! 1252: ! 1253: ipc_space_t ! 1254: convert_port_to_space( ! 1255: ipc_port_t port) ! 1256: { ! 1257: ipc_space_t space = IS_NULL; ! 1258: ! 1259: if (IP_VALID(port)) { ! 1260: ip_lock(port); ! 1261: if (ip_active(port) && ! 1262: (ip_kotype(port) == IKOT_TASK)) { ! 1263: space = ((task_t) port->ip_kobject)->itk_space; ! 1264: is_reference(space); ! 1265: } ! 1266: ip_unlock(port); ! 1267: } ! 1268: ! 1269: return space; ! 1270: } ! 1271: ! 1272: /* ! 1273: * Routine: convert_port_to_map ! 1274: * Purpose: ! 1275: * Convert from a port to a map. ! 1276: * Doesn't consume the port ref; produces a map ref, ! 1277: * which may be null. ! 1278: * Conditions: ! 1279: * Nothing locked. ! 1280: */ ! 1281: ! 1282: vm_map_t ! 1283: convert_port_to_map(port) ! 1284: ipc_port_t port; ! 1285: { ! 1286: vm_map_t map = VM_MAP_NULL; ! 1287: ! 1288: if (IP_VALID(port)) { ! 1289: ip_lock(port); ! 1290: if (ip_active(port) && ! 1291: (ip_kotype(port) == IKOT_TASK)) { ! 1292: map = ((task_t) port->ip_kobject)->map; ! 1293: vm_map_reference(map); ! 1294: } ! 1295: ip_unlock(port); ! 1296: } ! 1297: ! 1298: return map; ! 1299: } ! 1300: ! 1301: /* ! 1302: * Routine: convert_port_to_thread ! 1303: * Purpose: ! 1304: * Convert from a port to a thread. ! 1305: * Doesn't consume the port ref; produces a thread ref, ! 1306: * which may be null. ! 1307: * Conditions: ! 1308: * Nothing locked. ! 1309: */ ! 1310: ! 1311: thread_t ! 1312: convert_port_to_thread(port) ! 1313: ipc_port_t port; ! 1314: { ! 1315: thread_t thread = THREAD_NULL; ! 1316: ! 1317: if (IP_VALID(port)) { ! 1318: ip_lock(port); ! 1319: if (ip_active(port) && ! 1320: (ip_kotype(port) == IKOT_THREAD)) { ! 1321: thread = (thread_t) port->ip_kobject; ! 1322: thread_reference(thread); ! 1323: } ! 1324: ip_unlock(port); ! 1325: } ! 1326: ! 1327: return thread; ! 1328: } ! 1329: ! 1330: /* ! 1331: * Routine: convert_task_to_port ! 1332: * Purpose: ! 1333: * Convert from a task to a port. ! 1334: * Consumes a task ref; produces a naked send right ! 1335: * which may be invalid. ! 1336: * Conditions: ! 1337: * Nothing locked. ! 1338: */ ! 1339: ! 1340: ipc_port_t ! 1341: convert_task_to_port(task) ! 1342: task_t task; ! 1343: { ! 1344: ipc_port_t port; ! 1345: ! 1346: itk_lock(task); ! 1347: if (task->itk_self != IP_NULL) ! 1348: port = ipc_port_make_send(task->itk_self); ! 1349: else ! 1350: port = IP_NULL; ! 1351: itk_unlock(task); ! 1352: ! 1353: task_deallocate(task); ! 1354: return port; ! 1355: } ! 1356: ! 1357: /* ! 1358: * Routine: convert_thread_to_port ! 1359: * Purpose: ! 1360: * Convert from a thread to a port. ! 1361: * Consumes a thread ref; produces a naked send right ! 1362: * which may be invalid. ! 1363: * Conditions: ! 1364: * Nothing locked. ! 1365: */ ! 1366: ! 1367: ipc_port_t ! 1368: convert_thread_to_port(thread) ! 1369: thread_t thread; ! 1370: { ! 1371: ipc_port_t port; ! 1372: ! 1373: ith_lock(thread); ! 1374: if (thread->ith_self != IP_NULL) ! 1375: port = ipc_port_make_send(thread->ith_self); ! 1376: else ! 1377: port = IP_NULL; ! 1378: ith_unlock(thread); ! 1379: ! 1380: thread_deallocate(thread); ! 1381: return port; ! 1382: } ! 1383: ! 1384: /* ! 1385: * Routine: space_deallocate ! 1386: * Purpose: ! 1387: * Deallocate a space ref produced by convert_port_to_space. ! 1388: * Conditions: ! 1389: * Nothing locked. ! 1390: */ ! 1391: ! 1392: void ! 1393: space_deallocate(space) ! 1394: ipc_space_t space; ! 1395: { ! 1396: if (space != IS_NULL) ! 1397: is_release(space); ! 1398: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.