ID Number: Q61568
2.00
OS/2
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);
}
}