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