]> git.saurik.com Git - apple/xnu.git/blob - osfmk/ipc/ipc_pset.c
xnu-792.12.6.tar.gz
[apple/xnu.git] / osfmk / ipc / ipc_pset.c
1 /*
2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
14 * agreement.
15 *
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
18 * file.
19 *
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
27 *
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
29 */
30 /*
31 * @OSF_COPYRIGHT@
32 */
33 /*
34 * Mach Operating System
35 * Copyright (c) 1991,1990,1989 Carnegie Mellon University
36 * All Rights Reserved.
37 *
38 * Permission to use, copy, modify and distribute this software and its
39 * documentation is hereby granted, provided that both the copyright
40 * notice and this permission notice appear in all copies of the
41 * software, derivative works or modified versions, and any portions
42 * thereof, and that both notices appear in supporting documentation.
43 *
44 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
45 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
46 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
47 *
48 * Carnegie Mellon requests users of this software to return to
49 *
50 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
51 * School of Computer Science
52 * Carnegie Mellon University
53 * Pittsburgh PA 15213-3890
54 *
55 * any improvements or extensions that they make and grant Carnegie Mellon
56 * the rights to redistribute these changes.
57 */
58 /*
59 */
60 /*
61 * File: ipc/ipc_pset.c
62 * Author: Rich Draves
63 * Date: 1989
64 *
65 * Functions to manipulate IPC port sets.
66 */
67
68 #include <mach/port.h>
69 #include <mach/kern_return.h>
70 #include <mach/message.h>
71 #include <ipc/ipc_mqueue.h>
72 #include <ipc/ipc_object.h>
73 #include <ipc/ipc_pset.h>
74 #include <ipc/ipc_right.h>
75 #include <ipc/ipc_space.h>
76 #include <ipc/ipc_port.h>
77 #include <ipc/ipc_print.h>
78
79 #include <kern/kern_types.h>
80 #include <kern/spl.h>
81 /*
82 * Routine: ipc_pset_alloc
83 * Purpose:
84 * Allocate a port set.
85 * Conditions:
86 * Nothing locked. If successful, the port set is returned
87 * locked. (The caller doesn't have a reference.)
88 * Returns:
89 * KERN_SUCCESS The port set is allocated.
90 * KERN_INVALID_TASK The space is dead.
91 * KERN_NO_SPACE No room for an entry in the space.
92 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
93 */
94
95 kern_return_t
96 ipc_pset_alloc(
97 ipc_space_t space,
98 mach_port_name_t *namep,
99 ipc_pset_t *psetp)
100 {
101 ipc_pset_t pset;
102 mach_port_name_t name;
103 kern_return_t kr;
104
105 kr = ipc_object_alloc(space, IOT_PORT_SET,
106 MACH_PORT_TYPE_PORT_SET, 0,
107 &name, (ipc_object_t *) &pset);
108 if (kr != KERN_SUCCESS)
109 return kr;
110 /* pset is locked */
111
112 pset->ips_local_name = name;
113 ipc_mqueue_init(&pset->ips_messages, TRUE /* set */);
114
115 *namep = name;
116 *psetp = pset;
117 return KERN_SUCCESS;
118 }
119
120 /*
121 * Routine: ipc_pset_alloc_name
122 * Purpose:
123 * Allocate a port set, with a specific name.
124 * Conditions:
125 * Nothing locked. If successful, the port set is returned
126 * locked. (The caller doesn't have a reference.)
127 * Returns:
128 * KERN_SUCCESS The port set is allocated.
129 * KERN_INVALID_TASK The space is dead.
130 * KERN_NAME_EXISTS The name already denotes a right.
131 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
132 */
133
134 kern_return_t
135 ipc_pset_alloc_name(
136 ipc_space_t space,
137 mach_port_name_t name,
138 ipc_pset_t *psetp)
139 {
140 ipc_pset_t pset;
141 kern_return_t kr;
142
143
144 kr = ipc_object_alloc_name(space, IOT_PORT_SET,
145 MACH_PORT_TYPE_PORT_SET, 0,
146 name, (ipc_object_t *) &pset);
147 if (kr != KERN_SUCCESS)
148 return kr;
149 /* pset is locked */
150
151 pset->ips_local_name = name;
152 ipc_mqueue_init(&pset->ips_messages, TRUE /* set */);
153
154 *psetp = pset;
155 return KERN_SUCCESS;
156 }
157
158 /*
159 * Routine: ipc_pset_member
160 * Purpose:
161 * Checks to see if a port is a member of a pset
162 * Conditions:
163 * Both port and port set are locked.
164 * The port must be active.
165 */
166 boolean_t
167 ipc_pset_member(
168 ipc_pset_t pset,
169 ipc_port_t port)
170 {
171 assert(ip_active(port));
172
173 return (ipc_mqueue_member(&port->ip_messages, &pset->ips_messages));
174 }
175
176
177 /*
178 * Routine: ipc_pset_add
179 * Purpose:
180 * Puts a port into a port set.
181 * Conditions:
182 * Both port and port set are locked and active.
183 * The owner of the port set is also receiver for the port.
184 */
185
186 kern_return_t
187 ipc_pset_add(
188 ipc_pset_t pset,
189 ipc_port_t port)
190 {
191 kern_return_t kr;
192
193 assert(ips_active(pset));
194 assert(ip_active(port));
195
196 kr = ipc_mqueue_add(&port->ip_messages, &pset->ips_messages);
197
198 if (kr == KERN_SUCCESS)
199 port->ip_pset_count++;
200
201 return kr;
202 }
203
204
205
206 /*
207 * Routine: ipc_pset_remove
208 * Purpose:
209 * Removes a port from a port set.
210 * The port set loses a reference.
211 * Conditions:
212 * Both port and port set are locked.
213 * The port must be active.
214 */
215
216 kern_return_t
217 ipc_pset_remove(
218 ipc_pset_t pset,
219 ipc_port_t port)
220 {
221 kern_return_t kr;
222
223 assert(ip_active(port));
224
225 if (port->ip_pset_count == 0)
226 return KERN_NOT_IN_SET;
227
228 kr = ipc_mqueue_remove(&port->ip_messages, &pset->ips_messages);
229
230 if (kr == KERN_SUCCESS)
231 port->ip_pset_count--;
232
233 return kr;
234 }
235
236 /*
237 * Routine: ipc_pset_remove_from_all
238 * Purpose:
239 * Removes a port from all it's port sets.
240 * Conditions:
241 * port is locked and active.
242 */
243
244 kern_return_t
245 ipc_pset_remove_from_all(
246 ipc_port_t port)
247 {
248 assert(ip_active(port));
249
250 if (port->ip_pset_count == 0)
251 return KERN_NOT_IN_SET;
252
253 /*
254 * Remove the port's mqueue from all sets
255 */
256 ipc_mqueue_remove_from_all(&port->ip_messages);
257 port->ip_pset_count = 0;
258 return KERN_SUCCESS;
259 }
260
261
262 /*
263 * Routine: ipc_pset_destroy
264 * Purpose:
265 * Destroys a port_set.
266 * Conditions:
267 * The port_set is locked and alive.
268 * The caller has a reference, which is consumed.
269 * Afterwards, the port_set is unlocked and dead.
270 */
271
272 void
273 ipc_pset_destroy(
274 ipc_pset_t pset)
275 {
276 spl_t s;
277
278 assert(ips_active(pset));
279
280 pset->ips_object.io_bits &= ~IO_BITS_ACTIVE;
281
282 /*
283 * remove all the member message queues
284 */
285 ipc_mqueue_remove_all(&pset->ips_messages);
286
287 s = splsched();
288 imq_lock(&pset->ips_messages);
289 ipc_mqueue_changed(&pset->ips_messages);
290 imq_unlock(&pset->ips_messages);
291 splx(s);
292
293 /* XXXX Perhaps ought to verify ips_thread_pool is empty */
294
295 ips_release(pset); /* consume the ref our caller gave us */
296 ips_check_unlock(pset);
297 }
298
299 #include <mach_kdb.h>
300 #if MACH_KDB
301
302 #include <ddb/db_output.h>
303
304 #define printf kdbprintf
305
306 int
307 ipc_list_count(
308 struct ipc_kmsg *base)
309 {
310 register int count = 0;
311
312 if (base) {
313 struct ipc_kmsg *kmsg = base;
314
315 ++count;
316 while (kmsg && kmsg->ikm_next != base
317 && kmsg->ikm_next != IKM_BOGUS){
318 kmsg = kmsg->ikm_next;
319 ++count;
320 }
321 }
322 return(count);
323 }
324
325 /*
326 * Routine: ipc_pset_print
327 * Purpose:
328 * Pretty-print a port set for kdb.
329 */
330 void
331 ipc_pset_print(
332 ipc_pset_t pset)
333 {
334 printf("pset 0x%x\n", pset);
335
336 db_indent += 2;
337
338 ipc_object_print(&pset->ips_object);
339 iprintf("local_name = 0x%x\n", pset->ips_local_name);
340 iprintf("%d kmsgs => 0x%x",
341 ipc_list_count(pset->ips_messages.imq_messages.ikmq_base),
342 pset->ips_messages.imq_messages.ikmq_base);
343 printf(",rcvrs queue= 0x%x\n", &pset->ips_messages.imq_wait_queue);
344
345 db_indent -=2;
346 }
347
348 #endif /* MACH_KDB */