FreeBSD/Linux Kernel Cross Reference
sys/ipc/ipc_space.c
1 /*
2 * Mach Operating System
3 * Copyright (c) 1993,1991,1990,1989 Carnegie Mellon University
4 * All Rights Reserved.
5 *
6 * Permission to use, copy, modify and distribute this software and its
7 * documentation is hereby granted, provided that both the copyright
8 * notice and this permission notice appear in all copies of the
9 * software, derivative works or modified versions, and any portions
10 * thereof, and that both notices appear in supporting documentation.
11 *
12 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15 *
16 * Carnegie Mellon requests users of this software to return to
17 *
18 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
19 * School of Computer Science
20 * Carnegie Mellon University
21 * Pittsburgh PA 15213-3890
22 *
23 * any improvements or extensions that they make and grant Carnegie Mellon
24 * the rights to redistribute these changes.
25 */
26 /*
27 * HISTORY
28 * $Log: ipc_space.c,v $
29 * Revision 2.12 93/01/14 17:33:08 danner
30 * 64bit cleanup.
31 * [92/11/30 af]
32 *
33 * Revision 2.11 92/08/03 17:35:34 jfriedl
34 * removed silly prototypes
35 * [92/08/02 jfriedl]
36 *
37 * Revision 2.10 92/05/21 17:11:42 jfriedl
38 * tried prototypes.
39 * [92/05/20 jfriedl]
40 *
41 * Revision 2.9 92/03/10 16:26:21 jsb
42 * NORMA_IPC: declare ipc_space_remote.
43 * [91/12/24 14:00:40 jsb]
44 *
45 * Revision 2.8 91/10/09 16:10:26 af
46 * Revision 2.7.2.1 91/09/16 10:15:57 rpd
47 * Added <ipc/ipc_hash.h>.
48 * [91/09/02 rpd]
49 *
50 * Revision 2.7.2.1 91/09/16 10:15:57 rpd
51 * Added <ipc/ipc_hash.h>.
52 * [91/09/02 rpd]
53 *
54 * Revision 2.7 91/05/14 16:36:44 mrt
55 * Correcting copyright
56 *
57 * Revision 2.6 91/03/16 14:48:37 rpd
58 * Added is_growing.
59 * [91/03/07 16:38:42 rpd]
60 *
61 * Revision 2.5 91/02/05 17:23:43 mrt
62 * Changed to new Mach copyright
63 * [91/02/01 15:51:18 mrt]
64 *
65 * Revision 2.4 91/01/08 15:14:48 rpd
66 * Removed MACH_IPC_GENNOS.
67 * [90/11/08 rpd]
68 *
69 * Revision 2.3 90/11/05 14:30:20 rpd
70 * Use new ip_reference and ip_release.
71 * [90/10/29 rpd]
72 *
73 * Revision 2.2 90/06/02 14:51:39 rpd
74 * Created for new IPC.
75 * [90/03/26 21:03:12 rpd]
76 *
77 */
78 /*
79 * File: ipc/ipc_space.c
80 * Author: Rich Draves
81 * Date: 1989
82 *
83 * Functions to manipulate IPC capability spaces.
84 */
85
86 #include <mach_ipc_compat.h>
87 #include <norma_ipc.h>
88
89 #include <mach/boolean.h>
90 #include <mach/kern_return.h>
91 #include <mach/port.h>
92 #include <kern/assert.h>
93 #include <kern/sched_prim.h>
94 #include <kern/zalloc.h>
95 #include <ipc/port.h>
96 #include <ipc/ipc_entry.h>
97 #include <ipc/ipc_splay.h>
98 #include <ipc/ipc_hash.h>
99 #include <ipc/ipc_table.h>
100 #include <ipc/ipc_port.h>
101 #include <ipc/ipc_space.h>
102 #include <ipc/ipc_right.h>
103
104
105
106 zone_t ipc_space_zone;
107 ipc_space_t ipc_space_kernel;
108 ipc_space_t ipc_space_reply;
109 #if NORMA_IPC
110 ipc_space_t ipc_space_remote;
111 #endif NORMA_IPC
112
113 /*
114 * Routine: ipc_space_reference
115 * Routine: ipc_space_release
116 * Purpose:
117 * Function versions of the IPC space macros.
118 * The "is_" cover macros can be defined to use the
119 * macros or the functions, as desired.
120 */
121
122 void
123 ipc_space_reference(space)
124 ipc_space_t space;
125 {
126 ipc_space_reference_macro(space);
127 }
128
129 void
130 ipc_space_release(space)
131 ipc_space_t space;
132 {
133 ipc_space_release_macro(space);
134 }
135
136 /*
137 * Routine: ipc_space_create
138 * Purpose:
139 * Creates a new IPC space.
140 *
141 * The new space has two references, one for the caller
142 * and one because it is active.
143 * Conditions:
144 * Nothing locked. Allocates memory.
145 * Returns:
146 * KERN_SUCCESS Created a space.
147 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
148 */
149
150 kern_return_t
151 ipc_space_create(initial, spacep)
152 ipc_table_size_t initial;
153 ipc_space_t *spacep;
154 {
155 ipc_space_t space;
156 ipc_entry_t table;
157 ipc_entry_num_t new_size;
158 mach_port_index_t index;
159
160 space = is_alloc();
161 if (space == IS_NULL)
162 return KERN_RESOURCE_SHORTAGE;
163
164 table = it_entries_alloc(initial);
165 if (table == IE_NULL) {
166 is_free(space);
167 return KERN_RESOURCE_SHORTAGE;
168 }
169
170 new_size = initial->its_size;
171 bzero((char *) table, new_size * sizeof(struct ipc_entry));
172
173 /*
174 * Initialize the free list in the table.
175 * Add the entries in reverse order, and
176 * set the generation number to -1, so that
177 * initial allocations produce "natural" names.
178 */
179
180 for (index = 0; index < new_size; index++) {
181 ipc_entry_t entry = &table[index];
182
183 entry->ie_bits = IE_BITS_GEN_MASK;
184 entry->ie_next = index+1;
185 }
186 table[new_size-1].ie_next = 0;
187
188 is_ref_lock_init(space);
189 space->is_references = 2;
190
191 is_lock_init(space);
192 space->is_active = TRUE;
193 space->is_growing = FALSE;
194 space->is_table = table;
195 space->is_table_size = new_size;
196 space->is_table_next = initial+1;
197
198 ipc_splay_tree_init(&space->is_tree);
199 space->is_tree_total = 0;
200 space->is_tree_small = 0;
201 space->is_tree_hash = 0;
202
203 #if MACH_IPC_COMPAT
204 {
205 mach_port_t name;
206 ipc_port_t port;
207 kern_return_t kr;
208
209 /*
210 * ipc_port_alloc_compat probably won't look at is_notify,
211 * but make sure all fields have sane values anyway.
212 */
213
214 space->is_notify = IP_NULL;
215
216 kr = ipc_port_alloc_compat(space, &name, &port);
217 if (kr != KERN_SUCCESS) {
218 ipc_space_destroy(space);
219 is_release(space);
220 return kr;
221 }
222
223 ip_reference(port);
224 port->ip_srights++;
225 ip_unlock(port);
226 space->is_notify = port;
227 }
228 #endif MACH_IPC_COMPAT
229
230 *spacep = space;
231 return KERN_SUCCESS;
232 }
233
234 /*
235 * Routine: ipc_space_create_special
236 * Purpose:
237 * Create a special space. A special space
238 * doesn't hold rights in the normal way.
239 * Instead it is place-holder for holding
240 * disembodied (naked) receive rights.
241 * See ipc_port_alloc_special/ipc_port_dealloc_special.
242 * Conditions:
243 * Nothing locked.
244 * Returns:
245 * KERN_SUCCESS Created a space.
246 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
247 */
248
249 kern_return_t
250 ipc_space_create_special(spacep)
251 ipc_space_t *spacep;
252 {
253 ipc_space_t space;
254
255 space = is_alloc();
256 if (space == IS_NULL)
257 return KERN_RESOURCE_SHORTAGE;
258
259 is_ref_lock_init(space);
260 space->is_references = 1;
261
262 is_lock_init(space);
263 space->is_active = FALSE;
264
265 *spacep = space;
266 return KERN_SUCCESS;
267 }
268
269 /*
270 * Routine: ipc_space_destroy
271 * Purpose:
272 * Marks the space as dead and cleans up the entries.
273 * Does nothing if the space is already dead.
274 * Conditions:
275 * Nothing locked.
276 */
277
278 void
279 ipc_space_destroy(space)
280 ipc_space_t space;
281 {
282 ipc_tree_entry_t tentry;
283 ipc_entry_t table;
284 ipc_entry_num_t size;
285 mach_port_index_t index;
286 boolean_t active;
287
288 assert(space != IS_NULL);
289
290 is_write_lock(space);
291 active = space->is_active;
292 space->is_active = FALSE;
293 is_write_unlock(space);
294
295 if (!active)
296 return;
297
298 /*
299 * If somebody is trying to grow the table,
300 * we must wait until they finish and figure
301 * out the space died.
302 */
303
304 is_read_lock(space);
305 while (space->is_growing) {
306 assert_wait((event_t) space, FALSE);
307 is_read_unlock(space);
308 thread_block((void (*)()) 0);
309 is_read_lock(space);
310 }
311 is_read_unlock(space);
312
313 /*
314 * Now we can futz with it without having it locked.
315 */
316
317 table = space->is_table;
318 size = space->is_table_size;
319
320 for (index = 0; index < size; index++) {
321 ipc_entry_t entry = &table[index];
322 mach_port_type_t type = IE_BITS_TYPE(entry->ie_bits);
323
324 if (type != MACH_PORT_TYPE_NONE) {
325 mach_port_t name =
326 MACH_PORT_MAKEB(index, entry->ie_bits);
327
328 ipc_right_clean(space, name, entry);
329 }
330 }
331
332 it_entries_free(space->is_table_next-1, table);
333
334 for (tentry = ipc_splay_traverse_start(&space->is_tree);
335 tentry != ITE_NULL;
336 tentry = ipc_splay_traverse_next(&space->is_tree, TRUE)) {
337 mach_port_type_t type = IE_BITS_TYPE(tentry->ite_bits);
338 mach_port_t name = tentry->ite_name;
339
340 assert(type != MACH_PORT_TYPE_NONE);
341
342 /* use object before ipc_right_clean releases ref */
343
344 if (type == MACH_PORT_TYPE_SEND)
345 ipc_hash_global_delete(space, tentry->ite_object,
346 name, tentry);
347
348 ipc_right_clean(space, name, &tentry->ite_entry);
349 }
350 ipc_splay_traverse_finish(&space->is_tree);
351
352 #if MACH_IPC_COMPAT
353 if (IP_VALID(space->is_notify))
354 ipc_port_release_send(space->is_notify);
355 #endif MACH_IPC_COMPAT
356
357 /*
358 * Because the space is now dead,
359 * we must release the "active" reference for it.
360 * Our caller still has his reference.
361 */
362
363 is_release(space);
364 }
Cache object: f976ee1413988ee063562d5a70f671f1
|