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