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

Cache object: 77876ca6864386f7e76fa973ed43146c


[ 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.