Document revision date: 19 July 1999
[Compaq] [Go to the documentation home page] [How to order documentation] [Help on this site] [How to contact us]
[OpenVMS documentation]

OpenVMS Programming Concepts Manual


Previous Contents Index

  1. The IOSB for the I/O operations is structured so that the program can easily check for the completion status (in the first word) and the length of the input string returned (in the second word).
  2. The string will be read into the buffer BUFFER; the longword OUTLEN will contain the length of the string for the output operation.
  3. The TTNAME label is a character string descriptor for the logical device SYS$INPUT, and TTCHAN is a word to receive the channel number assigned to it.
  4. The $ASSIGN service assigns a channel and writes the channel number at TTCHAN.
  5. If the $ASSIGN service completes successfully, the $QIOW macro reads a line from the terminal, and requests that the completion status be posted in the I/O status block defined at TTIOSB.
  6. The process waits until the I/O is complete, then checks the first word in the I/O status block for a successful return. If unsuccessful, the program takes an error path.
  7. The length of the string read is moved into the longword at OUTLEN, because the $QIOW macro requires a longword argument. However, the length field of the I/O status block is only 1 word long. The $QIOW macro writes the line just read to the terminal.
  8. The program performs error checks. First, it ensures that the $OUTPUT macro successfully queued the I/O request; then, when the request is completed, it ensures that the I/O was successful.
  9. When all I/O operations on the channel are finished, the channel is deassigned.

11.13 Canceling I/O Requests

If a process must cancel I/O requests that have been queued but not yet completed, it can issue the Cancel I/O On Channel (SYS$CANCEL) system service. All pending I/O requests issued by the process on that channel are canceled; you cannot specify a particular I/O request.

The SYS$CANCEL system service performs an asynchronous cancel operation. This means that the application must wait for each I/O operation issued to the driver to complete before checking the status for that operation.

For example, you can call the SYS$CANCEL system service as follows:


 
        unsigned int status, efn1=3, efn2=4; 
   .
   .
   .
        status = SYS$QIO(efn1, ttchan, &iosb1, ...); 
        status = SYS$QIO(efn2, ttchan, &iosb2, ...); 
   .
   .
   .
        status = SYS$CANCEL(ttchan); 
        status = SYS$SYNCH(efn1, &iosb1); 
        status = SYS$SYNCH(efn2, &iosb2); 
 
 
 

In this example, the SYS$CANCEL system service initiates the cancellation of all pending I/O requests to the channel whose number is located at TTCHAN.

The SYS$CANCEL system service returns after initiating the cancellation of the I/O requests. If the call to SYS$QIO specified an event flag, AST service routine, or I/O status block, the system sets the flag, delivers the AST, or posts the I/O status block as appropriate when the cancellation is completed.

11.14 Logical Names and Physical Device Names

When you specify a device name as input to an I/O system service, it can be a physical device name or a logical name. If the device name contains a colon (:), the colon and the characters after it are ignored. When an underscore character (_) precedes a device name string, it indicates that the string is a physical device name string, for example, _TTB3:.

Any string that does not begin with an underscore is considered a logical name, even though it may be a physical device name. Table 11-3 lists system services that translate a logical name iteratively until a physical device name is returned, or until the system default number of translations have been performed.

Table 11-3 System Services for Translating Logical Names
System Service Definition
SYS$ALLOC Allocate Device
SYS$ASSIGN Assign I/O Channel
SYS$BRDCST Broadcast
SYS$DALLOC Deallocate Device
SYS$DISMOU Dismount Volume
SYS$GETDEV Get I/O Device Information
SYS$GETDVI Get Device/Volume Information
SYS$MOUNT Mount Volume

In each translation, the logical name tables defined by the logical name LNM$FILE_DEV are searched in order. These tables, listed in search order, are normally LNM$PROCESS, LNM$JOB, LNM$GROUP, and LNM$SYSTEM. If a physical device name is located, the I/O request is performed for that device.

If the services do not locate an entry for the logical name, the I/O service treats the name specified as a physical device name. When you specify the name of an actual physical device in a call to one of these services, include the underscore character to bypass the logical name translation.

When the SYS$ALLOC system service returns the device name of the physical device that has been allocated, the device name string returned is prefixed with an underscore character. When this name is used for the subsequent SYS$ASSIGN system service, the SYS$ASSIGN service does not attempt to translate the device name.

