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