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_migrate.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 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_migrate.c,v $
   29  * Revision 2.6  92/03/10  16:27:43  jsb
   30  *      Merged in norma branch changes as of NORMA_MK7.
   31  *      [92/03/09  12:49:26  jsb]
   32  * 
   33  * Revision 2.5.2.4  92/02/21  11:24:29  jsb
   34  *      Don't convert migrated kmsgs to network format.
   35  *      [92/02/21  09:06:25  jsb]
   36  * 
   37  *      Changed norma_ipc_send_rright to return uid.
   38  *      [92/02/20  17:14:09  jsb]
   39  * 
   40  * Revision 2.5.2.3  92/01/21  21:51:25  jsb
   41  *      From dlb@osf.org: Fixed ip_kotype assertions and stransit logic.
   42  *      [92/01/17  14:39:09  jsb]
   43  * 
   44  *      More de-linting.
   45  *      [92/01/17  11:39:52  jsb]
   46  * 
   47  *      De-linted.
   48  *      [92/01/16  22:11:26  jsb]
   49  * 
   50  * Revision 2.5.2.2  92/01/09  18:45:27  jsb
   51  *      Corrected setting of ip_norma_stransit for migrated-from port.
   52  *      [92/01/09  13:17:34  jsb]
   53  * 
   54  *      Use remote_host_priv() instead of norma_get_special_port().
   55  *      [92/01/04  18:24:21  jsb]
   56  * 
   57  * Revision 2.5.2.1  92/01/03  16:37:33  jsb
   58  *      Use ipc_port_release instead of ip_release to allow port deallocation.
   59  *      Changed ndproxy macros to nsproxy.
   60  *      [91/12/31  21:35:52  jsb]
   61  * 
   62  *      Added code to use norma_port_tabled function.
   63  *      Added missing ip_reference when receiving a receive right.
   64  *      [91/12/31  17:19:11  jsb]
   65  * 
   66  *      Changed printfs to debugging printfs.
   67  *      Changes for IP_NORMA_REQUEST macros being renamed to ip_ndproxy{,m,p}.
   68  *      [91/12/31  12:20:36  jsb]
   69  * 
   70  *      Fixed reference counting. No-senders now works for migrated ports.
   71  *      [91/12/28  18:44:05  jsb]
   72  * 
   73  *      Added source_node parameter to norma_ipc_receive_rright so that
   74  *      we know exactly where to send norma_ipc_pull_receive request.
   75  *      [91/12/27  21:32:31  jsb]
   76  * 
   77  *      Norma_ipc_pull_receive now uses a temporary proxy for forwarded
   78  *      messages, since norma_ipc_send now uses port queue.
   79  *      Still need to wait for proxy to drain, and receive_rright still
   80  *      needs to not clobber any proxy-queued messages when moving over
   81  *      messages received on atrium.
   82  *      [91/12/27  17:07:10  jsb]
   83  * 
   84  *      A new implementation that migrates queued messages and port state
   85  *      (such as qlimit) when migrating receive rights. Contains reference
   86  *      counting workarounds; no-senders does not yet work on migrated ports.
   87  *      This implementation does not change the migrated port's uid.
   88  *      [91/12/26  18:23:25  jsb]
   89  * 
   90  *      Corrected log. Removed uses of obsolete ipc_port fields.
   91  *      Added a debugging printf in place of an assertion failure.
   92  *      [91/12/24  14:24:46  jsb]
   93  * 
   94  * Revision 2.4  91/12/13  14:00:04  jsb
   95  *      Changed debugging printf routines.
   96  * 
   97  * Revision 2.3  91/12/10  13:26:05  jsb
   98  *      Make sure a port has a uid before migrating its receive right.
   99  *      Set ip_receiver_name and ip_destination for migrated right.
  100  *      [91/12/10  11:28:53  jsb]
  101  * 
  102  * Revision 2.2  91/11/14  16:45:56  rpd
  103  *      Created.
  104  * 
  105  */
  106 /*
  107  *      File:   norma/ipc_migrate.c
  108  *      Author: Joseph S. Barrera III
  109  *      Date:   1991
  110  *
  111  *      Functions for migration of receive rights between nodes.
  112  */
  113 
  114 #include <norma_vm.h>
  115 #include <norma_ether.h>
  116 
  117 #include <vm/vm_kern.h>
  118 #include <mach/vm_param.h>
  119 #include <mach/port.h>
  120 #include <mach/message.h>
  121 #include <kern/assert.h>
  122 #include <kern/host.h>
  123 #include <kern/sched_prim.h>
  124 #include <kern/ipc_sched.h>
  125 #include <kern/ipc_kobject.h>
  126 #include <kern/zalloc.h>
  127 #include <device/device_port.h>
  128 #include <ipc/ipc_mqueue.h>
  129 #include <ipc/ipc_thread.h>
  130 #include <ipc/ipc_kmsg.h>
  131 #include <ipc/ipc_port.h>
  132 #include <ipc/ipc_pset.h>
  133 #include <ipc/ipc_space.h>
  134 #include <ipc/ipc_marequest.h>
  135 #include <norma/ipc_node.h>
  136 
  137 extern ipc_port_t norma_port_lookup();
  138 extern ipc_port_t remote_host_priv();
  139 extern unsigned long norma_new_uid();
  140 extern void norma_port_insert();
  141 extern void norma_port_remove();
  142 
  143 /*
  144  * Called whenever a receive right is sent to another node.
  145  * Port must be locked. Port must be a local port.
  146  */
  147 unsigned long
  148 norma_ipc_send_rright(port)
  149         ipc_port_t port;
  150 {
  151         unsigned long uid;
  152 
  153         /*
  154          * If this port has never been exported (for either srights or
  155          * sorights), assign it a uid and place it on the norma port list.
  156          */
  157         if (port->ip_norma_uid == 0) {
  158                 port->ip_norma_uid = norma_new_uid();
  159                 norma_port_insert(port);
  160         } else if (! norma_port_tabled(port)) {
  161                 norma_port_insert(port);
  162         }
  163         assert(! port->ip_norma_is_proxy);
  164         uid = port->ip_norma_uid;
  165 
  166         /*
  167          * The only reference after this will be one in the norma port table.
  168          */
  169         ipc_port_release(port);
  170 
  171         /*
  172          * For now, we continue to accept messages here.
  173          * We turn into a proxy only when we have a dest_node to give senders,
  174          * which will be sent by the receiver of this receive right.
  175          * (We may not yet know where dest_node is, since the message
  176          * carrying this receive right may be indirected...)
  177          */
  178         return uid;
  179 }
  180 
  181 /*
  182  * When a node receives a migrated receive right, it sends this message
  183  * to the source of the receive right. The source then starts sending
  184  * queued messages until it runs out...
  185  * Note of course that if this port is busy enough, the migration will
  186  * never happen. Not easy to fix this, but it's not a correctness problem
  187  * and I don't think it will be a problem in practice.
  188  *
  189  * This call is executed in a kserver thread context.
  190  */
  191 norma_ipc_pull_receive(host, uid, dest_node, stransit, sotransit, nsrequest,
  192                        pdrequest, dnrequest_list, dnrequest_count,
  193                        seqno, qlimit)
  194         host_t host;
  195         unsigned long uid;
  196         unsigned long dest_node;
  197         int *stransit;
  198         int *sotransit;
  199         ipc_port_t *nsrequest;
  200         ipc_port_t *pdrequest;
  201         ipc_port_t *dnrequest_list;
  202         int *dnrequest_count;
  203         int *seqno;
  204         int *qlimit;
  205 {
  206         ipc_port_t port, proxy;
  207         ipc_mqueue_t mqueue;
  208         ipc_kmsg_queue_t kmqueue;
  209         ipc_kmsg_t kmsg;
  210         int proxy_stransit;
  211 
  212         printf1("norma_ipc_pull_receive(uid=%x dest=%d)\n", uid, dest_node);
  213         /*
  214          * Guard against random bozos calling this routine.
  215          */
  216         if (host == HOST_NULL) {
  217                 return KERN_INVALID_ARGUMENT;
  218         }
  219 
  220         /*
  221          * Find the port.
  222          */
  223         port = norma_port_lookup(uid);
  224         assert(port != IP_NULL);
  225         assert(! port->ip_norma_is_proxy);
  226 
  227         /*
  228          * Create a private proxy for forwarding messages via norma_ipc_send.
  229          * XXX
  230          * Need to wait for it to drain!
  231          * XXXO
  232          * Could move initial queue of messages from port to proxy
  233          */
  234         proxy = ipc_port_alloc_special(ipc_space_remote);
  235         if (proxy == IP_NULL) {
  236                 panic("norma_ipc_pull_receive: ipc_port_alloc_special");
  237         }
  238         proxy->ip_norma_uid = uid;
  239         proxy->ip_norma_dest_node = dest_node;
  240         proxy->ip_norma_is_proxy = TRUE;
  241 
  242         /*
  243          * Migrate messages to destination.
  244          * New messages may show up. We could turn
  245          * them off, perhaps, by adjusting queue
  246          * limit, but it's probably not worth it,
  247          * and what do we do about SEND_ALWAYS?
  248          *
  249          * The lack of port locking is particularly conspicuous here.
  250          */
  251         printf1("norma_ipc_pull_receive: moving %d msgs\n", port->ip_msgcount);
  252         mqueue = &port->ip_messages;
  253         imq_lock(mqueue);
  254         assert(ipc_thread_queue_empty(&mqueue->imq_threads));
  255         kmqueue = &mqueue->imq_messages;
  256         while ((kmsg = ipc_kmsg_dequeue(kmqueue)) != IKM_NULL) {
  257                 imq_unlock(mqueue);
  258                 assert(kmsg->ikm_header.msgh_remote_port == (mach_port_t)port);
  259 
  260                 /*
  261                  * Undo norma_ipc_receive_dest so that we can compute
  262                  * local ip_srights below.
  263                  */
  264                 if (MACH_MSGH_BITS_REMOTE(kmsg->ikm_header.msgh_bits)
  265                     == MACH_MSG_TYPE_PORT_SEND) {
  266                         port->ip_srights--;
  267                         ipc_port_release(port);
  268                 }
  269 
  270                 /*
  271                  * Send the message.
  272                  */
  273                 kmsg->ikm_header.msgh_remote_port = (mach_port_t) proxy;
  274                 kmsg->ikm_header.msgh_bits |= MACH_MSGH_BITS_MIGRATED;
  275 
  276                 (void) norma_ipc_send(kmsg);
  277                 printf1("sent    kmsg 0x%x\n", kmsg);
  278                 imq_lock(mqueue);
  279         }
  280         imq_unlock(mqueue);
  281 
  282         /*
  283          * Copy out port state.
  284          * Some assertions came from ipc_port_clear_receiver.
  285          */
  286         assert(port->ip_mscount == 0);
  287         assert(port->ip_seqno == 0);
  288         assert((ip_kotype(port) == IKOT_NONE) ||
  289                (ip_kotype(port) == IKOT_PAGER));
  290         assert(port->ip_pset == IPS_NULL);
  291         *nsrequest = port->ip_nsrequest;
  292         *pdrequest = port->ip_pdrequest;
  293         *dnrequest_list = (ipc_port_t) 0;       /* XXX */
  294         *dnrequest_count = 0;                   /* XXX */
  295         *seqno = port->ip_seqno;
  296         *qlimit = port->ip_qlimit;
  297 
  298         /*
  299          * If there are any local send rights, increment stransit by 1
  300          * so that recipient of receiver right knows they exist.
  301          *
  302          * Note that any send rights associated with messages
  303          * (as destinations) have already been accounted for above.
  304          *
  305          * The true number of local send rights is
  306          * ip_srights - ip_norma_stransit.
  307          */
  308         assert(port->ip_srights >= port->ip_norma_stransit);
  309         if (port->ip_srights - port->ip_norma_stransit > 0) {
  310                 proxy_stransit = 1;
  311         } else {
  312                 proxy_stransit = 0;
  313         }
  314         *stransit = port->ip_norma_stransit + proxy_stransit;
  315 
  316         /*
  317          * Send count of non-local send-once rights.
  318          *
  319          * The true number of local send-once rights is
  320          * ip_sorights - ip_norma_sotransit.
  321          */
  322         *sotransit = port->ip_norma_sotransit - port->ip_sorights;
  323 
  324         /*
  325          * Change port into a proxy.
  326          */
  327         assert((ip_kotype(port) == IKOT_NONE) ||
  328                (ip_kotype(port) == IKOT_PAGER));
  329         port->ip_receiver = ipc_space_remote;
  330         port->ip_receiver_name = 1; /* name used by ipc_port_alloc_special */
  331 
  332         port->ip_mscount = 0;
  333         port->ip_srights -= port->ip_norma_stransit;
  334         port->ip_sorights -= port->ip_norma_sotransit;
  335         port->ip_references -= (port->ip_norma_stransit +
  336                                 port->ip_norma_sotransit);
  337 
  338         port->ip_nsrequest = ip_nsproxym(port);
  339         port->ip_pdrequest = IP_NULL;
  340         port->ip_dnrequests = IPR_NULL;
  341 
  342         port->ip_pset = IPS_NULL;
  343         port->ip_seqno = 0;
  344         port->ip_msgcount = 0;
  345         port->ip_qlimit = MACH_PORT_QLIMIT_DEFAULT;
  346 
  347         port->ip_norma_stransit = -proxy_stransit;
  348         port->ip_norma_sotransit = 0;
  349         port->ip_norma_dest_node = dest_node;
  350         port->ip_norma_is_proxy = TRUE;
  351         port->ip_norma_is_special = FALSE;
  352 
  353         /*
  354          * XXX
  355          * What do we do with:
  356          *      ip_blocked?
  357          *
  358          */
  359 
  360         /*
  361          * We could probably have done this earlier...
  362          */
  363         if (port->ip_srights == 0 && port->ip_sorights == 0) {
  364                 printf1("pull_receive: destroying 0x%x:%x\n",
  365                        port, port->ip_norma_uid);
  366                 norma_port_remove(port);
  367         }
  368 
  369         return KERN_SUCCESS;
  370 }
  371 
  372 /*
  373  * Receive a receive right.
  374  * We create a port and export it, giving the uid that we pick
  375  * to the node that sent us the receive right. We enter a forwarding
  376  * from its uid to ours in our forwarding table. We will first receive
  377  * all the messages queued at its port, then it will stop queueing
  378  * messages and instead tell nodes to send messages to us.
  379  *
  380  * What happens if we had a proxy for this uid?
  381  * Note that we still have to send messages to the old uid
  382  * until the real migration happens.
  383  *
  384  * This routine is always called from a thread context.
  385  */
  386 ipc_port_t
  387 norma_ipc_receive_rright(uid, source_node)
  388         unsigned long uid;
  389         unsigned long source_node;
  390 {
  391         kern_return_t kr;
  392         ipc_port_t port, atrium;
  393         ipc_port_t *dnrequest_list = (ipc_port_t *) 0;
  394         int dnrequest_count = 0;
  395         long stransit, sotransit;
  396 
  397         mumble("receive_rright %x\n", uid);
  398         assert(source_node != node_self());
  399         /*
  400          * Find or allocate proxy for this uid.
  401          * XXX
  402          * What keeps this port from being deallocated?
  403          * Perhaps we should hack up another sright/reference.
  404          */
  405         port = norma_port_lookup(uid);
  406         if (port == IP_NULL) {
  407                 mumble("receive_rright: new proxy\n");
  408                 port = ipc_port_alloc_special(ipc_space_remote);
  409                 if (port == IP_NULL) {
  410                         panic("receive_rright: ipc_port_alloc_special");
  411                 }
  412                 port->ip_nsrequest = ip_nsproxym(port);
  413                 port->ip_norma_uid = uid;
  414                 port->ip_norma_dest_node = source_node;
  415                 port->ip_norma_is_proxy = TRUE;
  416                 norma_port_insert(port);
  417         } else {
  418                 mumble("receive_rright: old proxy\n");
  419                 assert(ip_active(port));
  420                 assert(port->ip_norma_is_proxy);
  421         }
  422 
  423         /*
  424          * I believe there is one port reference associated with
  425          * the receive right itself. This ip_reference matches the
  426          * ipc_port_release in norma_ipc_send_rright.
  427          */
  428         ip_reference(port);
  429 
  430 
  431         /*
  432          * Allocate an atrium port to hold forwarded messages.
  433          * This gives us one queue for forwarded messages and another
  434          * for proxy usage.
  435          */
  436         atrium = ip_alloc();
  437         printf1("ip_alloc:atrium=0x%x\n", atrium);
  438         if (atrium == IP_NULL) {
  439                 panic("receive_rright: ip_alloc");
  440         }
  441         atrium->ip_receiver = ipc_space_remote;
  442         atrium->ip_msgcount = 0;
  443         ipc_kmsg_queue_init(&atrium->ip_messages.imq_messages);
  444         port->ip_norma_atrium = atrium;
  445 
  446         /*
  447          * Pull over the receive right (and all of its messages).
  448          */
  449         printf1("about to call r_norma_ipc_pull_receive\n");
  450         kr = r_norma_ipc_pull_receive(remote_host_priv(source_node),
  451                                       uid,
  452                                       node_self(),
  453                                       &stransit,
  454                                       &sotransit,
  455                                       &port->ip_nsrequest,
  456                                       &port->ip_pdrequest,
  457                                       &dnrequest_list,
  458                                       &dnrequest_count,
  459                                       &port->ip_seqno,
  460                                       &port->ip_qlimit);
  461         printf1("r_norma_ipc_pull_receive returns %d/%x\n", kr, kr);
  462         assert(kr == KERN_SUCCESS);
  463 
  464         /*
  465          * Should block in case not all messages have arrived!
  466          * (If that's possible, and I don't think it is.)
  467          */
  468 
  469         /*
  470          *
  471          */
  472         port->ip_norma_stransit = stransit + -(port->ip_norma_stransit);
  473         port->ip_norma_sotransit = sotransit + -(port->ip_norma_sotransit);
  474 
  475         /*
  476          * Set any remaining fields.
  477          * XXX Does ip_receiver's value matter here?
  478          */
  479         port->ip_norma_is_proxy = FALSE;
  480         port->ip_receiver_name = MACH_PORT_NULL;
  481         port->ip_destination = IP_NULL;
  482         port->ip_srights += port->ip_norma_stransit;
  483         port->ip_sorights += port->ip_norma_sotransit;
  484         port->ip_references += (port->ip_norma_stransit +
  485                                 port->ip_norma_sotransit);
  486 
  487         /*
  488          * Move messages from atrium to new principal.
  489          * Deallocate atrium.
  490          *
  491          * XXX
  492          * Should not lose messages still queued on proxy!
  493          */
  494         printf1("port=0x%x, ->atrium=0x%x atrium=0x%x count=%d\n",
  495                port,
  496                port->ip_norma_atrium,
  497                atrium,
  498                atrium->ip_msgcount);
  499         printf1("--- old count=%d\n", port->ip_msgcount);
  500         port->ip_msgcount = atrium->ip_msgcount;
  501         port->ip_messages.imq_messages = atrium->ip_messages.imq_messages;
  502         ip_free(atrium);
  503         port->ip_norma_atrium = IP_NULL;
  504 
  505         /*
  506          * Return port.
  507          */
  508         mumble("receive_rright: returning port 0x%x\n", port);
  509         return port;
  510 }

Cache object: ce4cdb10d1916a934bb95abb70400573


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