darwin-xnu/osfmk/ipc/ipc_object.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
   3 *
   4 * @APPLE_LICENSE_HEADER_START@
   5 * 
   6 * The contents of this file constitute Original Code as defined in and
   7 * are subject to the Apple Public Source License Version 1.1 (the
   8 * "License").  You may not use this file except in compliance with the
   9 * License.  Please obtain a copy of the License at
  10 * http://www.apple.com/publicsource and read it before using this file.
  11 * 
  12 * This Original Code and all software distributed under the License are
  13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
  16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
  17 * License for the specific language governing rights and limitations
  18 * under the License.
  19 * 
  20 * @APPLE_LICENSE_HEADER_END@
  21 */
  22/*
  23 * @OSF_COPYRIGHT@
  24 */
  25/* 
  26 * Mach Operating System
  27 * Copyright (c) 1991,1990,1989 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  Software.Distribution@CS.CMU.EDU
  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/*
  53 *      File:   ipc/ipc_object.c
  54 *      Author: Rich Draves
  55 *      Date:   1989
  56 *
  57 *      Functions to manipulate IPC objects.
  58 */
  59
  60#include <mach_rt.h>
  61
  62#include <mach/mach_types.h>
  63#include <mach/boolean.h>
  64#include <mach/kern_return.h>
  65#include <mach/port.h>
  66#include <mach/message.h>
  67
  68#include <kern/kern_types.h>
  69#include <kern/misc_protos.h>
  70
  71#include <ipc/ipc_types.h>
  72#include <ipc/port.h>
  73#include <ipc/ipc_space.h>
  74#include <ipc/ipc_entry.h>
  75#include <ipc/ipc_object.h>
  76#include <ipc/ipc_hash.h>
  77#include <ipc/ipc_right.h>
  78#include <ipc/ipc_notify.h>
  79#include <ipc/ipc_pset.h>
  80
  81zone_t ipc_object_zones[IOT_NUMBER];
  82
  83/*
  84 *      Routine:        ipc_object_reference
  85 *      Purpose:
  86 *              Take a reference to an object.
  87 */
  88
  89void
  90ipc_object_reference(
  91        ipc_object_t    object)
  92{
  93        io_lock(object);
  94        assert(object->io_references > 0);
  95        io_reference(object);
  96        io_unlock(object);
  97}
  98
  99/*
 100 *      Routine:        ipc_object_release
 101 *      Purpose:
 102 *              Release a reference to an object.
 103 */
 104
 105void
 106ipc_object_release(
 107        ipc_object_t    object)
 108{
 109        io_lock(object);
 110        assert(object->io_references > 0);
 111        io_release(object);
 112        io_check_unlock(object);
 113}
 114
 115/*
 116 *      Routine:        ipc_object_translate
 117 *      Purpose:
 118 *              Look up an object in a space.
 119 *      Conditions:
 120 *              Nothing locked before.  If successful, the object
 121 *              is returned locked.  The caller doesn't get a ref.
 122 *      Returns:
 123 *              KERN_SUCCESS            Object returned locked.
 124 *              KERN_INVALID_TASK       The space is dead.
 125 *              KERN_INVALID_NAME       The name doesn't denote a right.
 126 *              KERN_INVALID_RIGHT      Name doesn't denote the correct right.
 127 */
 128
 129kern_return_t
 130ipc_object_translate(
 131        ipc_space_t             space,
 132        mach_port_name_t        name,
 133        mach_port_right_t       right,
 134        ipc_object_t            *objectp)
 135{
 136        ipc_entry_t entry;
 137        ipc_object_t object;
 138        kern_return_t kr;
 139
 140        kr = ipc_right_lookup_read(space, name, &entry);
 141        if (kr != KERN_SUCCESS)
 142                return kr;
 143        /* space is read-locked and active */
 144
 145        if ((entry->ie_bits & MACH_PORT_TYPE(right)) == MACH_PORT_TYPE_NONE) {
 146                is_read_unlock(space);
 147                return KERN_INVALID_RIGHT;
 148        }
 149
 150        object = entry->ie_object;
 151        assert(object != IO_NULL);
 152
 153        io_lock(object);
 154        is_read_unlock(space);
 155
 156        *objectp = object;
 157        return KERN_SUCCESS;
 158}
 159
 160/*
 161 *      Routine:        ipc_object_translate_two
 162 *      Purpose:
 163 *              Look up two objects in a space.
 164 *      Conditions:
 165 *              Nothing locked before.  If successful, the objects
 166 *              are returned locked.  The caller doesn't get a ref.
 167 *      Returns:
 168 *              KERN_SUCCESS            Objects returned locked.
 169 *              KERN_INVALID_TASK       The space is dead.
 170 *              KERN_INVALID_NAME       A name doesn't denote a right.
 171 *              KERN_INVALID_RIGHT      A name doesn't denote the correct right.
 172 */
 173
 174kern_return_t
 175ipc_object_translate_two(
 176        ipc_space_t             space,
 177        mach_port_name_t        name1,
 178        mach_port_right_t       right1,
 179        ipc_object_t            *objectp1,
 180        mach_port_name_t        name2,
 181        mach_port_right_t       right2,
 182        ipc_object_t            *objectp2)
 183{
 184        ipc_entry_t entry1;
 185        ipc_entry_t entry2;
 186        ipc_object_t object;
 187        kern_return_t kr;
 188
 189        kr = ipc_right_lookup_two_read(space, name1, &entry1, name2, &entry2);
 190        if (kr != KERN_SUCCESS)
 191                return kr;
 192        /* space is read-locked and active */
 193
 194        if ((entry1->ie_bits & MACH_PORT_TYPE(right1)) == MACH_PORT_TYPE_NONE) {
 195                is_read_unlock(space);
 196                return KERN_INVALID_RIGHT;
 197        }
 198
 199        if ((entry2->ie_bits & MACH_PORT_TYPE(right2)) == MACH_PORT_TYPE_NONE) {
 200                is_read_unlock(space);
 201                return KERN_INVALID_RIGHT;
 202        }
 203
 204        object = entry1->ie_object;
 205        assert(object != IO_NULL);
 206        io_lock(object);
 207        *objectp1 = object;
 208
 209        object = entry2->ie_object;
 210        assert(object != IO_NULL);
 211        io_lock(object);
 212        *objectp2 = object;
 213
 214        is_read_unlock(space);
 215        return KERN_SUCCESS;
 216}
 217
 218/*
 219 *      Routine:        ipc_object_alloc_dead
 220 *      Purpose:
 221 *              Allocate a dead-name entry.
 222 *      Conditions:
 223 *              Nothing locked.
 224 *      Returns:
 225 *              KERN_SUCCESS            The dead name is allocated.
 226 *              KERN_INVALID_TASK       The space is dead.
 227 *              KERN_NO_SPACE           No room for an entry in the space.
 228 *              KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
 229 */
 230
 231kern_return_t
 232ipc_object_alloc_dead(
 233        ipc_space_t             space,
 234        mach_port_name_t        *namep)
 235{
 236        ipc_entry_t entry;
 237        kern_return_t kr;
 238
 239        kr = ipc_entry_alloc(space, namep, &entry);
 240        if (kr != KERN_SUCCESS)
 241                return kr;
 242        /* space is write-locked */
 243
 244        /* null object, MACH_PORT_TYPE_DEAD_NAME, 1 uref */
 245
 246        assert(entry->ie_object == IO_NULL);
 247        entry->ie_bits |= MACH_PORT_TYPE_DEAD_NAME | 1;
 248        
 249        is_write_unlock(space);
 250        return KERN_SUCCESS;
 251}
 252
 253/*
 254 *      Routine:        ipc_object_alloc_dead_name
 255 *      Purpose:
 256 *              Allocate a dead-name entry, with a specific name.
 257 *      Conditions:
 258 *              Nothing locked.
 259 *      Returns:
 260 *              KERN_SUCCESS            The dead name is allocated.
 261 *              KERN_INVALID_TASK       The space is dead.
 262 *              KERN_NAME_EXISTS        The name already denotes a right.
 263 *              KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
 264 */
 265
 266kern_return_t
 267ipc_object_alloc_dead_name(
 268        ipc_space_t             space,
 269        mach_port_name_t        name)
 270{
 271        ipc_entry_t entry;
 272        kern_return_t kr;
 273
 274        kr = ipc_entry_alloc_name(space, name, &entry);
 275        if (kr != KERN_SUCCESS)
 276                return kr;
 277        /* space is write-locked */
 278
 279        if (ipc_right_inuse(space, name, entry))
 280                return KERN_NAME_EXISTS;
 281
 282        /* null object, MACH_PORT_TYPE_DEAD_NAME, 1 uref */
 283
 284        assert(entry->ie_object == IO_NULL);
 285        entry->ie_bits |= MACH_PORT_TYPE_DEAD_NAME | 1;
 286
 287        is_write_unlock(space);
 288        return KERN_SUCCESS;
 289}
 290
 291/*
 292 *      Routine:        ipc_object_alloc
 293 *      Purpose:
 294 *              Allocate an object.
 295 *      Conditions:
 296 *              Nothing locked.  If successful, the object is returned locked.
 297 *              The caller doesn't get a reference for the object.
 298 *      Returns:
 299 *              KERN_SUCCESS            The object is allocated.
 300 *              KERN_INVALID_TASK       The space is dead.
 301 *              KERN_NO_SPACE           No room for an entry in the space.
 302 *              KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
 303 */
 304
 305kern_return_t
 306ipc_object_alloc(
 307        ipc_space_t             space,
 308        ipc_object_type_t       otype,
 309        mach_port_type_t        type,
 310        mach_port_urefs_t       urefs,
 311        mach_port_name_t        *namep,
 312        ipc_object_t            *objectp)
 313{
 314        ipc_object_t object;
 315        ipc_entry_t entry;
 316        kern_return_t kr;
 317
 318        assert(otype < IOT_NUMBER);
 319        assert((type & MACH_PORT_TYPE_ALL_RIGHTS) == type);
 320        assert(type != MACH_PORT_TYPE_NONE);
 321        assert(urefs <= MACH_PORT_UREFS_MAX);
 322
 323        object = io_alloc(otype);
 324        if (object == IO_NULL)
 325                return KERN_RESOURCE_SHORTAGE;
 326
 327        if (otype == IOT_PORT) {
 328                ipc_port_t port = (ipc_port_t)object;
 329
 330                bzero((char *)port, sizeof(*port));
 331        } else if (otype == IOT_PORT_SET) {
 332                ipc_pset_t pset = (ipc_pset_t)object;
 333
 334                bzero((char *)pset, sizeof(*pset));
 335        }
 336
 337        io_lock_init(object);
 338        *namep = (mach_port_name_t)object;
 339        kr = ipc_entry_alloc(space, namep, &entry);
 340        if (kr != KERN_SUCCESS) {
 341                io_free(otype, object);
 342                return kr;
 343        }
 344        /* space is write-locked */
 345
 346        entry->ie_bits |= type | urefs;
 347        entry->ie_object = object;
 348
 349        io_lock(object);
 350        is_write_unlock(space);
 351
 352        object->io_references = 1; /* for entry, not caller */
 353        object->io_bits = io_makebits(TRUE, otype, 0);
 354
 355        *objectp = object;
 356        return KERN_SUCCESS;
 357}
 358
 359/*
 360 *      Routine:        ipc_object_alloc_name
 361 *      Purpose:
 362 *              Allocate an object, with a specific name.
 363 *      Conditions:
 364 *              Nothing locked.  If successful, the object is returned locked.
 365 *              The caller doesn't get a reference for the object.
 366 *      Returns:
 367 *              KERN_SUCCESS            The object is allocated.
 368 *              KERN_INVALID_TASK       The space is dead.
 369 *              KERN_NAME_EXISTS        The name already denotes a right.
 370 *              KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
 371 */
 372
 373kern_return_t
 374ipc_object_alloc_name(
 375        ipc_space_t             space,
 376        ipc_object_type_t       otype,
 377        mach_port_type_t        type,
 378        mach_port_urefs_t       urefs,
 379        mach_port_name_t        name,
 380        ipc_object_t            *objectp)
 381{
 382        ipc_object_t object;
 383        ipc_entry_t entry;
 384        kern_return_t kr;
 385
 386        assert(otype < IOT_NUMBER);
 387        assert((type & MACH_PORT_TYPE_ALL_RIGHTS) == type);
 388        assert(type != MACH_PORT_TYPE_NONE);
 389        assert(urefs <= MACH_PORT_UREFS_MAX);
 390
 391        object = io_alloc(otype);
 392        if (object == IO_NULL)
 393                return KERN_RESOURCE_SHORTAGE;
 394
 395        if (otype == IOT_PORT) {
 396                ipc_port_t port = (ipc_port_t)object;
 397
 398                bzero((char *)port, sizeof(*port));
 399        } else if (otype == IOT_PORT_SET) {
 400                ipc_pset_t pset = (ipc_pset_t)object;
 401
 402                bzero((char *)pset, sizeof(*pset));
 403        }
 404
 405        io_lock_init(object);
 406        kr = ipc_entry_alloc_name(space, name, &entry);
 407        if (kr != KERN_SUCCESS) {
 408                io_free(otype, object);
 409                return kr;
 410        }
 411        /* space is write-locked */
 412
 413        if (ipc_right_inuse(space, name, entry)) {
 414                io_free(otype, object);
 415                return KERN_NAME_EXISTS;
 416        }
 417
 418        entry->ie_bits |= type | urefs;
 419        entry->ie_object = object;
 420
 421        io_lock(object);
 422        is_write_unlock(space);
 423
 424        object->io_references = 1; /* for entry, not caller */
 425        object->io_bits = io_makebits(TRUE, otype, 0);
 426
 427        *objectp = object;
 428        return KERN_SUCCESS;
 429}
 430
 431/*
 432 *      Routine:        ipc_object_copyin_type
 433 *      Purpose:
 434 *              Convert a send type name to a received type name.
 435 */
 436
 437mach_msg_type_name_t
 438ipc_object_copyin_type(
 439        mach_msg_type_name_t    msgt_name)
 440{
 441        switch (msgt_name) {
 442
 443            case MACH_MSG_TYPE_MOVE_RECEIVE:
 444            case MACH_MSG_TYPE_COPY_RECEIVE:
 445                return MACH_MSG_TYPE_PORT_RECEIVE;
 446
 447            case MACH_MSG_TYPE_MOVE_SEND_ONCE:
 448            case MACH_MSG_TYPE_MAKE_SEND_ONCE:
 449                return MACH_MSG_TYPE_PORT_SEND_ONCE;
 450
 451            case MACH_MSG_TYPE_MOVE_SEND:
 452            case MACH_MSG_TYPE_MAKE_SEND:
 453            case MACH_MSG_TYPE_COPY_SEND:
 454                return MACH_MSG_TYPE_PORT_SEND;
 455
 456            default:
 457                return MACH_MSG_TYPE_PORT_NONE;
 458        }
 459}
 460
 461/*
 462 *      Routine:        ipc_object_copyin
 463 *      Purpose:
 464 *              Copyin a capability from a space.
 465 *              If successful, the caller gets a ref
 466 *              for the resulting object, unless it is IO_DEAD.
 467 *      Conditions:
 468 *              Nothing locked.
 469 *      Returns:
 470 *              KERN_SUCCESS            Acquired an object, possibly IO_DEAD.
 471 *              KERN_INVALID_TASK       The space is dead.
 472 *              KERN_INVALID_NAME       Name doesn't exist in space.
 473 *              KERN_INVALID_RIGHT      Name doesn't denote correct right.
 474 */
 475
 476kern_return_t
 477ipc_object_copyin(
 478        ipc_space_t             space,
 479        mach_port_name_t        name,
 480        mach_msg_type_name_t    msgt_name,
 481        ipc_object_t            *objectp)
 482{
 483        ipc_entry_t entry;
 484        ipc_port_t soright;
 485        kern_return_t kr;
 486
 487        /*
 488         *      Could first try a read lock when doing
 489         *      MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND,
 490         *      and MACH_MSG_TYPE_MAKE_SEND_ONCE.
 491         */
 492
 493        kr = ipc_right_lookup_write(space, name, &entry);
 494        if (kr != KERN_SUCCESS)
 495                return kr;
 496        /* space is write-locked and active */
 497
 498        kr = ipc_right_copyin(space, name, entry,
 499                              msgt_name, TRUE,
 500                              objectp, &soright);
 501        if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE)
 502                ipc_entry_dealloc(space, name, entry);
 503        is_write_unlock(space);
 504
 505        if ((kr == KERN_SUCCESS) && (soright != IP_NULL))
 506                ipc_notify_port_deleted(soright, name);
 507
 508        return kr;
 509}
 510
 511/*
 512 *      Routine:        ipc_object_copyin_from_kernel
 513 *      Purpose:
 514 *              Copyin a naked capability from the kernel.
 515 *
 516 *              MACH_MSG_TYPE_MOVE_RECEIVE
 517 *                      The receiver must be ipc_space_kernel
 518 *                      or the receive right must already be in limbo.
 519 *                      Consumes the naked receive right.
 520 *              MACH_MSG_TYPE_COPY_SEND
 521 *                      A naked send right must be supplied.
 522 *                      The port gains a reference, and a send right
 523 *                      if the port is still active.
 524 *              MACH_MSG_TYPE_MAKE_SEND
 525 *                      The receiver must be ipc_space_kernel.
 526 *                      The port gains a reference and a send right.
 527 *              MACH_MSG_TYPE_MOVE_SEND
 528 *                      Consumes a naked send right.
 529 *              MACH_MSG_TYPE_MAKE_SEND_ONCE
 530 *                      The port gains a reference and a send-once right.
 531 *                      Receiver also be the caller of device subsystem,
 532 *                      so no assertion.
 533 *              MACH_MSG_TYPE_MOVE_SEND_ONCE
 534 *                      Consumes a naked send-once right.
 535 *      Conditions:
 536 *              Nothing locked.
 537 */
 538
 539void
 540ipc_object_copyin_from_kernel(
 541        ipc_object_t            object,
 542        mach_msg_type_name_t    msgt_name)
 543{
 544        assert(IO_VALID(object));
 545
 546        switch (msgt_name) {
 547            case MACH_MSG_TYPE_MOVE_RECEIVE: {
 548                ipc_port_t port = (ipc_port_t) object;
 549
 550                ip_lock(port);
 551                assert(ip_active(port));
 552                if (port->ip_destination != IP_NULL) {
 553                        assert(port->ip_receiver == ipc_space_kernel);
 554
 555                        /* relevant part of ipc_port_clear_receiver */
 556                        ipc_port_set_mscount(port, 0);
 557
 558                        port->ip_receiver_name = MACH_PORT_NULL;
 559                        port->ip_destination = IP_NULL;
 560                }
 561                ip_unlock(port);
 562                break;
 563            }
 564
 565            case MACH_MSG_TYPE_COPY_SEND: {
 566                ipc_port_t port = (ipc_port_t) object;
 567
 568                ip_lock(port);
 569                if (ip_active(port)) {
 570                        assert(port->ip_srights > 0);
 571                        port->ip_srights++;
 572                }
 573                ip_reference(port);
 574                ip_unlock(port);
 575                break;
 576            }
 577
 578            case MACH_MSG_TYPE_MAKE_SEND: {
 579                ipc_port_t port = (ipc_port_t) object;
 580
 581                ip_lock(port);
 582                assert(ip_active(port));
 583                assert(port->ip_receiver_name != MACH_PORT_NULL);
 584                assert(port->ip_receiver == ipc_space_kernel);
 585
 586                ip_reference(port);
 587                port->ip_mscount++;
 588                port->ip_srights++;
 589                ip_unlock(port);
 590                break;
 591            }
 592
 593            case MACH_MSG_TYPE_MOVE_SEND: {
 594                /* move naked send right into the message */
 595                assert(((ipc_port_t)object)->ip_srights);
 596                break;
 597            }
 598
 599            case MACH_MSG_TYPE_MAKE_SEND_ONCE: {
 600                ipc_port_t port = (ipc_port_t) object;
 601
 602                ip_lock(port);
 603                assert(ip_active(port));
 604                assert(port->ip_receiver_name != MACH_PORT_NULL);
 605
 606                ip_reference(port);
 607                port->ip_sorights++;
 608                ip_unlock(port);
 609                break;
 610            }
 611
 612            case MACH_MSG_TYPE_MOVE_SEND_ONCE: {
 613                /* move naked send-once right into the message */
 614                assert(((ipc_port_t)object)->ip_sorights);
 615                break;
 616            }
 617
 618            default:
 619                panic("ipc_object_copyin_from_kernel: strange rights");
 620        }
 621}
 622
 623/*
 624 *      Routine:        ipc_object_destroy
 625 *      Purpose:
 626 *              Destroys a naked capability.
 627 *              Consumes a ref for the object.
 628 *
 629 *              A receive right should be in limbo or in transit.
 630 *      Conditions:
 631 *              Nothing locked.
 632 */
 633
 634void
 635ipc_object_destroy(
 636        ipc_object_t            object,
 637        mach_msg_type_name_t    msgt_name)
 638{
 639        assert(IO_VALID(object));
 640        assert(io_otype(object) == IOT_PORT);
 641
 642        switch (msgt_name) {
 643            case MACH_MSG_TYPE_PORT_SEND:
 644                ipc_port_release_send((ipc_port_t) object);
 645                break;
 646
 647            case MACH_MSG_TYPE_PORT_SEND_ONCE:
 648                ipc_notify_send_once((ipc_port_t) object);
 649                break;
 650
 651            case MACH_MSG_TYPE_PORT_RECEIVE:
 652                ipc_port_release_receive((ipc_port_t) object);
 653                break;
 654
 655            default:
 656                panic("ipc_object_destroy: strange rights");
 657        }
 658}
 659
 660/*
 661 *      Routine:        ipc_object_copyout
 662 *      Purpose:
 663 *              Copyout a capability, placing it into a space.
 664 *              If successful, consumes a ref for the object.
 665 *      Conditions:
 666 *              Nothing locked.
 667 *      Returns:
 668 *              KERN_SUCCESS            Copied out object, consumed ref.
 669 *              KERN_INVALID_TASK       The space is dead.
 670 *              KERN_INVALID_CAPABILITY The object is dead.
 671 *              KERN_NO_SPACE           No room in space for another right.
 672 *              KERN_RESOURCE_SHORTAGE  No memory available.
 673 *              KERN_UREFS_OVERFLOW     Urefs limit exceeded
 674 *                      and overflow wasn't specified.
 675 */
 676
 677kern_return_t
 678ipc_object_copyout(
 679        ipc_space_t             space,
 680        ipc_object_t            object,
 681        mach_msg_type_name_t    msgt_name,
 682        boolean_t               overflow,
 683        mach_port_name_t        *namep)
 684{
 685        mach_port_name_t name;
 686        ipc_entry_t entry;
 687        kern_return_t kr;
 688
 689        assert(IO_VALID(object));
 690        assert(io_otype(object) == IOT_PORT);
 691
 692        is_write_lock(space);
 693
 694        for (;;) {
 695                if (!space->is_active) {
 696                        is_write_unlock(space);
 697                        return KERN_INVALID_TASK;
 698                }
 699
 700                if ((msgt_name != MACH_MSG_TYPE_PORT_SEND_ONCE) &&
 701                    ipc_right_reverse(space, object, &name, &entry)) { 
 702                        /* object is locked and active */
 703
 704                        assert(entry->ie_bits & MACH_PORT_TYPE_SEND_RECEIVE);
 705                        break;
 706                }
 707
 708                name = (mach_port_name_t)object;
 709                kr = ipc_entry_get(space, &name, &entry);
 710                if (kr != KERN_SUCCESS) {
 711                        /* unlocks/locks space, so must start again */
 712
 713                        kr = ipc_entry_grow_table(space, ITS_SIZE_NONE);
 714                        if (kr != KERN_SUCCESS)
 715                                return kr; /* space is unlocked */
 716
 717                        continue;
 718                }
 719
 720                assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE);
 721                assert(entry->ie_object == IO_NULL);
 722
 723                io_lock(object);
 724                if (!io_active(object)) {
 725                        io_unlock(object);
 726                        ipc_entry_dealloc(space, name, entry);
 727                        is_write_unlock(space);
 728                        return KERN_INVALID_CAPABILITY;
 729                }
 730
 731                entry->ie_object = object;
 732                break;
 733        }
 734
 735        /* space is write-locked and active, object is locked and active */
 736
 737        kr = ipc_right_copyout(space, name, entry,
 738                               msgt_name, overflow, object);
 739        /* object is unlocked */
 740        is_write_unlock(space);
 741
 742        if (kr == KERN_SUCCESS)
 743                *namep = name;
 744        return kr;
 745}
 746
 747/*
 748 *      Routine:        ipc_object_copyout_name
 749 *      Purpose:
 750 *              Copyout a capability, placing it into a space.
 751 *              The specified name is used for the capability.
 752 *              If successful, consumes a ref for the object.
 753 *      Conditions:
 754 *              Nothing locked.
 755 *      Returns:
 756 *              KERN_SUCCESS            Copied out object, consumed ref.
 757 *              KERN_INVALID_TASK       The space is dead.
 758 *              KERN_INVALID_CAPABILITY The object is dead.
 759 *              KERN_RESOURCE_SHORTAGE  No memory available.
 760 *              KERN_UREFS_OVERFLOW     Urefs limit exceeded
 761 *                      and overflow wasn't specified.
 762 *              KERN_RIGHT_EXISTS       Space has rights under another name.
 763 *              KERN_NAME_EXISTS        Name is already used.
 764 */
 765
 766kern_return_t
 767ipc_object_copyout_name(
 768        ipc_space_t             space,
 769        ipc_object_t            object,
 770        mach_msg_type_name_t    msgt_name,
 771        boolean_t               overflow,
 772        mach_port_name_t        name)
 773{
 774        mach_port_name_t oname;
 775        ipc_entry_t oentry;
 776        ipc_entry_t entry;
 777        kern_return_t kr;
 778
 779        assert(IO_VALID(object));
 780        assert(io_otype(object) == IOT_PORT);
 781
 782        kr = ipc_entry_alloc_name(space, name, &entry);
 783        if (kr != KERN_SUCCESS)
 784                return kr;
 785        /* space is write-locked and active */
 786
 787        if ((msgt_name != MACH_MSG_TYPE_PORT_SEND_ONCE) &&
 788            ipc_right_reverse(space, object, &oname, &oentry)) {
 789                /* object is locked and active */
 790
 791                if (name != oname) {
 792                        io_unlock(object);
 793
 794                        if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE)
 795                                ipc_entry_dealloc(space, name, entry);
 796
 797                        is_write_unlock(space);
 798                        return KERN_RIGHT_EXISTS;
 799                }
 800
 801                assert(entry == oentry);
 802                assert(entry->ie_bits & MACH_PORT_TYPE_SEND_RECEIVE);
 803        } else {
 804                if (ipc_right_inuse(space, name, entry))
 805                        return KERN_NAME_EXISTS;
 806
 807                assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE);
 808                assert(entry->ie_object == IO_NULL);
 809
 810                io_lock(object);
 811                if (!io_active(object)) {
 812                        io_unlock(object);
 813                        ipc_entry_dealloc(space, name, entry);
 814                        is_write_unlock(space);
 815                        return KERN_INVALID_CAPABILITY;
 816                }
 817
 818                entry->ie_object = object;
 819        }
 820
 821        /* space is write-locked and active, object is locked and active */
 822
 823        kr = ipc_right_copyout(space, name, entry,
 824                               msgt_name, overflow, object);
 825        /* object is unlocked */
 826        is_write_unlock(space);
 827        return kr;
 828}
 829
 830/*
 831 *      Routine:        ipc_object_copyout_dest
 832 *      Purpose:
 833 *              Translates/consumes the destination right of a message.
 834 *              This is unlike normal copyout because the right is consumed
 835 *              in a funny way instead of being given to the receiving space.
 836 *              The receiver gets his name for the port, if he has receive
 837 *              rights, otherwise MACH_PORT_NULL.
 838 *      Conditions:
 839 *              The object is locked and active.  Nothing else locked.
 840 *              The object is unlocked and loses a reference.
 841 */
 842
 843void
 844ipc_object_copyout_dest(
 845        ipc_space_t             space,
 846        ipc_object_t            object,
 847        mach_msg_type_name_t    msgt_name,
 848        mach_port_name_t        *namep)
 849{
 850        mach_port_name_t name;
 851
 852        assert(IO_VALID(object));
 853        assert(io_active(object));
 854
 855        io_release(object);
 856
 857        /*
 858         *      If the space is the receiver/owner of the object,
 859         *      then we quietly consume the right and return
 860         *      the space's name for the object.  Otherwise
 861         *      we destroy the right and return MACH_PORT_NULL.
 862         */
 863
 864        switch (msgt_name) {
 865            case MACH_MSG_TYPE_PORT_SEND: {
 866                ipc_port_t port = (ipc_port_t) object;
 867                ipc_port_t nsrequest = IP_NULL;
 868                mach_port_mscount_t mscount;
 869
 870                if (port->ip_receiver == space)
 871                        name = port->ip_receiver_name;
 872                else
 873                        name = MACH_PORT_NULL;
 874
 875                assert(port->ip_srights > 0);
 876                if (--port->ip_srights == 0 &&
 877                    port->ip_nsrequest != IP_NULL) {
 878                        nsrequest = port->ip_nsrequest;
 879                        port->ip_nsrequest = IP_NULL;
 880                        mscount = port->ip_mscount;
 881                        ip_unlock(port);
 882                        ipc_notify_no_senders(nsrequest, mscount);
 883                } else
 884                        ip_unlock(port);
 885                break;
 886            }
 887
 888            case MACH_MSG_TYPE_PORT_SEND_ONCE: {
 889                ipc_port_t port = (ipc_port_t) object;
 890
 891                assert(port->ip_sorights > 0);
 892
 893                if (port->ip_receiver == space) {
 894                        /* quietly consume the send-once right */
 895
 896                        port->ip_sorights--;
 897                        name = port->ip_receiver_name;
 898                        ip_unlock(port);
 899                } else {
 900                        /*
 901                         *      A very bizarre case.  The message
 902                         *      was received, but before this copyout
 903                         *      happened the space lost receive rights.
 904                         *      We can't quietly consume the soright
 905                         *      out from underneath some other task,
 906                         *      so generate a send-once notification.
 907                         */
 908
 909                        ip_reference(port); /* restore ref */
 910                        ip_unlock(port);
 911
 912                        ipc_notify_send_once(port);
 913                        name = MACH_PORT_NULL;
 914                }
 915
 916                break;
 917            }
 918
 919            default:
 920                panic("ipc_object_copyout_dest: strange rights");
 921                name = MACH_PORT_DEAD;
 922        }
 923
 924        *namep = name;
 925}
 926
 927/*
 928 *      Routine:        ipc_object_rename
 929 *      Purpose:
 930 *              Rename an entry in a space.
 931 *      Conditions:
 932 *              Nothing locked.
 933 *      Returns:
 934 *              KERN_SUCCESS            Renamed the entry.
 935 *              KERN_INVALID_TASK       The space was dead.
 936 *              KERN_INVALID_NAME       oname didn't denote an entry.
 937 *              KERN_NAME_EXISTS        nname already denoted an entry.
 938 *              KERN_RESOURCE_SHORTAGE  Couldn't allocate new entry.
 939 */
 940
 941kern_return_t
 942ipc_object_rename(
 943        ipc_space_t             space,
 944        mach_port_name_t        oname,
 945        mach_port_name_t        nname)
 946{
 947        ipc_entry_t oentry, nentry;
 948        kern_return_t kr;
 949        
 950        kr = ipc_entry_alloc_name(space, nname, &nentry);
 951        if (kr != KERN_SUCCESS)
 952                return kr;
 953
 954        /* space is write-locked and active */
 955
 956        if (ipc_right_inuse(space, nname, nentry)) {
 957                /* space is unlocked */
 958                return KERN_NAME_EXISTS;
 959        }
 960
 961        /* don't let ipc_entry_lookup see the uninitialized new entry */
 962
 963        if ((oname == nname) ||
 964            ((oentry = ipc_entry_lookup(space, oname)) == IE_NULL)) {
 965                ipc_entry_dealloc(space, nname, nentry);
 966                is_write_unlock(space);
 967                return KERN_INVALID_NAME;
 968        }
 969
 970        kr = ipc_right_rename(space, oname, oentry, nname, nentry);
 971        /* space is unlocked */
 972        return kr;
 973}
 974
 975#if     MACH_ASSERT
 976/*
 977 *      Check whether the object is a port if so, free it.  But
 978 *      keep track of that fact.
 979 */
 980void
 981io_free(
 982        unsigned int    otype,
 983        ipc_object_t    object)
 984{
 985        ipc_port_t      port;
 986
 987        if (otype == IOT_PORT) {
 988                port = (ipc_port_t) object;
 989#if     MACH_ASSERT
 990                ipc_port_track_dealloc(port);
 991#endif  /* MACH_ASSERT */
 992        }
 993        zfree(ipc_object_zones[otype], object);
 994}
 995#endif  /* MACH_ASSERT */
 996
 997#include <mach_kdb.h>
 998#if     MACH_KDB
 999
