|
|
1.1 ! root 1: #define _DDI_DKI 1 ! 2: #define _SYSV4 1 ! 3: ! 4: /* ! 5: * This file contains the fundamental STREAMS routines defined in Appendix ! 6: * C of the STREAMS Programmer's Guide for System V Release 4. Note that ! 7: * additional information about the definition of these routines has been ! 8: * taken from the System V Release 4 Multi-Processor DDI/DKI For Intel CPU's. ! 9: * ! 10: * Later documents significantly redefine the semantics of many STREAMS ! 11: * routines. If there is a conflict, the normal System V Release 4 version ! 12: * is preferred, and the conflict is noted. However, where possible the later ! 13: * semantics have been incorporated or anticipated. ! 14: */ ! 15: ! 16: /* ! 17: *-IMPORTS: ! 18: * <common/ccompat.h> ! 19: * __USE_PROTO__ ! 20: * __ARGS () ! 21: * <kernel/defer.h> ! 22: * defer_int_any () ! 23: * <sys/debug.h> ! 24: * ASSERT () ! 25: * <sys/types.h> ! 26: * uchar_t ! 27: * uint_t ! 28: * ushort_t ! 29: * toid_t ! 30: * <sys/kmem.h> ! 31: * KM_NOSLEEP ! 32: * kmem_alloc () ! 33: * kmem_free () ! 34: * <sys/cmn_err.h> ! 35: * CE_WARN ! 36: * cmn_err () ! 37: * <sys/strlog.h> ! 38: * SL_ERROR ! 39: * SL_TRACE ! 40: * SL_CONSOLE ! 41: * SL_NOTIFY ! 42: * SL_FATAL ! 43: * SL_WARN ! 44: * SL_NOTE ! 45: * SL_LEVEL_MASK ! 46: * NLOGARGS ! 47: * struct log_ctl ! 48: * <sys/errno.h> ! 49: * EINVAL ! 50: * ENOMEM ! 51: * EPERM ! 52: * <stdarg.h> ! 53: * va_start () ! 54: * va_arg () ! 55: * va_end () ! 56: * <string.h> ! 57: * memcpy () ! 58: */ ! 59: ! 60: #include <common/ccompat.h> ! 61: #include <kernel/defer.h> ! 62: #include <sys/debug.h> ! 63: #include <sys/types.h> ! 64: #include <sys/kmem.h> ! 65: #include <sys/cmn_err.h> ! 66: #include <sys/strlog.h> ! 67: #include <sys/errno.h> ! 68: #include <stdarg.h> ! 69: #include <string.h> ! 70: ! 71: #include <sys/stream.h> ! 72: #include <kernel/strmlib.h> ! 73: ! 74: ! 75: /* ! 76: * The pre-SVR4 STREAMS system used a marker bit to determine when putq () and ! 77: * putbq () should enable a queue. This flag, documented as QWANTR in the SVR4 ! 78: * STREAMS documentation, is no longer sufficient to deal with scheduling with ! 79: * priority bands. The DDI/DKI and STREAMS documentation in SVR4 do not ! 80: * contain detailed new rules for dealing with exactly when a queue should be ! 81: * enabled automatically. ! 82: * ! 83: * The rules that we have adopted to deal with band flow control use our own ! 84: * member of the queue structure, "q_lastband". The idea is for getq () and ! 85: * rmvq () to record the band of the last message that was dequeued (or to ! 86: * set QWANTR), so that when a message in a higher band is queued the stream ! 87: * will be enabled to process it. If the last message retrieved is returned ! 88: * to the queue because of a flow-control blockage, putq () will see that the ! 89: * message is not a member of a higher band that the last read, and thus will ! 90: * know not to enable the queue. ! 91: */ ! 92: ! 93: ! 94: /* ! 95: * Simple helper macro: is this message a priority message? ! 96: */ ! 97: ! 98: #define IS_PRI_MSG(mp) pcmsg ((mp)->b_datap->db_type) ! 99: ! 100: ! 101: /* ! 102: * Simple realloc () function for memory allocated with kmem_alloc () ! 103: * (assuming that it is our kmem_alloc (), that is). ! 104: */ ! 105: ! 106: #if __USE_PROTO__ ! 107: __LOCAL__ _VOID * (kmem_realloc) (_VOID * mem, size_t newsize, size_t oldsize) ! 108: #else ! 109: __LOCAL__ _VOID * ! 110: kmem_realloc __ARGS ((mem, newsize, oldsize)) ! 111: _VOID * mem; ! 112: size_t newsize; ! 113: size_t oldsize; ! 114: #endif ! 115: { ! 116: pl_t prev_pl; ! 117: ! 118: ASSERT (mem != NULL && newsize > 0 && oldsize > 0); ! 119: ! 120: prev_pl = LOCK (str_mem->sm_other_lock, str_other_pl); ! 121: ! 122: mem = st_realloc (str_mem->sm_other_heap, mem, newsize, oldsize); ! 123: ! 124: OTHER_ALLOCED (newsize - oldsize); ! 125: ! 126: UNLOCK (str_mem->sm_other_lock, prev_pl); ! 127: ! 128: return mem; ! 129: } ! 130: ! 131: ! 132: /* ! 133: * This internal function actually implements the queue freezing; in addition, ! 134: * it asserts that the queue is non-NULL, traces who froze the queue, and ! 135: * so forth. If a queue monitoring facility is introduced, this would be the ! 136: * place to do it. ! 137: */ ! 138: ! 139: #if __USE_PROTO__ ! 140: pl_t (QFREEZE_TRACE) (queue_t * q, __CONST__ char * name) ! 141: #else ! 142: pl_t ! 143: QFREEZE_TRACE __ARGS ((q, name)) ! 144: queue_t * q; ! 145: __CONST__ char * name; ! 146: #endif ! 147: { ! 148: if (q == NULL) ! 149: cmn_err (CE_PANIC, "NULL queue passed to STREAMS utility %s", ! 150: name); ! 151: ! 152: return SFREEZE_LOCK (q, name); ! 153: } ! 154: ! 155: ! 156: /* ! 157: * This internal function is similar to QFREEZE_TRACE (), but performs the ! 158: * assertions and tracing functions for routines that require that the queue ! 159: * already be frozen on entry. ! 160: */ ! 161: ! 162: #if __USE_PROTO__ ! 163: void (QFROZEN_TRACE) (queue_t * q, __CONST__ char * name) ! 164: #else ! 165: void ! 166: QFROZEN_TRACE __ARGS ((q, name)) ! 167: queue_t * q; ! 168: __CONST__ char * name; ! 169: #endif ! 170: { ! 171: if (q == NULL) ! 172: cmn_err (CE_PANIC, "NULL queue passed to STREAMS utility %s", ! 173: name); ! 174: ! 175: SFREEZE_ASSERT_FROZEN (q); ! 176: } ! 177: ! 178: ! 179: /* ! 180: * This internal function is for utility routines that walk over various ! 181: * queues (and hence perform multiple freeze/unfreeze operations in local ! 182: * procedures such as QUEUE_NEXT). ! 183: */ ! 184: ! 185: #if __USE_PROTO__ ! 186: void (QUEUE_TRACE) (queue_t * q, __CONST__ char * name) ! 187: #else ! 188: void ! 189: QUEUE_TRACE __ARGS ((q, name)) ! 190: queue_t * q; ! 191: __CONST__ char * name; ! 192: #endif ! 193: { ! 194: if (q == NULL) ! 195: cmn_err (CE_PANIC, "NULL queue passed to STREAMS utility %s", ! 196: name); ! 197: } ! 198: ! 199: ! 200: /* ! 201: * This internal function follows the singly-threaded lists of priority band ! 202: * structures to find the "pri"th priority band attached to the queue. It ! 203: * returns NULL if no such band has been allocated. ! 204: * ! 205: * The queue passed to this function must be frozen. ! 206: */ ! 207: ! 208: #if ! defined (VECTOR_BANDS) || defined (VECTOR_BANDS_TEST) ! 209: ! 210: #if __USE_PROTO__ ! 211: qband_t * (QUEUE_BAND) (queue_t * q, uchar_t pri) ! 212: #else ! 213: qband_t * ! 214: QUEUE_BAND __ARGS ((q, pri)) ! 215: queue_t * q; ! 216: uchar_t pri; ! 217: #endif ! 218: { ! 219: qband_t * qbandp; ! 220: uchar_t count = pri; ! 221: ! 222: ! 223: ASSERT (pri > 0); ! 224: QFROZEN_TRACE (q, "QUEUE_BAND"); ! 225: ! 226: /* ! 227: * Just iterate through the list of band structures. ! 228: */ ! 229: ! 230: if ((qbandp = q->q_bandp) != NULL) ! 231: while (-- count > 0) ! 232: if ((qbandp = qbandp->qb_next) == NULL) ! 233: break; ! 234: ! 235: ASSERT (pri > q->q_nband ? qbandp == NULL : qbandp != NULL); ! 236: ! 237: #ifdef VECTOR_BANDS_TEST ! 238: /* ! 239: * For extra fun, we define a mode where we work everything out both ! 240: * ways to ensure correctness. The #undef makes all the later uses ! 241: * of the QUEUE_BAND name map to this function version so that the ! 242: * test gets included. ! 243: */ ! 244: ! 245: ASSERT (qbandp == QUEUE_BAND (q, pri)); ! 246: # undef QUEUE_BAND ! 247: #endif ! 248: ! 249: return qbandp; ! 250: } ! 251: ! 252: ! 253: /* ! 254: * This internal function gets the predecessor to a band structure from a ! 255: * queue, or NULL if there is no such predecessor. ! 256: * ! 257: * The definition of the "qband" structure was public from its introduction in ! 258: * SVR4, but was made private in the SVR4 MP release. We could reasonably ! 259: * change the definition of this structure to include a back-link, but for ! 260: * now we'll do it the hard way and stay with the structure as defined. ! 261: * ! 262: * The queue passed to this function must be frozen. ! 263: */ ! 264: ! 265: #if __USE_PROTO__ ! 266: qband_t * (QBAND_PREV) (queue_t * q, qband_t * qbandp) ! 267: #else ! 268: qband_t * ! 269: QBAND_PREV __ARGS ((q, qbandp)) ! 270: queue_t * q; ! 271: qband_t * qbandp; ! 272: #endif ! 273: { ! 274: qband_t * scan; ! 275: ! 276: ASSERT (qbandp != NULL); ! 277: QFROZEN_TRACE (q, "QBAND_PREV"); ! 278: ! 279: if ((scan = q->q_bandp) == qbandp) ! 280: return NULL; ! 281: ! 282: while (scan->qb_next != qbandp) { ! 283: scan = scan->qb_next; ! 284: ! 285: ASSERT (scan != NULL); ! 286: } ! 287: ! 288: #ifdef VECTOR_BANDS_TEST ! 289: ASSERT (scan == QBAND_PREV (q, qbandp)); ! 290: ! 291: # undef QBAND_PREV ! 292: #endif ! 293: ! 294: return scan; ! 295: } ! 296: ! 297: #endif /* ! defined (VECTOR_BANDS) || defined (VECTOR_BANDS_TEST) */ ! 298: ! 299: ! 300: /* ! 301: * This local function attempts to allocate new storage for a priority-band ! 302: * structure associated with a queue. Since for a given band "n", band ! 303: * structures 1 through "n-1" must also be present, this function may attempt ! 304: * to acquire several structures simultaneously. ! 305: * ! 306: * The caller must have the queue frozen. ! 307: */ ! 308: ! 309: #if __USE_PROTO__ ! 310: __LOCAL__ qband_t * (QBAND_ALLOC) (queue_t * q, uchar_t pri) ! 311: #else ! 312: __LOCAL__ qband_t * ! 313: QBAND_ALLOC __ARGS ((q, pri)) ! 314: queue_t * q; ! 315: uchar_t pri; ! 316: #endif ! 317: { ! 318: qband_t * newband; ! 319: int nbands; ! 320: ! 321: QFROZEN_TRACE (q, "QBAND_ALLOC"); ! 322: ASSERT (pri > 0); ! 323: ASSERT (pri > q->q_nband); ! 324: ! 325: /* ! 326: * We want to allocate band structures "q->q_nband + 1" ... "pri". ! 327: * ! 328: * Since the caller has the stream frozen, we want to do this fairly ! 329: * quickly, so we allocate the new structures as a vector. In order ! 330: * to speed up other operations, we may also try to reallocate any ! 331: * existing information so that the entire set of band structures is ! 332: * kept in a single block of memory. ! 333: */ ! 334: ! 335: #ifdef VECTOR_BANDS ! 336: if (q->q_bandp != NULL) { ! 337: /* ! 338: * There are some existing band structures to be moved around ! 339: * (note that this will require that all the "qb_next" ! 340: * pointers be rethreaded). ! 341: */ ! 342: ! 343: if ((newband = (qband_t *) ! 344: kmem_realloc (q->q_bandp, pri * sizeof (qband_t), ! 345: q->q_nband * sizeof (qband_t))) == NULL) ! 346: return NULL; ! 347: ! 348: q->q_bandp = newband; ! 349: ! 350: for (nbands = 0 ; nbands < q->q_nband ; newband ++, nbands ++) ! 351: newband->qb_next = newband + 1; ! 352: ! 353: /* ! 354: * Now we have rethreaded the relocated version of the old ! 355: * band structures, "newband" is set correctly to initialize ! 356: * the new band structures. ! 357: * ! 358: * We zero the remaining memory to ease initialization. ! 359: */ ! 360: ! 361: memset (newband, 0, (pri - q->q_nband) * sizeof (qband_t)); ! 362: } else ! 363: #endif ! 364: ! 365: if ((newband = (qband_t *) ! 366: kmem_zalloc ((pri - q->q_nband) * sizeof (qband_t), ! 367: KM_NOSLEEP)) == NULL) ! 368: return NULL; ! 369: ! 370: #ifndef VECTOR_BANDS ! 371: newband->qb_flag = QB_FIRST; ! 372: ! 373: /* ! 374: * Special-case update the "qb_next" pointer of the previously highest ! 375: * band. ! 376: */ ! 377: ! 378: if (q->q_nbands > 0) ! 379: QUEUE_BAND (q, q->q_nbands)->qb_next = newband; ! 380: #endif ! 381: ! 382: /* ! 383: * Thread the "qb_next" pointers of the new structures together. ! 384: */ ! 385: ! 386: for (nbands = q->q_nband ; nbands < pri - 1 ; newband ++, nbands ++) ! 387: newband->qb_next = newband + 1; ! 388: ! 389: return newband; ! 390: } ! 391: ! 392: ! 393: /* ! 394: * This internal function performs an atomic read of the "q_next" member of ! 395: * the queue passed to it, skipping over queues that are hidden from the ! 396: * STREAMS system. ! 397: * ! 398: * The queue passed to this function must be frozen. After this function, the ! 399: * passed queue is unfrozen and the returned queue is frozen (unless it is ! 400: * NULL). ! 401: * ! 402: * Note that this function illustrates a problem with using a fixed-hierarchy ! 403: * basic lock scheme; this code can't deadlock with itself because of the ! 404: * relationship expressed by the "q_next" member. Locks are only acquired in ! 405: * one direction along a stream axis, so each queue lock has an implicit ! 406: * hierarchy value lower that its successor. ! 407: */ ! 408: ! 409: #if __USE_PROTO__ ! 410: queue_t * (QUEUE_NEXT) (queue_t * q) ! 411: #else ! 412: queue_t * ! 413: QUEUE_NEXT __ARGS ((q)) ! 414: queue_t * q; ! 415: #endif ! 416: { ! 417: QFROZEN_TRACE (q, "QUEUE_NEXT"); ! 418: ! 419: do { ! 420: queue_t * next; ! 421: ! 422: if ((next = q->q_next) != NULL) ! 423: (void) QFREEZE_TRACE (next, "QUEUE_NEXT"); ! 424: ! 425: QUNFREEZE_TRACE (q, plstr); ! 426: ! 427: q = next; ! 428: } while (q != NULL && (q->q_flag & QPROCSOFF) != 0); ! 429: ! 430: return q; ! 431: } ! 432: ! 433: ! 434: /* ! 435: * This internal function attempts to schedule a queue. It will fail if the ! 436: * queue has no service procedure or if the service procedure has been ! 437: * disabled. It will do nothing, but return success, if the queue is currently ! 438: * scheduled for service. ! 439: */ ! 440: ! 441: #if __USE_PROTO__ ! 442: __LOCAL__ int (QUEUE_TRYSCHED) (queue_t * q) ! 443: #else ! 444: __LOCAL__ int ! 445: QUEUE_TRYSCHED __ARGS ((q)) ! 446: queue_t * q; ! 447: #endif ! 448: { ! 449: QFROZEN_TRACE (q, "QUEUE_TRYSCHED"); ! 450: ! 451: if (q->q_qinfo->qi_srvp == NULL || (q->q_flag & QPROCSOFF) != 0) ! 452: return 0; ! 453: ! 454: if ((q->q_flag & QENAB) != 0 || ! 455: QSCHED_SCHEDULE (q, str_mem->sm_sched) != 0) ! 456: return 1; ! 457: ! 458: /* ! 459: * Mark the queue as having been scheduled, and if the STREAMS service ! 460: * procedure scheduler has not been deferred, do so. ! 461: */ ! 462: ! 463: q->q_flag |= QENAB; ! 464: ! 465: if (ATOMIC_FETCH_AND_STORE_UCHAR (ddi_global_data ()->dg_run_strsched, ! 466: 1) == 0) ! 467: defer_int_any (RUN_STREAMS); ! 468: ! 469: return 1; ! 470: } ! 471: ! 472: ! 473: /* ! 474: * QUEUE_BACKENAB () is an internal function used to unblock a queue which ! 475: * has been blocked by flow control. When a queue with a service procedure ! 476: * becomes full, and a queue "behind" it finds that it cannot put into it ! 477: * with bcanput (), bcanputnext (), canput (), or canputnext (), the target ! 478: * queue is marked so that this procedure will be called when it is ready to ! 479: * receive more data. ! 480: * ! 481: * Since the "behind" queue should have a service procedure (otherwise, the ! 482: * flow-control tests would have no point), we scan the queues behind the ! 483: * passed queue "q" and enable the first one which has a service procedure. ! 484: * ! 485: * The queue passed to this function must *not* be frozen. To avoid deadlock, ! 486: * a single function cannot hold both sides of a queue frozen; this is the ! 487: * only function in the STREAMS library that might plausibly want to do so. ! 488: * ! 489: * This function is normally called as a result of action in QBAND_REDUCE () ! 490: * or QUEUE_REDUCE (), and under normal circumstances this would not cause an ! 491: * inconvenience. However, the action of rvmq () means that we use a condition ! 492: * in the "q_flags" member of the queue to indirectly schedule this function ! 493: * at a safe time. We only need to test the flag in a path that includes one ! 494: * of the above named functions or in user calls to unfreezestr (). ! 495: */ ! 496: ! 497: #if __USE_PROTO__ ! 498: void (QUEUE_BACKENAB) (queue_t * q) ! 499: #else ! 500: void ! 501: QUEUE_BACKENAB __ARGS ((q)) ! 502: queue_t * q; ! 503: #endif ! 504: { ! 505: int done; ! 506: queue_t * other; ! 507: pl_t prev_pl; ! 508: ! 509: ASSERT (q != NULL); ! 510: ! 511: /* ! 512: * To walk backwards along the queue list, we must first move to the ! 513: * other kind of queue and walk along that, which effectively moves us ! 514: * in the reverse direction with respect to the original queue type. ! 515: */ ! 516: ! 517: other = OTHERQ (q); ! 518: ! 519: prev_pl = QFREEZE_TRACE (other, "QUEUE_BACKENAB"); ! 520: ! 521: do { ! 522: /* ! 523: * Atomically read the "q_next" member of the queue. ! 524: */ ! 525: ! 526: if ((other = QUEUE_NEXT (other)) == NULL) { ! 527: /* ! 528: * Cannot search further. ! 529: */ ! 530: ! 531: (void) splx (prev_pl); ! 532: break; ! 533: } ! 534: ! 535: ! 536: /* ! 537: * To avoid deadlock, we have to unfreeze "other" before we ! 538: * look at freezing its partner. We ensure that it won't go ! 539: * away on us after we unfreeze it by incrementing the ! 540: * "active" count. ! 541: */ ! 542: ! 543: other->q_active ++; ! 544: ! 545: QUNFREEZE_TRACE (other, prev_pl); ! 546: ! 547: ! 548: /* ! 549: * We might be attempting to schedule an empty queue, which ! 550: * we should allow. ! 551: */ ! 552: ! 553: q = OTHERQ (other); ! 554: ! 555: prev_pl = QFREEZE_TRACE (q, "QUEUE_BACKENAB"); ! 556: ! 557: done = QUEUE_TRYSCHED (q); ! 558: ! 559: QUNFREEZE_TRACE (q, prev_pl); ! 560: ! 561: ! 562: /* ! 563: * Now we go back and remove our reference to the partner ! 564: * queue after relocking it. ! 565: */ ! 566: ! 567: prev_pl = QFREEZE_TRACE (other, "QUEUE_BACKENAB"); ! 568: ! 569: ASSERT (other->q_active > 0); ! 570: ! 571: other->q_active --; ! 572: ! 573: if ((q->q_flag & QPROCSOFF) != 0 && q->q_active == 0) { ! 574: /* ! 575: * Time to wake up the sleepers waiting for the put ! 576: * and service routines on a queue to exit. See ! 577: * qprocsoff () for a discussion of the locking ! 578: * protocol. ! 579: */ ! 580: ! 581: (void) LOCK (str_mem->sm_proc_lock, plstr); ! 582: SV_BROADCAST (str_mem->sm_proc_sv, 0); ! 583: UNLOCK (str_mem->sm_proc_lock, plstr); ! 584: } ! 585: } while (! done); ! 586: ! 587: QUNFREEZE_TRACE (other, prev_pl); ! 588: } ! 589: ! 590: ! 591: /* ! 592: * This local function is called whenever a queue's last message has been ! 593: * dequeued, and will wake up any function waiting for the queue to drain. ! 594: * ! 595: * The caller must have the stream frozen. ! 596: */ ! 597: ! 598: #if __USE_PROTO__ ! 599: __LOCAL__ void (QUEUE_DRAINED) (queue_t * q) ! 600: #else ! 601: __LOCAL__ void ! 602: QUEUE_DRAINED __ARGS ((q)) ! 603: queue_t * q; ! 604: #endif ! 605: { ! 606: pl_t prev_pl; ! 607: ! 608: QFROZEN_TRACE (q, "QUEUE_DRAINED"); ! 609: ! 610: if ((q->q_flag & QDRAIN) != 0) { ! 611: shead_t * sheadp; ! 612: ! 613: /* ! 614: * Under normal circumstances, a call to SV_BROADCAST () would ! 615: * be all we needed to do. However, since we allow ourself to ! 616: * use a more primitive kind of lock that a basic lock to ! 617: * implement freezing a queue, the process that waits for us ! 618: * to drain cannot use the frozen queue as the lock to pass to ! 619: * SV_WAIT (). By making us wait for the lock, we make ! 620: * the wakeup multiprocessor-safe; otherwise, we might be able ! 621: * to try and wake the process before it has actually slept, ! 622: * causing infinite sleep. ! 623: * ! 624: * Since the synchronization variable we are going to ! 625: * broadcast to is part of the stream head, we ensure that ! 626: * this code is only executed for the module or driver which ! 627: * is immediately below the stream head, or the stream head ! 628: * write queue itself. ! 629: */ ! 630: ! 631: ASSERT (RD (q)->q_next == NULL || ! 632: RD (q)->q_next->q_next == NULL); ! 633: ! 634: sheadp = (shead_t *) ! 635: (RD (q)->q_next == NULL ? q->q_ptr : ! 636: RD (q)->q_next->q_ptr); ! 637: ! 638: prev_pl = SHEAD_LOCK (sheadp); ! 639: ! 640: SV_BROADCAST (sheadp->sh_wait_sv, 0); ! 641: ! 642: q->q_flag &= ~ QDRAIN; ! 643: ! 644: SHEAD_UNLOCK (sheadp, prev_pl); ! 645: } ! 646: } ! 647: ! 648: ! 649: /* ! 650: * This local function updates the flow-control information for a priority ! 651: * band when the band current level is increasing. ! 652: * ! 653: * The queue passed to this function must be frozen. ! 654: */ ! 655: ! 656: #if __USE_PROTO__ ! 657: __LOCAL__ void (QBAND_INCREASE) (queue_t * q, qband_t * qbandp, ulong_t adjust) ! 658: #else ! 659: __LOCAL__ void ! 660: QBAND_INCREASE __ARGS ((q, qbandp, adjust)) ! 661: queue_t * q; ! 662: qband_t * qbandp; ! 663: ulong_t adjust; ! 664: #endif ! 665: { ! 666: ASSERT (qbandp != NULL); ! 667: QFROZEN_TRACE (q, "QBAND_INCREASE"); ! 668: ! 669: /* ! 670: * If the band we are dealing with is already flow-controlled, just ! 671: * get out of here. ! 672: */ ! 673: ! 674: qbandp->qb_count += adjust; ! 675: ! 676: if ((qbandp->qb_flag & QB_FULL) != 0) ! 677: return; ! 678: ! 679: /* ! 680: * If we are over the high-water mark, then we must mark ourself and ! 681: * all the bands below us (including the normal messages) as full as ! 682: * well. ! 683: */ ! 684: ! 685: if (qbandp->qb_count >= qbandp->qb_hiwat) { ! 686: ! 687: do ! 688: qbandp->qb_flag |= QB_FULL; ! 689: while ((qbandp = QBAND_PREV (q, qbandp)) != NULL); ! 690: ! 691: ! 692: /* ! 693: * According to the way I read the STREAMS ! 694: * programmer's guide, band flow control ! 695: * should affect normal messages as well (ie, ! 696: * as if they are band 0). ! 697: * ! 698: * We deal with this as a special case. ! 699: */ ! 700: ! 701: if (q->q_count >= q->q_hiwat) ! 702: q->q_flag |= QFULL; ! 703: } ! 704: } ! 705: ! 706: ! 707: /* ! 708: * This local function updates the flow-control information for a priority ! 709: * band when the band current level is decreasing. ! 710: * ! 711: * The queue passed to this function must be frozen. ! 712: */ ! 713: ! 714: #if __USE_PROTO__ ! 715: __LOCAL__ void (QBAND_REDUCE) (queue_t * q, qband_t * qbandp, ulong_t adjust) ! 716: #else ! 717: __LOCAL__ void ! 718: QBAND_REDUCE __ARGS ((q, qbandp, adjust)) ! 719: queue_t * q; ! 720: qband_t * qbandp; ! 721: ulong_t adjust; ! 722: #endif ! 723: { ! 724: ! 725: ASSERT (qbandp != NULL); ! 726: ASSERT (qbandp->qb_count >= adjust); ! 727: QFROZEN_TRACE (q, "QBAND_REDUCE"); ! 728: ! 729: /* ! 730: * If this band wasn't flow-controlled anyway, then we don't need to ! 731: * do anything other than adjust the count. ! 732: */ ! 733: ! 734: qbandp->qb_count -= adjust; ! 735: ! 736: if ((qbandp->qb_flag & QB_FULL) == 0) ! 737: return; ! 738: ! 739: ! 740: /* ! 741: * If we are under the low-water mark, then we can release any pending ! 742: * writes to this band and our hold on lower bands if and only if the ! 743: * bands above us are not controlled. ! 744: * ! 745: * We can test the bands above us in one step since we require that a ! 746: * band which has become full also mark all lower bands as full. If ! 747: * our immediate upper neighbour is full then we cannot proceed. ! 748: */ ! 749: ! 750: if (qbandp->qb_count <= qbandp->qb_lowat && ! 751: (qbandp->qb_next == NULL || ! 752: (qbandp->qb_next->qb_flag & QB_FULL) == 0)) { ! 753: ! 754: /* ! 755: * We release lower bands as long as they are under their low- ! 756: * water marks. It seems pointless to resume bands that are ! 757: * too close to entering a controlled state anyway. ! 758: */ ! 759: ! 760: do { ! 761: qbandp->qb_flag &= ~ QB_FULL; ! 762: ! 763: if ((qbandp->qb_flag & QB_WANTW) != 0) { ! 764: /* ! 765: * Propagate a back-enable request to the ! 766: * queue. ! 767: */ ! 768: ! 769: qbandp->qb_flag &= ~ QB_WANTW; ! 770: q->q_flag |= QBACK; ! 771: } ! 772: ! 773: if ((qbandp = QBAND_PREV (q, qbandp)) == NULL) { ! 774: /* ! 775: * According to the way I read the STREAMS ! 776: * programmer's guide, band flow control ! 777: * should affect normal messages as well (ie, ! 778: * as if they are band 0). ! 779: * ! 780: * We deal with this as a special case. ! 781: */ ! 782: ! 783: if (q->q_count <= q->q_lowat) { ! 784: q->q_flag &= ~ QFULL; ! 785: ! 786: if ((q->q_flag & QWANTW) != 0) { ! 787: ! 788: q->q_flag &= ~ QWANTW; ! 789: q->q_flag |= QBACK; ! 790: } ! 791: } ! 792: ! 793: break; ! 794: } ! 795: } while (qbandp->qb_count <= qbandp->qb_lowat); ! 796: } ! 797: } ! 798: ! 799: ! 800: /* ! 801: * This local function factors out the computation of the total number of ! 802: * data bytes in a message from the routines that manipulate flow-control ! 803: * parameters. Since this is often the only loop in such routines, factoring ! 804: * this out might help inlining in some cases. ! 805: */ ! 806: ! 807: #if __USE_PROTO__ ! 808: __LOCAL__ ulong_t (MSG_SIZE) (mblk_t * mp) ! 809: #else ! 810: __LOCAL__ ulong_t ! 811: MSG_SIZE __ARGS ((mp)) ! 812: mblk_t * mp; ! 813: #endif ! 814: { ! 815: ulong_t total = 0; ! 816: ! 817: ASSERT (mp != NULL); ! 818: ! 819: do ! 820: total += mp->b_wptr - mp->b_rptr; ! 821: while ((mp = mp->b_cont) != NULL); ! 822: ! 823: return total; ! 824: } ! 825: ! 826: ! 827: /* ! 828: * This internal function wraps up the check for whether a newly queued ! 829: * message is of sufficient priority to cause the queue to be enabled. ! 830: * ! 831: * The queue passed to this function must be frozen. ! 832: */ ! 833: ! 834: #if __USE_PROTO__ ! 835: __LOCAL__ int (QUEUE_CHECK_SCHED) (queue_t * q, mblk_t * mp, ! 836: qband_t * qbandp) ! 837: #else ! 838: __LOCAL__ int ! 839: QUEUE_CHECK_SCHED __ARGS ((q, mp, qbandp)) ! 840: queue_t * q; ! 841: mblk_t * mp; ! 842: qband_t * qbandp; ! 843: #endif ! 844: { ! 845: ulong_t msgsize; ! 846: ! 847: QFROZEN_TRACE (q, "QUEUE_CHECK_SCHED"); ! 848: ! 849: if ((q->q_flag & QNOENB) == 0 && ! 850: ((q->q_flag & QWANTR) != 0 || q->q_lastband < mp->b_band)) { ! 851: /* ! 852: * The new message is part of a higher-priority band than the ! 853: * last message that was retrieved, so we need to enable the ! 854: * queue. ! 855: */ ! 856: ! 857: q->q_lastband = mp->b_band; ! 858: (void) QUEUE_TRYSCHED (q); ! 859: } ! 860: ! 861: ! 862: /* ! 863: * As a convenience to the callers, all of whom are queueing the new ! 864: * message, update the flow control parameters. ! 865: */ ! 866: ! 867: msgsize = MSG_SIZE (mp); ! 868: ! 869: if (mp->b_band > 0) { ! 870: ! 871: ASSERT (qbandp != NULL); ! 872: ! 873: QBAND_INCREASE (q, qbandp, msgsize); ! 874: ! 875: return 1; ! 876: } else { ! 877: /* ! 878: * Just deal with the base flow-control stuff. ! 879: */ ! 880: ! 881: if ((q->q_count += msgsize) > q->q_hiwat) ! 882: q->q_flag |= QFULL; ! 883: ! 884: return 0; ! 885: } ! 886: } ! 887: ! 888: ! 889: /* ! 890: * This internal function collects the details of dequeuing a message from ! 891: * a priority-band structure. ! 892: * ! 893: * The queue on which "mp" was queued must be frozen. ! 894: */ ! 895: ! 896: #if __USE_PROTO__ ! 897: __LOCAL__ void (QBAND_DEQUEUE) (qband_t * qbandp, mblk_t * mp) ! 898: #else ! 899: __LOCAL__ void ! 900: QBAND_DEQUEUE __ARGS ((qbandp, mp)) ! 901: qband_t * qbandp; ! 902: mblk_t * mp; ! 903: #endif ! 904: { ! 905: ASSERT (qbandp != NULL); ! 906: ASSERT (mp != NULL); ! 907: ASSERT (mp->b_band > 0); ! 908: ! 909: if (qbandp->qb_first == mp) { ! 910: ! 911: if (qbandp->qb_last == mp) { ! 912: /* ! 913: * The band has become empty. ! 914: */ ! 915: ! 916: ASSERT (mp->b_next == NULL || ! 917: mp->b_next->b_band < mp->b_band); ! 918: ! 919: qbandp->qb_last = qbandp->qb_first = NULL; ! 920: } else { ! 921: /* ! 922: * There is more data in the band. ! 923: */ ! 924: ! 925: ASSERT (mp->b_next != NULL); ! 926: ASSERT (mp->b_next->b_band == mp->b_band); ! 927: ! 928: qbandp->qb_first = mp->b_next; ! 929: } ! 930: } else if (qbandp->qb_last == mp) { ! 931: /* ! 932: * The band is non-empty, but we have to move the end up. ! 933: */ ! 934: ! 935: ASSERT (mp->b_prev != NULL); ! 936: ASSERT (mp->b_prev->b_band == mp->b_band); ! 937: ! 938: qbandp->qb_last = mp->b_prev; ! 939: } ! 940: } ! 941: ! 942: ! 943: /* ! 944: * This internal function tests to see whether a stream wanting to write to ! 945: * this queue should block to honour the flow-control scheme. The return ! 946: * value is 1 if the caller can write to this queue, 0 otherwise. ! 947: * ! 948: * The queue passed to this function must be frozen. ! 949: */ ! 950: ! 951: #if __USE_PROTO__ ! 952: __LOCAL__ int (QBAND_CANPUT) (queue_t * q, uchar_t pri) ! 953: #else ! 954: __LOCAL__ int ! 955: QBAND_CANPUT __ARGS ((q, pri)) ! 956: queue_t * q; ! 957: uchar_t pri; ! 958: #endif ! 959: { ! 960: qband_t * qbandp; ! 961: ! 962: QFROZEN_TRACE (q, "QBAND_CANPUT"); ! 963: ! 964: if (pri > 0) { ! 965: ! 966: qbandp = QUEUE_BAND (q, pri); ! 967: ! 968: if (qbandp != NULL && (qbandp->qb_flag & QB_FULL) != 0) { ! 969: /* ! 970: * We must set the following flag to indicate that ! 971: * back-enabling is desired for this priority band. ! 972: * ! 973: * We'll set the global QWANTW flag as well, to make ! 974: * testing simpler for qprocson (). ! 975: */ ! 976: ! 977: qbandp->qb_flag |= QB_WANTW; ! 978: q->q_flag |= QWANTW; ! 979: return 0; ! 980: } ! 981: } else ! 982: if ((q->q_flag & QFULL) != 0) { ! 983: /* ! 984: * We must set the following flag to indicate that the ! 985: * queue has a writer who has made a failed write ! 986: * attempt. ! 987: */ ! 988: ! 989: q->q_flag |= QWANTW; ! 990: return 0; ! 991: } ! 992: ! 993: return 1; ! 994: } ! 995: ! 996: ! 997: /* ! 998: * This internal function collects the non-priority-band flow-control actions ! 999: * from flushq () and getq (). ! 1000: * ! 1001: * The queue passed to this function must be frozen. ! 1002: */ ! 1003: ! 1004: #if __USE_PROTO__ ! 1005: __LOCAL__ void (QUEUE_REDUCE) (queue_t * q, ulong_t adjust) ! 1006: #else ! 1007: __LOCAL__ void ! 1008: QUEUE_REDUCE __ARGS ((q, adjust)) ! 1009: queue_t * q; ! 1010: ulong_t adjust; ! 1011: #endif ! 1012: { ! 1013: QFROZEN_TRACE (q, "QUEUE_REDUCE"); ! 1014: ! 1015: ASSERT (q->q_count >= adjust); ! 1016: ! 1017: /* ! 1018: * If the queue was not previously full, then we don't need to do ! 1019: * anything other than tweak the count. ! 1020: */ ! 1021: ! 1022: q->q_count -= adjust; ! 1023: ! 1024: if ((q->q_flag & QFULL) != 0 && q->q_count <= q->q_lowat) { ! 1025: ! 1026: q->q_flag &= ~ QFULL; ! 1027: ! 1028: if ((q->q_flag & QWANTW) != 0) { ! 1029: ! 1030: q->q_flag &= ~ QWANTW; ! 1031: q->q_flag |= QBACK; ! 1032: } ! 1033: } ! 1034: } ! 1035: ! 1036: ! 1037: /* ! 1038: * This function contains part of the M_SETOPTS processing; specifically, here ! 1039: * we deal with changing the watermarks of a band. The caller should test the ! 1040: * QBACK flag when unfreezing the stream. ! 1041: */ ! 1042: ! 1043: #if __USE_PROTO__ ! 1044: void (QBAND_SETOPT) (queue_t * q, struct stroptions * so) ! 1045: #else ! 1046: void ! 1047: QBAND_SETOPT __ARGS ((q, so)) ! 1048: queue_t * q; ! 1049: struct stroptions ! 1050: * so; ! 1051: #endif ! 1052: { ! 1053: qband_t * qbandp; ! 1054: pl_t prev_pl; ! 1055: ! 1056: prev_pl = QFREEZE_TRACE (q, "QBAND_SETOPTS"); ! 1057: ! 1058: if ((so->so_flags & (SO_LOWAT | SO_HIWAT)) == 0) ! 1059: return; ! 1060: ! 1061: if ((so->so_flags & SO_BAND) != 0 && so->so_band > 0) { ! 1062: ! 1063: if ((qbandp = QUEUE_BAND (q, so->so_band)) == NULL && ! 1064: (qbandp = QBAND_ALLOC (q, so->so_band)) == NULL) { ! 1065: /* ! 1066: * We cannot allocate space for the band accounting ! 1067: * structures. Give up. ! 1068: */ ! 1069: ! 1070: QUNFREEZE_TRACE (q, prev_pl); ! 1071: return; ! 1072: } ! 1073: ! 1074: if ((so->so_flags & SO_LOWAT) != 0) { ! 1075: ! 1076: qbandp->qb_lowat = so->so_lowat; ! 1077: QBAND_REDUCE (q, qbandp, 0L); ! 1078: } ! 1079: ! 1080: if ((so->so_flags & SO_HIWAT) != 0) { ! 1081: ! 1082: qbandp->qb_hiwat = so->so_hiwat; ! 1083: QBAND_INCREASE (q, qbandp, 0L); ! 1084: } ! 1085: } else { ! 1086: ! 1087: if ((so->so_flags & SO_LOWAT) != 0) { ! 1088: ! 1089: q->q_lowat = so->so_lowat; ! 1090: QUEUE_REDUCE (q, 0L); ! 1091: } ! 1092: ! 1093: if ((so->so_flags & SO_HIWAT) != 0) { ! 1094: ! 1095: q->q_hiwat = so->so_hiwat; ! 1096: if (q->q_count > q->q_hiwat) ! 1097: q->q_flag |= QFULL; ! 1098: } ! 1099: } ! 1100: ! 1101: ! 1102: /* ! 1103: * Since we are in a path with QBAND_REDUCE (), check for QBACK before ! 1104: * unfreezing the stream. ! 1105: */ ! 1106: ! 1107: { ! 1108: unsigned long back; ! 1109: ! 1110: if ((back = q->q_flag & QBACK) != 0) ! 1111: q->q_flag &= ~ QBACK; ! 1112: ! 1113: QUNFREEZE_TRACE (q, prev_pl); ! 1114: ! 1115: if (back) ! 1116: QUEUE_BACKENAB (q); ! 1117: } ! 1118: } ! 1119: ! 1120: ! 1121: /* ! 1122: * This internal function is used by bufcall () and esbbcall () to queue a ! 1123: * STREAMS event cell on the queue for eventual processing once memory ! 1124: * becomes available. ! 1125: */ ! 1126: ! 1127: #if __USE_PROTO__ ! 1128: __LOCAL__ toid_t (STORE_EVENT) (sevent_t * seventp, int pri) ! 1129: #else ! 1130: __LOCAL__ toid_t ! 1131: STORE_EVENT __ARGS ((seventp, pri)) ! 1132: sevent_t * seventp; ! 1133: int pri; ! 1134: #endif ! 1135: { ! 1136: pl_t prev_pl; ! 1137: selist_t * selistp; ! 1138: sevent_t * sprev; ! 1139: ! 1140: /* ! 1141: * Let's lock the list that we are going to thread the new event on. ! 1142: */ ! 1143: ! 1144: selistp = & str_mem->sm_bcevents [MAP_PRI_LEVEL (pri)]; ! 1145: ! 1146: prev_pl = SELIST_LOCK (selistp); ! 1147: ! 1148: ! 1149: #if _TOID_MEMBER ! 1150: /* ! 1151: * Before we perform the insertion of the event cell, we use the above ! 1152: * lock to make our ID code generation multiprocessor-safe. ! 1153: */ ! 1154: ! 1155: selistp->sl_id = (((seventp->se_id = selistp->sl_id) + ! 1156: TOID_INCREMENT) % TOID_MODULUS); ! 1157: ! 1158: ASSERT (seventp->se_id != 0); ! 1159: ASSERT (TOID_TO_PRI (seventp->se_id) == pri); ! 1160: #endif ! 1161: ! 1162: /* ! 1163: * RESEARCH NOTE: There doesn't seem to be any compelling reason to ! 1164: * choose a particular policy for managing event cells. Try getting ! 1165: * some data of performance effects for low->high, high->low and FIFO ! 1166: * queueing. ! 1167: */ ! 1168: #if _FIFO_BUFCALL ! 1169: /* ! 1170: * FIFO queueing is nice and simple. ! 1171: */ ! 1172: ! 1173: if ((sprev = selistp->sl_tail) == NULL) { ! 1174: ! 1175: ASSERT (selistp->sl_head == NULL); ! 1176: ! 1177: selistp->sl_head = selistp->sl_tail = seventp; ! 1178: seventp->se_prev = seventp->se_next = NULL; ! 1179: } else { ! 1180: ! 1181: sprev->se_next = seventp; ! 1182: seventp->se_prev = sprev; ! 1183: seventp->se_next = NULL; ! 1184: selistp->sl_tail = seventp; ! 1185: } ! 1186: #else ! 1187: /* ! 1188: * Now insert the event cell in the event list, keeping it sorted from ! 1189: * low size to high size. ! 1190: */ ! 1191: ! 1192: { ! 1193: sevent_t * sscan; ! 1194: ! 1195: for (sscan = selistp->sl_head, sprev = NULL ; sscan != NULL ; ! 1196: sscan = (sprev = sscan)->se_next) { ! 1197: ! 1198: if (sscan->se_size > seventp->se_size) ! 1199: break; ! 1200: } ! 1201: ! 1202: if (sprev == NULL) ! 1203: selistp->sl_head = seventp; ! 1204: else ! 1205: sprev->se_next = seventp; ! 1206: ! 1207: if (sscan != NULL) ! 1208: sscan->se_prev = seventp; ! 1209: ! 1210: seventp->se_prev = sprev; ! 1211: seventp->se_next = sscan; ! 1212: } ! 1213: #endif ! 1214: ! 1215: SELIST_UNLOCK (selistp, prev_pl); ! 1216: ! 1217: #if _TOID_MEMBER ! 1218: return seventp->se_id; ! 1219: #endif ! 1220: } ! 1221: ! 1222: ! 1223: /* ! 1224: * This local function factors out the common code in put () and ! 1225: * QUEUE_PUTNEXT () [used to implement the putnext (), putnextctl () and ! 1226: * similar functions]. ! 1227: * ! 1228: * The queue must be frozen on entry to this function. ! 1229: */ ! 1230: ! 1231: #if __USE_PROTO__ ! 1232: __LOCAL__ void (QUEUE_PUT) (queue_t * q, mblk_t * mp, pl_t prev_pl) ! 1233: #else ! 1234: __LOCAL__ void ! 1235: QUEUE_PUT __ARGS ((q, mp, prev_pl)) ! 1236: queue_t * q; ! 1237: mblk_t * mp; ! 1238: pl_t prev_pl; ! 1239: #endif ! 1240: { ! 1241: QFROZEN_TRACE (q, "QUEUE_PUT"); ! 1242: ! 1243: q->q_active ++; ! 1244: ! 1245: if (q->q_qinfo->qi_mstat != NULL) ! 1246: q->q_qinfo->qi_mstat->ms_pcnt ++; ! 1247: ! 1248: QUNFREEZE_TRACE (q, prev_pl); ! 1249: ! 1250: ! 1251: (* q->q_qinfo->qi_putp) (q, mp); ! 1252: ! 1253: ! 1254: (void) QFREEZE_TRACE (q, "QUEUE_PUT"); ! 1255: ! 1256: q->q_active --; ! 1257: ! 1258: if ((q->q_flag & QPROCSOFF) != 0 && q->q_active == 0) { ! 1259: /* ! 1260: * Time to wake up the sleepers waiting for the put and ! 1261: * service routines on a queue to exit. See qprocsoff () for ! 1262: * a discussion of the locking protocol. ! 1263: */ ! 1264: ! 1265: (void) LOCK (str_mem->sm_proc_lock, plstr); ! 1266: SV_BROADCAST (str_mem->sm_proc_sv, 0); ! 1267: UNLOCK (str_mem->sm_proc_lock, plstr); ! 1268: } ! 1269: } ! 1270: ! 1271: ! 1272: /* ! 1273: * This local function factors out most of the interesting part of putnext () ! 1274: * into a common block that can be called from any of the related group of ! 1275: * functions putnext (), putnextctl (), putnextctl1 (), and qreply (). ! 1276: */ ! 1277: ! 1278: #if __USE_PROTO__ ! 1279: __LOCAL__ void (QUEUE_PUTNEXT) (queue_t * q, mblk_t * mp) ! 1280: #else ! 1281: __LOCAL__ void ! 1282: QUEUE_PUTNEXT __ARGS ((q, mp)) ! 1283: queue_t * q; ! 1284: mblk_t * mp; ! 1285: #endif ! 1286: { ! 1287: pl_t prev_pl; ! 1288: ! 1289: /* ! 1290: * We call QUEUE_NEXT () to find the next queue on the stream that has ! 1291: * not been disabled via qprocsoff (). It may be that there is no ! 1292: * such queue. This can happen on a uniprocessor or multiprocessor if ! 1293: * a device's interrupt routine begins generating data before the ! 1294: * queue open () entry point has issued qprocson (). Since this is ! 1295: * really an error, we complain about it. ! 1296: */ ! 1297: ! 1298: prev_pl = QFREEZE_TRACE (q, "QUEUE_PUTNEXT"); ! 1299: ! 1300: q = QUEUE_NEXT (q); ! 1301: ! 1302: if (q != NULL) { ! 1303: /* ! 1304: * We have found a queue we are allowed to put to. ! 1305: */ ! 1306: ! 1307: QUEUE_PUT (q, mp, prev_pl); ! 1308: } else { ! 1309: /* ! 1310: * We have run off the end of the stream... we can ! 1311: * either wait, put the message anyway, or discard ! 1312: * the message. Either way, a warning is appropriate. ! 1313: */ ! 1314: ! 1315: cmn_err (CE_WARN, "putnext () ran off end of stream"); ! 1316: freemsg (mp); ! 1317: } ! 1318: ! 1319: QUNFREEZE_TRACE (q, prev_pl); ! 1320: } ! 1321: ! 1322: ! 1323: /* ! 1324: * This internal function is similar in spirit to QUEUE_PUTNEXT (), above, but ! 1325: * instead factors out the process of looking for a queue with a service ! 1326: * procedure that can be enabled from the bcanputnext () and canputnext () ! 1327: * routines. ! 1328: * ! 1329: * Determines whether the caller can legitimately put downstream in the ! 1330: * indicated priority band. ! 1331: * ! 1332: * The queue passed to this function cannot be frozen. ! 1333: */ ! 1334: ! 1335: #if __USE_PROTO__ ! 1336: __LOCAL__ int (QBAND_SRVNEXT) (queue_t * q, uchar_t pri) ! 1337: #else ! 1338: __LOCAL__ int ! 1339: QBAND_SRVNEXT __ARGS ((q, pri)) ! 1340: queue_t * q; ! 1341: uchar_t pri; ! 1342: #endif ! 1343: { ! 1344: int retval; ! 1345: pl_t prev_pl; ! 1346: ! 1347: /* ! 1348: * Scan through the stream for a queue with a service procedure that ! 1349: * we can enable. ! 1350: */ ! 1351: ! 1352: prev_pl = QFREEZE_TRACE (q, "QBAND_SRVNEXT"); ! 1353: ! 1354: for (;;) { ! 1355: ! 1356: q = QUEUE_NEXT (q); ! 1357: ! 1358: if (q == NULL) { ! 1359: /* ! 1360: * We have run off the end of the stream, so return ! 1361: * true to the caller. ! 1362: */ ! 1363: ! 1364: retval = 1; ! 1365: break; ! 1366: ! 1367: } else if (q->q_qinfo->qi_srvp != NULL) { ! 1368: ! 1369: retval = QBAND_CANPUT (q, pri); ! 1370: break; ! 1371: } ! 1372: ! 1373: /* ! 1374: * No service procedure, try next queue in line. ! 1375: */ ! 1376: } ! 1377: ! 1378: QUNFREEZE_TRACE (q, prev_pl); ! 1379: ! 1380: ! 1381: /* ! 1382: * If there are no queues with service procedures, the caller is ! 1383: * allowed to put by default; the special case above is an exception. ! 1384: */ ! 1385: ! 1386: return retval; ! 1387: } ! 1388: ! 1389: ! 1390: /* ! 1391: * This function deals with allocating and initializing a message block from ! 1392: * the message memory; unlike allocb (), an extra parameter can be used to ! 1393: * cause this function to block if there is insufficient memory available to ! 1394: * satisfy the request immediately. ! 1395: */ ! 1396: ! 1397: #if __USE_PROTO__ ! 1398: mblk_t * (MSGB_ALLOC) (size_t size, int pri, int flag) ! 1399: #else ! 1400: mblk_t * ! 1401: MSGB_ALLOC __ARGS ((size, pri, flag)) ! 1402: size_t size; ! 1403: int pri; ! 1404: int flag; ! 1405: #endif ! 1406: { ! 1407: mblk_t * mblkp; ! 1408: ! 1409: ASSERT (flag == KM_SLEEP || flag == KM_NOSLEEP); ! 1410: ASSERT (pri == BPRI_LO || pri == BPRI_MED || pri == BPRI_HI); ! 1411: ! 1412: if ((mblkp = STRMEM_ALLOC (MSGB_SIZE (size), pri, flag)) != NULL) { ! 1413: /* ! 1414: * Note that we don't bother setting up the b_prev and ! 1415: * b_next members of the message block. ! 1416: */ ! 1417: ! 1418: mblkp->b_cont = NULL; ! 1419: mblkp->b_datap = MB_TO_DB (mblkp); ! 1420: mblkp->b_rptr = DB_TO_DATA (mblkp->b_datap); ! 1421: mblkp->b_wptr = mblkp->b_rptr; ! 1422: ! 1423: /* ! 1424: * We specially flag this message block as part of ! 1425: * a triple. While there are other ways we could test ! 1426: * this, for now we permit the possibility that a ! 1427: * client might change the attachments of data blocks ! 1428: * and message blocks perversely. ! 1429: */ ! 1430: ! 1431: mblkp->b_flag = MSGTRIPLE; ! 1432: mblkp->b_band = 0; ! 1433: ! 1434: mblkp->b_datap->db_base = mblkp->b_rptr; ! 1435: mblkp->b_datap->db_lim = mblkp->b_rptr + size; ! 1436: mblkp->b_datap->db_type = M_DATA; ! 1437: mblkp->b_datap->db_ref = 1; ! 1438: ! 1439: mblkp->b_datap->db_frtnp = NULL; ! 1440: } ! 1441: ! 1442: return mblkp; ! 1443: } ! 1444: ! 1445: ! 1446: /* ! 1447: * This local helper function factors out some code in strlog () common to ! 1448: * building the "struct log_ctl" headers for the log messages. ! 1449: */ ! 1450: ! 1451: #if __USE_PROTO__ ! 1452: __LOCAL__ mblk_t * (STRLOG_MAKE) (short mid, short sid, char level, ! 1453: ushort_t flags, ulong_t seq, ushort_t whoami, ! 1454: int * copies, int * failures, mblk_t * data) ! 1455: #else ! 1456: __LOCAL__ mblk_t * ! 1457: STRLOG_MAKE __ARGS ((mid, sid, level, flags, seq, whoami, copies, failures, data)) ! 1458: short mid; ! 1459: short sid; ! 1460: char level; ! 1461: ushort_t flags; ! 1462: ulong_t seq; ! 1463: ushort_t whoami; ! 1464: int * copies; ! 1465: int * failures; ! 1466: mblk_t * data; ! 1467: #endif ! 1468: { ! 1469: mblk_t * ctl; ! 1470: struct log_ctl * lcp; ! 1471: int alloc_pri; ! 1472: int log_pri; ! 1473: ! 1474: if ((flags & whoami) == 0) ! 1475: return NULL; ! 1476: ! 1477: /* ! 1478: * Work out an allocation priority for the M_PROTO message block that ! 1479: * will contain the "log_ctl" description structure, and also ! 1480: * work out a priority for the "mwc_pri" member of the "log_ctl" ! 1481: * structure. ! 1482: * ! 1483: * This code is pretty funky; the real rules might be much simpler, ! 1484: * but this is what I get from the docs. The "log_pri" rules go from ! 1485: * low to high priority, so this code should match the order defined ! 1486: * for the ! 1487: */ ! 1488: ! 1489: if (whoami == SL_ERROR || (flags & SL_FATAL) != 0) ! 1490: alloc_pri = BPRI_HI; ! 1491: else if ((flags & SL_WARN) != 0) ! 1492: alloc_pri = BPRI_MED; ! 1493: else ! 1494: alloc_pri = BPRI_LO; ! 1495: ! 1496: ! 1497: /* ! 1498: * if (whoami == SL_CONSOLE) ! 1499: */ ! 1500: log_pri = LOG_INFO; ! 1501: ! 1502: if ((flags & SL_NOTE) != 0) ! 1503: log_pri = LOG_NOTICE; ! 1504: ! 1505: if (whoami == SL_TRACE) ! 1506: log_pri = LOG_DEBUG; ! 1507: ! 1508: if ((flags & SL_WARN) != 0) ! 1509: log_pri = LOG_WARNING; ! 1510: ! 1511: if (whoami == SL_ERROR) ! 1512: log_pri = LOG_ERR; ! 1513: ! 1514: if ((flags & SL_FATAL) != 0) ! 1515: log_pri = LOG_CRIT; ! 1516: ! 1517: ! 1518: /* ! 1519: * Allocate the necessary structures and fill them in. ! 1520: */ ! 1521: ! 1522: if ((ctl = MSGB_ALLOC (sizeof (struct log_ctl), alloc_pri, ! 1523: KM_NOSLEEP)) == NULL) { ! 1524: ! 1525: (* failures) ++; ! 1526: return NULL; /* return failure */ ! 1527: } ! 1528: ! 1529: if (* copies == 0) ! 1530: ctl->b_cont = data; ! 1531: else if ((ctl->b_cont = dupb (data)) == NULL) { ! 1532: ! 1533: freeb (ctl); ! 1534: ! 1535: (* failures) ++; ! 1536: return NULL; ! 1537: } ! 1538: ! 1539: (* copies) ++; ! 1540: ! 1541: ctl->b_datap->db_type = M_PROTO; ! 1542: lcp = (struct log_ctl *) ctl->b_rptr; ! 1543: ctl->b_wptr = (uchar_t *) (lcp + 1); ! 1544: ! 1545: lcp->mwc_mid = mid; ! 1546: lcp->mwc_sid = sid; ! 1547: lcp->level = level; ! 1548: lcp->flags = flags; ! 1549: lcp->mwc_seqno = seq; ! 1550: lcp->mwc_pri = log_pri | LOG_KERN; ! 1551: ! 1552: return ctl; ! 1553: } ! 1554: ! 1555: ! 1556: /* ! 1557: * This function factors out common code from putbq () and putq () for finding ! 1558: * the insertion point for a message. The original routines differed only in ! 1559: * whether the search was for the end of a band or the front of a band. By ! 1560: * passing in an appropriately adjusted band parameter, the same code can be ! 1561: * made to do double duty. ! 1562: * ! 1563: * The queue passed to this function must be frozen. ! 1564: */ ! 1565: ! 1566: #if __USE_PROTO__ ! 1567: __LOCAL__ void (QUEUE_PLACE_MSG) (queue_t * q, mblk_t * mp, uchar_t band) ! 1568: #else ! 1569: __LOCAL__ void ! 1570: QUEUE_PLACE_MSG __ARGS ((q, mp, band)) ! 1571: queue_t * q; ! 1572: mblk_t * mp; ! 1573: uchar_t band; ! 1574: #endif ! 1575: { ! 1576: mblk_t * scan; ! 1577: ! 1578: /* ! 1579: * The first stage is to skip over all the high-priority messages, and \ ! 1580: * then to find the right band location. ! 1581: */ ! 1582: ! 1583: for (scan = q->q_first ; scan != NULL ; scan = scan->b_next) ! 1584: if (! IS_PRI_MSG (scan)) ! 1585: break; ! 1586: ! 1587: while (scan != NULL && scan->b_band > band) ! 1588: scan = scan->b_next; ! 1589: ! 1590: /* ! 1591: * Now we know where the message goes, do it. ! 1592: */ ! 1593: ! 1594: if ((mp->b_next = scan) == NULL) { ! 1595: ! 1596: if ((mp->b_prev = q->q_last) == NULL) ! 1597: q->q_first = mp; ! 1598: else ! 1599: mp->b_prev->b_next = mp; ! 1600: ! 1601: q->q_last = mp; ! 1602: } else { ! 1603: ! 1604: if ((mp->b_prev = scan->b_prev) == NULL) ! 1605: q->q_first = mp; ! 1606: else ! 1607: mp->b_prev->b_next = mp; ! 1608: ! 1609: scan->b_prev = mp; ! 1610: } ! 1611: } ! 1612: ! 1613: ! 1614: /* ! 1615: *-STATUS: ! 1616: * DDI/DKI ! 1617: * ! 1618: *-NAME: ! 1619: * adjmsg Trim bytes from a message ! 1620: * ! 1621: *-SYNOPSIS: ! 1622: * #include <sys/streams.h> ! 1623: * ! 1624: * int adjmsg (mblk_t * mp, int len); ! 1625: * ! 1626: *-ARGUMENTS: ! 1627: * mp Pointer to the message to be trimmed. ! 1628: * ! 1629: * len The number of bytes to be removed. ! 1630: * ! 1631: *-DESCRIPTION: ! 1632: * adjmsg () removes bytes from a message. |"len"| (the absolute value of ! 1633: * "len") specifies the how many bytes are to be removed. If "len" is ! 1634: * greater than 0, bytes are removed from the head of the message. If ! 1635: * "len" is less than 0, bytes are removed from the tail. adjmsg () fails ! 1636: * if |"len"| is greater than the number of bytes in "mp". If "len" spans ! 1637: * more than one message block in the message, the message blocks must be ! 1638: * the same type, or else adjmsg () will fail. ! 1639: * ! 1640: *-RETURN VALUE: ! 1641: * If the message can be trimmed successfully, 1 is returned. Otherwise, ! 1642: * 0 is returned. ! 1643: * ! 1644: *-LEVEL: ! 1645: * Base or interrupt. ! 1646: * ! 1647: *-NOTES: ! 1648: * Does not sleep. ! 1649: * ! 1650: * Driver-defined basic locks, read/write locks, and sleep locks may be ! 1651: * held across calls to this function. ! 1652: * ! 1653: * If "len" is greater than the amount of data in a single message block, ! 1654: * that message block is not freed. Rather, it is left linked in the ! 1655: * message, and its read and write pointers are set equal to each other, ! 1656: * indicating no data present in the block. ! 1657: * ! 1658: *-SEE ALSO: ! 1659: * msgb ! 1660: */ ! 1661: ! 1662: #if __USE_PROTO__ ! 1663: int (adjmsg) (mblk_t * mp, int len) ! 1664: #else ! 1665: int ! 1666: adjmsg __ARGS ((mp, len)) ! 1667: mblk_t * mp; ! 1668: int len; ! 1669: #endif ! 1670: { ! 1671: uchar_t msgtype = mp->b_datap->db_type; ! 1672: int result = 1; ! 1673: ! 1674: ASSERT (mp != NULL); ! 1675: ! 1676: /* ! 1677: * The DDI/DKI does not specify whether the message blocks are to be ! 1678: * left unmodified in the case of failure. For now, we interpret the ! 1679: * semantics of the routine such that a failure leaves all the ! 1680: * requested data removed, with the return value supplying an ! 1681: * indication that overflow occurred. ! 1682: */ ! 1683: ! 1684: if (len >= 0) { ! 1685: /* ! 1686: * Remove bytes forward from the head of the message. ! 1687: */ ! 1688: ! 1689: while (len != 0) { ! 1690: mblk_t * next; ! 1691: ! 1692: if (mp->b_wptr - mp->b_rptr >= len) { ! 1693: /* ! 1694: * We are only comsuming part of the message. ! 1695: */ ! 1696: ! 1697: mp->b_rptr += len; ! 1698: ! 1699: return 1; ! 1700: } else if ((next = mp->b_cont) == NULL) { ! 1701: /* ! 1702: * All the message blocks in the message have ! 1703: * been totally consumed, so return failure. ! 1704: */ ! 1705: ! 1706: mp->b_rptr = mp->b_wptr; ! 1707: ! 1708: return 0; ! 1709: } ! 1710: ! 1711: /* ! 1712: * This message block has been consumed, so leave it ! 1713: * empty. ! 1714: */ ! 1715: ! 1716: len -= mp->b_wptr - mp->b_rptr; ! 1717: ! 1718: mp->b_wptr = mp->b_rptr = mp->b_datap->db_base; ! 1719: ! 1720: mp = next; ! 1721: ! 1722: if (mp->b_datap->db_type != msgtype) ! 1723: return 0; /* wrong types */ ! 1724: } ! 1725: ! 1726: } else { ! 1727: mblk_t * span = mp; ! 1728: int size = 0; ! 1729: ! 1730: /* ! 1731: * Since message blocks only have forward links, we have to ! 1732: * employ some subterfuge to implement this efficiently. We ! 1733: * first scan forward to discover the size and start of the ! 1734: * last span of message blocks with the same type. ! 1735: */ ! 1736: ! 1737: for (;;) { ! 1738: size += mp->b_wptr - mp->b_rptr; ! 1739: ! 1740: if ((mp = mp->b_cont) == NULL) ! 1741: break; ! 1742: ! 1743: if (mp->b_datap->db_type != msgtype) { ! 1744: /* ! 1745: * The type has changed, so we reset our count ! 1746: * and start pointers to begin a new span. ! 1747: */ ! 1748: ! 1749: size = 0; ! 1750: msgtype = mp->b_datap->db_type; ! 1751: span = mp; ! 1752: } ! 1753: } ! 1754: ! 1755: ! 1756: if (size < len) { ! 1757: /* ! 1758: * The user has requested too many bytes be removed, ! 1759: * so we return a failure indication and remove as ! 1760: * many as we are able. ! 1761: */ ! 1762: ! 1763: result = 0; ! 1764: len = size; ! 1765: } ! 1766: ! 1767: ! 1768: /* ! 1769: * Now we have the last span, we can scan forward for the ! 1770: * point where we must begin emptying messages. ! 1771: */ ! 1772: ! 1773: while (size > 0) { ! 1774: ! 1775: size -= span->b_wptr - span->b_rptr; ! 1776: ! 1777: if (size < len) { ! 1778: /* ! 1779: * The count of bytes remaining in the span ! 1780: * is less than the threshold, so we start to ! 1781: * remove data. ! 1782: */ ! 1783: ! 1784: span->b_wptr -= (len - size); ! 1785: ! 1786: len = size; ! 1787: } ! 1788: ! 1789: span = span->b_next; ! 1790: } ! 1791: } ! 1792: ! 1793: return result; ! 1794: } ! 1795: ! 1796: ! 1797: /* ! 1798: *-STATUS: ! 1799: * DDI/DKI ! 1800: * ! 1801: *-NAME: ! 1802: * allocb Allocate a message block ! 1803: * ! 1804: *-SYNOPSIS: ! 1805: * #include <sys/types.h> ! 1806: * #include <sys/stream.h> ! 1807: * ! 1808: * mblk_t * allocb (int size, uint_t pri); ! 1809: * ! 1810: *-ARGUMENTS: ! 1811: * size The number of bytes in the message block. ! 1812: * ! 1813: * pri Priority of the request. This can take on one of three ! 1814: * values: BPRI_LO, BPRI_MED, or BPRI_HI. ! 1815: * ! 1816: *-DESCRIPTION: ! 1817: * allocb () tries to allocate a STREAMS message block. Buffer allocation ! 1818: * fails only when the system is out of memory. If no buffer is ! 1819: * available, the bufcall () function can help a module recover from an ! 1820: * allocation failure. ! 1821: * ! 1822: * The "pri" argument is a hint to the allocator indicating how badly the ! 1823: * message is needed. BPRI_LO should be used for normal data allocations, ! 1824: * BPRI_MED should be used for other non-critical allocations. BPRI_HI ! 1825: * should be used for allocations that absolutely must succeed, even ! 1826: * though success is not guaranteed. Some implementations may choose to ! 1827: * ignore this parameter. ! 1828: * ! 1829: *-RETURN VALUE: ! 1830: * If successful, allocb () returns a pointer to the allocated message ! 1831: * block of type M_DATA (defined in <sys/stream.h>). If a block cannot be ! 1832: * allocated, a NULL pointer is returned. ! 1833: * ! 1834: *-LEVEL: ! 1835: * Base or Interrupt. ! 1836: * ! 1837: *-NOTES: ! 1838: * Does not sleep. ! 1839: * ! 1840: * Driver-defined basic locks, read/write locks, and sleep locks may be ! 1841: * held across calls to this function. ! 1842: * ! 1843: *-SEE ALSO: ! 1844: * bufcall (), esballoc (), esbbcall (), freeb (), msgb ! 1845: */ ! 1846: ! 1847: #if __USE_PROTO__ ! 1848: mblk_t * (allocb) (int size, uint_t pri) ! 1849: #else ! 1850: mblk_t * ! 1851: allocb __ARGS ((size, pri)) ! 1852: uint_t size; ! 1853: uint_t pri; ! 1854: #endif ! 1855: { ! 1856: ASSERT (size >= 0); ! 1857: ASSERT (ATOMIC_FETCH_UCHAR (str_mem->sm_init) && ! 1858: str_mem->sm_msg_lock != NULL); ! 1859: ! 1860: /* ! 1861: * Since we allocate things in triples, "allocb (0)" could be legal if ! 1862: * we wanted. There aren't any compelling reasons either way, but for ! 1863: * simplicity I'll permit it. ! 1864: */ ! 1865: ! 1866: #if 0 ! 1867: if (size == 0) ! 1868: return NULL; ! 1869: #endif ! 1870: ! 1871: return MSGB_ALLOC (size, pri, KM_NOSLEEP); ! 1872: } ! 1873: ! 1874: ! 1875: /* ! 1876: *-STATUS: ! 1877: * DDI/DKI ! 1878: * ! 1879: *-NAME: ! 1880: * bcanput Test for flow control in specified priority band. ! 1881: * ! 1882: *-SYNOPSIS: ! 1883: * #include <sys/types.h> ! 1884: * #include <sys/stream.h> ! 1885: * ! 1886: * int bcanput (queue_t * q, uchar_t pri); ! 1887: * ! 1888: *-ARGUMENTS: ! 1889: * q Pointer to the message queue. ! 1890: * ! 1891: * pri Message priority. ! 1892: * ! 1893: *-DESCRIPTION: ! 1894: * bcanput () tests if there is room for a message in priority band "pri" ! 1895: * of the queue pointed to by "q". The queue _must_ have a service ! 1896: * procedure. ! 1897: * ! 1898: * If "pri" is 0, the bcanput () call is equivalent to a call to ! 1899: * canput (). ! 1900: * ! 1901: * It is possible because of race conditions to test for room using ! 1902: * bcanput () and get an indication that there is room for a message, and ! 1903: * then have the queue fill up before subsequently enqueuing the message, ! 1904: * causing a violation of flow control. This is not a problem, since the ! 1905: * violation of flow control in this case is bounded. ! 1906: * ! 1907: *-RETURN VALUE: ! 1908: * bcanput () returns 1 if a message of priority "pri" can be placed on ! 1909: * the queue. 0 is returned if a message of priority "pri" cannot be ! 1910: * enqueued because of flow control within the priority band. ! 1911: * ! 1912: *-LEVEL: ! 1913: * Base or interrupt. ! 1914: * ! 1915: *-NOTES: ! 1916: * Does not sleep. ! 1917: * ! 1918: * The driver writer is responsible for both testing a queue with ! 1919: * bcanput () and refraining from placing a message if bcanput () fails. ! 1920: * ! 1921: * The caller cannot have the stream frozen [see freezestr ()] when ! 1922: * calling this function. ! 1923: * ! 1924: * Driver-defined basic locks, read/write locks, and sleep locks may be ! 1925: * held across calls to this function. ! 1926: * ! 1927: * The "q" argument may not reference "q_next" (for example, an argument ! 1928: * of "q->q_next" is erroneous on a multiprocessor and is disallowed by ! 1929: * the DDI/DKI). "bcanputnext (q)" is provided as a multiprocessor-safe ! 1930: * equivalent to the common call "bcanput (q->q_next)", which is no ! 1931: * longer allowed [see bcanputnext ()]. ! 1932: * ! 1933: *-SEE ALSO: ! 1934: * bcanputnext (), canput (), canputnext (), putbq (), putnext () ! 1935: */ ! 1936: ! 1937: #if __USE_PROTO__ ! 1938: int (bcanput) (queue_t * q, uchar_t pri) ! 1939: #else ! 1940: int ! 1941: bcanput __ARGS ((q, pri)) ! 1942: queue_t * q; ! 1943: uchar_t pri; ! 1944: #endif ! 1945: { ! 1946: pl_t prev_pl; ! 1947: int result = 1; ! 1948: ! 1949: prev_pl = QFREEZE_TRACE (q, "bcanput"); ! 1950: ! 1951: result = QBAND_CANPUT (q, pri); ! 1952: ! 1953: QUNFREEZE_TRACE (q, prev_pl); ! 1954: ! 1955: return result; ! 1956: } ! 1957: ! 1958: ! 1959: /* ! 1960: *-STATUS: ! 1961: * DDI/DKI ! 1962: * ! 1963: *-NAME: ! 1964: * bcanputnext Test for flow control in specified priority band. ! 1965: * ! 1966: *-SYNOPSIS: ! 1967: * #include <sys/types.h> ! 1968: * #include <sys/stream.h> ! 1969: * ! 1970: * int bcanputnext (queue_t * q, uchar_t pri); ! 1971: * ! 1972: *-ARGUMENTS: ! 1973: * q Pointer to the message queue. ! 1974: * ! 1975: * pri Message priority. ! 1976: * ! 1977: *-DESCRIPTION: ! 1978: * bcanputnext () searches through the stream (starting at "q->q_next") ! 1979: * until it finds a queue containing a service routine, or until it ! 1980: * reaches the end of the stream. If found, the queue containing the ! 1981: * service routine is tested to see if a message in priority band "pri" ! 1982: * can be enqueued. If the band is full, bcanputnext () marks the queue ! 1983: * to automatically back-enable the caller's service routine when the ! 1984: * amount of data in messages on the queue has reached its low water ! 1985: * mark. ! 1986: * ! 1987: * If "pri" is 0, the bcanputnext () call is equivalent to a call to ! 1988: * canputnext (). ! 1989: * ! 1990: * It is possible because of race conditions to test for room using ! 1991: * bcanputnext () and get an indication that there is room for a message, ! 1992: * and then have the queue fill up before subsequently enqueuing the ! 1993: * message, causing a violation of flow control. This is not a problem, ! 1994: * since the violation of flow control in this case is bounded. ! 1995: * ! 1996: *-RETURN VALUE: ! 1997: * bcanputnext () returns 1 if a message of priority "pri" can be sent in ! 1998: * the stream, or 0 if the stream is flow-controlled. If bcanputnext () ! 1999: * reaches the end of the stream without finding a queue with a service ! 2000: * procedure, then it returns 1. ! 2001: * ! 2002: *-LEVEL: ! 2003: * Base or interrupt. ! 2004: * ! 2005: *-NOTES: ! 2006: * Does not sleep. ! 2007: * ! 2008: * The driver writer is responsible for both testing a queue with ! 2009: * bcanputnext () and refraining from placing a message if bcanputnext () ! 2010: * fails. ! 2011: * ! 2012: * The caller cannot have the stream frozen [see freezestr ()] when ! 2013: * calling this function. ! 2014: * ! 2015: * Driver-defined basic locks, read/write locks, and sleep locks may be ! 2016: * held across calls to this function. ! 2017: * ! 2018: * The "q" argument may not reference "q_next" (for example, an argument ! 2019: * of "q->q_next" is erroneous on a multiprocessor and is disallowed by ! 2020: * the DDI/DKI). "bcanputnext (q)" is provided as a multiprocessor-safe ! 2021: * equivalent to the common call "bcanput (q->q_next)", which is no ! 2022: * longer allowed [see bcanputnext ()]. ! 2023: * ! 2024: *-SEE ALSO: ! 2025: * bcanput (), canput (), canputnext (), putbq (), putnext () ! 2026: */ ! 2027: ! 2028: #if __USE_PROTO__ ! 2029: int (bcanputnext) (queue_t * q, uchar_t pri) ! 2030: #else ! 2031: int ! 2032: bcanputnext __ARGS ((q, pri)) ! 2033: queue_t * q; ! 2034: uchar_t pri; ! 2035: #endif ! 2036: { ! 2037: QUEUE_TRACE (q, "bcanputnext"); ! 2038: ! 2039: return QBAND_SRVNEXT (q, pri); ! 2040: } ! 2041: ! 2042: ! 2043: /* ! 2044: * Note: backq () is not present in the System V DDI/DKI For Intel Processors ! 2045: * with Multiprocessing reference, and is listed in one of the appendices of ! 2046: * that volume as having been removed in the R3.2 to R4 transition. However, ! 2047: * the function is present in the regular generic System V DDI/DKI. ! 2048: */ ! 2049: ! 2050: #if 0 ! 2051: /* ! 2052: *-STATUS: ! 2053: * DDI/DKI ! 2054: * ! 2055: *-NAME: ! 2056: * backq Get pointer to the queue behind the current queue. ! 2057: * ! 2058: *-SYNOPSIS: ! 2059: * #include <sys/stream.h> ! 2060: * ! 2061: * queue_t * backq (queue_t * q); ! 2062: * ! 2063: *-ARGUMENTS: ! 2064: * q Pointer to the current queue. ! 2065: * ! 2066: *-DESCRIPTION: ! 2067: * backq () returns a pointer to the queue preceding "q". If "q" is a ! 2068: * read queue, backq () returns a pointer to the queue downstream from ! 2069: * "q", unless it is the stream end. If "q" is a write queue, backq () ! 2070: * returns a pointer to the next queue upstream from "q", unless it is ! 2071: * the stream head. ! 2072: * ! 2073: *-RETURN VALUE: ! 2074: * If successful, backq () returns a pointer to the queue preceding the ! 2075: * current queue. Otherwise, it returns NULL. ! 2076: * ! 2077: *-LEVEL: ! 2078: * Base or interrupt. ! 2079: * ! 2080: *-NOTES: ! 2081: * Does not sleep. ! 2082: * ! 2083: * The caller cannot have the stream frozen [see freezestr ()] when ! 2084: * calling this function. ! 2085: * ! 2086: * Driver-defined basic locks, read/write locks, and sleep locks may be ! 2087: * held across calls to this function. ! 2088: * ! 2089: * If the case of a STREAMS-based fifo, this function takes no special ! 2090: * action at the midpoint of the stream where the read and write sides ! 2091: * interchange. ! 2092: */ ! 2093: ! 2094: #if __USE_PROTO__ ! 2095: queue_t * (backq) (queue_t * q) ! 2096: #else ! 2097: queue_t * ! 2098: backq __ARGS ((q)) ! 2099: queue_t * q; ! 2100: #endif ! 2101: { ! 2102: q = OTHERQ (q); ! 2103: ! 2104: q = QUEUE_NEXT (q); ! 2105: ! 2106: if (q == NULL) ! 2107: return NULL; ! 2108: ! 2109: return OTHERQ (q); ! 2110: } ! 2111: #endif ! 2112: ! 2113: ! 2114: /* ! 2115: *-STATUS: ! 2116: * DDI/DKI ! 2117: * ! 2118: *-NAME: ! 2119: * bufcall Call a function when a buffer becomes available. ! 2120: * ! 2121: *-SYNOPSIS: ! 2122: * #include <sys/types.h> ! 2123: * #include <sys/stream.h> ! 2124: * ! 2125: * toid_t bufcall (uint_t size, int pri, void (* func) (), long arg); ! 2126: * ! 2127: *-ARGUMENTS: ! 2128: * size Number of bytes in the buffer to be allocated (from ! 2129: * the failed allocb () request). ! 2130: * ! 2131: * pri Priority of the allocb () allocation request (BPRI_LO, ! 2132: * BPRI_MED, or BPRI_HI). ! 2133: * ! 2134: * func Fuction or driver routine to be called when a buffer ! 2135: * becomes available. ! 2136: * ! 2137: * arg Argument to the function to be called when a buffer ! 2138: * becomes available. ! 2139: * ! 2140: *-DESCRIPTION: ! 2141: * bufcall () serves as a timeout call of indeterminate length. When a ! 2142: * buffer allocation request fails, bufcall () can be used to schedule ! 2143: * the routine "func" to be called with the argument "arg" when a buffer ! 2144: * of at least "size" bytes becomes available. ! 2145: * ! 2146: * When "func" runs, all interrupts from STREAMS devices will be blocked ! 2147: * on the processor on which it is running. "func" will have no user ! 2148: * context and may not call any function that sleeps. ! 2149: * ! 2150: *-RETURN VALUE: ! 2151: * If successful, bufcall () returns a non-zero value that identifies the ! 2152: * scheduling request. This non-zero identifier may be passed to ! 2153: * unbufcall () to cancel the request. If any failure occurs, bufcall () ! 2154: * returns 0. ! 2155: * ! 2156: *-LEVEL: ! 2157: * Base or interrupt. ! 2158: * ! 2159: *-NOTES: ! 2160: * Does not sleep. ! 2161: * ! 2162: * Driver-defined basic locks, read/write locks, and sleep locks may be ! 2163: * held across calls to this function. ! 2164: * ! 2165: * Even when "func" is called, allocb () can still fail if another ! 2166: * module or driver had allocated the memory before "func" was able to ! 2167: * call allocb (). ! 2168: * ! 2169: *-SEE ALSO: ! 2170: * allocb (), esballoc (), esbbcall (), itimeout (), unbufcall (). ! 2171: */ ! 2172: ! 2173: #if __USE_PROTO__ ! 2174: toid_t (bufcall) (uint_t size, int pri, ...) ! 2175: #else ! 2176: toid_t ! 2177: bufcall __ARGS ((size, pri)) ! 2178: uint_t size; ! 2179: int pri; ! 2180: #endif ! 2181: { ! 2182: se_funcptr_t func; ! 2183: long arg; ! 2184: va_list arglist; ! 2185: sevent_t * seventp; ! 2186: ! 2187: ! 2188: /* ! 2189: * Before we do anything, we fetch the two other arguments. We use ! 2190: * the variable-argument function convention to get around problems ! 2191: * with implicit conversions introduced by having a prototype for ! 2192: * this function visible. ! 2193: * ! 2194: * This is a generic problem with callbacks, since the shape of a ! 2195: * function type includes the shapes of the function arguments, and ! 2196: * because we want to pass some argument to the user-supplied function ! 2197: * without knowing its type (and hence, we must not cause any implicit ! 2198: * conversions on its value). ! 2199: */ ! 2200: ! 2201: va_start (arglist, pri); ! 2202: ! 2203: func = va_arg (arglist, se_funcptr_t); ! 2204: arg = va_arg (arglist, long); ! 2205: ! 2206: va_end (arglist); ! 2207: ! 2208: ! 2209: /* ! 2210: * It may be that NULL is defined in such a way that it is not ! 2211: * meaningful to compare it with a function pointer, so we just cast ! 2212: * a zero to get the right kind of effect. ! 2213: * ! 2214: * We add some extra assertions below to check that "long" is of ! 2215: * sufficient size to contain all likely parameter data items. For ! 2216: * C, "likely" means the fundamental types, which has to include ! 2217: * pointers to functions, pointers to void, and also pointers to ! 2218: * structures since under C++ there is currently no guarantee to match ! 2219: * the ISO C requirement that a pointer of type "void *" be able to ! 2220: * hold the value of any pointer type without loss of information. ! 2221: * [We don't consider member pointers here; they are pathological] ! 2222: */ ! 2223: ! 2224: ASSERT (sizeof (se_funcptr_t) <= sizeof (long) && ! 2225: sizeof (_VOID *) <= sizeof (long) && ! 2226: sizeof (selist_t *) <= sizeof (long)); ! 2227: ! 2228: ASSERT (func != (se_funcptr_t) 0); ! 2229: ASSERT (pri == BPRI_LO || pri == BPRI_HI || pri == BPRI_LO); ! 2230: ! 2231: ! 2232: /* ! 2233: * Here we *could* lock and test the available space in the STREAMS ! 2234: * message heap to see whether sufficient space to satisfy the ! 2235: * request has become available between the failed allocb () and ! 2236: * the bufcall () request. ! 2237: * ! 2238: * The question is whether the extra time that the heap is locked is ! 2239: * worth overcoming a delay for a freemsg () to trigger the bufcall () ! 2240: * later, especially given the fact that we'll have to unlock the ! 2241: * heap to call the user's callback (introducing the opportunity for ! 2242: * the newly-discovered space to vanish). ! 2243: * ! 2244: * All in all, once things get to the bufcall () stage there seems ! 2245: * little reason to keep pushing the system, so we don't bother. ! 2246: */ ! 2247: ! 2248: /* ! 2249: * First off, let's get ourselves an event cell. This is mutually ! 2250: * dependent with the ID generation policy; if ID codes are stored in ! 2251: * the event cells, we are free to allocate and discard from a general ! 2252: * memory pool; if ID codes are not stored, then they must reflect ! 2253: * some persistent attribute of the cell, which usually implies that ! 2254: * cells come from some nonshrinking managed pool. ! 2255: * ! 2256: * Of course, a generative ID code scheme requires extra locking in ! 2257: * the absence of atomic FETCH_AND_INCREMENT () operations. In this ! 2258: * implementation, we get around this by using the list-head locks ! 2259: * to guard the counter operations. [This has interesting implications ! 2260: * for the design of a generic list-manipulation facility.] ! 2261: */ ! 2262: ! 2263: #if _TOID_MEMBER ! 2264: if ((seventp = (sevent_t *) kmem_alloc (sizeof (sevent_t), ! 2265: KM_NOSLEEP)) == NULL) ! 2266: return 0; ! 2267: #else ! 2268: #error Need an allocator for event cells that matches the ID policy ! 2269: #endif ! 2270: ! 2271: /* ! 2272: * Fill in the event cell. Note that the size member includes the ! 2273: * memory space required for the message block and data block! ! 2274: */ ! 2275: ! 2276: seventp->se_arg = arg; ! 2277: seventp->se_func = func; ! 2278: seventp->se_size = MSGB_SIZE (size); ! 2279: ! 2280: ! 2281: return STORE_EVENT (seventp, pri); ! 2282: } ! 2283: ! 2284: ! 2285: /* ! 2286: *-STATUS: ! 2287: * DDI/DKI ! 2288: * ! 2289: *-NAME: ! 2290: * canput Test for room in a message queue. ! 2291: * ! 2292: *-SYNOPSIS: ! 2293: * #include <sys/stream.h> ! 2294: * ! 2295: * int canput (queue_t * q); ! 2296: * ! 2297: *-ARGUMENTS: ! 2298: * q Pointer to the message queue. ! 2299: * ! 2300: *-DESCRIPTION: ! 2301: * canput () tests if there is room for a message in the queue pointed to ! 2302: * by "q". The queue _must_ have a service procedure. ! 2303: * ! 2304: * It is possivle because of race conditions to test for room using ! 2305: * canput () and get an indication that there is room for a message, and ! 2306: * then have the queue fill up before subsequently enqueuing the message, ! 2307: * causing a violation of flow control. This is not a problem, since the ! 2308: * violation of flow control in this case is bounded. ! 2309: * ! 2310: *-RETURN VALUE: ! 2311: * canput () returns 1 if a message can be placed on the queue. 0 is ! 2312: * returned if a message cannot be enqueued because of flow control. ! 2313: * ! 2314: *-LEVEL: ! 2315: * Base or interrupt. ! 2316: * ! 2317: *-NOTES: ! 2318: * Does not sleep. ! 2319: * ! 2320: * The driver writer is responsible for both testing a queue with ! 2321: * canput () and refraining from placing a message if canput () fails. ! 2322: * ! 2323: * The caller cannot have the stream frozen [see freezestr ()] when ! 2324: * calling this function. ! 2325: * ! 2326: * Driver-defined basic locks, read/write locks, and sleep locks may be ! 2327: * held across calls to this function. ! 2328: * ! 2329: * The "q" argument may not reference "q_next" (for example, an argument ! 2330: * of "q->q_next" is erroneous on a multiprocessor and is disallowed by ! 2331: * the DDI/DKI). "canputnext (q)" is provided as a multiprocessor-safe ! 2332: * equivalent to the common call "canput (q->q_next)", which is no ! 2333: * longer allowed [see canputnext ()]. ! 2334: * ! 2335: *-SEE ALSO: ! 2336: * bcanputnext (), bcanput (), canputnext (), putbq (), putnext () ! 2337: */ ! 2338: ! 2339: #if __USE_PROTO__ ! 2340: int (canput) (queue_t * q) ! 2341: #else ! 2342: int ! 2343: canput __ARGS ((q)) ! 2344: queue_t * q; ! 2345: #endif ! 2346: { ! 2347: pl_t prev_pl; ! 2348: int result = 1; ! 2349: ! 2350: prev_pl = QFREEZE_TRACE (q, "canput"); ! 2351: ! 2352: if ((q->q_flag & QFULL) != 0) { ! 2353: /* ! 2354: * We must set the following flag to indicate that the ! 2355: * queue has a writer who has made a failed write ! 2356: * attempt. ! 2357: */ ! 2358: ! 2359: q->q_flag |= QWANTW; ! 2360: ! 2361: result = 0; ! 2362: } ! 2363: ! 2364: QUNFREEZE_TRACE (q, prev_pl); ! 2365: ! 2366: return result; ! 2367: } ! 2368: ! 2369: ! 2370: /* ! 2371: *-STATUS: ! 2372: * DDI/DKI ! 2373: * ! 2374: *-NAME: ! 2375: * canputnext Test for flow control in a stream. ! 2376: * ! 2377: *-SYNOPSIS: ! 2378: * #include <sys/stream.h> ! 2379: * ! 2380: * int bcanputnext (queue_t * q); ! 2381: * ! 2382: *-ARGUMENTS: ! 2383: * q Pointer to the message queue. ! 2384: * ! 2385: *-DESCRIPTION: ! 2386: * canputnext () searches through the stream (starting at "q->q_next") ! 2387: * until it finds a queue containing a service routine, or until it ! 2388: * reaches the end of the stream. If found, the queue containing the ! 2389: * service routine is tested to see if there is room for a message in the ! 2390: * queue. If the band is full, canputnext () marks the queue to ! 2391: * automatically back-enable the caller's service routine when the amount ! 2392: * of data in messages on the queue has reached its low water mark. ! 2393: * ! 2394: * It is possible because of race conditions to test for room using ! 2395: * canputnext () and get an indication that there is room for a message, ! 2396: * and then have the queue fill up before subsequently enqueuing the ! 2397: * message, causing a violation of flow control. This is not a problem, ! 2398: * since the violation of flow control in this case is bounded. ! 2399: * ! 2400: *-RETURN VALUE: ! 2401: * canputnext () returns 1 if a message can be sent in the stream, or 0 ! 2402: * if the stream is flow-controlled. If canputnext () reaches the end of ! 2403: * the stream without finding a queue with a service procedure, then it ! 2404: * returns 1. ! 2405: * ! 2406: *-LEVEL: ! 2407: * Base or interrupt. ! 2408: * ! 2409: *-NOTES: ! 2410: * Does not sleep. ! 2411: * ! 2412: * The driver writer is responsible for both testing a queue with ! 2413: * bcanputnext () and refraining from placing a message if bcanputnext () ! 2414: * fails. ! 2415: * ! 2416: * The caller cannot have the stream frozen [see freezestr ()] when ! 2417: * calling this function. ! 2418: * ! 2419: * Driver-defined basic locks, read/write locks, and sleep locks may be ! 2420: * held across calls to this function. ! 2421: * ! 2422: * The "q" argument may not reference "q_next" (for example, an argument ! 2423: * of "q->q_next" is erroneous on a multiprocessor and is disallowed by ! 2424: * the DDI/DKI). "bcanputnext (q)" is provided as a multiprocessor-safe ! 2425: * equivalent to the common call "bcanput (q->q_next)", which is no ! 2426: * longer allowed [see bcanputnext ()]. ! 2427: * ! 2428: *-SEE ALSO: ! 2429: * bcanput (), bcanputnext (), canput (), putbq (), putnext () ! 2430: */ ! 2431: ! 2432: #if __USE_PROTO__ ! 2433: int (canputnext) (queue_t * q) ! 2434: #else ! 2435: int ! 2436: canputnext __ARGS ((q)) ! 2437: queue_t * q; ! 2438: #endif ! 2439: { ! 2440: QUEUE_TRACE (q, "canputnext"); ! 2441: ! 2442: /* ! 2443: * Rather than depend on canput () above, we'll use the band-capable ! 2444: * function QBAND_SRVNEXT () and depend on its ability to handle ! 2445: * band 0. The mechanics of iterating through a stream are much more ! 2446: * complex now than in the old SVR3.2 days due to both freezestr () ! 2447: * and qprocsoff (). ! 2448: */ ! 2449: ! 2450: return QBAND_SRVNEXT (q, 0); ! 2451: } ! 2452: ! 2453: ! 2454: /* ! 2455: *-STATUS: ! 2456: * DDI/DKI ! 2457: * ! 2458: *-NAME: ! 2459: * copyb Copy a message block. ! 2460: * ! 2461: *-SYNOPSIS: ! 2462: * #include <sys/stream.h> ! 2463: * ! 2464: * mblk_t * copyb (mblk_t * bp); ! 2465: * ! 2466: *-ARGUMENTS: ! 2467: * bp Pointer to the message block from which data are ! 2468: * copied. ! 2469: * ! 2470: *-DESCRIPTION: ! 2471: * copyb () allocates a new message block, and copies into it the data ! 2472: * from the block pointed to by "bp". The new block will be at least as ! 2473: * large as the block being copied. The "b_rptr" and "b_wptr" members of ! 2474: * the message block pointed to by "bp" are used to determine how many ! 2475: * bytes to copy. ! 2476: * ! 2477: *-RETURN VALUE: ! 2478: * If successful, copyb () returns a pointer to the newly allocated ! 2479: * message block containing the copied data. Otherwise, it returns a NULL ! 2480: * pointer. ! 2481: * ! 2482: *-LEVEL: ! 2483: * Base or interrupt. ! 2484: * ! 2485: *-NOTES: ! 2486: * Does not sleep. ! 2487: * ! 2488: * Driver-defined basic locks, read/write locks, and sleep locks may be ! 2489: * held across calls to this function. ! 2490: * ! 2491: *-SEE ALSO: ! 2492: * allocb (), copymsg (), msgb ! 2493: */ ! 2494: ! 2495: #define ALLOW_EMPTY_COPIES ! 2496: ! 2497: #if __USE_PROTO__ ! 2498: mblk_t * (copyb) (mblk_t * bp) ! 2499: #else ! 2500: mblk_t * ! 2501: copyb __ARGS ((bp)) ! 2502: mblk_t * bp; ! 2503: #endif ! 2504: { ! 2505: mblk_t * newmsg; ! 2506: size_t size; ! 2507: ! 2508: ASSERT (bp != NULL && bp->b_datap != NULL); ! 2509: ! 2510: /* ! 2511: * What to do if there is no real data in the original message? ! 2512: * ! 2513: * Copy it anyway, I guess. ! 2514: */ ! 2515: ! 2516: size = bp->b_wptr - bp->b_rptr; ! 2517: ! 2518: if (size == 0) ! 2519: return MSGB_ALLOC (0, BPRI_LO, KM_NOSLEEP); ! 2520: ! 2521: ! 2522: /* ! 2523: * In this implementation we only allocate exactly as much space as ! 2524: * we require (thus opening the zero-length issue). It is possible to ! 2525: * interpret the wording of the manual-page as implying that the size ! 2526: * of the new block is at least the size of the old block including ! 2527: * unused space, but that doesn't seem reasonable. I read that ! 2528: * requirement as merely pointing out that the allocator can give ! 2529: * more memory to the new block that is strictly necessary. ! 2530: */ ! 2531: ! 2532: if ((newmsg = MSGB_ALLOC (size, BPRI_LO, KM_NOSLEEP)) != NULL) { ! 2533: ! 2534: newmsg->b_datap->db_type = bp->b_datap->db_type; ! 2535: ! 2536: memcpy (newmsg->b_rptr, bp->b_rptr, size); ! 2537: ! 2538: newmsg->b_wptr += size; ! 2539: } ! 2540: ! 2541: return newmsg; ! 2542: } ! 2543: ! 2544: ! 2545: /* ! 2546: *-STATUS: ! 2547: * DDI/DKI ! 2548: * ! 2549: *-NAME: ! 2550: * copymsg Copy a message. ! 2551: * ! 2552: *-SYNOPSIS: ! 2553: * #include <sys/stream.h> ! 2554: * ! 2555: * mblk_t * copymsg (mblk_t * mp); ! 2556: * ! 2557: *-ARGUMENTS: ! 2558: * mp Pointer to the message to be copied. ! 2559: * ! 2560: *-DESCRIPTION: ! 2561: * copymsg () forms a new message by allocating message blocks, copies ! 2562: * the conents of the message referred to by "mp" (using the copyb () ! 2563: * function) and returns a pointer to the new message. ! 2564: * ! 2565: *-RETURN VALUE: ! 2566: * If successful, copymsg () returns a pointer to the new message. ! 2567: * Otherwise, it returns a NULL pointer. ! 2568: * ! 2569: *-LEVEL: ! 2570: * Base or interrupt. ! 2571: * ! 2572: *-NOTES: ! 2573: * Does not sleep. ! 2574: * ! 2575: * Driver-defined basic locks, read/write locks, and sleep locks may be ! 2576: * held across calls to this function. ! 2577: * ! 2578: *-SEE ALSO: ! 2579: * allocb (), copyb (), msgb ! 2580: */ ! 2581: ! 2582: #if __USE_PROTO__ ! 2583: mblk_t * (copymsg) (mblk_t * mp) ! 2584: #else ! 2585: mblk_t * ! 2586: copymsg __ARGS ((mp)) ! 2587: mblk_t * mp; ! 2588: #endif ! 2589: { ! 2590: mblk_t * oldscan; ! 2591: mblk_t * msg; ! 2592: mblk_t * newblk; ! 2593: ! 2594: ASSERT (mp != NULL && mp->b_datap != NULL); ! 2595: ! 2596: /* ! 2597: * Rather than simply layering on top of copyb (), we can make this ! 2598: * function be more friendly in situations where memory is scarce by ! 2599: * trying the allocations before the copies, so that we don't spend ! 2600: * time copying data that is going to be discarded. ! 2601: */ ! 2602: ! 2603: if ((newblk = msg = MSGB_ALLOC (mp->b_wptr - mp->b_rptr, BPRI_LO, ! 2604: KM_NOSLEEP)) == NULL) ! 2605: return NULL; ! 2606: ! 2607: for (oldscan = mp->b_cont ; oldscan != NULL ; ! 2608: newblk = newblk->b_cont, oldscan = oldscan->b_cont) { ! 2609: ! 2610: if ((newblk->b_cont = ! 2611: MSGB_ALLOC (oldscan->b_wptr - oldscan->b_rptr, ! 2612: BPRI_LO, KM_NOSLEEP)) == NULL) { ! 2613: freemsg (msg); ! 2614: return NULL; ! 2615: } ! 2616: } ! 2617: ! 2618: /* ! 2619: * Now we have the memory, do the copy. Like copyb (), we have have to ! 2620: * remember to dance around zero-length blocks in the original, which ! 2621: * we will be preserve as copied zero-length blocks. ! 2622: */ ! 2623: ! 2624: oldscan = mp; ! 2625: newblk = msg; ! 2626: ! 2627: do { ! 2628: size_t size; ! 2629: ! 2630: ASSERT (oldscan != NULL); ! 2631: ! 2632: if ((size = oldscan->b_wptr - oldscan->b_rptr) > 0) ! 2633: memcpy (newblk->b_rptr, oldscan->b_rptr, size); ! 2634: newblk->b_wptr += size; ! 2635: ! 2636: oldscan = oldscan->b_cont; ! 2637: } while ((newblk = newblk->b_cont) != NULL); ! 2638: ! 2639: ASSERT (oldscan == NULL); ! 2640: ! 2641: #if 0 ! 2642: if ((msg = newblk = copyb (mp)) != NULL) ! 2643: while ((mp = mp->b_cont) != NULL) ! 2644: if ((newblk = (newblk->b_cont = copyb (mp))) == NULL) { ! 2645: /* ! 2646: * If a given block in the message cannot be ! 2647: * copied, undo all the work done so far. ! 2648: */ ! 2649: ! 2650: freemsg (msg); ! 2651: return NULL; ! 2652: } ! 2653: #endif ! 2654: ! 2655: return msg; ! 2656: } ! 2657: ! 2658: ! 2659: /* ! 2660: *-STATUS: ! 2661: * DDI/DKI ! 2662: * ! 2663: *-NAME: ! 2664: * datamsg Test whether a message is a data message. ! 2665: * ! 2666: *-SYNOPSIS: ! 2667: * #include <sys/types.h> ! 2668: * #include <sys/stream.h> ! 2669: * #include <sys/ddi.h> ! 2670: * ! 2671: * int datamsg (uchar_t type); ! 2672: * ! 2673: *-ARGUMENTS: ! 2674: * type The type of message to be tested. The "db_type" field ! 2675: * of the "datab" structure contains the message type. ! 2676: * This field may be accessed through the message block ! 2677: * using "mp->b_datap->db_type". ! 2678: * ! 2679: *-DESCRIPTION: ! 2680: * The datamsg () function tests the type of message to determine if it ! 2681: * is a data message type (M_DATA, M_DELAY, M_PROTO or M_PCPROTO). ! 2682: * ! 2683: *-RETURN VALUE: ! 2684: * datamsg () returns 1 if the message is a data message and 0 if the ! 2685: * message is any other type. ! 2686: * ! 2687: *-LEVEL: ! 2688: * Base or interrupt. ! 2689: * ! 2690: *-NOTES: ! 2691: * Does not sleep. ! 2692: * ! 2693: * Driver-defined basic locks, read/write locks, and sleep locks may be ! 2694: * held across calls to this function. ! 2695: * ! 2696: *-SEE ALSO: ! 2697: * allocb (), datab, msgb, messages ! 2698: */ ! 2699: ! 2700: #if __USE_PROTO__ ! 2701: int (datamsg) (uchar_t type) ! 2702: #else ! 2703: int ! 2704: datamsg __ARGS ((type)) ! 2705: uchar_t type; ! 2706: #endif ! 2707: { ! 2708: return datamsg (type); /* appeal to the macro version */ ! 2709: } ! 2710: ! 2711: ! 2712: /* ! 2713: *-STATUS: ! 2714: * DDI/DKI ! 2715: * ! 2716: *-NAME: ! 2717: * dupb Duplicate a message block. ! 2718: * ! 2719: *-SYNOPSIS: ! 2720: * #include <sys/stream.h> ! 2721: * ! 2722: * mblk_t * dupb (mblk_t * bp); ! 2723: * ! 2724: *-ARGUMENTS: ! 2725: * bp Pointer to the message block to be duplicated. ! 2726: * ! 2727: *-DESCRIPTION: ! 2728: * dupb () creates a new message block structure to reference the message ! 2729: * block pointed to by "bp". Unlike copyb (), dupb () does not copy the ! 2730: * information in the data block, but creates a new structure to point to ! 2731: * it. ! 2732: * ! 2733: *-RETURN VALUE: ! 2734: * If successful, dupb () returns a pointer to the new message block. ! 2735: * Otherwise, it returns a NULL pointer. ! 2736: * ! 2737: *-LEVEL: ! 2738: * Base or interrupt. ! 2739: * ! 2740: *-NOTES: ! 2741: * Does not sleep. ! 2742: * ! 2743: * Driver-defined basic locks, read/write locks, and sleep locks may be ! 2744: * held across calls to this function. ! 2745: * ! 2746: *-SEE ALSO: ! 2747: * copyb (), dupmsg (), datab, msgb ! 2748: */ ! 2749: ! 2750: #if __USE_PROTO__ ! 2751: mblk_t * (dupb) (mblk_t * bp) ! 2752: #else ! 2753: mblk_t * ! 2754: dupb __ARGS ((bp)) ! 2755: mblk_t * bp; ! 2756: #endif ! 2757: { ! 2758: mblk_t * newblk; ! 2759: ! 2760: ASSERT (bp != NULL); ! 2761: ! 2762: if ((newblk = STRMEM_ALLOC (sizeof (mblk_t), BPRI_HI, ! 2763: KM_NOSLEEP)) != NULL) { ! 2764: /* ! 2765: * Note that we do not initialize the "b_prev" and "b_next" ! 2766: * members, and that the "b_cont" member is NULL rather than ! 2767: * a copy of the original. ! 2768: */ ! 2769: ! 2770: newblk->b_cont = NULL; ! 2771: newblk->b_datap = bp->b_datap; ! 2772: newblk->b_rptr = bp->b_rptr; ! 2773: newblk->b_wptr = bp->b_wptr; ! 2774: ++ newblk->b_datap->db_ref; ! 2775: } ! 2776: ! 2777: return newblk; ! 2778: } ! 2779: ! 2780: ! 2781: /* ! 2782: *-STATUS: ! 2783: * DDI/DKI ! 2784: * ! 2785: *-NAME: ! 2786: * dupmsg Duplicate a message. ! 2787: * ! 2788: *-SYNOPSIS: ! 2789: * #include <sys/stream.h> ! 2790: * ! 2791: * mblk_t * dupmsg (mblk_t * mp); ! 2792: * ! 2793: *-ARGUMENTS: ! 2794: * mp Pointer to the message to be duplicated. ! 2795: * ! 2796: *-DESCRIPTION: ! 2797: * dupmsg () forms a new message by duplicating the message blocks in the ! 2798: * message pointed to by "mp" and linking them via their "b_cont" ! 2799: * pointers. ! 2800: * ! 2801: *-RETURN VALUE: ! 2802: * If successful, dupmsg () returns a pointer to the new message. ! 2803: * Otherwise it returns a NULL pointer. ! 2804: * ! 2805: *-LEVEL: ! 2806: * Base or interrupt. ! 2807: * ! 2808: *-NOTES: ! 2809: * Does not sleep. ! 2810: * ! 2811: * Driver-defined basic locks, read/write locks, and sleep locks may be ! 2812: * held across calls to this function. ! 2813: * ! 2814: *-SEE ALSO: ! 2815: * copyb (), copymsg (), dupb (), datab, msgb ! 2816: */ ! 2817: ! 2818: #if __USE_PROTO__ ! 2819: mblk_t * (dupmsg) (mblk_t * mp) ! 2820: #else ! 2821: mblk_t * ! 2822: dupmsg __ARGS ((mp)) ! 2823: mblk_t * mp; ! 2824: #endif ! 2825: { ! 2826: mblk_t * msg; ! 2827: mblk_t * newblk; ! 2828: ! 2829: ASSERT (mp != NULL); ! 2830: ! 2831: if ((msg = newblk = dupb (mp)) != NULL) ! 2832: while ((mp = mp->b_cont) != NULL) ! 2833: if ((newblk = (newblk->b_cont = dupb (mp))) == NULL) { ! 2834: /* ! 2835: * Discard the work we have done so far. ! 2836: */ ! 2837: ! 2838: freemsg (msg); ! 2839: return NULL; ! 2840: } ! 2841: ! 2842: return msg; ! 2843: } ! 2844: ! 2845: ! 2846: /* ! 2847: *-STATUS: ! 2848: * DDI/DKI ! 2849: * ! 2850: *-NAME: ! 2851: * enableok Enable a queue to be serviced. ! 2852: * ! 2853: *-SYNOPSIS: ! 2854: * #include <sys/stream.h> ! 2855: * #include <sys/ddi.h> ! 2856: * ! 2857: * void enableok (queue_t * q); ! 2858: * ! 2859: *-ARGUMENTS: ! 2860: * q Pointer to the queue. ! 2861: * ! 2862: *-DESCRIPTION: ! 2863: * The enableok () function allows the service routine of the queue ! 2864: * pointed to by "q" to be rescheduled for service. It cancels the effect ! 2865: * of a previous use of the noenable () function on "q". ! 2866: * ! 2867: *-RETURN VALUE: ! 2868: * None. ! 2869: * ! 2870: *-LEVEL: ! 2871: * Base or interrupt. ! 2872: * ! 2873: *-NOTES: ! 2874: * Does not sleep. ! 2875: * ! 2876: * The caller cannot have the stream frozen [see freezestr ()] when ! 2877: * calling this function. ! 2878: * ! 2879: * Driver-defined basic locks, read/write locks, and sleep locks may be ! 2880: * held across calls to this function. ! 2881: * ! 2882: *-SEE ALSO: ! 2883: * noenable (), qenable (), queue ! 2884: */ ! 2885: ! 2886: #if __USE_PROTO__ ! 2887: void (enableok) (queue_t * q) ! 2888: #else ! 2889: void ! 2890: enableok __ARGS ((q)) ! 2891: queue_t * q; ! 2892: #endif ! 2893: { ! 2894: pl_t prev_pl; ! 2895: ! 2896: prev_pl = QFREEZE_TRACE (q, "enableok"); ! 2897: ! 2898: q->q_flag &= ~ QNOENB; ! 2899: ! 2900: QUNFREEZE_TRACE (q, prev_pl); ! 2901: } ! 2902: ! 2903: ! 2904: /* ! 2905: *-STATUS: ! 2906: * DDI/DKI ! 2907: * ! 2908: *-NAME: ! 2909: * esballoc Allocate a message block using an externally supplied ! 2910: * buffer. ! 2911: * ! 2912: *-SYNOPSIS: ! 2913: * #include <sys/stream.h> ! 2914: * ! 2915: * mblk_t * esballoc (uchar_t * base, int size, int pri, ! 2916: * frtn_t * fr_rtnp); ! 2917: * ! 2918: *-ARGUMENTS: ! 2919: * base Address of driver-supplied data buffer. ! 2920: * ! 2921: * size Number of bytes in data buffer. ! 2922: * ! 2923: * pri Priority of allocation request (used to allocate the ! 2924: * message and data blocks). Valid values are BPRI_LO, ! 2925: * BPRI_MED, and BPRI_HI. ! 2926: * ! 2927: * fr_rtnp Pointer to the free-routine data structure. ! 2928: * ! 2929: *-DESCRIPTION: ! 2930: * esballoc () creates a STREAMS message and attaches a driver-supplied ! 2931: * data buffer in place of a STREAMS data buffer. It allocates a message ! 2932: * and data block header only. The driver-supplied data buffer, pointed ! 2933: * to by "base", is used as the data buffer for the message. ! 2934: * ! 2935: * When freeb () is called to free the message, on the last reference to ! 2936: * the message the driver's free-routine specified by the "free_func" ! 2937: * field in the "free_rtn" structure is called with one argument ! 2938: * (specified by the "free_arg" field) to free the data buffer. ! 2939: * ! 2940: * Instead of requiring a specific number of arguments, the "free_arg" ! 2941: * field is defined as type "char *". This way, the driver can pass a ! 2942: * pointer to a structure if more than one argument is needed. ! 2943: * ! 2944: * When the "free_func" function runs, interrupts from all STREAMS ! 2945: * devices will be blocked. It has no user context and may not call any ! 2946: * routine that sleeps. The function may not access any dynamically ! 2947: * allocated data structures that might no longer exist when it runs. ! 2948: * ! 2949: *-RETURN VALUE: ! 2950: * On success, a pointer to the newly allocated message block is ! 2951: * returned. On failure, a NULL pointer is returned. ! 2952: * ! 2953: *-LEVEL: ! 2954: * Base or interrupt. ! 2955: * ! 2956: *-NOTES: ! 2957: * Does not sleep. ! 2958: * ! 2959: * Driver-defined basic locks, read/write locks, and sleep locks may be ! 2960: * held across calls to this function. ! 2961: * ! 2962: *-SEE ALSO: ! 2963: * allocb (), freeb (), free_rtn ! 2964: */ ! 2965: ! 2966: #if __USE_PROTO__ ! 2967: mblk_t * (esballoc) (uchar_t * base, int size, int pri, frtn_t * fr_rtnp) ! 2968: #else ! 2969: mblk_t * ! 2970: esballoc __ARGS ((base, size, pri, fr_rtnp)) ! 2971: uchar_t * base; ! 2972: int size; ! 2973: int pri; ! 2974: frtn_t * fr_rtnp; ! 2975: #endif ! 2976: { ! 2977: mblk_t * mblkp; ! 2978: ! 2979: ASSERT (base != NULL); ! 2980: ASSERT (size >= 0); ! 2981: ASSERT (pri == BPRI_LO || pri == BPRI_HI || pri == BPRI_LO); ! 2982: ASSERT (ATOMIC_FETCH_UCHAR (str_mem->sm_init) && ! 2983: str_mem->sm_msg_lock != NULL); ! 2984: ! 2985: /* ! 2986: * Is it permissible for a driver to specify a NULL fr_rtnp? ! 2987: * ! 2988: * I think that it seems entirely logical, but neither the DDI/DKI ! 2989: * nor the STREAMS Programmer's Guide say anything about this. ! 2990: */ ! 2991: ! 2992: if ((mblkp = STRMEM_ALLOC (MSGB_SIZE (0), pri, KM_NOSLEEP)) != NULL) { ! 2993: /* ! 2994: * Note that we don't bother setting up the "b_prev" and ! 2995: * "b_next" members of the message block. ! 2996: */ ! 2997: ! 2998: mblkp->b_cont = NULL; ! 2999: mblkp->b_datap = MB_TO_DB (mblkp); ! 3000: mblkp->b_rptr = base; ! 3001: mblkp->b_wptr = base; ! 3002: ! 3003: /* ! 3004: * We specially flag this message block as part of ! 3005: * a triple. While there are other ways we could test ! 3006: * this, for now we permit the possibility that a ! 3007: * client might change the attachments of data blocks ! 3008: * and message blocks perversely. ! 3009: */ ! 3010: ! 3011: mblkp->b_flag = MSGTRIPLE; ! 3012: mblkp->b_band = 0; ! 3013: ! 3014: mblkp->b_datap->db_base = base; ! 3015: mblkp->b_datap->db_lim = base + size; ! 3016: mblkp->b_datap->db_type = M_DATA; ! 3017: mblkp->b_datap->db_ref = 1; ! 3018: ! 3019: mblkp->b_datap->db_frtnp = fr_rtnp; ! 3020: } ! 3021: ! 3022: return mblkp; ! 3023: } ! 3024: ! 3025: ! 3026: /* ! 3027: *-STATUS: ! 3028: * DDI/DKI ! 3029: * ! 3030: *-NAME: ! 3031: * esbbcall Call a function when an externally-supplied buffer ! 3032: * can be allocated. ! 3033: * ! 3034: *-SYNOPSIS: ! 3035: * #include <sys/types.h> ! 3036: * #include <sys/stream.h> ! 3037: * ! 3038: * toid_t esbbcall (int pri, int (* func) (), long arg); ! 3039: * ! 3040: *-ARGUMENTS: ! 3041: * pri Priority of the esballoc () allocation request ! 3042: * (BPRI_LO, BPRI_MED or BPRI_HI). ! 3043: * ! 3044: * func Function to be called when a buffer becomes available. ! 3045: * ! 3046: * arg Argument to the function to be called when a buffer ! 3047: * becomes available. ! 3048: * ! 3049: *-DESCRIPTION: ! 3050: * esbbcall (), like bufcall (), serves as a timeout call of ! 3051: * indeterminate duration. If esballoc () is unable to allocate a message ! 3052: * block header and a data block header to go with the externally ! 3053: * supplied data buffer, esbbcall () can be used to schedule the routine ! 3054: * "func", to be called with the argument "arg" when memory becomes ! 3055: * available. ! 3056: * ! 3057: * When "func" runs, all interrupts from STREAMS devices will be blocked ! 3058: * on the processor on which it is running. "func" will have no user ! 3059: * context and may not call any function that sleeps. ! 3060: * ! 3061: *-RETURN VALUE: ! 3062: * If successful, esbbcall () returns a non-zero value that identifies ! 3063: * the scheduling request. This non-zero identifier may be passed to ! 3064: * unbufcall () to cancel the request. If any failure occurs, esbbcall () ! 3065: * returns 0. ! 3066: * ! 3067: *-LEVEL: ! 3068: * Base or interrupt. ! 3069: * ! 3070: *-NOTES: ! 3071: * Does not sleep. ! 3072: * ! 3073: * Driver-defined basic locks, read/write locks, and sleep locks may be ! 3074: * held across calls to this function. ! 3075: * ! 3076: * Even when "func" is called, esballoc () can still fail if another ! 3077: * module or driver had allocated the memory before "func" was able to ! 3078: * call esballoc (). ! 3079: * ! 3080: *-SEE ALSO: ! 3081: * allocb (), bufcall (), esballoc (), itimeout (), unbufcall () ! 3082: */ ! 3083: ! 3084: #if __USE_PROTO__ ! 3085: toid_t (esbbcall) (int pri, ...) ! 3086: #else ! 3087: toid_t ! 3088: esbbcall __ARGS ((pri)) ! 3089: int pri; ! 3090: #endif ! 3091: { ! 3092: se_funcptr_t func; ! 3093: long arg; ! 3094: va_list arglist; ! 3095: sevent_t * seventp; ! 3096: ! 3097: ! 3098: /* ! 3099: * Before we do anything, we fetch the two other arguments. We use ! 3100: * the variable-argument function convention to get around problems ! 3101: * with implicit conversions introduced by having a prototype for ! 3102: * this function visible. ! 3103: * ! 3104: * This is a generic problem with callbacks, since the shape of a ! 3105: * function type includes the shapes of the function arguments, and ! 3106: * because we want to pass some argument to the user-supplied function ! 3107: * without knowing its type (and hence, we must not cause any implicit ! 3108: * conversions on its value). ! 3109: */ ! 3110: ! 3111: va_start (arglist, pri); ! 3112: ! 3113: func = va_arg (arglist, se_funcptr_t); ! 3114: arg = va_arg (arglist, long); ! 3115: ! 3116: va_end (arglist); ! 3117: ! 3118: ! 3119: /* ! 3120: * It may be that NULL is defined in such a way that it is not ! 3121: * meaningful to compare it with a function pointer, so we just cast ! 3122: * a zero to get the right kind of effect. ! 3123: * ! 3124: * We add some extra assertions below to check that "long" is of ! 3125: * sufficient size to contain all likely parameter data items. For ! 3126: * C, "likely" means the fundamental types, which has to include ! 3127: * pointers to functions, pointers to void, and also pointers to ! 3128: * structures since under C++ there is currently no guarantee to match ! 3129: * the ISO C requirement that a pointer of type "void *" be able to ! 3130: * hold the value of any pointer type without loss of information. ! 3131: * [We don't consider member pointers here; they are pathological] ! 3132: */ ! 3133: ! 3134: ASSERT (sizeof (se_funcptr_t) <= sizeof (long) && ! 3135: sizeof (_VOID *) <= sizeof (long) && ! 3136: sizeof (selist_t *) <= sizeof (long)); ! 3137: ! 3138: ASSERT (func != (se_funcptr_t) 0); ! 3139: ASSERT (pri == BPRI_LO || pri == BPRI_HI || pri == BPRI_LO); ! 3140: ! 3141: ! 3142: /* ! 3143: * Here we *could* lock and test the available space in the STREAMS ! 3144: * message heap to see whether sufficient space to satisfy the ! 3145: * request has become available between the failed allocb () and ! 3146: * the bufcall () request. ! 3147: * ! 3148: * The question is whether the extra time that the heap is locked is ! 3149: * worth overcoming a delay for a freemsg () to trigger the bufcall () ! 3150: * later, especially given the fact that we'll have to unlock the ! 3151: * heap to call the user's callback (introducing the opportunity for ! 3152: * the newly-discovered space to vanish). ! 3153: * ! 3154: * All in all, once things get to the bufcall () stage there seems ! 3155: * little reason to keep pushing the system, so we don't bother. ! 3156: */ ! 3157: ! 3158: /* ! 3159: * First off, let's get ourselves an event cell. This is mutually ! 3160: * dependent with the ID generation policy; if ID codes are stored in ! 3161: * the event cells, we are free to allocate and discard from a general ! 3162: * memory pool; if ID codes are not stored, then they must reflect ! 3163: * some persistent attribute of the cell, which usually implies that ! 3164: * cells come from some nonshrinking managed pool. ! 3165: * ! 3166: * Of course, a generative ID code scheme requires extra locking in ! 3167: * the absence of atomic FETCH_AND_INCREMENT () operations. In this ! 3168: * implementation, we get around this by using the list-head locks ! 3169: * to guard the counter operations. [This has interesting implications ! 3170: * for the design of a generic list-manipulation facility.] ! 3171: */ ! 3172: ! 3173: #if _TOID_MEMBER ! 3174: if ((seventp = (sevent_t *) kmem_alloc (sizeof (sevent_t), ! 3175: KM_NOSLEEP)) == NULL) ! 3176: return 0; ! 3177: #else ! 3178: #error Need an allocator for event cells that matches the ID policy ! 3179: #endif ! 3180: ! 3181: seventp->se_arg = arg; ! 3182: seventp->se_func = func; ! 3183: seventp->se_size = MSGB_SIZE (0); ! 3184: ! 3185: return STORE_EVENT (seventp, pri); ! 3186: } ! 3187: ! 3188: ! 3189: /* ! 3190: *-STATUS: ! 3191: * DDI/DKI ! 3192: * ! 3193: *-NAME: ! 3194: * flushband Flush messages in a specified priority band. ! 3195: * ! 3196: *-SYNOPSIS: ! 3197: * #include <sys/types.h> ! 3198: * #include <sys/stream.h> ! 3199: * ! 3200: * void flushband (queue_t * q, uchar_t pri, int flag); ! 3201: * ! 3202: *-ARGUMENTS: ! 3203: * q Pointer to the queue. ! 3204: * ! 3205: * pri Priority band of messages to be flushed. ! 3206: * ! 3207: * flag Determines messages to flush. Valid "flag" values are: ! 3208: * ! 3209: * FLUSHDATA Flush only data messages (types ! 3210: * M_DATA, M_DELAY, M_PROTO, and ! 3211: * M_PCPROTO). ! 3212: * ! 3213: * FLUSHALL Flush all messages. ! 3214: * ! 3215: *-DESCRIPTION: ! 3216: * The flushband () function flushes messages associated with the ! 3217: * priority band specified by "pri". If "pri" is 0, only normal and high ! 3218: * priority messages are flushed. Otherwise, messages are flushed from ! 3219: * the band "pri" according to the value of "flag". ! 3220: * ! 3221: *-RETURN VALUE: ! 3222: * None. ! 3223: * ! 3224: *-LEVEL: ! 3225: * Base or interrupt. ! 3226: * ! 3227: *-NOTES: ! 3228: * Does not sleep. ! 3229: * ! 3230: * The caller cannot have the stream frozen [see freezestr ()] when ! 3231: * calling this function. ! 3232: * ! 3233: * Driver-defined basic locks, read/write locks, and sleep locks may be ! 3234: * held across calls to this function. ! 3235: * ! 3236: *-SEE ALSO: ! 3237: * put (), flushq (), queue ! 3238: */ ! 3239: ! 3240: #if __USE_PROTO__ ! 3241: void (flushband) (queue_t * q, uchar_t pri, int flag) ! 3242: #else ! 3243: void ! 3244: flushband __ARGS ((q, pri, flag)) ! 3245: queue_t * q; ! 3246: uchar_t pri; ! 3247: int flag; ! 3248: #endif ! 3249: { ! 3250: pl_t prev_pl; ! 3251: qband_t * qbandp; ! 3252: mblk_t * mp; ! 3253: mblk_t * next; ! 3254: ulong_t flushsize; ! 3255: ! 3256: ASSERT (flag == FLUSHDATA || flag == FLUSHALL); ! 3257: ! 3258: if (pri == 0) { ! 3259: /* ! 3260: * Since the priority-band flush algorithm is necessarily ! 3261: * different from the regular one (due to flow control ! 3262: * handling), we'll just forward this on to the regular ! 3263: * version. ! 3264: */ ! 3265: ! 3266: flushq (q, flag); ! 3267: return; ! 3268: } ! 3269: ! 3270: prev_pl = QFREEZE_TRACE (q, "flushband"); ! 3271: ! 3272: if ((qbandp = QUEUE_BAND (q, pri)) != NULL && ! 3273: (mp = qbandp->qb_first) != NULL) { ! 3274: ! 3275: flushsize = 0; ! 3276: ! 3277: do { ! 3278: /* ! 3279: * Read the "b_next" member now in case we unlink this message ! 3280: * from the queue. ! 3281: */ ! 3282: ! 3283: next = mp->b_next; ! 3284: ! 3285: ASSERT (mp->b_band == pri); ! 3286: ! 3287: if (flag == FLUSHALL || datamsg (mp->b_datap->db_type)) { ! 3288: ! 3289: if (mp->b_prev == NULL) ! 3290: q->q_first = next; ! 3291: else ! 3292: mp->b_prev->b_next = next; ! 3293: ! 3294: if (next == NULL) ! 3295: q->q_last = mp->b_prev; ! 3296: else ! 3297: next->b_prev = mp->b_prev; ! 3298: ! 3299: QBAND_DEQUEUE (qbandp, mp); ! 3300: ! 3301: ! 3302: /* ! 3303: * Free the message, accumulating the total ! 3304: * size of the data referred to by the ! 3305: * message. ! 3306: */ ! 3307: ! 3308: flushsize += MSG_SIZE (mp); ! 3309: freemsg (mp); ! 3310: } ! 3311: } while ((mp = next) != qbandp->qb_last); ! 3312: ! 3313: ! 3314: /* ! 3315: * Here we update the flow control parameters for the band ! 3316: * now that we have accumulated all the necessary changes. ! 3317: */ ! 3318: ! 3319: QBAND_REDUCE (q, qbandp, flushsize); ! 3320: } ! 3321: ! 3322: ! 3323: /* ! 3324: * Since we are in a path with QBAND_REDUCE (), check for QBACK before ! 3325: * unfreezing the stream. ! 3326: */ ! 3327: ! 3328: { ! 3329: unsigned long back; ! 3330: ! 3331: if ((back = q->q_flag & QBACK) != 0) ! 3332: q->q_flag &= ~ QBACK; ! 3333: ! 3334: QUNFREEZE_TRACE (q, prev_pl); ! 3335: ! 3336: if (back) ! 3337: QUEUE_BACKENAB (q); ! 3338: } ! 3339: } ! 3340: ! 3341: ! 3342: /* ! 3343: *-STATUS: ! 3344: * DDI/DKI ! 3345: * ! 3346: *-NAME: ! 3347: * flushq Flush messages on a queue. ! 3348: * ! 3349: *-SYNOPSIS: ! 3350: * #include <sys/stream.h> ! 3351: * ! 3352: * void flushq (queue_t * q, int flag); ! 3353: * ! 3354: *-ARGUMENTS: ! 3355: * q Pointer to the queue. ! 3356: * ! 3357: * flag Determines messages to flush. Valid "flag" values are: ! 3358: * ! 3359: * FLUSHDATA Flush only data messages (types ! 3360: * M_DATA, M_DELAY, M_PROTO, and ! 3361: * M_PCPROTO). ! 3362: * ! 3363: * FLUSHALL Flush all messages. ! 3364: * ! 3365: *-DESCRIPTION: ! 3366: * flushq () frees messages on a queue by calling freemsg () for each ! 3367: * message. If the queue's count falls below the low water mark and ! 3368: * someone wants to write to the queue, the nearest upstream or ! 3369: * downstream (as approriate) service procedure is enabled. ! 3370: * ! 3371: *-RETURN VALUE: ! 3372: * None. ! 3373: * ! 3374: *-LEVEL: ! 3375: * Base or interrupt. ! 3376: * ! 3377: *-NOTES: ! 3378: * Does not sleep. ! 3379: * ! 3380: * The caller cannot have the stream frozen [see freezestr ()] when ! 3381: * calling this function. ! 3382: * ! 3383: * Driver-defined basic locks, read/write locks, and sleep locks may be ! 3384: * held across calls to this function. ! 3385: * ! 3386: *-SEE ALSO: ! 3387: * put (), flushband (), freemsg (), putq (), queue ! 3388: */ ! 3389: ! 3390: #if __USE_PROTO__ ! 3391: void (flushq) (queue_t * q, int flag) ! 3392: #else ! 3393: void ! 3394: flushq __ARGS ((q, flag)) ! 3395: queue_t * q; ! 3396: int flag; ! 3397: #endif ! 3398: { ! 3399: pl_t prev_pl; ! 3400: mblk_t * mp; ! 3401: mblk_t * next; ! 3402: ulong_t flushsize; ! 3403: ! 3404: ASSERT (flag == FLUSHDATA || flag == FLUSHALL); ! 3405: ! 3406: flushsize = 0; ! 3407: ! 3408: prev_pl = QFREEZE_TRACE (q, "flushq"); ! 3409: ! 3410: /* ! 3411: * High-priority messages are flushed as well as low-priority messages ! 3412: * so we could presumably split this function into a two-part scan ! 3413: * since the high-priority messages are at the front of the message ! 3414: * list while the low-priority messages are at the end. ! 3415: * ! 3416: * However, this function is not called very often, and we expect ! 3417: * band usage to be rare. ! 3418: */ ! 3419: ! 3420: for (mp = q->q_first ; mp != NULL ; mp = next) { ! 3421: /* ! 3422: * Read the "b_next" member now in case we unlink this message ! 3423: * from the queue. ! 3424: */ ! 3425: ! 3426: next = mp->b_next; ! 3427: ! 3428: if (mp->b_band == 0 && ! 3429: (flag == FLUSHALL || datamsg (mp->b_datap->db_type))) { ! 3430: ! 3431: if (mp->b_prev == NULL) ! 3432: q->q_first = next; ! 3433: else ! 3434: mp->b_prev->b_next = next; ! 3435: ! 3436: if (next == NULL) ! 3437: q->q_last = mp->b_prev; ! 3438: else ! 3439: next->b_prev = mp->b_prev; ! 3440: ! 3441: /* ! 3442: * If the message is high-priority, then we skip the ! 3443: * accumulation of the size. ! 3444: */ ! 3445: ! 3446: if (IS_PRI_MSG (mp)) { ! 3447: freemsg (mp); ! 3448: continue; ! 3449: } ! 3450: ! 3451: /* ! 3452: * Free the message, accumulating the total size of ! 3453: * the data referred to by the message. ! 3454: */ ! 3455: ! 3456: flushsize += MSG_SIZE (mp); ! 3457: freemsg (mp); ! 3458: } ! 3459: } ! 3460: ! 3461: QUEUE_REDUCE (q, flushsize); ! 3462: ! 3463: ! 3464: /* ! 3465: * Since we are in a path with QUEUE_REDUCE (), check for QBACK before ! 3466: * unfreezing the stream. ! 3467: */ ! 3468: ! 3469: { ! 3470: unsigned long back; ! 3471: ! 3472: if ((back = q->q_flag & QBACK) != 0) ! 3473: q->q_flag &= ~ QBACK; ! 3474: ! 3475: QUNFREEZE_TRACE (q, prev_pl); ! 3476: ! 3477: if (back) ! 3478: QUEUE_BACKENAB (q); ! 3479: } ! 3480: } ! 3481: ! 3482: ! 3483: /* ! 3484: *-STATUS: ! 3485: * DDI/DKI ! 3486: * ! 3487: *-NAME: ! 3488: * freeb Free a message block. ! 3489: * ! 3490: *-SYNOPSIS: ! 3491: * #include <sys/stream.h> ! 3492: * ! 3493: * void freeb (mblk_t * bp); ! 3494: * ! 3495: *-ARGUMENTS: ! 3496: * bp Pointer to the message block to be deallocated. ! 3497: * ! 3498: *-DESCRIPTION: ! 3499: * freeb () deallocates a message block. If the reference count of the ! 3500: * "db_ref" member of the "datab" structure is greater than 1, freeb () ! 3501: * decrements the count and returns. Otherwise, if "db_ref" equals 1, it ! 3502: * deallocates the message block and the corresponding data block and the ! 3503: * corresponding data block and buffer. ! 3504: * ! 3505: * If the data buffer to be freed was allocated with esballoc (), the ! 3506: * driver is notified that the attached data buffer needs to be freed by ! 3507: * calling the free-routine [see free_rtn] associated with the data ! 3508: * buffer. Once this is accomplished, freeb () releases the STREAMS ! 3509: * resources associated with the buffer. ! 3510: * ! 3511: *-RETURN VALUE: ! 3512: * None. ! 3513: * ! 3514: *-LEVEL: ! 3515: * Base or interrupt. ! 3516: * ! 3517: *-NOTES: ! 3518: * Does not sleep. ! 3519: * ! 3520: * Driver-defined basic locks, read/write locks, and sleep locks may be ! 3521: * held across calls to this function. ! 3522: * ! 3523: *-SEE ALSO: ! 3524: * allocb (), dupb (), esballoc (), datab, free_rtn, msgb ! 3525: */ ! 3526: ! 3527: #if __USE_PROTO__ ! 3528: void (freeb) (mblk_t * bp) ! 3529: #else ! 3530: void ! 3531: freeb __ARGS ((bp)) ! 3532: mblk_t * bp; ! 3533: #endif ! 3534: { ! 3535: size_t size; ! 3536: pl_t prev_pl; ! 3537: dblk_t * datap; ! 3538: frtn_t * frtnp = NULL; ! 3539: ! 3540: ! 3541: ASSERT (bp != NULL && bp->b_datap != NULL); ! 3542: ASSERT (bp->b_datap->db_ref > 0); ! 3543: ! 3544: datap = bp->b_datap; ! 3545: ! 3546: /* ! 3547: * It is expected that almost all of the calls to freeb () will result ! 3548: * in some memory being returned to the free pool, so to save space ! 3549: * and ensure correctness we lock the heap now. ! 3550: * ! 3551: * This has the advantage of serializing some of the tests below for ! 3552: * dealing with which parts of a message triple are free. Since the ! 3553: * message and data parts of a triple could be being freed ! 3554: * simultaneously by different contexts, this will guarantee that the ! 3555: * data will be freed by exactly one of the contexts. ! 3556: * ! 3557: * Another note about memory management: if the message and other ! 3558: * heaps are not kept separate, then some extra work needs to be done ! 3559: * to wake up processes sleeping for memory and for calling the ! 3560: * scheduled buffer events. Essentially, the systems need to map to ! 3561: * some common code that correctly prioritizes access and runs at an ! 3562: * appropriate time (possibly when some processor is about to return ! 3563: * to user mode from the kernel, or is totally idle). ! 3564: */ ! 3565: ! 3566: prev_pl = LOCK (str_mem->sm_msg_lock, str_msg_pl); ! 3567: ! 3568: -- datap->db_ref; ! 3569: ! 3570: if (datap->db_ref > 0) { ! 3571: /* ! 3572: * Ok, we don't need to free the data block and buffer, but ! 3573: * we may still need to free the message block. This gets a ! 3574: * little convoluted since we might be deallocating only part ! 3575: * of a structure that was actually allocated as a whole by ! 3576: * allocb () or esballoc (). ! 3577: */ ! 3578: ! 3579: if ((bp->b_flag & MSGTRIPLE) == 0) { ! 3580: ! 3581: STRMEM_FREE (bp, sizeof (mblk_t)); ! 3582: goto free_done; ! 3583: } ! 3584: ! 3585: if ((datap = MB_TO_DB (bp))->db_ref > 0) { ! 3586: /* ! 3587: * The data block part of the triple is not free, ! 3588: * so we set a flag (tested when the data block is ! 3589: * freed). ! 3590: */ ! 3591: ! 3592: bp->b_flag |= MSGFREE; ! 3593: ! 3594: goto free_done; ! 3595: } ! 3596: ! 3597: /* ! 3598: * If the test above was false, it arranged for the message ! 3599: * block to be associated with its triple partner so that ! 3600: * we can proceed with the freeing process. ! 3601: */ ! 3602: ! 3603: } else if ((bp->b_flag & MSGTRIPLE) == 0) { ! 3604: /* ! 3605: * The message block isn't from the same triple as the data ! 3606: * block. We free the message block and then see whether the ! 3607: * message block from the triple with the data block is free. ! 3608: */ ! 3609: ! 3610: ! 3611: STRMEM_FREE (bp, sizeof (mblk_t)); ! 3612: ! 3613: bp = DB_TO_MB (datap); ! 3614: ! 3615: if ((bp->b_flag & MSGFREE) == 0) { ! 3616: /* ! 3617: * The data block part of the triple is free but the ! 3618: * message block isn't. The triple will be freed when ! 3619: * the message block is freed. ! 3620: */ ! 3621: ! 3622: goto free_done; ! 3623: } ! 3624: } ! 3625: ! 3626: ! 3627: /* ! 3628: * Now we deal with freeing the data portion of the message. First off ! 3629: * we check whether or not the data block holds a user-supplied buffer ! 3630: * or not. ! 3631: */ ! 3632: ! 3633: if (datap->db_base != DB_TO_DATA (datap)) { ! 3634: /* ! 3635: * Calling the user-supplied free function now would be a ! 3636: * really bad idea, since while all the conditions that are ! 3637: * guaranteed to true while the function is called are true, ! 3638: * we are still holding the lock on the heap. We record the ! 3639: * information we need and do the job later. ! 3640: */ ! 3641: ! 3642: ASSERT (datap->db_frtnp != NULL); ! 3643: ! 3644: frtnp = datap->db_frtnp; ! 3645: size = 0; ! 3646: ! 3647: } else { ! 3648: ASSERT (datap->db_frtnp == NULL); ! 3649: ! 3650: size = datap->db_lim - datap->db_base; ! 3651: } ! 3652: ! 3653: ! 3654: /* ! 3655: * At this point we know we have a message block and a data block to ! 3656: * free, plus "size" bytes of data buffer. ! 3657: */ ! 3658: ! 3659: STRMEM_FREE (bp, MSGB_SIZE (size)); ! 3660: ! 3661: free_done: ! 3662: UNLOCK (str_mem->sm_msg_lock, plstr); ! 3663: ! 3664: /* ! 3665: * Here we call any deferred user data buffer free function ! 3666: */ ! 3667: ! 3668: if (frtnp != NULL) ! 3669: (* frtnp->free_func) (frtnp->free_arg); ! 3670: ! 3671: (void) splx (prev_pl); ! 3672: } ! 3673: ! 3674: ! 3675: /* ! 3676: *-STATUS: ! 3677: * DDI/DKI ! 3678: * ! 3679: *-NAME: ! 3680: * freemsg Free a message. ! 3681: * ! 3682: *-SYNOPSIS: ! 3683: * #include <sys/stream.h> ! 3684: * ! 3685: * void freemsg (mblk_t * mp); ! 3686: * ! 3687: *-ARGUMENTS: ! 3688: * mp Pointer to the message to be freed. ! 3689: * ! 3690: *-DESCRIPTION: ! 3691: * freemsg () frees all message blocks, data blocks, and data buffers ! 3692: * associated with the message pointed to by "mp". freemsg () walks down ! 3693: * the "b_cont" list [see msgb], calling freeb () for every message block ! 3694: * in the message. ! 3695: * ! 3696: *-RETURN VALUE: ! 3697: * None. ! 3698: * ! 3699: *-LEVEL: ! 3700: * Base or interrupt. ! 3701: * ! 3702: *-NOTES: ! 3703: * Does not sleep. ! 3704: * ! 3705: * Driver-defined basic locks, read/write locks, and sleep locks may be ! 3706: * held across calls to this function. ! 3707: * ! 3708: *-SEE ALSO: ! 3709: * freeb (), msgb ! 3710: */ ! 3711: ! 3712: #if __USE_PROTO__ ! 3713: void (freemsg) (mblk_t * mp) ! 3714: #else ! 3715: void ! 3716: freemsg __ARGS ((mp)) ! 3717: mblk_t * mp; ! 3718: #endif ! 3719: { ! 3720: mblk_t * next; ! 3721: ! 3722: ASSERT (mp != NULL); ! 3723: ! 3724: do { ! 3725: next = mp->b_cont; ! 3726: freeb (mp); ! 3727: } while ((mp = next) != NULL); ! 3728: } ! 3729: ! 3730: ! 3731: /* ! 3732: *-STATUS: ! 3733: * DDI/DKI ! 3734: * ! 3735: *-NAME: ! 3736: * freezestr Freeze the state of a stream. ! 3737: * ! 3738: *-SYNOPSIS: ! 3739: * #include <sys/types.h> ! 3740: * #include <sys/stream.h> ! 3741: * ! 3742: * pl_t freezestr (queue_t * q); ! 3743: * ! 3744: *-ARGUMENTS: ! 3745: * q Pointer to a message queue. ! 3746: * ! 3747: *-DESCRIPTION: ! 3748: * freezestr () sets the interrupt priority to "plstr" (if the current ! 3749: * level is lower than "plstr" and the implementation requires that ! 3750: * interrupts be blocked while the stream is frozen) and freezes the ! 3751: * state of the stream containing the queue specified by "q". Freezing ! 3752: * the stream prevents any further entries into open, close, put or ! 3753: * service procedures on the stream and prevents any messages from being ! 3754: * taken on or taken off any queues in the stream (except by the caller ! 3755: * of freezestr ()). Freezing the stream does not automatically stop all ! 3756: * functions that are running within the stream; functions will continue ! 3757: * to run until they attempt to perform some operation which changes the ! 3758: * state of the stream, at while point they will be forced to wait for ! 3759: * the stream to be unfrozen by a call to unfreezestr (). ! 3760: * ! 3761: * Drivers and modules must freeze the stream while they manipulate its ! 3762: * queues directly. This includes searching the queues and for the ! 3763: * duration of any calls to insq (), rmvq (), strqset (), and strqget (). ! 3764: * ! 3765: *-RETURN VALUE: ! 3766: * freezestr () returns the previous interrupt priority level which is ! 3767: * typically used in a subsequent call to unfreezestr (). ! 3768: * ! 3769: *-LEVEL: ! 3770: * Base or interrupt. ! 3771: * ! 3772: *-NOTES: ! 3773: * Does not sleep. ! 3774: * ! 3775: * Calling freezestr () to freeze a stream that is already frozen by the ! 3776: * caller will result in deadlock. ! 3777: * ! 3778: * Driver-defined basic locks, read/write locks, and sleep locks may be ! 3779: * held across calls to this function. ! 3780: * ! 3781: * freezestr () should be used sparingly as it is rarely necessary to ! 3782: * freeze a stream (most modules do not need to manipulate their queues ! 3783: * directly) and freezing a stream can have a significant negative impact ! 3784: * on performance. ! 3785: * ! 3786: *-SEE ALSO: ! 3787: * unfreezestr () ! 3788: */ ! 3789: ! 3790: #if __USE_PROTO__ ! 3791: pl_t (freezestr) (queue_t * q) ! 3792: #else ! 3793: pl_t ! 3794: freezestr __ARGS ((q)) ! 3795: queue_t * q; ! 3796: #endif ! 3797: { ! 3798: return QFREEZE_TRACE (q, "freezestr"); ! 3799: } ! 3800: ! 3801: ! 3802: /* ! 3803: *-STATUS: ! 3804: * DDI/DKI ! 3805: * ! 3806: *-NAME: ! 3807: * getq Get the next message from a queue. ! 3808: * ! 3809: *-SYNOPSIS: ! 3810: * #include <sys/stream.h> ! 3811: * ! 3812: * mblk_t * getq (queue_t * q); ! 3813: * ! 3814: *-ARGUMENTS: ! 3815: * q Pointer to the queue from which the message is to be ! 3816: * retrieved. ! 3817: * ! 3818: *-DESCRIPTION: ! 3819: * getq () is used by service routines to retrieve queue messages. It ! 3820: * gets the next available message from the top of the queue pointed to ! 3821: * by "q". getq () handles flow control, restarting I/O that was blocked ! 3822: * as needed. ! 3823: * ! 3824: *-RETURN VALUE: ! 3825: * If there is a message to retrieve, getq () returns a pointer to it. If ! 3826: * no message is queued, getq () returns a NULL pointer. ! 3827: * ! 3828: *-LEVEL: ! 3829: * Base or interrupt. ! 3830: * ! 3831: *-NOTES: ! 3832: * Does not sleep. ! 3833: * ! 3834: * The caller cannot have the stream frozen [see freezestr ()] when ! 3835: * calling this function. ! 3836: * ! 3837: * Driver-defined basic locks, read/write locks, and sleep locks may be ! 3838: * held across calls to this function. ! 3839: * ! 3840: *-SEE ALSO: ! 3841: * bcanput (), canput (), putbq (), putq (), qenable (), rmvq () ! 3842: */ ! 3843: ! 3844: #if __USE_PROTO__ ! 3845: mblk_t * (getq) (queue_t * q) ! 3846: #else ! 3847: mblk_t * ! 3848: getq __ARGS ((q)) ! 3849: queue_t * q; ! 3850: #endif ! 3851: { ! 3852: pl_t prev_pl; ! 3853: mblk_t * mp; ! 3854: ! 3855: prev_pl = QFREEZE_TRACE (q, "getq"); ! 3856: ! 3857: if ((mp = q->q_first) != NULL) { ! 3858: ulong_t msgsize; ! 3859: ! 3860: /* ! 3861: * There is a message. Dequeue it and adjust the flow-control ! 3862: * parameters appropriately depending on whether the message ! 3863: * is a priority message and also on the band of the message. ! 3864: */ ! 3865: ! 3866: if ((q->q_first = mp->b_next) == NULL) { ! 3867: ! 3868: q->q_last = NULL; ! 3869: QUEUE_DRAINED (q); ! 3870: } else ! 3871: mp->b_next->b_prev = NULL; ! 3872: ! 3873: /* ! 3874: * Record the message band for the putq () enabling mechanism. ! 3875: */ ! 3876: ! 3877: q->q_lastband = mp->b_band; ! 3878: ! 3879: ! 3880: /* ! 3881: * If the message is a priority-band message, we have to ! 3882: * finish up the dequeueing operation by adjusting the ! 3883: * "qb_first" and "qb_last" members of the "qband" structure. ! 3884: * ! 3885: * We do this below with the band flow-control management. ! 3886: */ ! 3887: ! 3888: ASSERT (mp->b_datap != NULL); ! 3889: ! 3890: if (! IS_PRI_MSG (mp)) { ! 3891: ! 3892: msgsize = MSG_SIZE (mp); ! 3893: ! 3894: if (mp->b_band > 0) { ! 3895: qband_t * qbandp = QUEUE_BAND (q, mp->b_band); ! 3896: ! 3897: ASSERT (qbandp->qb_first == mp); ! 3898: ! 3899: QBAND_DEQUEUE (qbandp, mp); ! 3900: ! 3901: QBAND_REDUCE (q, qbandp, msgsize); ! 3902: } else ! 3903: QUEUE_REDUCE (q, msgsize); ! 3904: } ! 3905: } else { ! 3906: /* ! 3907: * The queue is empty; we set a flag to indicate to putq () ! 3908: * that it should enable the queue when a message is put. ! 3909: */ ! 3910: ! 3911: q->q_flag |= QWANTR; ! 3912: } ! 3913: ! 3914: ! 3915: /* ! 3916: * Since we are in a path with QUEUE_REDUCE (), check for QBACK before ! 3917: * unfreezing the stream. ! 3918: */ ! 3919: ! 3920: { ! 3921: unsigned long back; ! 3922: ! 3923: if ((back = q->q_flag & QBACK) != 0) ! 3924: q->q_flag &= ~ QBACK; ! 3925: ! 3926: QUNFREEZE_TRACE (q, prev_pl); ! 3927: ! 3928: if (back) ! 3929: QUEUE_BACKENAB (q); ! 3930: } ! 3931: ! 3932: return mp; ! 3933: } ! 3934: ! 3935: ! 3936: /* ! 3937: *-STATUS: ! 3938: * DDI/DKI ! 3939: * ! 3940: *-NAME: ! 3941: * insq Insert a message into a queue. ! 3942: * ! 3943: *-SYNOPSIS: ! 3944: * #include <sys/stream.h> ! 3945: * ! 3946: * int insq (queue_t * q, mblk_t * emp, mblk_t * nmp); ! 3947: * ! 3948: *-ARGUMENTS: ! 3949: * q Pointer to the queue containing message "emp". ! 3950: * ! 3951: * emp Pointer to the existing message before which the new ! 3952: * message is to be inserted. ! 3953: * ! 3954: * nmp Pointer to the new message to be inserted. ! 3955: * ! 3956: *-DESCRIPTION: ! 3957: * insq () inserts a message into a queue. The message to be inserted, ! 3958: * "nmp", is placed in the queue pointer to by "q", immediately before ! 3959: * the message "emp". If "emp" is NULL, the new message is placed at the ! 3960: * end of the queue. All flow control parameters are updated. The service ! 3961: * procedure is scheduled to run unless disabled by a previous call to ! 3962: * noenable (). ! 3963: * ! 3964: * Messages are ordered in the queue based on their priority. If an ! 3965: * attempt is made to insert a message out of order in the queue, then ! 3966: * "nmp" is not enqueued. ! 3967: * ! 3968: *-RETURN VALUE: ! 3969: * If "nmp" was successfully enqueued, insq () returns 1. Otherwise, ! 3970: * insq () returns 0. ! 3971: * ! 3972: *-LEVEL: ! 3973: * Base or interrupt. ! 3974: * ! 3975: *-NOTES: ! 3976: * Does not sleep. ! 3977: * ! 3978: * The caller must have the stream frozen [see freezestr ()] when calling ! 3979: * this function. ! 3980: * ! 3981: * Driver-defined basic locks, read/write locks, and sleep locks may be ! 3982: * held across calls to this function. ! 3983: * ! 3984: * The insertion can fail if there is not enough memory to allocate the ! 3985: * accounting data structures used with messages whose priority bands are ! 3986: * greater than zero. ! 3987: * ! 3988: * If "emp" is non-NULL, it must point to a message in the queue pointed ! 3989: * to by "q", or a system panic could result. ! 3990: * ! 3991: *-SEE ALSO: ! 3992: * freezestr (), getq (), putbq (), putq (), rmvq (), unfreezestr () ! 3993: */ ! 3994: ! 3995: #if __USE_PROTO__ ! 3996: int (insq) (queue_t * q, mblk_t * emp, mblk_t * nmp) ! 3997: #else ! 3998: int ! 3999: insq __ARGS ((q, emp, nmp)) ! 4000: queue_t * q; ! 4001: mblk_t * emp; ! 4002: mblk_t * nmp; ! 4003: #endif ! 4004: { ! 4005: qband_t * qbandp; ! 4006: ! 4007: ASSERT (nmp != NULL); ! 4008: QFROZEN_TRACE (q, "insq"); ! 4009: ! 4010: ! 4011: /* ! 4012: * The code for high-priority messages has been factored out into a ! 4013: * completely separate path since the legality tests are incompatible ! 4014: * with the regular sequence, and in addition because such messages do ! 4015: * not have their size accumulated in the flow control-parameters at ! 4016: * all, at all. The execution path here is torturous enough without ! 4017: * folding all the checks into a sequence with a common exit. ! 4018: */ ! 4019: ! 4020: if (IS_PRI_MSG (nmp)) { ! 4021: /* ! 4022: * Since putq () is defined as forcing b_band to 0 for high- ! 4023: * priority messages, we do the same. ! 4024: */ ! 4025: ! 4026: nmp->b_band = 0; ! 4027: ! 4028: if ((nmp->b_next = emp) == NULL) { ! 4029: ! 4030: if ((nmp->b_prev = q->q_last) == NULL) { ! 4031: ! 4032: q->q_first = nmp; ! 4033: } else { ! 4034: ! 4035: if (! IS_PRI_MSG (nmp->b_prev)) ! 4036: return 0; ! 4037: ! 4038: nmp->b_prev->b_next = nmp; ! 4039: } ! 4040: ! 4041: q->q_last = nmp; ! 4042: } else { ! 4043: ! 4044: if ((nmp->b_prev = emp->b_prev) == NULL) { ! 4045: ! 4046: q->q_first = nmp; ! 4047: } else { ! 4048: ! 4049: if (! IS_PRI_MSG (nmp->b_prev)) ! 4050: return 0; ! 4051: ! 4052: nmp->b_prev->b_next = nmp; ! 4053: } ! 4054: ! 4055: emp->b_prev = nmp; ! 4056: ! 4057: } ! 4058: ! 4059: ! 4060: /* ! 4061: * A high-priority message causes a queue to be scheduled, ! 4062: * even if a noenable () has been done. If we cannot schedule ! 4063: * the queue for some reason (it is disabled with qprocsoff () ! 4064: * or has no service routine) that is not our concern. ! 4065: */ ! 4066: ! 4067: (void) QUEUE_TRYSCHED (q); ! 4068: return 1; ! 4069: } ! 4070: ! 4071: ! 4072: qbandp = NULL; /* paranoia */ ! 4073: ! 4074: if (nmp->b_band > 0 && ! 4075: (qbandp = QUEUE_BAND (q, nmp->b_band)) == NULL && ! 4076: (qbandp = QBAND_ALLOC (q, nmp->b_band)) == NULL) { ! 4077: /* ! 4078: * Return failure if we were unable to allocate a necessary ! 4079: * extra band structure. ! 4080: */ ! 4081: ! 4082: return 0; ! 4083: } ! 4084: ! 4085: ! 4086: if ((nmp->b_next = emp) == NULL) { ! 4087: ! 4088: if ((nmp->b_prev = q->q_last) == NULL) { ! 4089: ! 4090: q->q_first = nmp; ! 4091: } else { ! 4092: ! 4093: if (nmp->b_prev->b_band < nmp->b_band) ! 4094: return 0; ! 4095: ! 4096: nmp->b_prev->b_next = nmp; ! 4097: ! 4098: } ! 4099: ! 4100: q->q_last = nmp; ! 4101: ! 4102: } else { ! 4103: /* ! 4104: * The check against "emp" isn't sufficient, since this ! 4105: * request could be attempting to insert a message in the ! 4106: * middle of a sequence of messages with a lower band. ! 4107: */ ! 4108: ! 4109: if (emp->b_band > nmp->b_band || IS_PRI_MSG (emp)) ! 4110: return 0; ! 4111: ! 4112: if ((nmp->b_prev = emp->b_prev) == NULL) { ! 4113: ! 4114: q->q_first = nmp; ! 4115: } else { ! 4116: ! 4117: if (nmp->b_prev->b_band < nmp->b_band) ! 4118: return 0; ! 4119: ! 4120: emp->b_prev->b_next = nmp; ! 4121: } ! 4122: ! 4123: emp->b_prev = nmp; ! 4124: } ! 4125: ! 4126: ! 4127: /* ! 4128: * Now update the flow control information and priority-band pointers ! 4129: * after possibly scheduling the queue. ! 4130: */ ! 4131: ! 4132: if (QUEUE_CHECK_SCHED (q, nmp, qbandp)) { ! 4133: /* ! 4134: * Keep the band pointers updated. ! 4135: */ ! 4136: ! 4137: if (qbandp->qb_first == emp) ! 4138: qbandp->qb_first = nmp; ! 4139: ! 4140: if (qbandp->qb_last == NULL || (qbandp->qb_last->b_next == emp)) ! 4141: qbandp->qb_last = nmp; ! 4142: } ! 4143: ! 4144: return 1; /* success ! */ ! 4145: } ! 4146: ! 4147: ! 4148: /* ! 4149: *-STATUS: ! 4150: * DDI/DKI ! 4151: * ! 4152: *-NAME: ! 4153: * linkb Concatenate two message blocks. ! 4154: * ! 4155: *-SYNOPSIS: ! 4156: * #include <sys/stream.h> ! 4157: * ! 4158: * void linkb (mblk_t * mp1, mblk_t * mp2); ! 4159: * ! 4160: *-ARGUMENTS: ! 4161: * mp1 Pointer to the message block to which "mp2" is to be ! 4162: * added. ! 4163: * ! 4164: * mp2 Pointer to the message to be added. ! 4165: * ! 4166: *-DESCRIPTION: ! 4167: * linkb () appends the message "mp2" to the tail of message "mp1". The ! 4168: * continuation pointer "b_cont" of the last message block in the first ! 4169: * message is set to point to the second message. ! 4170: * ! 4171: *-RETURN VALUE: ! 4172: * None. ! 4173: * ! 4174: *-LEVEL: ! 4175: * Base or interrupt. ! 4176: * ! 4177: *-NOTES: ! 4178: * Does not sleep. ! 4179: * ! 4180: * Driver-defined basic locks, read/write locks, and sleep locks may be ! 4181: * held across calls to this function. ! 4182: * ! 4183: *-SEE ALSO: ! 4184: * unlinkb (), msgb ! 4185: */ ! 4186: ! 4187: #if __USE_PROTO__ ! 4188: void (linkb) (mblk_t * mp1, mblk_t * mp2) ! 4189: #else ! 4190: void ! 4191: linkb __ARGS ((mp1, mp2)) ! 4192: mblk_t * mp1; ! 4193: mblk_t * mp2; ! 4194: #endif ! 4195: { ! 4196: ASSERT (mp1 != NULL && mp2 != NULL); ! 4197: ! 4198: while (mp1->b_cont != NULL) ! 4199: mp1 = mp1->b_cont; ! 4200: ! 4201: mp1->b_cont = mp2; ! 4202: } ! 4203: ! 4204: ! 4205: /* ! 4206: *-STATUS: ! 4207: * DDI/DKI ! 4208: * ! 4209: *-NAME: ! 4210: * msgdsize Return number of bytes of data in a message. ! 4211: * ! 4212: *-SYNOPSIS: ! 4213: * #include <sys/stream.h> ! 4214: * ! 4215: * int msgdsize (mblk_t * mp); ! 4216: * ! 4217: *-ARGUMENTS: ! 4218: * mp Pointer to the message to be evaluated. ! 4219: * ! 4220: *-DESCRIPTION: ! 4221: * msgdsize () counts the number of bytes of data in the message pointed ! 4222: * to by "mp". Only bytes included in message blocks of type "M_DATA" are ! 4223: * included in the count. ! 4224: * ! 4225: *-RETURN VALUE: ! 4226: * The number of bytes of data in the message. ! 4227: * ! 4228: *-LEVEL: ! 4229: * Base or interrupt. ! 4230: * ! 4231: *-NOTES: ! 4232: * Does not sleep. ! 4233: * ! 4234: * Driver-defined basic locks, read/write locks, and sleep locks may be ! 4235: * held across calls to this function. ! 4236: * ! 4237: *-SEE ALSO: ! 4238: * msgb ! 4239: */ ! 4240: ! 4241: #if __USE_PROTO__ ! 4242: int (msgdsize) (mblk_t * mp) ! 4243: #else ! 4244: int ! 4245: msgdsize __ARGS ((mp)) ! 4246: mblk_t * mp; ! 4247: #endif ! 4248: { ! 4249: int sum = 0; ! 4250: ! 4251: ASSERT (mp != NULL); ! 4252: ! 4253: do ! 4254: if (mp->b_datap->db_type == M_DATA) ! 4255: sum += mp->b_wptr - mp->b_rptr; ! 4256: while ((mp = mp->b_cont) != NULL); ! 4257: ! 4258: return sum; ! 4259: } ! 4260: ! 4261: ! 4262: /* ! 4263: *-STATUS: ! 4264: * DDI/DKI ! 4265: * ! 4266: *-NAME: ! 4267: * msgpullup Concatenate bytes in a message, ! 4268: * ! 4269: *-SYNOPSIS: ! 4270: * #include <sys/stream.h> ! 4271: * ! 4272: * mblk_t * msgpullup (mblk_t * mp, int len); ! 4273: * ! 4274: *-ARGUMENTS: ! 4275: * mp Pointer to the message whose blocks are to be ! 4276: * concatenated. ! 4277: * ! 4278: * len Number of bytes to concatenate, ! 4279: * ! 4280: *-DESCRIPTION: ! 4281: * msgpullup () concatenates and aligns the first "len" data bytes of the ! 4282: * message pointed to by "mp", copying the data into a new message. The ! 4283: * original message is unaltered. If "len" equals -1, all data are ! 4284: * concatenated. If "len" bytes of the same message type cannot be found, ! 4285: * msgpullup () fails and returns NULL. ! 4286: * ! 4287: *-RETURN VALUE: ! 4288: * On success, a pointer to the new message is returned; on failure a ! 4289: * NULL pointer is returned. ! 4290: * ! 4291: *-LEVEL: ! 4292: * Base or interrupt. ! 4293: * ! 4294: *-NOTES: ! 4295: * Does not sleep. ! 4296: * ! 4297: * Driver-defined basic locks, read/write locks, and sleep locks may be ! 4298: * held across calls to this function. ! 4299: * ! 4300: *-SEE ALSO: ! 4301: * allocb (), msgb ! 4302: */ ! 4303: ! 4304: #if __USE_PROTO__ ! 4305: mblk_t * (msgpullup) (mblk_t * mp, int len) ! 4306: #else ! 4307: mblk_t * ! 4308: msgpullup __ARGS ((mp, len)) ! 4309: mblk_t * mp; ! 4310: int len; ! 4311: #endif ! 4312: { ! 4313: size_t size; ! 4314: uchar_t msgtype; ! 4315: mblk_t * scan; ! 4316: ! 4317: ASSERT (mp != NULL); ! 4318: ASSERT (mp->b_datap != NULL); ! 4319: ! 4320: /* ! 4321: * Something that is now particularly well-specified about this new ! 4322: * routine (intended to replace pullupmsg () from SVR3.2 STREAMS and ! 4323: * the SVR4 DDI/DKI) is what happens to the message data in the ! 4324: * original message *after* the "len" bytes to be pulled up? ! 4325: * ! 4326: * Basically, without a usage example (which I haven't been able to ! 4327: * find in the new SVR4 MP STREAMS programmer's guide) I can't tell ! 4328: * whether the remaining data in the message should be duplicated for ! 4329: * the new message or not. In order to make this routine a closer ! 4330: * functional replacement for pullupmsg (), I'm tempted to say "yes", ! 4331: * but it could be that the new message is a single standalone message ! 4332: * block. Hence, I'm putting in a switch to select between the two ! 4333: * interpretations I consider most likely. ! 4334: * ! 4335: * This is particularly important for "msgpullup (mp, 0)", which I'd ! 4336: * like to make an error. ! 4337: */ ! 4338: ! 4339: #define MSGPULLUP_DUPMSG ! 4340: ! 4341: if (len == 0) { ! 4342: #ifdef MSGPULLUP_DUPMSG ! 4343: return dupmsg (mp); ! 4344: #else ! 4345: return MSG_ALLOC (0, BPRI_MED, KM_NOSLEEP); ! 4346: #endif ! 4347: } ! 4348: ! 4349: /* ! 4350: * Begin by calculating the amount of data of the same message type ! 4351: * that is present in the message. ! 4352: */ ! 4353: ! 4354: msgtype = mp->b_datap->db_type; ! 4355: size = 0; ! 4356: scan = mp; ! 4357: ! 4358: do ! 4359: size += scan->b_wptr - scan->b_rptr; ! 4360: while ((scan = scan->b_cont) != NULL && ! 4361: scan->b_datap->db_type == msgtype); ! 4362: ! 4363: if (len == -1) ! 4364: len = size; ! 4365: else if (len > size) ! 4366: return NULL; ! 4367: ! 4368: /* ! 4369: * Note that it may be reasonable to interpret the definition of this ! 4370: * function as implying that data can be shared between the old and ! 4371: * new message blocks if the old data block does not need to be ! 4372: * altered (ie, if the previous data was aligned and contiguous up to ! 4373: * the length "len"). ! 4374: */ ! 4375: ! 4376: /* #define MSGPULLUP_SHARE */ ! 4377: ! 4378: #ifdef MSGPULLUP_SHARE ! 4379: if ((mp->b_wptr - mp->b_rptr) >= len && ! 4380: ((ulong_t) mp->b_rptr) & (sizeof (int) - 1)) == 0) ! 4381: return dupmsg (mp); ! 4382: #endif /* defined (MSGPULLUP_SHARE) */ ! 4383: ! 4384: ! 4385: if ((scan = MSGB_ALLOC (len, BPRI_MED, KM_NOSLEEP)) == NULL) ! 4386: return NULL; ! 4387: ! 4388: /* ! 4389: * There are some message attributes other than data that need to be ! 4390: * copied from the source to the new message. ! 4391: */ ! 4392: ! 4393: scan->b_band = mp->b_band; ! 4394: scan->b_flag |= mp->b_flag & ~ MSGMASK_SYSTEM; ! 4395: ! 4396: ! 4397: /* ! 4398: * Now transfer the data from the old space to the new space. ! 4399: * ! 4400: * More unspecified behaviour deals with how zero-length blocks are ! 4401: * to be treated. The following loop is coded specifically to skip ! 4402: * over zero-length message blocks in the source that follow the ! 4403: * "len" copied bytes of data. ! 4404: */ ! 4405: ! 4406: #define MSGPULLUP_DUPMSG ! 4407: ! 4408: while (mp != NULL) { ! 4409: size_t blklen = mp->b_wptr - mp->b_rptr; ! 4410: ! 4411: if (blklen > 0) ! 4412: memcpy (scan->b_wptr, mp->b_rptr, blklen); ! 4413: ! 4414: scan->b_wptr += blklen; ! 4415: len -= blklen; ! 4416: ! 4417: ! 4418: if (blklen > len) { ! 4419: /* ! 4420: * Copy a partial block. Since this must also be the ! 4421: * last message block in the source message whose ! 4422: * data are being moved to the new message, here is a ! 4423: * good place to decide on the dispensation of the ! 4424: * remaining data. ! 4425: */ ! 4426: ! 4427: #ifdef MSGPULLUP_DUPMSG ! 4428: if ((scan->b_cont = dupmsg (mp)) == NULL) { ! 4429: /* ! 4430: * The remaining data could not be duplicated, ! 4431: * so we have to fail the call overall. ! 4432: */ ! 4433: ! 4434: freeb (scan); ! 4435: return NULL; ! 4436: } ! 4437: #endif ! 4438: break; ! 4439: } ! 4440: ! 4441: mp = mp->b_cont; ! 4442: } ! 4443: ! 4444: ! 4445: return scan; ! 4446: } ! 4447: ! 4448: ! 4449: /* ! 4450: *-STATUS: ! 4451: * DDI/DKI ! 4452: * ! 4453: *-NAME: ! 4454: * noenable Prevent a queue from being scheduled. ! 4455: * ! 4456: *-SYNOPSIS: ! 4457: * #include <sys/stream.h> ! 4458: * ! 4459: * void noenable (queue_t * q); ! 4460: * ! 4461: *-ARGUMENTS: ! 4462: * q Pointer to the queue. ! 4463: * ! 4464: *-DESCRIPTION: ! 4465: * The noenable () function prevents the service routine of the queue ! 4466: * pointed to by "q" from being scheduled for service by insq (), ! 4467: * putbq (), or putq () when enqueuing a message that is not a high ! 4468: * priority message. This restriction can be lifted with the enableok () ! 4469: * function. ! 4470: * ! 4471: * noenable () does not prevent the queue's service routine from being ! 4472: * scheduled when a high priority message is enqueued, or by an explicit ! 4473: * call to qenable (). ! 4474: * ! 4475: *-RETURN VALUE: ! 4476: * None. ! 4477: * ! 4478: *-LEVEL: ! 4479: * Base or interrupt. ! 4480: * ! 4481: *-NOTES: ! 4482: * Does not sleep. ! 4483: * ! 4484: * The caller cannot have the stream frozen [see freezestr ()] when ! 4485: * calling this function. ! 4486: * ! 4487: * Driver-defined basic locks, read/write locks, and sleep locks may be ! 4488: * held across calls to this function. ! 4489: * ! 4490: *-SEE ALSO: ! 4491: * enableok (), insq (), putbq (), putq (), qenable (), queue ! 4492: */ ! 4493: ! 4494: #if __USE_PROTO__ ! 4495: void (noenable) (queue_t * q) ! 4496: #else ! 4497: void ! 4498: noenable __ARGS ((q)) ! 4499: queue_t * q; ! 4500: #endif ! 4501: { ! 4502: pl_t prev_pl; ! 4503: ! 4504: prev_pl = QFREEZE_TRACE (q, "noenable"); ! 4505: ! 4506: q->q_flag |= QNOENB; ! 4507: ! 4508: QUNFREEZE_TRACE (q, prev_pl); ! 4509: } ! 4510: ! 4511: ! 4512: /* ! 4513: *-STATUS: ! 4514: * DDI/DKI ! 4515: * ! 4516: *-NAME: ! 4517: * OTHERQ Get pointer to queue's partner queue. ! 4518: * ! 4519: *-SYNOPSIS: ! 4520: * #include <sys/stream.h> ! 4521: * ! 4522: * queue_t * OTHERQ (queue_t * q); ! 4523: * ! 4524: *-ARGUMENTS: ! 4525: * q Pointer to the queue. ! 4526: * ! 4527: *-DESCRIPTION: ! 4528: * The OTHERQ () function returns a pointer to the other of the two ! 4529: * queue structures that make up an instance of a STREAMS module or ! 4530: * driver. If "q" points to the read queue the write queue will be ! 4531: * returned, and vice versa. ! 4532: * ! 4533: *-RETURN VALUE: ! 4534: * OTHERQ () returns a pointer to the queue's partner. ! 4535: * ! 4536: *-LEVEL: ! 4537: * Base or interrupt. ! 4538: * ! 4539: *-NOTES: ! 4540: * Does not sleep. ! 4541: * ! 4542: * Driver-defined basic locks, read/write locks, and sleep locks may be ! 4543: * held across calls to this function. ! 4544: * ! 4545: *-SEE ALSO: ! 4546: * RD (), WR () ! 4547: */ ! 4548: ! 4549: #if __USE_PROTO__ ! 4550: queue_t * (OTHERQ) (queue_t * q) ! 4551: #else ! 4552: queue_t * ! 4553: OTHERQ __ARGS ((q)) ! 4554: queue_t * q; ! 4555: #endif ! 4556: { ! 4557: return OTHERQ (q); ! 4558: } ! 4559: ! 4560: ! 4561: /* ! 4562: *-STATUS: ! 4563: * DDI/DKI ! 4564: * ! 4565: *-NAME: ! 4566: * pcmsg Test whether a message is a priority control message. ! 4567: * ! 4568: *-SYNOPSIS: ! 4569: * #include <sys/types.h> ! 4570: * #include <sys/stream.h> ! 4571: * #include <sys/ddi.h> ! 4572: * ! 4573: * int pcmsg (uchar_t type); ! 4574: * ! 4575: *-ARGUMENTS: ! 4576: * type The type of message to be tested. ! 4577: * ! 4578: *-DESCRIPTION: ! 4579: * The pcmsg () function tests the type of message to determine if it is ! 4580: * a priority control message (also known as a high priority message). ! 4581: * The "db_type" field of the "datab" structure contains the message ! 4582: * type. This field may be accessed through the message block using ! 4583: * "mp->b_datap->db_type". ! 4584: * ! 4585: *-RETURN VALUE: ! 4586: * pcmsg () returns 1 if the message is a priority control message and ! 4587: * 0 if the message is any other type. ! 4588: * ! 4589: *-LEVEL: ! 4590: * Base or interrupt. ! 4591: * ! 4592: *-NOTES: ! 4593: * Does not sleep. ! 4594: * ! 4595: * Driver-defined basic locks, read/write locks, and sleep locks may be ! 4596: * held across calls to this function. ! 4597: * ! 4598: *-SEE ALSO: ! 4599: * allocb (), datab, msgb, messages ! 4600: */ ! 4601: ! 4602: #if __USE_PROTO__ ! 4603: int (pcmsg) (uchar_t type) ! 4604: #else ! 4605: int ! 4606: pcmsg __ARGS ((type)) ! 4607: uchar_t type; ! 4608: #endif ! 4609: { ! 4610: return pcmsg (type); ! 4611: } ! 4612: ! 4613: ! 4614: /* ! 4615: *-STATUS: ! 4616: * Compatibility (pre-MP DDI/DKI) ! 4617: * ! 4618: *-NAME: ! 4619: * pullupmsg Concatenate bytes in a message. ! 4620: * ! 4621: *-SYNOPSIS: ! 4622: * #include <sys/stream.h> ! 4623: * ! 4624: * int pullupmsg (mblk_t * mp, int len); ! 4625: * ! 4626: *-ARGUMENTS: ! 4627: * mp Pointer to the message whose blocks are to be ! 4628: * concatenated. ! 4629: * ! 4630: * len Number of bytes to concatenate. ! 4631: * ! 4632: *-DESCRIPTION: ! 4633: * pullupmsg () tries to combine multiple data blocks into a single ! 4634: * block. pullupmsg () concatenates and aligns the first "len" data bytes ! 4635: * of the message pointed to by "mp". If "len" equals -1, all data is ! 4636: * concatenated. If "len" bytes of the same message type cannot be found, ! 4637: * pullupmsg () fails and returns 0. ! 4638: * ! 4639: *-RETURN VALUE: ! 4640: * On success, 1 is returned; on failure, 0 is returned. ! 4641: * ! 4642: *-LEVEL: ! 4643: * Base or interrupt. ! 4644: * ! 4645: *-NOTES: ! 4646: * Does not sleep. ! 4647: * ! 4648: * Driver-defined basic locks, read/write locks, and sleep locks may be ! 4649: * held across calls to this function. ! 4650: * ! 4651: * This function is provided for compatibility with versions of the ! 4652: * DDI/DKI prior to the System V, Release 4 Multiprocessor edition. Calls ! 4653: * to this function should be replaced by calls to the msgpullup () ! 4654: * function instead. ! 4655: * ! 4656: *-SEE ALSO: ! 4657: * allocb (), msgpullup () ! 4658: */ ! 4659: ! 4660: #if __USE_PROTO__ ! 4661: int (pullupmsg) (mblk_t * mp, int len) ! 4662: #else ! 4663: int ! 4664: pullupmsg __ARGS ((mp, len)) ! 4665: mblk_t * mp; ! 4666: int len; ! 4667: #endif ! 4668: { ! 4669: mblk_t * newmsg; ! 4670: ! 4671: ASSERT (mp != NULL); ! 4672: ASSERT (mp->b_datap != NULL); ! 4673: ! 4674: /* ! 4675: * If the first block of the old message is sufficiently large to ! 4676: * encompass the pullup request, then we need do no work. It is not ! 4677: * clear whether the new msgpullup () function allows this simple ! 4678: * optimisation, so we test for this here to guarantee it. ! 4679: */ ! 4680: ! 4681: if (((mp->b_wptr - mp->b_rptr) > len || ! 4682: (len == -1 && mp->b_cont == NULL)) && ! 4683: ((ulong_t) mp->b_rptr & (sizeof (int) - 1)) == 0) { ! 4684: /* ! 4685: * Do nothing and return success. Note that the alignment test ! 4686: * above is specific to the i386 implementation. ! 4687: */ ! 4688: ! 4689: return 1; ! 4690: } ! 4691: ! 4692: ! 4693: /* ! 4694: * Now use the new msgpullup () function to perform the harder task ! 4695: * of concatenating the message, and then perform some subterfuge to ! 4696: * ensure that the new message replaces the old message's storage. ! 4697: * ! 4698: * This requires some delicate manipulations to avoid disrupting ! 4699: * the flags and whatnot that support the message-triple storage ! 4700: * system. ! 4701: */ ! 4702: ! 4703: if ((newmsg = msgpullup (mp, len)) == NULL) ! 4704: return 0; ! 4705: ! 4706: ! 4707: { ! 4708: dblk_t * temp = mp->b_datap; ! 4709: mp->b_datap = newmsg->b_datap; ! 4710: newmsg->b_datap = temp; ! 4711: } { ! 4712: mblk_t * temp = mp->b_cont; ! 4713: mp->b_cont = newmsg->b_cont; ! 4714: newmsg->b_cont = temp; ! 4715: } ! 4716: ! 4717: mp->b_rptr = newmsg->b_rptr; ! 4718: mp->b_wptr = newmsg->b_wptr; ! 4719: ! 4720: /* ! 4721: * Since we exchanged the "b_datap" and "b_cont" members of the ! 4722: * message blocks, freeing the "new" message pointer will free those ! 4723: * elements of the original message that have been made redundant by ! 4724: * the pull-up operation, leaving the original message block intact ! 4725: * but pointing to the rearranged data. ! 4726: */ ! 4727: ! 4728: freemsg (newmsg); ! 4729: return 1; ! 4730: } ! 4731: ! 4732: ! 4733: /* ! 4734: *-STATUS: ! 4735: * DDI/DKI ! 4736: * ! 4737: *-NAME: ! 4738: * put Call a put procedure. ! 4739: * ! 4740: *-SYNOPSIS: ! 4741: * #include <sys/stream.h> ! 4742: * ! 4743: * void put (queue_t * q, mblk_t * mp); ! 4744: * ! 4745: *-ARGUMENTS: ! 4746: * q Pointer to a message queue. ! 4747: * ! 4748: * mp Pointer to the message block being passed. ! 4749: * ! 4750: *-DESCRIPTION: ! 4751: * put () calls the "put" procedure for the queue specified by "q", ! 4752: * passing it the arguments "q" and "mp". It is typically used by a ! 4753: * driver or module to call its own "put" procedure so that the proper ! 4754: * accounting is done in the stream. ! 4755: * ! 4756: *-RETURN VALUE: ! 4757: * None. ! 4758: * ! 4759: *-LEVEL: ! 4760: * Base or interrupt. ! 4761: * ! 4762: *-NOTES: ! 4763: * Does not sleep. ! 4764: * ! 4765: * The caller cannot have the stream frozen [see freezestr ()] when ! 4766: * calling this function. ! 4767: * ! 4768: * Driver-defined basic locks, read/write locks, and sleep locks may be ! 4769: * held across calls to this function. ! 4770: * ! 4771: * DDI/DKI conforming drivers and modules are no longer permitted to call ! 4772: * "put" procedures directly, but must call through the appropriate ! 4773: * STREAMS utility function - for example, put (), putnext (), putctl (), ! 4774: * putnextctl (), or qreply (). "put (q, mp)" is provided as a DDI/DKI- ! 4775: * conforming equivalent to a direct call to a "put" procedure, which is ! 4776: * no longer allowed. ! 4777: * ! 4778: *-SEE ALSO: ! 4779: * putctl (), putctl1 (), putnext (), putnextctl (), putnextctl1 (), ! 4780: * qreply () ! 4781: */ ! 4782: ! 4783: #if __USE_PROTO__ ! 4784: void (put) (queue_t * q, mblk_t * mp) ! 4785: #else ! 4786: void ! 4787: put __ARGS ((q, mp)) ! 4788: queue_t * q; ! 4789: mblk_t * mp; ! 4790: #endif ! 4791: { ! 4792: pl_t prev_pl; ! 4793: ! 4794: ASSERT (mp != NULL); ! 4795: ASSERT (mp->b_datap != NULL); ! 4796: ! 4797: /* ! 4798: * If a message is put to a queue that either has no put procedure at ! 4799: * all, or has been disabled with qprocsoff (), then we discard the ! 4800: * message and return without doing anything. ! 4801: */ ! 4802: ! 4803: prev_pl = QFREEZE_TRACE (q, "put"); ! 4804: ! 4805: if ((q->q_active == 0 && (q->q_flag & QPROCSOFF) != 0) || ! 4806: q->q_qinfo->qi_putp == NULL) ! 4807: cmn_err (CE_WARN, "put () to disabled queue/NULL putp"); ! 4808: else ! 4809: QUEUE_PUT (q, mp, prev_pl); ! 4810: ! 4811: QUNFREEZE_TRACE (q, prev_pl); ! 4812: } ! 4813: ! 4814: ! 4815: /* ! 4816: *-STATUS: ! 4817: * DDI/DKI ! 4818: * ! 4819: *-NAME: ! 4820: * putbq Place a message at the head of a queue. ! 4821: * ! 4822: *-SYNOPSIS: ! 4823: * #include <sys/stream.h> ! 4824: * ! 4825: * int putbq (queue_t * q, mblk_t * mp); ! 4826: * ! 4827: *-ARGUMENTS: ! 4828: * q Pointer to the queue. ! 4829: * ! 4830: * mp Pointer to the message. ! 4831: * ! 4832: *-DESCRIPTION: ! 4833: * putbq () puts a message back at the head of the queue. If messages of ! 4834: * a higher priority are present on the queue, then "bp" is placed at the ! 4835: * head of its corresponding priority band. ! 4836: * ! 4837: * All flow control parameters are updated. The queue's service routine ! 4838: * is scheduled if it has not been disabled by a previous call to ! 4839: * noenable (). ! 4840: * ! 4841: * putbq () is usually called when bcanputnext () or canputnext () ! 4842: * determines that the message cannot be passed on to the next stream ! 4843: * component. ! 4844: * ! 4845: *-RETURN VALUE: ! 4846: * putbq () returns 1 on success and 0 on failure. ! 4847: * ! 4848: *-LEVEL: ! 4849: * Base or interrupt. ! 4850: * ! 4851: *-NOTES: ! 4852: * Does not sleep. ! 4853: * ! 4854: * The caller cannot have the stream frozen [see freezestr ()] when ! 4855: * calling this function. ! 4856: * ! 4857: * Driver-defined basic locks, read/write locks, and sleep locks may be ! 4858: * held across calls to this function. ! 4859: * ! 4860: * putbq () can fail if there is not enough memory to allocate the ! 4861: * accounting data structures used with messages whose priority bands are ! 4862: * greater than zero. ! 4863: * ! 4864: * High priority messages should never be put back on a queue from within ! 4865: * a service routine. ! 4866: * ! 4867: *-SEE ALSO: ! 4868: * bcanputnext (), canputnext (), getq (), insq (), putq (), rmvq (), ! 4869: * msgb, queue ! 4870: */ ! 4871: ! 4872: #if __USE_PROTO__ ! 4873: int (putbq) (queue_t * q, mblk_t * mp) ! 4874: #else ! 4875: int ! 4876: putbq __ARGS ((q, mp)) ! 4877: queue_t * q; ! 4878: mblk_t * mp; ! 4879: #endif ! 4880: { ! 4881: pl_t prev_pl; ! 4882: qband_t * qbandp; ! 4883: ! 4884: ASSERT (mp != NULL); ! 4885: ASSERT (mp->b_datap != NULL); ! 4886: ASSERT (! pcmsg (mp->b_datap->db_type)); ! 4887: ! 4888: prev_pl = QFREEZE_TRACE (q, "putbq"); ! 4889: ! 4890: /* ! 4891: * The code for high-priority messages has been factored out into a ! 4892: * completely separate path because such messages do not have their ! 4893: * size accumulated in the flow control-parameters at all, at all, and ! 4894: * because the location where such messages are to be queued is ! 4895: * determined in one step without search. ! 4896: */ ! 4897: ! 4898: if (IS_PRI_MSG (mp)) { ! 4899: /* ! 4900: * Since putq () is defined as forcing b_band to 0 for high- ! 4901: * priority messages, we do the same. ! 4902: */ ! 4903: ! 4904: if ((mp->b_next = q->q_first) == NULL) ! 4905: q->q_last = mp; ! 4906: else ! 4907: mp->b_next->b_prev = mp; ! 4908: ! 4909: mp->b_prev = NULL; ! 4910: mp->b_band = 0; ! 4911: q->q_first = mp; ! 4912: ! 4913: ! 4914: /* ! 4915: * A high-priority message causes a queue to be scheduled ! 4916: * even if a noenable () has been performed. For putbq (), ! 4917: * this is true whether or not the condition set by getq () ! 4918: * returning null is true or not, which is the reason for the ! 4919: * proscription against calling this routine for a high- ! 4920: * priority message within a service procedure. ! 4921: */ ! 4922: ! 4923: /* ! 4924: *!!! We need help from the STREAMS service-routine scheduler ! 4925: *!!! to build a testable assertion for detecting when we are ! 4926: *!!! called within the context of a service routine. ! 4927: */ ! 4928: ! 4929: (void) QUEUE_TRYSCHED (q); ! 4930: goto alldone; ! 4931: } ! 4932: ! 4933: ! 4934: qbandp = NULL; /* paranoia */ ! 4935: ! 4936: if (mp->b_band > 0 && ! 4937: (qbandp = QUEUE_BAND (q, mp->b_band)) == NULL && ! 4938: (qbandp = QBAND_ALLOC (q, mp->b_band)) == NULL) ! 4939: return 0; ! 4940: else if (QUEUE_CHECK_SCHED (q, mp, qbandp)) { ! 4941: /* ! 4942: * Deal with band pointer maintenance now. ! 4943: */ ! 4944: ! 4945: if ((mp->b_next = qbandp->qb_first) != NULL) { ! 4946: /* ! 4947: * We directly know where we want to put the message. ! 4948: */ ! 4949: ! 4950: if ((mp->b_prev = mp->b_next->b_prev) == NULL) ! 4951: q->q_first = mp; ! 4952: else ! 4953: mp->b_prev->b_next = mp; ! 4954: ! 4955: mp->b_next->b_prev = mp; ! 4956: ! 4957: qbandp->qb_first = mp; ! 4958: ! 4959: goto alldone; ! 4960: } ! 4961: ! 4962: ! 4963: /* ! 4964: * This is the only message in this band. We will need to ! 4965: * search for the correct position to queue this message. ! 4966: */ ! 4967: ! 4968: qbandp->qb_last = qbandp->qb_first = mp; ! 4969: } ! 4970: ! 4971: ! 4972: /* ! 4973: * Now use a brute-force search for the position. We could use the ! 4974: * band structures to speed this up, but we anticipate that there will ! 4975: * be few band or high-priority messages, so that a brute-force search ! 4976: * will be suitably short. ! 4977: */ ! 4978: ! 4979: QUEUE_PLACE_MSG (q, mp, mp->b_band); ! 4980: ! 4981: alldone: ! 4982: QUNFREEZE_TRACE (q, prev_pl); ! 4983: return 1; ! 4984: } ! 4985: ! 4986: ! 4987: /* ! 4988: *-STATUS: ! 4989: * DDI/DKI ! 4990: * ! 4991: *-NAME: ! 4992: * putctl Send a control message to a queue. ! 4993: * ! 4994: *-SYNOPSIS: ! 4995: * #include <sys/stream.h> ! 4996: * ! 4997: * int putctl (queue_t * q, int type); ! 4998: * ! 4999: *-ARGUMENTS: ! 5000: * q Pointer to the queue to which the message is to be ! 5001: * sent. ! 5002: * ! 5003: * type Message type (must be control). ! 5004: * ! 5005: *-DESCRIPTION: ! 5006: * putctl () tests the "type" argument to make sure a data type has not ! 5007: * been specified, and then attempts to allocate a message block. ! 5008: * putctl () fails if "type" is M_DATA, M_PROTO, or M_PCPROTO, or if a ! 5009: * message block cannot be allocated. If successful, putctl () calls the ! 5010: * "put" routine of the queue pointed to by "q", passing it the allocated ! 5011: * message. ! 5012: * ! 5013: *-RETURN VALUE: ! 5014: * On success, 1 is returned. Otherwise, if "type" is a data type, or if ! 5015: * a message block cannot be allocated, 0 is returned. ! 5016: * ! 5017: *-LEVEL: ! 5018: * Base or interrupt. ! 5019: * ! 5020: *-NOTES: ! 5021: * Does not sleep. ! 5022: * ! 5023: * The caller cannot have the stream frozen [see freezestr ()] when ! 5024: * calling this function. ! 5025: * ! 5026: * Driver-defined basic locks, read/write locks, and sleep locks may be ! 5027: * held across calls to this function. ! 5028: * ! 5029: * The "q" argument to putctl () and putnextctl () may not reference ! 5030: * "q_next" (eg, an argument of "q->q_next" is erroneous on a ! 5031: * multiprocessor and is disallowed by the DDI/DKI). ! 5032: * "putnextctl (q, type)" is provided as a multiprocessor-safe equivalent ! 5033: * to the common call "putctl (q->q_next, type)" which is no longer ! 5034: * allowed. ! 5035: * ! 5036: *-SEE ALSO: ! 5037: * put (), putctl1 (), putnextctl (), putnextctl1 () ! 5038: */ ! 5039: ! 5040: #if __USE_PROTO__ ! 5041: int (putctl) (queue_t * q, int type) ! 5042: #else ! 5043: int ! 5044: putctl __ARGS ((q, type)) ! 5045: queue_t * q; ! 5046: int type; ! 5047: #endif ! 5048: { ! 5049: mblk_t * ctlmsg; ! 5050: ! 5051: QUEUE_TRACE (q, "putctl"); ! 5052: ! 5053: /* ! 5054: * We cannot use datamsg () to test the type because datamsg () is ! 5055: * specified as testing for M_DATA in addition to M_DATA, M_PROTO, and ! 5056: * M_PCPROTO. ! 5057: */ ! 5058: ! 5059: if ((type & (M_PRI - 1)) <= M_PROTO || ! 5060: (ctlmsg = MSGB_ALLOC (0, BPRI_HI, KM_NOSLEEP)) == NULL) ! 5061: return 0; ! 5062: ! 5063: ctlmsg->b_datap->db_type = type; ! 5064: put (q, ctlmsg); ! 5065: ! 5066: return 1; ! 5067: } ! 5068: ! 5069: ! 5070: /* ! 5071: *-STATUS: ! 5072: * DDI/DKI ! 5073: * ! 5074: *-NAME: ! 5075: * putctl1 Send a control message with a one-byte parameter to a ! 5076: * queue. ! 5077: * ! 5078: *-SYNOPSIS: ! 5079: * #include <sys/stream.h> ! 5080: * ! 5081: * int putctl1 (queue_t * q, int type, int param); ! 5082: * ! 5083: *-ARGUMENTS: ! 5084: * q Pointer to the queue to which the message is to be ! 5085: * sent. ! 5086: * ! 5087: * type Message type (must be control). ! 5088: * ! 5089: * param One-byte parameter. ! 5090: * ! 5091: *-DESCRIPTION: ! 5092: * putctl1 (), like putctl (), tests the "type" argument to make sure a ! 5093: * data type has not been specified, and attempts to allocate a message ! 5094: * block. The "param" parameter can be used, for example, to specify the ! 5095: * signal number when an "M_PCSIG" message is being sent. putctl1 () ! 5096: * fails if "type" is M_DATA, M_PROTO, or M_PCPROTO, or if a message ! 5097: * block cannot be allocated. If successful, putctl1 () calls the "put" ! 5098: * routine of the queue pointed to by "q", passing it the allocated ! 5099: * message. ! 5100: * ! 5101: *-RETURN VALUE: ! 5102: * On success, 1 is returned. Otherwise, if "type" is a data type, or if ! 5103: * a message block cannot be allocated, 0 is returned. ! 5104: * ! 5105: *-LEVEL: ! 5106: * Base or interrupt. ! 5107: * ! 5108: *-NOTES: ! 5109: * Does not sleep. ! 5110: * ! 5111: * The caller cannot have the stream frozen [see freezestr ()] when ! 5112: * calling this function. ! 5113: * ! 5114: * Driver-defined basic locks, read/write locks, and sleep locks may be ! 5115: * held across calls to this function. ! 5116: * ! 5117: * The "q" argument to putctl1 () and putnextctl1 () may not reference ! 5118: * "q_next" (eg, an argument of "q->q_next" is erroneous on a ! 5119: * multiprocessor and is disallowed by the DDI/DKI). ! 5120: * "putnextctl1 (q, type)" is provided as a multiprocessor-safe ! 5121: * equivalent to the common call "putctl1 (q->q_next, type)" which is no ! 5122: * longer allowed. ! 5123: * ! 5124: *-SEE ALSO: ! 5125: * put (), putctl (), putnextctl (), putnextctl1 () ! 5126: */ ! 5127: ! 5128: #if __USE_PROTO__ ! 5129: int (putctl1) (queue_t * q, int type, int param) ! 5130: #else ! 5131: int ! 5132: putctl1 __ARGS ((q, type, param)) ! 5133: queue_t * q; ! 5134: int type; ! 5135: int param; ! 5136: #endif ! 5137: { ! 5138: mblk_t * ctlmsg; ! 5139: ! 5140: QUEUE_TRACE (q, "putctl1"); ! 5141: ! 5142: /* ! 5143: * We cannot use datamsg () to test the type because datamsg () is ! 5144: * specified as testing for M_DATA in addition to M_DATA, M_PROTO, and ! 5145: * M_PCPROTO. ! 5146: */ ! 5147: ! 5148: if ((type & (M_PRI - 1)) <= M_PROTO || ! 5149: (ctlmsg = MSGB_ALLOC (1, BPRI_HI, KM_NOSLEEP)) == NULL) ! 5150: return 0; ! 5151: ! 5152: ctlmsg->b_datap->db_type = type; ! 5153: * ctlmsg->b_wptr ++ = (unsigned char) param; ! 5154: ! 5155: put (q, ctlmsg); ! 5156: ! 5157: return 1; ! 5158: } ! 5159: ! 5160: ! 5161: /* ! 5162: *-STATUS: ! 5163: * DDI/DKI ! 5164: * ! 5165: *-NAME: ! 5166: * putnext Send a message to the next queue. ! 5167: * ! 5168: *-SYNOPSIS: ! 5169: * #include <sys/stream.h> ! 5170: * ! 5171: * int putnext (queue_t * q, mblk_t * mp); ! 5172: * ! 5173: *-ARGUMENTS: ! 5174: * q Pointer to the queue from which the message "mp" will ! 5175: * be sent. ! 5176: * ! 5177: * mp Pointer to the message to be passed. ! 5178: * ! 5179: *-DESCRIPTION: ! 5180: * The putnext () function is used to pass a message to the "put" routine ! 5181: * of the next queue ("q->q_next") in the stream. ! 5182: * ! 5183: *-RETURN VALUE: ! 5184: * Ignored. ! 5185: * ! 5186: *-LEVEL: ! 5187: * Base or interrupt. ! 5188: * ! 5189: *-NOTES: ! 5190: * Does not sleep. ! 5191: * ! 5192: * The caller cannot have the stream frozen [see freezestr ()] when ! 5193: * calling this function. ! 5194: * ! 5195: * Driver-defined basic locks, read/write locks, and sleep locks may be ! 5196: * held across calls to this function. ! 5197: * ! 5198: *-SEE ALSO: ! 5199: * putnextctl (), putnextctl1 () ! 5200: */ ! 5201: ! 5202: #if __USE_PROTO__ ! 5203: int (putnext) (queue_t * q, mblk_t * mp) ! 5204: #else ! 5205: int ! 5206: putnext __ARGS ((q, mp)) ! 5207: queue_t * q; ! 5208: mblk_t * mp; ! 5209: #endif ! 5210: { ! 5211: QUEUE_TRACE (q, "putnext"); ! 5212: ! 5213: QUEUE_PUTNEXT (q, mp); ! 5214: ! 5215: return 0; ! 5216: } ! 5217: ! 5218: ! 5219: /* ! 5220: *-STATUS: ! 5221: * DDI/DKI ! 5222: * ! 5223: *-NAME: ! 5224: * putnextctl Send a control message to a queue. ! 5225: * ! 5226: *-SYNOPSIS: ! 5227: * #include <sys/stream.h> ! 5228: * ! 5229: * int putnextctl (queue_t * q, int type); ! 5230: * ! 5231: *-ARGUMENTS: ! 5232: * q Pointer to the queue from which the message is to be ! 5233: * sent. ! 5234: * ! 5235: * type Message type (must be control type). ! 5236: * ! 5237: *-DESCRIPTION: ! 5238: * putnextctl () tests the "type" argument to make sure a data type has ! 5239: * been specified, and then attempts to allocate a message block. ! 5240: * putnextctl () fails if "type" is M_DATA, M_PROTO, or M_PCPROTO, or ! 5241: * if a message block cannot be allocated. If successful, putnextctl () ! 5242: * calls the "put" procedure of the queue pointed to by "q->q_next", ! 5243: * passing it the allocated message. ! 5244: * ! 5245: *-RETURN VALUE: ! 5246: * Upon successful completion, putnextctl () returns 1. If "type" is a ! 5247: * data type, or if a message block cannot be allocated, 0 is returned. ! 5248: * ! 5249: *-LEVEL: ! 5250: * Base or interrupt. ! 5251: * ! 5252: *-NOTES: ! 5253: * Does not sleep. ! 5254: * ! 5255: * The caller cannot have the stream frozen [see freezestr ()] when ! 5256: * calling this function. ! 5257: * ! 5258: * Driver-defined basic locks, read/write locks, and sleep locks may be ! 5259: * held across calls to this function. ! 5260: * ! 5261: * The "q" argument to putctl () and putnextctl () may not reference ! 5262: * "q_next" (eg, an argument of "q->q_next" is erroneous on a ! 5263: * multiprocessor and is disallowed by the DDI/DKI). ! 5264: * "putnextctl (q, type)" is provided as a multiprocessor-safe equivalent ! 5265: * to the common call "putctl (q->q_next, type)" which is no longer ! 5266: * allowed. ! 5267: * ! 5268: *-SEE ALSO: ! 5269: * put (), putctl (), putctl1 (), putnextctl1 () ! 5270: */ ! 5271: ! 5272: #if __USE_PROTO__ ! 5273: int (putnextctl) (queue_t * q, int type) ! 5274: #else ! 5275: int ! 5276: putnextctl __ARGS ((q, type)) ! 5277: queue_t * q; ! 5278: int type; ! 5279: #endif ! 5280: { ! 5281: mblk_t * ctlmsg; ! 5282: ! 5283: QUEUE_TRACE (q, "putnextctl"); ! 5284: ! 5285: /* ! 5286: * We cannot use datamsg () to test the type because datamsg () is ! 5287: * specified as testing for M_DATA in addition to M_DATA, M_PROTO, and ! 5288: * M_PCPROTO. ! 5289: */ ! 5290: ! 5291: if ((type & (M_PRI - 1)) <= M_PROTO || ! 5292: (ctlmsg = MSGB_ALLOC (0, BPRI_HI, KM_NOSLEEP)) == NULL) ! 5293: return 0; ! 5294: ! 5295: ctlmsg->b_datap->db_type = type; ! 5296: ! 5297: QUEUE_PUTNEXT (q, ctlmsg); ! 5298: ! 5299: return 1; ! 5300: } ! 5301: ! 5302: ! 5303: /* ! 5304: *-STATUS: ! 5305: * DDI/DKI ! 5306: * ! 5307: *-NAME: ! 5308: * putnextctl1 Send a control message with a one-byte parameter to a ! 5309: * queue. ! 5310: * ! 5311: *-SYNOPSIS: ! 5312: * #include <sys/stream.h> ! 5313: * ! 5314: * int putctl1 (queue_t * q, int type, int param); ! 5315: * ! 5316: *-ARGUMENTS: ! 5317: * q Pointer to the queue from which the message is to be ! 5318: * sent. ! 5319: * ! 5320: * type Message type (must be control). ! 5321: * ! 5322: * param One-byte parameter. ! 5323: * ! 5324: *-DESCRIPTION: ! 5325: * putnextctl1 () tests the "type" argument to make sure a data type has ! 5326: * not been specified, and attempts to allocate a message block. ! 5327: * putnext ctl1 () fails if "type" is M_DATA, M_PROTO, or M_PCPROTO, or ! 5328: * if a message block cannot be allocated. If successful, putctl1 () ! 5329: * calls the "put" routine of the queue pointed to by "q->q_next", ! 5330: * passing it the allocated message with the one byte parameter specified ! 5331: * by "param". ! 5332: * ! 5333: *-RETURN VALUE: ! 5334: * Upon successful completion, putnextctl1 () returns 1. If "type" is a ! 5335: & data type, or if a message block cannot be allocated, 0 is returned. ! 5336: * ! 5337: *-LEVEL: ! 5338: * Base or interrupt. ! 5339: * ! 5340: *-NOTES: ! 5341: * Does not sleep. ! 5342: * ! 5343: * The caller cannot have the stream frozen [see freezestr ()] when ! 5344: * calling this function. ! 5345: * ! 5346: * Driver-defined basic locks, read/write locks, and sleep locks may be ! 5347: * held across calls to this function. ! 5348: * ! 5349: * The "q" argument to putctl1 () and putnextctl1 () may not reference ! 5350: * "q_next" (eg, an argument of "q->q_next" is erroneous on a ! 5351: * multiprocessor and is disallowed by the DDI/DKI). ! 5352: * "putnextctl1 (q, type)" is provided as a multiprocessor-safe ! 5353: * equivalent to the common call "putctl1 (q->q_next, type)" which is no ! 5354: * longer allowed. ! 5355: * ! 5356: *-SEE ALSO: ! 5357: * put (), putctl (), putctl1 (), putnextctl () ! 5358: */ ! 5359: ! 5360: #if __USE_PROTO__ ! 5361: int (putnextctl1) (queue_t * q, int type, int param) ! 5362: #else ! 5363: int ! 5364: putnextctl1 __ARGS ((q, type, param)) ! 5365: queue_t * q; ! 5366: int type; ! 5367: int param; ! 5368: #endif ! 5369: { ! 5370: mblk_t * ctlmsg; ! 5371: ! 5372: QUEUE_TRACE (q, "putnextctl1"); ! 5373: ! 5374: /* ! 5375: * We cannot use datamsg () to test the type because datamsg () is ! 5376: * specified as testing for M_DATA in addition to M_DATA, M_PROTO, and ! 5377: * M_PCPROTO. ! 5378: */ ! 5379: ! 5380: if ((type & (M_PRI - 1)) <= M_PROTO || ! 5381: (ctlmsg = MSGB_ALLOC (1, BPRI_HI, KM_NOSLEEP)) == NULL) ! 5382: return 0; ! 5383: ! 5384: ctlmsg->b_datap->db_type = type; ! 5385: * ctlmsg->b_wptr ++ = (unsigned char) param; ! 5386: ! 5387: QUEUE_PUTNEXT (q, ctlmsg); ! 5388: ! 5389: return 1; ! 5390: } ! 5391: ! 5392: ! 5393: /* ! 5394: *-STATUS: ! 5395: * DDI/DKI ! 5396: * ! 5397: *-NAME: ! 5398: * putq Put a message to a queue. ! 5399: * ! 5400: *-SYNOPSIS: ! 5401: * #include <sys/stream.h> ! 5402: * ! 5403: * int putq (queue_t * q, mblk_t * mp); ! 5404: * ! 5405: *-ARGUMENTS: ! 5406: * q Pointer to the queue. ! 5407: * ! 5408: * mp Pointer to the message. ! 5409: * ! 5410: *-DESCRIPTION: ! 5411: * putq () is used to put messages on a queue after the "put" routine has ! 5412: * finished processing the message. The message is placed after any other ! 5413: * messages of the same priority, and flow control parameters are ! 5414: * updated. The queue's service routine is scheduled if it has not been ! 5415: * disabled by a previous call to noenable (). ! 5416: * ! 5417: *-RETURN VALUE: ! 5418: * putq () returns 1 on success and 0 on failure. ! 5419: * ! 5420: *-LEVEL: ! 5421: * Base or interrupt. ! 5422: * ! 5423: *-NOTES: ! 5424: * Does not sleep. ! 5425: * ! 5426: * The caller cannot have the stream frozen [see freezestr ()] when ! 5427: * calling this function. ! 5428: * ! 5429: * Driver-defined basic locks, read/write locks, and sleep locks may be ! 5430: * held across calls to this function. ! 5431: * ! 5432: * putq () can fail if there is not enough memory to allocate the ! 5433: * accounting data structures used with messages whose priority bands are ! 5434: * greater than zero. ! 5435: * ! 5436: *-SEE ALSO: ! 5437: * getq (), insq (), putbq (), rmvq (), msgb, queue ! 5438: */ ! 5439: ! 5440: #if __USE_PROTO__ ! 5441: int (putq) (queue_t * q, mblk_t * mp) ! 5442: #else ! 5443: int ! 5444: putq __ARGS ((q, mp)) ! 5445: queue_t * q; ! 5446: mblk_t * mp; ! 5447: #endif ! 5448: { ! 5449: pl_t prev_pl; ! 5450: qband_t * qbandp; ! 5451: ! 5452: ASSERT (mp != NULL); ! 5453: ASSERT (mp->b_datap != NULL); ! 5454: ! 5455: prev_pl = QFREEZE_TRACE (q, "putq"); ! 5456: ! 5457: if (IS_PRI_MSG (mp)) { ! 5458: /* ! 5459: * Since putq () is defined as forcing b_band to 0 for high- ! 5460: * priority messages, we do the same. In addition, we also ! 5461: * always schedule the queue. No flow-control parameters are ! 5462: * updated for high-priority messages. ! 5463: */ ! 5464: ! 5465: mp->b_band = 0; ! 5466: (void) QUEUE_TRYSCHED (q); ! 5467: ! 5468: /* ! 5469: * We need to flow into the code that finds the correct ! 5470: * insertion point for high-priority and band messages. ! 5471: */ ! 5472: } else if (qbandp = NULL, mp->b_band > 0 && ! 5473: (qbandp = QUEUE_BAND (q, mp->b_band)) == NULL && ! 5474: (qbandp = QBAND_ALLOC (q, mp->b_band)) == NULL) ! 5475: return 0; ! 5476: else if (QUEUE_CHECK_SCHED (q, mp, qbandp)) { ! 5477: /* ! 5478: * Deal with band pointer maintenance now. ! 5479: */ ! 5480: ! 5481: if ((mp->b_next = qbandp->qb_first) != NULL) { ! 5482: /* ! 5483: * We directly know where we want to put the message. ! 5484: */ ! 5485: ! 5486: if ((mp->b_prev = mp->b_next->b_prev) == NULL) ! 5487: q->q_first = mp; ! 5488: else ! 5489: mp->b_prev->b_next = mp; ! 5490: ! 5491: mp->b_next->b_prev = mp; ! 5492: ! 5493: qbandp->qb_first = mp; ! 5494: ! 5495: goto alldone; ! 5496: } ! 5497: ! 5498: /* ! 5499: * This is the only message in this band. We will need to ! 5500: * search for the correct position to queue this message. ! 5501: */ ! 5502: ! 5503: qbandp->qb_last = qbandp->qb_first = mp; ! 5504: } else { ! 5505: /* ! 5506: * Since we will always be inserting at the end of the queue, ! 5507: * we directly know where we will be inserting the new ! 5508: * message. ! 5509: */ ! 5510: ! 5511: mp->b_next = NULL; ! 5512: ! 5513: if ((mp->b_prev = q->q_last) == NULL) ! 5514: q->q_first = mp; ! 5515: else ! 5516: mp->b_prev->b_next = mp; ! 5517: ! 5518: q->q_last = mp; ! 5519: ! 5520: goto alldone; ! 5521: } ! 5522: ! 5523: ! 5524: /* ! 5525: * Since we want to insert after other messages with the same band ! 5526: * number, we adjust the band down by one. This introduces a special ! 5527: * case for high-priority messages, which we want to queue before all ! 5528: * normal messages. Since we define high-priority messages as having ! 5529: * a band number of 0, subtracting one makes the band value wrap ! 5530: * around, yielding the desired behaviour. ! 5531: */ ! 5532: ! 5533: QUEUE_PLACE_MSG (q, mp, mp->b_band - 1); ! 5534: ! 5535: alldone: ! 5536: QUNFREEZE_TRACE (q, prev_pl); ! 5537: return 1; ! 5538: } ! 5539: ! 5540: ! 5541: /* ! 5542: *-STATUS: ! 5543: * DDI/DKI ! 5544: * ! 5545: *-NAME: ! 5546: * qenable Schedule a queue's service routine to be run. ! 5547: * ! 5548: *-SYNOPSIS: ! 5549: * #include <sys/stream.h> ! 5550: * ! 5551: * void qenable (queue_t * q); ! 5552: * ! 5553: *-ARGUMENTS: ! 5554: * q Pointer to the queue. ! 5555: * ! 5556: *-DESCRIPTION: ! 5557: * qenable () puts the queue pointed to by "q" on the linked list of ! 5558: * STREAMS routines that are ready to be called by the STREAMS scheduler. ! 5559: * qenable () works regardless of whether the service routine has been ! 5560: * disabled by a previous call to noenable (). ! 5561: * ! 5562: *-RETURN VALUE: ! 5563: * None. ! 5564: * ! 5565: *-LEVEL: ! 5566: * Base or interrupt. ! 5567: * ! 5568: *-NOTES: ! 5569: * Does not sleep. ! 5570: * ! 5571: * The caller cannot have the stream frozen [see freezestr ()] when ! 5572: * calling this function. ! 5573: * ! 5574: * Driver-defined basic locks, read/write locks, and sleep locks may be ! 5575: * held across calls to this function. ! 5576: * ! 5577: *-SEE ALSO: ! 5578: * enableok (), noenable (), queue ! 5579: */ ! 5580: ! 5581: #if __USE_PROTO__ ! 5582: void (qenable) (queue_t * q) ! 5583: #else ! 5584: void ! 5585: qenable __ARGS ((q)) ! 5586: queue_t * q; ! 5587: #endif ! 5588: { ! 5589: pl_t prev_pl; ! 5590: ! 5591: prev_pl = QFREEZE_TRACE (q, "qenable"); ! 5592: ! 5593: (void) QUEUE_TRYSCHED (q); ! 5594: ! 5595: QUNFREEZE_TRACE (q, prev_pl); ! 5596: } ! 5597: ! 5598: ! 5599: /* ! 5600: *-STATUS: ! 5601: * DDI/DKI ! 5602: * ! 5603: *-NAME: ! 5604: * qprocsoff Disable put and service procedures. ! 5605: * ! 5606: *-SYNOPSIS: ! 5607: * #include <sys/stream.h> ! 5608: * ! 5609: * void qprocsoff (queue_t * rq); ! 5610: * ! 5611: *-ARGUMENTS: ! 5612: * rq Pointer to a read queue. ! 5613: * ! 5614: *-DESCRIPTION: ! 5615: * qprocsoff () disables the "put" and "service" routines of the driver ! 5616: * or module whose read queue is pointed to by "rq". When the routines ! 5617: * are disabled in a module, messages flow around the module as if it ! 5618: * were not present in the stream. ! 5619: * ! 5620: * qprocsoff () must be called by the "close" routine of a driver or ! 5621: * module before deallocating any resources on which the driver/module's ! 5622: * put and service procedures depend. ! 5623: * ! 5624: * qprocsoff () will remove the queue's service routines from the list of ! 5625: * service routines to be run and waits until any concurrent "put" or ! 5626: & "service" routines are finished. ! 5627: * ! 5628: *-RETURN VALUE: ! 5629: * None. ! 5630: * ! 5631: *-LEVEL: ! 5632: * Base level only. ! 5633: * ! 5634: *-NOTES: ! 5635: * May sleep. ! 5636: * ! 5637: * The caller cannot have the stream frozen [see freezestr ()] when ! 5638: * calling this function. ! 5639: * ! 5640: * Driver-defined basic locks and read/write locks may not be held across ! 5641: * calls to this function. ! 5642: * ! 5643: * Driver-defined sleep locks may be held across calls to this function. ! 5644: * ! 5645: *-SEE ALSO: ! 5646: * qprocson () ! 5647: */ ! 5648: ! 5649: #if __USE_PROTO__ ! 5650: void (qprocsoff) (queue_t * rq) ! 5651: #else ! 5652: void ! 5653: qprocsoff __ARGS ((rq)) ! 5654: queue_t * rq; ! 5655: #endif ! 5656: { ! 5657: pl_t prev_pl; ! 5658: int dosleep; ! 5659: queue_t * wq; ! 5660: ! 5661: ! 5662: try_rprocsoff: ! 5663: prev_pl = QFREEZE_TRACE (rq, "qprocsoff"); ! 5664: ! 5665: rq->q_flag |= QPROCSOFF; ! 5666: if ((dosleep = rq->q_active > 0) != 0) ! 5667: (void) LOCK (str_mem->sm_proc_lock, plstr); ! 5668: ! 5669: QUNFREEZE_TRACE (rq, prev_pl); ! 5670: ! 5671: if (dosleep) { ! 5672: SV_WAIT (str_mem->sm_proc_sv, prilo, str_mem->sm_proc_lock); ! 5673: ! 5674: goto try_rprocsoff; ! 5675: } ! 5676: ! 5677: /* ! 5678: * Now do the same for the write side. ! 5679: */ ! 5680: ! 5681: ASSERT ((rq->q_flag & QREADR) != 0); ! 5682: ! 5683: wq = W (rq); ! 5684: ! 5685: try_wprocsoff: ! 5686: prev_pl = QFREEZE_TRACE (wq, "qprocsoff"); ! 5687: ! 5688: wq->q_flag |= QPROCSOFF; ! 5689: if ((dosleep = wq->q_active > 0) != 0) ! 5690: (void) LOCK (str_mem->sm_proc_lock, plstr); ! 5691: ! 5692: ! 5693: QUNFREEZE_TRACE (wq, prev_pl); ! 5694: ! 5695: if (dosleep) { ! 5696: SV_WAIT (str_mem->sm_proc_sv, prilo, str_mem->sm_proc_lock); ! 5697: ! 5698: goto try_wprocsoff; ! 5699: } ! 5700: } ! 5701: ! 5702: ! 5703: /* ! 5704: *-STATUS: ! 5705: * DDI/DKI ! 5706: * ! 5707: *-NAME: ! 5708: * qprocson Enable put and service routines. ! 5709: * ! 5710: *-SYNOPSIS: ! 5711: * #include <sys/stream.h> ! 5712: * ! 5713: * void qprocson (queue_t * rq); ! 5714: * ! 5715: *-ARGUMENTS: ! 5716: * rq Pointer to a read queue. ! 5717: * ! 5718: *-DESCRIPTION: ! 5719: * qprocson () enables the "put" and "service" routines of the driver or ! 5720: * module whose read queue is pointed to by "rq". Prior to the call to ! 5721: * qprocson (), the put and service routines of a newly pushed module or ! 5722: * driver are disabled. For the module, messages flow around it as if it ! 5723: * were not present in the stream. ! 5724: * ! 5725: * qprocson () must be called by the first open of a module or driver ! 5726: * after allocation and initialization of any resources on which the put ! 5727: * and service routines depend. ! 5728: * ! 5729: *-RETURN VALUE: ! 5730: * None. ! 5731: * ! 5732: *-LEVEL: ! 5733: * Base level only. ! 5734: * ! 5735: *-NOTES: ! 5736: * May sleep. ! 5737: * ! 5738: * The caller cannot have the stream frozen [see freezestr ()] when ! 5739: * calling this function. ! 5740: * ! 5741: * Driver-defined basic locks and read/write locks may not be held across ! 5742: * calls to this function. ! 5743: * ! 5744: * Driver-defined sleep locks may be held across calls to this function. ! 5745: * ! 5746: *-SEE ALSO: ! 5747: * qprocsoff () ! 5748: */ ! 5749: ! 5750: #if __USE_PROTO__ ! 5751: void (qprocson) (queue_t * rq) ! 5752: #else ! 5753: void ! 5754: qprocson __ARGS ((rq)) ! 5755: queue_t * rq; ! 5756: #endif ! 5757: { ! 5758: pl_t prev_pl; ! 5759: queue_t * wq; ! 5760: ! 5761: /* ! 5762: * Actually, this implementation of qprocsoff () busy-waits rather ! 5763: * than sleeping, but don't count on that. ! 5764: */ ! 5765: ! 5766: prev_pl = QFREEZE_TRACE (rq, "qprocson"); ! 5767: ! 5768: ASSERT ((rq->q_flag & QREADR) != 0); ! 5769: ! 5770: wq = W (rq); ! 5771: ! 5772: (void) QFREEZE_TRACE (wq, "qprocson"); ! 5773: ! 5774: rq->q_flag &= ~ QPROCSOFF; ! 5775: wq->q_flag &= ~ QPROCSOFF; ! 5776: ! 5777: ASSERT (rq->q_active == 0 && wq->q_active == 0); ! 5778: ! 5779: ! 5780: /* ! 5781: * If there are any messages on the queues, the service procedures ! 5782: * should be run. If the QWANTW flag is set, we'll back-enable the ! 5783: * queues. ! 5784: */ ! 5785: ! 5786: if (rq->q_first != NULL && (rq->q_flag & QNOENB) != 0) ! 5787: (void) QUEUE_TRYSCHED (rq); ! 5788: ! 5789: if (wq->q_first != NULL && (wq->q_flag & QNOENB) != 0) ! 5790: (void) QUEUE_TRYSCHED (wq); ! 5791: ! 5792: if ((rq->q_flag & QWANTW) != 0) { ! 5793: ! 5794: rq->q_flag &= ~ QWANTW; ! 5795: QUEUE_BACKENAB (rq); ! 5796: } ! 5797: ! 5798: if ((wq->q_flag & QWANTW) != 0) { ! 5799: ! 5800: wq->q_flag &= ~ QWANTW; ! 5801: QUEUE_BACKENAB (wq); ! 5802: } ! 5803: ! 5804: QUNFREEZE_TRACE (wq, plstr); ! 5805: QUNFREEZE_TRACE (rq, prev_pl); ! 5806: } ! 5807: ! 5808: ! 5809: /* ! 5810: *-STATUS: ! 5811: * DDI/DKI ! 5812: * ! 5813: *-NAME: ! 5814: * qreply Send a message in the opposite direction on a stream. ! 5815: * ! 5816: *-SYNOPSIS: ! 5817: * #include <sys/stream.h> ! 5818: * ! 5819: * void qreply (queue_t * q, mblk_t * mp); ! 5820: * ! 5821: *-ARGUMENTS: ! 5822: * q Pointer to the queue from which the message is being ! 5823: * sent. ! 5824: * ! 5825: * mp Pointer to the message to be sent in the opposite ! 5826: * direction. ! 5827: * ! 5828: *-DESCRIPTION: ! 5829: * qreply () sends a message in the opposite direction from that which ! 5830: * "q" is pointing. It calls the OTHERQ () function to find "q"'s ! 5831: * partner, and passes the message by calling the "put" routine of the ! 5832: * next queue in the stream after "q"'s partner. ! 5833: * ! 5834: *-RETURN VALUE: ! 5835: * None. ! 5836: * ! 5837: *-LEVEL: ! 5838: * Base or interrupt. ! 5839: * ! 5840: *-NOTES: ! 5841: * Does not sleep. ! 5842: * ! 5843: * The caller cannot have the stream frozen [see freezestr ()] when ! 5844: * calling this function. ! 5845: * ! 5846: * Driver-defined basic locks, read/write locks, and sleep locks may be ! 5847: * held across calls to this function. ! 5848: * ! 5849: *-SEE ALSO: ! 5850: */ ! 5851: ! 5852: #if __USE_PROTO__ ! 5853: void (qreply) (queue_t * q, mblk_t * mp) ! 5854: #else ! 5855: void ! 5856: qreply __ARGS ((q, mp)) ! 5857: queue_t * q; ! 5858: mblk_t * mp; ! 5859: #endif ! 5860: { ! 5861: /* ! 5862: * The DDI/DKI says the caller cannot have the stream frozen, but we ! 5863: * don't actually need to do anything that would freeze the stream. ! 5864: * The proscription arises because we need to freeze the other queue ! 5865: * temporarily, and for one context to freeze both sides of a stream ! 5866: * may induce deadlock. ! 5867: */ ! 5868: ! 5869: #ifndef NDEBUG ! 5870: pl_t prev_pl; ! 5871: ! 5872: prev_pl = QFREEZE_TRACE (q, "qreply"); ! 5873: QUNFREEZE_TRACE (q, prev_pl); ! 5874: #endif ! 5875: ! 5876: ASSERT (mp != NULL); ! 5877: ASSERT (mp->b_datap != NULL); ! 5878: ! 5879: q = OTHERQ (q); ! 5880: ! 5881: QUEUE_PUTNEXT (q, mp); ! 5882: } ! 5883: ! 5884: ! 5885: /* ! 5886: *-STATUS: ! 5887: * DDI/DKI ! 5888: * ! 5889: *-NAME: ! 5890: * qsize Find the number of messages on a queue. ! 5891: * ! 5892: *-SYNOPSIS: ! 5893: * #include <sys/stream.h> ! 5894: * ! 5895: * int qsize (queue_t * q); ! 5896: * ! 5897: *-ARGUMENTS: ! 5898: * q Pointer to the queue to be evaluated. ! 5899: * ! 5900: *-DESCRIPTION: ! 5901: * qsize () evaluates the queue pointed to by "q" and returns the number ! 5902: * of messages it contains. ! 5903: * ! 5904: *-RETURN VALUE: ! 5905: * If there are no messages on the queue, "qsize" returns 0. Otherwise, ! 5906: * it returns the number of messages on the queue. ! 5907: * ! 5908: *-LEVEL: ! 5909: * Base or interrupt. ! 5910: * ! 5911: *-NOTES: ! 5912: * Does not sleep. ! 5913: * ! 5914: * The caller cannot have the stream frozen [see freezestr ()] when ! 5915: * calling this function. ! 5916: * ! 5917: * Driver-defined basic locks, read/write locks, and sleep locks may be ! 5918: * held across calls to this function. ! 5919: * ! 5920: *-SEE ALSO: ! 5921: * msgb, queue ! 5922: */ ! 5923: ! 5924: #if __USE_PROTO__ ! 5925: int (qsize) (queue_t * q) ! 5926: #else ! 5927: int ! 5928: qsize __ARGS ((q)) ! 5929: queue_t * q; ! 5930: #endif ! 5931: { ! 5932: pl_t prev_pl; ! 5933: mblk_t * scan; ! 5934: int count = 0; ! 5935: ! 5936: prev_pl = QFREEZE_TRACE (q, "qsize"); ! 5937: ! 5938: for (scan = q->q_first ; scan != NULL ; scan = scan->b_next) ! 5939: count ++; ! 5940: ! 5941: QUNFREEZE_TRACE (q, prev_pl); ! 5942: ! 5943: return count; ! 5944: } ! 5945: ! 5946: ! 5947: /* ! 5948: *-STATUS: ! 5949: * DDI/DKI ! 5950: * ! 5951: *-NAME: ! 5952: * RD Get a pointer to the read queue. ! 5953: * ! 5954: *-SYNOPSIS: ! 5955: * #include <sys/stream.h> ! 5956: * ! 5957: * queue_t * RD (queue_t * q); ! 5958: * ! 5959: *-ARGUMENTS: ! 5960: * q Pointer to the queue whose read queue is to be ! 5961: * returned. ! 5962: * ! 5963: *-DESCRIPTION: ! 5964: * The RD () function accepts a queue pointer as an argument and returns ! 5965: * a pointer to the read queue of the same module or driver. ! 5966: * ! 5967: *-RETURN VALUE: ! 5968: * The pointer to the read queue. ! 5969: * ! 5970: *-LEVEL: ! 5971: * Base or interrupt. ! 5972: * ! 5973: *-NOTES: ! 5974: * Does not sleep. ! 5975: * ! 5976: * Driver-defined basic locks, read/write locks, and sleep locks may be ! 5977: * held across calls to this function. ! 5978: * ! 5979: *-SEE ALSO: ! 5980: * OTHERQ (), WR () ! 5981: */ ! 5982: ! 5983: #if __USE_PROTO__ ! 5984: queue_t * (RD) (queue_t * q) ! 5985: #else ! 5986: queue_t * ! 5987: RD __ARGS ((q)) ! 5988: queue_t * q; ! 5989: #endif ! 5990: { ! 5991: QUEUE_TRACE (q, "RD"); ! 5992: ! 5993: return RD (q); ! 5994: } ! 5995: ! 5996: ! 5997: /* ! 5998: *-STATUS: ! 5999: * DDI/DKI ! 6000: * ! 6001: *-NAME: ! 6002: * rmvb Remove a message block from a message. ! 6003: * ! 6004: *-SYNOPSIS: ! 6005: * #include <sys/stream.h> ! 6006: * ! 6007: * mblk_t * rmvb (mblk_t * mp, mblk_t * bp); ! 6008: * ! 6009: *-ARGUMENTS: ! 6010: * mp Message from which a message block is to be removed. ! 6011: * ! 6012: * bp Message block to be removed. ! 6013: * ! 6014: *-DESCRIPTION: ! 6015: * rmvb () removes a message block ("bp") from a message ("mp"), and ! 6016: * returns a pointer to the altered message. The message block is not ! 6017: * freed, merely removed from the message. It is the caller's ! 6018: * responsibility to free the message block. ! 6019: * ! 6020: *-RETURN VALUE: ! 6021: * If successful, a pointer to the message (minus the removed block) is ! 6022: * returned. If "bp" was the only block in the message before rmvb () ! 6023: * was called, NULL is returned. If the designated message block ("bp") ! 6024: * was not in the message, -1 is returned. ! 6025: * ! 6026: *-LEVEL: ! 6027: * Base or interrupt. ! 6028: * ! 6029: *-NOTES: ! 6030: * Does not sleep. ! 6031: * ! 6032: * Driver-defined basic locks, read/write locks, and sleep locks may be ! 6033: * held across calls to this function. ! 6034: */ ! 6035: ! 6036: #if __USE_PROTO__ ! 6037: mblk_t * (rmvb) (mblk_t * mp, mblk_t * bp) ! 6038: #else ! 6039: mblk_t * ! 6040: rmvb __ARGS ((mp, bp)) ! 6041: mblk_t * mp; ! 6042: mblk_t * bp; ! 6043: #endif ! 6044: { ! 6045: mblk_t * scan; ! 6046: ! 6047: ASSERT (mp != NULL); ! 6048: ASSERT (bp != NULL); ! 6049: ! 6050: if (mp == bp) ! 6051: return mp->b_cont; ! 6052: ! 6053: for (scan = mp ; scan != NULL ; scan = scan->b_cont) ! 6054: if (scan->b_cont == bp) { ! 6055: ! 6056: scan->b_cont = bp->b_cont; ! 6057: return mp; ! 6058: } ! 6059: ! 6060: return (mblk_t *) -1; ! 6061: } ! 6062: ! 6063: ! 6064: /* ! 6065: *-STATUS: ! 6066: * DDI/DKI ! 6067: * ! 6068: *-NAME: ! 6069: * rmvq Remove a message from a queue. ! 6070: * ! 6071: *-SYNOPSIS: ! 6072: * #include <sys/stream.h> ! 6073: * ! 6074: * void rmvq (queue_t * q, mblk_t * mp); ! 6075: * ! 6076: *-ARGUMENTS: ! 6077: * q Pointer to the queue containing the message to be ! 6078: * removed. ! 6079: * ! 6080: * mp Pointer to the message to be removed. ! 6081: * ! 6082: *-DESCRIPTION: ! 6083: * rmvq () removes a message from a queue. A message can be removed from ! 6084: * anywhere in a queue. To prevent modules and drivers from having to ! 6085: * deal with the internals of message linkage on a queue, either rmvq () ! 6086: * or getq () should be used to remove a message from a queue. ! 6087: * ! 6088: *-RETURN VALUE: ! 6089: * None. ! 6090: * ! 6091: *-LEVEL: ! 6092: * Base or interrupt. ! 6093: * ! 6094: *-NOTES: ! 6095: * Does not sleep. ! 6096: * ! 6097: * The caller must have the stream frozen [see freezestr ()] when calling ! 6098: * this function. ! 6099: * ! 6100: * Driver-defined basic locks, read/write locks, and sleep locks may be ! 6101: * held across calls to this function. ! 6102: * ! 6103: * "mp" must point to an existing message in the queue pointed to by "q", ! 6104: * or a system panic will occur. ! 6105: * ! 6106: *-SEE ALSO: ! 6107: * freezestr (), getq (), insq (), unfreezestr (). ! 6108: */ ! 6109: ! 6110: #if __USE_PROTO__ ! 6111: void (rmvq) (queue_t * q, mblk_t * mp) ! 6112: #else ! 6113: void ! 6114: rmvq __ARGS ((q, mp)) ! 6115: queue_t * q; ! 6116: mblk_t * mp; ! 6117: #endif ! 6118: { ! 6119: ASSERT (mp != NULL); ! 6120: ! 6121: QFROZEN_TRACE (q, "rmvq"); ! 6122: ! 6123: /* ! 6124: * First, simply dequeue the message based on mp's "b_next" and ! 6125: * "b_prev" members. ! 6126: */ ! 6127: ! 6128: if (mp->b_next == NULL) { ! 6129: ! 6130: ASSERT (q->q_last == mp); ! 6131: if ((q->q_last = mp->b_prev) == NULL) ! 6132: QUEUE_DRAINED (q); ! 6133: } else ! 6134: mp->b_next->b_prev = mp->b_prev; ! 6135: ! 6136: if (mp->b_prev == NULL) { ! 6137: ! 6138: ASSERT (q->q_first == mp); ! 6139: q->q_first = mp->b_next; ! 6140: ! 6141: /* ! 6142: * Since we are dequeueing a message from the front of the ! 6143: * queue, record the message band. ! 6144: */ ! 6145: ! 6146: q->q_lastband = mp->b_band; ! 6147: } else ! 6148: mp->b_prev->b_next = mp->b_next; ! 6149: ! 6150: /* ! 6151: * Now we adjust the flow-control parameters and band information. ! 6152: */ ! 6153: ! 6154: if (! IS_PRI_MSG (mp)) { ! 6155: ulong_t msgsize = MSG_SIZE (mp); ! 6156: ! 6157: if (mp->b_band > 0) { ! 6158: qband_t * qbandp = QUEUE_BAND (q, mp->b_band); ! 6159: ! 6160: ASSERT (qbandp->qb_first == mp); ! 6161: ! 6162: QBAND_DEQUEUE (qbandp, mp); ! 6163: ! 6164: QBAND_REDUCE (q, qbandp, msgsize); ! 6165: } else ! 6166: QUEUE_REDUCE (q, msgsize); ! 6167: } ! 6168: } ! 6169: ! 6170: ! 6171: /* ! 6172: *-STATUS: ! 6173: * DDI/DKI ! 6174: * ! 6175: *-NAME: ! 6176: * SAMESTR Test if next queue is same type. ! 6177: * ! 6178: *-SYNOPSIS: ! 6179: * #include <sys/stream.h> ! 6180: * ! 6181: * int SAMESTR (queue_t * q); ! 6182: * ! 6183: *-ARGUMENTS: ! 6184: * q Pointer to the queue. ! 6185: * ! 6186: *-DESCRIPTION: ! 6187: * The SAMESTR () function is used to see if the next queue in a stream ! 6188: * (if it exists) is the same type as the current queue (that is, both ! 6189: * are read queues or both are write queues). This can be used to ! 6190: * determine the point in a STREAMS-based pipe where a read queue is ! 6191: * linked to a write queue. ! 6192: * ! 6193: *-RETURN VALUE: ! 6194: * SAMESTR () returns 1 if the next queue is the same type as the current ! 6195: * queue. It returns 0 if the next queue does not exist or if it is not ! 6196: * the same type. ! 6197: * ! 6198: *-LEVEL: ! 6199: * Base or interrupt. ! 6200: * ! 6201: *-NOTES: ! 6202: * Does not sleep. ! 6203: * ! 6204: * The caller cannot have the stream frozen [see freezestr ()] when ! 6205: * calling this function. ! 6206: * ! 6207: * Driver-defined basic locks, read/write locks, and sleep locks may be ! 6208: * held across calls to this function. ! 6209: * ! 6210: * The argument "q" may not reference "q_next" (for example, an argument ! 6211: * of "q->q_next" is erroneous on a multiprocessor and is disallowed by ! 6212: * the DDI/DKI). ! 6213: * ! 6214: *-SEE ALSO: ! 6215: * OTHERQ () ! 6216: */ ! 6217: ! 6218: #if __USE_PROTO__ ! 6219: int (SAMESTR) (queue_t * q) ! 6220: #else ! 6221: int ! 6222: SAMESTR __ARGS ((q)) ! 6223: queue_t * q; ! 6224: #endif ! 6225: { ! 6226: int retval; ! 6227: pl_t prev_pl; ! 6228: ! 6229: prev_pl = QFREEZE_TRACE (q, "SAMESTR"); ! 6230: ! 6231: retval = q->q_next == NULL ? 0 : ! 6232: (q->q_next->q_flag & QREADR) == (q->q_flag & QREADR); ! 6233: ! 6234: QUNFREEZE_TRACE (q, prev_pl); ! 6235: ! 6236: return retval; ! 6237: } ! 6238: ! 6239: ! 6240: /* ! 6241: *-STATUS: ! 6242: * DDI/DKI ! 6243: * ! 6244: *-NAME: ! 6245: * strlog Submit messages to the log driver. ! 6246: * ! 6247: *-SYNOPSIS: ! 6248: * #include <sys/types.h> ! 6249: * #include <sys/stream.h> ! 6250: * #include <sys/strlog.h> ! 6251: * #include <sys/log.h> ! 6252: * ! 6253: * int strlog (short mid, short sid, char level, uchar_t flags, ! 6254: * char * fmt, ...); ! 6255: * ! 6256: *-ARGUMENTS: ! 6257: * mid Identification number of the module or driver ! 6258: * submitting the message. ! 6259: * ! 6260: * sid Identification number for a particular minor device. ! 6261: * ! 6262: * flags Bitmask of flags indicating message purpose. Valid ! 6263: * flags are: ! 6264: * SL_ERROR Message is for error logger. ! 6265: * SL_TRACE Message is for tracing. ! 6266: * SL_CONSOLE Message is for console logger. ! 6267: * SL_NOTIFY If SL_ERROR is also set, mail copy of ! 6268: * message to system administrator. ! 6269: * SL_FATAL Modifier indicating error is fatal. ! 6270: * SL_WARN Modifier indicating error is a ! 6271: * warning. ! 6272: * SL_NOTE Modifier indicating error is a notice. ! 6273: * ! 6274: * fmt printf () style format string. %s, %e, %g and %G ! 6275: * formats are not allowed. ! 6276: * ! 6277: * ... Zero or more arguments to printf () (maximum of ! 6278: * NLOGARGS, currently three). ! 6279: * ! 6280: *-DESCRIPTION: ! 6281: * strlog () submits formatted messages to the "log" driver. The messages ! 6282: * can be retrieved with the getmsg () system call. The "flags" argument ! 6283: * specifies the type of the message and where it is to be sent. ! 6284: * ! 6285: *-RETURN VALUE: ! 6286: * strlog () returns 0 if the message is not seen by all the readers, 1 ! 6287: * otherwise. ! 6288: * ! 6289: *-LEVEL: ! 6290: * Base or interrupt. ! 6291: * ! 6292: *-NOTES: ! 6293: * Does not sleep. ! 6294: * ! 6295: * Driver-defined basic locks, read/write locks, and sleep locks may be ! 6296: * held across calls to this function. ! 6297: * ! 6298: *-SEE ALSO: ! 6299: * log (7) in the "Programmer's Guide: STREAMS" ! 6300: */ ! 6301: ! 6302: #if __USE_PROTO__ ! 6303: int (strlog) (short mid, short sid, char level, ushort_t flags, char * fmt, ! 6304: ...) ! 6305: #else ! 6306: int ! 6307: strlog __ARGS ((mid, sid, level, flags, fmt)) ! 6308: short mid; ! 6309: short sid; ! 6310: char level; ! 6311: ushort_t flags; ! 6312: char * fmt; ! 6313: #endif ! 6314: { ! 6315: mblk_t * data; ! 6316: ulong_t err_seq, trc_seq, con_seq; ! 6317: mblk_t * errmsg, * trcmsg, * conmsg; ! 6318: int failures; ! 6319: int copies; ! 6320: int pri; ! 6321: ! 6322: # define SL_ALL (SL_ERROR | SL_TRACE | SL_CONSOLE | SL_NOTIFY |\ ! 6323: SL_FATAL | SL_WARN | SL_NOTE) ! 6324: ! 6325: ASSERT ((flags & SL_ALL) != 0); ! 6326: ASSERT ((flags & ~ SL_ALL) == 0); ! 6327: ASSERT (fmt != NULL); ! 6328: ! 6329: /* ! 6330: * The first thing we do is assign a sequence number to this log item ! 6331: * so that we can correctly detect when log items have been discarded ! 6332: * due to lack of available resources. In addition, there are several ! 6333: * sequence-number spaces available, depending on the destination of ! 6334: * the log message. We acquire numbers from all the spaces now, and ! 6335: * write them into the actual log messages later. ! 6336: */ ! 6337: ! 6338: { ! 6339: pl_t prev_pl; ! 6340: int temp; ! 6341: ! 6342: prev_pl = LOCK (str_mem->sm_seq_lock, plstr); ! 6343: ! 6344: err_seq = trc_seq = con_seq = 0; /* paranoia */ ! 6345: ! 6346: if ((flags & SL_ERROR) != 0) ! 6347: err_seq = str_mem->sm_err_seq ++; ! 6348: if ((flags & SL_TRACE) != 0) ! 6349: trc_seq = str_mem->sm_trc_seq ++; ! 6350: if ((flags & SL_CONSOLE) != 0) ! 6351: con_seq = str_mem->sm_con_seq ++; ! 6352: ! 6353: temp = str_mem->sm_log_rq == NULL; ! 6354: ! 6355: UNLOCK (str_mem->sm_seq_lock, prev_pl); ! 6356: ! 6357: ! 6358: /* ! 6359: * If the log driver isn't installed yet, don't bother with ! 6360: * the rest of this routine. ! 6361: */ ! 6362: ! 6363: if (temp) ! 6364: return 0; ! 6365: } ! 6366: ! 6367: /* ! 6368: * While the documentation for this function doesn't spell it out, ! 6369: * the log (7) driver traffics in error, trace and console messages, ! 6370: * with the others being variations on that theme. ! 6371: * ! 6372: * Somehow the "flags" have to be mapped into a priority/facility code ! 6373: * according to some rules that are alluded to in the log (7) manual ! 6374: * pages. ! 6375: */ ! 6376: ! 6377: { ! 6378: size_t size; ! 6379: va_list args; ! 6380: uchar_t * dest; ! 6381: int temp; ! 6382: ! 6383: if ((flags & (SL_ERROR | SL_FATAL)) != 0) ! 6384: pri = BPRI_HI; ! 6385: else if ((flags & SL_WARN) != 0) ! 6386: pri = BPRI_MED; ! 6387: else ! 6388: pri = BPRI_LO; ! 6389: ! 6390: ! 6391: /* ! 6392: * The data portion of a STREAMS logger message contains the ! 6393: * unexpanded text of the "fmt" string plus NLOGARGS worth of ! 6394: * data containing any extra arguments packed after the string ! 6395: * aligned to the next word address. ! 6396: * ! 6397: * We'll also need at least one control message section, which ! 6398: * we can copy as necessary later on. ! 6399: */ ! 6400: /* ! 6401: * ALIGNMENT-DEPENDENT CODE. ! 6402: */ ! 6403: size = ((strlen (fmt) + 4) & ~ (sizeof (int) - 1)) + ! 6404: NLOGARGS * sizeof (ulong_t); ! 6405: ! 6406: if ((data = MSGB_ALLOC (size, pri, KM_NOSLEEP)) == NULL) { ! 6407: /* ! 6408: * Return a failure indication. This is not a major ! 6409: * problem, as the gaps in the sequence space tell a ! 6410: * story... ! 6411: */ ! 6412: ! 6413: return 0; ! 6414: } ! 6415: ! 6416: /* ! 6417: * Copy the format string and the argument data to the log ! 6418: * buffer. ! 6419: */ ! 6420: ! 6421: dest = data->b_rptr; ! 6422: while ((* dest ++ = * (uchar_t *) fmt ++) != 0) ! 6423: ; ! 6424: dest += (sizeof (int) - 1) - (((unsigned long) dest - 1) & ! 6425: (sizeof (int) - 1)); ! 6426: ! 6427: va_start (args, fmt); ! 6428: for (temp = 0 ; temp < NLOGARGS ; temp ++) { ! 6429: * (ulong_t *) dest = va_arg (args, ulong_t); ! 6430: dest += sizeof (ulong_t); ! 6431: } ! 6432: va_end (args); ! 6433: ! 6434: data->b_wptr += size; ! 6435: ! 6436: ASSERT (data->b_wptr == dest); ! 6437: } ! 6438: ! 6439: ! 6440: /* ! 6441: * Now send the log request to the read side of the log driver. This ! 6442: * is how we distinguish kernel log requests from user log requests, ! 6443: * since the user requests will arrive on the write side as usual. ! 6444: * ! 6445: * Since the various destinations for log messages expect to see ! 6446: * messages with sequence numbers tailored to them, we create ! 6447: * additional copies of the log message as needed. For this to work, ! 6448: * we work out the copies first, and then send them. ! 6449: * ! 6450: * This would be a lot easier if C had nested functions as standard. ! 6451: * Sadly, only GNU does this now. ! 6452: */ ! 6453: ! 6454: failures = 0; ! 6455: copies = 0; ! 6456: ! 6457: errmsg = STRLOG_MAKE (mid, sid, level, flags, err_seq, SL_ERROR, ! 6458: & copies, & failures, data); ! 6459: ! 6460: trcmsg = STRLOG_MAKE (mid, sid, level, flags, trc_seq, SL_TRACE, ! 6461: & copies, & failures, data); ! 6462: ! 6463: conmsg = STRLOG_MAKE (mid, sid, level, flags, con_seq, SL_CONSOLE, ! 6464: & copies, & failures, data); ! 6465: ! 6466: if (errmsg != NULL) ! 6467: put (str_mem->sm_log_rq, errmsg); ! 6468: if (trcmsg != NULL) ! 6469: put (str_mem->sm_log_rq, trcmsg); ! 6470: if (conmsg != NULL) ! 6471: put (str_mem->sm_log_rq, conmsg); ! 6472: ! 6473: if (copies == 0) ! 6474: freemsg (data); ! 6475: ! 6476: return failures == 0; ! 6477: } ! 6478: ! 6479: ! 6480: /* ! 6481: *-STATUS: ! 6482: * DDI/DKI ! 6483: * ! 6484: *-NAME: ! 6485: * strqget Get information about a queue or band of the queue. ! 6486: * ! 6487: *-SYNOPSIS: ! 6488: * #include <sys/stream.h> ! 6489: * ! 6490: * int strqget (queue_t * q, qfields_t what, uchar_t pri, long * valp); ! 6491: * ! 6492: *-ARGUMENTS: ! 6493: * q Pointer to the queue. ! 6494: * ! 6495: * what The field of the queeu about which to return ! 6496: * information. Valid values are: ! 6497: * ! 6498: * QHIWAT High water mark of the specified priority ! 6499: * band. ! 6500: * ! 6501: * QLOWAT Low water mark of the specified priority band. ! 6502: * ! 6503: * QMAXPSZ Maximum packet size of the specified priority ! 6504: * band. ! 6505: * ! 6506: * QMINPSZ Minimum packet size of the specified priority ! 6507: * band. ! 6508: * ! 6509: * QCOUNT Number of bytes of data in messages in the ! 6510: * specified priority band. ! 6511: * ! 6512: * QFIRST Pointer to the first message in the specified ! 6513: * priority band. ! 6514: * ! 6515: * QLAST Pointer to the last message in the specified ! 6516: * priority band. ! 6517: * ! 6518: * QFLAG Flags for the specified priority band. ! 6519: * ! 6520: * pri Priority band of the queue about which to obtain ! 6521: * information. ! 6522: * ! 6523: * valp Pointer to the memory locatation where the value is ! 6524: * to be stored. ! 6525: * ! 6526: *-DESCRIPTION: ! 6527: * strqget () gives drivers and modules a way to get information about ! 6528: * a queue or a particular priority band of a queue without directly ! 6529: * accessing STREAMS data structures. ! 6530: * ! 6531: *-RETURN VALUE: ! 6532: * On success, 0 is returns. An error number is returned on failure. The ! 6533: * actual value of the requested field is returned through the reference ! 6534: * parameter "valp". ! 6535: * ! 6536: *-LEVEL: ! 6537: * Base or interrupt. ! 6538: * ! 6539: *-NOTES: ! 6540: * Does not sleep. ! 6541: * ! 6542: * The caller must have the stream frozen [see freezestr ()] when calling ! 6543: * this function. ! 6544: * ! 6545: * Driver-defined basic locks, read/write locks, and sleep locks may be ! 6546: * held across calls to this function. ! 6547: * ! 6548: *-SEE ALSO: ! 6549: * freezestr (), strqset (), unfreezestr (), queue ! 6550: */ ! 6551: ! 6552: #if __USE_PROTO__ ! 6553: int (strqget) (queue_t * q, qfields_t what, uchar_t pri, long * valp) ! 6554: #else ! 6555: int ! 6556: strqget __ARGS ((q, what, pri, valp)) ! 6557: queue_t * q; ! 6558: qfields_t what; ! 6559: uchar_t pri; ! 6560: long * valp; ! 6561: #endif ! 6562: { ! 6563: QFROZEN_TRACE (q, "strqget"); ! 6564: ! 6565: if (pri > 0) ! 6566: switch (what) { ! 6567: ! 6568: case QHIWAT: ! 6569: * valp = q->q_hiwat; ! 6570: break; ! 6571: ! 6572: case QLOWAT: ! 6573: * valp = q->q_lowat; ! 6574: break; ! 6575: ! 6576: case QMAXPSZ: ! 6577: * valp = q->q_maxpsz; ! 6578: break; ! 6579: ! 6580: case QMINPSZ: ! 6581: * valp = q->q_minpsz; ! 6582: break; ! 6583: ! 6584: case QCOUNT: ! 6585: * valp = q->q_count; ! 6586: break; ! 6587: ! 6588: case QFIRST: ! 6589: * valp = (long) q->q_first; ! 6590: break; ! 6591: ! 6592: case QLAST: ! 6593: * valp = (long) q->q_last; ! 6594: break; ! 6595: ! 6596: case QFLAG: ! 6597: * valp = q->q_flag; ! 6598: break; ! 6599: ! 6600: default: ! 6601: return EINVAL; ! 6602: } ! 6603: else { ! 6604: qband_t * qbandp; ! 6605: ! 6606: if ((qbandp = QUEUE_BAND (q, pri)) == NULL && ! 6607: (qbandp = QBAND_ALLOC (q, pri)) == NULL) ! 6608: return ENOMEM; ! 6609: ! 6610: switch (what) { ! 6611: ! 6612: case QHIWAT: ! 6613: * valp = qbandp->qb_hiwat; ! 6614: break; ! 6615: ! 6616: case QLOWAT: ! 6617: * valp = qbandp->qb_lowat; ! 6618: break; ! 6619: ! 6620: case QCOUNT: ! 6621: * valp = qbandp->qb_count; ! 6622: break; ! 6623: ! 6624: case QFIRST: ! 6625: * valp = (long) qbandp->qb_first; ! 6626: break; ! 6627: ! 6628: case QLAST: ! 6629: * valp = (long) qbandp->qb_last; ! 6630: break; ! 6631: ! 6632: case QFLAG: ! 6633: * valp = qbandp->qb_flag; ! 6634: break; ! 6635: ! 6636: default: ! 6637: return EINVAL; ! 6638: } ! 6639: } ! 6640: ! 6641: return 0; ! 6642: } ! 6643: ! 6644: ! 6645: /* ! 6646: *-STATUS: ! 6647: * DDI/DKI ! 6648: * ! 6649: *-NAME: ! 6650: * strqset Change information about a queue or band of the queue. ! 6651: * ! 6652: *-SYNOPSIS: ! 6653: * #include <sys/types.h> ! 6654: * #include <sys/stream.h> ! 6655: * ! 6656: * int strqset (queue_t * q, qfields_t what, uchar_t pri, long val); ! 6657: * ! 6658: *-ARGUMENTS: ! 6659: * q Pointer to the queue. ! 6660: * ! 6661: * what The field of the queue to change. Value values are: ! 6662: * ! 6663: * QHIWAT High water mark of the specified priority ! 6664: * band. ! 6665: * ! 6666: * QLOWAT Low water mark of the specified priority band. ! 6667: * ! 6668: * QMAXPSZ Maximum packet size of the specified priority ! 6669: * band. ! 6670: * ! 6671: * QMINPSZ Minimum packet size of the specified priority ! 6672: * band. ! 6673: * ! 6674: * pri Priority band of the queue to be changed. ! 6675: * ! 6676: * val New value for the field to be changed. ! 6677: * ! 6678: *-DESCRIPTION: ! 6679: * strqset () gives drivers and modules a way to change information about ! 6680: * a queue or a particular priority band of a queue without directly ! 6681: * accessing STREAMS data structures. ! 6682: * ! 6683: *-RETURN VALUE: ! 6684: * On success, 0 is returned. An error number is returned on failure. ! 6685: * ! 6686: *-LEVEL: ! 6687: * Base or interrupt. ! 6688: * ! 6689: *-NOTES: ! 6690: * Does not sleep. ! 6691: * ! 6692: * The caller must have the stream frozen [see freezestr ()] when calling ! 6693: * this function. ! 6694: * ! 6695: * Driver-defined basic locks, read/write locks, and sleep locks may be ! 6696: * held across calls to this function. ! 6697: * ! 6698: *-SEE ALSO: ! 6699: */ ! 6700: ! 6701: #if __USE_PROTO__ ! 6702: int (strqset) (queue_t * q, qfields_t what, uchar_t pri, long val) ! 6703: #else ! 6704: int ! 6705: strqset __ARGS ((q, what, pri, val)) ! 6706: queue_t * q; ! 6707: qfields_t what; ! 6708: uchar_t pri; ! 6709: long val; ! 6710: #endif ! 6711: { ! 6712: QFROZEN_TRACE (q, "strqset"); ! 6713: ! 6714: if (pri > 0) ! 6715: switch (what) { ! 6716: ! 6717: case QHIWAT: ! 6718: q->q_hiwat = val; ! 6719: break; ! 6720: ! 6721: case QLOWAT: ! 6722: q->q_lowat = val; ! 6723: break; ! 6724: ! 6725: case QMAXPSZ: ! 6726: q->q_maxpsz = val; ! 6727: break; ! 6728: ! 6729: case QMINPSZ: ! 6730: q->q_minpsz = val; ! 6731: break; ! 6732: ! 6733: case QCOUNT: ! 6734: case QFIRST: ! 6735: case QLAST: ! 6736: case QFLAG: ! 6737: return EPERM; ! 6738: ! 6739: default: ! 6740: return EINVAL; ! 6741: } ! 6742: else { ! 6743: qband_t * qbandp; ! 6744: ! 6745: if ((qbandp = QUEUE_BAND (q, pri)) == NULL && ! 6746: (qbandp = QBAND_ALLOC (q, pri)) == NULL) ! 6747: return ENOMEM; ! 6748: ! 6749: switch (what) { ! 6750: ! 6751: case QHIWAT: ! 6752: qbandp->qb_hiwat = val; ! 6753: break; ! 6754: ! 6755: case QLOWAT: ! 6756: qbandp->qb_lowat = val; ! 6757: break; ! 6758: ! 6759: case QCOUNT: ! 6760: case QFIRST: ! 6761: case QLAST: ! 6762: case QFLAG: ! 6763: return EPERM; ! 6764: ! 6765: default: ! 6766: return EINVAL; ! 6767: } ! 6768: } ! 6769: ! 6770: return 0; ! 6771: } ! 6772: ! 6773: ! 6774: /* ! 6775: *-STATUS: ! 6776: * Compatibility (pre-MP DDI/DKI) ! 6777: * ! 6778: *-NAME: ! 6779: * testb Check for an available buffer. ! 6780: * ! 6781: *-SYNOPSIS: ! 6782: * #include <sys/stream.h> ! 6783: * ! 6784: * int testb (int size, int pri); ! 6785: * ! 6786: *-ARGUMENTS: ! 6787: * size Size of the requested buffer. ! 6788: * ! 6789: * pri Priority of the allocb () request. ! 6790: * ! 6791: *-DESCRIPTION: ! 6792: * testb () checks to see if an allocb () call is likely to succeed if ! 6793: * a buffer of "size" bytes at priority "pri" is requested. Even if ! 6794: * testb () returns successfully, the call to allocb () can fail. ! 6795: * ! 6796: *-RETURN VALUE: ! 6797: * Returns 1 if a buffer of the requested size is available, and 0 if ! 6798: * one is not. ! 6799: * ! 6800: *-LEVEL: ! 6801: * Base or interrupt. ! 6802: * ! 6803: *-NOTES: ! 6804: * Does not sleep. ! 6805: * ! 6806: * Driver-defined basic locks, read/write locks, and sleep locks may be ! 6807: * held across calls to this function. ! 6808: * ! 6809: * This function is provided purely as a porting convenience for ! 6810: * developers working with drivers developed under earlier releases of ! 6811: * the System V DDI/DKI or under STREAMS from System V, Release 3. Calls ! 6812: * to this function should be replaced with calls to functions that do ! 6813: * the real work. ! 6814: * ! 6815: *-SEE ALSO: ! 6816: * allocb (), bufcall (). ! 6817: */ ! 6818: ! 6819: #if __USE_PROTO__ ! 6820: int (testb) (int size, int pri) ! 6821: #else ! 6822: int ! 6823: testb __ARGS ((size, pri)) ! 6824: int size; ! 6825: int pri; ! 6826: #endif ! 6827: { ! 6828: pl_t prev_pl; ! 6829: int return_val; ! 6830: ! 6831: /* ! 6832: * This function is one of the most braindead peices of STREAMS. It ! 6833: * may not have been initially, but by the SVR4 DDI/DKI, it was ! 6834: * *totally* useless. The example code given in that DDI/DKI issue is ! 6835: * so bad it's unbelievable, and they admit it too... ! 6836: */ ! 6837: ! 6838: ASSERT (size > 0); ! 6839: ASSERT (pri == BPRI_LO || pri == BPRI_HI || pri == BPRI_LO); ! 6840: ! 6841: pri = MAP_PRI_LEVEL (pri); ! 6842: size = MSGB_SIZE (pri); ! 6843: ! 6844: ! 6845: /* ! 6846: * Lock the basic lock protecting access to the memory pool ! 6847: * and attempt to acquire the memory we desire. ! 6848: */ ! 6849: ! 6850: prev_pl = LOCK (str_mem->sm_msg_lock, str_msg_pl); ! 6851: ! 6852: /* ! 6853: * Before allocating any memory, we check to see that it makes sense ! 6854: * to give out that memory to the given priority level. ! 6855: */ ! 6856: ! 6857: return_val = str_mem->sm_used + size < str_mem->sm_max [pri] && ! 6858: st_maxavail (str_mem->sm_msg_heap) >= size; ! 6859: ! 6860: UNLOCK (str_mem->sm_msg_lock, prev_pl); ! 6861: ! 6862: return return_val; ! 6863: } ! 6864: ! 6865: ! 6866: /* ! 6867: *-STATUS: ! 6868: * DDI/DKI ! 6869: * ! 6870: *-NAME: ! 6871: * unbufcall Cancel a pending bufcall () request. ! 6872: * ! 6873: *-SYNOPSIS: ! 6874: * #include <sys/stream.h> ! 6875: * ! 6876: * void unbufcall (toid_t id); ! 6877: * ! 6878: *-ARGUMENTS: ! 6879: * id Identifier returned from bufcall () or esbbcall (). ! 6880: * ! 6881: *-DESCRIPTION: ! 6882: * unbufcall () cancels a pending bufcall () or esbbcall () request. The ! 6883: * argument "id" is a non-zero identifier for the request to be ! 6884: * cancelled. "id" is returned from the bufcall () or esbbcall () ! 6885: * function used to issue the request. ! 6886: * ! 6887: *-RETURN VALUE: ! 6888: * None. ! 6889: * ! 6890: *-LEVEL: ! 6891: * Base or interrupt. ! 6892: * ! 6893: *-NOTES: ! 6894: * Does not sleep. ! 6895: * ! 6896: * Driver-defined basic locks, read/write locks, and sleep locks may be ! 6897: * held across calls to this function. ! 6898: * ! 6899: *-SEE ALSO: ! 6900: * bufcall (), esbbcall () ! 6901: */ ! 6902: ! 6903: #if __USE_PROTO__ ! 6904: void (unbufcall) (toid_t id) ! 6905: #else ! 6906: void ! 6907: unbufcall __ARGS ((id)) ! 6908: toid_t id; ! 6909: #endif ! 6910: { ! 6911: pl_t prev_pl; ! 6912: selist_t * selistp; ! 6913: sevent_t * sscan; ! 6914: sevent_t * sprev; ! 6915: ! 6916: ASSERT (id != 0); ! 6917: ! 6918: /* ! 6919: * Let's lock the list that we are going to search for the new event ! 6920: * on. ! 6921: */ ! 6922: ! 6923: selistp = & str_mem->sm_bcevents [MAP_PRI_LEVEL (TOID_TO_PRI (id))]; ! 6924: ! 6925: prev_pl = SELIST_LOCK (selistp); ! 6926: ! 6927: for (sscan = selistp->sl_head, sprev = NULL ; sscan != NULL ; ! 6928: sscan = (sprev = sscan)->se_next) { ! 6929: /* ! 6930: * If we find it, dequeue it. ! 6931: */ ! 6932: ! 6933: if (sscan->se_id == id) { ! 6934: if (sprev == NULL) ! 6935: selistp->sl_head = sscan->se_next; ! 6936: else ! 6937: sprev->se_next = sscan->se_next; ! 6938: #if _FIFO_BUFCALL ! 6939: if (selistp->sl_tail == sscan) { ! 6940: ! 6941: ASSERT (sscan->se_next == NULL); ! 6942: selistp->sl_tail = sprev; ! 6943: } else ! 6944: ASSERT (sscan->se_next != NULL); ! 6945: #endif ! 6946: break; ! 6947: } ! 6948: } ! 6949: ! 6950: SELIST_UNLOCK (selistp, prev_pl); ! 6951: } ! 6952: ! 6953: ! 6954: /* ! 6955: *-STATUS: ! 6956: * DDI/DKI ! 6957: * ! 6958: *-NAME: ! 6959: * unfreezestr Unfreeze the state of a stream. ! 6960: * ! 6961: *-SYNOPSIS: ! 6962: * #include <sys/types.h> ! 6963: * #include <sys/stream.h> ! 6964: * ! 6965: * void unfreezestr (queue_t * q, pl_t prev_pl); ! 6966: * ! 6967: *-ARGUMENTS: ! 6968: * q Pointer to a message queue. ! 6969: * ! 6970: * pl The interrupt priority level to be set (if the ! 6971: * implementation requires that interrupts be blocked in ! 6972: * order to prevent deadlock) after unfreezing the ! 6973: * stream. See LOCK_ALLOC () for a list of valid values ! 6974: * for "pl". "pl" should be the value that was returned ! 6975: * from the corresponding call to freezestr () unless the ! 6976: * caller has a specific need to set some other interrupt ! 6977: * priority level. Although portable drivers must always ! 6978: * specify an appropriate "pl" argument, implementations ! 6979: * which do not require that the interrupt priority be ! 6980: * raised while the stream is frozen may choose to ignore ! 6981: * this argument. ! 6982: * ! 6983: *-DESCRIPTION: ! 6984: * unfreezestr () unfreezes the state of the stream containing the queue ! 6985: * specified by "q", and sets the interrupt priority level to the value ! 6986: * specified by "pl". Unfreezing the state of the stream allows ! 6987: * continuation of all activities that were forced to wait while the ! 6988: * stream was frozen. ! 6989: * ! 6990: *-RETURN VALUE: ! 6991: * None. ! 6992: * ! 6993: *-LEVEL: ! 6994: * Base or interrupt. ! 6995: * ! 6996: *-NOTES: ! 6997: * Does not sleep. ! 6998: * ! 6999: * The caller must have the stream frozen [see freezestr ()] when calling ! 7000: * this function. ! 7001: * ! 7002: * Driver-defined basic locks, read/write locks, and sleep locks may be ! 7003: * held across calls to this function. ! 7004: * ! 7005: *-SEE ALSO: ! 7006: * freezestr () ! 7007: */ ! 7008: ! 7009: #if __USE_PROTO__ ! 7010: void (unfreezestr) (queue_t * q, pl_t pl) ! 7011: #else ! 7012: void ! 7013: unfreezestr __ARGS ((q, pl)) ! 7014: queue_t * q; ! 7015: pl_t pl; ! 7016: #endif ! 7017: { ! 7018: unsigned long back; ! 7019: ! 7020: QFROZEN_TRACE (q, "unfreezestr"); ! 7021: ! 7022: /* ! 7023: * Since the caller might have used rmvq () to cause a condition where ! 7024: * queues behind the current one need back-enabling, test for this. ! 7025: */ ! 7026: ! 7027: if ((back = q->q_flag & QBACK) != 0) ! 7028: q->q_flag &= ~ QBACK; ! 7029: ! 7030: QUNFREEZE_TRACE (q, pl); ! 7031: ! 7032: if (back) ! 7033: QUEUE_BACKENAB (q); ! 7034: } ! 7035: ! 7036: ! 7037: /* ! 7038: *-STATUS: ! 7039: * DDI/DKI ! 7040: * ! 7041: *-NAME: ! 7042: * unlinkb Remove a message block from the head of a message. ! 7043: * ! 7044: *-SYNOPSIS: ! 7045: * #include <sys/stream.h> ! 7046: * ! 7047: * mblk_t * unlinkb (mblk_t * mp); ! 7048: * ! 7049: *-ARGUMENTS: ! 7050: * mp Pointer to the message. ! 7051: * ! 7052: *-DESCRIPTION: ! 7053: * unlinkb () removes the first message block from the message pointed to ! 7054: * by "mp". The removed message block is not freed. It is the caller's ! 7055: * responsibility to free it. ! 7056: * ! 7057: *-RETURN VALUE: ! 7058: * unlinkb () returns a pointer to the remainder of the message after the ! 7059: * first message block has been removed. If there is only one message ! 7060: * block in the message, NULL is returned. ! 7061: * ! 7062: *-LEVEL: ! 7063: * Base or interrupt. ! 7064: * ! 7065: *-NOTES: ! 7066: * Does not sleep. ! 7067: * ! 7068: * Driver-defined basic locks, read/write locks, and sleep locks may be ! 7069: * held across calls to this function. ! 7070: * ! 7071: *-SEE ALSO: ! 7072: * linkb () ! 7073: */ ! 7074: ! 7075: #if __USE_PROTO__ ! 7076: mblk_t * (unlinkb) (mblk_t * mp) ! 7077: #else ! 7078: mblk_t * ! 7079: unlinkb __ARGS ((mp)) ! 7080: mblk_t * mp; ! 7081: #endif ! 7082: { ! 7083: mblk_t * retval; ! 7084: ! 7085: ASSERT (mp != NULL); ! 7086: ! 7087: retval = mp->b_cont; ! 7088: mp->b_cont = NULL; ! 7089: ! 7090: return retval; ! 7091: } ! 7092: ! 7093: ! 7094: /* ! 7095: *-STATUS: ! 7096: * DDI/DKI ! 7097: * ! 7098: *-NAME: ! 7099: * WR Get a pointer to the write queue. ! 7100: * ! 7101: *-SYNOPSIS: ! 7102: * #include <sys/stream.h> ! 7103: * ! 7104: * queue_t * WR (queue_t * q); ! 7105: * ! 7106: *-ARGUMENTS: ! 7107: * q Pointer to the queue whose write queue is to be ! 7108: * returned. ! 7109: * ! 7110: *-DESCRIPTION: ! 7111: * The WR () function accepts a queue pointer as an argument and returns ! 7112: * a pointer to the write queue of the same module. ! 7113: * ! 7114: *-RETURN VALUE: ! 7115: * To pointer to the write queue. ! 7116: * ! 7117: *-LEVEL: ! 7118: * Base or interrupt. ! 7119: * ! 7120: *-NOTES: ! 7121: * Does not sleep. ! 7122: * ! 7123: * Driver-defined basic locks, read/write locks, and sleep locks may be ! 7124: * held across calls to this function. ! 7125: * ! 7126: *-SEE ALSO: ! 7127: * OTHERQ (), RD (). ! 7128: */ ! 7129: ! 7130: #if __USE_PROTO__ ! 7131: queue_t * (WR) (queue_t * q) ! 7132: #else ! 7133: queue_t * ! 7134: WR __ARGS ((q)) ! 7135: queue_t * q; ! 7136: #endif ! 7137: { ! 7138: QUEUE_TRACE (q, "WR"); ! 7139: ! 7140: return WR (q); ! 7141: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.