If you use logical names in I/O service calls, you must be sure to establish a valid device name equivalence before program execution. You can do this by issuing a DEFINE command from the command stream, or by having the program establish the equivalence name before the I/O service call with the Create Logical Name (SYS$CRELNM) system service.

For details about how to create and use logical names, see Chapter 12.

11.15 Device Name Defaults

If, after logical name translation, a device name string in an I/O system service call does not fully specify the device name (that is, device, controller, and unit), the service either provides default values for nonspecified fields, or provides values based on device availability.

The following rules apply:

Table 11-4 Default Device Names for I/O Services
Device Device Name1 Generic Device
dd: ddA0: (unit 0 on controller A) ddxy: (any available device of the specified type)
ddc: ddc0: (unit 0 on controller specified) ddcy: (any available unit on the specified controller)
ddu: ddA u: (unit specified on controller A) ddxu: (device of specified type and unit on any available controller)
ddcu: ddcu: (unit and controller specified) ddcu: (unit and controller specified)


1See the OpenVMS User's Manual for a summary of the device names.

Key

11.16 Obtaining Information About Physical Devices

The Get Device/Volume Information (SYS$GETDVI) system service returns information about devices. The information returned is specified by an item list created before the call to SYS$GETDVI.

When you call the SYS$GETDVI system service, you must provide the address of an item list that specifies the information to be returned. The format of the item list is described in the description of SYS$GETDVI in the OpenVMS System Services Reference Manual. The OpenVMS I/O User's Reference Manual contains details on the device-specific information these services return.

In cases where a generic (that is, nonspecific) device name is used in an I/O service, a program may need to find out what device has been used. To do this, the program should provide SYS$GETDVI with the number of the channel to the device and request the name of the device with the DVI$_DEVNAM item identifier.

The operating system also supports a device called the null device for program development. The mnemonic for the null device is NL. Its characteristics are as follows:

The null device functions as a virtual device to which you can direct output but from which the data does not return.

11.16.1 Checking the Terminal Device

You are restricted to a terminal device if you use any of the special functions described in this section. If the user of your program redirects SYS$INPUT or SYS$OUTPUT to a file or nonterminal device, an error occurs. You can use the SYS$GETDVIW system service to make sure the logical name is associated with a terminal, as shown in Example 11-7. SYS$GETDVIW returns a status of SS$_IVDEVNAM if the logical name is defined as a file or otherwise does not equate to a device name. The type of device is the response associated with the DVI$_DEVCLASS request code and should be DC$_TERM for a terminal.

Example 11-7 Using SYS$GETDVIW to Verify the Device Name

 
RECORD /ITMLST/ DVI_LIST 
LOGICAL*4 STATUS 
! GETDVI buffers 
INTEGER CLASS,             ! Response buffer 
2       CLASS_LEN          ! Response length 
! GETDVI symbols 
INCLUDE '($DCDEF)' 
INCLUDE '($SSDEF)' 
INCLUDE '($DVIDEF)' 
! Define subprograms 
INTEGER SYS$GETDVIW 
! Find out the device class of SYS$INPUT 
DVI_LIST.BUFLEN = 4 
DVI_LIST.CODE = DVI$_DEVCLASS 
DVI_LIST.BUFADR = %LOC (CLASS) 
DVI_LIST.RETLENADR = %LOC (CLASS_LEN) 
STATUS = SYS$GETDVIW (,,'SYS$INPUT', 
2                     DVI_LIST,,,,,) 
IF ((.NOT. STATUS) .AND. (STATUS .NE. SS$_IVDEVNAM)) THEN 
  CALL LIB$SIGNAL (%VAL (STATUS)) 
END IF 
! Make sure device is a terminal 
IF ((STATUS .NE. SS$_IVDEVNAM) .AND. (CLASS .EQ. DC$_TERM)) THEN 
   .
   .
   .
ELSE 
  TYPE *, 'Input device not a terminal' 
END IF 

11.16.2 Terminal Characteristics

The OpenVMS I/O User's Reference Manual describes device-specific characteristics associated with terminals. To examine a characteristic, issue a call to SYS$QIO or SYS$QIOW system service with the IO$_SENSEMODE function and examine the appropriate bit in the structure returned to the P1 argument. To change a characteristic:

  1. Issue a call to SYS$QIO or SYS$QIOW system service with the IO$_SENSEMODE function.
  2. Set or clear the appropriate bit in the structure returned to the P1 argument.
  3. Issue a call to SYS$QIO or SYS$QIOW system service with the IO$_SETMODE function passing, as the P1 argument, to modify the structure you obtained from the sense mode operation.

