FreeBSD/Linux Kernel Cross Reference
sys/ipc/ipc_pset.c
1 /*
2 * Mach Operating System
3 * Copyright (c) 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_pset.c,v $
29 * Revision 2.7 92/08/03 17:35:19 jfriedl
30 * removed silly prototypes
31 * [92/08/02 jfriedl]
32 *
33 * Revision 2.6 92/05/21 17:11:23 jfriedl
34 * tried prototypes.
35 * [92/05/20 jfriedl]
36 *
37 * Revision 2.5 91/05/14 16:35:47 mrt
38 * Correcting copyright
39 *
40 * Revision 2.4 91/02/05 17:23:15 mrt
41 * Changed to new Mach copyright
42 * [91/02/01 15:50:24 mrt]
43 *
44 * Revision 2.3 90/11/05 14:29:47 rpd
45 * Use new ips_reference and ips_release.
46 * [90/10/29 rpd]
47 *
48 * Revision 2.2 90/06/02 14:51:19 rpd
49 * Created for new IPC.
50 * [90/03/26 21:01:53 rpd]
51 *
52 */
53 /*
54 * File: ipc/ipc_pset.c
55 * Author: Rich Draves
56 * Date: 1989
57 *
58 * Functions to manipulate IPC port sets.
59 */
60
61 #include <mach/port.h>
62 #include <mach/kern_return.h>
63 #include <mach/message.h>
64 #include <ipc/ipc_mqueue.h>
65 #include <ipc/ipc_object.h>
66 #include <ipc/ipc_pset.h>
67 #include <ipc/ipc_right.h>
68 #include <ipc/ipc_space.h>
69
70
71 /*
72 * Routine: ipc_pset_alloc
73 * Purpose:
74 * Allocate a port set.
75 * Conditions:
76 * Nothing locked. If successful, the port set is returned
77 * locked. (The caller doesn't have a reference.)
78 * Returns:
79 * KERN_SUCCESS The port set is allocated.
80 * KERN_INVALID_TASK The space is dead.
81 * KERN_NO_SPACE No room for an entry in the space.
82 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
83 */
84
85 kern_return_t
86 ipc_pset_alloc(space, namep, psetp)
87 ipc_space_t space;
88 mach_port_t *namep;
89 ipc_pset_t *psetp;
90 {
91 ipc_pset_t pset;
92 mach_port_t name;
93 kern_return_t kr;
94
95 kr = ipc_object_alloc(space, IOT_PORT_SET,
96 MACH_PORT_TYPE_PORT_SET, 0,
97 &name, (ipc_object_t *) &pset);
98 if (kr != KERN_SUCCESS)
99 return kr;
100 /* pset is locked */
101
102 pset->ips_local_name = name;
103 ipc_mqueue_init(&pset->ips_messages);
104
105 *namep = name;
106 *psetp = pset;
107 return KERN_SUCCESS;
108 }
109
110 /*
111 * Routine: ipc_pset_alloc_name
112 * Purpose:
113 * Allocate a port set, with a specific name.
114 * Conditions:
115 * Nothing locked. If successful, the port set is returned
116 * locked. (The caller doesn't have a reference.)
117 * Returns:
118 * KERN_SUCCESS The port set is allocated.
119 * KERN_INVALID_TASK The space is dead.
120 * KERN_NAME_EXISTS The name already denotes a right.
121 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
122 */
123
124 kern_return_t
125 ipc_pset_alloc_name(space, name, psetp)
126 ipc_space_t space;
127 mach_port_t name;
128 ipc_pset_t *psetp;
129 {
130 ipc_pset_t pset;
131 kern_return_t kr;
132
133 kr = ipc_object_alloc_name(space, IOT_PORT_SET,
134 MACH_PORT_TYPE_PORT_SET, 0,
135 name, (ipc_object_t *) &pset);
136 if (kr != KERN_SUCCESS)
137 return kr;
138 /* pset is locked */
139
140 pset->ips_local_name = name;
141 ipc_mqueue_init(&pset->ips_messages);
142
143 *psetp = pset;
144 return KERN_SUCCESS;
145 }
146
147 /*
148 * Routine: ipc_pset_add
149 * Purpose:
150 * Puts a port into a port set.
151 * The port set gains a reference.
152 * Conditions:
153 * Both port and port set are locked and active.
154 * The port isn't already in a set.
155 * The owner of the port set is also receiver for the port.
156 */
157
158 void
159 ipc_pset_add(pset, port)
160 ipc_pset_t pset;
161 ipc_port_t port;
162 {
163 assert(ips_active(pset));
164 assert(ip_active(port));
165 assert(port->ip_pset == IPS_NULL);
166
167 port->ip_pset = pset;
168 ips_reference(pset);
169
170 imq_lock(&port->ip_messages);
171 imq_lock(&pset->ips_messages);
172
173 /* move messages from port's queue to the port set's queue */
174
175 ipc_mqueue_move(&pset->ips_messages, &port->ip_messages, port);
176 imq_unlock(&pset->ips_messages);
177 assert(ipc_kmsg_queue_empty(&port->ip_messages.imq_messages));
178
179 /* wake up threads waiting to receive from the port */
180
181 ipc_mqueue_changed(&port->ip_messages, MACH_RCV_PORT_CHANGED);
182 assert(ipc_thread_queue_empty(&port->ip_messages.imq_threads));
183 imq_unlock(&port->ip_messages);
184 }
185
186 /*
187 * Routine: ipc_pset_remove
188 * Purpose:
189 * Removes a port from a port set.
190 * The port set loses a reference.
191 * Conditions:
192 * Both port and port set are locked.
193 * The port must be active.
194 */
195
196 void
197 ipc_pset_remove(pset, port)
198 ipc_pset_t pset;
199 ipc_port_t port;
200 {
201 assert(ip_active(port));
202 assert(port->ip_pset == pset);
203
204 port->ip_pset = IPS_NULL;
205 ips_release(pset);
206
207 imq_lock(&port->ip_messages);
208 imq_lock(&pset->ips_messages);
209
210 /* move messages from port set's queue to the port's queue */
211
212 ipc_mqueue_move(&port->ip_messages, &pset->ips_messages, port);
213
214 imq_unlock(&pset->ips_messages);
215 imq_unlock(&port->ip_messages);
216 }
217
218 /*
219 * Routine: ipc_pset_move
220 * Purpose:
221 * If nset is IPS_NULL, removes port
222 * from the port set it is in. Otherwise, adds
223 * port to nset, removing it from any set
224 * it might already be in.
225 * Conditions:
226 * The space is read-locked.
227 * Returns:
228 * KERN_SUCCESS Moved the port.
229 * KERN_NOT_IN_SET nset is null and port isn't in a set.
230 */
231
232 kern_return_t
233 ipc_pset_move(space, port, nset)
234 ipc_space_t space;
235 ipc_port_t port;
236 ipc_pset_t nset;
237 {
238 ipc_pset_t oset;
239
240 /*
241 * While we've got the space locked, it holds refs for
242 * the port and nset (because of the entries). Also,
243 * they must be alive. While we've got port locked, it
244 * holds a ref for oset, which might not be alive.
245 */
246
247 ip_lock(port);
248 assert(ip_active(port));
249
250 oset = port->ip_pset;
251
252 if (oset == nset) {
253 /* the port is already in the new set: a noop */
254
255 is_read_unlock(space);
256 } else if (oset == IPS_NULL) {
257 /* just add port to the new set */
258
259 ips_lock(nset);
260 assert(ips_active(nset));
261 is_read_unlock(space);
262
263 ipc_pset_add(nset, port);
264
265 ips_unlock(nset);
266 } else if (nset == IPS_NULL) {
267 /* just remove port from the old set */
268
269 is_read_unlock(space);
270 ips_lock(oset);
271
272 ipc_pset_remove(oset, port);
273
274 if (ips_active(oset))
275 ips_unlock(oset);
276 else {
277 ips_check_unlock(oset);
278 oset = IPS_NULL; /* trigger KERN_NOT_IN_SET */
279 }
280 } else {
281 /* atomically move port from oset to nset */
282
283 if (oset < nset) {
284 ips_lock(oset);
285 ips_lock(nset);
286 } else {
287 ips_lock(nset);
288 ips_lock(oset);
289 }
290
291 is_read_unlock(space);
292 assert(ips_active(nset));
293
294 ipc_pset_remove(oset, port);
295 ipc_pset_add(nset, port);
296
297 ips_unlock(nset);
298 ips_check_unlock(oset); /* KERN_NOT_IN_SET not a possibility */
299 }
300
301 ip_unlock(port);
302
303 return (((nset == IPS_NULL) && (oset == IPS_NULL)) ?
304 KERN_NOT_IN_SET : KERN_SUCCESS);
305 }
306
307 /*
308 * Routine: ipc_pset_destroy
309 * Purpose:
310 * Destroys a port_set.
311 *
312 * Doesn't remove members from the port set;
313 * that happens lazily. As members are removed,
314 * their messages are removed from the queue.
315 * Conditions:
316 * The port_set is locked and alive.
317 * The caller has a reference, which is consumed.
318 * Afterwards, the port_set is unlocked and dead.
319 */
320
321 void
322 ipc_pset_destroy(pset)
323 ipc_pset_t pset;
324 {
325 assert(ips_active(pset));
326
327 pset->ips_object.io_bits &= ~IO_BITS_ACTIVE;
328
329 imq_lock(&pset->ips_messages);
330 ipc_mqueue_changed(&pset->ips_messages, MACH_RCV_PORT_DIED);
331 imq_unlock(&pset->ips_messages);
332
333 ips_release(pset); /* consume the ref our caller gave us */
334 ips_check_unlock(pset);
335 }
336
337 #include <mach_kdb.h>
338
339
340 #if MACH_KDB
341 #define printf kdbprintf
342
343 /*
344 * Routine: ipc_pset_print
345 * Purpose:
346 * Pretty-print a port set for kdb.
347 */
348
349 void
350 ipc_pset_print(pset)
351 ipc_pset_t pset;
352 {
353 extern int indent;
354
355 printf("pset 0x%x\n", pset);
356
357 indent += 2;
358
359 ipc_object_print(&pset->ips_object);
360 iprintf("local_name = 0x%x\n", pset->ips_local_name);
361 iprintf("kmsgs = 0x%x", pset->ips_messages.imq_messages.ikmq_base);
362 printf(",rcvrs = 0x%x\n", pset->ips_messages.imq_threads.ithq_base);
363
364 indent -=2;
365 }
366
367 #endif MACH_KDB
Cache object: 66e352c7339d0386e0e7419e5674b5f1
|