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