xref: /xnu-8019.80.24/osfmk/ipc/ipc_notify.c (revision a325d9c4a84054e40bbe985afedcb50ab80993ea)
1 /*
2  * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 /*
29  * @OSF_COPYRIGHT@
30  */
31 /*
32  * Mach Operating System
33  * Copyright (c) 1991,1990,1989 Carnegie Mellon University
34  * All Rights Reserved.
35  *
36  * Permission to use, copy, modify and distribute this software and its
37  * documentation is hereby granted, provided that both the copyright
38  * notice and this permission notice appear in all copies of the
39  * software, derivative works or modified versions, and any portions
40  * thereof, and that both notices appear in supporting documentation.
41  *
42  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
43  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
44  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
45  *
46  * Carnegie Mellon requests users of this software to return to
47  *
48  *  Software Distribution Coordinator  or  [email protected]
49  *  School of Computer Science
50  *  Carnegie Mellon University
51  *  Pittsburgh PA 15213-3890
52  *
53  * any improvements or extensions that they make and grant Carnegie Mellon
54  * the rights to redistribute these changes.
55  */
56 /*
57  */
58 /*
59  *	File:	ipc/ipc_notify.c
60  *	Author:	Rich Draves
61  *	Date:	1989
62  *
63  *	Notification-sending functions.
64  */
65 
66 #include <mach/port.h>
67 #include <mach/message.h>
68 #include <mach/mach_notify.h>
69 #include <kern/misc_protos.h>
70 #include <kern/ipc_kobject.h>
71 #include <ipc/ipc_notify.h>
72 #include <ipc/ipc_port.h>
73 
74 /*
75  *	Routine:	ipc_notify_port_deleted
76  *	Purpose:
77  *		Send a port-deleted notification.
78  *	Conditions:
79  *		Nothing locked.
80  *		Consumes a ref/soright for port.
81  */
82 
83 void
ipc_notify_port_deleted(ipc_port_t port,mach_port_name_t name)84 ipc_notify_port_deleted(
85 	ipc_port_t              port,
86 	mach_port_name_t        name)
87 {
88 	(void)mach_notify_port_deleted(port, name);
89 	/* send-once right consumed */
90 }
91 
92 /*
93  *	Routine:	ipc_notify_send_possible
94  *	Purpose:
95  *		Send a send-possible notification.
96  *	Conditions:
97  *		Nothing locked.
98  *		Consumes a ref/soright for port.
99  */
100 
101 void
ipc_notify_send_possible(ipc_port_t port,mach_port_name_t name)102 ipc_notify_send_possible(
103 	ipc_port_t              port,
104 	mach_port_name_t        name)
105 {
106 	(void)mach_notify_send_possible(port, name);
107 	/* send-once right consumed */
108 }
109 
110 /*
111  *	Routine:	ipc_notify_port_destroyed
112  *	Purpose:
113  *		Send a port-destroyed notification.
114  *	Conditions:
115  *		Nothing locked.
116  *		Consumes a ref/soright for port.
117  *		Consumes a ref for right, which should be a receive right
118  *		prepped for placement into a message.  (In-transit,
119  *		or in-limbo if a circularity was detected.)
120  */
121 
122 void
ipc_notify_port_destroyed(ipc_port_t port,ipc_port_t right)123 ipc_notify_port_destroyed(
124 	ipc_port_t      port,
125 	ipc_port_t      right)
126 {
127 	mach_notify_port_destroyed(port, right);
128 	/* send-once and receive rights consumed */
129 }
130 
131 /*
132  *	Routine:	ipc_notify_no_senders_prepare
133  *	Purpose:
134  *		Prepare for consuming a no senders notification
135  *		when the port send right count just hit 0.
136  *	Conditions:
137  *		The port is locked.
138  *
139  *		For kobjects (ns_is_kobject), the `ns_notify` port has a reference.
140  *		For regular ports, the `ns_notify` has an outstanding send once right.
141  *	Returns:
142  *		A token that must be passed to ipc_notify_no_senders_emit.
143  */
144 ipc_notify_nsenders_t
ipc_notify_no_senders_prepare(ipc_port_t port)145 ipc_notify_no_senders_prepare(
146 	ipc_port_t              port)
147 {
148 	ipc_notify_nsenders_t req = { };
149 
150 	ip_mq_lock_held(port);
151 
152 	if (port->ip_kobject_nsrequest) {
153 		assert(port->ip_nsrequest == IP_NULL);
154 		port->ip_kobject_nsrequest = false;
155 
156 		if (ip_active(port)) {
157 			req.ns_notify = port;
158 			req.ns_mscount = port->ip_mscount;
159 			req.ns_is_kobject = true;
160 		} else {
161 			/* silently consume the port-ref */
162 			ip_release_live(port);
163 		}
164 	} else if (port->ip_nsrequest) {
165 		req.ns_notify = port->ip_nsrequest;
166 		req.ns_mscount = port->ip_mscount;
167 		req.ns_is_kobject = false;
168 
169 		port->ip_nsrequest = IP_NULL;
170 	}
171 
172 	return req;
173 }
174 
175 /*
176  *	Routine:	ipc_notify_no_senders
177  *	Purpose:
178  *		Send a no-senders notification.
179  *	Conditions:
180  *		Nothing locked.
181  *		Consumes a ref/soright for port.
182  */
183 
184 void
ipc_notify_no_senders(ipc_port_t port,mach_port_mscount_t mscount,boolean_t kobject)185 ipc_notify_no_senders(
186 	ipc_port_t              port,
187 	mach_port_mscount_t     mscount,
188 	boolean_t               kobject)
189 {
190 	if (kobject) {
191 		ipc_kobject_notify_no_senders(port, mscount);
192 	} else {
193 		(void)mach_notify_no_senders(port, mscount);
194 		/* send-once right consumed */
195 	}
196 }
197 
198 /*
199  *	Routine:	ipc_notify_no_senders_consume
200  *	Purpose:
201  *		Consume a no-senders notification.
202  *	Conditions:
203  *		Nothing locked.
204  *		Consumes a ref/soright for port.
205  */
206 
207 void
ipc_notify_no_senders_consume(ipc_notify_nsenders_t nsrequest)208 ipc_notify_no_senders_consume(
209 	ipc_notify_nsenders_t   nsrequest)
210 {
211 	if (nsrequest.ns_notify) {
212 		if (nsrequest.ns_is_kobject) {
213 			ip_release(nsrequest.ns_notify);
214 		} else {
215 			ipc_port_release_sonce(nsrequest.ns_notify);
216 		}
217 	}
218 }
219 
220 /*
221  *	Routine:	ipc_notify_send_once_and_unlock
222  *	Purpose:
223  *		Send a send-once notification.
224  *	Conditions:
225  *		Port is locked.
226  *		Consumes a ref/soright for port.
227  */
228 
229 void
ipc_notify_send_once_and_unlock(ipc_port_t port)230 ipc_notify_send_once_and_unlock(
231 	ipc_port_t      port)
232 {
233 	if (!ip_active(port)) {
234 		ipc_port_release_sonce_and_unlock(port);
235 	} else if (ip_in_space(port, ipc_space_kernel)) {
236 		ipc_kobject_notify_send_once_and_unlock(port);
237 	} else if (ip_full_kernel(port)) {
238 		ipc_port_release_sonce_and_unlock(port);
239 	} else {
240 		ip_mq_unlock(port);
241 		(void)mach_notify_send_once(port);
242 	}
243 	/* send-once right consumed */
244 }
245 
246 /*
247  *	Routine:	ipc_notify_dead_name
248  *	Purpose:
249  *		Send a dead-name notification.
250  *	Conditions:
251  *		Nothing locked.
252  *		Consumes a ref/soright for port.
253  */
254 
255 void
ipc_notify_dead_name(ipc_port_t port,mach_port_name_t name)256 ipc_notify_dead_name(
257 	ipc_port_t              port,
258 	mach_port_name_t        name)
259 {
260 	(void)mach_notify_dead_name(port, name);
261 	/* send-once right consumed */
262 }
263