socknotify.c revision 8348:4137e18bfaf0
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#include <sys/types.h>
28#include <sys/param.h>
29#include <sys/systm.h>
30#include <sys/stropts.h>
31#include <sys/socketvar.h>
32#include <sys/ksocket.h>
33#include <io/ksocket/ksocket_impl.h>
34#include <fs/sockfs/sockcommon.h>
35
36/*
37 * There can only be a single thread waiting for data (enforced by
38 * so_lock_read()), whereas for write there might be multiple threads
39 * waiting for transmit buffers. So therefore we use cv_broadcast for
40 * write and cv_signal for read.
41 */
42#define	SO_WAKEUP_READER(so) {				\
43	if ((so)->so_rcv_wakeup) {			\
44		(so)->so_rcv_wakeup = B_FALSE;		\
45		cv_signal(&(so)->so_rcv_cv);		\
46	}						\
47}
48
49#define	SO_WAKEUP_WRITER(so) {			\
50	if ((so)->so_snd_wakeup) {		\
51		(so)->so_snd_wakeup = B_FALSE;	\
52		cv_broadcast(&(so)->so_snd_cv);	\
53	}					\
54}
55
56static int i_so_notify_last_rx(struct sonode *, int *, int *);
57static int i_so_notify_last_tx(struct sonode *, int *, int *);
58
59/*
60 * The notification functions must be called with so_lock held,
61 * and they will all *drop* so_lock before returning.
62 */
63
64/*
65 * Wake up anyone waiting for the connection to be established.
66 */
67void
68so_notify_connected(struct sonode *so)
69{
70	ASSERT(MUTEX_HELD(&so->so_lock));
71
72	if (IS_KERNEL_SOCKET(so)) {
73		KSOCKET_CALLBACK(so, connected, 0);
74		mutex_exit(&so->so_lock);
75	} else {
76		socket_sendsig(so, SOCKETSIG_WRITE);
77		mutex_exit(&so->so_lock);
78		pollwakeup(&so->so_poll_list, POLLOUT);
79	}
80
81	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
82}
83
84/*
85 * The socket is disconnecting, so no more data can be sent. Wake up
86 * anyone that is waiting to send data.
87 */
88void
89so_notify_disconnecting(struct sonode *so)
90{
91	int pollev = 0;
92	int sigev = 0;
93
94	ASSERT(MUTEX_HELD(&so->so_lock));
95
96	if (IS_KERNEL_SOCKET(so)) {
97		SO_WAKEUP_WRITER(so);
98		KSOCKET_CALLBACK(so, cantsendmore, 0);
99		mutex_exit(&so->so_lock);
100	} else if (i_so_notify_last_tx(so, &pollev, &sigev)) {
101		socket_sendsig(so, sigev);
102		mutex_exit(&so->so_lock);
103		pollwakeup(&so->so_poll_list, pollev);
104	} else {
105		mutex_exit(&so->so_lock);
106	}
107
108	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
109}
110
111/*
112 * The socket is disconnected, so not more data can be sent or received.
113 * Wake up anyone that is waiting to send or receive data.
114 */
115void
116so_notify_disconnected(struct sonode *so, int error)
117{
118	int pollev = 0;
119	int sigev = 0;
120
121	ASSERT(MUTEX_HELD(&so->so_lock));
122
123	(void) i_so_notify_last_tx(so, &pollev, &sigev);
124	(void) i_so_notify_last_rx(so, &pollev, &sigev);
125
126	if (IS_KERNEL_SOCKET(so)) {
127		KSOCKET_CALLBACK(so, disconnected, error);
128		mutex_exit(&so->so_lock);
129	} else {
130		if (sigev != 0)
131			socket_sendsig(so, sigev);
132		mutex_exit(&so->so_lock);
133		if (pollev != 0)
134			pollwakeup(&so->so_poll_list, pollev);
135	}
136
137	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
138}
139
140/*
141 * The socket is writeable. Wake up anyone waiting to send data.
142 */
143void
144so_notify_writable(struct sonode *so)
145{
146	ASSERT(MUTEX_HELD(&so->so_lock));
147
148	SO_WAKEUP_WRITER(so);
149
150	if (IS_KERNEL_SOCKET(so)) {
151		KSOCKET_CALLBACK(so, cansend, 0);
152		mutex_exit(&so->so_lock);
153	} else {
154		socket_sendsig(so, SOCKETSIG_WRITE);
155		mutex_exit(&so->so_lock);
156		pollwakeup(&so->so_poll_list, POLLOUT);
157	}
158
159	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
160}
161
162/*
163 * Data is available, so wake up anyone waiting for data.
164 */
165void
166so_notify_data(struct sonode *so, size_t qlen)
167{
168	ASSERT(MUTEX_HELD(&so->so_lock));
169
170	SO_WAKEUP_READER(so);
171
172	if (IS_KERNEL_SOCKET(so)) {
173		KSOCKET_CALLBACK(so, newdata, qlen);
174		mutex_exit(&so->so_lock);
175	} else {
176		socket_sendsig(so, SOCKETSIG_READ);
177		if (so->so_pollev & (SO_POLLEV_IN|SO_POLLEV_ALWAYS)) {
178			so->so_pollev &= ~SO_POLLEV_IN;
179			mutex_exit(&so->so_lock);
180			pollwakeup(&so->so_poll_list, POLLIN|POLLRDNORM);
181		} else {
182			mutex_exit(&so->so_lock);
183		}
184	}
185
186	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
187}
188
189/*
190 * Transient error. Wake up anyone waiting to send or receive data.
191 */
192void
193so_notify_error(struct sonode *so)
194{
195	ASSERT(MUTEX_HELD(&so->so_lock));
196
197	SO_WAKEUP_WRITER(so);
198	SO_WAKEUP_READER(so);
199
200	if (IS_KERNEL_SOCKET(so)) {
201		KSOCKET_CALLBACK(so, error, 0);
202		mutex_exit(&so->so_lock);
203	} else {
204		socket_sendsig(so, SOCKETSIG_WRITE|SOCKETSIG_READ);
205		so->so_pollev &= ~SO_POLLEV_IN;
206		mutex_exit(&so->so_lock);
207		pollwakeup(&so->so_poll_list, POLLOUT|POLLIN|POLLRDNORM);
208	}
209
210	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
211}
212
213/*
214 * Out-of-band data is incoming, notify any interested parties.
215 */
216void
217so_notify_oobsig(struct sonode *so)
218{
219	socket_sendsig(so, SOCKETSIG_URG);
220	mutex_exit(&so->so_lock);
221	pollwakeup(&so->so_poll_list, POLLRDBAND);
222}
223
224/*
225 * Received out-of-band data. If the OOB data is delivered inline, then
226 * in addition of regular OOB notification, anyone waiting for normal
227 * data is also notified.
228 */
229void
230so_notify_oobdata(struct sonode *so, boolean_t oob_inline)
231{
232	ASSERT(MUTEX_HELD(&so->so_lock));
233	SOD_UIOAFINI(so->so_direct);
234
235	if (IS_KERNEL_SOCKET(so)) {
236		if (oob_inline)
237			SO_WAKEUP_READER(so);
238		KSOCKET_CALLBACK(so, oobdata, 0);
239		mutex_exit(&so->so_lock);
240	} else {
241		if (oob_inline) {
242			socket_sendsig(so, SOCKETSIG_READ);
243			so->so_pollev &= ~SO_POLLEV_IN;
244			mutex_exit(&so->so_lock);
245			pollwakeup(&so->so_poll_list,
246			    POLLRDBAND|POLLIN|POLLRDNORM);
247
248			SO_WAKEUP_READER(so);
249		} else {
250			mutex_exit(&so->so_lock);
251			pollwakeup(&so->so_poll_list, POLLRDBAND);
252		}
253	}
254
255	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
256}
257
258/*
259 * End-of-file has been reach, so peer will send no new data. Wake up
260 * anyone that is waiting for data.
261 */
262void
263so_notify_eof(struct sonode *so)
264{
265	int pollev = 0;
266	int sigev = 0;
267
268	ASSERT(MUTEX_HELD(&so->so_lock));
269
270	(void) i_so_notify_last_rx(so, &pollev, &sigev);
271
272	if (IS_KERNEL_SOCKET(so)) {
273		SO_WAKEUP_READER(so);
274		KSOCKET_CALLBACK(so, cantrecvmore, 0);
275		mutex_exit(&so->so_lock);
276	} else {
277		if (sigev != 0)
278			socket_sendsig(so, sigev);
279		mutex_exit(&so->so_lock);
280		if (pollev != 0)
281			pollwakeup(&so->so_poll_list, pollev);
282
283	}
284
285	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
286}
287
288/*
289 * Wake up anyone waiting for a new connection.
290 */
291void
292so_notify_newconn(struct sonode *so)
293{
294	ASSERT(MUTEX_HELD(&so->so_lock));
295
296	if (IS_KERNEL_SOCKET(so)) {
297		KSOCKET_CALLBACK(so, newconn, so->so_rcv_queued);
298		mutex_exit(&so->so_lock);
299	} else {
300		socket_sendsig(so, SOCKETSIG_READ);
301		if (so->so_pollev & (SO_POLLEV_IN|SO_POLLEV_ALWAYS)) {
302			so->so_pollev &= ~SO_POLLEV_IN;
303			mutex_exit(&so->so_lock);
304			pollwakeup(&so->so_poll_list, POLLIN|POLLRDNORM);
305		} else {
306			mutex_exit(&so->so_lock);
307		}
308	}
309
310	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
311}
312
313/*
314 * User initated shutdown/close, wake anyone that is trying to do
315 * an operation that is no longer possible.
316 */
317void
318so_notify_shutdown(struct sonode *so)
319{
320	int pollev = 0;
321	int sigev = 0;
322
323	ASSERT(MUTEX_HELD(&so->so_lock));
324	ASSERT(so->so_state & (SS_CANTSENDMORE|SS_CANTRCVMORE));
325
326	if (so->so_state & SS_CANTSENDMORE)
327		(void) i_so_notify_last_tx(so, &pollev, &sigev);
328	if (so->so_state & SS_CANTRCVMORE)
329		(void) i_so_notify_last_rx(so, &pollev, &sigev);
330
331	if (sigev != 0)
332		socket_sendsig(so, sigev);
333	mutex_exit(&so->so_lock);
334	if (pollev != 0)
335		pollwakeup(&so->so_poll_list, pollev);
336
337	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
338}
339
340/*
341 * No more data will be coming in, and this will be the last notification
342 * made.
343 */
344static int
345i_so_notify_last_rx(struct sonode *so, int *pollev, int *sigev)
346{
347	if (!(so->so_state & SS_SENTLASTREADSIG)) {
348		SOCKET_TIMER_CANCEL(so);
349		SO_WAKEUP_READER(so);
350		so->so_state |= SS_SENTLASTREADSIG;
351		so->so_pollev &= ~SO_POLLEV_IN;
352
353		*pollev |= POLLIN|POLLRDNORM;
354		*sigev |= SOCKETSIG_READ;
355
356		return (1);
357	} else {
358		return (0);
359	}
360}
361
362/*
363 * The socket is un-writeable. Make one last notification.
364 */
365static int
366i_so_notify_last_tx(struct sonode *so, int *pollev, int *sigev)
367{
368	if (!(so->so_state & SS_SENTLASTWRITESIG)) {
369		SO_WAKEUP_WRITER(so);
370		so->so_state |= SS_SENTLASTWRITESIG;
371
372		*pollev |= POLLOUT;
373		*sigev |= SOCKETSIG_WRITE;
374
375		return (1);
376	} else {
377		return (0);
378	}
379}
380