]> git.saurik.com Git - apple/xnu.git/blob - osfmk/ipc/ipc_pset.c
xnu-344.49.tar.gz
[apple/xnu.git] / osfmk / ipc / ipc_pset.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
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
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
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.
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_pset.c
57 * Author: Rich Draves
58 * Date: 1989
59 *
60 * Functions to manipulate IPC port sets.
61 */
62
63 #include <mach/port.h>
64 #include <mach/kern_return.h>
65 #include <mach/message.h>
66 #include <ipc/ipc_mqueue.h>
67 #include <ipc/ipc_object.h>
68 #include <ipc/ipc_pset.h>
69 #include <ipc/ipc_right.h>
70 #include <ipc/ipc_space.h>
71 #include <ipc/ipc_port.h>
72 #include <ipc/ipc_print.h>
73
74 /*
75 * Routine: ipc_pset_alloc
76 * Purpose:
77 * Allocate a port set.
78 * Conditions:
79 * Nothing locked. If successful, the port set is returned
80 * locked. (The caller doesn't have a reference.)
81 * Returns:
82 * KERN_SUCCESS The port set is allocated.
83 * KERN_INVALID_TASK The space is dead.
84 * KERN_NO_SPACE No room for an entry in the space.
85 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
86 */
87
88 kern_return_t
89 ipc_pset_alloc(
90 ipc_space_t space,
91 mach_port_name_t *namep,
92 ipc_pset_t *psetp)
93 {
94 ipc_pset_t pset;
95 mach_port_name_t name;
96 kern_return_t kr;
97
98 kr = ipc_object_alloc(space, IOT_PORT_SET,
99 MACH_PORT_TYPE_PORT_SET, 0,
100 &name, (ipc_object_t *) &pset);
101 if (kr != KERN_SUCCESS)
102 return kr;
103 /* pset is locked */
104
105 pset->ips_local_name = name;
106 ipc_mqueue_init(&pset->ips_messages, TRUE /* set */);
107
108 *namep = name;
109 *psetp = pset;
110 return KERN_SUCCESS;
111 }
112
113 /*
114 * Routine: ipc_pset_alloc_name
115 * Purpose:
116 * Allocate a port set, with a specific name.
117 * Conditions:
118 * Nothing locked. If successful, the port set is returned
119 * locked. (The caller doesn't have a reference.)
120 * Returns:
121 * KERN_SUCCESS The port set is allocated.
122 * KERN_INVALID_TASK The space is dead.
123 * KERN_NAME_EXISTS The name already denotes a right.
124 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
125 */
126
127 kern_return_t
128 ipc_pset_alloc_name(
129 ipc_space_t space,
130 mach_port_name_t name,
131 ipc_pset_t *psetp)
132 {
133 ipc_pset_t pset;
134 kern_return_t kr;
135
136
137 kr = ipc_object_alloc_name(space, IOT_PORT_SET,
138 MACH_PORT_TYPE_PORT_SET, 0,
139 name, (ipc_object_t *) &pset);
140 if (kr != KERN_SUCCESS)
141 return kr;
142 /* pset is locked */
143
144 pset->ips_local_name = name;
145 ipc_mqueue_init(&pset->ips_messages, TRUE /* set */);
146
147 *psetp = pset;
148 return KERN_SUCCESS;
149 }
150
151 /*
152 * Routine: ipc_pset_member
153 * Purpose:
154 * Checks to see if a port is a member of a pset
155 * Conditions:
156 * Both port and port set are locked.
157 * The port must be active.
158 */
159 boolean_t
160 ipc_pset_member(
161 ipc_pset_t pset,
162 ipc_port_t port)
163 {
164 assert(ip_active(port));
165
166 return (ipc_mqueue_member(&port->ip_messages, &pset->ips_messages));
167 }
168
169
170 /*
171 * Routine: ipc_pset_add
172 * Purpose:
173 * Puts a port into a port set.
174 * Conditions:
175 * Both port and port set are locked and active.
176 * The owner of the port set is also receiver for the port.
177 */
178
179 kern_return_t
180 ipc_pset_add(
181 ipc_pset_t pset,
182 ipc_port_t port)
183 {
184 kern_return_t kr;
185
186 assert(ips_active(pset));
187 assert(ip_active(port));
188
189 kr = ipc_mqueue_add(&port->ip_messages, &pset->ips_messages);
190
191 if (kr == KERN_SUCCESS)
192 port->ip_pset_count++;
193
194 return kr;
195 }
196
197
198
199 /*
200 * Routine: ipc_pset_remove
201 * Purpose:
202 * Removes a port from a port set.
203 * The port set loses a reference.
204 * Conditions:
205 * Both port and port set are locked.
206 * The port must be active.
207 */
208
209 kern_return_t
210 ipc_pset_remove(
211 ipc_pset_t pset,
212 ipc_port_t port)
213 {
214 kern_return_t kr;
215
216 assert(ip_active(port));
217
218 if (port->ip_pset_count == 0)
219 return KERN_NOT_IN_SET;
220
221 kr = ipc_mqueue_remove(&port->ip_messages, &pset->ips_messages);
222
223 if (kr == KERN_SUCCESS)
224 port->ip_pset_count--;
225
226 return kr;
227 }
228
229 /*
230 * Routine: ipc_pset_remove_from_all
231 * Purpose:
232 * Removes a port from all it's port sets.
233 * Conditions:
234 * port is locked and active.
235 */
236
237 kern_return_t
238 ipc_pset_remove_from_all(
239 ipc_port_t port)
240 {
241 ipc_pset_t pset;
242
243 assert(ip_active(port));
244
245 if (port->ip_pset_count == 0)
246 return KERN_NOT_IN_SET;
247
248 /*
249 * Remove the port's mqueue from all sets
250 */
251 ipc_mqueue_remove_from_all(&port->ip_messages);
252 port->ip_pset_count = 0;
253 return KERN_SUCCESS;
254 }
255
256
257 /*
258 * Routine: ipc_pset_destroy
259 * Purpose:
260 * Destroys a port_set.
261 * Conditions:
262 * The port_set is locked and alive.
263 * The caller has a reference, which is consumed.
264 * Afterwards, the port_set is unlocked and dead.
265 */
266
267 void
268 ipc_pset_destroy(
269 ipc_pset_t pset)
270 {
271 spl_t s;
272
273 assert(ips_active(pset));
274
275 pset->ips_object.io_bits &= ~IO_BITS_ACTIVE;
276
277 /*
278 * remove all the member message queues
279 */
280 ipc_mqueue_remove_all(&pset->ips_messages);
281
282 s = splsched();
283 imq_lock(&pset->ips_messages);
284 ipc_mqueue_changed(&pset->ips_messages);
285 imq_unlock(&pset->ips_messages);
286 splx(s);
287
288 /* XXXX Perhaps ought to verify ips_thread_pool is empty */
289
290 ips_release(pset); /* consume the ref our caller gave us */
291 ips_check_unlock(pset);
292 }
293
294 #include <mach_kdb.h>
295 #if MACH_KDB
296
297 #include <ddb/db_output.h>
298
299 #define printf kdbprintf
300
301 int
302 ipc_list_count(
303 struct ipc_kmsg *base)
304 {
305 register int count = 0;
306
307 if (base) {
308 struct ipc_kmsg *kmsg = base;
309
310 ++count;
311 while (kmsg && kmsg->ikm_next != base
312 && kmsg->ikm_next != IKM_BOGUS){
313 kmsg = kmsg->ikm_next;
314 ++count;
315 }
316 }
317 return(count);
318 }
319
320 /*
321 * Routine: ipc_pset_print
322 * Purpose:
323 * Pretty-print a port set for kdb.
324 */
325
326 void
327 ipc_pset_print(
328 ipc_pset_t pset)
329 {
330 extern int db_indent;
331
332 printf("pset 0x%x\n", pset);
333
334 db_indent += 2;
335
336 ipc_object_print(&pset->ips_object);
337 iprintf("local_name = 0x%x\n", pset->ips_local_name);
338 iprintf("%d kmsgs => 0x%x",
339 ipc_list_count(pset->ips_messages.imq_messages.ikmq_base),
340 pset->ips_messages.imq_messages.ikmq_base);
341 printf(",rcvrs queue= 0x%x\n", &pset->ips_messages.imq_wait_queue);
342
343 db_indent -=2;
344 }
345
346 #endif /* MACH_KDB */