Example 11-8 turns off the HOSTSYNC terminal characteristic. To check whether NOHOSTSYNC has been set, enter the SHOW TERMINAL command.

Example 11-8 Disabling the HOSTSYNC Terminal Characteristic

   .
   .
   .
INTEGER*4 STATUS 
! I/O channel 
INTEGER*2 INPUT_CHAN 
! I/O status block 
STRUCTURE /IOSTAT_BLOCK/ 
  INTEGER*2 IOSTAT 
  BYTE      TRANSMIT, 
2           RECEIVE, 
2           CRFILL, 
2           LFFILL, 
2           PARITY, 
2           ZERO 
END STRUCTURE 
RECORD /IOSTAT_BLOCK/ IOSB 
! Characteristics buffer 
! Note: basic characteristics are first three 
!       bytes of second longword -- length is 
!       last byte 
STRUCTURE /CHARACTERISTICS/ 
  BYTE      CLASS, 
2           TYPE 
  INTEGER*2 WIDTH 
  UNION 
   MAP 
    INTEGER*4 BASIC 
   END MAP 
   MAP 
    BYTE LENGTH(4) 
   END MAP 
  END UNION 
  INTEGER*4 EXTENDED 
END STRUCTURE 
RECORD /CHARACTERISTICS/ CHARBUF 
! Define symbols used for I/O and terminal operations 
INCLUDE '($IODEF)' 
INCLUDE '($TTDEF)' 
! Subroutines 
INTEGER*4 SYS$ASSIGN, 
2         SYS$QIOW 
! Assign channel to terminal 
STATUS = SYS$ASSIGN ('SYS$INPUT', 
2                    INPUT_CHAN,,) 
IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) 
! Get current characteristics 
STATUS = SYS$QIOW (, 
2                  %VAL (INPUT_CHAN), 
2                  %VAL (IO$_SENSEMODE), 
2                  IOSB,,, 
2                  CHARBUF,          ! Buffer 
2                  %VAL (12),,,,)    ! Buffer size 
IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) 
IF (.NOT. IOSB.IOSTAT) CALL LIB$SIGNAL (%VAL (IOSB.IOSTAT)) 
! Turn off hostsync 
CHARBUF.BASIC = IBCLR (CHARBUF.BASIC, TT$V_HOSTSYNC) 
! Set new characteristics 
STATUS = SYS$QIOW (, 
2                  %VAL (INPUT_CHAN), 
2                  %VAL (IO$_SETMODE), 
2                  IOSB,,, 
2                  CHARBUF, 
2                  %VAL (12),,,,) 
IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) 
IF (.NOT. IOSB.IOSTAT) CALL LIB$SIGNAL (%VAL (IOSB.IOSTAT)) 
 
END 

If you modify terminal characteristics with set mode QIO operations, you should save the characteristics buffer that you obtain on the first sense mode operation, and restore those characteristics with a set mode operation before exiting. (Resetting is not necessary if you just use modifiers on each read operation.) To ensure that the restoration is performed if the program aborts (for example, if the user presses Ctrl/Y), you should restore the user's environment in an exit handler. See Chapter 15 for a description of exit handlers.

11.16.3 Record Terminators

A QIO read operation ends when the user enters a terminator or when the input buffer fills, whichever occurs first. The standard set of terminators applies unless you specify the 4 argument in the read QIO operation. You can examine the terminator that ended the read operation by examining the input buffer starting at the terminator offset (second word of the I/O status block). The length, in bytes, of the terminator is specified by the high-order word of the I/O status block. The third word of the I/O status block contains the value of the first character of the terminator.

Examining the terminator enables you to read escape sequences from the terminal, provided that you modify the QIO read operation with the IO$M_ESCAPE modifier (or the ESCAPE terminal characteristic is set). The first character of the terminator will be the ESC character (an ASCII value of 27). The remaining characters will contain the value of the escape sequence.

11.16.4 File Terminators

You must examine the terminator to detect end-of-file (Ctrl/Z) on the terminal. No error condition is generated at the QIO level. If the user presses Ctrl/Z, the terminator will be the SUB character (an ASCII value of 26).

11.17 Device Allocation