1000#include <ddb/db_output.h>
1001#include <kern/ipc_kobject.h>
1002
1003#define printf  kdbprintf 
1004
1005/*
1006 *      Routine:        ipc_object_print
1007 *      Purpose:
1008 *              Pretty-print an object for kdb.
1009 */
1010
1011const char *ikot_print_array[IKOT_MAX_TYPE] = {
1012        "(NONE)             ",
1013        "(THREAD)           ",
1014        "(TASK)             ",
1015        "(HOST)             ",
1016        "(HOST_PRIV)        ",
1017        "(PROCESSOR)        ",
1018        "(PSET)             ",
1019        "(PSET_NAME)        ",
1020        "(TIMER)            ",
1021        "(PAGER_REQUEST)    ",
1022        "(DEVICE)           ",  /* 10 */
1023        "(XMM_OBJECT)       ",
1024        "(XMM_PAGER)        ",
1025        "(XMM_KERNEL)       ",
1026        "(XMM_REPLY)        ",
1027        "(NOTDEF 15)        ",
1028        "(NOTDEF 16)        ",
1029        "(HOST_SECURITY)    ",
1030        "(LEDGER)           ",
1031        "(MASTER_DEVICE)    ",
1032        "(ACTIVATION)       ",  /* 20 */
1033        "(SUBSYSTEM)        ",
1034        "(IO_DONE_QUEUE)    ",
1035        "(SEMAPHORE)        ",
1036        "(LOCK_SET)         ",
1037        "(CLOCK)            ",
1038        "(CLOCK_CTRL)       ",  /* 26 */
1039        "(IOKIT_SPARE)      ",  /* 27 */
1040        "(NAMED_MEM_ENTRY)  ",  /* 28 */
1041        "(IOKIT_CONNECT)    ",
1042        "(IOKIT_OBJECT)     ",  /* 30 */
1043        "(UPL)              ",
1044                                                /* << new entries here  */
1045        "(UNKNOWN)          "   /* magic catchall       */
1046};
1047/* Please keep in sync with kern/ipc_kobject.h  */
1048
1049void
1050ipc_object_print(
1051        ipc_object_t    object)
1052{
1053        int kotype;
1054
1055        iprintf("%s", io_active(object) ? "active" : "dead");
1056        printf(", refs=%d", object->io_references);
1057        printf(", otype=%d", io_otype(object));
1058        kotype = io_kotype(object);
1059        if (kotype >= 0 && kotype < IKOT_MAX_TYPE)
1060                printf(", kotype=%d %s\n", io_kotype(object),
1061                       ikot_print_array[kotype]);
1062        else
1063                printf(", kotype=0x%x %s\n", io_kotype(object),
1064                       ikot_print_array[IKOT_UNKNOWN]);
1065}
1066
1067#endif  /* MACH_KDB */
1068
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.