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/norma/ipc_transit.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,1992 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_transit.c,v $
   29  * Revision 2.6  92/03/10  16:28:25  jsb
   30  *      Merged in norma branch changes as of NORMA_MK7.
   31  *      [92/03/09  12:50:27  jsb]
   32  * 
   33  * Revision 2.5.2.4  92/02/21  11:24:59  jsb
   34  *      Norma_ipc_send_{port,soright,sright,rright} now return uids.
   35  *      Use new norma_ipc_remove_try routine.
   36  *      [92/02/20  17:13:19  jsb]
   37  * 
   38  *      Changed reference counting in norma_ipc_send_*_dest, now that they
   39  *      are called only after successful acknowledgement of message.
   40  *      Removed calls to db_show_all_uids, now that 'show all uids' exists.
   41  *      Added rearm of ip_nsrequest in norma_ipc_notify_no_senders.
   42  *      [92/02/18  08:58:56  jsb]
   43  * 
   44  *      Added checks for losing all send rights without stransit becoming zero,
   45  *      in which case we must generate a no-local-senders notification.
   46  *      [92/02/16  15:22:29  jsb]
   47  * 
   48  * Revision 2.5.2.3  92/01/21  21:52:42  jsb
   49  *      More de-linting.
   50  *      [92/01/17  11:42:23  jsb]
   51  * 
   52  *      De-linted.
   53  *      [92/01/16  22:16:55  jsb]
   54  * 
   55  * Revision 2.5.2.2  92/01/09  18:45:59  jsb
   56  *      Use quieter debugging printf when queue limit exceeded.
   57  *      [92/01/09  16:13:18  jsb]
   58  * 
   59  *      Use remote_host_priv() instead of norma_get_special_port().
   60  *      Use new routines norma_unset_special_port and {local,remote}_special.
   61  *      [92/01/04  18:20:55  jsb]
   62  * 
   63  * Revision 2.5.2.1  92/01/03  16:38:04  jsb
   64  *      Use ipc_port_release instead of ip_release to allow port deallocation.
   65  *      Added ip_reference to norma_ipc_send_migrating_dest so that
   66  *      norma_ipc_send can always release a reference.
   67  *      Changed ndproxy macros to nsproxy.
   68  *      [91/12/31  21:34:24  jsb]
   69  * 
   70  *      Added code to use norma_port_tabled function, which separates the
   71  *      issues of whether a port has a uid and whether it is accessible
   72  *      via norma_port_lookup.
   73  *      Added a hard panic on a failed lookup in norma_ipc_no_local_senders.
   74  *      Test for and ignore special uids in norma_ipc_notify_no_senders.
   75  *      [91/12/31  17:14:19  jsb]
   76  * 
   77  *      Added code to destroy active principal when no remote refs are left.
   78  *      Added forwarding and absorbtion code to norma_ipc_no_local_senders.
   79  *      Declared norma_ipc_no_local_senders void; changed returns accordingly.
   80  *      Split norma_ipc_send_no_local_senders from norma_ipc_notify_no_senders.
   81  *      Changed printfs to debugging printfs.
   82  *      [91/12/31  11:57:31  jsb]
   83  * 
   84  *      Changes for IP_NORMA_REQUEST macros being renamed to ip_ndproxy{,m,p}.
   85  *      [91/12/30  10:18:08  jsb]
   86  * 
   87  *      Test for proxies in norma_ipc_port_destroy.
   88  *      [91/12/29  21:24:18  jsb]
   89  * 
   90  *      Distinguish between dead and unfound ports in norma_ipc_receive_dest.
   91  *      [91/12/29  15:58:20  jsb]
   92  * 
   93  *      Use IP_NORMA_NSREQUEST macros. Release proxies in all cases.
   94  *      Simulate copyin in receive_migrating_dest to account for
   95  *      migrated messages.
   96  *      [91/12/28  18:05:27  jsb]
   97  * 
   98  *      Added source_node parameter to norma_ipc_receive_port so that it can
   99  *      be passed to norma_ipc_receive_rright.
  100  *      [91/12/27  21:33:34  jsb]
  101  * 
  102  *      Norma_ipc_send_migrating_dest now expects a proxy.
  103  *      [91/12/27  17:00:19  jsb]
  104  * 
  105  *      Added norma_ipc_{send,receive}_migrating_dest routines.
  106  *      Removed migrated parameter from norma_ipc_receive_dest.
  107  *      Removed migration/retarget debugging code.
  108  *      [91/12/26  20:45:44  jsb]
  109  * 
  110  *      Replaced token-based implementation with stransit_request based one.
  111  *      Added norma_ipc_send_dest. Removed norma_port_wire hack.
  112  *      Moved norma_port_list routines to norma/ipc_list.c. Corrected log.
  113  *      [91/12/24  14:23:14  jsb]
  114  * 
  115  * Revision 2.5  91/12/14  14:35:10  jsb
  116  *      Removed ipc_fields.h hack.
  117  * 
  118  * Revision 2.4  91/12/13  14:09:42  jsb
  119  *      Changed printfs to debugging printfs.
  120  * 
  121  * Revision 2.3  91/11/19  09:41:28  rvb
  122  *      Added norma_port_wire hack, to avoid reference counting bug.
  123  *      Added code to test receive right migration.
  124  *      [91/11/00            jsb]
  125  * 
  126  * Revision 2.2  91/11/14  16:46:18  rpd
  127  *      Created.
  128  */
  129 /*
  130  *      File:   norma/ipc_transit.c
  131  *      Author: Joseph S. Barrera III
  132  *      Date:   1991
  133  *
  134  *      Functions for movement of rights between nodes, excluding receive
  135  *      rights (for which see norma/ipc_migrate.c).
  136  */
  137 
  138 #include <ipc/ipc_port.h>
  139 #include <ipc/ipc_space.h>
  140 #include <kern/host.h>
  141 #include <norma/ipc_node.h>
  142 
  143 extern ipc_port_t local_special();
  144 extern ipc_port_t remote_special();
  145 extern ipc_port_t remote_host_priv();
  146 extern unsigned long norma_new_uid();
  147 
  148 extern unsigned long norma_ipc_send_port();
  149 extern unsigned long norma_ipc_send_soright();
  150 extern unsigned long norma_ipc_send_sright();
  151 extern unsigned long norma_ipc_send_rright();
  152 extern void norma_ipc_send_dest();
  153 extern void norma_ipc_send_migrating_dest();
  154 
  155 extern ipc_port_t norma_ipc_receive_port();
  156 extern ipc_port_t norma_ipc_receive_sright();
  157 extern ipc_port_t norma_ipc_receive_soright();
  158 extern ipc_port_t norma_ipc_receive_rright();
  159 extern kern_return_t norma_ipc_receive_dest();
  160 extern kern_return_t norma_ipc_receive_migrating_dest();
  161 
  162 extern ipc_port_t norma_port_lookup();
  163 extern ipc_port_t norma_port_lookup_locked();
  164 extern void norma_port_insert();
  165 extern void norma_port_remove();
  166 extern void norma_port_remove_locked();
  167 
  168 /*
  169  * Note: no decisions should be made based on who you think the receiver
  170  * will be, since it might not be who you think it will be.
  171  * (Receive rights move.) The only exception is norma_ipc_send_dest.
  172  * For example, if you have a send right and you are sending it to
  173  * who you think the receiver is, XXX finish this comment
  174  */
  175 
  176 /*
  177  * Called when a port right of any flavor is sent to another node.
  178  * Port must be unlocked. Port may be a local or proxy port.
  179  */
  180 unsigned long
  181 norma_ipc_send_port(port, type_name)
  182         ipc_port_t port;
  183         mach_msg_type_name_t type_name;
  184 {
  185         unsigned long uid;
  186 
  187         ip_lock(port);
  188         if (type_name == MACH_MSG_TYPE_PORT_SEND_ONCE) {
  189                 uid = norma_ipc_send_soright(port);
  190         } else if (type_name == MACH_MSG_TYPE_PORT_SEND) {
  191                 uid = norma_ipc_send_sright(port);
  192         } else if (type_name == MACH_MSG_TYPE_PORT_RECEIVE) {
  193                 uid = norma_ipc_send_rright(port);
  194         } else {
  195                 panic("norma_ipc_send_port: bad type %d\n", type_name);
  196         }
  197         ip_unlock(port);
  198         return uid;
  199 }
  200 
  201 /*
  202  * Called whenever a send right is sent to another node.
  203  * Port must be locked. Port may be a local or proxy port.
  204  */
  205 unsigned long
  206 norma_ipc_send_sright(port)
  207         ipc_port_t port;
  208 {
  209         unsigned long uid;
  210 
  211         /*
  212          * Port must be active.
  213          */
  214         assert(ip_active(port));
  215 
  216         if (port->ip_norma_is_proxy) {
  217                 /*
  218                  * A proxy must always have a nonpositive stransit,
  219                  * so that total stransit is no greater than the
  220                  * principal's stransit.
  221                  *
  222                  * Indeed, a proxy must have a negative stransit as
  223                  * long as it holds send rights, so that the principal
  224                  * can trust its stransit (in the face of proxies
  225                  * sending send rights to it).
  226                  * If we're here, then we must have send rights.
  227                  */
  228                 mumble("norma_ipc_send_sright: sender sending sright\n");
  229                 assert(port->ip_srights > 0);
  230                 assert(port->ip_norma_stransit < 0);
  231                 if (port->ip_srights == 1) {
  232                         /*
  233                          * We are about to lose all send rights.
  234                          * It is therefore okay to let stransit
  235                          * drop to zero, as an implicit no-local-senders
  236                          * notification. (If stransit does not drop
  237                          * to zero, then we have to do an explicit
  238                          * no-local-senders notification.) This works
  239                          * since either we are sending to the receiver,
  240                          * who will be able to figure it out (since
  241                          * he will decr stransit accordingly), or
  242                          * we are not sending to receiver, in which
  243                          * case no-senders isn't true.
  244                          */
  245                 } else {
  246                         /*
  247                          * We will still retain some send rights,
  248                          * and must therefore keep stransit negative.
  249                          */
  250                         assert(port->ip_srights > 1);
  251                         assert(port->ip_norma_stransit <= -1);
  252                         if (port->ip_norma_stransit == -1) {
  253                                 norma_ipc_stransit_wait(port);
  254                         }
  255                 }
  256                 port->ip_norma_stransit++;
  257                 assert(port->ip_norma_stransit <= 0);
  258 
  259                 /*
  260                  * Save uid
  261                  */
  262                 uid = port->ip_norma_uid;
  263 
  264                 /*
  265                  * Release send right. If this is the last send right,
  266                  * and stransit is not zero, then we must generate
  267                  * an explicit no-local-senders notification.
  268                  */
  269                 if (port->ip_srights == 1 && port->ip_norma_stransit != 0) {
  270                         ipc_port_release_send(port);
  271                 } else {
  272                         port->ip_srights--;
  273                         ipc_port_release(port);
  274                 }
  275         } else {
  276                 /*
  277                  * The principal can always immediately increase stransit.
  278                  * He does not release send right here, but rather when
  279                  * stransit comes back via no-local-senders notification.
  280                  * This allows the principal's send right count to be an
  281                  * upper bound on the true number of send rights in the
  282                  * system, which among other things keeps the a lack of
  283                  * senders on the principal's node from triggering a
  284                  * premature no-senders notification.
  285                  */
  286                 assert(port->ip_norma_stransit >= 0);
  287                 port->ip_norma_stransit++;
  288                 
  289                 /*
  290                  * If this port has never been exported, assign it a uid
  291                  * and place it on the norma port list.
  292                  */
  293                 if ((uid = port->ip_norma_uid) == 0) {
  294                         uid = port->ip_norma_uid = norma_new_uid();
  295                         norma_port_insert(port);
  296                 } else if (! norma_port_tabled(port)) {
  297                         norma_port_insert(port);
  298                 }
  299                 assert(! port->ip_norma_is_proxy);
  300         }
  301         assert(uid != 0);
  302         return uid;
  303 }
  304 
  305 /*
  306  * Called whenever a send-once right is sent to another node.
  307  * Port must be locked. Port must be a local port.
  308  */
  309 unsigned long
  310 norma_ipc_send_soright(port)
  311         ipc_port_t port;
  312 {
  313         unsigned long uid;
  314 
  315         /*
  316          * Port must be active.
  317          */
  318         assert(ip_active(port));
  319 
  320         if (port->ip_norma_is_proxy) {
  321                 /*
  322                  * Save uid
  323                  */
  324                 uid = port->ip_norma_uid;
  325 
  326                 /*
  327                  * A proxy releases the send-once right.
  328                  * This case occurs when moving a send-once right
  329                  * to another node.
  330                  */
  331                 port->ip_sorights--;
  332                 ipc_port_release(port);
  333                 norma_port_remove_try(port);
  334         } else {
  335                 /*
  336                  * The principal does not release send-once right here, but
  337                  * rather when the send-once right is used as a destination
  338                  * (of either a reply or a send-once notification).
  339                  * This allows the principal's send-once right count to
  340                  * be an accurate count of the true number of send-once
  341                  * rights in the system.
  342                  */
  343                 port->ip_norma_sotransit++;
  344 
  345                 /*
  346                  * If this port has never been exported, assign it a uid
  347                  * and place it on the norma port list.
  348                  */
  349                 if ((uid = port->ip_norma_uid) == 0) {
  350                         uid = port->ip_norma_uid = norma_new_uid();
  351                         norma_port_insert(port);
  352                 } else if (! norma_port_tabled(port)) {
  353                         norma_port_insert(port);
  354                 }
  355                 assert(! port->ip_norma_is_proxy);
  356         }
  357         assert(uid != 0);
  358         return uid;
  359 }
  360 
  361 void
  362 norma_ipc_send_dest(port, type_name)
  363         ipc_port_t port;
  364         mach_msg_type_name_t type_name;
  365 {
  366         /*
  367          * ipc_kmsg_copyin_header asserts that this is so.
  368          */
  369         assert(type_name == MACH_MSG_TYPE_PORT_SEND ||
  370                type_name == MACH_MSG_TYPE_PORT_SEND_ONCE);
  371 
  372         /*
  373          * This port must be a proxy!
  374          */
  375         assert(port->ip_norma_uid != 0);
  376         assert(port->ip_norma_is_proxy);
  377 
  378         /*
  379          * This is different from norma_ipc_send_port, because we know
  380          * we are sending to receiver. We just need to undo refcount
  381          * changes performed by copyin; we don't need to modify
  382          * stransit, and neither does the receiver. However, if we lose
  383          * all send rights here (e.g., from a move_send destination),
  384          * then we must generate an explicit no-local-senders notification.
  385          */
  386         if (type_name == MACH_MSG_TYPE_PORT_SEND) {
  387                 if (port->ip_srights == 1) {
  388                         printf1("norma_ipc_send_dest.s: release %x\n", port);
  389                         ipc_port_release_send(port);
  390                         printf1("norma_ipc_send_dest.s: released %x\n", port);
  391                 } else {
  392                         assert(port->ip_srights > 1);
  393                         ip_release(port);
  394                         port->ip_srights--;
  395                 }
  396         } else {
  397                 ip_release(port);
  398                 port->ip_sorights--;
  399                 norma_port_remove_try(port);
  400         }
  401 }
  402 
  403 void
  404 norma_ipc_send_migrating_dest(port)
  405         ipc_port_t port;
  406 {
  407         /*
  408          * This port must be a proxy with a uid.
  409          */
  410         assert(port->ip_norma_uid != 0);
  411         assert(port->ip_norma_is_proxy);
  412         assert(port->ip_norma_dest_node != node_self());
  413 }
  414 
  415 /*
  416  * Called when a port right of any flavor is received from another node.
  417  */
  418 ipc_port_t
  419 norma_ipc_receive_port(uid, type_name, source_node)
  420         unsigned long uid;
  421         mach_msg_type_name_t type_name;
  422         unsigned long source_node;
  423 {
  424         /*
  425          * A null uid maps to a null port.
  426          */
  427         if (uid == 0) {
  428                 return IP_NULL;
  429         }
  430 
  431         if (type_name == MACH_MSG_TYPE_PORT_SEND_ONCE) {
  432                 return norma_ipc_receive_soright(uid);
  433         } else if (type_name == MACH_MSG_TYPE_PORT_SEND) {
  434                 return norma_ipc_receive_sright(uid);
  435         } else if (type_name == MACH_MSG_TYPE_PORT_RECEIVE) {
  436                 return norma_ipc_receive_rright(uid, source_node);
  437         } else {
  438                 panic("norma_ipc_receive_port: bad type %d\n", type_name);
  439                 return IP_NULL;
  440         }
  441 }
  442 
  443 /*
  444  * Find or create proxy for given uid, and add a send right reference.
  445  */
  446 ipc_port_t
  447 norma_ipc_receive_sright(uid)
  448         unsigned long uid;
  449 {
  450         ipc_port_t port;
  451 
  452         /*
  453          * Try to find the port.
  454          */
  455         port = norma_port_lookup(uid);
  456 
  457         /*
  458          * If we don't have a port, then we must create a proxy.
  459          */
  460         if (port == IP_NULL) {
  461                 assert(IP_NORMA_NODE(uid) != node_self());
  462                 port = ipc_port_alloc_special(ipc_space_remote);
  463                 if (port == IP_NULL) {
  464                         panic("receive_sright: ipc_port_alloc_special");
  465                 }
  466                 port->ip_nsrequest = ip_nsproxym(port);
  467                 port->ip_norma_stransit = -1;
  468                 port->ip_srights = 1;
  469                 port->ip_norma_uid = uid;
  470                 port->ip_norma_dest_node = IP_NORMA_NODE(uid);
  471                 port->ip_norma_is_proxy = TRUE;
  472                 norma_port_insert(port);
  473                 return port;
  474         }
  475 
  476         /*
  477          * Is it a proxy?
  478          */
  479         if (port->ip_norma_is_proxy) {
  480                 /*
  481                  * Just adjust srights and stransit.
  482                  */
  483                 assert(port->ip_nsrequest != IP_NULL);
  484                 assert(ip_nsproxyp(port->ip_nsrequest));
  485                 assert(ip_active(port)); /* XXX How could it be otherwise? */
  486                 port->ip_srights++;
  487                 port->ip_norma_stransit--;
  488                 ip_reference(port);
  489                 return port;
  490         }
  491 
  492         /*
  493          * It is a principal. Is it dead?
  494          */
  495         if (! ip_active(port)) {
  496                 printf1("norma_ipc_receive_sright: dead port %x\n", uid);
  497                 /*
  498                  * Adjust stransit, since sender used up an stransit in
  499                  * sending to us. This may enable us to free the port.
  500                  * Consume immediately the sright associated with stransit.
  501                  */
  502                 assert(port->ip_norma_stransit > 0);
  503                 assert(port->ip_srights > 0);
  504                 port->ip_norma_stransit--;
  505                 port->ip_srights--;
  506                 norma_port_remove_try(port);
  507                 return IP_DEAD;
  508         }
  509 
  510         /*
  511          * It is a living principal.
  512          * Decrement stransit, since sender incremented stransit,
  513          * since it could not be sure that we were still the principal.
  514          * Consume sright that was associated with stransit.
  515          */
  516         assert(port->ip_srights > 0);
  517         assert(port->ip_norma_stransit > 0);
  518         port->ip_norma_stransit--;
  519         return port;
  520 }
  521 
  522 /*
  523  * Find or create proxy for given uid, and add a send-once right reference.
  524  */
  525 ipc_port_t
  526 norma_ipc_receive_soright(uid)
  527         unsigned long uid;
  528 {
  529         ipc_port_t port;
  530 
  531         /*
  532          * Try to find the port.
  533          */
  534         port = norma_port_lookup(uid);
  535 
  536         /*
  537          * If we don't have a port, then we must create a proxy.
  538          */
  539         if (port == IP_NULL) {
  540                 assert(IP_NORMA_NODE(uid) != node_self());
  541                 port = ipc_port_alloc_special(ipc_space_remote);
  542                 if (port == IP_NULL) {
  543                         panic("receive_soright: ipc_port_alloc_special");
  544                 }
  545                 port->ip_nsrequest = ip_nsproxym(port);
  546                 port->ip_sorights = 1;
  547                 port->ip_norma_uid = uid;
  548                 port->ip_norma_dest_node = IP_NORMA_NODE(uid);
  549                 port->ip_norma_is_proxy = TRUE;
  550                 norma_port_insert(port);
  551                 return port;
  552         }
  553 
  554         /*
  555          * Is it a proxy?
  556          */
  557         if (port->ip_norma_is_proxy) {
  558                 /*
  559                  * Just adjust sorights.
  560                  * We increment, because we are inheriting a remote count.
  561                  */
  562                 assert(port->ip_nsrequest != IP_NULL);
  563                 assert(ip_nsproxyp(port->ip_nsrequest));
  564                 assert(ip_active(port)); /* XXX How could it be otherwise? */
  565                 port->ip_sorights++;
  566                 ip_reference(port);
  567                 return port;
  568         }
  569 
  570         /*
  571          * It is a principal. Is it dead?
  572          */
  573         if (! ip_active(port)) {
  574                 /*
  575                  * We decrement sorights, because it has come home.
  576                  */
  577                 printf1("norma_ipc_receive_soright: dead port %x\n", uid);
  578                 port->ip_sorights--;
  579                 port->ip_norma_sotransit--;
  580                 assert((long) port->ip_sorights >= 0);
  581                 assert(port->ip_norma_sotransit >= 0);
  582                 norma_port_remove_try(port);
  583                 return IP_DEAD;
  584         }
  585 
  586         /*
  587          * It is a living principal.
  588          * Leave sorights alone; we consume the one we left for remote node.
  589          */
  590         port->ip_norma_sotransit--;
  591         assert((long) port->ip_sorights >= 0);
  592         assert(port->ip_norma_sotransit >= 0);
  593         ip_reference(port);
  594         return port;
  595 }
  596 
  597 /*
  598  * Find destination port for given uid.
  599  * XXX need to make safe to call from interrupt level!
  600  * XXX perhaps make_send/sonce should be deferred? (XXX no longer make_send)
  601  */
  602 kern_return_t
  603 norma_ipc_receive_dest(uid, type_name, remote_port)
  604         unsigned long uid;
  605         mach_msg_type_name_t type_name;
  606         ipc_port_t *remote_port;
  607 {
  608         ipc_port_t port;
  609 
  610         /*
  611          * This can only be some flavor of send or send-once right.
  612          */
  613         assert(type_name == MACH_MSG_TYPE_PORT_SEND ||
  614                type_name == MACH_MSG_TYPE_PORT_SEND_ONCE);
  615 
  616         /*
  617          * Handle the special port case.
  618          */
  619         if (IP_NORMA_SPECIAL(uid)) {
  620                 if (IP_NORMA_NODE(uid) == node_self()) {
  621                         *remote_port = local_special(IP_NORMA_LID(uid));
  622                 } else {
  623                         *remote_port = remote_special(IP_NORMA_NODE(uid),
  624                                                       IP_NORMA_LID(uid));
  625                 }
  626                 return KERN_SUCCESS;
  627         }
  628 
  629         /*
  630          * Find associated port.
  631          */
  632         port = norma_port_lookup_locked(uid);
  633         if (port == IP_NULL) {
  634                 /*
  635                  * Must be an invalid uid; otherwise, we would have
  636                  * found something with norma_port_lookup.
  637                  */
  638                 panic("norma_ipc_receive_dest: invalid uid %x!\n", uid);
  639                 return KERN_INVALID_NAME;
  640         }
  641 
  642         /*
  643          * Check to see whether we are the correct receiver for this message.
  644          * If not, try to say where the correct receiver would be.
  645          */
  646         if (port->ip_norma_is_proxy) {
  647                 /*
  648                  * Tell sender to use new node.
  649                  */
  650                 printf1("norma_ipc_receive_dest: migrated dest %d -> %d\n",
  651                        node_self(), port->ip_norma_dest_node);
  652                 * (unsigned long *) remote_port = port->ip_norma_dest_node;
  653                 return KERN_NOT_RECEIVER;
  654         }
  655 
  656         /*
  657          * We have a local principal. Make sure it is active.
  658          */
  659         if (! ip_active(port)) {
  660                 /*
  661                  * If it is not active, it is a dead port, kept alive
  662                  * by remote send and send-once references.
  663                  */
  664                 printf1("norma_ipc_receive_dest: dead port %x\n", uid);
  665                 if (type_name == MACH_MSG_TYPE_PORT_SEND_ONCE) {
  666                         assert(port->ip_sorights > 0);
  667                         port->ip_norma_sotransit--;
  668                         port->ip_sorights--;
  669                         if (port->ip_sorights == 0 &&
  670                             port->ip_norma_stransit == 0) {
  671                                 /*
  672                                  * The last outside send/send-once reference
  673                                  * has been consumed; release port.
  674                                  */
  675                                 printf1("norma_ipc_receive_dest: send_once: ");
  676                                 printf1("releasing port %x\n", port);
  677                                 norma_port_remove_locked(port);
  678                         }
  679                 }
  680                 return KERN_INVALID_RIGHT;
  681         }
  682         
  683         /*
  684          * Check queue limit.
  685          */
  686 #if 1
  687         /*
  688          * There are locking issues here that need to be adressed.
  689          * In the meantime, don't even bother looking at ip_msgcount.
  690          */
  691 #else
  692         if (port->ip_msgcount >= port->ip_qlimit) {
  693                 mumble("norma_ipc_receive_dest: queue=%d >= limit=%d uid=%x\n",
  694                        port->ip_msgcount, port->ip_qlimit, uid);
  695                 /*
  696                  * XXX
  697                  * Should tell sender to block, and remember to wake him up.
  698                  */
  699         }
  700 #endif
  701         
  702         /*
  703          * Return port. Simulate copyin.
  704          */
  705         if (type_name == MACH_MSG_TYPE_PORT_SEND) {
  706                 /*
  707                  * Create a send right reference.
  708                  */
  709                 ip_reference(port);
  710                 port->ip_srights++;
  711         } else {
  712                 /*
  713                  * Consume a preexisting send-once reference,
  714                  * created when send-once right was sent to current sender.
  715                  */
  716                 assert(type_name == MACH_MSG_TYPE_PORT_SEND_ONCE);
  717         }
  718         *remote_port = port;
  719         return KERN_SUCCESS;
  720 }
  721 
  722 norma_ipc_receive_migrating_dest(uid, type_name, remote_port)
  723         unsigned long uid;
  724         mach_msg_type_name_t type_name;
  725         ipc_port_t *remote_port;
  726 {
  727         ipc_port_t port;
  728 
  729         assert(! IP_NORMA_SPECIAL(uid));
  730 
  731         /*
  732          * Find associated port.
  733          * It must be a proxy with an atrium.
  734          */
  735         port = norma_port_lookup_locked(uid);
  736         if (port == IP_NULL) {
  737                 panic("norma_ipc_receive_migrating_dest: invalid uid %x!\n",
  738                       uid);
  739                 return KERN_INVALID_RIGHT;
  740         }
  741         if (! port->ip_norma_is_proxy) {
  742                 panic("norma_ipc_receive_migrating_dest: %x not proxy!\n",
  743                       uid);
  744                 return KERN_INVALID_RIGHT;
  745         }
  746         if (port->ip_norma_atrium == IP_NULL) {
  747                 panic("norma_ipc_receive_migrating_dest: %x not migrating!\n",
  748                       uid);
  749                 return KERN_INVALID_RIGHT;
  750         }
  751         assert(ip_active(port));
  752 
  753         /*
  754          * Return port. Simulate copyin.
  755          */
  756         if (type_name == MACH_MSG_TYPE_PORT_SEND) {
  757                 /*
  758                  * Create a send right reference.
  759                  */
  760                 ip_reference(port);
  761                 port->ip_srights++;
  762         } else {
  763                 /*
  764                  * Consume a preexisting send-once reference,
  765                  * created when send-once right was sent to current sender.
  766                  */
  767                 assert(type_name == MACH_MSG_TYPE_PORT_SEND_ONCE);
  768         }
  769         *remote_port = port;
  770         return KERN_SUCCESS;
  771 }
  772 
  773 /*
  774  * Called from ipc_port_destroy.
  775  */
  776 norma_ipc_port_destroy(port)
  777         ipc_port_t port;
  778 {
  779         /*
  780          * Don't bother with non-norma-affected ports.
  781          */
  782 #if 0
  783         if (port->ip_norma_uid == 0) {
  784                 return;
  785         }
  786 #else
  787         /*
  788          * A port can be tabled but not have a uid
  789          * if external refcounts dropped to zero.
  790          */
  791         if (! norma_port_tabled(port)) {
  792                 return;
  793         }
  794 #endif
  795 
  796         /*
  797          * Don't deal with proxies here. The only way that this could be
  798          * a proxy is if norma_ipc_proxy_destroy called ipc_port_destroy,
  799          * in which case we'll let norma_ipc_proxy_destroy deal with it.
  800          *
  801          * Proxies are destroyed in this module, either in send_dest
  802          * or send_soright for send-once rights, or in
  803          * norma_ipc_notify_no_local_senders for send rights.
  804          */
  805         if (port->ip_norma_is_proxy) {
  806                 return;
  807         }
  808 
  809         /*
  810          * This routine cannot be called on a migrating port, since
  811          * the receive right is held by the kernel.
  812          * However, it's hard for us to tell if a port is migrating,
  813          * and thus hard to assert anything here.
  814          */
  815 
  816         /*
  817          * If this is a special port (principal), remove it from the
  818          * special port table. Note that it may be in more than one slot.
  819          * Release send right reference for each slot.
  820          *
  821          * No-senders is never true as long as a port is in the list,
  822          * since the list holds a send right for each occurance of the
  823          * port in the list.
  824          */
  825         if (port->ip_norma_is_special) {
  826                 norma_unset_special_port(port);
  827                 assert(port->ip_norma_is_special == FALSE);
  828         }
  829 
  830         /*
  831          * Remove the port from the norma port list, but
  832          * only if there are no outstanding references.
  833          * If there are, we will release the port when they
  834          * are all used up. We detect this when we receive
  835          * a (dead) send-once right or when we receive
  836          * a no_local_senders notification.
  837          *
  838          * If we destroyed the port immediately despite
  839          * outstanding references, someone might send us
  840          * a send right to it, and we would blindly create
  841          * a proxy instead of realizing that the port was dead.
  842          *
  843          * Now of course, we should also at that point notice
  844          * that IP_NORMA_NODE(uid) is node_self() and that we
  845          * should have some knowledge of the port. We might be
  846          * able to take advantage of this fact.
  847          *
  848          * Normally, we can check ip_srights intead of ip_norma_stransit.
  849          * However, we are about to forcibly trash all local srights...
  850          * urg. see ipc_port_destroy for ordering to see what I mean.
  851          * XXX fix this comment
  852          */
  853         norma_port_remove_try(port);
  854         /* XXX port->ip_norma_uid = 0; ??? used to do this if we removed it */
  855 }
  856 
  857 void
  858 norma_ipc_send_no_local_senders(dest_node, uid, stransit)
  859         unsigned long dest_node;
  860         unsigned long uid;
  861         int stransit;
  862 {
  863         kern_return_t kr;
  864 
  865         if (IP_NORMA_SPECIAL(uid)) {
  866                 return;
  867         }
  868         kr = r_norma_ipc_no_local_senders(remote_host_priv(dest_node), uid,
  869                                           stransit);
  870         if (kr != KERN_SUCCESS) {
  871                 panic("norma_ipc_notify_no_senders: no_local_senders: %d/%x\n",
  872                       kr, kr);
  873         }
  874 }
  875 
  876 void
  877 norma_ipc_notify_no_senders(port)
  878         ipc_port_t port;
  879 {
  880         unsigned long dest_node;
  881         unsigned long uid;
  882         int stransit;
  883 
  884         assert(port->ip_nsrequest == IP_NULL);
  885         assert(port->ip_norma_is_proxy);
  886         assert(port->ip_norma_stransit < 0);
  887         uid = port->ip_norma_uid;
  888         dest_node = port->ip_norma_dest_node;
  889         stransit = -port->ip_norma_stransit;
  890         port->ip_norma_stransit = 0;
  891         printf1("notify no_senders(0x%x:%x) s=0 so=%d\n",
  892                port, uid, port->ip_sorights);
  893         assert(port->ip_srights == 0);
  894 
  895         /*
  896          * There are no local send rights...
  897          * if there are also no local send-once rights, then destroy
  898          * the proxy; otherwise, rearm nsrequest in case this proxy
  899          * acquires send rights in the future.
  900          */
  901         if (port->ip_sorights == 0) {
  902                 norma_port_remove(port);
  903         } else {
  904                 port->ip_nsrequest = ip_nsproxym(port);
  905         }
  906         if (IP_NORMA_SPECIAL(uid)) {
  907                 /*
  908                  * Don't generate no-senders notifications for special uids.
  909                  * Remote node wouldn't even know what to do with one.
  910                  */
  911                 printf1("norma_ipc_notify_no_senders: special port %x\n", uid);
  912                 return;
  913         }
  914         norma_ipc_send_no_local_senders(dest_node, uid, stransit);
  915 }
  916 
  917 void
  918 norma_ipc_no_local_senders(host_priv, uid, stransit)
  919         host_t host_priv;
  920         unsigned long uid;
  921         int stransit;
  922 {
  923         ipc_port_t port;
  924 
  925         if (host_priv == HOST_NULL) {
  926                 fret("norma_ipc_no_local_senders: invalid host\n");
  927                 return;
  928         }
  929         port = norma_port_lookup(uid);
  930         if (port == IP_NULL) {
  931                 if (IP_NORMA_NODE(uid) == node_self()) {
  932                         /*
  933                          * XXX
  934                          * This can happen if this node rebooted.
  935                          * Otherwise, it is supposed to have saved
  936                          * a port for forwarding purposes.
  937                          */
  938                         printf("norma_ipc_no_local_senders: failed lookup!\n");
  939                         panic("uid %x stransit %d\n", uid, stransit);
  940                 } else {
  941                         fret("norma_ipc_no_local_senders: trying node %d\n",
  942                              IP_NORMA_NODE(uid));
  943                         norma_ipc_send_no_local_senders(IP_NORMA_NODE(uid),
  944                                                         uid, stransit);
  945                 }
  946                 return;
  947         }
  948         printf1("norma_ipc_no_local_senders(uid=%x port=0x%x stransit=%d)\n",
  949              uid, port, stransit);
  950         if (port->ip_norma_is_proxy) {
  951                 /*
  952                  * Instead of forwarding, we simply absorb the stransit.
  953                  */
  954                 fret("norma_ipc_no_local_senders: absorb(%d) %x!\n",
  955                      stransit, port);
  956                 assert(port->ip_srights > 0 || port->ip_sorights > 0);
  957                 port->ip_norma_stransit -= stransit;
  958                 return;
  959         }
  960         assert(stransit > 0);
  961         assert(port->ip_norma_stransit >= stransit);
  962         assert(port->ip_srights >= stransit);
  963         port->ip_norma_stransit -= stransit;
  964         port->ip_srights -= (stransit - 1);
  965         port->ip_references -= (stransit - 1);
  966         if (ip_active(port)) {
  967                 ipc_port_release_send(port);
  968         } else {
  969                 port->ip_srights--;
  970                 port->ip_references--;
  971         }
  972         norma_port_remove_try(port);
  973 }
  974 
  975 /*
  976  * An obvious improvement here would be to somehow, in the initial
  977  * sending of send rights from receiver to sender, pass along some
  978  * initial negative stransit. The current scheme is a lose for send
  979  * rights that are used as capabilities, i.e., passed in the body
  980  * of the message instead of being used as a destination.
  981  */
  982 kern_return_t
  983 norma_ipc_stransit_wait(port)
  984         ipc_port_t port;
  985 {
  986         kern_return_t kr;
  987         int stransit;
  988         
  989         kr = r_norma_ipc_stransit_request(remote_host_priv(port->
  990                                                            ip_norma_dest_node),
  991                                           port->ip_norma_uid, &stransit);
  992         if (kr != KERN_SUCCESS) {
  993                 panic("norma_ipc_stransit_wait: stransit_request: %d/%x\n",
  994                       kr, kr);
  995                 return;
  996         }
  997         mumble("ip_stransit_wait: stransit += %d\n", stransit);
  998         port->ip_norma_stransit -= stransit;
  999 }
 1000 
 1001 kern_return_t
 1002 norma_ipc_stransit_request(host_priv, uid, stransitp)
 1003         host_t host_priv;
 1004         unsigned long uid;
 1005         int *stransitp;
 1006 {
 1007         ipc_port_t port;
 1008 
 1009         mumble("norma_ipc_stransit_request: called\n");
 1010         if (host_priv == HOST_NULL) {
 1011                 fret("norma_ipc_stransit_request: invalid host\n");
 1012                 return KERN_INVALID_HOST;
 1013         }
 1014         port = norma_port_lookup(uid);
 1015         if (port == IP_NULL) {
 1016                 fret("norma_ipc_stransit_request: failed lookup %x\n",
 1017                      uid);
 1018                 return KERN_INVALID_NAME;
 1019         }
 1020         if (port->ip_norma_is_proxy) {
 1021                 /* XXX should probably forward to current principal */
 1022                 fret("norma_ipc_stransit_request: is proxy\n");
 1023                 return KERN_INVALID_RIGHT;
 1024         }
 1025         if (! ip_active(port)) {
 1026                 fret("norma_ipc_stransit_request: is not active\n");
 1027                 return KERN_FAILURE;
 1028         }
 1029         *stransitp = 10000;
 1030         port->ip_norma_stransit += *stransitp;
 1031         port->ip_srights += *stransitp;
 1032         port->ip_references += *stransitp;
 1033         mumble("norma_ipc_stransit_request: success\n");
 1034         return KERN_SUCCESS;
 1035 }

Cache object: 5981ceff8bf43412360d3b48e7f042a7


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