xref: /xnu-12377.41.6/osfmk/ipc/ipc_notify.c (revision bbb1b6f9e71b8cdde6e5cd6f4841f207dee3d828)
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/mach_notify.h>
68 #include <kern/ipc_kobject.h>
69 #include <ipc/ipc_notify.h>
70 #include <ipc/ipc_policy.h>
71 
72 /*!
73  * @abstract
74  * Perform a check on whether forming a notification message
75  * to the specified notification port can be elided.
76  *
77  * @discussion
78  * This is racy but helps avoiding costly messages to be formed
79  * just to be destroyed because the notification port is already
80  * dead.
81  *
82  * This happens quite a lot during ipc_space_terminate(): all
83  * receive rights are destroyed first, then other ports.
84  * This avoids sending notifications to receive rights in that
85  * space reliably.
86  */
87 static inline bool
ipc_notify_should_send(ipc_port_t notification_port)88 ipc_notify_should_send(ipc_port_t notification_port)
89 {
90 	return ip_active(notification_port);
91 }
92 
93 void
ipc_notify_dead_name(ipc_port_t port,mach_port_name_t name)94 ipc_notify_dead_name(ipc_port_t port, mach_port_name_t name)
95 {
96 	if (ipc_notify_should_send(port)) {
97 		(void)mach_notify_dead_name(port, name);
98 		/* send-once right consumed */
99 	} else {
100 		ipc_port_release_sonce(port);
101 	}
102 }
103 
104 void
ipc_notify_send_possible(ipc_port_t port,mach_port_name_t name)105 ipc_notify_send_possible(ipc_port_t port, mach_port_name_t name)
106 {
107 	if (ipc_notify_should_send(port)) {
108 		(void)mach_notify_send_possible(port, name);
109 		/* send-once right consumed */
110 	} else {
111 		ipc_port_release_sonce(port);
112 	}
113 }
114 
115 void
ipc_notify_port_deleted(ipc_port_t port,mach_port_name_t name)116 ipc_notify_port_deleted(ipc_port_t port, mach_port_name_t name)
117 {
118 	if (ipc_notify_should_send(port)) {
119 		(void)mach_notify_port_deleted(port, name);
120 		/* send-once right consumed */
121 	} else {
122 		ipc_port_release_sonce(port);
123 	}
124 }
125 
126 void
ipc_notify_port_destroyed(ipc_port_t port,ipc_port_t right)127 ipc_notify_port_destroyed(ipc_port_t port, ipc_port_t right)
128 {
129 	mach_notify_port_destroyed(port, right);
130 	/* send-once and receive rights consumed */
131 }
132 
133 ipc_notify_nsenders_t
ipc_notify_no_senders_prepare(ipc_port_t port)134 ipc_notify_no_senders_prepare(ipc_port_t port)
135 {
136 	ipc_notify_nsenders_t req = { };
137 	ipc_object_type_t type = ip_type(port);
138 
139 	ip_mq_lock_held(port);
140 
141 	if (io_is_kobject_type(type)) {
142 		if (ip_active(port) && ipc_policy(type)->pol_notif_no_senders) {
143 			ip_reference(port);
144 			req.ns_notify = port;
145 			req.ns_mscount = port->ip_mscount;
146 			req.ns_is_kobject = true;
147 		}
148 	} else if (port->ip_nsrequest) {
149 		ipc_release_assert(ipc_policy(type)->pol_notif_no_senders);
150 		req.ns_notify = port->ip_nsrequest;
151 		req.ns_mscount = port->ip_mscount;
152 		req.ns_is_kobject = false;
153 
154 		port->ip_nsrequest = IP_NULL;
155 	}
156 
157 	return req;
158 }
159 
160 void
ipc_notify_no_senders_mqueue(ipc_port_t port,mach_port_mscount_t mscount)161 ipc_notify_no_senders_mqueue(ipc_port_t port, mach_port_mscount_t mscount)
162 {
163 	if (ipc_notify_should_send(port)) {
164 		(void)mach_notify_no_senders(port, mscount);
165 		/* send-once right consumed */
166 	} else {
167 		ipc_port_release_sonce(port);
168 	}
169 }
170 
171 void
ipc_notify_no_senders_kobject(ipc_port_t port,mach_port_mscount_t mscount)172 ipc_notify_no_senders_kobject(ipc_port_t port, mach_port_mscount_t mscount)
173 {
174 	if (ipc_notify_should_send(port)) {
175 		ipc_policy(port)->pol_kobject_no_senders(port, mscount);
176 	}
177 	ip_release(port);
178 }
179 
180 void
ipc_notify_send_once_and_unlock(ipc_port_t port)181 ipc_notify_send_once_and_unlock(ipc_port_t port)
182 {
183 	/*
184 	 * clear any reply context:
185 	 * no one will be sending the response b/c we are destroying
186 	 * the single, outstanding send once right.
187 	 */
188 	port->ip_reply_context = 0;
189 
190 	if (!ip_active(port)) {
191 		ipc_port_release_sonce_and_unlock(port);
192 	} else if (ip_in_space(port, ipc_space_kernel)) {
193 		ipc_kobject_notify_send_once_and_unlock(port);
194 	} else if (ip_full_kernel(port)) {
195 		ipc_port_release_sonce_and_unlock(port);
196 	} else {
197 		ip_mq_unlock(port);
198 		(void)mach_notify_send_once(port);
199 	}
200 	/* send-once right consumed */
201 }
202