Annotation of Gnu-Mach/ipc/ipc_pset.c, revision 1.1.1.4

1.1       root        1: /*
                      2:  * Mach Operating System
                      3:  * Copyright (c) 1991,1990,1989Carnegie Mellon University.
                      4:  * Copyright (c) 1993,1994 The University of Utah and
                      5:  * the Computer Systems Laboratory (CSL).
                      6:  * All rights reserved.
                      7:  *
                      8:  * Permission to use, copy, modify and distribute this software and its
                      9:  * documentation is hereby granted, provided that both the copyright
                     10:  * notice and this permission notice appear in all copies of the
                     11:  * software, derivative works or modified versions, and any portions
                     12:  * thereof, and that both notices appear in supporting documentation.
                     13:  *
                     14:  * CARNEGIE MELLON, THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF
                     15:  * THIS SOFTWARE IN ITS "AS IS" CONDITION, AND DISCLAIM ANY LIABILITY
                     16:  * OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF
                     17:  * THIS SOFTWARE.
                     18:  *
                     19:  * Carnegie Mellon requests users of this software to return to
                     20:  *
                     21:  *  Software Distribution Coordinator  or  [email protected]
                     22:  *  School of Computer Science
                     23:  *  Carnegie Mellon University
                     24:  *  Pittsburgh PA 15213-3890
                     25:  *
                     26:  * any improvements or extensions that they make and grant Carnegie Mellon
                     27:  * the rights to redistribute these changes.
                     28:  */
                     29: /*
                     30:  */
                     31: /*
                     32:  *     File:   ipc/ipc_pset.c
                     33:  *     Author: Rich Draves
                     34:  *     Date:   1989
                     35:  *
                     36:  *     Functions to manipulate IPC port sets.
                     37:  */
                     38: 
1.1.1.3   root       39: #include <kern/printf.h>
1.1       root       40: #include <mach/port.h>
                     41: #include <mach/kern_return.h>
                     42: #include <mach/message.h>
                     43: #include <ipc/ipc_mqueue.h>
                     44: #include <ipc/ipc_object.h>
                     45: #include <ipc/ipc_pset.h>
                     46: #include <ipc/ipc_right.h>
                     47: #include <ipc/ipc_space.h>
                     48: 
1.1.1.3   root       49: #if    MACH_KDB
                     50: #include <ddb/db_output.h>
                     51: #include <ipc/ipc_print.h>
                     52: #endif /* MACH_KDB */
                     53: 
