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

Cache object: b0a6eb5941ea205b460367ce7cbb79bf


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