|
|
1.1 ! root 1: /* ! 2: * Mach Operating System ! 3: * Copyright (c) 1991,1990,1989 Carnegie 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: * File: ipc/ipc_marequest.c ! 31: * Author: Rich Draves ! 32: * Date: 1989 ! 33: * ! 34: * Functions to handle msg-accepted requests. ! 35: */ ! 36: ! 37: #include <mach_ipc_compat.h> ! 38: ! 39: #include <mach/message.h> ! 40: #include <mach/port.h> ! 41: #include <kern/lock.h> ! 42: #include <kern/mach_param.h> ! 43: #include <kern/kalloc.h> ! 44: #include <kern/zalloc.h> ! 45: #include <ipc/port.h> ! 46: #include <ipc/ipc_init.h> ! 47: #include <ipc/ipc_space.h> ! 48: #include <ipc/ipc_entry.h> ! 49: #include <ipc/ipc_port.h> ! 50: #include <ipc/ipc_right.h> ! 51: #include <ipc/ipc_marequest.h> ! 52: #include <ipc/ipc_notify.h> ! 53: ! 54: #include <mach_ipc_debug.h> ! 55: #if MACH_IPC_DEBUG ! 56: #include <mach/kern_return.h> ! 57: #include <mach_debug/hash_info.h> ! 58: #include <vm/vm_map.h> ! 59: #include <vm/vm_kern.h> ! 60: #include <vm/vm_user.h> ! 61: #endif ! 62: ! 63: ! 64: zone_t ipc_marequest_zone; ! 65: int ipc_marequest_max = IMAR_MAX; ! 66: ! 67: #define imar_alloc() ((ipc_marequest_t) zalloc(ipc_marequest_zone)) ! 68: #define imar_free(imar) zfree(ipc_marequest_zone, (vm_offset_t) (imar)) ! 69: ! 70: typedef unsigned int ipc_marequest_index_t; ! 71: ! 72: ipc_marequest_index_t ipc_marequest_size; ! 73: ipc_marequest_index_t ipc_marequest_mask; ! 74: ! 75: #define IMAR_HASH(space, name) \ ! 76: ((((ipc_marequest_index_t)((vm_offset_t)space) >> 4) + \ ! 77: MACH_PORT_INDEX(name) + MACH_PORT_NGEN(name)) & \ ! 78: ipc_marequest_mask) ! 79: ! 80: typedef struct ipc_marequest_bucket { ! 81: decl_simple_lock_data(, imarb_lock_data) ! 82: ipc_marequest_t imarb_head; ! 83: } *ipc_marequest_bucket_t; ! 84: ! 85: #define IMARB_NULL ((ipc_marequest_bucket_t) 0) ! 86: ! 87: #define imarb_lock_init(imarb) simple_lock_init(&(imarb)->imarb_lock_data) ! 88: #define imarb_lock(imarb) simple_lock(&(imarb)->imarb_lock_data) ! 89: #define imarb_unlock(imarb) simple_unlock(&(imarb)->imarb_lock_data) ! 90: ! 91: ipc_marequest_bucket_t ipc_marequest_table; ! 92: ! 93: ! 94: ! 95: /* ! 96: * Routine: ipc_marequest_init ! 97: * Purpose: ! 98: * Initialize the msg-accepted request module. ! 99: */ ! 100: ! 101: void ! 102: ipc_marequest_init() ! 103: { ! 104: ipc_marequest_index_t i; ! 105: ! 106: /* if not configured, initialize ipc_marequest_size */ ! 107: ! 108: if (ipc_marequest_size == 0) { ! 109: ipc_marequest_size = ipc_marequest_max >> 8; ! 110: if (ipc_marequest_size < 16) ! 111: ipc_marequest_size = 16; ! 112: } ! 113: ! 114: /* make sure it is a power of two */ ! 115: ! 116: ipc_marequest_mask = ipc_marequest_size - 1; ! 117: if ((ipc_marequest_size & ipc_marequest_mask) != 0) { ! 118: unsigned int bit; ! 119: ! 120: /* round up to closest power of two */ ! 121: ! 122: for (bit = 1;; bit <<= 1) { ! 123: ipc_marequest_mask |= bit; ! 124: ipc_marequest_size = ipc_marequest_mask + 1; ! 125: ! 126: if ((ipc_marequest_size & ipc_marequest_mask) == 0) ! 127: break; ! 128: } ! 129: } ! 130: ! 131: /* allocate ipc_marequest_table */ ! 132: ! 133: ipc_marequest_table = (ipc_marequest_bucket_t) ! 134: kalloc((vm_size_t) (ipc_marequest_size * ! 135: sizeof(struct ipc_marequest_bucket))); ! 136: assert(ipc_marequest_table != IMARB_NULL); ! 137: ! 138: /* and initialize it */ ! 139: ! 140: for (i = 0; i < ipc_marequest_size; i++) { ! 141: ipc_marequest_bucket_t bucket; ! 142: ! 143: bucket = &ipc_marequest_table[i]; ! 144: imarb_lock_init(bucket); ! 145: bucket->imarb_head = IMAR_NULL; ! 146: } ! 147: ! 148: ipc_marequest_zone = ! 149: zinit(sizeof(struct ipc_marequest), ! 150: ipc_marequest_max * sizeof(struct ipc_marequest), ! 151: sizeof(struct ipc_marequest), ! 152: IPC_ZONE_TYPE, "ipc msg-accepted requests"); ! 153: } ! 154: ! 155: /* ! 156: * Routine: ipc_marequest_create ! 157: * Purpose: ! 158: * Create a msg-accepted request, because ! 159: * a sender is forcing a message with MACH_SEND_NOTIFY. ! 160: * ! 161: * The "notify" argument should name a receive right ! 162: * that is used to create the send-once notify port. ! 163: * ! 164: * [MACH_IPC_COMPAT] If "notify" is MACH_PORT_NULL, ! 165: * then an old-style msg-accepted request is created. ! 166: * Conditions: ! 167: * Nothing locked; refs held for space and port. ! 168: * Returns: ! 169: * MACH_MSG_SUCCESS Msg-accepted request created. ! 170: * MACH_SEND_INVALID_NOTIFY The space is dead. ! 171: * MACH_SEND_INVALID_NOTIFY The notify port is bad. ! 172: * MACH_SEND_NOTIFY_IN_PROGRESS ! 173: * This space has already forced a message to this port. ! 174: * MACH_SEND_NO_NOTIFY Can't allocate a msg-accepted request. ! 175: */ ! 176: ! 177: mach_msg_return_t ! 178: ipc_marequest_create(space, port, notify, marequestp) ! 179: ipc_space_t space; ! 180: ipc_port_t port; ! 181: mach_port_t notify; ! 182: ipc_marequest_t *marequestp; ! 183: { ! 184: mach_port_t name; ! 185: ipc_entry_t entry; ! 186: ipc_port_t soright; ! 187: ipc_marequest_t marequest; ! 188: ipc_marequest_bucket_t bucket; ! 189: ! 190: #if !MACH_IPC_COMPAT ! 191: assert(notify != MACH_PORT_NULL); ! 192: #endif /* !MACH_IPC_COMPAT */ ! 193: ! 194: marequest = imar_alloc(); ! 195: if (marequest == IMAR_NULL) ! 196: return MACH_SEND_NO_NOTIFY; ! 197: ! 198: /* ! 199: * Delay creating the send-once right until ! 200: * we know there will be no errors. Otherwise, ! 201: * we would have to worry about disposing of it ! 202: * when it turned out it wasn't needed. ! 203: */ ! 204: ! 205: is_write_lock(space); ! 206: if (!space->is_active) { ! 207: is_write_unlock(space); ! 208: imar_free(marequest); ! 209: return MACH_SEND_INVALID_NOTIFY; ! 210: } ! 211: ! 212: if (ipc_right_reverse(space, (ipc_object_t) port, &name, &entry)) { ! 213: ipc_entry_bits_t bits; ! 214: ! 215: /* port is locked and active */ ! 216: ip_unlock(port); ! 217: bits = entry->ie_bits; ! 218: ! 219: assert(port == (ipc_port_t) entry->ie_object); ! 220: assert(bits & MACH_PORT_TYPE_SEND_RECEIVE); ! 221: ! 222: if (bits & IE_BITS_MAREQUEST) { ! 223: is_write_unlock(space); ! 224: imar_free(marequest); ! 225: return MACH_SEND_NOTIFY_IN_PROGRESS; ! 226: } ! 227: ! 228: #if MACH_IPC_COMPAT ! 229: if (notify == MACH_PORT_NULL) ! 230: soright = IP_NULL; ! 231: else ! 232: #endif /* MACH_IPC_COMPAT */ ! 233: if ((soright = ipc_port_lookup_notify(space, notify)) ! 234: == IP_NULL) { ! 235: is_write_unlock(space); ! 236: imar_free(marequest); ! 237: return MACH_SEND_INVALID_NOTIFY; ! 238: } ! 239: ! 240: entry->ie_bits = bits | IE_BITS_MAREQUEST; ! 241: ! 242: is_reference(space); ! 243: marequest->imar_space = space; ! 244: marequest->imar_name = name; ! 245: marequest->imar_soright = soright; ! 246: ! 247: bucket = &ipc_marequest_table[IMAR_HASH(space, name)]; ! 248: imarb_lock(bucket); ! 249: ! 250: marequest->imar_next = bucket->imarb_head; ! 251: bucket->imarb_head = marequest; ! 252: ! 253: imarb_unlock(bucket); ! 254: } else { ! 255: #if MACH_IPC_COMPAT ! 256: if (notify == MACH_PORT_NULL) ! 257: soright = IP_NULL; ! 258: else ! 259: #endif /* MACH_IPC_COMPAT */ ! 260: if ((soright = ipc_port_lookup_notify(space, notify)) ! 261: == IP_NULL) { ! 262: is_write_unlock(space); ! 263: imar_free(marequest); ! 264: return MACH_SEND_INVALID_NOTIFY; ! 265: } ! 266: ! 267: is_reference(space); ! 268: marequest->imar_space = space; ! 269: marequest->imar_name = MACH_PORT_NULL; ! 270: marequest->imar_soright = soright; ! 271: } ! 272: ! 273: is_write_unlock(space); ! 274: *marequestp = marequest; ! 275: return MACH_MSG_SUCCESS; ! 276: } ! 277: ! 278: /* ! 279: * Routine: ipc_marequest_cancel ! 280: * Purpose: ! 281: * Cancel a msg-accepted request, because ! 282: * the space's entry is being destroyed. ! 283: * Conditions: ! 284: * The space is write-locked and active. ! 285: */ ! 286: ! 287: void ! 288: ipc_marequest_cancel(space, name) ! 289: ipc_space_t space; ! 290: mach_port_t name; ! 291: { ! 292: ipc_marequest_bucket_t bucket; ! 293: ipc_marequest_t marequest, *last; ! 294: ! 295: assert(space->is_active); ! 296: ! 297: bucket = &ipc_marequest_table[IMAR_HASH(space, name)]; ! 298: imarb_lock(bucket); ! 299: ! 300: for (last = &bucket->imarb_head; ! 301: (marequest = *last) != IMAR_NULL; ! 302: last = &marequest->imar_next) ! 303: if ((marequest->imar_space == space) && ! 304: (marequest->imar_name == name)) ! 305: break; ! 306: ! 307: assert(marequest != IMAR_NULL); ! 308: *last = marequest->imar_next; ! 309: imarb_unlock(bucket); ! 310: ! 311: marequest->imar_name = MACH_PORT_NULL; ! 312: } ! 313: ! 314: /* ! 315: * Routine: ipc_marequest_rename ! 316: * Purpose: ! 317: * Rename a msg-accepted request, because the entry ! 318: * in the space is being renamed. ! 319: * Conditions: ! 320: * The space is write-locked and active. ! 321: */ ! 322: ! 323: void ! 324: ipc_marequest_rename(space, old, new) ! 325: ipc_space_t space; ! 326: mach_port_t old, new; ! 327: { ! 328: ipc_marequest_bucket_t bucket; ! 329: ipc_marequest_t marequest, *last; ! 330: ! 331: assert(space->is_active); ! 332: ! 333: bucket = &ipc_marequest_table[IMAR_HASH(space, old)]; ! 334: imarb_lock(bucket); ! 335: ! 336: for (last = &bucket->imarb_head; ! 337: (marequest = *last) != IMAR_NULL; ! 338: last = &marequest->imar_next) ! 339: if ((marequest->imar_space == space) && ! 340: (marequest->imar_name == old)) ! 341: break; ! 342: ! 343: assert(marequest != IMAR_NULL); ! 344: *last = marequest->imar_next; ! 345: imarb_unlock(bucket); ! 346: ! 347: marequest->imar_name = new; ! 348: ! 349: bucket = &ipc_marequest_table[IMAR_HASH(space, new)]; ! 350: imarb_lock(bucket); ! 351: ! 352: marequest->imar_next = bucket->imarb_head; ! 353: bucket->imarb_head = marequest; ! 354: ! 355: imarb_unlock(bucket); ! 356: } ! 357: ! 358: /* ! 359: * Routine: ipc_marequest_destroy ! 360: * Purpose: ! 361: * Destroy a msg-accepted request, because ! 362: * the kernel message is being received/destroyed. ! 363: * Conditions: ! 364: * Nothing locked. ! 365: */ ! 366: ! 367: void ! 368: ipc_marequest_destroy(marequest) ! 369: ipc_marequest_t marequest; ! 370: { ! 371: ipc_space_t space = marequest->imar_space; ! 372: mach_port_t name; ! 373: ipc_port_t soright; ! 374: #if MACH_IPC_COMPAT ! 375: ipc_port_t sright = IP_NULL; ! 376: #endif /* MACH_IPC_COMPAT */ ! 377: ! 378: is_write_lock(space); ! 379: ! 380: name = marequest->imar_name; ! 381: soright = marequest->imar_soright; ! 382: ! 383: if (name != MACH_PORT_NULL) { ! 384: ipc_marequest_bucket_t bucket; ! 385: ipc_marequest_t this, *last; ! 386: ! 387: bucket = &ipc_marequest_table[IMAR_HASH(space, name)]; ! 388: imarb_lock(bucket); ! 389: ! 390: for (last = &bucket->imarb_head; ! 391: (this = *last) != IMAR_NULL; ! 392: last = &this->imar_next) ! 393: if ((this->imar_space == space) && ! 394: (this->imar_name == name)) ! 395: break; ! 396: ! 397: assert(this == marequest); ! 398: *last = this->imar_next; ! 399: imarb_unlock(bucket); ! 400: ! 401: if (space->is_active) { ! 402: ipc_entry_t entry; ! 403: ! 404: entry = ipc_entry_lookup(space, name); ! 405: assert(entry != IE_NULL); ! 406: assert(entry->ie_bits & IE_BITS_MAREQUEST); ! 407: assert(entry->ie_bits & MACH_PORT_TYPE_SEND_RECEIVE); ! 408: ! 409: entry->ie_bits &= ~IE_BITS_MAREQUEST; ! 410: ! 411: #if MACH_IPC_COMPAT ! 412: if (soright == IP_NULL) ! 413: sright = ipc_space_make_notify(space); ! 414: #endif /* MACH_IPC_COMPAT */ ! 415: } else ! 416: name = MACH_PORT_NULL; ! 417: } ! 418: ! 419: is_write_unlock(space); ! 420: is_release(space); ! 421: ! 422: imar_free(marequest); ! 423: ! 424: #if MACH_IPC_COMPAT ! 425: if (soright == IP_NULL) { ! 426: if (IP_VALID(sright)) { ! 427: assert(name != MACH_PORT_NULL); ! 428: ipc_notify_msg_accepted_compat(sright, name); ! 429: } ! 430: ! 431: return; ! 432: } ! 433: assert(sright == IP_NULL); ! 434: #endif /* MACH_IPC_COMPAT */ ! 435: ! 436: assert(soright != IP_NULL); ! 437: ipc_notify_msg_accepted(soright, name); ! 438: } ! 439: ! 440: #if MACH_IPC_DEBUG ! 441: ! 442: ! 443: /* ! 444: * Routine: ipc_marequest_info ! 445: * Purpose: ! 446: * Return information about the marequest hash table. ! 447: * Fills the buffer with as much information as possible ! 448: * and returns the desired size of the buffer. ! 449: * Conditions: ! 450: * Nothing locked. The caller should provide ! 451: * possibly-pageable memory. ! 452: */ ! 453: ! 454: unsigned int ! 455: ipc_marequest_info(maxp, info, count) ! 456: unsigned int *maxp; ! 457: hash_info_bucket_t *info; ! 458: unsigned int count; ! 459: { ! 460: ipc_marequest_index_t i; ! 461: ! 462: if (ipc_marequest_size < count) ! 463: count = ipc_marequest_size; ! 464: ! 465: for (i = 0; i < count; i++) { ! 466: ipc_marequest_bucket_t bucket = &ipc_marequest_table[i]; ! 467: unsigned int bucket_count = 0; ! 468: ipc_marequest_t marequest; ! 469: ! 470: imarb_lock(bucket); ! 471: for (marequest = bucket->imarb_head; ! 472: marequest != IMAR_NULL; ! 473: marequest = marequest->imar_next) ! 474: bucket_count++; ! 475: imarb_unlock(bucket); ! 476: ! 477: /* don't touch pageable memory while holding locks */ ! 478: info[i].hib_count = bucket_count; ! 479: } ! 480: ! 481: *maxp = ipc_marequest_max; ! 482: return ipc_marequest_size; ! 483: } ! 484: ! 485: #endif /* MACH_IPC_DEBUG */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.