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