Q61568: Processing Data Returned from DosQNmPipeSemState()
Article: Q61568
Product(s): Microsoft LAN Manager
Version(s):
Operating System(s):
Keyword(s):
Last Modified: 30-JUL-2001
SUMMARY
=======
DosQNmPipeSemState() returns information in the form of PIPESEMSTATE structures.
In earlier releases, these structures were named "npss". The following are
frequently asked questions involving these structures:
1. Q. How much space do you have to pass to DosQNmPipeSemState() to hold the
PIPESEMSTATE structures returned?
a. You can set the variable "pipes" to the number of pipes associated with
the semaphore you pass to DosQNmPipeSemState(), and then use the following
statement to calculate the buffer size:
USHORT PipeInfoSize=((3*pipes)+1)*sizeof(PIPESEMSTATE);
2. Q. In what order does DosQNmPipeSemState() return the PIPESEMSTATE
structures?
a. An application cannot safely make any assumptions about the order
returned, because the order is not specified. Since the order is not
specified, the order may change; therefore, do not rely on any order that
may appear in the current releases of OS/2.
MORE INFORMATION
================
More detailed information regarding the above questions is as follows:
1. [How much space do you have to pass to DosQNmPipeSemState() to hold the
PIPESEMSTATE structures returned?]
OS/2 does not allocate any space to hold PIPESEMSTATE structures. Each time
you call DosQNmPipeSemState(), OS/2 looks at each named pipe currently
associated with the semaphore you passed to DosQNmPipeSemState(), and builds
the PIPESEMSTATE structures in the buffer you passed to
DosQNmPipeSemState().
In other words, each time you call DosQNmPipeSemState(), OS/2 builds the
PIPESEMSTATE structures "on the fly" into the buffer you pass.
If the buffer you pass to DosQNmPipeSemState() is not big enough to hold all
the PIPESEMSTATE structures that OS/2 might have returned, OS/2 just stops
building PIPESEMSTATE structures into your buffer, and returns the ones it
was able to build before the buffer filled up.
Although you can check the DosQNmPipeSemState() return code to see whether the
buffer you passed was too small, the only practical approach to use is to
pass DosQNmPipeSemState() a buffer you know in advance will be large enough
to hold all of the structures.
The reason for this is that if the buffer is too small, no PIPESEMSTATE
structures may have been returned at all for some of the named pipes
associated with the semaphore.
If the return code from DosQNmPipeSemState() states that the buffer was too
small, you cannot call DosQNmPipeSemState() again with the same size buffer
to get the rest of the PIPESEMSTATE structures that would not fit in the
buffer on the previous call. You can, of course, make as many calls as you
want; however, subsequent calls do not get "the rest of the PIPESEMSTATE
structures"; subsequent calls build complete new lists of PIPESEMSTATE
structures.
Trying to get "the rest of the PIPESEMSTATE structures" will cause
DosQNmPipeSemState() to again build PIPESEMSTATE structures on the fly into
the buffer, and will probably again return no PIPESEMSTATE structures at all
for the same named pipes associated with the semaphore for which it returned
no PIPESEMSTATE structures the first time you called DosQNmPipeSemState().
This is because DosQNmPipeSemState() builds PIPESEMSTATE structures into the
buffer on the fly, and DosQNmPipeSemState() keeps no records of what named
pipes were previously successfully queried.
Therefore, it is fine to call again if the return code states that the buffer
was too small; however, remember that the second call will behave as if the
first call had not been made.
For some other OS/2 APIs, a practical approach to use is to make the call with
a buffer you know is too small, and have the API return to you how much data
was available (total). You then can allocate a buffer of that size, and make
the call again. This approach allows you to allocate a buffer not one byte
larger than is needed for those other APIs. This approach, however, does not
work for DosQNmPipeSemState(), because DosQNmPipeSemState() gives no
indication of how much data is available.
Fortunately, the approach mentioned above as "the only practical approach" for
DosQNmPipeSemState() is simple, but not costly, for most applications.
Allocating a buffer you know in advance is large enough costs about 18 bytes
per pipe associated with the semaphore, because the PIPESEMSTATE structures
are only 6 bytes long, and you need to allocate three of them per pipe.
As mentioned above, set the variable "pipes" to the number of pipes associated
with the semaphore you pass to DosQNmPipeSemState(), then use the following
statement to calculate the buffer size:
USHORT PipeInfoSize=((3*pipes)+1)*sizeof(PIPESEMSTATE);
This allocates space for three PIPESEMSTATE structures per pipe associated
with the semaphore, plus space for one PIPESEMSTATE structure for the
NPSS_EOI (end of information) structure that is always returned at the end of
the buffer.
The three PIPESEMSTATES structures per pipe must be allocated because at most,
DosQNmPipeSemState() will return for each pipe associated with the semaphore
one NPSS_RDATA, one NPSS_WSPACE, and one NPSS_CLOSE PIPESEMSTATE structure.
NPSS_RDATA, NPSS_WSPACE, and NPSS_CLOSE are defined in BSEDOS.H. The following
is an extract from BSEDOS.H for your convenience:
#define NPSS_EOI 0 /* End Of Information */
#define NPSS_RDATA 1 /* read data available */
#define NPSS_WSPACE 2 /* write space available */
#define NPSS_CLOSE 3 /* pipe in CLOSING state */
For some applications, it might be possible to get by with a little less than
((3*pipes)+1)*sizeof(PIPESEMSTATE) because you know at a certain point that
there cannot be any data to read in a certain pipe, or there cannot be any
write space available, or the pipe cannot be closing.
However, please remember that you save only 6 bytes per PIPESEMSTATE structure
you do not allocate. In most cases, saving only 6 bytes is not worth the risk
that the buffer you pass will be too small.
It is not recommended that you attempt to save 5 bytes by only allocating 1
byte in the buffer for the NPSS_EOI structure instead of the full 6. This may
work in some releases of OS/2; however, the specified behavior is that the
NPSS_EOI structure is a PIPESEMSTATE structure. Therefore, you should
allocate the same space for it as you would for the other structures.
To summarize the information for question 1: the recommended approach is to
use the following statement to calculate the buffer size:
USHORT PipeInfoSize=((3*pipes)+1)*sizeof(PIPESEMSTATE);
It is not recommended that you try to get by with less, because the risks
outweigh the number of bytes you might save.
2. [In what order does DosQNmPipeSemState() return the PIPESEMSTATE
structures?]
There is no specific order in which DosQNmPipeSemState() must return the
PIPESEMSTATE structures in the buffer. Therefore, the application should not
make any assumptions about the order of these structures.
The current releases of OS/2 return the PIPESEMSTATE structures in the
following order:
NPSS_CLOSE (optional)
NPSS_WSPACE (optional)
NPSS_RDATA (optional)
The NPSS_CLOSE structure comes first for a given pipe, if the pipe is closing;
followed by the NPSS_WSPACE structure if there is write space available for
that same given pipe; followed by the NPSS_RDATA structure, if that same
given pipe has any read data available. Then, more PIPESEMSTATE structures
follow in the same order for any other pipes associated with the semaphore.
It is not safe to assume that this type of ordering scheme will continue to be
used in all future releases of OS/2. An application should process the
PIPESEMSTATE structures returned in the buffer in such a way that any order
in which the PIPESEMSTATE structures are needed is guaranteed by the way the
buffer is processed.
For example, suppose you want to see any NPSS_CLOSE structures first. You then
can record the fact that a pipe is closing, so you will know, when later
processing the NPSS_RDATA structure, that the pipe is closing; therefore,
trying to write to it will not work. Similarly, you might want to see any
NPSS_WSPACE structures before the NPSS_RDATA structures, so you need to know
ahead of time how much can be written into the pipe in response to the
NPSS_RDATA structures.
Please note that the sample ordering in the preceding paragraph seems to be
one of the most practical orderings, and also happens to be the ordering that
current releases of OS/2 seem to provide. Nevertheless, rather than relying
on the fact that current releases of OS/2 seem to provide exactly that order,
if that is the order you need, the code should be written so that order will
happen even if OS/2 changes in the future.
To attain this ordering, loop twice through the buffer returned. In the first
loop, look for and record any NPSS_WSPACE and/or NPSS_CLOSE structures. Then,
in the second loop, look for and process any NPSS_RDATA structures.
Guaranteeing this order in your code costs an extra loop, and a place to
record for each pipe whether it is closing and how much write space is
available. For applications where DosQNmPipeSemState() returns extremely long
lists of PIPESEMSTATE structures, a different approach can be used. For
example, you might loop through the buffer returned just once, recording the
NPSS_RDATA structures along with the NPSS_WSPACE and/or NPSS_CLOSE
structures. Then in the second loop, loop through the array of pipes (instead
of a second loop through the buffer).
To summarize the answer to Question 2: You should not rely on the order in
which current releases of OS/2 happen to return the PIPESEMSTATE structures.
Your code should be written (as in the example below) to explicitly process
the PIPESEMSTATE structures in the order your applications require.
// Your application might not need this first resetting loop. In
// fact, this first resetting loop may be wrong for some
// applications.
for (i = 0; i < pipes; i++) {
hPipes[i].usWriteSpace = 0;
hPipes[i].bClosing = FALSE;
}
for (pInfo = PipeInfo; NPSS_EOI != pInfo->fStatus; pInfo++) {
if (NPSS_WSPACE == pInfo->fStatus)
hPipes[pInfo->usKey].usWriteSpace = pInfo->usAvail;
else if (NPSS_CLOSE == pInfo->fStatus)
hPipes[pInfo->usKey].bClosing = TRUE;
}
for (pInfo = PipeInfo; NPSS_EOI != pInfo->fStatus; pInfo++) {
if (NPSS_RDATA==pInfo->fStatus) {
hPipes[pInfo->usKey].pData=malloc(pInfo->usAvail);
rc=DosRead(hPipes[pInfo->usKey].hP,hPipes[pInfo->usKey].pData
,pInfo->usAvail,&uReadBytes);
if (0!=rc)
printf("\n\rRead error: rc=%d",rc);
else {
printf("\n\rJust read: %s",hPipes[pInfo->usKey].pData);
if (hPipes[pInfo->usKey].bClosing) {
printf("\n\rCan't write, pipe's closed");
}
else if (hPipes[pInfo->usKey].usWriteSpace <= 0) {
printf("\n\rCan't write, no space available");
}
else {
// For this example, ignore the possibility that some
// write space might not be enough.
// For this example, just write back the message received.
rc=DosWrite(hPipes[pInfo->usKey].hP
,hPipes[pInfo->usKey].pData
,(strlen(hPipes[pInfo->usKey].pData)+1)
,&uWriteBytes);
if (0!=rc)
printf("\n\rWrite error: rc=%d",rc);
}
}
free(hPipes[pInfo->usKey].pData);
}
}
Additional query words: 2.00 2.10 2.10a 2.20
======================================================================
Keywords :
=============================================================================
THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FOREGOING LIMITATION MAY NOT APPLY.
Copyright Microsoft Corporation 1986-2002.