Many I/O devices are shareable; that is, more than one process at a time can access the device. By calling the Assign I/O Channel (SYS$ASSIGN) system service, a process is given a channel to the device for I/O operations.

In some cases, a process may need exclusive use of a device so that data is not affected by other processes. To reserve a device for exclusive use, you must allocate it.

Device allocation is normally accomplished with the DCL command ALLOCATE. A process can also allocate a device by calling the Allocate Device (SYS$ALLOC) system service. When a device has been allocated by a process, only the process that allocated the device and any subprocesses it creates can assign channels to the device.

When you call the SYS$ALLOC system service, you must provide a device name. The device name specified can be any of the following:

If you specify a physical device name, SYS$ALLOC attempts to allocate the specified device.

If you specify a logical name, SYS$ALLOC translates the logical name and attempts to allocate the physical device name equated to the logical name.

If you specify a generic device name (that is, if you specify a device type but do not specify a controller or unit number, or both), SYS$ALLOC attempts to allocate any device available of the specified type. For more information about the allocation of devices by generic names, see Section 11.15.

When you specify generic device names, you must provide fields for the SYS$ALLOC system service to return the name and the length of the physical device that is actually allocated so that you can provide this name as input to the SYS$ASSIGN system service.

The following example illustrates the allocation of a tape device specified by the logical name TAPE:


 
#include <descrip.h> 
#include <lib$routines.h> 
#include <ssdef.h> 
#include <starlet.h> 
#include <stdio.h> 
 
main() { 
        unsigned int status; 
        char devstr[64]; 
        unsigned short phylen, tapechan; 
 
        $DESCRIPTOR(logdev,"TAPE");     /* Descriptor for logical name */ 
        $DESCRIPTOR(devdesc,devstr);    /* Descriptor for physical name */ 
 
/* Allocate a device */ 
        status = SYS$ALLOC( &logdev,    /* devnam - device name */      (1) 
                            &phylen,    /* phylen - length device name string */ 
                            &devdesc,   /* phybuf - buffer for devnam string */ 
                            0, 0); 
        if (!$VMS_STATUS_SUCCESS( status )) 
                LIB$SIGNAL( status ); 
        
/* Assign a channel to the device */ 
        status = SYS$ASSIGN( &devdesc,          /* devnam - device name */  (2)
                             &tapechan,         /* chan - channel number */ 
                             0, 0, 0); 
        if (!$VMS_STATUS_SUCCESS( status )) 
                LIB$SIGNAL( status ); 
 
/* Deassign the channel */ 
        status = SYS$DASSGN( tapechan );        /* chan - channel number */(3)
        if (!$VMS_STATUS_SUCCESS( status )) 
                LIB$SIGNAL( status ); 
 
/* Deallocate the device */ 
        status = SYS$DALLOC( &devdesc,          /* devnam - device name */ 
                             0 );               /* acmode - access mode */ 
        if (!$VMS_STATUS_SUCCESS( status )) 
                LIB$SIGNAL( status ); 
 
} 
 

  1. The SYS$ALLOC system service call requests allocation of a device corresponding to the logical name TAPE, defined by the character string descriptor LOGDEV. The argument DEVDESC refers to the buffer provided to receive the physical device name of the device that is allocated and the length of the name string. The SYS$ALLOC service translates the logical name TAPE and returns the equivalence name string of the device actually allocated into the buffer at DEVDESC. It writes the length of the string in the first word of DEVDESC.
  2. The SYS$ASSIGN command uses the character string returned by the SYS$ALLOC system service as the input device name argument, and requests that the channel number be written into TAPECHAN.
  3. When I/O operations are completed, the SYS$DASSGN system service deassigns the channel, and the SYS$DALLOC system service deallocates the device. The channel must be deassigned before the device can be deallocated.

11.17.1 Implicit Allocation

Devices that cannot be shared by more than one process (for example, terminals and line printers) do not have to be explicitly allocated. Because they are nonshareable, they are implicitly allocated by the SYS$ASSIGN system service when SYS$ASSIGN is called to assign a channel to the device.

11.17.2 Deallocation

When the program has finished using an allocated device, it should release the device with the Deallocate Device (SYS$DALLOC) system service to make it available for other processes.

At image exit, the system automatically deallocates devices allocated by the image.

11.18 Mounting, Dismounting, and Initializing Volumes

This section introduces you to using system services to mount, dismount, and initialize disk and tape volumes.

11.18.1 Mounting a Volume

