|
|
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.