| OpenSS7 SS7 for the Common Man | © Copyright 1997-2007 OpenSS7 Corporation All Rights Reserved. Last modified: Sat, 01 Nov 2008 10:41:53 GMT | ||||||||||||||||
| |||||||||||||||||
| Manpage of BCANPUTDescription: Manual PageKeywords: ss7 ss7/ip ss7 over ip ss7 mtp ss7 sccp ss7 tcap sigtran mtp sccp tcap openss7 acb56 linux telephony pstn linux telephony linux nebs linux compactpciBCANPUTSection: Linux Fast-STREAMS DDI/DKI (9)Updated: 2008-10-31 Index Return to Main Contents NAMEbcanput - test flow control on a STREAMS message queueSYNOPSIS#include <sys/stream.h>
ARGUMENTS
INTERFACEDESCRIPTIONbcanput() checks whether the Stream is flow controlled starting at q, and for band. bcanput() looks for the first queue with a qi_srvp(9) service procedure, or no next queue (i.e. the q_next pointer is NULL). If the first queue has the QFULL (band == 0) or QB_FULL (band >= 1) flag clear indicating that it is not full for the specified band, or a qband(9) structure does not yet exist for the specified band (band >= 1), then bcanput() will return true (1). If the first queue has the QFULL (band == 0) or QB_FULL (band >= 1) flag set indicating that it is full for the specified band, and a qband(9) structure exists for the specified band (band >= 1), then bcanput() will set the QWANTW (band == 0) or QB_WANTW (band >= 1) flag and return false (0). bcanput() sets the QWANTW or QB_WANTW flag so that rmvq(9), getq(9), flushq(9), or flushband(9), will back-enable the qi_srvp(9) service procedure feeding the flow controlled queue or queue band once the flow controlled queue or queue band is no longer full (i.e. messages have been read from the queue to reduce the queue or queue band count beneath the low water mark for the queue or queue band, or emptying the queue, clearing the QFULL or QB_FULL flag). USAGEIt is the responsibility of all STREAMS drivers putting a normal priority data message (M_PROTO(9), M_DATA(9)) to a message queue at a Stream end to check for flow control using canput(9) or bcanput(9) for the b_band of the message before placing a message on the queue with put(9) or putq(9). Each Stream head, Stream end and multiplexing driver is responsible for checking flow control before passing a message onto a Stream. Flow control is checked using one of canput(9) or bcanput(9). STREAMS modules have different responsibilities, see USAGE under canputnext(9) or bcanputnext(9). canput(9) and bcanput(9) will perform actions on a forward queue with no queue qi_srvp(9) service procedure, but for which there is no forward queue (q->q_next is NULL). The reason for this is that a write queue at the Stream end (driver) might remove messages from the message queue under conditions other than a service procedure. For example, a driver write queue qi_putp(9) put procedure could be designed to place all messages from the data stream onto the message queue. When a transmit interrupt service routine runs, it can take message off of the queue using rmvq(9) and use the messages so removed to fill the device's transmit buffer. For flow control to work correctly in this situation, canput(9) and bcanput(9) must still set the QWANTW or QB_WANTW flag when it encounters a driver write queue or queue band with the QFULL or QB_FULL flag set, so that getq(9), rmvq(9), flushq(9), flushband(9), called from the interrupt service routine will still back-enable the Stream, [see qbackenable(9)]. RETURNbcanput() will return false (0) when the specified STREAMS message queue is flow controlled for the specified band, and returns true (1) when the specified STREAMS message queue is not flow controlled for the specified band, or the specified band has not yet been written to. ERRORSbcanput() always succeeds for a valid q. If q is invalid, the result is undefined. CONTEXTbcanput() can be called from any context, including user context, module procedures, callouts, callbacks, soft interrupts (tasklets and bottom halves), and interrupt service routines. MP-STREAMSbcanput() is MP-safe when called from any context. However, the caller is responsible for the validity of the passed in queue pointer, q, across the call. The validity of either queue in the pair, and either q_next pointer for a queue in the pair, for the queue pointer passed to a module procedure, callout or synchronous callback functions, is guaranteed by Linux Fast-STREAMS. Any queue pointer in the pair passed as an argument to an asynchronous callback function is also valid, providing the driver or module observes the rules for cancellation of asynchronous callbacks on close. When wishing to test flow control on a driver's read queue from an interrupt service routine, where there is no qi_srvp(9) service procedure defined for the read queue, a more portable approach is to call put(9) instead and test flow control from within the read queue's qi_putp(9) put procedure. It is possible, due to race conditions in a multiprocessor (MP) system, that bcanput() can be called for a queue and return true (1) and yet the Stream becomes flow controlled before a call to putnext(9). The caller to putnext(9) is then in violation of flow-control rules; however, the extent of this violation is bounded. It is also possible, that bcanput() can be called for a queue and return false (0), and a queue utility retrieving a message from the full queue causes flow control to subside and the service procedure of the caller to become back-enabled before the call to putq(9) (in the case bcanput() is called from a qi_putp(9) put procedure), or putbq(9) (in the case bcanput() is called from a qi_srvp(9) service procedure). In the case that the service procedure runs before putq(9), placing the message on the queue will invoke the service procedure again, when necessary. In the case that the queue was enabled before putbq(9), execution of the service procedure will occur after the current service procedure exits. Although bcanput(q->q_next, band) is functionally equivalent to bcanputnext(q, band), for the bcanput(9) form, the dereference of the q_next pointer is not protected on some implementations of STREAMS for MP architectures: on which q_next may change as a result of a concurrent reconfiguration of the Stream (e.g. an I_PUSH or I_POP streamio(7) operation). For MP operation, portable STREAMS drivers and modules will always call bcanputnext(9) instead of bcanput(q->q_next, band). For maximum portability and compatibility, bcanput(q->q_next, band) under Linux Fast-STREAMS is always MP-safe from a module procedure or callout, or synchronous callback function that was passed q, or the queue pair containing q, (and is even safe for an asynchronous callback function passing q or q->q_next that was invoked from a procedure, callout or synchronous callback on q). NOTICESIt is the responsibility of a STREAMS driver putting a normal priority message to a message queue to check for flow control using bcanput() before placing a message on the queue with put(9) or putq(9). canputnext(9) and bcanputnext(9) will always be used instead of canput(q->q_next) or bcanput(q->q_next) by portable STREAMS drivers and modules on multiprocessor (MP) systems. canput(9) and canputnext(9) are the equivalent of bcanput() and bcanputnext(9) with a zero band: and are implemented as such. Note that there is some conflict in the documentation as to what happens when bcanput() hits the queue at end of the Stream (q->q_next is NULL) and the queue has no service procedure. Some implementations, notably UnixWare®[1], say bcanput() always returns true (1) in this situation. The SVR 4 SPG[2] stays that bcanput() searches for the a queue with a service procedure or which has no forward queue and then peforms the actions. This also consistent with Solaris®[3] behaviour. The SVR 4 SPG[2], however, also says that if a qi_putp(9) put procedure places a message onto its own queue with putq(9), that it requires a qi_srvp(9) service procedure. One would not then expect a queue without a service procedure to have anything but an empty message queue, and in that case, bcanput() can be expected to always return true (1) for it. Linux Fast-STREAMS performs the actions on the queue at the end of the Stream when it is reached regardless of whether it has a qi_srvp(9) service procedure or not. This is consistent with the description in the SVR 4 SPG[2] as well as Solaris® behaviour. If such a queue's qi_putp(9) put procedure never places message on the queue with putq(9), there will be no difference in the values returned to bcanput(); if the put procedure does place messages with putq(9), without a service procedure, bcanput() will act as expected by the description in the SVR 4 SPG[2]. See also USAGE , above. IMPLEMENTATIONLinux Fast-STREAMS[4] provides the additional feature that band can be specified as ANYBAND. When band is ANYBAND, bcanput() checks whether any band (other than band zero), is not flow controlled. If a band exists that is not flow controlled, bcanput() with ANYBAND returns one (1). If all existing bands are flow controlled, bcanput() returns zero (0). bcanput() uses atomic bit operations and does not require locking of the queue structure. Therefore, bcanput() can be called for a q that is frozen with freezestr(9). EXAMPLESExample #1 --- Put Procedurebcanput() is normally called before a call to putq(9) as follows:
1 void
2 example_putp(queue_t *q, mblk_t *mp)
3 {
4 priv_t p = (priv_t *) q->q_ptr;
5 queue_t *uq = p->upper_queue;
6
7 if (!q->q_count && (mp->b_datap->db_type >= QPCTL
8 || bcanput(uq, mp->b_band))) {
9 /* put to upper if we are empty and upper is
10 not flow controlled */
11 putq(uq, mp);
12 } else {
13 /* put to our own queue otherwise */
14 putq(q, mp);
15 }
16 }
Above, the example uses bcanput() from the lower queue qi_putp(9) procedure (in a multiplexing driver) to test the upper queue for flow control. If the upper queue is flow controlled, the message is placed on the lower queue. Otherwise, if the lower queue is empty and the upper queue is not flow controlled, the example places the message directly on the upper queue. Note that the upper queue must have a service procedure. Example #2 --- Interrupt Service Routinebcanput() is typically called before a call to put(9) in a driver interrupt service routine as follows:
1 int
2 example_putp(queue_t *q, mblk_t *mp)
3 {
4 if (bcanput(q, mp->b_band)) {
5 putq(q, mp);
6 } else {
7 some_global_flag_dropping = 1;
8 freemsg(mp);
9 }
10 return (0);
11 }
12
13 int
14 example_isr_handler(queue_t *q, caddr_t buf,
15 size_t len, unsigned char band)
16 {
17 mblk_t *mp;
18
19 if ((mp = allocb(len, BRPI_HI))) {
20 mp->b_band = band;
21 bcopy(buf, mp->b_wptr, len);
22 mp->b_wptr += len;
23 put(q, mp);
24 return (1);
25 }
26 return (0);
27 }
The above example is left as an exercise to the reader. Example #3 --- Alternative ISRAnother alternative for the ISR is to give the read side a service procedure and test before put(9) as follows:
1 int
2 example_srvp(queue_t *q)
3 {
4 mblk_t *mp;
5
6 while ((mp = getq(q))) {
7 if (mp->b_datap->db_type >= QPCTL
8 || (!q->q_first && !(q->q_flag & QSVCBUSY)
9 && bcanputnext(q, b->b_band))) {
10 putnext(q, mp);
11 continue;
12 }
13 putbq(q, mp);
14 return (0);
15 }
16 }
17
18 int
19 example_putp(queue_t *q, mblk_t *mp)
20 {
21 if (mp->b_datap->db_type >= QPCTL
22 || (!q->q_first && !(q->q_flag & QSVCBUSY)
23 && bcanputnext(q, b->b_band))) {
24 putnext(q, mp);
25 return (0);
26 }
27 putq(q, mp);
28 return (0);
29 }
30
31 int
32 example_isr_handler(queue_t *q, caddr_t buf,
33 size_t len, int band)
34 {
35 mblk_t *mp;
36
37 if (!bcanput(q, band))
38 return (0);
39 if ((mp = allocb(len, BPRI_HI))) {
40 bcopy(buf, mp->b_wptr, len);
41 mp->b_wptr += len;
42 put(q, mp);
43 return (1);
44 }
45 return (0);
46 }
The above example is also left as an excercise to the reader. Example #4 --- Cannonical ModuleFollowing is an example of the cannonical module band-aware, non-MP, put and service procedure (for a proper, band-aware, MP-safe example, see bcanputnext(9)):
1 int
2 example_putp(queue_t *q, mblk_t *mp)
3 {
4 if (mp->b_datap->db_type >= QPCTL) {
5 putnext(q, mp);
6 } else if (!q->q_first && bcanput(q->q_next, mp->b_band)) {
7 putnext(q, mp);
8 } else {
9 putq(q, mp);
10 }
11 return (0);
12 }
13 int
14 example_srvp(queue_t *q)
15 {
16 mblk_t *mp;
17
18 while ((mp = getq(q))) {
19 if (bcanput(q->q_next, mp->b_band)) {
20 putnext(q, mp);
21 } else {
22 putbq(q, mp);
23 break;
24 }
25 }
26 return (0);
27 }
SEE ALSOputq(9), canput(9), canputnext(9), bcanputnext(9), freezestr(9), noenable(9), enableok(9), STREAMS(9). BUGSCOMPATIBILITYbcanput() is compatible with SVR 4.2 MP DDI/DKI[5], and implementations based on SVR 4[2], with the following portability considerations:
See STREAMS(9) for additional compatibility information. CONFORMANCEHISTORYbcanput() first appeared in SVR 4.0 STREAMS[2]. Earlier versions of STREAMS (e.g. SVR 3)[11] did not have priority bands. REFERENCES
TRADEMARKS
Other trademarks are the property of their respective owners. IDENTIFICATION
Copyright©1997-2008OpenSS7 Corp.
All Rights Reserved.
Index
This document was created by man2html, using the manual pages. Time: 13:27:59 GMT, May 19, 2013 | ||||||||||||||||
| OpenSS7 SS7 for the Common Man |
| ||||||||||||||||
| Last modified: Sat, 01 Nov 2008 10:41:53 GMT © Copyright 1997-2007 OpenSS7 Corporation All Rights Reserved. |