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