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_pset.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_pset.c,v $
   29  * Revision 2.7  92/08/03  17:35:19  jfriedl
   30  *      removed silly prototypes
   31  *      [92/08/02            jfriedl]
   32  * 
   33  * Revision 2.6  92/05/21  17:11:23  jfriedl
   34  *      tried prototypes.
   35  *      [92/05/20            jfriedl]
   36  * 
   37  * Revision 2.5  91/05/14  16:35:47  mrt
   38  *      Correcting copyright
   39  * 
   40  * Revision 2.4  91/02/05  17:23:15  mrt
   41  *      Changed to new Mach copyright
   42  *      [91/02/01  15:50:24  mrt]
   43  * 
   44  * Revision 2.3  90/11/05  14:29:47  rpd
   45  *      Use new ips_reference and ips_release.
   46  *      [90/10/29            rpd]
   47  * 
   48  * Revision 2.2  90/06/02  14:51:19  rpd
   49  *      Created for new IPC.
   50  *      [90/03/26  21:01:53  rpd]
   51  * 
   52  */
   53 /*
   54  *      File:   ipc/ipc_pset.c
   55  *      Author: Rich Draves
   56  *      Date:   1989
   57  *
   58  *      Functions to manipulate IPC port sets.
   59  */
   60 
   61 #include <mach/port.h>
   62 #include <mach/kern_return.h>
   63 #include <mach/message.h>
   64 #include <ipc/ipc_mqueue.h>
   65 #include <ipc/ipc_object.h>
   66 #include <ipc/ipc_pset.h>
   67 #include <ipc/ipc_right.h>
   68 #include <ipc/ipc_space.h>
   69 
   70 
   71 /*
   72  *      Routine:        ipc_pset_alloc
   73  *      Purpose:
   74  *              Allocate a port set.
   75  *      Conditions:
   76  *              Nothing locked.  If successful, the port set is returned
   77  *              locked.  (The caller doesn't have a reference.)
   78  *      Returns:
   79  *              KERN_SUCCESS            The port set is allocated.
   80  *              KERN_INVALID_TASK       The space is dead.
   81  *              KERN_NO_SPACE           No room for an entry in the space.
   82  *              KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
   83  */
   84 
   85 kern_return_t
   86 ipc_pset_alloc(space, namep, psetp)
   87         ipc_space_t space;
   88         mach_port_t *namep;
   89         ipc_pset_t *psetp;
   90 {
   91         ipc_pset_t pset;
   92         mach_port_t name;
   93         kern_return_t kr;
   94 
   95         kr = ipc_object_alloc(space, IOT_PORT_SET,
   96                               MACH_PORT_TYPE_PORT_SET, 0,
   97                               &name, (ipc_object_t *) &pset);
   98         if (kr != KERN_SUCCESS)
   99                 return kr;
  100         /* pset is locked */
  101 
  102         pset->ips_local_name = name;
  103         ipc_mqueue_init(&pset->ips_messages);
  104 
  105         *namep = name;
  106         *psetp = pset;
  107         return KERN_SUCCESS;
  108 }
  109 
  110 /*
  111  *      Routine:        ipc_pset_alloc_name
  112  *      Purpose:
  113  *              Allocate a port set, with a specific name.
  114  *      Conditions:
  115  *              Nothing locked.  If successful, the port set is returned
  116  *              locked.  (The caller doesn't have a reference.)
  117  *      Returns:
  118  *              KERN_SUCCESS            The port set is allocated.
  119  *              KERN_INVALID_TASK       The space is dead.
  120  *              KERN_NAME_EXISTS        The name already denotes a right.
  121  *              KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
  122  */
  123 
  124 kern_return_t
  125 ipc_pset_alloc_name(space, name, psetp)
  126         ipc_space_t space;
  127         mach_port_t name;
  128         ipc_pset_t *psetp;
  129 {
  130         ipc_pset_t pset;
  131         kern_return_t kr;
  132 
  133         kr = ipc_object_alloc_name(space, IOT_PORT_SET,
  134                                    MACH_PORT_TYPE_PORT_SET, 0,
  135                                    name, (ipc_object_t *) &pset);
  136         if (kr != KERN_SUCCESS)
  137                 return kr;
  138         /* pset is locked */
  139 
  140         pset->ips_local_name = name;
  141         ipc_mqueue_init(&pset->ips_messages);
  142 
  143         *psetp = pset;
  144         return KERN_SUCCESS;
  145 }
  146 
  147 /*
  148  *      Routine:        ipc_pset_add
  149  *      Purpose:
  150  *              Puts a port into a port set.
  151  *              The port set gains a reference.
  152  *      Conditions:
  153  *              Both port and port set are locked and active.
  154  *              The port isn't already in a set.
  155  *              The owner of the port set is also receiver for the port.
  156  */
  157 
  158 void
  159 ipc_pset_add(pset, port)
  160         ipc_pset_t pset;
  161         ipc_port_t port;
  162 {
  163         assert(ips_active(pset));
  164         assert(ip_active(port));
  165         assert(port->ip_pset == IPS_NULL);
  166 
  167         port->ip_pset = pset;
  168         ips_reference(pset);
  169 
  170         imq_lock(&port->ip_messages);
  171         imq_lock(&pset->ips_messages);
  172 
  173         /* move messages from port's queue to the port set's queue */
  174 
  175         ipc_mqueue_move(&pset->ips_messages, &port->ip_messages, port);
  176         imq_unlock(&pset->ips_messages);
  177         assert(ipc_kmsg_queue_empty(&port->ip_messages.imq_messages));
  178 
  179         /* wake up threads waiting to receive from the port */
  180 
  181         ipc_mqueue_changed(&port->ip_messages, MACH_RCV_PORT_CHANGED);
  182         assert(ipc_thread_queue_empty(&port->ip_messages.imq_threads));
  183         imq_unlock(&port->ip_messages);
  184 }
  185 
  186 /*
  187  *      Routine:        ipc_pset_remove
  188  *      Purpose:
  189  *              Removes a port from a port set.
  190  *              The port set loses a reference.
  191  *      Conditions:
  192  *              Both port and port set are locked.
  193  *              The port must be active.
  194  */
  195 
  196 void
  197 ipc_pset_remove(pset, port)
  198         ipc_pset_t pset;
  199         ipc_port_t port;
  200 {
  201         assert(ip_active(port));
  202         assert(port->ip_pset == pset);
  203 
  204         port->ip_pset = IPS_NULL;
  205         ips_release(pset);
  206 
  207         imq_lock(&port->ip_messages);
  208         imq_lock(&pset->ips_messages);
  209 
  210         /* move messages from port set's queue to the port's queue */
  211 
  212         ipc_mqueue_move(&port->ip_messages, &pset->ips_messages, port);
  213 
  214         imq_unlock(&pset->ips_messages);
  215         imq_unlock(&port->ip_messages);
  216 }
  217 
  218 /*
  219  *      Routine:        ipc_pset_move
  220  *      Purpose:
  221  *              If nset is IPS_NULL, removes port
  222  *              from the port set it is in.  Otherwise, adds
  223  *              port to nset, removing it from any set
  224  *              it might already be in.
  225  *      Conditions:
  226  *              The space is read-locked.
  227  *      Returns:
  228  *              KERN_SUCCESS            Moved the port.
  229  *              KERN_NOT_IN_SET         nset is null and port isn't in a set.
  230  */
  231 
  232 kern_return_t
  233 ipc_pset_move(space, port, nset)
  234         ipc_space_t space;
  235         ipc_port_t port;
  236         ipc_pset_t nset;
  237 {
  238         ipc_pset_t oset;
  239 
  240         /*
  241          *      While we've got the space locked, it holds refs for
  242          *      the port and nset (because of the entries).  Also,
  243          *      they must be alive.  While we've got port locked, it
  244          *      holds a ref for oset, which might not be alive.
  245          */
  246 
  247         ip_lock(port);
  248         assert(ip_active(port));
  249 
  250         oset = port->ip_pset;
  251 
  252         if (oset == nset) {
  253                 /* the port is already in the new set:  a noop */
  254 
  255                 is_read_unlock(space);
  256         } else if (oset == IPS_NULL) {
  257                 /* just add port to the new set */
  258 
  259                 ips_lock(nset);
  260                 assert(ips_active(nset));
  261                 is_read_unlock(space);
  262 
  263                 ipc_pset_add(nset, port);
  264 
  265                 ips_unlock(nset);
  266         } else if (nset == IPS_NULL) {
  267                 /* just remove port from the old set */
  268 
  269                 is_read_unlock(space);
  270                 ips_lock(oset);
  271 
  272                 ipc_pset_remove(oset, port);
  273 
  274                 if (ips_active(oset))
  275                         ips_unlock(oset);
  276                 else {
  277                         ips_check_unlock(oset);
  278                         oset = IPS_NULL; /* trigger KERN_NOT_IN_SET */
  279                 }
  280         } else {
  281                 /* atomically move port from oset to nset */
  282 
  283                 if (oset < nset) {
  284                         ips_lock(oset);
  285                         ips_lock(nset);
  286                 } else {
  287                         ips_lock(nset);
  288                         ips_lock(oset);
  289                 }
  290 
  291                 is_read_unlock(space);
  292                 assert(ips_active(nset));
  293 
  294                 ipc_pset_remove(oset, port);
  295                 ipc_pset_add(nset, port);
  296 
  297                 ips_unlock(nset);
  298                 ips_check_unlock(oset); /* KERN_NOT_IN_SET not a possibility */
  299         }
  300 
  301         ip_unlock(port);
  302 
  303         return (((nset == IPS_NULL) && (oset == IPS_NULL)) ?
  304                 KERN_NOT_IN_SET : KERN_SUCCESS);
  305 }
  306 
  307 /*
  308  *      Routine:        ipc_pset_destroy
  309  *      Purpose:
  310  *              Destroys a port_set.
  311  *
  312  *              Doesn't remove members from the port set;
  313  *              that happens lazily.  As members are removed,
  314  *              their messages are removed from the queue.
  315  *      Conditions:
  316  *              The port_set is locked and alive.
  317  *              The caller has a reference, which is consumed.
  318  *              Afterwards, the port_set is unlocked and dead.
  319  */
  320 
  321 void
  322 ipc_pset_destroy(pset)
  323         ipc_pset_t pset;
  324 {
  325         assert(ips_active(pset));
  326 
  327         pset->ips_object.io_bits &= ~IO_BITS_ACTIVE;
  328 
  329         imq_lock(&pset->ips_messages);
  330         ipc_mqueue_changed(&pset->ips_messages, MACH_RCV_PORT_DIED);
  331         imq_unlock(&pset->ips_messages);
  332 
  333         ips_release(pset);      /* consume the ref our caller gave us */
  334         ips_check_unlock(pset);
  335 }
  336 
  337 #include <mach_kdb.h>
  338 
  339 
  340 #if     MACH_KDB
  341 #define printf  kdbprintf
  342 
  343 /*
  344  *      Routine:        ipc_pset_print
  345  *      Purpose:
  346  *              Pretty-print a port set for kdb.
  347  */
  348 
  349 void
  350 ipc_pset_print(pset)
  351         ipc_pset_t pset;
  352 {
  353         extern int indent;
  354 
  355         printf("pset 0x%x\n", pset);
  356 
  357         indent += 2;
  358 
  359         ipc_object_print(&pset->ips_object);
  360         iprintf("local_name = 0x%x\n", pset->ips_local_name);
  361         iprintf("kmsgs = 0x%x", pset->ips_messages.imq_messages.ikmq_base);
  362         printf(",rcvrs = 0x%x\n", pset->ips_messages.imq_threads.ithq_base);
  363 
  364         indent -=2;
  365 }
  366 
  367 #endif  MACH_KDB

Cache object: 66e352c7339d0386e0e7419e5674b5f1


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