1.1       root       54: 
                     55: /*
                     56:  *     Routine:        ipc_pset_alloc
                     57:  *     Purpose:
                     58:  *             Allocate a port set.
                     59:  *     Conditions:
                     60:  *             Nothing locked.  If successful, the port set is returned
                     61:  *             locked.  (The caller doesn't have a reference.)
                     62:  *     Returns:
                     63:  *             KERN_SUCCESS            The port set is allocated.
                     64:  *             KERN_INVALID_TASK       The space is dead.
                     65:  *             KERN_NO_SPACE           No room for an entry in the space.
                     66:  *             KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
                     67:  */
                     68: 
                     69: kern_return_t
                     70: ipc_pset_alloc(
                     71:        ipc_space_t     space,
                     72:        mach_port_t     *namep,
                     73:        ipc_pset_t      *psetp)
                     74: {
                     75:        ipc_pset_t pset;
                     76:        mach_port_t name;
                     77:        kern_return_t kr;
                     78: 
                     79:        kr = ipc_object_alloc(space, IOT_PORT_SET,
                     80:                              MACH_PORT_TYPE_PORT_SET, 0,
                     81:                              &name, (ipc_object_t *) &pset);
                     82:        if (kr != KERN_SUCCESS)
                     83:                return kr;
                     84:        /* pset is locked */
                     85: 
                     86:        ipc_target_init(&pset->ips_target, name);
                     87: 
                     88:        *namep = name;
                     89:        *psetp = pset;
                     90:        return KERN_SUCCESS;
                     91: }
                     92: 
                     93: /*
                     94:  *     Routine:        ipc_pset_alloc_name
                     95:  *     Purpose:
                     96:  *             Allocate a port set, with a specific name.
                     97:  *     Conditions:
                     98:  *             Nothing locked.  If successful, the port set is returned
                     99:  *             locked.  (The caller doesn't have a reference.)
                    100:  *     Returns:
                    101:  *             KERN_SUCCESS            The port set is allocated.
                    102:  *             KERN_INVALID_TASK       The space is dead.
                    103:  *             KERN_NAME_EXISTS        The name already denotes a right.
                    104:  *             KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
                    105:  */
                    106: 
                    107: kern_return_t
                    108: ipc_pset_alloc_name(
                    109:        ipc_space_t     space,
                    110:        mach_port_t     name,
                    111:        ipc_pset_t      *psetp)
                    112: {
                    113:        ipc_pset_t pset;
                    114:        kern_return_t kr;
                    115: 
                    116: 
                    117:        kr = ipc_object_alloc_name(space, IOT_PORT_SET,
                    118:                                   MACH_PORT_TYPE_PORT_SET, 0,
                    119:                                   name, (ipc_object_t *) &pset);
                    120:        if (kr != KERN_SUCCESS)
                    121:                return kr;
                    122:        /* pset is locked */
                    123: 
                    124:        ipc_target_init(&pset->ips_target, name);
                    125: 
                    126:        *psetp = pset;
                    127:        return KERN_SUCCESS;
                    128: }
                    129: 
                    130: /*
                    131:  *     Routine:        ipc_pset_add
                    132:  *     Purpose:
                    133:  *             Puts a port into a port set.
                    134:  *             The port set gains a reference.
                    135:  *     Conditions:
                    136:  *             Both port and port set are locked and active.
                    137:  *             The port isn't already in a set.
                    138:  *             The owner of the port set is also receiver for the port.
                    139:  */
                    140: 
                    141: void
                    142: ipc_pset_add(
                    143:        ipc_pset_t      pset,
                    144:        ipc_port_t      port)
                    145: {
                    146:        assert(ips_active(pset));
                    147:        assert(ip_active(port));
                    148:        assert(port->ip_pset == IPS_NULL);
                    149: 
                    150:        port->ip_pset = pset;
                    151:        port->ip_cur_target = &pset->ips_target;
                    152:        ips_reference(pset);
                    153: 
                    154:        imq_lock(&port->ip_messages);
                    155:        imq_lock(&pset->ips_messages);
                    156: 
                    157:        /* move messages from port's queue to the port set's queue */
                    158: 
                    159:        ipc_mqueue_move(&pset->ips_messages, &port->ip_messages, port);
                    160:        imq_unlock(&pset->ips_messages);
                    161:        assert(ipc_kmsg_queue_empty(&port->ip_messages.imq_messages));
                    162: 
                    163:        /* wake up threads waiting to receive from the port */
                    164: 
                    165:        ipc_mqueue_changed(&port->ip_messages, MACH_RCV_PORT_CHANGED);
                    166:        assert(ipc_thread_queue_empty(&port->ip_messages.imq_threads));
                    167:        imq_unlock(&port->ip_messages);
                    168: }
                    169: 
                    170: /*
                    171:  *     Routine:        ipc_pset_remove
                    172:  *     Purpose:
                    173:  *             Removes a port from a port set.
                    174:  *             The port set loses a reference.
                    175:  *     Conditions:
                    176:  *             Both port and port set are locked.
                    177:  *             The port must be active.
                    178:  */
                    179: 
                    180: void
                    181: ipc_pset_remove(
                    182:        ipc_pset_t      pset,
                    183:        ipc_port_t      port)
                    184: {
                    185:        assert(ip_active(port));
                    186:        assert(port->ip_pset == pset);
                    187: 
                    188:        port->ip_pset = IPS_NULL;
                    189:        port->ip_cur_target = &port->ip_target;
                    190:        ips_release(pset);
                    191: 
                    192:        imq_lock(&port->ip_messages);
                    193:        imq_lock(&pset->ips_messages);
                    194: 
                    195:        /* move messages from port set's queue to the port's queue */
                    196: 
                    197:        ipc_mqueue_move(&port->ip_messages, &pset->ips_messages, port);
                    198: 
                    199:        imq_unlock(&pset->ips_messages);
                    200:        imq_unlock(&port->ip_messages);
                    201: }
                    202: 
                    203: /*
                    204:  *     Routine:        ipc_pset_move
                    205:  *     Purpose:
                    206:  *             If nset is IPS_NULL, removes port
                    207:  *             from the port set it is in.  Otherwise, adds
                    208:  *             port to nset, removing it from any set
                    209:  *             it might already be in.
                    210:  *     Conditions:
                    211:  *             The space is read-locked.
                    212:  *     Returns:
                    213:  *             KERN_SUCCESS            Moved the port.
                    214:  *             KERN_NOT_IN_SET         nset is null and port isn't in a set.
                    215:  */
                    216: 
                    217: kern_return_t
                    218: ipc_pset_move(
                    219:        ipc_space_t     space,
                    220:        ipc_port_t      port,
                    221:        ipc_pset_t      nset)
                    222: {
                    223:        ipc_pset_t oset;
                    224: 
                    225:        /*
                    226:         *      While we've got the space locked, it holds refs for
                    227:         *      the port and nset (because of the entries).  Also,
                    228:         *      they must be alive.  While we've got port locked, it
                    229:         *      holds a ref for oset, which might not be alive.
                    230:         */
                    231: 
                    232:        ip_lock(port);
                    233:        assert(ip_active(port));
                    234: 
                    235:        oset = port->ip_pset;
                    236: 
                    237:        if (oset == nset) {
                    238:                /* the port is already in the new set:  a noop */
                    239: 
                    240:                is_read_unlock(space);
                    241:        } else if (oset == IPS_NULL) {
                    242:                /* just add port to the new set */
                    243: 
                    244:                ips_lock(nset);
                    245:                assert(ips_active(nset));
                    246:                is_read_unlock(space);
                    247: 
                    248:                ipc_pset_add(nset, port);
                    249: 
                    250:                ips_unlock(nset);
                    251:        } else if (nset == IPS_NULL) {
                    252:                /* just remove port from the old set */
                    253: 
                    254:                is_read_unlock(space);
                    255:                ips_lock(oset);
                    256: 
                    257:                ipc_pset_remove(oset, port);
                    258: 
                    259:                if (ips_active(oset))
                    260:                        ips_unlock(oset);
                    261:                else {
                    262:                        ips_check_unlock(oset);
                    263:                        oset = IPS_NULL; /* trigger KERN_NOT_IN_SET */
                    264:                }
                    265:        } else {
                    266:                /* atomically move port from oset to nset */
                    267: 
                    268:                if (oset < nset) {
                    269:                        ips_lock(oset);
                    270:                        ips_lock(nset);
                    271:                } else {
                    272:                        ips_lock(nset);
                    273:                        ips_lock(oset);
                    274:                }
                    275: 
                    276:                is_read_unlock(space);
                    277:                assert(ips_active(nset));
                    278: 
                    279:                ipc_pset_remove(oset, port);
                    280:                ipc_pset_add(nset, port);
                    281: 
                    282:                ips_unlock(nset);
                    283:                ips_check_unlock(oset); /* KERN_NOT_IN_SET not a possibility */
                    284:        }
                    285: 
                    286:        ip_unlock(port);
                    287: 
                    288:        return (((nset == IPS_NULL) && (oset == IPS_NULL)) ?
                    289:                KERN_NOT_IN_SET : KERN_SUCCESS);
                    290: }
                    291: 
                    292: /*
                    293:  *     Routine:        ipc_pset_destroy
                    294:  *     Purpose:
                    295:  *             Destroys a port_set.
                    296:  *
                    297:  *             Doesn't remove members from the port set;
                    298:  *             that happens lazily.  As members are removed,
                    299:  *             their messages are removed from the queue.
                    300:  *     Conditions:
                    301:  *             The port_set is locked and alive.
                    302:  *             The caller has a reference, which is consumed.
                    303:  *             Afterwards, the port_set is unlocked and dead.
                    304:  */
                    305: 
                    306: void
                    307: ipc_pset_destroy(
                    308:        ipc_pset_t      pset)
                    309: {
                    310:        assert(ips_active(pset));
                    311: 
                    312:        pset->ips_object.io_bits &= ~IO_BITS_ACTIVE;
                    313: 
                    314:        imq_lock(&pset->ips_messages);
                    315:        ipc_mqueue_changed(&pset->ips_messages, MACH_RCV_PORT_DIED);
                    316:        imq_unlock(&pset->ips_messages);
                    317: 
                    318:        /* Common destruction for the IPC target.  */
                    319:        ipc_target_terminate(&pset->ips_target);
                    320: 
                    321:        ips_release(pset);      /* consume the ref our caller gave us */
                    322:        ips_check_unlock(pset);
                    323: }
                    324: 
                    325: 
                    326: #if    MACH_KDB
                    327: #define        printf  kdbprintf
                    328: 
                    329: /*
                    330:  *     Routine:        ipc_pset_print
                    331:  *     Purpose:
                    332:  *             Pretty-print a port set for kdb.
                    333:  */
                    334: 
                    335: void
                    336: ipc_pset_print(
1.1.1.4 ! root      337:        const ipc_pset_t pset)
1.1       root      338: {
                    339:        printf("pset 0x%x\n", pset);
                    340: 
                    341:        indent += 2;
                    342: 
                    343:        ipc_object_print(&pset->ips_object);
                    344:        iprintf("local_name = 0x%x\n", pset->ips_local_name);
                    345:        iprintf("kmsgs = 0x%x", pset->ips_messages.imq_messages.ikmq_base);
                    346:        printf(",rcvrs = 0x%x\n", pset->ips_messages.imq_threads.ithq_base);
                    347: 
1.1.1.4 ! root      348:        indent -= 2;
1.1       root      349: }
                    350: 
1.1.1.2   root      351: #endif /* MACH_KDB */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.