The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/ipc/ipc_object.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /* 
    2  * Mach Operating System
    3  * Copyright (c) 1991,1990,1989 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  Software.Distribution@CS.CMU.EDU
   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  * HISTORY
   28  * $Log:        ipc_object.c,v $
   29  * Revision 2.9  93/02/01  09:54:52  danner
   30  *      return 0 in ipc_object_copyin_type if panic/assert returns.
   31  *      [93/01/25            jfriedl]
   32  * 
   33  * Revision 2.8  92/08/03  17:34:59  jfriedl
   34  *      removed silly prototypes
   35  *      [92/08/02            jfriedl]
   36  * 
   37  * Revision 2.7  92/05/21  17:10:59  jfriedl
   38  *      Fixed for when assert() is a nop and to quiet gcc warnings.
   39  *      [92/05/16            jfriedl]
   40  * 
   41  * Revision 2.6  92/03/10  16:26:07  jsb
   42  *      Made ipc_object_print look nicer.
   43  *      [92/03/09  13:21:38  jsb]
   44  * 
   45  * Revision 2.5  91/05/14  16:34:52  mrt
   46  *      Correcting copyright
   47  * 
   48  * Revision 2.4  91/02/05  17:22:44  mrt
   49  *      Changed to new Mach copyright
   50  *      [91/02/01  15:49:10  mrt]
   51  * 
   52  * Revision 2.3  90/11/05  14:29:11  rpd
   53  *      Removed ipc_object_reference_macro, ipc_object_release_macro.
   54  *      Use new io_reference and io_release.
   55  *      Use new ip_reference and ip_release.
   56  *      [90/10/29            rpd]
   57  * 
   58  * Revision 2.2  90/06/02  14:50:59  rpd
   59  *      Created for new IPC.
   60  *      [90/03/26  20:58:32  rpd]
   61  * 
   62  */
   63 /*
   64  *      File:   ipc/ipc_object.c
   65  *      Author: Rich Draves
   66  *      Date:   1989
   67  *
   68  *      Functions to manipulate IPC objects.
   69  */
   70 
   71 #include <mach_ipc_compat.h>
   72 
   73 #include <mach/boolean.h>
   74 #include <mach/kern_return.h>
   75 #include <mach/port.h>
   76 #include <mach/message.h>
   77 #include <ipc/port.h>
   78 #include <ipc/ipc_space.h>
   79 #include <ipc/ipc_entry.h>
   80 #include <ipc/ipc_object.h>
   81 #include <ipc/ipc_hash.h>
   82 #include <ipc/ipc_right.h>
   83 #include <ipc/ipc_notify.h>
   84 
   85 zone_t ipc_object_zones[IOT_NUMBER];
   86 
   87 
   88 
   89 /*
   90  *      Routine:        ipc_object_reference
   91  *      Purpose:
   92  *              Take a reference to an object.
   93  */
   94 
   95 void
   96 ipc_object_reference(object)
   97         ipc_object_t object;
   98 {
   99         io_lock(object);
  100         assert(object->io_references > 0);
  101         io_reference(object);
  102         io_unlock(object);
  103 }
  104 
  105 /*
  106  *      Routine:        ipc_object_release
  107  *      Purpose:
  108  *              Release a reference to an object.
  109  */
  110 
  111 void
  112 ipc_object_release(object)
  113         ipc_object_t object;
  114 {
  115         io_lock(object);
  116         assert(object->io_references > 0);
  117         io_release(object);
  118         io_check_unlock(object);
  119 }
  120 
  121 /*
  122  *      Routine:        ipc_object_translate
  123  *      Purpose:
  124  *              Look up an object in a space.
  125  *      Conditions:
  126  *              Nothing locked before.  If successful, the object
  127  *              is returned locked.  The caller doesn't get a ref.
  128  *      Returns:
  129  *              KERN_SUCCESS            Objected returned locked.
  130  *              KERN_INVALID_TASK       The space is dead.
  131  *              KERN_INVALID_NAME       The name doesn't denote a right.
  132  *              KERN_INVALID_RIGHT      Name doesn't denote the correct right.
  133  */
  134 
  135 kern_return_t
  136 ipc_object_translate(space, name, right, objectp)
  137         ipc_space_t space;
  138         mach_port_t name;
  139         mach_port_right_t right;
  140         ipc_object_t *objectp;
  141 {
  142         ipc_entry_t entry;
  143         ipc_object_t object;
  144         kern_return_t kr;
  145 
  146         kr = ipc_right_lookup_read(space, name, &entry);
  147         if (kr != KERN_SUCCESS)
  148                 return kr;
  149         /* space is read-locked and active */
  150 
  151         if ((entry->ie_bits & MACH_PORT_TYPE(right)) == 0) {
  152                 is_read_unlock(space);
  153                 return KERN_INVALID_RIGHT;
  154         }
  155 
  156         object = entry->ie_object;
  157         assert(object != IO_NULL);
  158 
  159         io_lock(object);
  160         is_read_unlock(space);
  161 
  162         *objectp = object;
  163         return KERN_SUCCESS;
  164 }
  165 
  166 /*
  167  *      Routine:        ipc_object_alloc_dead
  168  *      Purpose:
  169  *              Allocate a dead-name entry.
  170  *      Conditions:
  171  *              Nothing locked.
  172  *      Returns:
  173  *              KERN_SUCCESS            The dead name is allocated.
  174  *              KERN_INVALID_TASK       The space is dead.
  175  *              KERN_NO_SPACE           No room for an entry in the space.
  176  *              KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
  177  */
  178 
  179 kern_return_t
  180 ipc_object_alloc_dead(space, namep)
  181         ipc_space_t space;
  182         mach_port_t *namep;
  183 {
  184         ipc_entry_t entry;
  185         kern_return_t kr;
  186 
  187         kr = ipc_entry_alloc(space, namep, &entry);
  188         if (kr != KERN_SUCCESS)
  189                 return kr;
  190         /* space is write-locked */
  191 
  192         /* null object, MACH_PORT_TYPE_DEAD_NAME, 1 uref */
  193 
  194         assert(entry->ie_object == IO_NULL);
  195         entry->ie_bits |= MACH_PORT_TYPE_DEAD_NAME | 1;
  196 
  197         is_write_unlock(space);
  198         return KERN_SUCCESS;
  199 }
  200 
  201 /*
  202  *      Routine:        ipc_object_alloc_dead_name
  203  *      Purpose:
  204  *              Allocate a dead-name entry, with a specific name.
  205  *      Conditions:
  206  *              Nothing locked.
  207  *      Returns:
  208  *              KERN_SUCCESS            The dead name is allocated.
  209  *              KERN_INVALID_TASK       The space is dead.
  210  *              KERN_NAME_EXISTS        The name already denotes a right.
  211  *              KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
  212  */
  213 
  214 kern_return_t
  215 ipc_object_alloc_dead_name(space, name)
  216         ipc_space_t space;
  217         mach_port_t name;
  218 {
  219         ipc_entry_t entry;
  220         kern_return_t kr;
  221 
  222         kr = ipc_entry_alloc_name(space, name, &entry);
  223         if (kr != KERN_SUCCESS)
  224                 return kr;
  225         /* space is write-locked */
  226 
  227         if (ipc_right_inuse(space, name, entry))
  228                 return KERN_NAME_EXISTS;
  229 
  230         /* null object, MACH_PORT_TYPE_DEAD_NAME, 1 uref */
  231 
  232         assert(entry->ie_object == IO_NULL);
  233         entry->ie_bits |= MACH_PORT_TYPE_DEAD_NAME | 1;
  234 
  235         is_write_unlock(space);
  236         return KERN_SUCCESS;
  237 }
  238 
  239 /*
  240  *      Routine:        ipc_object_alloc
  241  *      Purpose:
  242  *              Allocate an object.
  243  *      Conditions:
  244  *              Nothing locked.  If successful, the object is returned locked.
  245  *              The caller doesn't get a reference for the object.
  246  *      Returns:
  247  *              KERN_SUCCESS            The object is allocated.
  248  *              KERN_INVALID_TASK       The space is dead.
  249  *              KERN_NO_SPACE           No room for an entry in the space.
  250  *              KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
  251  */
  252 
  253 kern_return_t
  254 ipc_object_alloc(space, otype, type, urefs, namep, objectp)
  255         ipc_space_t space;
  256         ipc_object_type_t otype;
  257         mach_port_type_t type;
  258         mach_port_urefs_t urefs;
  259         mach_port_t *namep;
  260         ipc_object_t *objectp;
  261 {
  262         ipc_object_t object;
  263         ipc_entry_t entry;
  264         kern_return_t kr;
  265 
  266         assert(otype < IOT_NUMBER);
  267         assert((type & MACH_PORT_TYPE_ALL_RIGHTS) == type);
  268         assert(type != MACH_PORT_TYPE_NONE);
  269         assert(urefs <= MACH_PORT_UREFS_MAX);
  270 
  271         object = io_alloc(otype);
  272         if (object == IO_NULL)
  273                 return KERN_RESOURCE_SHORTAGE;
  274 
  275         kr = ipc_entry_alloc(space, namep, &entry);
  276         if (kr != KERN_SUCCESS) {
  277                 io_free(otype, object);
  278                 return kr;
  279         }
  280         /* space is write-locked */
  281 
  282         entry->ie_bits |= type | urefs;
  283         entry->ie_object = object;
  284 
  285         io_lock_init(object);
  286         io_lock(object);
  287         is_write_unlock(space);
  288 
  289         object->io_references = 1; /* for entry, not caller */
  290         object->io_bits = io_makebits(TRUE, otype, 0);
  291 
  292         *objectp = object;
  293         return KERN_SUCCESS;
  294 }
  295 
  296 /*
  297  *      Routine:        ipc_object_alloc_name
  298  *      Purpose:
  299  *              Allocate an object, with a specific name.
  300  *      Conditions:
  301  *              Nothing locked.  If successful, the object is returned locked.
  302  *              The caller doesn't get a reference for the object.
  303  *      Returns:
  304  *              KERN_SUCCESS            The object is allocated.
  305  *              KERN_INVALID_TASK       The space is dead.
  306  *              KERN_NAME_EXISTS        The name already denotes a right.
  307  *              KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
  308  */
  309 
  310 kern_return_t
  311 ipc_object_alloc_name(space, otype, type, urefs, name, objectp)
  312         ipc_space_t space;
  313         ipc_object_type_t otype;
  314         mach_port_type_t type;
  315         mach_port_urefs_t urefs;
  316         mach_port_t name;
  317         ipc_object_t *objectp;
  318 {
  319         ipc_object_t object;
  320         ipc_entry_t entry;
  321         kern_return_t kr;
  322 
  323         assert(otype < IOT_NUMBER);
  324         assert((type & MACH_PORT_TYPE_ALL_RIGHTS) == type);
  325         assert(type != MACH_PORT_TYPE_NONE);
  326         assert(urefs <= MACH_PORT_UREFS_MAX);
  327 
  328         object = io_alloc(otype);
  329         if (object == IO_NULL)
  330                 return KERN_RESOURCE_SHORTAGE;
  331 
  332         kr = ipc_entry_alloc_name(space, name, &entry);
  333         if (kr != KERN_SUCCESS) {
  334                 io_free(otype, object);
  335                 return kr;
  336         }
  337         /* space is write-locked */
  338 
  339         if (ipc_right_inuse(space, name, entry)) {
  340                 io_free(otype, object);
  341                 return KERN_NAME_EXISTS;
  342         }
  343 
  344         entry->ie_bits |= type | urefs;
  345         entry->ie_object = object;
  346 
  347         io_lock_init(object);
  348         io_lock(object);
  349         is_write_unlock(space);
  350 
  351         object->io_references = 1; /* for entry, not caller */
  352         object->io_bits = io_makebits(TRUE, otype, 0);
  353 
  354         *objectp = object;
  355         return KERN_SUCCESS;
  356 }
  357 
  358 /*
  359  *      Routine:        ipc_object_copyin_type
  360  *      Purpose:
  361  *              Convert a send type name to a received type name.
  362  */
  363 mach_msg_type_name_t
  364 ipc_object_copyin_type(msgt_name)
  365         mach_msg_type_name_t msgt_name;
  366 {
  367         switch (msgt_name) {
  368             case 0:
  369                 return 0;
  370 
  371             case MACH_MSG_TYPE_MOVE_RECEIVE:
  372                 return MACH_MSG_TYPE_PORT_RECEIVE;
  373 
  374             case MACH_MSG_TYPE_MOVE_SEND_ONCE:
  375             case MACH_MSG_TYPE_MAKE_SEND_ONCE:
  376                 return MACH_MSG_TYPE_PORT_SEND_ONCE;
  377 
  378             case MACH_MSG_TYPE_MOVE_SEND:
  379             case MACH_MSG_TYPE_MAKE_SEND:
  380             case MACH_MSG_TYPE_COPY_SEND:
  381                 return MACH_MSG_TYPE_PORT_SEND;
  382 
  383 #if     MACH_IPC_COMPAT
  384             case MSG_TYPE_PORT:
  385                 return MACH_MSG_TYPE_PORT_SEND;
  386 
  387             case MSG_TYPE_PORT_ALL:
  388                 return MACH_MSG_TYPE_PORT_RECEIVE;
  389 #endif  MACH_IPC_COMPAT
  390 
  391             default:
  392 #if MACH_ASSERT
  393                 assert(!"ipc_object_copyin_type: strange rights");
  394 #else
  395                 panic("ipc_object_copyin_type: strange rights");
  396 #endif
  397                 return 0; /* in case assert/panic returns */
  398         }
  399 }
  400 
  401 /*
  402  *      Routine:        ipc_object_copyin
  403  *      Purpose:
  404  *              Copyin a capability from a space.
  405  *              If successful, the caller gets a ref
  406  *              for the resulting object, unless it is IO_DEAD.
  407  *      Conditions:
  408  *              Nothing locked.
  409  *      Returns:
  410  *              KERN_SUCCESS            Acquired an object, possibly IO_DEAD.
  411  *              KERN_INVALID_TASK       The space is dead.
  412  *              KERN_INVALID_NAME       Name doesn't exist in space.
  413  *              KERN_INVALID_RIGHT      Name doesn't denote correct right.
  414  */
  415 
  416 kern_return_t
  417 ipc_object_copyin(space, name, msgt_name, objectp)
  418         ipc_space_t space;
  419         mach_port_t name;
  420         mach_msg_type_name_t msgt_name;
  421         ipc_object_t *objectp;
  422 {
  423         ipc_entry_t entry;
  424         ipc_port_t soright;
  425         kern_return_t kr;
  426 
  427         /*
  428          *      Could first try a read lock when doing
  429          *      MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND,
  430          *      and MACH_MSG_TYPE_MAKE_SEND_ONCE.
  431          */
  432 
  433         kr = ipc_right_lookup_write(space, name, &entry);
  434         if (kr != KERN_SUCCESS)
  435                 return kr;
  436         /* space is write-locked and active */
  437 
  438         kr = ipc_right_copyin(space, name, entry,
  439                               msgt_name, TRUE,
  440                               objectp, &soright);
  441         if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE)
  442                 ipc_entry_dealloc(space, name, entry);
  443         is_write_unlock(space);
  444 
  445         if ((kr == KERN_SUCCESS) && (soright != IP_NULL))
  446                 ipc_notify_port_deleted(soright, name);
  447 
  448         return kr;
  449 }
  450 
  451 /*
  452  *      Routine:        ipc_object_copyin_from_kernel
  453  *      Purpose:
  454  *              Copyin a naked capability from the kernel.
  455  *
  456  *              MACH_MSG_TYPE_MOVE_RECEIVE
  457  *                      The receiver must be ipc_space_kernel.
  458  *                      Consumes the naked receive right.
  459  *              MACH_MSG_TYPE_COPY_SEND
  460  *                      A naked send right must be supplied.
  461  *                      The port gains a reference, and a send right
  462  *                      if the port is still active.
  463  *              MACH_MSG_TYPE_MAKE_SEND
  464  *                      The receiver must be ipc_space_kernel.
  465  *                      The port gains a reference and a send right.
  466  *              MACH_MSG_TYPE_MOVE_SEND
  467  *                      Consumes a naked send right.
  468  *              MACH_MSG_TYPE_MAKE_SEND_ONCE
  469  *                      The receiver must be ipc_space_kernel.
  470  *                      The port gains a reference and a send-once right.
  471  *              MACH_MSG_TYPE_MOVE_SEND_ONCE
  472  *                      Consumes a naked send-once right.
  473  *      Conditions:
  474  *              Nothing locked.
  475  */
  476 
  477 void
  478 ipc_object_copyin_from_kernel(object, msgt_name)
  479         ipc_object_t object;
  480         mach_msg_type_name_t msgt_name;
  481 {
  482         assert(IO_VALID(object));
  483 
  484         switch (msgt_name) {
  485             case MACH_MSG_TYPE_MOVE_RECEIVE: {
  486                 ipc_port_t port = (ipc_port_t) object;
  487 
  488                 ip_lock(port);
  489                 assert(ip_active(port));
  490                 assert(port->ip_receiver_name != MACH_PORT_NULL);
  491                 assert(port->ip_receiver == ipc_space_kernel);
  492 
  493                 /* relevant part of ipc_port_clear_receiver */
  494                 ipc_port_set_mscount(port, 0);
  495 
  496                 port->ip_receiver_name = MACH_PORT_NULL;
  497                 port->ip_destination = IP_NULL;
  498                 ip_unlock(port);
  499                 break;
  500             }
  501 
  502             case MACH_MSG_TYPE_COPY_SEND: {
  503                 ipc_port_t port = (ipc_port_t) object;
  504 
  505                 ip_lock(port);
  506                 if (ip_active(port)) {
  507                         assert(port->ip_srights > 0);
  508                         port->ip_srights++;
  509                 }
  510                 ip_reference(port);
  511                 ip_unlock(port);
  512                 break;
  513             }
  514 
  515             case MACH_MSG_TYPE_MAKE_SEND: {
  516                 ipc_port_t port = (ipc_port_t) object;
  517 
  518                 ip_lock(port);
  519                 assert(ip_active(port));
  520                 assert(port->ip_receiver_name != MACH_PORT_NULL);
  521                 assert(port->ip_receiver == ipc_space_kernel);
  522 
  523                 ip_reference(port);
  524                 port->ip_mscount++;
  525                 port->ip_srights++;
  526                 ip_unlock(port);
  527                 break;
  528             }
  529 
  530             case MACH_MSG_TYPE_MOVE_SEND:
  531                 /* move naked send right into the message */
  532                 break;
  533 
  534             case MACH_MSG_TYPE_MAKE_SEND_ONCE: {
  535                 ipc_port_t port = (ipc_port_t) object;
  536 
  537                 ip_lock(port);
  538                 assert(ip_active(port));
  539                 assert(port->ip_receiver_name != MACH_PORT_NULL);
  540                 assert(port->ip_receiver == ipc_space_kernel);
  541 
  542                 ip_reference(port);
  543                 port->ip_sorights++;
  544                 ip_unlock(port);
  545                 break;
  546             }
  547 
  548             case MACH_MSG_TYPE_MOVE_SEND_ONCE:
  549                 /* move naked send-once right into the message */
  550                 break;
  551 
  552             default:
  553 #if MACH_ASSERT
  554                 assert(!"ipc_object_copyin_from_kernel: strange rights");
  555 #else
  556                 panic("ipc_object_copyin_from_kernel: strange rights");
  557 #endif
  558         }
  559 }
  560 
  561 /*
  562  *      Routine:        ipc_object_destroy
  563  *      Purpose:
  564  *              Destroys a naked capability.
  565  *              Consumes a ref for the object.
  566  *
  567  *              A receive right should be in limbo or in transit.
  568  *      Conditions:
  569  *              Nothing locked.
  570  */
  571 
  572 void
  573 ipc_object_destroy(object, msgt_name)
  574         ipc_object_t object;
  575         mach_msg_type_name_t msgt_name;
  576 {
  577         assert(IO_VALID(object));
  578 
  579         switch (msgt_name) {
  580             case MACH_MSG_TYPE_PORT_SEND:
  581                 assert(io_otype(object) == IOT_PORT);
  582                 ipc_port_release_send((ipc_port_t) object);
  583                 break;
  584 
  585             case MACH_MSG_TYPE_PORT_SEND_ONCE:
  586                 assert(io_otype(object) == IOT_PORT);
  587                 ipc_notify_send_once((ipc_port_t) object);
  588                 break;
  589 
  590             case MACH_MSG_TYPE_PORT_RECEIVE:
  591                 assert(io_otype(object) == IOT_PORT);
  592                 ipc_port_release_receive((ipc_port_t) object);
  593                 break;
  594 
  595             default:
  596                 assert(!"ipc_object_destroy: strange rights");
  597         }
  598 }
  599 
  600 /*
  601  *      Routine:        ipc_object_copyout
  602  *      Purpose:
  603  *              Copyout a capability, placing it into a space.
  604  *              If successful, consumes a ref for the object.
  605  *      Conditions:
  606  *              Nothing locked.
  607  *      Returns:
  608  *              KERN_SUCCESS            Copied out object, consumed ref.
  609  *              KERN_INVALID_TASK       The space is dead.
  610  *              KERN_INVALID_CAPABILITY The object is dead.
  611  *              KERN_NO_SPACE           No room in space for another right.
  612  *              KERN_RESOURCE_SHORTAGE  No memory available.
  613  *              KERN_UREFS_OVERFLOW     Urefs limit exceeded
  614  *                      and overflow wasn't specified.
  615  */
  616 
  617 kern_return_t
  618 ipc_object_copyout(space, object, msgt_name, overflow, namep)
  619         ipc_space_t space;
  620         ipc_object_t object;
  621         mach_msg_type_name_t msgt_name;
  622         boolean_t overflow;
  623         mach_port_t *namep;
  624 {
  625         mach_port_t name;
  626         ipc_entry_t entry;
  627         kern_return_t kr;
  628 
  629         assert(IO_VALID(object));
  630         assert(io_otype(object) == IOT_PORT);
  631 
  632         is_write_lock(space);
  633 
  634         for (;;) {
  635                 if (!space->is_active) {
  636                         is_write_unlock(space);
  637                         return KERN_INVALID_TASK;
  638                 }
  639 
  640                 if ((msgt_name != MACH_MSG_TYPE_PORT_SEND_ONCE) &&
  641                     ipc_right_reverse(space, object, &name, &entry)) {
  642                         /* object is locked and active */
  643 
  644                         assert(entry->ie_bits & MACH_PORT_TYPE_SEND_RECEIVE);
  645                         break;
  646                 }
  647 
  648                 kr = ipc_entry_get(space, &name, &entry);
  649                 if (kr != KERN_SUCCESS) {
  650                         /* unlocks/locks space, so must start again */
  651 
  652                         kr = ipc_entry_grow_table(space);
  653                         if (kr != KERN_SUCCESS)
  654                                 return kr; /* space is unlocked */
  655 
  656                         continue;
  657                 }
  658 
  659                 assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE);
  660                 assert(entry->ie_object == IO_NULL);
  661 
  662                 io_lock(object);
  663                 if (!io_active(object)) {
  664                         io_unlock(object);
  665                         ipc_entry_dealloc(space, name, entry);
  666                         is_write_unlock(space);
  667                         return KERN_INVALID_CAPABILITY;
  668                 }
  669 
  670                 entry->ie_object = object;
  671                 break;
  672         }
  673 
  674         /* space is write-locked and active, object is locked and active */
  675 
  676         kr = ipc_right_copyout(space, name, entry,
  677                                msgt_name, overflow, object);
  678         /* object is unlocked */
  679         is_write_unlock(space);
  680 
  681         if (kr == KERN_SUCCESS)
  682                 *namep = name;
  683         return kr;
  684 }
  685 
  686 /*
  687  *      Routine:        ipc_object_copyout_name
  688  *      Purpose:
  689  *              Copyout a capability, placing it into a space.
  690  *              The specified name is used for the capability.
  691  *              If successful, consumes a ref for the object.
  692  *      Conditions:
  693  *              Nothing locked.
  694  *      Returns:
  695  *              KERN_SUCCESS            Copied out object, consumed ref.
  696  *              KERN_INVALID_TASK       The space is dead.
  697  *              KERN_INVALID_CAPABILITY The object is dead.
  698  *              KERN_RESOURCE_SHORTAGE  No memory available.
  699  *              KERN_UREFS_OVERFLOW     Urefs limit exceeded
  700  *                      and overflow wasn't specified.
  701  *              KERN_RIGHT_EXISTS       Space has rights under another name.
  702  *              KERN_NAME_EXISTS        Name is already used.
  703  */
  704 
  705 kern_return_t
  706 ipc_object_copyout_name(space, object, msgt_name, overflow, name)
  707         ipc_space_t space;
  708         ipc_object_t object;
  709         mach_msg_type_name_t msgt_name;
  710         boolean_t overflow;
  711         mach_port_t name;
  712 {
  713         mach_port_t oname;
  714         ipc_entry_t oentry;
  715         ipc_entry_t entry;
  716         kern_return_t kr;
  717 
  718         assert(IO_VALID(object));
  719         assert(io_otype(object) == IOT_PORT);
  720 
  721         kr = ipc_entry_alloc_name(space, name, &entry);
  722         if (kr != KERN_SUCCESS)
  723                 return kr;
  724         /* space is write-locked and active */
  725 
  726         if ((msgt_name != MACH_MSG_TYPE_PORT_SEND_ONCE) &&
  727             ipc_right_reverse(space, object, &oname, &oentry)) {
  728                 /* object is locked and active */
  729 
  730                 if (name != oname) {
  731                         io_unlock(object);
  732 
  733                         if (IE_BITS_TYPE(entry->ie_bits)
  734                                                 == MACH_PORT_TYPE_NONE)
  735                                 ipc_entry_dealloc(space, name, entry);
  736 
  737                         is_write_unlock(space);
  738                         return KERN_RIGHT_EXISTS;
  739                 }
  740 
  741                 assert(entry == oentry);
  742                 assert(entry->ie_bits & MACH_PORT_TYPE_SEND_RECEIVE);
  743         } else {
  744                 if (ipc_right_inuse(space, name, entry))
  745                         return KERN_NAME_EXISTS;
  746 
  747                 assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE);
  748                 assert(entry->ie_object == IO_NULL);
  749 
  750                 io_lock(object);
  751                 if (!io_active(object)) {
  752                         io_unlock(object);
  753                         ipc_entry_dealloc(space, name, entry);
  754                         is_write_unlock(space);
  755                         return KERN_INVALID_CAPABILITY;
  756                 }
  757 
  758                 entry->ie_object = object;
  759         }
  760 
  761         /* space is write-locked and active, object is locked and active */
  762 
  763         kr = ipc_right_copyout(space, name, entry,
  764                                msgt_name, overflow, object);
  765         /* object is unlocked */
  766         is_write_unlock(space);
  767         return kr;
  768 }
  769 
  770 /*
  771  *      Routine:        ipc_object_copyout_dest
  772  *      Purpose:
  773  *              Translates/consumes the destination right of a message.
  774  *              This is unlike normal copyout because the right is consumed
  775  *              in a funny way instead of being given to the receiving space.
  776  *              The receiver gets his name for the port, if he has receive
  777  *              rights, otherwise MACH_PORT_NULL.
  778  *      Conditions:
  779  *              The object is locked and active.  Nothing else locked.
  780  *              The object is unlocked and loses a reference.
  781  */
  782 
  783 void
  784 ipc_object_copyout_dest(space, object, msgt_name, namep)
  785         ipc_space_t space;
  786         ipc_object_t object;
  787         mach_msg_type_name_t msgt_name;
  788         mach_port_t *namep;
  789 {
  790         mach_port_t name = MACH_PORT_NULL; /* '=MACH_PORT_NULL' to quiet lint*/
  791 
  792         assert(IO_VALID(object));
  793         assert(io_active(object));
  794 
  795         io_release(object);
  796 
  797         /*
  798          *      If the space is the receiver/owner of the object,
  799          *      then we quietly consume the right and return
  800          *      the space's name for the object.  Otherwise
  801          *      we destroy the right and return MACH_PORT_NULL.
  802          */
  803 
  804         switch (msgt_name) {
  805             case MACH_MSG_TYPE_PORT_SEND: {
  806                 ipc_port_t port = (ipc_port_t) object;
  807                 ipc_port_t nsrequest = IP_NULL;
  808                 mach_port_mscount_t mscount = 0; /* '=0' to shut up lint */
  809 
  810                 assert(port->ip_srights > 0);
  811                 if (--port->ip_srights == 0) {
  812                         nsrequest = port->ip_nsrequest;
  813                         if (nsrequest != IP_NULL) {
  814                                 port->ip_nsrequest = IP_NULL;
  815                                 mscount = port->ip_mscount;
  816                         }
  817                 }
  818 
  819                 if (port->ip_receiver == space)
  820                         name = port->ip_receiver_name;
  821                 else
  822                         name = MACH_PORT_NULL;
  823 
  824                 ip_unlock(port);
  825 
  826                 if (nsrequest != IP_NULL)
  827                         ipc_notify_no_senders(nsrequest, mscount);
  828 
  829                 break;
  830             }
  831 
  832             case MACH_MSG_TYPE_PORT_SEND_ONCE: {
  833                 ipc_port_t port = (ipc_port_t) object;
  834 
  835                 assert(port->ip_sorights > 0);
  836 
  837                 if (port->ip_receiver == space) {
  838                         /* quietly consume the send-once right */
  839 
  840                         port->ip_sorights--;
  841                         name = port->ip_receiver_name;
  842                         ip_unlock(port);
  843                 } else {
  844                         /*
  845                          *      A very bizarre case.  The message
  846                          *      was received, but before this copyout
  847                          *      happened the space lost receive rights.
  848                          *      We can't quietly consume the soright
  849                          *      out from underneath some other task,
  850                          *      so generate a send-once notification.
  851                          */
  852 
  853                         ip_reference(port); /* restore ref */
  854                         ip_unlock(port);
  855 
  856                         ipc_notify_send_once(port);
  857                         name = MACH_PORT_NULL;
  858                 }
  859 
  860                 break;
  861             }
  862 
  863             default:
  864 #if MACH_ASSERT
  865                 assert(!"ipc_object_copyout_dest: strange rights");
  866 #else
  867                 panic("ipc_object_copyout_dest: strange rights");
  868 #endif
  869 
  870         }
  871 
  872         *namep = name;
  873 }
  874 
  875 /*
  876  *      Routine:        ipc_object_rename
  877  *      Purpose:
  878  *              Rename an entry in a space.
  879  *      Conditions:
  880  *              Nothing locked.
  881  *      Returns:
  882  *              KERN_SUCCESS            Renamed the entry.
  883  *              KERN_INVALID_TASK       The space was dead.
  884  *              KERN_INVALID_NAME       oname didn't denote an entry.
  885  *              KERN_NAME_EXISTS        nname already denoted an entry.
  886  *              KERN_RESOURCE_SHORTAGE  Couldn't allocate new entry.
  887  */
  888 
  889 kern_return_t
  890 ipc_object_rename(space, oname, nname)
  891         ipc_space_t space;
  892         mach_port_t oname, nname;
  893 {
  894         ipc_entry_t oentry, nentry;
  895         kern_return_t kr;
  896 
  897         kr = ipc_entry_alloc_name(space, nname, &nentry);
  898         if (kr != KERN_SUCCESS)
  899                 return kr;
  900         /* space is write-locked and active */
  901 
  902         if (ipc_right_inuse(space, nname, nentry)) {
  903                 /* space is unlocked */
  904                 return KERN_NAME_EXISTS;
  905         }
  906 
  907         /* don't let ipc_entry_lookup see the uninitialized new entry */
  908 
  909         if ((oname == nname) ||
  910             ((oentry = ipc_entry_lookup(space, oname)) == IE_NULL)) {
  911                 ipc_entry_dealloc(space, nname, nentry);
  912                 is_write_unlock(space);
  913                 return KERN_INVALID_NAME;
  914         }
  915 
  916         kr = ipc_right_rename(space, oname, oentry, nname, nentry);
  917         /* space is unlocked */
  918         return kr;
  919 }
  920 
  921 #if     MACH_IPC_COMPAT
  922 
  923 /*
  924  *      Routine:        ipc_object_copyout_type_compat
  925  *      Purpose:
  926  *              Convert a carried type name to an old type name.
  927  */
  928 
  929 mach_msg_type_name_t
  930 ipc_object_copyout_type_compat(msgt_name)
  931         mach_msg_type_name_t msgt_name;
  932 {
  933         switch (msgt_name) {
  934             case MACH_MSG_TYPE_PORT_SEND:
  935             case MACH_MSG_TYPE_PORT_SEND_ONCE:
  936                 return MSG_TYPE_PORT;
  937 
  938             case MACH_MSG_TYPE_PORT_RECEIVE:
  939                 return MSG_TYPE_PORT_ALL;
  940 
  941             default:
  942 #if MACH_ASSERT
  943                 assert(!"ipc_object_copyout_type_compat: strange rights");
  944 #else
  945                 panic("ipc_object_copyout_type_compat: strange rights");
  946 #endif
  947         }
  948 }
  949 
  950 /*
  951  *      Routine:        ipc_object_copyin_compat
  952  *      Purpose:
  953  *              Copyin a capability from a space.
  954  *              If successful, the caller gets a ref
  955  *              for the resulting object, which is always valid.
  956  *      Conditions:
  957  *              Nothing locked.
  958  *      Returns:
  959  *              KERN_SUCCESS            Acquired a valid object.
  960  *              KERN_INVALID_TASK       The space is dead.
  961  *              KERN_INVALID_NAME       Name doesn't exist in space.
  962  *              KERN_INVALID_RIGHT      Name doesn't denote correct right.
  963  */
  964 
  965 kern_return_t
  966 ipc_object_copyin_compat(space, name, msgt_name, dealloc, objectp)
  967         ipc_space_t space;
  968         mach_port_t name;
  969         mach_msg_type_name_t msgt_name;
  970         boolean_t dealloc;
  971         ipc_object_t *objectp;
  972 {
  973         ipc_entry_t entry;
  974         kern_return_t kr;
  975 
  976         kr = ipc_right_lookup_write(space, name, &entry);
  977         if (kr != KERN_SUCCESS)
  978                 return kr;
  979         /* space is write-locked and active */
  980 
  981         kr = ipc_right_copyin_compat(space, name, entry,
  982                                      msgt_name, dealloc, objectp);
  983         /* space is unlocked */
  984         return kr;
  985 }
  986 
  987 /*
  988  *      Routine:        ipc_object_copyin_header
  989  *      Purpose:
  990  *              Copyin a capability from a space.
  991  *              If successful, the caller gets a ref
  992  *              for the resulting object, which is always valid.
  993  *              The type of the acquired capability is returned.
  994  *      Conditions:
  995  *              Nothing locked.
  996  *      Returns:
  997  *              KERN_SUCCESS            Acquired a valid object.
  998  *              KERN_INVALID_TASK       The space is dead.
  999  *              KERN_INVALID_NAME       Name doesn't exist in space.
 1000  *              KERN_INVALID_RIGHT      Name doesn't denote correct right.
 1001  */
 1002 
 1003 kern_return_t
 1004 ipc_object_copyin_header(space, name, objectp, msgt_namep)
 1005         ipc_space_t space;
 1006         mach_port_t name;
 1007         ipc_object_t *objectp;
 1008         mach_msg_type_name_t *msgt_namep;
 1009 {
 1010         ipc_entry_t entry;
 1011         kern_return_t kr;
 1012 
 1013         kr = ipc_right_lookup_write(space, name, &entry);
 1014         if (kr != KERN_SUCCESS)
 1015                 return kr;
 1016         /* space is write-locked and active */
 1017 
 1018         kr = ipc_right_copyin_header(space, name, entry,
 1019                                      objectp, msgt_namep);
 1020         /* space is unlocked */
 1021         return kr;
 1022 }
 1023 
 1024 /*
 1025  *      Routine:        ipc_object_copyout_compat
 1026  *      Purpose:
 1027  *              Copyout a capability, placing it into a space.
 1028  *              If successful, consumes a ref for the object.
 1029  *
 1030  *              Marks new entries with IE_BITS_COMPAT.
 1031  *      Conditions:
 1032  *              Nothing locked.
 1033  *      Returns:
 1034  *              KERN_SUCCESS            Copied out object, consumed ref.
 1035  *              KERN_INVALID_TASK       The space is dead.
 1036  *              KERN_INVALID_CAPABILITY The object is dead.
 1037  *              KERN_NO_SPACE           No room in space for another right.
 1038  *              KERN_RESOURCE_SHORTAGE  No memory available.
 1039  */
 1040 
 1041 kern_return_t
 1042 ipc_object_copyout_compat(space, object, msgt_name, namep)
 1043         ipc_space_t space;
 1044         ipc_object_t object;
 1045         mach_msg_type_name_t msgt_name;
 1046         mach_port_t *namep;
 1047 {
 1048         mach_port_t name;
 1049         ipc_entry_t entry;
 1050         ipc_port_t port;
 1051         kern_return_t kr;
 1052 
 1053         assert(IO_VALID(object));
 1054         assert(io_otype(object) == IOT_PORT);
 1055         port = (ipc_port_t) object;
 1056 
 1057         is_write_lock(space);
 1058 
 1059         for (;;) {
 1060                 ipc_port_request_index_t request;
 1061 
 1062                 if (!space->is_active) {
 1063                         is_write_unlock(space);
 1064                         return KERN_INVALID_TASK;
 1065                 }
 1066 
 1067                 if ((msgt_name != MACH_MSG_TYPE_PORT_SEND_ONCE) &&
 1068                     ipc_right_reverse(space, (ipc_object_t) port,
 1069                                       &name, &entry)) {
 1070                         /* port is locked and active */
 1071 
 1072                         assert(entry->ie_bits & MACH_PORT_TYPE_SEND_RECEIVE);
 1073                         break;
 1074                 }
 1075 
 1076                 kr = ipc_entry_get(space, &name, &entry);
 1077                 if (kr != KERN_SUCCESS) {
 1078                         /* unlocks/locks space, so must start again */
 1079 
 1080                         kr = ipc_entry_grow_table(space);
 1081                         if (kr != KERN_SUCCESS)
 1082                                 return kr; /* space is unlocked */
 1083 
 1084                         continue;
 1085                 }
 1086 
 1087                 assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE);
 1088                 assert(entry->ie_object == IO_NULL);
 1089 
 1090                 ip_lock(port);
 1091                 if (!ip_active(port)) {
 1092                         ip_unlock(port);
 1093                         ipc_entry_dealloc(space, name, entry);
 1094                         is_write_unlock(space);
 1095                         return KERN_INVALID_CAPABILITY;
 1096                 }
 1097 
 1098                 kr = ipc_port_dnrequest(port, name, ipr_spacem(space),
 1099                                         &request);
 1100                 if (kr != KERN_SUCCESS) {
 1101                         ipc_entry_dealloc(space, name, entry);
 1102                         is_write_unlock(space);
 1103 
 1104                         kr = ipc_port_dngrow(port);
 1105                         /* port is unlocked */
 1106                         if (kr != KERN_SUCCESS)
 1107                                 return kr;
 1108 
 1109                         is_write_lock(space);
 1110                         continue;
 1111                 }
 1112 
 1113                 is_reference(space); /* for dnrequest */
 1114                 entry->ie_object = (ipc_object_t) port;
 1115                 entry->ie_request = request;
 1116                 entry->ie_bits |= IE_BITS_COMPAT;
 1117                 break;
 1118         }
 1119 
 1120         /* space is write-locked and active, port is locked and active */
 1121 
 1122         kr = ipc_right_copyout(space, name, entry,
 1123                                msgt_name, TRUE, (ipc_object_t) port);
 1124         /* object is unlocked */
 1125         is_write_unlock(space);
 1126 
 1127         if (kr == KERN_SUCCESS)
 1128                 *namep = name;
 1129         return kr;
 1130 }
 1131 
 1132 /*
 1133  *      Routine:        ipc_object_copyout_name_compat
 1134  *      Purpose:
 1135  *              Copyout a capability, placing it into a space.
 1136  *              The specified name is used for the capability.
 1137  *              If successful, consumes a ref for the object.
 1138  *
 1139  *              Like ipc_object_copyout_name, except that
 1140  *              the name can't be in use at all, even for the same
 1141  *              port, and IE_BITS_COMPAT gets turned on.
 1142  *      Conditions:
 1143  *              Nothing locked.
 1144  *      Returns:
 1145  *              KERN_SUCCESS            Copied out object, consumed ref.
 1146  *              KERN_INVALID_TASK       The space is dead.
 1147  *              KERN_INVALID_CAPABILITY The object is dead.
 1148  *              KERN_RESOURCE_SHORTAGE  No memory available.
 1149  *              KERN_RIGHT_EXISTS       Space has rights under another name.
 1150  *              KERN_NAME_EXISTS        Name is already used.
 1151  */
 1152 
 1153 kern_return_t
 1154 ipc_object_copyout_name_compat(space, object, msgt_name, name)
 1155         ipc_space_t space;
 1156         ipc_object_t object;
 1157         mach_msg_type_name_t msgt_name;
 1158         mach_port_t name;
 1159 {
 1160         ipc_entry_t entry;
 1161         ipc_port_t port;
 1162         kern_return_t kr;
 1163 
 1164         assert(IO_VALID(object));
 1165         assert(io_otype(object) == IOT_PORT);
 1166         port = (ipc_port_t) object;
 1167 
 1168         for (;;) {
 1169                 mach_port_t oname;
 1170                 ipc_entry_t oentry;
 1171                 ipc_port_request_index_t request;
 1172 
 1173                 kr = ipc_entry_alloc_name(space, name, &entry);
 1174                 if (kr != KERN_SUCCESS)
 1175                         return kr;
 1176                 /* space is write-locked and active */
 1177 
 1178                 if (ipc_right_inuse(space, name, entry))
 1179                         return KERN_NAME_EXISTS; /* space is unlocked */
 1180 
 1181                 assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE);
 1182                 assert(entry->ie_object == IO_NULL);
 1183 
 1184                 if ((msgt_name != MACH_MSG_TYPE_PORT_SEND_ONCE) &&
 1185                     ipc_right_reverse(space, (ipc_object_t) port,
 1186                                       &oname, &oentry)) {
 1187                         /* port is locked and active */
 1188 
 1189                         ip_unlock(port);
 1190                         ipc_entry_dealloc(space, name, entry);
 1191                         is_write_unlock(space);
 1192                         return KERN_RIGHT_EXISTS;
 1193                 }
 1194 
 1195                 ip_lock(port);
 1196                 if (!ip_active(port)) {
 1197                         ip_unlock(port);
 1198                         ipc_entry_dealloc(space, name, entry);
 1199                         is_write_unlock(space);
 1200                         return KERN_INVALID_CAPABILITY;
 1201                 }
 1202 
 1203                 kr = ipc_port_dnrequest(port, name, ipr_spacem(space),
 1204                                         &request);
 1205                 if (kr != KERN_SUCCESS) {
 1206                         ipc_entry_dealloc(space, name, entry);
 1207                         is_write_unlock(space);
 1208 
 1209                         kr = ipc_port_dngrow(port);
 1210                         /* port is unlocked */
 1211                         if (kr != KERN_SUCCESS)
 1212                                 return kr;
 1213 
 1214                         continue;
 1215                 }
 1216 
 1217                 is_reference(space); /* for dnrequest */
 1218                 entry->ie_object = (ipc_object_t) port;
 1219                 entry->ie_request = request;
 1220                 entry->ie_bits |= IE_BITS_COMPAT;
 1221                 break;
 1222         }
 1223 
 1224         /* space is write-locked and active, port is locked and active */
 1225 
 1226         kr = ipc_right_copyout(space, name, entry,
 1227                                msgt_name, TRUE, (ipc_object_t) port);
 1228         /* object is unlocked */
 1229         is_write_unlock(space);
 1230 
 1231         assert(kr == KERN_SUCCESS);
 1232         return kr;
 1233 }
 1234 
 1235 #endif  MACH_IPC_COMPAT
 1236 
 1237 #include <mach_kdb.h>
 1238 
 1239 
 1240 #if     MACH_KDB
 1241 #define printf  kdbprintf
 1242 
 1243 /*
 1244  *      Routine:        ipc_object_print
 1245  *      Purpose:
 1246  *              Pretty-print an object for kdb.
 1247  */
 1248 
 1249 void
 1250 ipc_object_print(object)
 1251         ipc_object_t object;
 1252 {
 1253         iprintf("%s", io_active(object) ? "active" : "dead");
 1254         printf(", refs=%d", object->io_references);
 1255         printf(", otype=%d", io_otype(object));
 1256         printf(", kotype=%d\n", io_kotype(object));
 1257 }
 1258 
 1259 #endif  MACH_KDB

Cache object: c6c0ceb6987fcbfbe104c74ae7920229


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.