previous next top contents index framed top this page unframed
Because streams are a fairly low-level concept, programmers typically do not use streams directly except to open and close them. They may, however, use features implemented using stream I/O, such as the Remote Procedure Call facility or servers built by XIDAK.
4.1. Making STREAMS Available to a MAINSAIL Program:
the STRHDR Intmod and $initializeStreams
The PROCEDUREs and symbols associated with
STREAMS are made available
to a MAINSAIL MODULE by restoring from the
STRHDR intmod when a MODULE that uses STREAMS is compiled.
It is also necessary at runtime to call the STREAMS system
PROCEDURE $initializeStreams
(shown in Figure 4–1)
before making use of any other
STREAMS facility (the effect is undefined if a STREAMS facility is
used before $initializeStreams is called).
$initializeStreams
may be called more than once with no ill effects.
Figure 4–1. $initializeStreams
BOOLEAN
PROCEDURE $initializeStreams
(OPTIONAL BITS ctrlBits);
$initializeStreams returns TRUE if successful, i.e., if the MODULEs necessary for initialization can be allocated, meaning that STREAMS is installed on the current system.
The only valid ctrlBits bit is errorOK. If set, an error message is suppressed in the case that STREAMS cannot be initialized, and $initializeStreams returns FALSE. If not set, $initializeStreams issues an error message.
Example 4–2. Use of $initializeStreams
| BEGIN "mod" RESTOREFROM "strHdr"; ... INITIAL PROCEDURE; BEGIN $initializeStreams; ... END; END "mod" |
STREAMS identifiers may at some point be included in the MAINSAIL system intmod, in which case the restore from STRHDR and perhaps the call to $initializeStreams would become unnecessary.
When a cooperating child process is started by a MAINSAIL parent, the stream $parent is automatically opened to the parent process. The $parent stream is typically used for communication with the parent, while the $tty is used for I/O outside of the normal communications protocol, e.g., for error messages. If the process was not started as a cooperating process by its parent, the variable $parent is NULLPOINTER.
The effects of closing $tty or $parent are undefined.
4.3. The CLASS $stream
Stream records have the
user-visible interface fields shown in Figure 4–3.
Figure 4–3. User-Visible Fields of $stream and STREAMS Macros
CLASS $stream (
STRING
$name,
$lastInputError,
$lastOutputError;
# Other user-visible fields are set according
# to the stream type
);
BOOLEAN
<macro> $systemSupportsScheduling;
BOOLEAN
<macro> $systemSupportsTimeout;
BOOLEAN
<macro> $isScheduled
(POINTER($stream) st);
BOOLEAN
<macro> $isaTty (POINTER($stream) st);
BOOLEAN
<macro> $isHalfDuplex
(POINTER($stream) st);
The $name field is the full name used to open this stream (analogous to the name field of a file record). The $lastInputError and $lastOutputError fields contain the most recent error message associated with stream input and output. If the operation producing the error was neither input nor output, the message is placed in $lastInputError.
The system attribute macros describe the functionality of the underlying implementation of the stream. $systemSupportsScheduling and $systemSupportsTimeout apply to all streams except, possibly, the $tty stream. If the system does not support timeouts, timeout values other than $block are ignored (see Section 10.1.1).
The stream-specific attribute macros describe the functionality of a particular stream. The macro $isScheduled tells whether I/O to the stream st will be scheduled (see Chapter 8). If this macro returns FALSE, the program may block until the I/O is complete.
Programmers should assume that all the attribute macros shown in Figure 4–3 are evaluated at runtime rather than compiletime. On some platforms they may actually be evaluated at compiletime, but this is subject to change.
The stream-specific attribute macro $isHalfDuplex applies to TTY
and PTYPRO streams only. It indicates that the terminal or
pseudoterminal is half-duplex.
Note that testing the MAINSAIL system variable $attributes for the
$halfDuplex bit applies only to the standard system
primary input and output associated with a
program. Other TTY streams (e.g., one opened to a remote system) might
not have the same characteristics as the primary input and output.
Figure 4–4. $openStream (GENERIC) and $closeStream
4.4. Opening and Closing Streams:
$openStream and $closeStream
NOTE: The actual STRINGs passed to $openStream are
subject to change in subsequent releases of STREAMS.
Programmers should write their programs in a way that
will make it easy to accommodate this change.
BOOLEAN
PROCEDURE $openStream (PRODUCES POINTER($stream) st;
STRING streamName;
OPTIONAL BITS ctrlBits;
PRODUCES OPTIONAL STRING
errorMsg);
BOOLEAN
PROCEDURE $openStream (PRODUCES POINTER($stream)
st1,st2;
STRING streamName;
OPTIONAL BITS ctrlBits;
PRODUCES OPTIONAL STRING
errorMsg);
BOOLEAN
PROCEDURE $closeStream
(MODIFIES POINTER($stream) st;
OPTIONAL BITS ctrlBits);
Streams are opened and closed by explicit calls that manipulate a $stream record.
4.4.1. $openStream
$openStream opens a stream identified by streamName,
making it available
for I/O in accordance with ctrlBits.
The stream name is of the form:
strmod>name
or:
strmod(host)>name
where strmod is the name of a stream MODULE (or special stream prefix; this prefix is often called a “stream MODULE” in the documentation even when it is a special name recognized by $openStream instead of the name of an actual MAINSAIL MODULE), name is a name with a syntax and meaning that depends on the stream MODULE name, and host (if supplied) is the host system on which the stream is to be opened.
Note: If you specify the host name as well as the service name, then a SERVICE entry need not exist in the services table for servers accessed through TCP/IP. This means that you can access servers from MAINSAIL clients without setting up a services table file that is accessible to the client (or adding the server to the services table, if the file already exists), provided that you are always willing to specify the host name explicitly and that both host and server machines support TCP/IP. However, you still need to set up a services table in order to start the server; the server needs to find an entry for itself in the services table. This feature is helpful only where it is difficult or impossible to make the services table for the server available to the client process.
Note: raw internet addresses are accepted wherever a TCP/IP host name would be required. For example, if the host named PaloAlto were at internet address 192.9.200.5, then service(192.9.200.5)>serviceName would be accepted wherever service(PaloAlto)>serviceName would be accepted.
The character > is always used as the stream prefix separator, unlike the corresponding separator for file names. The file name separator, $devModBrk, is > on most operating systems but may differ on some systems. The stream name separator is always >, so no special identifier is provided for it; programs that specify stream names should just use the character > in the STRINGs specifying the names.
The description given in this document of each stream MODULE gives the naming conventions and characteristics of each stream MODULE.
Some stream MODULEs produce only one stream when an $openStream is done. Such stream MODULEs include those that communicate with an external device, such as TTYSTR. For these stream MODULEs, the first form of $openStream must be used.
Some stream MODULEs, such as MEMSTR, always produce two streams. Stream pairs allow different coroutines within the same process to communicate with each other. For these stream MODULEs, the second form of $openStream must be used.
Some stream MODULEs can produce either one or two streams. For example, PROCESS and PTYPRO produce one stream (the first argument to $openStream) to talk to the child process's $tty, and may optionally produce another stream (the second argument to $openStream) to talk to the child's $parent. For these stream MODULEs, either the first or second form of $openStream may be used.
If $openStream is able to open the stream, it produces POINTER(s) to the stream handle record(s) and returns TRUE.
Table 4–5. Error Handling in $openStream
| errorOK not set: | errMsg is called and a new stream name is reprompted for until a valid name is given. A valid stream handle is always returned, and $openStream always returns TRUE. |
| errorOK set: | errorMsg is set to a description of the error, the stream handles to NULLPOINTER, and $openStream returns FALSE. |
The valid ctrlBits bits are input, output, and errorOK. If neither of input or output is given, both are assumed. In the second form of $openStream to a memory stream, specifying either input or output, but not both, makes st1 work in the specified direction and st2 work in the opposite direction.
A call to $openStream can raise the exception
$tooManyOpenFilesStr if
it is impossible to open the stream
because no more stream handles are available.
If the exception is handled by falling out of the handler, the
call is aborted.
If the exception is propagated, an error message is issued.
If a handler of this exception does a $raiseReturn,
it is assumed that the handler closed some files, so
the $openStream is attempted again.
4.4.2. $closeStream
The PROCEDURE $closeStream
closes a stream and sets its POINTER
argument to NULLPOINTER. In the case of stream pairs
opened with $openStream,
each POINTER should be closed individually with
$closeStream (in the case of
PTYPRO and PROCESS streams, you should
close the child's $tty stream before its control stream).
After a stream is closed, no further I/O may be performed
on the stream.
If an error occurs during closing (e.g., the stream handle is invalid) and errorOK is given in ctrlBits, $closeStream returns FALSE after printing the error message; if errorOK is not set, a fatal error occurs.
4.4.2.1. Detecting When a Child Process Has Exited
When manipulating a child process with MAINSAIL STREAMS,
$closeStream(childsTtyStream)
kills the child, and is in fact the
usual way to kill a child process
($writeStreamInterrupt may also be used in some cases;
see Section 7.6).
$closeStream kills the child immediately; it
does not wait for the child to die voluntarily.
The correct way to wait in the parent for the child to exit cleanly is to do a $readStream(child,s,errorOK) and look for an $eos return. The $eos return means that the child has closed its end of the stream, which happens on exit.
MAINSAIL STREAMS User's Guide, Chapter 4