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