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