MAINSAIL STREAMS User's Guide, Chapter 10

previous   next   top   contents   index   framed top   this page unframed


10. Low-level Stream I/O PROCEDUREs

Normally, programmers use remote PROCEDURE calls to implement distributed MAINSAIL programs. Occasionally, the RPC mechanism is not general enough, or the programmer may require more control over the stream than supported by RPC. The low-level stream I/O PROCEDUREs are supplied to provide an escape mechanism for such cases.

Note: The low-level streams PROCEDUREs are subject to change. RPC is sufficiently high-level that it is unlikely to experience significant change. Accordingly, RPC should be used in preference to low-level PROCEDUREs. Low-level streams PROCEDUREs should be used only when necessary, and the programmer should isolate such use so that changes in their formulation will be easily tracked in the application.

10.1. Low-Level Stream I/O PROCEDURE Conventions

Stream I/O consists of a flow of eight-bit character units. I/O to streams may be done to or from a supplied buffer, STRING, or an individual character. The type of buffer determines how the characters in the stream are interpreted and therefore how they are packed into the buffer or removed from the buffer.

10.1.1. Timeouts

Associated with each I/O PROCEDURE is a LONG INTEGER timeout value, the number of milliseconds to wait for the operation to complete. The timeout value may be a positive LONG INTEGER to cause the PROCEDURE to time out after that number of milliseconds, or one of the constants shown in Figure 10–1.

Figure 10–1. Special Timeout Values
LONG INTEGER
<
macro>   $poll;        # Return immediately

LONG INTEGER
<
macro>   $block;       # Block indefinitely (infinite timeout)

If timeout is omitted or $block is given, the PROCEDURE blocks indefinitely until something can be input/output or an error occurs. If timeout is greater than zero, it specifies a minimum amount of time in milliseconds to wait before returning a timeout failure. If timeout is $poll, the PROCEDURE returns immediately with either a success value or one of the error values described below, as applicable. $poll should always be used in conjunction with the errorOK bit. If the errorOK bit is not set and no I/O is ready, STREAMS PROCEDUREs call errMsg with a fatal error, even if the timeout value is $poll. If the timeout value is $poll and nothing is ready, the STREAMS PROCEDUREs in question return $timedOut.

If the system does not support timeout, i.e., if $systemSupportsTimeout returns FALSE, all timeout values are treated as if they were $block and the PROCEDURE does not return until the I/O is complete or an error occurs.

10.1.2. Success and Failure of I/O Operations

The I/O PROCEDUREs return a LONG INTEGER that is nonnegative to indicate success and negative to indicate failure. Unless the bit errorOK is given to the PROCEDURE, however, errMsg is called with the fatal bit if a failure of any kind occurs.

The macros shown in Figure 10–2 are defined to test the return values.

Figure 10–2. Error Testing Macros
BOOLEAN
<
macro>   $success (LONG INTEGER ee);
    # 
ee is return from stream PROCEDUREreturns TRUE
    # 
iff PROCEDURE succeeded

COMPILETIME
LONG INTEGER
<
macro>   $error;       # General error occurred

COMPILETIME
LONG INTEGER
<
macro>   $eos;         # End of stream occurred

COMPILETIME
LONG INTEGER
<
macro>   $timedOut;    # Operation timed out

A return of $error indicates a general error. A return of $timedOut indicates that the I/O operation did not occur because the timeout value was exceeded. A return of $eos indicates that no more data are available on input, or that no more data can be accepted by the other end on output.

The character-reading PROCEDURE $cReadStream returns INTEGER instead of LONG INTEGER values but is otherwise similar in this respect.

If an error return of any kind occurs, the field $lastInputError or $lastOutputError of the stream contains a description of the error. If the operation is neither input nor output, $lastInputError is set.

10.1.3. The General Error Return ($error)

The general error return occurs if the error does not fit one of the other error categories, or if the STREAMS package could not determine the precise reason for the failure. The error could be anything from a physical device error to an attempt to use an invalid stream handle.

10.1.4. The End-of-Stream Return ($eos)

The precise meaning of “end-of-stream” ($eos error) depends on the stream type, on whether the requested operations was input or output, and on the underlying implementation. The distinction between a normal $error and $eos might possibly be of some use to a program. When in doubt, treat $eos and $error the same way.