Mounting a volume establishes a link between a volume, a device, and a process. A volume, or volume set, must be mounted before I/O operations can be performed on the volume. You interactively mount or dismount a volume from the DCL command stream with the MOUNT or DISMOUNT command. A process can also mount or dismount a volume or volume set programmatically using the Mount Volume (SYS$MOUNT) or the Dismount Volume (SYS$DISMOU) system service, respectively.

Mounting a volume involves two operations:

  1. Place the volume on the device and start the device (by pressing the START or LOAD button).
  2. Mount the volume with the SYS$MOUNT system service.

11.18.1.1 Calling the SYS$MOUNT System Service

The Mount Volume (SYS$MOUNT) system service allows a process to mount a single volume or a volume set. When you call the SYS$MOUNT system service, you must specify a device name.

The SYS$MOUNT system service has a single argument, which is the address of a list of item descriptors. The list is terminated by a longword of binary zeros. Figure 11-8 shows the format of an item descriptor.

Figure 11-8 SYS$MOUNT Item Descriptor


Most item descriptors do not have to be in any order. To mount volume sets, you must specify one item descriptor per device and one item descriptor per volume; you must specify the descriptors for the volumes in the same order as the descriptors for the devices on which the volumes are loaded.

For item descriptors other than device and volume names, if you specify the same item descriptor more than once, the last occurrence of the descriptor is used.

The following example illustrates a call to SYS$MOUNT. The call is equivalent to the DCL command that precedes the example.


$ MOUNT/SYSTEM/NOQUOTA  DRA4:,DRA5:  USER01,USER02  USERD$


 
 
#include <descrip.h> 
#include <lib$routines.h> 
#include <mntdef.h> 
#include <starlet.h> 
#include <stdio.h> 
   .
   .
   .
 
 
struct { 
        unsigned short buflen, item_code; 
        void *bufaddr; 
        int *retlenaddr; 
}itm; 
 
         struct itm itm[7]; 
 
main() { 
   .
   .
   .
        unsigned int status, flags; 
 
        $DESCRIPTOR(dev1,"DRA4:");      
        $DESCRIPTOR(vol1,"USER01");    
        $DESCRIPTOR(dev2,"DRA5:");      
        $DESCRIPTOR(vol2,"USER02");    
        $DESCRIPTOR(log,"USERD$:"); 
 
 flags = MNT$M_SYSTEM | MNT$M_NODISKQ; 
 
 i = 0; 
 itm[i].buflen = sizeof( flags ); 
 itm[i].item_code = MNT$_FLAGS; 
 itm[i].bufaddr = flags; 
 itm[i++].retlenaddr = NULL; 
 
 itm[i].buflen = dev1.dsc$w_length; 
 itm[i].item_code = MNT$_DEVNAM; 
 itm[i].bufaddr = dev1.dsc$a_pointer; 
 itm[i++].retlenaddr = NULL; 
 
 itm[i].buflen = vol1.dsc$w_length; 
 itm[i].item_code = MNT$_VOLNAM; 
 itm[i].bufaddr = vol1.dsc$a_pointer; 
 itm[i++].retlenaddr = NULL; 
 
 itm[i].buflen = dev2.dsc$w_length; 
 itm[i].item_code = MNT$_DEVNAM; 
 itm[i].bufaddr = dev2.dsc$a_pointer; 
 itm[i++].retlenaddr = NULL; 
 
 itm[i].buflen = vol2.dsc$w_length; 
 itm[i].item_code = MNT$_VOLNAM; 
 itm[i].bufaddr = vol2.dsc$a_pointer; 
 itm[i++].retlenaddr = NULL; 
 
 itm[i].buflen = log.dsc$w_length; 
 itm[i].item_code = MNT$_LOGNAM; 
 itm[i].bufaddr = log.dsc$a_pointer; 
 itm[i++].retlenaddr = NULL; 
 
 itm[i].buflen = 0; 
 itm[i].item_code = 0; 
 itm[i].bufaddr = NULL; 
 itm[i++].retlenaddr = NULL; 
 
   .
   .
   .
        status = SYS$MOUNT ( itm ); 
        if (!$VMS_STATUS_SUCCESS(status)) 
                LIB$SIGNAL( status ); 
   .
   .
   .
} 
 


Previous Next Contents Index

  [Go to the documentation home page] [How to order documentation] [Help on this site] [How to contact us]  
  privacy and legal statement  
5841PRO_031.HTML