OpenVMS Utility Routines Manual
This routine also returns any error condition values that you have
coded your format routine to return. Refer to Section 16.3.1 for more
information about error condition values.
USER-OUTPUT-ROUTINE
The user-written USER-OUTPUT-ROUTINE performs output operations. You
supply a user output routine by calling the PSM$REPLACE routine with
the routine code PSM$K_OUTPUT.
Format
USER-OUTPUT-ROUTINE request_id ,work_area ,func ,funcdesc ,funcarg
RETURNS
OpenVMS usage: |
cond_value |
type: |
longword (unsigned) |
access: |
write only |
mechanism: |
by value |
Longword condition value. Most utility routines return a condition
value in R0. Condition values that this routine can return are listed
under Condition Values Returned.
Arguments
request_id
OpenVMS usage: |
address |
type: |
longword (unsigned) |
access: |
read only |
mechanism: |
by reference |
Request identifier value supplied by the symbiont when it calls your
output routine. The request_id argument is the address
of a longword containing this value.
If your output routine initiates an asynchronous operation (for
example, a call to the $QIO system service), you must save the
request_id argument because you will need to store the
request identifier value for later use with the PSM$REPORT routine. See
the description of the PSM$REPORT routine for more information.
work_area
OpenVMS usage: |
address |
type: |
longword (unsigned) |
access: |
write only |
mechanism: |
by reference |
Work area supplied by the symbiont for the use of your format routine.
The symbiont supplies the address of this area when it calls your
routine. The work_area argument is a longword
containing the address of the work area. The work area is a section of
memory that your format routine can use for buffering and other
internal operations.
The size of the work area allocated is specified by the
work_size argument in the PSM$PRINT routine. If you do
not specify work_size in the call to PSM$PRINT, no
work area is allocated.
In a multithreaded symbiont, a separate work area is allocated for each
thread. This work area is shared by all user routines. The work area is
initialized to zero when the symbiont is first started.
func
OpenVMS usage: |
function_code |
type: |
longword (unsigned) |
access: |
read only |
mechanism: |
by reference |
Function code supplied by the symbiont when it calls your output
routine. The func argument is the address of a
longword containing this code.
The function code specifies the reason the symbiont is calling your
output routine or, in other words, the function that the symbiont
expects your routine to perform at this time.
Most function codes require or allow additional information to be
passed in the call via the funcdesc and
funcarg arguments. The description of each output
function code, therefore, includes a description of how these two
arguments are used for that function code.
The following list describes all the function codes that the symbiont
might supply when it calls your output routine (function codes
applicable only to input and formatting routines are explained in the
descriptions of the user input routine and user formatting routine,
respectively). Each programming language provides an appropriate
mechanism for defining these function codes.
Function Codes for Output Routines
PSM$K_OPEN
When the symbiont calls your output routine with this function code,
your routine should prepare to move data to the device by performing
such tasks as allocating the device, assigning a channel to the device,
and so on. The next time the symbiont calls your output routine, the
symbiont specifies one of the WRITE function codes (PSM$K_WRITE or
PSM$K_WRITE_NOFORMAT).
The symbiont calls your output routine with the PSM$K_OPEN function
code when the symbiont receives the SMBMSG$K_START_STREAM message from
the job controller.
If your output routine returns an error condition value (low bit clear)
to the PSM$K_OPEN function call, the job controller stops processing on
the stream and reports the error to whomever entered the DCL command
START/QUEUE.
The funcdesc argument is the address of a descriptor
that identifies the name of the device to which the output routine is
to write. This device name is established by the DCL command
INITIALIZE/QUEUE/ON=device.
The funcarg argument is the address of a longword into
which the user output routine returns the device status longword. Your
output routine sets bits in the device status longword to indicate to
the job controller whether the device falls into one of the following
categories:
- Can print lowercase letters
- Is a terminal
- Is connected to the CPU by means of a modem (remote)
If your output routine does not set any of these bits in the device
status longword, the job controller assumes, by default, that the
device is a line printer that prints only uppercase letters.
PSM$K_WRITE
When the symbiont calls your routine with this function code, your
routine must write data to the device. The symbiont supplies the data
to be written in the funcdesc argument. Compaq
recommends that you use one of the Run-Time Library string routines to
access the data in the buffer described by the
funcdesc argument.
PSM$K_WRITE_NOFORMAT
When the symbiont calls your routine with this function code, your
routine must write data to the device and must indicate to the device
driver that the data is not to be formatted.
The symbiont calls your routine with this function code when: (1) the
print request specifies the PASSALL option or (2) data is introduced by
the ANSI DCS (device control string) escape sequence.
The symbiont supplies the data to be written in the
funcdesc argument. Compaq recommends that you use one
of the Run-Time Library string routines to move the data from the
descriptor to the device.
The output routine of the symbiont informs the device driver not to
format the data in the following way:
- When the device is a line printer, the symbiont's output routine
specifies the IO$_WRITEPBLK function code when it calls the $QIO system
service.
- When the device is a terminal, the symbiont's output routine
specifies the IO$M_NOFORMAT function modifier when it calls the $QIO
system serivce.
PSM$K_CANCEL
When the symbiont calls your routine with this function code, your
routine must abort any outstanding asynchronous I/O requests.
The output routine supplied by the symbiont aborts outstanding I/O
requests by calling the $CANCEL system service with the IO$_CANCEL
function code.
If your output routine returned the condition value PSM$_PENDING to one
or more previous write requests that are still outstanding (that is,
PSM$REPORT has not yet been called to report completion), then your
output routine must call PSM$REPORT one time for each outstanding write
request that is canceled with this call. That is, canceling an
asynchronous write request does not relieve the user output routine of
the requirement to call PSM$REPORT once for each asynchronous write
request.
You cannot use the funcdesc and
funcarg arguments with this function code.
PSM$K_CLOSE
When the symbiont calls your routine with this function code, your
output routine must terminate processing and release any resources it
allocated (for example, channels assigned to the device).
You cannot use the funcdesc and
funcarg arguments with this function code.
Other Output Function Codes
The symbiont can call your output routine with other function codes.
Your routine should return the status PSM$_FUNNOTSUP (function not
supported) when it is called with any of the following function codes
or with any undocumented function code. When the status PSM$_FUNNOTSUP
is returned, the symbiont performs its normal action as if no output
routine were supplied. To suppress the symbiont's normal action, you
should return SS$_NORMAL.
PSM$K_START_STREAM
|
PSM$K_STOP_STREAM
|
PSM$K_START_TASK
|
PSM$K_PAUSE_TASK
|
PSM$K_RESUME_TASK
|
PSM$K_STOP_TASK
|
PSM$K_RESET_STREAM
|
|
These function codes correspond to message items, which are discussed
in more detail in Section 17.1.6, sent by the job controller to the
symbiont.
Other function codes correspond to internal symbiont mechanisms that
are not part of the public interface to the print symbiont.
Your output routine should return the status PSM$_FUNNOTSUP or
SS$_NORMAL when it is called with a message function code or with a
private function code.
funcdesc
OpenVMS usage: |
char_string |
type: |
character string |
access: |
read only |
mechanism: |
by descriptor |
Function descriptor supplying information related to the function
specified by the func argument. The
funcdesc argument is the address of this descriptor.
The contents of the function descriptor can vary for each function.
Refer to the description of each function code to determine the
contents of the function descriptor. In some cases, the function
descriptor is not used at all.
funcarg
OpenVMS usage: |
user_arg |
type: |
longword (unsigned) |
access: |
read only |
mechanism: |
by reference |
Function argument supplying information related to the function
specified by the func argument. The
funcarg argument is the address of a longword
containing this function argument.
The contents of the function argument can vary for each function. Refer
to the description of each function code to determine the contents of
the function argument. In some cases, the function argument is not used.
Condition Values Returned
SS$_NORMAL
|
Normal successful completion. The user output routine has completed the
function that the symbiont requested.
|
PSM$_FUNNOTSUP
|
Function not supported. The user output routine does not support or
does not recognize the function code supplied by the symbiont. To
ensure future compatibility, your output routine should return this
status for any unrecognized status codes.
|
PSM$_PENDING
|
Requested function accepted but not completed. Your output routine can
return this status only with PSM$K_WRITE and PSM$K_WRITE_NOFORMAT
function calls. Further, if your routine returns PSM$_PENDING, your
routine must eventually signal completion by way of the PSM$REPORT
routine. Refer to the description of the PSM$REPORT routine for more
information about asynchronous write operations and the PSM$_PENDING
condition value.
|
This routine also returns any error condition values that you have
coded your output routine to return. Refer to Section 16.3.1 for more
information about error condition values.
Chapter 17 Symbiont/Job Controller Interface (SMB) Routines
The Symbiont/Job Controller Interface (SMB) routines provide the
interface between the job controller and symbiont processes. A
user-written symbiont must use these routines to communicate with the
job controller.
17.1 Introduction to SMB Routines
Always use the SMB interface routines or the $SNDJBC or $GETQUI system
services to communicate with the job controller. You need not and
should not attempt to communicate directly with the job controller.
To write your own symbiont, you need to understand how symbionts work
and, in particular, how the standard print symbiont behaves.
17.1.1 Types of Symbiont
There are two types of symbiont:
- Device symbiont, either an input symbiont or an output symbiont. An
input symbiont is one that transfers data from a slow device to a fast
device, for example, from a card reader to a disk. A card-reader
symbiont is an input symbiont.
An output symbiont is one that transfers data from a fast device to a
slow device, for example, from a disk to a printer or terminal. A print
symbiont is an output symbiont.
- Server symbiont, a symbiont that processes or transfers data but is
not associated with a particular device; one example is a symbiont that
transfers files across a network.
The operating system does not supply any server symbionts.
17.1.2 Symbionts Supplied with the Operating System
The operating system supplies two symbionts:
- SYS$SYSTEM:PRTSMB.EXE (PRTSMB for short), an output symbiont for
use with printers and printing terminals
PRTSMB performs such functions as inserting flag, burst, and
trailer pages into the output stream; reading and formatting input
files; and writing formatted pages to the printing device. You can
modify PRTSMB using the Print Symbiont Modification (PSM) routines.
- SYS$SYSTEM:INPSMB.EXE (INPSMB for short), an input symbiont for use
with card readers
This symbiont handles the transferring of data from a card reader
to a disk file. You cannot modify INPSMB, nor can you write an input
symbiont using the SMB routines.
17.1.3 Symbiont Behavior in the OpenVMS Environment
In the OpenVMS environment, a symbiont is a process under the control
of the job controller that transfers or processes data.
Figure 17-1 depicts the components that take part in the handling of
user requests that involve symbionts. This figure shows two symbionts:
(1) the print symbiont supplied by the operating system, PRTSMB, and
(2) a user-written symbiont, GRAPHICS.EXE, which services a graphics
plotter. The numbers in the figure correspond to the numbers in the
list that follows.
This list does not reflect the activities that must be performed by the
hypothetical, user-written symbiont, GRAPHICS.EXE. This symbiont is
represented in the figure to illustrate the correspondence between a
user-written symbiont and the print symbiont supplied by the operating
system.
Although SMB routines can be used for a different kind of symbiont,
many of their arguments and associated symbols have names related to
the print symbiont. The print symbiont is presented here as an example
of a typical symbiont and illustrates points that are generally true
for symbionts.
Figure 17-1 Symbionts in the OpenVMS Environment
- You request a printing job with the DCL
command PRINT. DCL calls the $SNDJBC system service, passing the name
of the file to be printed to the job controller, along with any other
information specified by qualifiers for the PRINT command.
- The job controller places the print request
in the appropriate queue and assigns the request a job number.
- The job controller breaks the print job into
a number of tasks (for example, printing three copies of the same file
is three separate tasks). The job controller makes a separate request
to the symbiont for each task.
Each request that the job controller
makes consists of a message. Each message consists of a code that
indicates what the symbiont is to do and a number of items of
information that the symbiont needs to carry out the task (the name of
the file, the name of the user, and so on).
- PRTSMB interprets the information it receives
from the job controller.
- PRTSMB locates and opens the file it is to
print by using the file-identification number the job controller
specified in the start-task message.
- PRTSMB sends the data from the file to the
printer's driver.
- The device driver sends the data to the
printer.
17.1.4 Writing a Symbiont
Writing your own symbiont permits you to use the queuing mechanisms and
control functions of the job controller. You might want to do this if
you need a symbiont for a device that cannot be served by PRTSMB (or a
modified form of PRTSMB) or if you need a server symbiont. The
interface between the job controller and the symbiont permits the
symbiont you write to use the many features of the job controller.
For example, when you use the DCL command PRINT, the job controller
sends a message to the print symbiont telling it to print the file.
However, when a user-written symbiont receives the same message (caused
by entering a PRINT command), it might interpret it to mean something
quite different. A robot symbiont, for example, might interpret the
message as a command for movement and the file specification (specified
with the PRINT command) might be a file describing the directions in
which the robot is to move.
Note
Modifying PRTSMB is easier than writing your own symbiont; choose this
option if possible. The Print Symbiont Modification (PSM) routines
describe how to modify PRTSMB to suit your needs.
|
17.1.5 Guidelines for Writing a Symbiont
Although you can write a symbiont to use the queuing mechanisms and
other features of the job controller in whatever way you want, you must
follow these guidelines to ensure that your symbiont works correctly:
- The symbiont must not use any of the process-permanent channels,
which are assigned to the following logical names:
- SYS$INPUT
- SYS$OUTPUT
- SYS$ERROR
- SYS$COMMAND
- The symbiont must allocate and deallocate memory using the Run-Time
Library (RTL) routines LIB$GET_VM and LIB$FREE_VM.
- To be compatible with future releases of the operating system, you
should write the symbiont to ignore unknown message-item codes and
unknown message-request codes. (See the SMB$READ_ITEM_MESSAGE routine.)
- The symbiont must communicate with the job controller by using the
SMB routines, the $SNDJBC system service, and the $GETQUI system
service.
- The symbiont should not perform lengthy operations within the
context of an AST routine. The symbiont can only receive messages from
the job controller when it is not executing within the context of an
AST routine.
- The symbiont code should be linked against SMBSRVSHR.EXE in order
to define the SMB routine address and the following status codes:
- SMB$_INVSTMNBR
- SMB$_INVSTRLEV
- SMB$_NOMOREITEMS
- To assign a symbiont to a queue after it is compiled and linked,
the executable image of the symbiont must reside in SYS$SYSTEM, and you
must enter either of the following commands:
INITIALIZE/QUEUE/PROCESSOR=symbiont_filename
START/QUEUE/PROCESSOR=symbiont_filename You should specify only the
file name in the command. The disk and directory default to SYS$SYSTEM,
and all fields except the file name are ignored.
- To help debug symbionts, you should define the logical names
DBG$INPUT and DBG$OUTPUT in the LNM$GROUP_000001 logical name table to
point to your debugging terminal.
17.1.6 The Symbiont/Job Controller Interface Routines
The five SMB routines form a public interface to the job controller.
The job controller delivers requests to symbionts by means of this
interface, and the symbionts communicate their responses to those
requests through this interface. A user-written symbiont uses the
following routines to exchange messages with the job controller:
Routine |
Description |
SMB$INITIALIZE
|
Initializes the SMB facility's internal database, establishes the
interface to the job controller, and defines whether:
- Messages from the job controller are to be delivered to the
symbiont synchronously or asynchronously with respect to execution of
the symbiont.
- The symbiont is to be single-threaded or multithreaded; these
concepts are described in the sections that follow.
|
SMB$CHECK_FOR_MESSAGE
|
Checks to see if a message from the job controller to the symbiont has
arrived (used with synchronous symbionts)
|
SMB$READ_MESSAGE
|
Reads the job controller's message into a buffer
|
SMB$READ_MESSAGE_ITEM
|
Returns one item of information from the job controller's message
(which can have several informational items)
|
SMB$SEND_TO_JOBCTL
|
Sends a message from the symbiont to the job controller
|
The following sections discuss how to use the SMB routines when writing
your symbiont.
17.1.7 Choosing the Symbiont Environment
The first SMB routine that a symbiont must call is the SMB$INITIALIZE
routine. In addition to allocating and initializing the SMB facility's
internal database, it offers you two options for your symbiont
environment: (1) synchronous or asynchonous delivery of messages from
the job controller, and (2) single streaming or multistreaming the
symbiont.
|