OpenSS7
SS7 for the
Common Man
© Copyright 1997-2007 OpenSS7 Corporation All Rights Reserved.
Last modified: Sat, 01 Nov 2008 10:41:53 GMT
Home TopIndex FirstPrev Next LastMore Download Info FAQ Mail  Home -> Documentation -> Man Pages -> Manual Page
Quick Links

Download

SCTP

SIGTRAN

SS7

Hardware

STREAMS

Asterisk

Related

Package

Manual

FAQ

Man Pages

Applications

SS7 Stack

ISDN Stack

SIGTRAN Stack

VoIP Stack

MG Stack

SS7/ISDN Devices

IP Transport

Embedded Systems

OS

Documentation

FAQ

SIGTRAN

Design

Conformance

Performance

References

Man Pages

Manuals

Papers

Home

Overview

Status

Documentation

Resources

About

News

Description: Manual Page

Keywords: 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 compactpci


CANPUTNEXT

Section: Linux Fast-STREAMS DDI/DKI (9)
Updated: 2008-10-31
Index Return to Main Contents

NAME

canputnext - test flow control on a STREAMS message queue

SYNOPSIS

#include <sys/stream.h>

int canputnext(queue_t *q);

ARGUMENTS

q

the queue to check for downstream flow control.

INTERFACE

STREAMS.

DESCRIPTION

It is the responsibility of a STREAMS module passing a normal priority, band zero (0), message to the next queue, to check for flow control using canputnext() before passing the message with putnext(9).

canputnext() checks whether the Stream is flow controlled starting at q->q_next. canputnext() 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 flag clear indicating that it is not full, then canputnext() will return true (1).

If the first queue has the QFULL flag set indicating that it is full, then canputnext() will set the QWANTW flag and return false (0).

canputnext() sets the QWANTW 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 once the flow controlled queue is no longer full (i.e. messages have been read from the queue to reduce the queue count beneath the low water mark for the queue, or emptying the queue, clearing the QFULL flag).

USAGE

It is the responsibility of all STREAMS modules with a qi_srvp(9) service procedure passing a normal priority, data message (M_PROTO(9), M_DATA(9)) to the next queue, to check for flow control using canputnext() or bcanputnext(9), for the b_band of the message, before passing a message to the queue with putnext(9). Modules without a qi_srvp(9) service procedure do not check flow control. Each module with a qi_srvp(9) service procedure is responsible for checking flow control before passing a message along a Stream. Flow control is checked using canputnext() or bcanputnext(9).

canputnext() and bcanputnext(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_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, canputnext(9) and bcanputnext(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)].

RETURN

canputnext() will return false (0) when the specified STREAMS message queue is flow controlled and returns true (1) when the specified STREAMS message queue is not flow controlled.

ERRORS

canputnext() always succeeds for a valid q. If q is invalid, the result is undefined. It is invalid to pass canputnext() a q where q->q_next is NULL.

CONTEXT

canputnext() can be called from any context, including user context, module procedures, callouts, callbacks, soft interrupts (tasklets and bottom halves), and interrupt service routines.

MP-STREAMS

canputnext() 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 the queue beyond a driver's upper multiplex 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 canputnext() 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 canputnext() 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 canputnext() is called from a qi_putp(9) put procedure), or putbq(9) (in the case canputnext() 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 canput(q->q_next) is functionally equivalent to canputnext(q), for the canput(9) form, the dereference of the q->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 canputnext() instead of canput(q->q_next).

For maximum portability and compatibility, canputnext(q) under Linux Fast-STREAMS is always MP-safe from any context and for any q whose validity the caller can guarantee across the call.

NOTICES

It is the responsibility of a STREAMS driver or module passing a normal priority, band zero (0), message to an adjacent queue to check for flow control using canputnext() before passing a message to the queue with putnext(9).

canputnext() and bcanputnext(9) should always be used instead of canput(q->q_next) and bcanput(q->q_next) on multiprocessor (MP) implementations.

