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