|
|
1.1 root 1: /*
2: * Mach Operating System
3: * Copyright (c) 1991,1990,1989Carnegie Mellon University.
4: * Copyright (c) 1993,1994 The University of Utah and
5: * the Computer Systems Laboratory (CSL).
6: * All rights reserved.
7: *
8: * Permission to use, copy, modify and distribute this software and its
9: * documentation is hereby granted, provided that both the copyright
10: * notice and this permission notice appear in all copies of the
11: * software, derivative works or modified versions, and any portions
12: * thereof, and that both notices appear in supporting documentation.
13: *
14: * CARNEGIE MELLON, THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF
15: * THIS SOFTWARE IN ITS "AS IS" CONDITION, AND DISCLAIM ANY LIABILITY
16: * OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF
17: * THIS SOFTWARE.
18: *
19: * Carnegie Mellon requests users of this software to return to
20: *
21: * Software Distribution Coordinator or [email protected]
22: * School of Computer Science
23: * Carnegie Mellon University
24: * Pittsburgh PA 15213-3890
25: *
26: * any improvements or extensions that they make and grant Carnegie Mellon
27: * the rights to redistribute these changes.
28: */
29: /*
30: */
31: /*
32: * File: ipc/ipc_pset.c
33: * Author: Rich Draves
34: * Date: 1989
35: *
36: * Functions to manipulate IPC port sets.
37: */
38:
39: #include <mach/port.h>
40: #include <mach/kern_return.h>
41: #include <mach/message.h>
42: #include <ipc/ipc_mqueue.h>
43: #include <ipc/ipc_object.h>
44: #include <ipc/ipc_pset.h>
45: #include <ipc/ipc_right.h>
46: #include <ipc/ipc_space.h>
47:
48:
49: /*
50: * Routine: ipc_pset_alloc
51: * Purpose:
52: * Allocate a port set.
53: * Conditions:
54: * Nothing locked. If successful, the port set is returned
55: * locked. (The caller doesn't have a reference.)
56: * Returns:
57: * KERN_SUCCESS The port set is allocated.
58: * KERN_INVALID_TASK The space is dead.
59: * KERN_NO_SPACE No room for an entry in the space.
60: * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
61: */
62:
63: kern_return_t
64: ipc_pset_alloc(
65: ipc_space_t space,
66: mach_port_t *namep,
67: ipc_pset_t *psetp)
68: {
69: ipc_pset_t pset;
70: mach_port_t name;
71: kern_return_t kr;
72:
73: kr = ipc_object_alloc(space, IOT_PORT_SET,
74: MACH_PORT_TYPE_PORT_SET, 0,
75: &name, (ipc_object_t *) &pset);
76: if (kr != KERN_SUCCESS)
77: return kr;
78: /* pset is locked */
79:
80: ipc_target_init(&pset->ips_target, name);
81:
82: *namep = name;
83: *psetp = pset;
84: return KERN_SUCCESS;
85: }
86:
87: /*
88: * Routine: ipc_pset_alloc_name
89: * Purpose:
90: * Allocate a port set, with a specific name.
91: * Conditions:
92: * Nothing locked. If successful, the port set is returned
93: * locked. (The caller doesn't have a reference.)
94: * Returns:
95: * KERN_SUCCESS The port set is allocated.
96: * KERN_INVALID_TASK The space is dead.
97: * KERN_NAME_EXISTS The name already denotes a right.
98: * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
99: */
100:
101: kern_return_t
102: ipc_pset_alloc_name(
103: ipc_space_t space,
104: mach_port_t name,
105: ipc_pset_t *psetp)
106: {
107: ipc_pset_t pset;
108: kern_return_t kr;
109:
110:
111: kr = ipc_object_alloc_name(space, IOT_PORT_SET,
112: MACH_PORT_TYPE_PORT_SET, 0,
113: name, (ipc_object_t *) &pset);
114: if (kr != KERN_SUCCESS)
115: return kr;
116: /* pset is locked */
117:
118: ipc_target_init(&pset->ips_target, name);
119:
120: *psetp = pset;
121: return KERN_SUCCESS;
122: }
123:
124: /*
125: * Routine: ipc_pset_add
126: * Purpose:
127: * Puts a port into a port set.
128: * The port set gains a reference.
129: * Conditions:
130: * Both port and port set are locked and active.
131: * The port isn't already in a set.
132: * The owner of the port set is also receiver for the port.
133: */
134:
135: void
136: ipc_pset_add(
137: ipc_pset_t pset,
138: ipc_port_t port)
139: {
140: assert(ips_active(pset));
141: assert(ip_active(port));
142: assert(port->ip_pset == IPS_NULL);
143:
144: port->ip_pset = pset;
145: port->ip_cur_target = &pset->ips_target;
146: ips_reference(pset);
147:
148: imq_lock(&port->ip_messages);
149: imq_lock(&pset->ips_messages);
150:
151: /* move messages from port's queue to the port set's queue */
152:
153: ipc_mqueue_move(&pset->ips_messages, &port->ip_messages, port);
154: imq_unlock(&pset->ips_messages);
155: assert(ipc_kmsg_queue_empty(&port->ip_messages.imq_messages));
156:
157: /* wake up threads waiting to receive from the port */
158:
159: ipc_mqueue_changed(&port->ip_messages, MACH_RCV_PORT_CHANGED);
160: assert(ipc_thread_queue_empty(&port->ip_messages.imq_threads));
161: imq_unlock(&port->ip_messages);
162: }
163:
164: /*
165: * Routine: ipc_pset_remove
166: * Purpose:
167: * Removes a port from a port set.
168: * The port set loses a reference.
169: * Conditions:
170: * Both port and port set are locked.
171: * The port must be active.
172: */
173:
174: void
175: ipc_pset_remove(
176: ipc_pset_t pset,
177: ipc_port_t port)
178: {
179: assert(ip_active(port));
180: assert(port->ip_pset == pset);
181:
182: port->ip_pset = IPS_NULL;
183: port->ip_cur_target = &port->ip_target;
184: ips_release(pset);
185:
186: imq_lock(&port->ip_messages);
187: imq_lock(&pset->ips_messages);
188:
189: /* move messages from port set's queue to the port's queue */
190:
191: ipc_mqueue_move(&port->ip_messages, &pset->ips_messages, port);
192:
193: imq_unlock(&pset->ips_messages);
194: imq_unlock(&port->ip_messages);
195: }
196:
197: /*
198: * Routine: ipc_pset_move
199: * Purpose:
200: * If nset is IPS_NULL, removes port
201: * from the port set it is in. Otherwise, adds
202: * port to nset, removing it from any set
203: * it might already be in.
204: * Conditions:
205: * The space is read-locked.
206: * Returns:
207: * KERN_SUCCESS Moved the port.
208: * KERN_NOT_IN_SET nset is null and port isn't in a set.
209: */
210:
211: kern_return_t
212: ipc_pset_move(
213: ipc_space_t space,
214: ipc_port_t port,
215: ipc_pset_t nset)
216: {
217: ipc_pset_t oset;
218:
219: /*
220: * While we've got the space locked, it holds refs for
221: * the port and nset (because of the entries). Also,
222: * they must be alive. While we've got port locked, it
223: * holds a ref for oset, which might not be alive.
224: */
225:
226: ip_lock(port);
227: assert(ip_active(port));
228:
229: oset = port->ip_pset;
230:
231: if (oset == nset) {
232: /* the port is already in the new set: a noop */
233:
234: is_read_unlock(space);
235: } else if (oset == IPS_NULL) {
236: /* just add port to the new set */
237:
238: ips_lock(nset);
239: assert(ips_active(nset));
240: is_read_unlock(space);
241:
242: ipc_pset_add(nset, port);
243:
244: ips_unlock(nset);
245: } else if (nset == IPS_NULL) {
246: /* just remove port from the old set */
247:
248: is_read_unlock(space);
249: ips_lock(oset);
250:
251: ipc_pset_remove(oset, port);
252:
253: if (ips_active(oset))
254: ips_unlock(oset);
255: else {
256: ips_check_unlock(oset);
257: oset = IPS_NULL; /* trigger KERN_NOT_IN_SET */
258: }
259: } else {
260: /* atomically move port from oset to nset */
261:
262: if (oset < nset) {
263: ips_lock(oset);
264: ips_lock(nset);
265: } else {
266: ips_lock(nset);
267: ips_lock(oset);
268: }
269:
270: is_read_unlock(space);
271: assert(ips_active(nset));
272:
273: ipc_pset_remove(oset, port);
274: ipc_pset_add(nset, port);
275:
276: ips_unlock(nset);
277: ips_check_unlock(oset); /* KERN_NOT_IN_SET not a possibility */
278: }
279:
280: ip_unlock(port);
281:
282: return (((nset == IPS_NULL) && (oset == IPS_NULL)) ?
283: KERN_NOT_IN_SET : KERN_SUCCESS);
284: }
285:
286: /*
287: * Routine: ipc_pset_destroy
288: * Purpose:
289: * Destroys a port_set.
290: *
291: * Doesn't remove members from the port set;
292: * that happens lazily. As members are removed,
293: * their messages are removed from the queue.
294: * Conditions:
295: * The port_set is locked and alive.
296: * The caller has a reference, which is consumed.
297: * Afterwards, the port_set is unlocked and dead.
298: */
299:
300: void
301: ipc_pset_destroy(
302: ipc_pset_t pset)
303: {
304: assert(ips_active(pset));
305:
306: pset->ips_object.io_bits &= ~IO_BITS_ACTIVE;
307:
308: imq_lock(&pset->ips_messages);
309: ipc_mqueue_changed(&pset->ips_messages, MACH_RCV_PORT_DIED);
310: imq_unlock(&pset->ips_messages);
311:
312: /* Common destruction for the IPC target. */
313: ipc_target_terminate(&pset->ips_target);
314:
315: ips_release(pset); /* consume the ref our caller gave us */
316: ips_check_unlock(pset);
317: }
318:
319: #include <mach_kdb.h>
320:
321:
322: #if MACH_KDB
323: #define printf kdbprintf
324:
325: /*
326: * Routine: ipc_pset_print
327: * Purpose:
328: * Pretty-print a port set for kdb.
329: */
330:
331: void
332: ipc_pset_print(
333: ipc_pset_t pset)
334: {
335: extern int indent;
336:
337: printf("pset 0x%x\n", pset);
338:
339: indent += 2;
340:
341: ipc_object_print(&pset->ips_object);
342: iprintf("local_name = 0x%x\n", pset->ips_local_name);
343: iprintf("kmsgs = 0x%x", pset->ips_messages.imq_messages.ikmq_base);
344: printf(",rcvrs = 0x%x\n", pset->ips_messages.imq_threads.ithq_base);
345:
346: indent -=2;
347: }
348:
349: #endif /* MACH_KDB */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.