canputnext() 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() are the equivalent of bcanput(9) 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 canputnext() 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 canputnext() always returns true (1) in this situation. The SVR 4 SPG[2] stays that canputnext() 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, canputnext() 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 canputnext(); if the put procedure does place messages with putq(9), without a service procedure, canputnext() will act as expected by the description in the SVR 4 SPG[2]. See also USAGE , above.

IMPLEMENTATION

canputnext() uses atomic bit operations and does not require locking of the queue structure. Therefore, canputnext() can be called for a q that is frozen with freezestr(9).

EXAMPLES

Example #1 --- Put Procedure

canputnext() is normally called before a call to putnext(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                          || canputnext(uq, mp->b_band))) {
 9          /* put to upper if we are empty and upper is
10             not flow controlled */
11          putnext(uq, mp);
12      } else {
13          /* put to our own queue otherwise */
14          putq(q, mp);
15      }
16  }

Above, the example uses canputnext() 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 Routine

canputnext() is typically called before a call to putnext(9) in a driver interrupt service routine as follows:

 1  int
 2  example_putp(queue_t *q, mblk_t *mp)
 3  {
 4      if (canputnext(q)) {
 5          putnext(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)
16  {
17      mblk_t *mp;
18  
19      if ((mp = allocb(len, BRPI_HI))) {
20          bcopy(buf, mp->b_wptr, len);
21          mp->b_wptr += len;
22          put(q, mp);
23          return (1);
24      }
25      return (0);
26  }

The above example is left as an exercise to the reader.

Example #3 --- Alternative ISR

Another 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                  && canputnext(q))) {
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              && canputnext(q))) {
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)
34  {
35      mblk_t *mp;
36  
37      if (!canputnext(q))
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 Module

Following is an example of the cannonical module non-band-aware, 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 && canputnext(q)) {
 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 (canputnext(q)) {
20              putnext(q, mp);
21          } else {
22              putbq(q, mp);
23              break;
24          }
25      }
26      return (0);
27  }

SEE ALSO

putnext(9), canput(9), bcanput(9), bcanputnext(9), freezestr(9), noenable(9), and enableok(9).

BUGS

canputnext() has no known bugs.

COMPATIBILITY

canputnext() is compatible with SVR 4.2 MP DDI/DKI[4], and implementations based on SVR 4.2 MP[5], with the following portability considerations:

