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_marequest.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /* 
    2  * Mach Operating System
    3  * Copyright (c) 1993,1992,1991,1990,1989 Carnegie Mellon University
    4  * All Rights Reserved.
    5  * 
    6  * Permission to use, copy, modify and distribute this software and its
    7  * documentation is hereby granted, provided that both the copyright
    8  * notice and this permission notice appear in all copies of the
    9  * software, derivative works or modified versions, and any portions
   10  * thereof, and that both notices appear in supporting documentation.
   11  * 
   12  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
   13  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
   14  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
   15  * 
   16  * Carnegie Mellon requests users of this software to return to
   17  * 
   18  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
   19  *  School of Computer Science
   20  *  Carnegie Mellon University
   21  *  Pittsburgh PA 15213-3890
   22  * 
   23  * any improvements or extensions that they make and grant Carnegie Mellon
   24  * the rights to redistribute these changes.
   25  */
   26 /*
   27  * HISTORY
   28  * $Log:        ipc_marequest.c,v $
   29  * Revision 2.11  93/11/17  16:57:53  dbg
   30  *      Added ANSI function prototypes.
   31  *      [93/09/23            dbg]
   32  * 
   33  * Revision 2.10  93/03/09  10:54:41  danner
   34  *      Added typecast in hashing macros to shutup GCC.
   35  *      [93/03/06            af]
   36  * 
   37  * Revision 2.9  92/08/03  17:34:37  jfriedl
   38  *      removed silly prototypes
   39  *      [92/08/02            jfriedl]
   40  * 
   41  * Revision 2.8  92/05/21  17:10:37  jfriedl
   42  *      tried prototypes.
   43  *      [92/05/20            jfriedl]
   44  * 
   45  * Revision 2.7  92/01/14  16:44:37  rpd
   46  *      Changed ipc_marequest_info for CountInOut.
   47  *      [92/01/14            rpd]
   48  * 
   49  * Revision 2.6  91/05/14  16:33:35  mrt
   50  *      Correcting copyright
   51  * 
   52  * Revision 2.5  91/02/05  17:22:13  mrt
   53  *      Changed to new Mach copyright
   54  *      [91/02/01  15:46:05  mrt]
   55  * 
   56  * Revision 2.4  91/01/08  15:14:11  rpd
   57  *      Changed ipc_info_bucket_t to hash_info_bucket_t.
   58  *      [91/01/02            rpd]
   59  * 
   60  *      Changed zchange calls to make the IPC zones non-collectable.
   61  *      [90/12/29            rpd]
   62  * 
   63  * Revision 2.3  90/12/20  16:38:53  jeffreyh
   64  *      Change zchange to match new number of arguments.
   65  *      Made zone collectable. 
   66  *      [90/12/11            jeffreyh]
   67  * 
   68  * Revision 2.2  90/06/02  14:50:30  rpd
   69  *      Created for new IPC.
   70  *      [90/03/26  20:56:33  rpd]
   71  * 
   72  */
   73 /*
   74  *      File:   ipc/ipc_marequest.c
   75  *      Author: Rich Draves
   76  *      Date:   1989
   77  *
   78  *      Functions to handle msg-accepted requests.
   79  */
   80 
   81 #include <mach_ipc_compat.h>
   82 
   83 #include <mach/message.h>
   84 #include <mach/port.h>
   85 #include <kern/lock.h>
   86 #include <kern/mach_param.h>
   87 #include <kern/kalloc.h>
   88 #include <kern/zalloc.h>
   89 #include <ipc/port.h>
   90 #include <ipc/ipc_space.h>
   91 #include <ipc/ipc_entry.h>
   92 #include <ipc/ipc_port.h>
   93 #include <ipc/ipc_right.h>
   94 #include <ipc/ipc_marequest.h>
   95 #include <ipc/ipc_notify.h>
   96 
   97 #include <mach_ipc_debug.h>
   98 #if     MACH_IPC_DEBUG
   99 #include <mach/kern_return.h>
  100 #include <mach_debug/hash_info.h>
  101 #include <vm/vm_map.h>
  102 #include <vm/vm_kern.h>
  103 #include <vm/vm_user.h>
  104 #endif
  105 
  106 
  107 zone_t ipc_marequest_zone;
  108 int ipc_marequest_max = IMAR_MAX;
  109 
  110 #define imar_alloc()            ((ipc_marequest_t) zalloc(ipc_marequest_zone))
  111 #define imar_free(imar)         zfree(ipc_marequest_zone, (vm_offset_t) (imar))
  112 
  113 typedef unsigned int ipc_marequest_index_t;
  114 
  115 ipc_marequest_index_t ipc_marequest_size;
  116 ipc_marequest_index_t ipc_marequest_mask;
  117 
  118 #define IMAR_HASH(space, name)                                          \
  119                 ((((ipc_marequest_index_t)((vm_offset_t)space) >> 4) +  \
  120                   MACH_PORT_INDEX(name) + MACH_PORT_NGEN(name)) &       \
  121                  ipc_marequest_mask)
  122 
  123 typedef struct ipc_marequest_bucket {
  124         decl_simple_lock_data(, imarb_lock_data)
  125         ipc_marequest_t imarb_head;
  126 } *ipc_marequest_bucket_t;
  127 
  128 #define IMARB_NULL      ((ipc_marequest_bucket_t) 0)
  129 
  130 #define imarb_lock_init(imarb)  simple_lock_init(&(imarb)->imarb_lock_data)
  131 #define imarb_lock(imarb)       simple_lock(&(imarb)->imarb_lock_data)
  132 #define imarb_unlock(imarb)     simple_unlock(&(imarb)->imarb_lock_data)
  133 
  134 ipc_marequest_bucket_t ipc_marequest_table;
  135 
  136 
  137 
  138 /*
  139  *      Routine:        ipc_marequest_init
  140  *      Purpose:
  141  *              Initialize the msg-accepted request module.
  142  */
  143 
  144 void
  145 ipc_marequest_init(void)
  146 {
  147         ipc_marequest_index_t i;
  148 
  149         /* if not configured, initialize ipc_marequest_size */
  150 
  151         if (ipc_marequest_size == 0) {
  152                 ipc_marequest_size = ipc_marequest_max >> 8;
  153                 if (ipc_marequest_size < 16)
  154                         ipc_marequest_size = 16;
  155         }
  156 
  157         /* make sure it is a power of two */
  158 
  159         ipc_marequest_mask = ipc_marequest_size - 1;
  160         if ((ipc_marequest_size & ipc_marequest_mask) != 0) {
  161                 unsigned int bit;
  162 
  163                 /* round up to closest power of two */
  164 
  165                 for (bit = 1;; bit <<= 1) {
  166                         ipc_marequest_mask |= bit;
  167                         ipc_marequest_size = ipc_marequest_mask + 1;
  168 
  169                         if ((ipc_marequest_size & ipc_marequest_mask) == 0)
  170                                 break;
  171                 }
  172         }
  173 
  174         /* allocate ipc_marequest_table */
  175 
  176         ipc_marequest_table = (ipc_marequest_bucket_t)
  177                 kalloc((vm_size_t) (ipc_marequest_size *
  178                                     sizeof(struct ipc_marequest_bucket)));
  179         assert(ipc_marequest_table != IMARB_NULL);
  180 
  181         /* and initialize it */
  182 
  183         for (i = 0; i < ipc_marequest_size; i++) {
  184                 ipc_marequest_bucket_t bucket;
  185 
  186                 bucket = &ipc_marequest_table[i];
  187                 imarb_lock_init(bucket);
  188                 bucket->imarb_head = IMAR_NULL;
  189         }
  190 
  191         ipc_marequest_zone =
  192                 zinit(sizeof(struct ipc_marequest),
  193                       ipc_marequest_max * sizeof(struct ipc_marequest),
  194                       sizeof(struct ipc_marequest),
  195                       FALSE, "ipc msg-accepted requests");
  196         /* make it exhaustible */
  197         zchange(ipc_marequest_zone, FALSE, FALSE, TRUE, FALSE);
  198 }
  199 
  200 /*
  201  *      Routine:        ipc_marequest_create
  202  *      Purpose:
  203  *              Create a msg-accepted request, because
  204  *              a sender is forcing a message with MACH_SEND_NOTIFY.
  205  *
  206  *              The "notify" argument should name a receive right
  207  *              that is used to create the send-once notify port.
  208  *
  209  *              [MACH_IPC_COMPAT] If "notify" is MACH_PORT_NULL,
  210  *              then an old-style msg-accepted request is created.
  211  *      Conditions:
  212  *              Nothing locked; refs held for space and port.
  213  *      Returns:
  214  *              MACH_MSG_SUCCESS        Msg-accepted request created.
  215  *              MACH_SEND_INVALID_NOTIFY        The space is dead.
  216  *              MACH_SEND_INVALID_NOTIFY        The notify port is bad.
  217  *              MACH_SEND_NOTIFY_IN_PROGRESS
  218  *                      This space has already forced a message to this port.
  219  *              MACH_SEND_NO_NOTIFY     Can't allocate a msg-accepted request.
  220  */
  221 
  222 mach_msg_return_t
  223 ipc_marequest_create(
  224         ipc_space_t space,
  225         ipc_port_t port,
  226         mach_port_t notify,
  227         ipc_marequest_t *marequestp)
  228 {
  229         mach_port_t name;
  230         ipc_entry_t entry;
  231         ipc_port_t soright;
  232         ipc_marequest_t marequest;
  233         ipc_marequest_bucket_t bucket;
  234 
  235 #if     !MACH_IPC_COMPAT
  236         assert(notify != MACH_PORT_NULL);
  237 #endif  /* !MACH_IPC_COMPAT */
  238 
  239         marequest = imar_alloc();
  240         if (marequest == IMAR_NULL)
  241                 return MACH_SEND_NO_NOTIFY;
  242 
  243         /*
  244          *      Delay creating the send-once right until
  245          *      we know there will be no errors.  Otherwise,
  246          *      we would have to worry about disposing of it
  247          *      when it turned out it wasn't needed.
  248          */
  249 
  250         is_write_lock(space);
  251         if (!space->is_active) {
  252                 is_write_unlock(space);
  253                 imar_free(marequest);
  254                 return MACH_SEND_INVALID_NOTIFY;
  255         }
  256 
  257         if (ipc_right_reverse(space, (ipc_object_t) port, &name, &entry)) {
  258                 ipc_entry_bits_t bits;
  259 
  260                 /* port is locked and active */
  261                 ip_unlock(port);
  262                 bits = entry->ie_bits;
  263 
  264                 assert(port == (ipc_port_t) entry->ie_object);
  265                 assert(bits & MACH_PORT_TYPE_SEND_RECEIVE);
  266 
  267                 if (bits & IE_BITS_MAREQUEST) {
  268                         is_write_unlock(space);
  269                         imar_free(marequest);
  270                         return MACH_SEND_NOTIFY_IN_PROGRESS;
  271                 }
  272 
  273 #if     MACH_IPC_COMPAT
  274                 if (notify == MACH_PORT_NULL)
  275                         soright = IP_NULL;
  276                 else
  277 #endif  /* MACH_IPC_COMPAT */
  278                 if ((soright = ipc_port_lookup_notify(space, notify))
  279                                                                 == IP_NULL) {
  280                         is_write_unlock(space);
  281                         imar_free(marequest);
  282                         return MACH_SEND_INVALID_NOTIFY;
  283                 }
  284 
  285                 entry->ie_bits = bits | IE_BITS_MAREQUEST;
  286 
  287                 is_reference(space);
  288                 marequest->imar_space = space;
  289                 marequest->imar_name = name;
  290                 marequest->imar_soright = soright;
  291 
  292                 bucket = &ipc_marequest_table[IMAR_HASH(space, name)];
  293                 imarb_lock(bucket);
  294 
  295                 marequest->imar_next = bucket->imarb_head;
  296                 bucket->imarb_head = marequest;
  297 
  298                 imarb_unlock(bucket);
  299         } else {
  300 #if     MACH_IPC_COMPAT
  301                 if (notify == MACH_PORT_NULL)
  302                         soright = IP_NULL;
  303                 else
  304 #endif  /* MACH_IPC_COMPAT */
  305                 if ((soright = ipc_port_lookup_notify(space, notify))
  306                                                                 == IP_NULL) {
  307                         is_write_unlock(space);
  308                         imar_free(marequest);
  309                         return MACH_SEND_INVALID_NOTIFY;
  310                 }
  311 
  312                 is_reference(space);
  313                 marequest->imar_space = space;
  314                 marequest->imar_name = MACH_PORT_NULL;
  315                 marequest->imar_soright = soright;
  316         }
  317 
  318         is_write_unlock(space);
  319         *marequestp = marequest;
  320         return MACH_MSG_SUCCESS;
  321 }
  322 
  323 /*
  324  *      Routine:        ipc_marequest_cancel
  325  *      Purpose:
  326  *              Cancel a msg-accepted request, because
  327  *              the space's entry is being destroyed.
  328  *      Conditions:
  329  *              The space is write-locked and active.
  330  */
  331 
  332 void
  333 ipc_marequest_cancel(
  334         ipc_space_t space,
  335         mach_port_t name)
  336 {
  337         ipc_marequest_bucket_t bucket;
  338         ipc_marequest_t marequest, *last;
  339 
  340         assert(space->is_active);
  341 
  342         bucket = &ipc_marequest_table[IMAR_HASH(space, name)];
  343         imarb_lock(bucket);
  344 
  345         for (last = &bucket->imarb_head;
  346              (marequest = *last) != IMAR_NULL;
  347              last = &marequest->imar_next)
  348                 if ((marequest->imar_space == space) &&
  349                     (marequest->imar_name == name))
  350                         break;
  351 
  352         assert(marequest != IMAR_NULL);
  353         *last = marequest->imar_next;
  354         imarb_unlock(bucket);
  355 
  356         marequest->imar_name = MACH_PORT_NULL;
  357 }
  358 
  359 /*
  360  *      Routine:        ipc_marequest_rename
  361  *      Purpose:
  362  *              Rename a msg-accepted request, because the entry
  363  *              in the space is being renamed.
  364  *      Conditions:
  365  *              The space is write-locked and active.
  366  */
  367 
  368 void
  369 ipc_marequest_rename(
  370         ipc_space_t space,
  371         mach_port_t old,
  372         mach_port_t new)
  373 {
  374         ipc_marequest_bucket_t bucket;
  375         ipc_marequest_t marequest, *last;
  376 
  377         assert(space->is_active);
  378 
  379         bucket = &ipc_marequest_table[IMAR_HASH(space, old)];
  380         imarb_lock(bucket);
  381 
  382         for (last = &bucket->imarb_head;
  383              (marequest = *last) != IMAR_NULL;
  384              last = &marequest->imar_next)
  385                 if ((marequest->imar_space == space) &&
  386                     (marequest->imar_name == old))
  387                         break;
  388 
  389         assert(marequest != IMAR_NULL);
  390         *last = marequest->imar_next;
  391         imarb_unlock(bucket);
  392 
  393         marequest->imar_name = new;
  394 
  395         bucket = &ipc_marequest_table[IMAR_HASH(space, new)];
  396         imarb_lock(bucket);
  397 
  398         marequest->imar_next = bucket->imarb_head;
  399         bucket->imarb_head = marequest;
  400 
  401         imarb_unlock(bucket);
  402 }
  403 
  404 /*
  405  *      Routine:        ipc_marequest_destroy
  406  *      Purpose:
  407  *              Destroy a msg-accepted request, because
  408  *              the kernel message is being received/destroyed.
  409  *      Conditions:
  410  *              Nothing locked.
  411  */
  412 
  413 void
  414 ipc_marequest_destroy(
  415         ipc_marequest_t marequest)
  416 {
  417         ipc_space_t space = marequest->imar_space;
  418         mach_port_t name;
  419         ipc_port_t soright;
  420 #if     MACH_IPC_COMPAT
  421         ipc_port_t sright = IP_NULL;
  422 #endif  /* MACH_IPC_COMPAT */
  423 
  424         is_write_lock(space);
  425 
  426         name = marequest->imar_name;
  427         soright = marequest->imar_soright;
  428 
  429         if (name != MACH_PORT_NULL) {
  430                 ipc_marequest_bucket_t bucket;
  431                 ipc_marequest_t this, *last;
  432 
  433                 bucket = &ipc_marequest_table[IMAR_HASH(space, name)];
  434                 imarb_lock(bucket);
  435 
  436                 for (last = &bucket->imarb_head;
  437                      (this = *last) != IMAR_NULL;
  438                      last = &this->imar_next)
  439                         if ((this->imar_space == space) &&
  440                             (this->imar_name == name))
  441                                 break;
  442 
  443                 assert(this == marequest);
  444                 *last = this->imar_next;
  445                 imarb_unlock(bucket);
  446 
  447                 if (space->is_active) {
  448                         ipc_entry_t entry;
  449 
  450                         entry = ipc_entry_lookup(space, name);
  451                         assert(entry != IE_NULL);
  452                         assert(entry->ie_bits & IE_BITS_MAREQUEST);
  453                         assert(entry->ie_bits & MACH_PORT_TYPE_SEND_RECEIVE);
  454 
  455                         entry->ie_bits &= ~IE_BITS_MAREQUEST;
  456 
  457 #if     MACH_IPC_COMPAT
  458                         if (soright == IP_NULL)
  459                                 sright = ipc_space_make_notify(space);
  460 #endif  /* MACH_IPC_COMPAT */
  461                 } else
  462                         name = MACH_PORT_NULL;
  463         }
  464 
  465         is_write_unlock(space);
  466         is_release(space);
  467 
  468         imar_free(marequest);
  469 
  470 #if     MACH_IPC_COMPAT
  471         if (soright == IP_NULL) {
  472                 if (IP_VALID(sright)) {
  473                         assert(name != MACH_PORT_NULL);
  474                         ipc_notify_msg_accepted_compat(sright, name);
  475                 }
  476 
  477                 return;
  478         }
  479         assert(sright == IP_NULL);
  480 #endif  /* MACH_IPC_COMPAT */
  481 
  482         assert(soright != IP_NULL);
  483         ipc_notify_msg_accepted(soright, name);
  484 }
  485 
  486 #if     MACH_IPC_DEBUG
  487 
  488 
  489 /*
  490  *      Routine:        ipc_marequest_info
  491  *      Purpose:
  492  *              Return information about the marequest hash table.
  493  *              Fills the buffer with as much information as possible
  494  *              and returns the desired size of the buffer.
  495  *      Conditions:
  496  *              Nothing locked.  The caller should provide
  497  *              possibly-pageable memory.
  498  */
  499 
  500 unsigned int
  501 ipc_marequest_info(
  502         unsigned int *maxp,
  503         hash_info_bucket_t *info,
  504         unsigned int count)
  505 {
  506         ipc_marequest_index_t i;
  507 
  508         if (ipc_marequest_size < count)
  509                 count = ipc_marequest_size;
  510 
  511         for (i = 0; i < count; i++) {
  512                 ipc_marequest_bucket_t bucket = &ipc_marequest_table[i];
  513                 unsigned int bucket_count = 0;
  514                 ipc_marequest_t marequest;
  515 
  516                 imarb_lock(bucket);
  517                 for (marequest = bucket->imarb_head;
  518                      marequest != IMAR_NULL;
  519                      marequest = marequest->imar_next)
  520                         bucket_count++;
  521                 imarb_unlock(bucket);
  522 
  523                 /* don't touch pageable memory while holding locks */
  524                 info[i].hib_count = bucket_count;
  525         }
  526 
  527         *maxp = ipc_marequest_max;
  528         return ipc_marequest_size;
  529 }
  530 
  531 #endif  /* MACH_IPC_DEBUG */

Cache object: 718dffc2dafd3acd1d9487f3dc94e9d7


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