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_port.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_port.c,v $
   29  * Revision 2.18  93/11/17  17:00:18  dbg
   30  *      Added ANSI function prototypes.
   31  *      [93/03/30            dbg]
   32  * 
   33  *      Include kern/sched_prim.h instead of kern/ipc_sched.h.
   34  *      [93/01/26            dbg]
   35  * 
   36  * Revision 2.17  92/08/03  17:35:07  jfriedl
   37  *      removed silly prototypes
   38  *      [92/08/02            jfriedl]
   39  * 
   40  * Revision 2.16  92/05/21  17:11:11  jfriedl
   41  *      Added a few things to shut up gcc warnings.
   42  *      [92/05/16            jfriedl]
   43  * 
   44  * Revision 2.15  92/04/06  01:16:19  rpd
   45  *      Fixed ipc_port_dealloc_special for ipc_space_reply.
   46  *      Fixed ipc_port_set_seqno with ipc_port_lock_mqueue.
   47  *      [92/04/05            rpd]
   48  * 
   49  * Revision 2.14  92/03/10  16:26:13  jsb
   50  *      Merged in norma branch changes as of NORMA_MK7:
   51  *      Removed token-related fields. Added fields for receive-right migration
   52  *      and xmm support. Updated ipc_port_{init,print} accordingly.
   53  *      [92/03/09  13:20:23  jsb]
   54  * 
   55  * Revision 2.13  91/12/14  14:27:37  jsb
   56  *      Removed ipc_fields.h hack.
   57  * 
   58  * Revision 2.12  91/11/14  16:56:14  rpd
   59  *      Added ipc_fields.h support to ipc_port_{init,print}.
   60  *      Call norma_ipc_port_destroy instead of norma_ipc_destroy.
   61  *      [91/11/00            jsb]
   62  * 
   63  * Revision 2.11  91/10/09  16:09:42  af
   64  *      Removed unused variable.
   65  *      [91/09/16  09:42:52  rpd]
   66  * 
   67  * Revision 2.10  91/08/28  11:13:44  jsb
   68  *      Added ip_seqno and ipc_port_set_seqno.
   69  *      Changed ipc_port_init to initialize ip_seqno.
   70  *      Changed ipc_port_clear_receiver to zero ip_seqno.
   71  *      [91/08/09            rpd]
   72  *      Renamed clport fields in struct ipc_port to ip_norma fields.
   73  *      [91/08/15  08:20:08  jsb]
   74  * 
   75  * Revision 2.9  91/08/03  18:18:30  jsb
   76  *      Call norma_ipc_destroy when destroying port.
   77  *      Added clport fields to ipc_port_print.
   78  *      [91/07/24  22:14:01  jsb]
   79  * 
   80  *      Fixed include. Changed clport field initialization.
   81  *      [91/07/17  14:05:38  jsb]
   82  * 
   83  * Revision 2.8  91/06/17  15:46:21  jsb
   84  *      Renamed NORMA conditionals.
   85  *      [91/06/17  10:44:21  jsb]
   86  * 
   87  * Revision 2.7  91/05/14  16:35:22  mrt
   88  *      Correcting copyright
   89  * 
   90  * Revision 2.6  91/03/16  14:48:27  rpd
   91  *      Renamed ipc_thread_go to thread_go.
   92  *      [91/02/17            rpd]
   93  * 
   94  * Revision 2.5  91/02/05  17:23:02  mrt
   95  *      Changed to new Mach copyright
   96  *      [91/02/01  15:49:46  mrt]
   97  * 
   98  * Revision 2.4  90/11/05  14:29:30  rpd
   99  *      Changed ip_release to ipc_port_release.
  100  *      Use new ip_reference and ip_release.
  101  *      [90/10/29            rpd]
  102  * 
  103  * Revision 2.3  90/09/28  16:55:10  jsb
  104  *      Added NORMA_IPC support.
  105  *      [90/09/28  14:03:45  jsb]
  106  * 
  107  * Revision 2.2  90/06/02  14:51:08  rpd
  108  *      Created for new IPC.
  109  *      [90/03/26  21:01:02  rpd]
  110  * 
  111  */
  112 /*
  113  *      File:   ipc/ipc_port.c
  114  *      Author: Rich Draves
  115  *      Date:   1989
  116  *
  117  *      Functions to manipulate IPC ports.
  118  */
  119 
  120 #include <mach_ipc_compat.h>
  121 
  122 #include <mach/port.h>
  123 #include <mach/kern_return.h>
  124 #include <kern/lock.h>
  125 #include <kern/sched_prim.h>
  126 #include <kern/ipc_kobject.h>
  127 #include <kern/memory.h>
  128 #include <ipc/ipc_entry.h>
  129 #include <ipc/ipc_space.h>
  130 #include <ipc/ipc_object.h>
  131 #include <ipc/ipc_port.h>
  132 #include <ipc/ipc_pset.h>
  133 #include <ipc/ipc_right.h>
  134 #include <ipc/ipc_thread.h>
  135 #include <ipc/ipc_mqueue.h>
  136 #include <ipc/ipc_notify.h>
  137 #if     NORMA_IPC
  138 #include <norma/ipc_node.h>
  139 #endif  /* NORMA_IPC */
  140 
  141 
  142 
  143 decl_simple_lock_data(, ipc_port_multiple_lock_data)
  144 
  145 decl_simple_lock_data(, ipc_port_timestamp_lock_data)
  146 ipc_port_timestamp_t ipc_port_timestamp_data;
  147 
  148 /*
  149  *      Routine:        ipc_port_timestamp
  150  *      Purpose:
  151  *              Retrieve a timestamp value.
  152  */
  153 
  154 ipc_port_timestamp_t
  155 ipc_port_timestamp(void)
  156 {
  157         ipc_port_timestamp_t timestamp;
  158 
  159         ipc_port_timestamp_lock();
  160         timestamp = ipc_port_timestamp_data++;
  161         ipc_port_timestamp_unlock();
  162 
  163         return timestamp;
  164 }
  165 
  166 /*
  167  *      Routine:        ipc_port_dnrequest
  168  *      Purpose:
  169  *              Try to allocate a dead-name request slot.
  170  *              If successful, returns the request index.
  171  *              Otherwise returns zero.
  172  *      Conditions:
  173  *              The port is locked and active.
  174  *      Returns:
  175  *              KERN_SUCCESS            A request index was found.
  176  *              KERN_NO_SPACE           No index allocated.
  177  */
  178 
  179 kern_return_t
  180 ipc_port_dnrequest(
  181         ipc_port_t port,
  182         mach_port_t name,
  183         ipc_port_t soright,
  184         ipc_port_request_index_t *indexp)
  185 {
  186         ipc_port_request_t ipr, table;
  187         ipc_port_request_index_t index;
  188 
  189         assert(ip_active(port));
  190         assert(name != MACH_PORT_NULL);
  191         assert(soright != IP_NULL);
  192 
  193         table = port->ip_dnrequests;
  194         if (table == IPR_NULL)
  195                 return KERN_NO_SPACE;
  196 
  197         index = table->ipr_next;
  198         if (index == 0)
  199                 return KERN_NO_SPACE;
  200 
  201         ipr = &table[index];
  202         assert(ipr->ipr_name == MACH_PORT_NULL);
  203 
  204         table->ipr_next = ipr->ipr_next;
  205         ipr->ipr_name = name;
  206         ipr->ipr_soright = soright;
  207 
  208         *indexp = index;
  209         return KERN_SUCCESS;
  210 }
  211 
  212 /*
  213  *      Routine:        ipc_port_dngrow
  214  *      Purpose:
  215  *              Grow a port's table of dead-name requests.
  216  *      Conditions:
  217  *              The port must be locked and active.
  218  *              Nothing else locked; will allocate memory.
  219  *              Upon return the port is unlocked.
  220  *      Returns:
  221  *              KERN_SUCCESS            Grew the table.
  222  *              KERN_SUCCESS            Somebody else grew the table.
  223  *              KERN_SUCCESS            The port died.
  224  *              KERN_RESOURCE_SHORTAGE  Couldn't allocate new table.
  225  */
  226 
  227 kern_return_t
  228 ipc_port_dngrow(
  229         ipc_port_t port)
  230 {
  231         ipc_table_size_t its;
  232         ipc_port_request_t otable, ntable;
  233 
  234         assert(ip_active(port));
  235 
  236         otable = port->ip_dnrequests;
  237         if (otable == IPR_NULL)
  238                 its = &ipc_table_dnrequests[0];
  239         else
  240                 its = otable->ipr_size + 1;
  241 
  242         ip_reference(port);
  243         ip_unlock(port);
  244 
  245         if ((its->its_size == 0) ||
  246             ((ntable = it_dnrequests_alloc(its)) == IPR_NULL)) {
  247                 ipc_port_release(port);
  248                 return KERN_RESOURCE_SHORTAGE;
  249         }
  250 
  251         ip_lock(port);
  252         ip_release(port);
  253 
  254         /*
  255          *      Check that port is still active and that nobody else
  256          *      has slipped in and grown the table on us.  Note that
  257          *      just checking port->ip_dnrequests == otable isn't
  258          *      sufficient; must check ipr_size.
  259          */
  260 
  261         if (ip_active(port) &&
  262             (port->ip_dnrequests == otable) &&
  263             ((otable == IPR_NULL) || (otable->ipr_size+1 == its))) {
  264                 ipc_table_size_t oits = 0; /* '=0' to shut up lint */
  265                 ipc_table_elems_t osize, nsize;
  266                 ipc_port_request_index_t free, i;
  267 
  268                 /* copy old table to new table */
  269 
  270                 if (otable != IPR_NULL) {
  271                         oits = otable->ipr_size;
  272                         osize = oits->its_size;
  273                         free = otable->ipr_next;
  274 
  275                         bcopy((char *)(otable + 1), (char *)(ntable + 1),
  276                               (osize - 1) * sizeof(struct ipc_port_request));
  277                 } else {
  278                         osize = 1;
  279                         free = 0;
  280                 }
  281 
  282                 nsize = its->its_size;
  283                 assert(nsize > osize);
  284 
  285                 /* add new elements to the new table's free list */
  286 
  287                 for (i = osize; i < nsize; i++) {
  288                         ipc_port_request_t ipr = &ntable[i];
  289 
  290                         ipr->ipr_name = MACH_PORT_NULL;
  291                         ipr->ipr_next = free;
  292                         free = i;
  293                 }
  294 
  295                 ntable->ipr_next = free;
  296                 ntable->ipr_size = its;
  297                 port->ip_dnrequests = ntable;
  298                 ip_unlock(port);
  299 
  300                 if (otable != IPR_NULL)
  301                         it_dnrequests_free(oits, otable);
  302         } else {
  303                 ip_check_unlock(port);
  304                 it_dnrequests_free(its, ntable);
  305         }
  306 
  307         return KERN_SUCCESS;
  308 }
  309  
  310 /*
  311  *      Routine:        ipc_port_dncancel
  312  *      Purpose:
  313  *              Cancel a dead-name request and return the send-once right.
  314  *      Conditions:
  315  *              The port must be locked and active.
  316  */
  317 
  318 ipc_port_t
  319 ipc_port_dncancel(
  320         ipc_port_t port,
  321         mach_port_t name,
  322         ipc_port_request_index_t index)
  323 {
  324         ipc_port_request_t ipr, table;
  325         ipc_port_t dnrequest;
  326 
  327         assert(ip_active(port));
  328         assert(name != MACH_PORT_NULL);
  329         assert(index != 0);
  330 
  331         table = port->ip_dnrequests;
  332         assert(table != IPR_NULL);
  333 
  334         ipr = &table[index];
  335         dnrequest = ipr->ipr_soright;
  336         assert(ipr->ipr_name == name);
  337 
  338         /* return ipr to the free list inside the table */
  339 
  340         ipr->ipr_name = MACH_PORT_NULL;
  341         ipr->ipr_next = table->ipr_next;
  342         table->ipr_next = index;
  343 
  344         return dnrequest;
  345 }
  346 
  347 /*
  348  *      Routine:        ipc_port_pdrequest
  349  *      Purpose:
  350  *              Make a port-deleted request, returning the
  351  *              previously registered send-once right.
  352  *              Just cancels the previous request if notify is IP_NULL.
  353  *      Conditions:
  354  *              The port is locked and active.  It is unlocked.
  355  *              Consumes a ref for notify (if non-null), and
  356  *              returns previous with a ref (if non-null).
  357  */
  358 
  359 void
  360 ipc_port_pdrequest(
  361         ipc_port_t port,
  362         ipc_port_t notify,
  363         ipc_port_t *previousp)
  364 {
  365         ipc_port_t previous;
  366 
  367         assert(ip_active(port));
  368 
  369         previous = port->ip_pdrequest;
  370         port->ip_pdrequest = notify;
  371         ip_unlock(port);
  372 
  373         *previousp = previous;
  374 }
  375 
  376 /*
  377  *      Routine:        ipc_port_nsrequest
  378  *      Purpose:
  379  *              Make a no-senders request, returning the
  380  *              previously registered send-once right.
  381  *              Just cancels the previous request if notify is IP_NULL.
  382  *      Conditions:
  383  *              The port is locked and active.  It is unlocked.
  384  *              Consumes a ref for notify (if non-null), and
  385  *              returns previous with a ref (if non-null).
  386  */
  387 
  388 void
  389 ipc_port_nsrequest(
  390         ipc_port_t port,
  391         mach_port_mscount_t sync,
  392         ipc_port_t notify,
  393         ipc_port_t *previousp)
  394 {
  395         ipc_port_t previous;
  396         mach_port_mscount_t mscount;
  397 
  398         assert(ip_active(port));
  399 
  400         previous = port->ip_nsrequest;
  401         mscount = port->ip_mscount;
  402 
  403         if ((port->ip_srights == 0) &&
  404             (sync <= mscount) &&
  405             (notify != IP_NULL)) {
  406                 port->ip_nsrequest = IP_NULL;
  407                 ip_unlock(port);
  408                 ipc_notify_no_senders(notify, mscount);
  409         } else {
  410                 port->ip_nsrequest = notify;
  411                 ip_unlock(port);
  412         }
  413 
  414         *previousp = previous;
  415 }
  416 
  417 /*
  418  *      Routine:        ipc_port_set_qlimit
  419  *      Purpose:
  420  *              Changes a port's queue limit; the maximum number
  421  *              of messages which may be queued to the port.
  422  *      Conditions:
  423  *              The port is locked and active.
  424  */
  425 
  426 void
  427 ipc_port_set_qlimit(
  428         ipc_port_t port,
  429         mach_port_msgcount_t qlimit)
  430 {
  431         assert(ip_active(port));
  432         assert(qlimit <= MACH_PORT_QLIMIT_MAX);
  433 
  434         /* wake up senders allowed by the new qlimit */
  435 
  436         if (qlimit > port->ip_qlimit) {
  437                 mach_port_msgcount_t i, wakeup;
  438 
  439                 /* caution: wakeup, qlimit are unsigned */
  440 
  441                 wakeup = qlimit - port->ip_qlimit;
  442 
  443                 for (i = 0; i < wakeup; i++) {
  444                         ipc_thread_t th;
  445 
  446                         th = ipc_thread_dequeue(&port->ip_blocked);
  447                         if (th == ITH_NULL)
  448                                 break;
  449 
  450                         th->ith_state = MACH_MSG_SUCCESS;
  451                         thread_go(th);
  452                 }
  453         }
  454 
  455         port->ip_qlimit = qlimit;
  456 }
  457 
  458 /*
  459  *      Routine:        ipc_port_lock_mqueue
  460  *      Purpose:
  461  *              Locks and returns the message queue that the port is using.
  462  *              The message queue may be in the port or in its port set.
  463  *      Conditions:
  464  *              The port is locked and active.
  465  *              Port set, message queue locks may be taken.
  466  */
  467 
  468 ipc_mqueue_t
  469 ipc_port_lock_mqueue(
  470         ipc_port_t port)
  471 {
  472         if (port->ip_pset != IPS_NULL) {
  473                 ipc_pset_t pset = port->ip_pset;
  474 
  475                 ips_lock(pset);
  476                 if (ips_active(pset)) {
  477                         imq_lock(&pset->ips_messages);
  478                         ips_unlock(pset);
  479                         return &pset->ips_messages;
  480                 }
  481 
  482                 ipc_pset_remove(pset, port);
  483                 ips_check_unlock(pset);
  484         }
  485 
  486         imq_lock(&port->ip_messages);
  487         return &port->ip_messages;
  488 }
  489 
  490 /*
  491  *      Routine:        ipc_port_set_seqno
  492  *      Purpose:
  493  *              Changes a port's sequence number.
  494  *      Conditions:
  495  *              The port is locked and active.
  496  *              Port set, message queue locks may be taken.
  497  */
  498 
  499 void
  500 ipc_port_set_seqno(
  501         ipc_port_t port,
  502         mach_port_seqno_t seqno)
  503 {
  504         ipc_mqueue_t mqueue;
  505 
  506         mqueue = ipc_port_lock_mqueue(port);
  507         port->ip_seqno = seqno;
  508         imq_unlock(mqueue);
  509 }
  510 
  511 /*
  512  *      Routine:        ipc_port_clear_receiver
  513  *      Purpose:
  514  *              Prepares a receive right for transmission/destruction.
  515  *      Conditions:
  516  *              The port is locked and active.
  517  */
  518 
  519 void
  520 ipc_port_clear_receiver(
  521         ipc_port_t port)
  522 {
  523         ipc_pset_t pset;
  524 
  525         assert(ip_active(port));
  526 
  527         pset = port->ip_pset;
  528         if (pset != IPS_NULL) {
  529                 /* No threads receiving from port, but must remove from set. */
  530 
  531                 ips_lock(pset);
  532                 ipc_pset_remove(pset, port);
  533                 ips_check_unlock(pset);
  534         } else {
  535                 /* Else, wake up all receivers, indicating why. */
  536 
  537                 imq_lock(&port->ip_messages);
  538                 ipc_mqueue_changed(&port->ip_messages, MACH_RCV_PORT_DIED);
  539                 imq_unlock(&port->ip_messages);
  540         }
  541 
  542         ipc_port_set_mscount(port, 0);
  543         imq_lock(&port->ip_messages);
  544         port->ip_seqno = 0;
  545         imq_unlock(&port->ip_messages);
  546 }
  547 
  548 /*
  549  *      Routine:        ipc_port_init
  550  *      Purpose:
  551  *              Initializes a newly-allocated port.
  552  *              Doesn't touch the ip_object fields.
  553  */
  554 
  555 void
  556 ipc_port_init(
  557         ipc_port_t port,
  558         ipc_space_t space,
  559         mach_port_t name)
  560 {
  561         /* port->ip_kobject doesn't have to be initialized */
  562 
  563         port->ip_receiver = space;
  564         port->ip_receiver_name = name;
  565 
  566         port->ip_mscount = 0;
  567         port->ip_srights = 0;
  568         port->ip_sorights = 0;
  569 
  570         port->ip_nsrequest = IP_NULL;
  571         port->ip_pdrequest = IP_NULL;
  572         port->ip_dnrequests = IPR_NULL;
  573 
  574         port->ip_pset = IPS_NULL;
  575         port->ip_seqno = 0;
  576         port->ip_msgcount = 0;
  577         port->ip_qlimit = MACH_PORT_QLIMIT_DEFAULT;
  578 
  579 #if     NORMA_IPC
  580         port->ip_norma_uid = 0;
  581         port->ip_norma_dest_node = 0;
  582         port->ip_norma_stransit = 0;
  583         port->ip_norma_sotransit = 0;
  584         port->ip_norma_xmm_object_refs = 0;
  585         port->ip_norma_is_proxy = FALSE;
  586         port->ip_norma_is_special = FALSE;
  587         port->ip_norma_atrium = IP_NULL;
  588         port->ip_norma_queue_next = port;
  589         port->ip_norma_xmm_object = IP_NULL;
  590         port->ip_norma_next = port;
  591         port->ip_norma_spare1 = 0L;
  592         port->ip_norma_spare2 = 0L;
  593         port->ip_norma_spare3 = 0L;
  594         port->ip_norma_spare4 = 0L;
  595 #endif  /* NORMA_IPC */
  596 
  597         ipc_mqueue_init(&port->ip_messages);
  598         ipc_thread_queue_init(&port->ip_blocked);
  599 }
  600 
  601 /*
  602  *      Routine:        ipc_port_alloc
  603  *      Purpose:
  604  *              Allocate a port.
  605  *      Conditions:
  606  *              Nothing locked.  If successful, the port is returned
  607  *              locked.  (The caller doesn't have a reference.)
  608  *      Returns:
  609  *              KERN_SUCCESS            The port is allocated.
  610  *              KERN_INVALID_TASK       The space is dead.
  611  *              KERN_NO_SPACE           No room for an entry in the space.
  612  *              KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
  613  */
  614 
  615 kern_return_t
  616 ipc_port_alloc(
  617         ipc_space_t space,
  618         mach_port_t *namep,
  619         ipc_port_t *portp)
  620 {
  621         ipc_port_t port;
  622         mach_port_t name;
  623         kern_return_t kr;
  624 
  625         kr = ipc_object_alloc(space, IOT_PORT,
  626                               MACH_PORT_TYPE_RECEIVE, 0,
  627                               &name, (ipc_object_t *) &port);
  628         if (kr != KERN_SUCCESS)
  629                 return kr;
  630         /* port is locked */
  631 
  632         ipc_port_init(port, space, name);
  633 
  634         *namep = name;
  635         *portp = port;
  636         return KERN_SUCCESS;
  637 }
  638 
  639 /*
  640  *      Routine:        ipc_port_alloc_name
  641  *      Purpose:
  642  *              Allocate a port, with a specific name.
  643  *      Conditions:
  644  *              Nothing locked.  If successful, the port is returned
  645  *              locked.  (The caller doesn't have a reference.)
  646  *      Returns:
  647  *              KERN_SUCCESS            The port is allocated.
  648  *              KERN_INVALID_TASK       The space is dead.
  649  *              KERN_NAME_EXISTS        The name already denotes a right.
  650  *              KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
  651  */
  652 
  653 kern_return_t
  654 ipc_port_alloc_name(
  655         ipc_space_t space,
  656         mach_port_t name,
  657         ipc_port_t *portp)
  658 {
  659         ipc_port_t port;
  660         kern_return_t kr;
  661 
  662         kr = ipc_object_alloc_name(space, IOT_PORT,
  663                                    MACH_PORT_TYPE_RECEIVE, 0,
  664                                    name, (ipc_object_t *) &port);
  665         if (kr != KERN_SUCCESS)
  666                 return kr;
  667         /* port is locked */
  668 
  669         ipc_port_init(port, space, name);
  670 
  671         *portp = port;
  672         return KERN_SUCCESS;
  673 }
  674 
  675 #if     MACH_IPC_COMPAT
  676 /*
  677  *      Routine:        ipc_port_delete_compat
  678  *      Purpose:
  679  *              Find and destroy a compat entry for a dead port.
  680  *              If successful, generate a port-deleted notification.
  681  *      Conditions:
  682  *              Nothing locked; the port is dead.
  683  *              Frees a ref for the space.
  684  */
  685 
  686 void
  687 ipc_port_delete_compat(
  688         ipc_port_t port,
  689         ipc_space_t space,
  690         mach_port_t name)
  691 {
  692         ipc_entry_t entry;
  693         kern_return_t kr;
  694 
  695         assert(!ip_active(port));
  696 
  697         kr = ipc_right_lookup_write(space, name, &entry);
  698         if (kr == KERN_SUCCESS) {
  699                 ipc_port_t sright;
  700 
  701                 /* space is write-locked and active */
  702 
  703                 if ((ipc_port_t) entry->ie_object == port) {
  704                         assert(entry->ie_bits & IE_BITS_COMPAT);
  705 
  706                         sright = ipc_space_make_notify(space);
  707 
  708                         kr = ipc_right_destroy(space, name, entry);
  709                         /* space is unlocked */
  710                         assert(kr == KERN_INVALID_NAME);
  711                 } else {
  712                         is_write_unlock(space);
  713                         sright = IP_NULL;
  714                 }
  715 
  716                 if (IP_VALID(sright))
  717                         ipc_notify_port_deleted_compat(sright, name);
  718         }
  719 
  720         is_release(space);
  721 }
  722 #endif  /* MACH_IPC_COMPAT */
  723 
  724 /*
  725  *      Routine:        ipc_port_destroy
  726  *      Purpose:
  727  *              Destroys a port.  Cleans up queued messages.
  728  *
  729  *              If the port has a backup, it doesn't get destroyed,
  730  *              but is sent in a port-destroyed notification to the backup.
  731  *      Conditions:
  732  *              The port is locked and alive; nothing else locked.
  733  *              The caller has a reference, which is consumed.
  734  *              Afterwards, the port is unlocked and dead.
  735  */
  736 
  737 void
  738 ipc_port_destroy(
  739         ipc_port_t port)
  740 {
  741         ipc_port_t pdrequest, nsrequest;
  742         ipc_mqueue_t mqueue;
  743         ipc_kmsg_queue_t kmqueue;
  744         ipc_kmsg_t kmsg;
  745         ipc_thread_t sender;
  746         ipc_port_request_t dnrequests;
  747 
  748         assert(ip_active(port));
  749         /* port->ip_receiver_name is garbage */
  750         /* port->ip_receiver/port->ip_destination is garbage */
  751         assert(port->ip_pset == IPS_NULL);
  752         assert(port->ip_mscount == 0);
  753         assert(port->ip_seqno == 0);
  754 
  755         /* first check for a backup port */
  756 
  757         pdrequest = port->ip_pdrequest;
  758         if (pdrequest != IP_NULL) {
  759                 /* we assume the ref for pdrequest */
  760                 port->ip_pdrequest = IP_NULL;
  761 
  762                 /* make port be in limbo */
  763                 port->ip_receiver_name = MACH_PORT_NULL;
  764                 port->ip_destination = IP_NULL;
  765                 ip_unlock(port);
  766 
  767 #if     MACH_IPC_COMPAT
  768                 /*
  769                  *      pdrequest might actually be a send right instead
  770                  *      of a send-once right, indicated by the low bit
  771                  *      of the pointer value.  If this is the case,
  772                  *      we must use ipc_notify_port_destroyed_compat.
  773                  */
  774 
  775                 if (ip_pdsendp(pdrequest)) {
  776                         ipc_port_t sright = ip_pdsend(pdrequest);
  777 
  778                         if (!ipc_port_check_circularity(port, sright)) {
  779                                 /* consumes our refs for port and sright */
  780                                 ipc_notify_port_destroyed_compat(sright, port);
  781                                 return;
  782                         } else {
  783                                 /* consume sright and destroy port */
  784                                 ipc_port_release_send(sright);
  785                         }
  786                 } else
  787 #endif  /* MACH_IPC_COMPAT */
  788 
  789                 if (!ipc_port_check_circularity(port, pdrequest)) {
  790                         /* consumes our refs for port and pdrequest */
  791                         ipc_notify_port_destroyed(pdrequest, port);
  792                         return;
  793                 } else {
  794                         /* consume pdrequest and destroy port */
  795                         ipc_port_release_sonce(pdrequest);
  796                 }
  797 
  798                 ip_lock(port);
  799                 assert(ip_active(port));
  800                 assert(port->ip_pset == IPS_NULL);
  801                 assert(port->ip_mscount == 0);
  802                 assert(port->ip_seqno == 0);
  803                 assert(port->ip_pdrequest == IP_NULL);
  804                 assert(port->ip_receiver_name == MACH_PORT_NULL);
  805                 assert(port->ip_destination == IP_NULL);
  806 
  807                 /* fall through and destroy the port */
  808         }
  809 
  810 #if     NORMA_IPC
  811         /*
  812          *      destroy any NORMA_IPC state associated with port
  813          */
  814         norma_ipc_port_destroy(port);
  815 #endif  /* NORMA_IPC */
  816 
  817         /*
  818          *      rouse all blocked senders
  819          *
  820          *      This must be done with the port locked, because
  821          *      ipc_mqueue_send can play with the ip_blocked queue
  822          *      of a dead port.
  823          */
  824 
  825         while ((sender = ipc_thread_dequeue(&port->ip_blocked)) != ITH_NULL) {
  826                 sender->ith_state = MACH_MSG_SUCCESS;
  827                 thread_go(sender);
  828         }
  829 
  830         /* once port is dead, we don't need to keep it locked */
  831 
  832         port->ip_object.io_bits &= ~IO_BITS_ACTIVE;
  833         port->ip_timestamp = ipc_port_timestamp();
  834         ip_unlock(port);
  835 
  836         /* throw away no-senders request */
  837 
  838         nsrequest = port->ip_nsrequest;
  839         if (nsrequest != IP_NULL)
  840                 ipc_notify_send_once(nsrequest); /* consumes ref */
  841 
  842         /* destroy any queued messages */
  843 
  844         mqueue = &port->ip_messages;
  845         imq_lock(mqueue);
  846         assert(ipc_thread_queue_empty(&mqueue->imq_threads));
  847         kmqueue = &mqueue->imq_messages;
  848 
  849         while ((kmsg = ipc_kmsg_dequeue(kmqueue)) != IKM_NULL) {
  850                 imq_unlock(mqueue);
  851 
  852                 assert(kmsg->ikm_header.msgh_remote_port ==
  853                                                 (mach_port_t) port);
  854 
  855                 ipc_port_release(port);
  856                 kmsg->ikm_header.msgh_remote_port = MACH_PORT_NULL;
  857                 ipc_kmsg_destroy(kmsg);
  858 
  859                 imq_lock(mqueue);
  860         }
  861 
  862         imq_unlock(mqueue);
  863 
  864         /* generate dead-name notifications */
  865 
  866         dnrequests = port->ip_dnrequests;
  867         if (dnrequests != IPR_NULL) {
  868                 ipc_table_size_t its = dnrequests->ipr_size;
  869                 ipc_table_elems_t size = its->its_size;
  870                 ipc_port_request_index_t index;
  871 
  872                 for (index = 1; index < size; index++) {
  873                         ipc_port_request_t ipr = &dnrequests[index];
  874                         mach_port_t name = ipr->ipr_name;
  875                         ipc_port_t soright;
  876 
  877                         if (name == MACH_PORT_NULL)
  878                                 continue;
  879 
  880                         soright = ipr->ipr_soright;
  881                         assert(soright != IP_NULL);
  882 
  883 #if     MACH_IPC_COMPAT
  884                         if (ipr_spacep(soright)) {
  885                                 ipc_port_delete_compat(port,
  886                                                 ipr_space(soright), name);
  887                                 continue;
  888                         }
  889 #endif  /* MACH_IPC_COMPAT */
  890 
  891                         ipc_notify_dead_name(soright, name);
  892                 }
  893 
  894                 it_dnrequests_free(its, dnrequests);
  895         }
  896 
  897         if (ip_kotype(port) != IKOT_NONE)
  898                 ipc_kobject_destroy(port);
  899 
  900         ipc_port_release(port); /* consume caller's ref */
  901 }
  902 
  903 /*
  904  *      Routine:        ipc_port_check_circularity
  905  *      Purpose:
  906  *              Check if queueing "port" in a message for "dest"
  907  *              would create a circular group of ports and messages.
  908  *
  909  *              If no circularity (FALSE returned), then "port"
  910  *              is changed from "in limbo" to "in transit".
  911  *
  912  *              That is, we want to set port->ip_destination == dest,
  913  *              but guaranteeing that this doesn't create a circle
  914  *              port->ip_destination->ip_destination->... == port
  915  *      Conditions:
  916  *              No ports locked.  References held for "port" and "dest".
  917  */
  918 
  919 boolean_t
  920 ipc_port_check_circularity(
  921         ipc_port_t port,
  922         ipc_port_t dest)
  923 {
  924         ipc_port_t base;
  925 
  926         assert(port != IP_NULL);
  927         assert(dest != IP_NULL);
  928 
  929         if (port == dest)
  930                 return TRUE;
  931         base = dest;
  932 
  933         /*
  934          *      First try a quick check that can run in parallel.
  935          *      No circularity if dest is not in transit.
  936          */
  937 
  938         ip_lock(port);
  939         if (ip_lock_try(dest)) {
  940                 if (!ip_active(dest) ||
  941                     (dest->ip_receiver_name != MACH_PORT_NULL) ||
  942                     (dest->ip_destination == IP_NULL))
  943                         goto not_circular;
  944 
  945                 /* dest is in transit; further checking necessary */
  946 
  947                 ip_unlock(dest);
  948         }
  949         ip_unlock(port);
  950 
  951         ipc_port_multiple_lock(); /* massive serialization */
  952 
  953         /*
  954          *      Search for the end of the chain (a port not in transit),
  955          *      acquiring locks along the way.
  956          */
  957 
  958         for (;;) {
  959                 ip_lock(base);
  960 
  961                 if (!ip_active(base) ||
  962                     (base->ip_receiver_name != MACH_PORT_NULL) ||
  963                     (base->ip_destination == IP_NULL))
  964                         break;
  965 
  966                 base = base->ip_destination;
  967         }
  968 
  969         /* all ports in chain from dest to base, inclusive, are locked */
  970 
  971         if (port == base) {
  972                 /* circularity detected! */
  973 
  974                 ipc_port_multiple_unlock();
  975 
  976                 /* port (== base) is in limbo */
  977 
  978                 assert(ip_active(port));
  979                 assert(port->ip_receiver_name == MACH_PORT_NULL);
  980                 assert(port->ip_destination == IP_NULL);
  981 
  982                 while (dest != IP_NULL) {
  983                         ipc_port_t next;
  984 
  985                         /* dest is in transit or in limbo */
  986 
  987                         assert(ip_active(dest));
  988                         assert(dest->ip_receiver_name == MACH_PORT_NULL);
  989 
  990                         next = dest->ip_destination;
  991                         ip_unlock(dest);
  992                         dest = next;
  993                 }
  994 
  995                 return TRUE;
  996         }
  997 
  998         /*
  999          *      The guarantee:  lock port while the entire chain is locked.
 1000          *      Once port is locked, we can take a reference to dest,
 1001          *      add port to the chain, and unlock everything.
 1002          */
 1003 
 1004         ip_lock(port);
 1005         ipc_port_multiple_unlock();
 1006 
 1007     not_circular:
 1008 
 1009         /* port is in limbo */
 1010 
 1011         assert(ip_active(port));
 1012         assert(port->ip_receiver_name == MACH_PORT_NULL);
 1013         assert(port->ip_destination == IP_NULL);
 1014 
 1015         ip_reference(dest);
 1016         port->ip_destination = dest;
 1017 
 1018         /* now unlock chain */
 1019 
 1020         while (port != base) {
 1021                 ipc_port_t next;
 1022 
 1023                 /* port is in transit */
 1024 
 1025                 assert(ip_active(port));
 1026                 assert(port->ip_receiver_name == MACH_PORT_NULL);
 1027                 assert(port->ip_destination != IP_NULL);
 1028 
 1029                 next = port->ip_destination;
 1030                 ip_unlock(port);
 1031                 port = next;
 1032         }
 1033 
 1034         /* base is not in transit */
 1035 
 1036         assert(!ip_active(base) ||
 1037                (base->ip_receiver_name != MACH_PORT_NULL) ||
 1038                (base->ip_destination == IP_NULL));
 1039         ip_unlock(base);
 1040 
 1041         return FALSE;
 1042 }
 1043 
 1044 /*
 1045  *      Routine:        ipc_port_lookup_notify
 1046  *      Purpose:
 1047  *              Make a send-once notify port from a receive right.
 1048  *              Returns IP_NULL if name doesn't denote a receive right.
 1049  *      Conditions:
 1050  *              The space must be locked (read or write) and active.
 1051  */
 1052 
 1053 ipc_port_t
 1054 ipc_port_lookup_notify(
 1055         ipc_space_t space,
 1056         mach_port_t name)
 1057 {
 1058         ipc_port_t port;
 1059         ipc_entry_t entry;
 1060 
 1061         assert(space->is_active);
 1062 
 1063         entry = ipc_entry_lookup(space, name);
 1064         if (entry == IE_NULL)
 1065                 return IP_NULL;
 1066 
 1067         if ((entry->ie_bits & MACH_PORT_TYPE_RECEIVE) == 0)
 1068                 return IP_NULL;
 1069 
 1070         port = (ipc_port_t) entry->ie_object;
 1071         assert(port != IP_NULL);
 1072 
 1073         ip_lock(port);
 1074         assert(ip_active(port));
 1075         assert(port->ip_receiver_name == name);
 1076         assert(port->ip_receiver == space);
 1077 
 1078         ip_reference(port);
 1079         port->ip_sorights++;
 1080         ip_unlock(port);
 1081 
 1082         return port;
 1083 }
 1084 
 1085 /*
 1086  *      Routine:        ipc_port_make_send
 1087  *      Purpose:
 1088  *              Make a naked send right from a receive right.
 1089  *      Conditions:
 1090  *              The port is not locked but it is active.
 1091  */
 1092 
 1093 ipc_port_t
 1094 ipc_port_make_send(
 1095         ipc_port_t port)
 1096 {
 1097         assert(IP_VALID(port));
 1098 
 1099         ip_lock(port);
 1100         assert(ip_active(port));
 1101         port->ip_mscount++;
 1102         port->ip_srights++;
 1103         ip_reference(port);
 1104         ip_unlock(port);
 1105 
 1106         return port;
 1107 }
 1108 
 1109 /*
 1110  *      Routine:        ipc_port_copy_send
 1111  *      Purpose:
 1112  *              Make a naked send right from another naked send right.
 1113  *                      IP_NULL         -> IP_NULL
 1114  *                      IP_DEAD         -> IP_DEAD
 1115  *                      dead port       -> IP_DEAD
 1116  *                      live port       -> port + ref
 1117  *      Conditions:
 1118  *              Nothing locked except possibly a space.
 1119  */
 1120 
 1121 ipc_port_t
 1122 ipc_port_copy_send(
 1123         ipc_port_t port)
 1124 {
 1125         ipc_port_t sright;
 1126 
 1127         if (!IP_VALID(port))
 1128                 return port;
 1129 
 1130         ip_lock(port);
 1131         if (ip_active(port)) {
 1132                 assert(port->ip_srights > 0);
 1133 
 1134                 ip_reference(port);
 1135                 port->ip_srights++;
 1136                 sright = port;
 1137         } else
 1138                 sright = IP_DEAD;
 1139         ip_unlock(port);
 1140 
 1141         return sright;
 1142 }
 1143 
 1144 /*
 1145  *      Routine:        ipc_port_copyout_send
 1146  *      Purpose:
 1147  *              Copyout a naked send right (possibly null/dead),
 1148  *              or if that fails, destroy the right.
 1149  *      Conditions:
 1150  *              Nothing locked.
 1151  */
 1152 
 1153 mach_port_t
 1154 ipc_port_copyout_send(
 1155         ipc_port_t sright,
 1156         ipc_space_t space)
 1157 {
 1158         mach_port_t name;
 1159 
 1160         if (IP_VALID(sright)) {
 1161                 kern_return_t kr;
 1162 
 1163                 kr = ipc_object_copyout(space, (ipc_object_t) sright,
 1164                                         MACH_MSG_TYPE_PORT_SEND, TRUE, &name);
 1165                 if (kr != KERN_SUCCESS) {
 1166                         ipc_port_release_send(sright);
 1167 
 1168                         if (kr == KERN_INVALID_CAPABILITY)
 1169                                 name = MACH_PORT_DEAD;
 1170                         else
 1171                                 name = MACH_PORT_NULL;
 1172                 }
 1173         } else
 1174                 name = (mach_port_t) sright;
 1175 
 1176         return name;
 1177 }
 1178 
 1179 /*
 1180  *      Routine:        ipc_port_release_send
 1181  *      Purpose:
 1182  *              Release a (valid) naked send right.
 1183  *              Consumes a ref for the port.
 1184  *      Conditions:
 1185  *              Nothing locked.
 1186  */
 1187 
 1188 void
 1189 ipc_port_release_send(
 1190         ipc_port_t port)
 1191 {
 1192         ipc_port_t nsrequest;
 1193 
 1194         assert(IP_VALID(port));
 1195 
 1196         ip_lock(port);
 1197         ip_release(port);
 1198 
 1199         if (!ip_active(port)) {
 1200                 ip_check_unlock(port);
 1201                 return;
 1202         }
 1203 
 1204         assert(port->ip_srights > 0);
 1205 
 1206         if ((--port->ip_srights == 0) &&
 1207             ((nsrequest = port->ip_nsrequest) != IP_NULL)) {
 1208 
 1209                 /* handle no-more-senders notification */
 1210 
 1211                 mach_port_mscount_t mscount;
 1212 
 1213                 port->ip_nsrequest = IP_NULL;
 1214                 mscount = port->ip_mscount;
 1215 
 1216                 ip_unlock(port);
 1217                 ipc_notify_no_senders(nsrequest, mscount);
 1218         }
 1219         else {
 1220                 ip_unlock(port);
 1221         }
 1222 }
 1223 
 1224 /*
 1225  *      Routine:        ipc_port_make_sonce
 1226  *      Purpose:
 1227  *              Make a naked send-once right from a receive right.
 1228  *      Conditions:
 1229  *              The port is not locked but it is active.
 1230  */
 1231 
 1232 ipc_port_t
 1233 ipc_port_make_sonce(
 1234         ipc_port_t port)
 1235 {
 1236         assert(IP_VALID(port));
 1237 
 1238         ip_lock(port);
 1239         assert(ip_active(port));
 1240         port->ip_sorights++;
 1241         ip_reference(port);
 1242         ip_unlock(port);
 1243 
 1244         return port;
 1245 }
 1246 
 1247 /*
 1248  *      Routine:        ipc_port_release_sonce
 1249  *      Purpose:
 1250  *              Release a naked send-once right.
 1251  *              Consumes a ref for the port.
 1252  *
 1253  *              In normal situations, this is never used.
 1254  *              Send-once rights are only consumed when
 1255  *              a message (possibly a send-once notification)
 1256  *              is sent to them.
 1257  *      Conditions:
 1258  *              Nothing locked except possibly a space.
 1259  */
 1260 
 1261 void
 1262 ipc_port_release_sonce(
 1263         ipc_port_t port)
 1264 {
 1265         assert(IP_VALID(port));
 1266 
 1267         ip_lock(port);
 1268         ip_release(port);
 1269 
 1270         if (!ip_active(port)) {
 1271                 ip_check_unlock(port);
 1272                 return;
 1273         }
 1274 
 1275         assert(port->ip_sorights > 0);
 1276 
 1277         port->ip_sorights--;
 1278         ip_unlock(port);
 1279 }
 1280 
 1281 /*
 1282  *      Routine:        ipc_port_release_receive
 1283  *      Purpose:
 1284  *              Release a naked (in limbo or in transit) receive right.
 1285  *              Consumes a ref for the port; destroys the port.
 1286  *      Conditions:
 1287  *              Nothing locked.
 1288  */
 1289 
 1290 void
 1291 ipc_port_release_receive(
 1292         ipc_port_t port)
 1293 {
 1294         ipc_port_t dest;
 1295 
 1296         assert(IP_VALID(port));
 1297 
 1298         ip_lock(port);
 1299         assert(ip_active(port));
 1300         assert(port->ip_receiver_name == MACH_PORT_NULL);
 1301         dest = port->ip_destination;
 1302 
 1303         ipc_port_destroy(port); /* consumes ref, unlocks */
 1304 
 1305         if (dest != IP_NULL)
 1306                 ipc_port_release(dest);
 1307 }
 1308 
 1309 /*
 1310  *      Routine:        ipc_port_alloc_special
 1311  *      Purpose:
 1312  *              Allocate a port in a special space.
 1313  *              The new port is returned with one ref.
 1314  *              If unsuccessful, IP_NULL is returned.
 1315  *      Conditions:
 1316  *              Nothing locked.
 1317  */
 1318 
 1319 ipc_port_t
 1320 ipc_port_alloc_special(
 1321         ipc_space_t space)
 1322 {
 1323 #if     NORMA_IPC
 1324 #if     i386
 1325         int ret = (&ret)[2];    /* where we were called from */
 1326 #else
 1327         int ret = (int) ipc_port_alloc_special;
 1328 #endif
 1329         extern int input_msgh_id;
 1330 #endif  /* NORMA_IPC */
 1331         ipc_port_t port;
 1332 
 1333         port = (ipc_port_t) io_alloc(IOT_PORT);
 1334         if (port == IP_NULL)
 1335                 return IP_NULL;
 1336 
 1337         io_lock_init(&port->ip_object);
 1338         port->ip_references = 1;
 1339         port->ip_object.io_bits = io_makebits(TRUE, IOT_PORT, 0);
 1340 
 1341         /*
 1342          *      The actual values of ip_receiver_name aren't important,
 1343          *      as long as they are valid (not null/dead).
 1344          */
 1345 
 1346         ipc_port_init(port, space, 1);
 1347 
 1348 #if     NORMA_IPC
 1349         port->ip_norma_spare1 = ret;
 1350         port->ip_norma_spare2 = input_msgh_id;
 1351 #endif  /* NORMA_IPC */
 1352         return port;
 1353 }
 1354 
 1355 /*
 1356  *      Routine:        ipc_port_dealloc_special
 1357  *      Purpose:
 1358  *              Deallocate a port in a special space.
 1359  *              Consumes one ref for the port.
 1360  *      Conditions:
 1361  *              Nothing locked.
 1362  */
 1363 
 1364 void
 1365 ipc_port_dealloc_special(
 1366         ipc_port_t port,
 1367         ipc_space_t space)
 1368 {
 1369         ip_lock(port);
 1370         assert(ip_active(port));
 1371         assert(port->ip_receiver_name != MACH_PORT_NULL);
 1372         assert(port->ip_receiver == space);
 1373 
 1374         /*
 1375          *      We clear ip_receiver_name and ip_receiver to simplify
 1376          *      the ipc_space_kernel check in ipc_mqueue_send.
 1377          */
 1378 
 1379         port->ip_receiver_name = MACH_PORT_NULL;
 1380         port->ip_receiver = IS_NULL;
 1381 
 1382         /*
 1383          *      For ipc_space_kernel, all ipc_port_clear_receiver does
 1384          *      is clean things up for the assertions in ipc_port_destroy.
 1385          *      For ipc_space_reply, there might be a waiting receiver.
 1386          */
 1387 
 1388         ipc_port_clear_receiver(port);
 1389         ipc_port_destroy(port);
 1390 }
 1391 
 1392 #if     MACH_IPC_COMPAT
 1393 
 1394 /*
 1395  *      Routine:        ipc_port_alloc_compat
 1396  *      Purpose:
 1397  *              Allocate a port.
 1398  *      Conditions:
 1399  *              Nothing locked.  If successful, the port is returned
 1400  *              locked.  (The caller doesn't have a reference.)
 1401  *
 1402  *              Like ipc_port_alloc, except that the new entry
 1403  *              is IE_BITS_COMPAT.
 1404  *      Returns:
 1405  *              KERN_SUCCESS            The port is allocated.
 1406  *              KERN_INVALID_TASK       The space is dead.
 1407  *              KERN_NO_SPACE           No room for an entry in the space.
 1408  *              KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
 1409  */
 1410 
 1411 kern_return_t
 1412 ipc_port_alloc_compat(
 1413         ipc_space_t space,
 1414         mach_port_t *namep,
 1415         ipc_port_t *portp)
 1416 {
 1417         ipc_port_t port;
 1418         ipc_entry_t entry;
 1419         mach_port_t name;
 1420         ipc_table_size_t its;
 1421         ipc_port_request_t table;
 1422         ipc_table_elems_t size;
 1423         ipc_port_request_index_t free, i;
 1424         kern_return_t kr;
 1425 
 1426         port = ip_alloc();
 1427         if (port == IP_NULL)
 1428                 return KERN_RESOURCE_SHORTAGE;
 1429 
 1430         its = &ipc_table_dnrequests[0];
 1431         table = it_dnrequests_alloc(its);
 1432         if (table == IPR_NULL) {
 1433                 ip_free(port);
 1434                 return KERN_RESOURCE_SHORTAGE;
 1435         }
 1436 
 1437         kr = ipc_entry_alloc(space, &name, &entry);
 1438         if (kr != KERN_SUCCESS) {
 1439                 ip_free(port);
 1440                 it_dnrequests_free(its, table);
 1441                 return kr;
 1442         }
 1443         /* space is write-locked */
 1444 
 1445         entry->ie_object = (ipc_object_t) port;
 1446         entry->ie_request = 1;
 1447         entry->ie_bits |= IE_BITS_COMPAT|MACH_PORT_TYPE_RECEIVE;
 1448 
 1449         ip_lock_init(port);
 1450         ip_lock(port);
 1451         is_write_unlock(space);
 1452 
 1453         port->ip_references = 1; /* for entry, not caller */
 1454         port->ip_bits = io_makebits(TRUE, IOT_PORT, 0);
 1455 
 1456         ipc_port_init(port, space, name);
 1457 
 1458         size = its->its_size;
 1459         assert(size > 1);
 1460         free = 0;
 1461 
 1462         for (i = 2; i < size; i++) {
 1463                 ipc_port_request_t ipr = &table[i];
 1464 
 1465                 ipr->ipr_name = MACH_PORT_NULL;
 1466                 ipr->ipr_next = free;
 1467                 free = i;
 1468         }
 1469 
 1470         table->ipr_next = free;
 1471         table->ipr_size = its;
 1472         port->ip_dnrequests = table;
 1473 
 1474         table[1].ipr_name = name;
 1475         table[1].ipr_soright = ipr_spacem(space);
 1476         is_reference(space);
 1477 
 1478         *namep = name;
 1479         *portp = port;
 1480         return KERN_SUCCESS;
 1481 }
 1482 
 1483 /*
 1484  *      Routine:        ipc_port_copyout_send_compat
 1485  *      Purpose:
 1486  *              Copyout a naked send right (possibly null/dead),
 1487  *              or if that fails, destroy the right.
 1488  *              Like ipc_port_copyout_send, except that if a
 1489  *              new translation is created it has the compat bit.
 1490  *      Conditions:
 1491  *              Nothing locked.
 1492  */
 1493 
 1494 mach_port_t
 1495 ipc_port_copyout_send_compat(
 1496         ipc_port_t sright,
 1497         ipc_space_t space)
 1498 {
 1499         mach_port_t name;
 1500 
 1501         if (IP_VALID(sright)) {
 1502                 kern_return_t kr;
 1503 
 1504                 kr = ipc_object_copyout_compat(space, (ipc_object_t) sright,
 1505                                                MACH_MSG_TYPE_PORT_SEND, &name);
 1506                 if (kr != KERN_SUCCESS) {
 1507                         ipc_port_release_send(sright);
 1508                         name = MACH_PORT_NULL;
 1509                 }
 1510         } else
 1511                 name = (mach_port_t) sright;
 1512 
 1513         return name;
 1514 }
 1515 
 1516 /*
 1517  *      Routine:        ipc_port_copyout_receiver
 1518  *      Purpose:
 1519  *              Copyout a port reference (possibly null)
 1520  *              by giving the caller his name for the port,
 1521  *              if he is the receiver.
 1522  *      Conditions:
 1523  *              Nothing locked.  Consumes a ref for the port.
 1524  */
 1525 
 1526 mach_port_t
 1527 ipc_port_copyout_receiver(
 1528         ipc_port_t port,
 1529         ipc_space_t space)
 1530 {
 1531         mach_port_t name;
 1532 
 1533         if (!IP_VALID(port))
 1534                 return MACH_PORT_NULL;
 1535 
 1536         ip_lock(port);
 1537         if (port->ip_receiver == space) {
 1538                 name = port->ip_receiver_name;
 1539                 assert(MACH_PORT_VALID(name));
 1540         } else
 1541                 name = MACH_PORT_NULL;
 1542 
 1543         ip_release(port);
 1544         ip_check_unlock(port);
 1545 
 1546         return name;
 1547 }
 1548 
 1549 #endif  /* MACH_IPC_COMPAT */
 1550 
 1551 #include <mach_kdb.h>
 1552 
 1553 
 1554 #if     MACH_KDB
 1555 #include <ddb/db_output.h>
 1556 
 1557 /*
 1558  *      Routine:        ipc_port_print
 1559  *      Purpose:
 1560  *              Pretty-print a port for kdb.
 1561  */
 1562 
 1563 void
 1564 ipc_port_print(
 1565         ipc_port_t port)
 1566 {
 1567         db_printf("port 0x%x\n", port);
 1568 
 1569         db_indent += 2;
 1570 
 1571         ipc_object_print(&port->ip_object);
 1572         db_iprintf("receiver=0x%x", port->ip_receiver);
 1573         db_printf(", receiver_name=0x%x\n", port->ip_receiver_name);
 1574 
 1575         db_iprintf("mscount=%d", port->ip_mscount);
 1576         db_printf(", srights=%d", port->ip_srights);
 1577         db_printf(", sorights=%d\n", port->ip_sorights);
 1578 
 1579         db_iprintf("nsrequest=0x%x", port->ip_nsrequest);
 1580         db_printf(", pdrequest=0x%x", port->ip_pdrequest);
 1581         db_printf(", dnrequests=0x%x\n", port->ip_dnrequests);
 1582 
 1583         db_iprintf("pset=0x%x", port->ip_pset);
 1584         db_printf(", seqno=%d", port->ip_seqno);
 1585         db_printf(", msgcount=%d", port->ip_msgcount);
 1586         db_printf(", qlimit=%d\n", port->ip_qlimit);
 1587 
 1588         db_iprintf("kmsgs=0x%x", port->ip_messages.imq_messages.ikmq_base);
 1589         db_printf(", rcvrs=0x%x", port->ip_messages.imq_threads.ithq_base);
 1590         db_printf(", sndrs=0x%x", port->ip_blocked.ithq_base);
 1591         db_printf(", kobj=0x%x\n", port->ip_kobject);
 1592 
 1593 #if     NORMA_IPC
 1594         db_iprintf("norma_uid=%x", port->ip_norma_uid);
 1595         db_printf(", dest_node=%d", port->ip_norma_dest_node);
 1596         db_printf(", stransit=%d", port->ip_norma_stransit);
 1597         db_printf(", xorefs=%d", port->ip_norma_xmm_object_refs);
 1598         db_printf(", sotransit=%d\n", port->ip_norma_sotransit);
 1599 
 1600         db_iprintf("norma_is_proxy=%d", port->ip_norma_is_proxy);
 1601         db_printf(", is_special=%d\n", port->ip_norma_is_special);
 1602 
 1603         db_iprintf("norma_atrium=0x%x", port->ip_norma_atrium);
 1604         db_printf(", queue_next=0x%x", port->ip_norma_queue_next);
 1605         db_printf(", xmm_object=0x%x", port->ip_norma_xmm_object);
 1606         db_printf(", next=0x%x\n", port->ip_norma_next);
 1607 
 1608         db_iprintf("norma_spare1=0x%x", port->ip_norma_spare1);
 1609         db_printf(", norma_spare2=0x%x", port->ip_norma_spare2);
 1610         db_printf(", norma_spare3=0x%x", port->ip_norma_spare3);
 1611         db_printf(", norma_spare4=0x%x\n", port->ip_norma_spare4);
 1612 #endif  /* NORMA_IPC */
 1613 
 1614         db_indent -=2;
 1615 }
 1616 
 1617 #endif  /* MACH_KDB */

Cache object: c91cff1764dac337743005409bd781d6


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