---
Because all STREAMS drivers and modules will be aware of queue priority bands when performing flow control, use of canputnext() is not very useful and the band aware bcanputnext(9) should be used in its stead. canputnext() is only provided for use by drivers and modules that either have no need to support queue bands (e.g., on a driver read queue for a driver that never places non-zero priority messages on the queue), or were written to the earlier SVR 3[6] specification that did not include queue bands; however, SVR 3 did not support the MP-supporting canputnext() either.
Portable STREAMS drivers and reusable modules will call bcanputnext(9) instead of canputnext() in all cases where it cannot be guaranteed that the driver or module will not receive a non-zero priority message to the queue. (Some might even go to the extent of setting b_band to zero in all messages received by the qi_putp(9) put procedure.)
---
HP-UX®[7] lists canputnext() as a function that can only be passed a queue in the queue pair currently being synchronized within a module procedure. HP-UX®[7] also lists canputnext() as a utility that cannot be called from user functions or non-STREAMS code; that is, contexts asynchronous to the Stream containing q. HP-UX® compatible drivers and modules will not call canputnext() from outside of a qinit(9) routine for the queue pair of q.
Solaris[8], does the reverse: canputnext() and bcanputnext(9) can be called from outside of STREAMS, but canput(9) and bcanput(9) cannot. Solaris® compatible drivers and modules will not call canput(9) from outside of a qinit(9) routine for the queue pair of q.
canputnext() under Linux Fast-STREAMS can be passed any valid q pointer from any context, and the q_next pointer from any q synchronous context, and remain MP-safe. Therefore, there are no compatibility issues for Linux Fast-STREAMS.
---
canputnext() is MP-safe. Under LiS, canputnext() does not protect dereferencing of queue pointers during the search for a queue or band limited queue.
---
canputnext() always succeeds. Under LiS, canput() will return zero (0 - flow controlled) if an internal error occurs, without setting the QWANTW or QB_WANTW flag for the queue or band. This means that, although flow controlled, no back-enable procedure will be run. This can lead to indefinite postponement of a queue qi_srvp(9) procedure under LiS. Linux Fast-STREAMS[9] canputnext() does not have this problem.
Portable STREAMS drivers and modules will use Linux Fast-STREAMS[9] instead of LiS.
---
canputnext() called with a NULL or invalid q pointer will have undefined results and may crash or destabilize the kernel. Under LiS, if canputnext() suffers an internal error, q is NULL, or points to a structure other than a queue_t structure, it will return false (0).
Portable STREAMS drivers and modules will not pass NULL or invalid arguments to STREAMS functions. Portable STREAMS drivers and modules will use Linux Fast-STREAMS instead of LiS.
---
Although a call to bcanputnext(q, 0) is functionally equivalent to canputnext(q), canputnext() is implemented separately from bcanputnext() for speed. LiS implements canput(q), canputnext(q) and bcanputnext(q, band) with macros that call bcanput(q, band). This means that the LiS implementation of canputnext() suffers all of the same difficulties as its implementation of bcanput(9). See COMPATIBILITY , under bcanput(9), for details.
Portable STREAMS drivers and modules will use Linux Fast-STREAMS instead of LiS.
---
canputnext() explicitly protects dereferencing of the q->q_next pointer with the Stream head read lock that prevents reconfiguration of the Stream during the call. LiS does not explicitly protect this dereference.
Portable STREAMS drivers and modules will use Linux Fast-STREAMS instead of LiS.
---
canputnext() called with an invalid q pointer or a q pointer that has an invalid q->q_next pointer, will have undefined results and may crash or destabilize the kernel. LiS will return false (0) under the same conditions. STREAMS drivers and modules that always obtain q from a pointer passed by the STREAMS scheduler via qi_qopen(9), qi_qclose(9), qi_putp(9), qi_srvp(9), (as is normal) will not encounter this problem.
---
HP-UX®[7] allows canput(9) (but not canputnext()) to be called from outside the STREAMS framework, but it cannot be passed a q->q_next pointer, even from within the framework. This is the reverse of Solaris®, below. HP-UX®, documented rules[7] are more restrictive than Linux Fast-STREAMS, so there are no portability issues.
Solaris®[3], on the other hand, allows canputnext() (but not canput(9)) to be called from outside the STREAMS framework, but it cannot be passed a q->q_next pointer, even from within the framework. This is the reverse of HP-UX®, above. Solaris®, documented rules[3] are more restrictive than Linux Fast-STREAMS, so there are no portability issues.
---
canputnext() may be called on a Stream frozen with freezestr(9). SVR 4.2 MP DDI/DKI[4], Solaris®[3], SUPER-UX®[10] and UnixWare®[11] do not permit canputnext() to be called on a Stream frozen with freezestr(9).
Portable STREAMS drivers and modules will not call canputnext() on a Stream frozen with freezestr(9).
---
canputnext() is an SVR 4.2 function, not a macro. LiS implements canput(q), canputnext(q), bcanput(q, band), and bcanputnext(q, band), with a macros that call bcanput(q, band)
or bcanput(q->q_next, 0). This makes canputnext() and bcanputnext(9) unsafe under LiS across a multiplexing driver.
Portable STREAMS drivers and modules will use Linux Fast-STREAMS instead of LiS.
---
All versions of LiS contain the bug that they keep track of message queue counts, q_count, qb_count, in terms of the sum of the absolute sizes of the data buffers referenced by message blocks, (db_lim - db_base), and not the sizes of the message blocks themselves, (b_wptr - b_rptr), which does not conform to SVR 4.2 STREAMS[5]. See msgsize(9). No other implementation has this bug.
Portable STREAMS applications programs, drivers and modules will use Linux Fast-STREAMS instead of LiS.
---
Binary compatibility is not guaranteed.

See STREAMS(9) for additional compatibility information.

CONFORMANCE

SVR 4.2 MP DDI/DKI[4,5].

HISTORY

canputnext() first appeared in SVR 4.0 MP and SVR 4.2 MP[4,12].

REFERENCES

