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