|
|
1.1 ! root 1: #define _DDI_DKI 1 ! 2: #define _SYSV4 1 ! 3: ! 4: /* ! 5: * This file contains the stream head put and service routines. ! 6: */ ! 7: ! 8: #include <common/ccompat.h> ! 9: #include <kernel/strmlib.h> ! 10: #include <sys/debug.h> ! 11: #include <sys/types.h> ! 12: #include <sys/stream.h> ! 13: #include <sys/stropts.h> ! 14: #include <sys/poll.h> ! 15: #include <sys/errno.h> ! 16: #include <sys/signal.h> ! 17: #include <stddef.h> ! 18: ! 19: ! 20: #define QUEUE_POLL(q) ((shead_t *) (q)->q_ptr)->sh_pollhead ! 21: ! 22: ! 23: /* ! 24: * This function processes a "set options" request for a stream. ! 25: */ ! 26: ! 27: #if __USE_PROTO__ ! 28: __LOCAL__ void (STREAM_SETOPT) (queue_t * q, struct stroptions * so) ! 29: #else ! 30: __LOCAL__ void ! 31: STREAM_SETOPT __ARGS ((q, so)) ! 32: queue_t * q; ! 33: struct stroptions ! 34: * so; ! 35: #endif ! 36: { ! 37: shead_t * sheadp; ! 38: ulong_t flags; ! 39: pl_t prev_pl; ! 40: ! 41: ASSERT (q != NULL); ! 42: ASSERT (so != NULL); ! 43: ! 44: sheadp = (shead_t *) q->q_ptr; ! 45: flags = so->so_flags; ! 46: ! 47: prev_pl = SHEAD_LOCK (sheadp); ! 48: ! 49: if ((flags & SO_READOPT) != 0) { ! 50: /* ! 51: * Set the read option flags. If multiple of the flag values ! 52: * are specified, collapse to one. ! 53: */ ! 54: ! 55: SHEAD_SRDOPT (sheadp, so->so_readopt); ! 56: } ! 57: ! 58: if ((flags & SO_WROFF) != 0) ! 59: sheadp->sh_wroff = so->so_wroff; ! 60: ! 61: if ((flags & SO_MREADOFF) != 0) ! 62: sheadp->sh_flags &= ~ SH_READMSG; ! 63: else if ((flags & SO_MREADON) != 0) ! 64: sheadp->sh_flags |= SH_READMSG; ! 65: ! 66: if ((flags & SO_NDELOFF) != 0) ! 67: sheadp->sh_flags &= ~ SH_NDELAY; ! 68: else if ((flags & SO_NDELON) != 0) ! 69: sheadp->sh_flags |= SH_NDELAY; ! 70: ! 71: if ((flags & SO_ISNTTY) != 0) ! 72: sheadp->sh_flags &= ~ SH_TTY; ! 73: else if ((flags & SO_ISTTY) != 0) ! 74: sheadp->sh_flags |= SH_TTY; ! 75: ! 76: if ((flags & SO_TONSTOP) != 0) ! 77: sheadp->sh_flags &= ~ SH_TOSTOP; ! 78: else if ((flags & SO_TOSTOP) != 0) ! 79: sheadp->sh_flags |= SH_TOSTOP; ! 80: ! 81: SHEAD_UNLOCK (sheadp, prev_pl); ! 82: ! 83: ! 84: prev_pl = QFREEZE_TRACE (q, "STREAM_SETOPT"); ! 85: ! 86: if ((flags & SO_MINPSZ) != 0) ! 87: q->q_minpsz = so->so_minpsz; ! 88: ! 89: if ((flags & SO_MAXPSZ) != 0) ! 90: q->q_maxpsz = so->so_maxpsz; ! 91: ! 92: QUNFREEZE_TRACE (q, prev_pl); ! 93: ! 94: QBAND_SETOPT (q, so); ! 95: } ! 96: ! 97: ! 98: /* ! 99: * The read side put procedure, where data enters the stream head. Process ! 100: * the priority messages, queue the normal ones for processes to grab. ! 101: * ! 102: * We use the stream head service procedure purely for doing the less time- ! 103: * critical stuff such as waking up processes waiting for data and dealing ! 104: * with polling. ! 105: */ ! 106: ! 107: #if __USE_PROTO__ ! 108: __LOCAL__ void headrput (queue_t * q, mblk_t * mp) ! 109: #else ! 110: __LOCAL__ void ! 111: headrput (q, mp) ! 112: queue_t * q; ! 113: mblk_t * mp; ! 114: #endif ! 115: { ! 116: shead_t * sheadp = (shead_t *) q->q_ptr; ! 117: int tmp; ! 118: pl_t prev_pl; ! 119: ! 120: switch (mp->b_datap->db_type) { ! 121: ! 122: case M_PCPROTO: ! 123: /* ! 124: * Basically like normal data/protocol messages, but we ! 125: * discard later arrivals if there is already such a message ! 126: * queued at the stream head. ! 127: */ ! 128: ! 129: prev_pl = QFREEZE_TRACE (q, "headrput"); ! 130: ! 131: tmp = q->q_first->b_datap->db_type == M_PCPROTO; ! 132: ! 133: QUNFREEZE_TRACE (q, prev_pl); ! 134: ! 135: if (tmp) ! 136: break; ! 137: ! 138: /* FALL INTO */ ! 139: case M_PROTO: ! 140: case M_DATA: ! 141: putq (q, mp); ! 142: mp = NULL; ! 143: break; ! 144: ! 145: case M_PCSIG: ! 146: /* ! 147: * Priority signals get generated straight away. ! 148: */ ! 149: ! 150: SHEAD_SIGNAL (sheadp, * mp->b_rptr); ! 151: break; ! 152: ! 153: case M_SIG: ! 154: /* ! 155: * Non-priority signals are generated in-band when the signal ! 156: * message is dequeued by a reading process. ! 157: */ ! 158: ! 159: putq (q, mp); ! 160: mp = NULL; ! 161: break; ! 162: ! 163: ! 164: case M_IOCACK: ! 165: case M_IOCNAK: ! 166: /* ! 167: * Send this message to the specific waiting process based ! 168: * on the ID field. ! 169: */ ! 170: ! 171: prev_pl = SHEAD_LOCK (sheadp); ! 172: ! 173: if (sheadp->sh_ioc_seq == ! 174: ((struct iocblk *) mp->b_rptr)->ioc_id && ! 175: sheadp->sh_ioc_msg == NULL) { ! 176: /* ! 177: * Park the message and let the waiting process know ! 178: * about it. ! 179: */ ! 180: ! 181: sheadp->sh_ioc_msg = mp; ! 182: mp = NULL; ! 183: } ! 184: ! 185: SHEAD_UNLOCK (sheadp, prev_pl); ! 186: ! 187: SHEAD_WAKE (sheadp, SH_IOCTL_WAIT); ! 188: break; ! 189: ! 190: case M_IOCTL: ! 191: /* ! 192: * Thanks to the operation of STREAMS pipes, we can see ! 193: * messages sent from the other end. ! 194: */ ! 195: ! 196: mp->b_datap->db_type = M_IOCNAK; ! 197: qreply (q, mp); ! 198: mp = NULL; ! 199: break; ! 200: ! 201: case M_FLUSH: ! 202: /* ! 203: * Check to see what action we should perform; ! 204: */ ! 205: ! 206: tmp = * mp->b_rptr; ! 207: ! 208: if ((tmp & FLUSHR) != 0) { ! 209: ! 210: if ((tmp & FLUSHBAND) != 0) ! 211: flushband (q, mp->b_rptr [1], FLUSHALL); ! 212: else ! 213: flushq (q, FLUSHALL); ! 214: ! 215: tmp = * mp->b_rptr &= ~ FLUSHR; ! 216: } ! 217: ! 218: if ((tmp & FLUSHW) != 0) { ! 219: ! 220: qreply (q, mp); ! 221: mp = NULL; ! 222: } ! 223: break; ! 224: ! 225: case M_ERROR: ! 226: prev_pl = SHEAD_LOCK (sheadp); ! 227: ! 228: if (mp->b_wptr > mp->b_rptr + 1) { ! 229: /* ! 230: * Two-byte form of the M_ERROR message. ! 231: */ ! 232: ! 233: if (mp->b_rptr [0] != NOERROR) ! 234: sheadp->sh_rerrcode = mp->b_rptr [0]; ! 235: ! 236: if (mp->b_rptr [1] != NOERROR) ! 237: sheadp->sh_rerrcode = mp->b_rptr [1]; ! 238: } else { ! 239: /* ! 240: * One-byte form of M_ERROR; NOERROR or 0 are not ! 241: * valid values for the error code. ! 242: */ ! 243: ! 244: tmp = (uchar_t) mp->b_rptr [0]; ! 245: ! 246: if (tmp == 0 || tmp == NOERROR) ! 247: tmp = ENXIO; ! 248: ! 249: sheadp->sh_rerrcode = tmp; ! 250: sheadp->sh_werrcode = tmp; ! 251: } ! 252: ! 253: ! 254: /* ! 255: * Since we already have the stream head locked, and because ! 256: * we want to wake up everyone, we call SV_BROADCAST () ! 257: * directly rather than going through SHEAD_WAKE (). ! 258: */ ! 259: ! 260: sheadp->sh_lock_mask &= ~ SH_WAIT_MASK; ! 261: SV_BROADCAST (sheadp->sh_wait_sv, 0); ! 262: ! 263: SHEAD_UNLOCK (sheadp, prev_pl); ! 264: ! 265: tmp = (sheadp->sh_rerrcode != 0 ? FLUSHR : 0) | ! 266: (sheadp->sh_werrcode != 0 ? FLUSHW : 0); ! 267: ! 268: if (tmp != 0) { ! 269: ! 270: pollwakeup (sheadp->sh_pollhead, POLLERR); ! 271: putctl1 (W (sheadp->sh_head), M_FLUSH, tmp); ! 272: } ! 273: break; ! 274: ! 275: case M_HANGUP: ! 276: prev_pl = SHEAD_LOCK (sheadp); ! 277: ! 278: sheadp->sh_flags |= SH_HANGUP; ! 279: ! 280: /* ! 281: * Since we already have the stream head locked, and because ! 282: * we want to wake up everyone, we call SV_BROADCAST () ! 283: * directly rather than going through SHEAD_WAKE (). ! 284: */ ! 285: ! 286: sheadp->sh_lock_mask &= ~ SH_WAIT_MASK; ! 287: SV_BROADCAST (sheadp->sh_wait_sv, 0); ! 288: ! 289: SHEAD_UNLOCK (sheadp, prev_pl); ! 290: ! 291: if (sheadp->sh_controller != NULL) { ! 292: /* ! 293: * If we have acquired a controlling process, send a ! 294: * SIGHUP to the process (and not the foreground ! 295: * process group). ! 296: */ ! 297: ! 298: proc_signal (sheadp->sh_controller, SIGHUP); ! 299: } ! 300: ! 301: break; ! 302: ! 303: case M_SETOPTS: ! 304: STREAM_SETOPT (q, (struct stroptions *) mp->b_rptr); ! 305: break; ! 306: } ! 307: ! 308: if (mp != NULL) ! 309: freemsg (mp); ! 310: } ! 311: ! 312: ! 313: /* ! 314: * The stream head read side service procedure exists to defer notification of ! 315: * data arrivals at the stream head. ! 316: */ ! 317: ! 318: #if __USE_PROTO__ ! 319: __LOCAL__ void headrsrv (queue_t * q) ! 320: #else ! 321: __LOCAL__ void ! 322: headrsrv (q) ! 323: queue_t * q; ! 324: #endif ! 325: { ! 326: mblk_t * msg; ! 327: pl_t prev_pl; ! 328: ! 329: prev_pl = QFREEZE_TRACE (q, "headrsrv"); ! 330: ! 331: if ((msg = q->q_first) != NULL && datamsg (msg->b_datap->db_type)) { ! 332: ! 333: if (! pcmsg (msg->b_datap->db_type)) { ! 334: ! 335: pollwakeup (QUEUE_POLL (q), POLLIN); ! 336: ! 337: pollwakeup (QUEUE_POLL (q), ! 338: msg->b_band == 0 ? POLLRDNORM : ! 339: POLLRDBAND); ! 340: } else ! 341: pollwakeup (QUEUE_POLL (q), POLLPRI); ! 342: ! 343: } ! 344: ! 345: QUNFREEZE_TRACE (q, prev_pl); ! 346: ! 347: if (msg != NULL) ! 348: SHEAD_WAKE ((shead_t *) q->q_ptr, SH_READ_WAIT); ! 349: } ! 350: ! 351: ! 352: /* ! 353: * The stream head write put procedure is not normally used; stream head ! 354: * actions call putq () directly. However, M_FLUSH processing comes through ! 355: * here. ! 356: */ ! 357: ! 358: #if __USE_PROTO__ ! 359: __LOCAL__ void headwput (queue_t * q, mblk_t * mp) ! 360: #else ! 361: __LOCAL__ void ! 362: headwput (q, mp) ! 363: queue_t * q; ! 364: mblk_t * mp; ! 365: #endif ! 366: { ! 367: if (mp->b_datap->db_type == M_FLUSH && ! 368: (* mp->b_rptr & FLUSHW) != 0) { ! 369: ! 370: if ((* mp->b_rptr & FLUSHBAND) != 0) ! 371: flushband (q, mp->b_rptr [1], FLUSHALL); ! 372: else ! 373: flushq (q, FLUSHALL); ! 374: ! 375: pollwakeup (QUEUE_POLL (q), POLLOUT); ! 376: SHEAD_WAKE ((shead_t *) q->q_ptr, SH_WRITE_WAIT); ! 377: } ! 378: ! 379: putq (q, mp); ! 380: } ! 381: ! 382: ! 383: /* ! 384: * The stream head write service procedure just forwards messages on down the ! 385: * line, checking for (band) flow control. ! 386: */ ! 387: ! 388: #if __USE_PROTO__ ! 389: __LOCAL__ void headwsrv (queue_t * q) ! 390: #else ! 391: __LOCAL__ void ! 392: headwsrv (q) ! 393: queue_t * q; ! 394: #endif ! 395: { ! 396: mblk_t * mp; ! 397: ! 398: pollwakeup (QUEUE_POLL (q), POLLWRBAND); ! 399: ! 400: while ((mp = getq (q)) != NULL) { ! 401: ! 402: if (pcmsg (mp->b_datap->db_type) || ! 403: (mp->b_band > 0 && bcanputnext (q, mp->b_band)) || ! 404: canputnext (q)) ! 405: putnext (q, mp); ! 406: else { ! 407: putbq (q, mp); ! 408: return ; ! 409: } ! 410: } ! 411: ! 412: /* ! 413: * Flow control has been relieved on this queue; let the processes ! 414: * know about it! ! 415: */ ! 416: ! 417: pollwakeup (QUEUE_POLL (q), POLLOUT); ! 418: SHEAD_WAKE ((shead_t *) q->q_ptr, SH_WRITE_WAIT); ! 419: } ! 420: ! 421: ! 422: /* ! 423: * since the stream head is a queue pair like any other, we need a ! 424: * streamtab/qinit for it. ! 425: */ ! 426: ! 427: __LOCAL__ struct module_info headrinfo = { ! 428: 0, "standard head", 0, 256, 512, 0 ! 429: }; ! 430: ! 431: __LOCAL__ struct qinit defstreamread = { ! 432: headrput, headrsrv, NULL, NULL, NULL, ! 433: & headrinfo, NULL ! 434: }, defstreamwrite = { ! 435: headwput, headwsrv, NULL, NULL, NULL, ! 436: & headrinfo, NULL ! 437: }; ! 438: ! 439: struct streamtab headinfo = { ! 440: & defstreamread, & defstreamwrite, NULL, NULL ! 441: }; ! 442:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.