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