|
|
1.1 root 1: /*
2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22: /*
23: * @OSF_COPYRIGHT@
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: */
52: /*
53: * File: ipc/ipc_space.c
54: * Author: Rich Draves
55: * Date: 1989
56: *
57: * Functions to manipulate IPC capability spaces.
58: */
59:
60: #include <dipc.h>
61: #include <mach_kdb.h>
62:
63: #include <mach/boolean.h>
64: #include <mach/kern_return.h>
65: #include <mach/port.h>
66: #include <kern/assert.h>
67: #include <kern/sched_prim.h>
68: #include <kern/zalloc.h>
69: #include <ipc/port.h>
70: #include <ipc/ipc_entry.h>
71: #include <ipc/ipc_splay.h>
72: #include <ipc/ipc_object.h>
73: #include <ipc/ipc_hash.h>
74: #include <ipc/ipc_table.h>
75: #include <ipc/ipc_port.h>
76: #include <ipc/ipc_space.h>
77: #include <ipc/ipc_right.h>
78: #include <string.h>
79:
80: zone_t ipc_space_zone;
81: ipc_space_t ipc_space_kernel;
82: ipc_space_t ipc_space_reply;
83: #if DIPC
84: ipc_space_t ipc_space_remote;
85: #endif /* DIPC */
86: #if DIPC || MACH_KDB
87: ipc_space_t default_pager_space;
88: #endif /* DIPC || MACH_KDB */
89:
90: /*
91: * Routine: ipc_space_reference
92: * Routine: ipc_space_release
93: * Purpose:
94: * Function versions of the IPC space macros.
95: * The "is_" cover macros can be defined to use the
96: * macros or the functions, as desired.
97: */
98:
99: void
100: ipc_space_reference(
101: ipc_space_t space)
102: {
103: ipc_space_reference_macro(space);
104: }
105:
106: void
107: ipc_space_release(
108: ipc_space_t space)
109: {
110: ipc_space_release_macro(space);
111: }
112:
113: /*
114: * Routine: ipc_space_create
115: * Purpose:
116: * Creates a new IPC space.
117: *
118: * The new space has two references, one for the caller
119: * and one because it is active.
120: * Conditions:
121: * Nothing locked. Allocates memory.
122: * Returns:
123: * KERN_SUCCESS Created a space.
124: * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
125: */
126:
127: kern_return_t
128: ipc_space_create(
129: ipc_table_size_t initial,
130: ipc_space_t *spacep)
131: {
132: ipc_space_t space;
133: ipc_entry_t table;
134: ipc_entry_num_t new_size;
135: mach_port_index_t index;
136:
137: space = is_alloc();
138: if (space == IS_NULL)
139: return KERN_RESOURCE_SHORTAGE;
140:
141: table = it_entries_alloc(initial);
142: if (table == IE_NULL) {
143: is_free(space);
144: return KERN_RESOURCE_SHORTAGE;
145: }
146:
147: new_size = initial->its_size;
148: memset((void *) table, 0, new_size * sizeof(struct ipc_entry));
149:
150: /*
151: * Initialize the free list in the table.
152: * Add the entries in reverse order, and
153: * set the generation number to -1, so that
154: * initial allocations produce "natural" names.
155: */
156: for (index = 0; index < new_size; index++) {
157: ipc_entry_t entry = &table[index];
158:
159: entry->ie_bits = IE_BITS_GEN_MASK;
160: entry->ie_next = index+1;
161: }
162: table[new_size-1].ie_next = 0;
163:
164: is_ref_lock_init(space);
165: space->is_references = 2;
166:
167: is_lock_init(space);
168: space->is_active = TRUE;
169: space->is_growing = FALSE;
170: space->is_table = table;
171: space->is_table_size = new_size;
172: space->is_table_next = initial+1;
173:
174: ipc_splay_tree_init(&space->is_tree);
175: space->is_tree_total = 0;
176: space->is_tree_small = 0;
177: space->is_tree_hash = 0;
178:
179: *spacep = space;
180: return KERN_SUCCESS;
181: }
182:
183: /*
184: * Routine: ipc_space_create_special
185: * Purpose:
186: * Create a special space. A special space
187: * doesn't hold rights in the normal way.
188: * Instead it is place-holder for holding
189: * disembodied (naked) receive rights.
190: * See ipc_port_alloc_special/ipc_port_dealloc_special.
191: * Conditions:
192: * Nothing locked.
193: * Returns:
194: * KERN_SUCCESS Created a space.
195: * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
196: */
197:
198: kern_return_t
199: ipc_space_create_special(
200: ipc_space_t *spacep)
201: {
202: ipc_space_t space;
203:
204: space = is_alloc();
205: if (space == IS_NULL)
206: return KERN_RESOURCE_SHORTAGE;
207:
208: is_ref_lock_init(space);
209: space->is_references = 1;
210:
211: is_lock_init(space);
212: space->is_active = FALSE;
213:
214: *spacep = space;
215: return KERN_SUCCESS;
216: }
217:
218: /*
219: * ipc_space_clean - remove all port references from an ipc space.
220: *
221: * In order to follow the traditional semantic, ipc_space_destroy
222: * will not destroy the entire port table of a shared space. Instead
223: * it will simply clear its own sub-space.
224: */
225: void
226: ipc_space_clean(
227: ipc_space_t space)
228: {
229: ipc_tree_entry_t tentry;
230: ipc_entry_t table;
231: ipc_entry_num_t size;
232: mach_port_index_t index;
233:
234: /*
235: * If somebody is trying to grow the table,
236: * we must wait until they finish and figure
237: * out the space died.
238: */
239: is_write_lock(space);
240: while (space->is_growing) {
241: assert_wait((event_t) space, THREAD_UNINT);
242: is_write_unlock(space);
243: thread_block((void (*)(void)) 0);
244: is_write_lock(space);
245: }
246:
247: /*
248: * Now we can futz with it since we have the write lock.
249: */
250: #if DIPC || MACH_KDB
251: if (space == default_pager_space)
252: default_pager_space = IS_NULL;
253: #endif /* DIPC || MACH_KDB */
254:
255: table = space->is_table;
256: size = space->is_table_size;
257:
258: for (index = 0; index < size; index++) {
259: ipc_entry_t entry = &table[index];
260: mach_port_type_t type;
261:
262: type = IE_BITS_TYPE(entry->ie_bits);
263: if (type != MACH_PORT_TYPE_NONE) {
264: mach_port_name_t name = MACH_PORT_MAKE(index,
265: IE_BITS_GEN(entry->ie_bits));
266: ipc_right_destroy(space, name, entry);
267: }
268: }
269:
270: /*
271: * JMM - Now the table is cleaned out. We don't bother shrinking the
272: * size of the table at this point, but we probably should if it is
273: * really large. Lets just clean up the splay tree.
274: */
275: start_splay:
276: for (tentry = ipc_splay_traverse_start(&space->is_tree);
277: tentry != ITE_NULL;
278: tentry = ipc_splay_traverse_next(&space->is_tree, TRUE)) {
279: int i;
280: mach_port_type_t type;
281: mach_port_name_t name = tentry->ite_name;
282:
283: type = IE_BITS_TYPE(tentry->ite_bits);
284: /*
285: * If it is a real right, then destroy it. This will have the
286: * side effect of removing it from the splay, so start over.
287: */
288: if(type != MACH_PORT_TYPE_NONE) {
289: ipc_splay_traverse_finish(&space->is_tree);
290: ipc_right_destroy(space, name, &tentry->ite_entry);
291: goto start_splay;
292: }
293: }
294: ipc_splay_traverse_finish(&space->is_tree);
295: is_write_unlock(space);
296: }
297:
298:
299: /*
300: * Routine: ipc_space_destroy
301: * Purpose:
302: * Marks the space as dead and cleans up the entries.
303: * Does nothing if the space is already dead.
304: * Conditions:
305: * Nothing locked.
306: */
307:
308: void
309: ipc_space_destroy(
310: ipc_space_t space)
311: {
312: boolean_t active;
313: ipc_tree_entry_t tentry;
314: ipc_entry_t table;
315: ipc_entry_num_t size;
316: mach_port_index_t index;
317:
318: assert(space != IS_NULL);
319:
320: is_write_lock(space);
321: active = space->is_active;
322: space->is_active = FALSE;
323: is_write_unlock(space);
324:
325: if (!active)
326: return;
327:
328:
329: /*
330: * If somebody is trying to grow the table,
331: * we must wait until they finish and figure
332: * out the space died.
333: */
334: is_read_lock(space);
335: while (space->is_growing) {
336: assert_wait((event_t) space, THREAD_UNINT);
337: is_read_unlock(space);
338: thread_block((void (*)(void)) 0);
339: is_read_lock(space);
340: }
341:
342: is_read_unlock(space);
343: /*
344: * Now we can futz with it unlocked.
345: */
346: #if DIPC || MACH_KDB
347: if (space == default_pager_space)
348: default_pager_space = IS_NULL;
349: #endif /* DIPC || MACH_KDB */
350:
351: table = space->is_table;
352: size = space->is_table_size;
353:
354: for (index = 0; index < size; index++) {
355: ipc_entry_t entry = &table[index];
356: mach_port_type_t type;
357:
358: type = IE_BITS_TYPE(entry->ie_bits);
359: if (type != MACH_PORT_TYPE_NONE) {
360: mach_port_name_t name;
361:
362: name = MACH_PORT_MAKE(index,
363: IE_BITS_GEN(entry->ie_bits));
364: ipc_right_clean(space, name, entry);
365: }
366: }
367:
368: it_entries_free(space->is_table_next-1, table);
369: space->is_table_size = 0;
370:
371: for (tentry = ipc_splay_traverse_start(&space->is_tree);
372: tentry != ITE_NULL;
373: tentry = ipc_splay_traverse_next(&space->is_tree, TRUE)) {
374: mach_port_type_t type;
375: mach_port_name_t name = tentry->ite_name;
376:
377: type = IE_BITS_TYPE(tentry->ite_bits);
378: assert(type != MACH_PORT_TYPE_NONE);
379:
380: ipc_right_clean(space, name, &tentry->ite_entry);
381:
382: if(type == MACH_PORT_TYPE_SEND)
383: ipc_hash_global_delete(space, tentry->ite_object,
384: name, tentry);
385: }
386: ipc_splay_traverse_finish(&space->is_tree);
387:
388: /*
389: * Because the space is now dead,
390: * we must release the "active" reference for it.
391: * Our caller still has his reference.
392: */
393: is_release(space);
394: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.