For TTY streams, in the input direction, $eos means that the user typed some system-dependent key combination to signal the end of an exchange (e.g., CTRL-D under BSD UNIX). Repeated $eos errors, however, might mean that no more input is available at all.

For socket streams, in both the input and output directions, $eos means that the process at the other end has “hung up” the connection for some reason.

For some implementations of some stream types, such as standard UNIX V.0 TTY streams, the STREAMS package may not be able to distinguish end-of-stream from a simple lack of data. On such platforms, the $eos return does not occur.

10.1.5. Timeout Return ($timedOut)

A return of $timedOut indicates that the I/O operation did not occur because the timeout value was exceeded. This error does not occur if a timeout value of $block (default) was supplied.

10.2. Octets

The term “octets” refers to eight-bit character units or their contents. The term differs from “characters” or “character units” in that octets are uninterpreted and untranslated; i.e., the stream operations on “characters” interpret their arguments or return values as text, whereas “octet” operations work on “raw bits”.

All physical channels on which stream communication is based transmit information in the form of eight-bit units, so the octet is the quantum of information used by most stream I/O PROCEDUREs.

10.3. Input: $readStream

Figure 10–3. $readStream (GENERIC)
LONG INTEGER
PROCEDURE   $readStream (POINTER($streamst;
                         
PRODUCES STRING s;
                         
OPTIONAL BITS ctrlBits;
                         
OPTIONAL LONG INTEGER timeout);

LONG INTEGER
PROCEDURE   $readStream (POINTER($streamst;
                         
CHARADR ca;
                         
LONG INTEGER bufSize;
                         
OPTIONAL BITS ctrlBits;
                         
OPTIONAL LONG INTEGER timeout);

LONG INTEGER
PROCEDURE   $readStream (POINTER($streamst;
                         
ADDRESS a;
                         
LONG INTEGER bufSize;
                         
OPTIONAL BITS ctrlBits;
                         
OPTIONAL LONG INTEGER timeout);

$readStream reads octets from the stream st into the destination STRING or buffer with maximum size given by bufSize.

The interpretation of the octets read from the stream (how they are packed into memory) depends on the the form of $readStream that is used. The STRING and CHARADR forms read text ($text mode), the CHARADR form with the $octet bit set reads octets, and the ADDRESS form reads octets into complete storage units ($image mode).

It is not necessary to specify the bits $text or $image in ctrlBits because they are implied by the GENERIC instance. However, when reading octets it is necessary to include the $octet bit, since octets are addressed by CHARADRs.

The precise interpretation of the octets in the stream is as follows:

At most one of the following buffering bits may be set:

The buffering modes and defaults for each type of object read are summarized in Table 10–4.

Table 10–4. Buffering Modes
Buffering Mode $text $octet $image
$unbuffered D D D
$line X - -
$fillBuffer X X X
$packet X X X
(X = valid, - = invalid, D = Default)

If the read is successful, the number of characters or octets actually read is returned. Otherwise, a negative error value is returned.

On streams that buffer output and that are opened for both input and output, the output is flushed with $flushStream (see below) before a read on the stream. This ensures that prompts or requests to a user or another process are sent out to the other side before the read blocks waiting for a response.

The MAINSAIL PROCEDURE ttyRead acts similarly to the following stream calls:

$readStream($tty,tempString,$line);
read(tempString,resultString);

The second call to read removes the eol that $readStream returns as part of the line.

Additional conventions applicable to $readStream are described in Section 10.1.

10.4. Output: $writeStream

Figure 10–5. $writeStream (GENERIC)
LONG INTEGER
PROCEDURE   $writeStream
                        (
POINTER($streamst;
                         
STRING s;
                         
OPTIONAL BITS ctrlBits;
                         
OPTIONAL LONG INTEGER timeout);

LONG INTEGER
PROCEDURE   $writeStream
                        (
POINTER($streamst;
                         
CHARADR ca;
                         
LONG INTEGER bufSize;
                         
OPTIONAL BITS ctrlBits;
                         
OPTIONAL LONG INTEGER timeout);

LONG INTEGER
PROCEDURE   $writeStream
                        (
POINTER($streamst;
                         
ADDRESS a;
                         
LONG INTEGER bufSize;
                         
OPTIONAL BITS ctrlBits;
                         
OPTIONAL LONG INTEGER timeout);

$writeStream writes the data contained in the specified buffer to the stream st.

The interpretation of the buffer (how it is converted into octets) depends on the the form of $writeStream that is used. The STRING and CHARADR (without $octet set) forms write text by translating it to the PDF character set (if necessary), the CHARADR form with $octet set in ctrlBits writes octets directly, and the ADDRESS form writes storage units by converting them to octets in the standard way for the host system. The bufSize parameter is in character units for the CHARADR form and storage units for the ADDRESS form.

It is not necessary to specify the bits $text or $image in ctrlBits because they are implied by the GENERIC instance. However, when writing octets it is necessary to include the $octet bit because octets are addressed by CHARADRs.

At most one of the following buffering bits may be set:

$writeStream returns a nonnegative LONG INTEGER on a successful write. Otherwise, a negative value is returned.

The system PROCEDURE ttyWrite produces results similar to:

$writeStream($tty,argStr,$line)

Additional conventions applicable to $writeStream are described in Section 10.1.

10.5. Single-Character I/O: $cReadStream and $cWriteStream

Figure 10–6. $cReadStream and $cWriteStream
INTEGER
PROCEDURE   $cReadStream
                        (
POINTER($streamst;
                         
OPTIONAL BITS ctrlBits;
                         
OPTIONAL LONG INTEGER timeout);

LONG INTEGER
PROCEDURE   $cWriteStream
                        (
POINTER($streamst;
                         
INTEGER c;
                         
OPTIONAL BITS ctrlBits;
                         
OPTIONAL LONG INTEGER timeout);

The PROCEDUREs $cReadStream and $cWriteStream are similar to $readStream and $writeStream except that they read and write single characters or octets at a time. It is necessary to include the $text or $octet bit to indicate whether characters or octets should be read or written.

The following bits are valid in ctrlBits:

On success, $cReadStream returns the actual octet or character value. On failure it returns one of the standard error codes $error, $eos, or $timedOut, except that the value is converted to an INTEGER instead of a LONG INTEGER (i.e., test for cvi($error), cvi($eos), or cvi($timedOut)). $cReadStream is the only stream I/O PROCEDURE that returns an INTEGER instead of a LONG INTEGER.

On success, $cWriteStream returns an arbitrary nonnegative value; on failure, it returns a negative value.

The buffer PROCEDUREs $readStream and $writeStream are more efficient for reading many characters or octets. However, the character versions of these PROCEDUREs are more convenient when program logic requires reading a single character or octet at a time.

Additional conventions applicable to $cReadStream and $cWriteStream are described in Section 10.1.

10.6. Miscellaneous Operations: $flushStream and $clearStream

Figure 10–7. $flushStream and $clearStream
BOOLEAN
PROCEDURE   $flushStream
                        (
POINTER($streamst;
                         
OPTIONAL BITS ctrlBits);

BOOLEAN
PROCEDURE   $clearStream
                        (
POINTER($streamst;
                         
BITS ctrlBits);

$flushStream forces all output done to the stream out so that it is available to the process or device at the other end. This action is of use if the implementation of the stream uses an internal buffer for efficiency. A read on the stream automatically causes the previously buffered output to be sent, but a program might want to ensure that all output has been sent before issuing an error message, for example.

$clearStream discards pending input (if input is set in ctrlBits) and/or output (if output is set in ctrlBits) on st. For example, if an editor reads an invalid command character from the terminal and prints an error message, it would be reasonable to call $clearStream($tty,input) so that all unread characters typed ahead by the user are discarded (since the user is likely to assume that the errant command was performed).

Both $flushStream and $clearStream return TRUE if the operation was successful and FALSE if the operation failed and errorOK was specified in ctrlBits. If errorOK was not set, they issue a fatal error.

10.7. Constants and Macros for Stream I/O

The following constants are provided to aid in writing portable MAINSAIL programs that manipulate streams:

10.8. Multiple Coroutines Performing I/O to the Same Scheduled Stream

If two coroutines attempt to read from the same scheduled stream at the same time, it is not specified which stream sees the next available data from the stream. If the two coroutines are attempting such reads in a tight loop, the most likely behavior is that the coroutines alternate in reading data from the stream; however, this is not guaranteed, and one stream may wind up reading most or all of the data.

Similarly, when two streams write to the same scheduled stream, it is not specified which write occurs first, or whether one stream's write is more likely to succeed after the other stream's write has been performed.


previous   next   top   contents   index   framed top   this page unframed

MAINSAIL STREAMS User's Guide, Chapter 10