[1]
UnixWare® 7.1.3, UnixWare 7.1.3 (OpenUnix 8) Documentation, 2002, (Lindon, Utah), Caldera International, Inc., Caldera. <http://uw713doc.sco.com/>
[2]
SVR 4, UNIX® System V Release 4 STREAMS Programmer's Guide, 1990, (Englewood Cliffs, New Jersey), AT&T UNIX System Laboratories, Inc., Prentice Hall.
[3]
Solaris® 8, STREAMS Programming Guide, August 1999, (Palo Alto, California), Sun Microsystems, Inc., Sun. [Part No: 805-7478-05] <http://docs-pdf.sun.com/>
[4]
USL DDI/DKI, Device Driver Interface/Driver-Kernel Interface (DDI/DKI) Reference Manual for Intel Processors, 1992, (Englewood Cliffs, New Jersey), AT&T UNIX System Laboratories, Inc., Prentice Hall.
[5]
SVR 4.2, STREAMS Programmer's Guide, 1992, (Englewood Cliffs, New Jersey), AT&T UNIX System Laboratories, Inc., Prentice Hall.
[6]
SVR 3, UNIX® System V Release 3 Programmer's Manual, (Englewood Cliffs, New Jersey), AT&T UNIX System Laboratories, Inc., Prentice Hall.
[7]
HP-UX STREAMS, STREAMS Programmer's Guide -- HP 9000 and Integrity Server Computer Systems, October 2005, (Palo Alto, California), Hewlett-Packard Development Company L.P., HP. <http://docs.hp.com/>
[8]
Solaris® 8, Solaris 8 Docmentation, 2001, (Santa Clara, California), Sun Microsystems, Inc., Sun. <http://docs.sun.com/>
[9]
streams-0.9.2, Linux Fast-STREAMS (LfS) 0.9.2 Source Code, Brian Bidulock, ed., OpenSS7 Corporation. <http://www.openss7.org/>
[10]
SUPER-UX® Release 9.2, SUPER-UX STREAMS Programmers Guide, 1999, NEC Corporation, NEC.
[11]
UnixWare® 7.1.3, UnixWare® 7 STREAMS Programmer's Guide, 2002, (Lindon, Utah), Caldera International, Inc., Caldera. <http://uw713doc.sco.com/>
[12]
SVR 4 DDI/DKI, UNIX® System V Release 4 Device Driver Interface/Driver-Kernel Interface (DDI/DKI) Reference Manual, 1990, (Englewood Cliffs, New Jersey), AT&T UNIX System Laboratories, Inc., Prentice Hall.

TRADEMARKS

OpenSS7tm
is a trademark of OpenSS7 Corporation.
Linux®
is a registered trademark of Linus Torvalds.
UNIX®
is a registered trademark of The Open Group.
Solaris®
is a registered trademark of Sun Microsystems.

Other trademarks are the property of their respective owners.

IDENTIFICATION


Linux Fast-STREAMS: Package streams version 0.9.2.4 released 2008-10-31.

Copyright©1997-2008OpenSS7 Corp. All Rights Reserved.
(See roff source for permission notice.)



Index

NAME
SYNOPSIS
ARGUMENTS
INTERFACE
DESCRIPTION
USAGE
RETURN
ERRORS
CONTEXT
MP-STREAMS
NOTICES
IMPLEMENTATION
EXAMPLES
Example #1 --- Put Procedure
Example #2 --- Interrupt Service Routine
Example #3 --- Alternative ISR
Example #4 --- Cannonical Module
SEE ALSO
BUGS
COMPATIBILITY
CONFORMANCE
HISTORY
REFERENCES
TRADEMARKS
IDENTIFICATION

This document was created by man2html, using the manual pages.
Time: 09:10:58 GMT, May 19, 2013
OpenSS7
SS7 for the
Common Man
Home TopIndex FirstPrev Next LastMore Download Info FAQ Mail  Home -> Documentation -> Man Pages -> Manual Page
Last modified: Sat, 01 Nov 2008 10:41:53 GMT
© Copyright 1997-2007 OpenSS7 Corporation All Rights Reserved.