Updated: 11 December 1998 |
OpenVMS Programming Concepts Manual
Previous | Contents | Index |
When you open a file for mapping in Fortran, for example, you must specify a user-open routine ( Section 10.6 discusses user-open routines) to perform the following operations:
After setting the user-file open bit in the FAB options mask, you cannot use language I/O statements to access data in that file. Therefore, you should free the logical unit number associated with the file. The file is still open. You access the file with the channel number.
Example 10-3 shows a user-open routine invoked by the sample program in Section 10.4.1.1 if the file STATS.SAV exists. (If STATS.SAV does not exist, the user-open routine must invoke SYS$CREATE rather than SYS$OPEN.)
Example 10-3 Using a User-Open Routine |
---|
!UFO_OPEN.FOR INTEGER FUNCTION UFO_OPEN (FAB, 2 RAB, 2 LUN) ! Include Open VMS RMS definitions INCLUDE '($FABDEF)' INCLUDE '($RABDEF)' ! Declare dummy arguments RECORD /FABDEF/ FAB RECORD /RABDEF/ RAB INTEGER LUN ! Declare channel INTEGER*4 CHAN COMMON /CHANNEL/ CHAN ! Declare status variable INTEGER STATUS ! Declare system procedures INTEGER SYS$OPEN ! Set useropen bit in the FAB options longword FAB.FAB$L_FOP = FAB.FAB$L_FOP .OR. FAB$M_UFO ! Open file STATUS = SYS$OPEN (FAB) ! Read channel from FAB status word CHAN = FAB.FAB$L_STV ! Return status of open operation UFO_OPEN = STATUS END |
The first time you map a file you must perform the following operations in addition to those listed at the beginning of Section 10.4.1:
The user-open routine for creating a file is the same as the user-open
routine for opening a file except that SYS$OPEN is replaced by
SYS$CREATE.
10.4.1.4 Saving a Mapped File
To close a data file that was opened for user I/O, you must deassign the I/O channel assigned to that file. Before you can deassign a channel assigned to a mapped file, you must delete the virtual memory associated with the file (the memory used by the common block). When you delete the virtual memory used by a mapped file, any changes made while the file was mapped are written back to the disk file. Use the Delete Virtual Address Space (SYS$DELTVA) system service to delete the virtual memory used by a mapped file. Use the Deassign I/O Channel (SYS$DASSGN) system service to deassign the I/O channel assigned to a file.
The program segment shown in Example 10-4 closes a mapped file, automatically writing any modifications back to the disk. To ensure that the proper locations are deleted, pass SYS$DELTVA the addresses returned to your program by SYS$CRMPSC rather than the addresses you passed to SYS$CRMPSC. If you want to save modifications made to the mapped section without closing the file, use the Update Section File on Disk (SYS$UPDSEC) system service. To ensure that the proper locations are updated, pass SYS$UPDSEC the addresses returned to your program by SYS$CRMPSC rather than the addresses you passed to SYS$CRMPSC. Typically, you want to wait until the update operation completes before continuing program execution. Therefore, use the efn argument of SYS$UPDSEC to specify an event flag to be set when the update is complete, and wait for the system service to complete before continuing. For a complete description of the SYS$DELTVA, SYS$DASSGN, and SYS$UPDSEC system services, see the OpenVMS System Services Reference Manual.
Example 10-4 Closing a Mapped File |
---|
! Section address INTEGER*4 ADDR(2), 2 RET_ADDR(2) ! Event flag INTEGER*4 FLAG ! Status block STRUCTURE /IO_BLOCK/ INTEGER*2 IOSTAT, 2 HARDWARE INTEGER*4 BAD_PAGE END STRUCTURE RECORD /IO_BLOCK/ IOSTATUS . . . ! Get an event flag STATUS = LIB$GET_EF (FLAG) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS)) ! Update the section STATUS = SYS$UPDSEC (RET_ADDR, 2 ,,, 2 %VAL(FLAG) 2 , 2 IOSTATUS,,) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS)) ! Wait for section to be updated STATUS = SYS$SYNCH (%VAL(FLAG), 2 IOSTATUS) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS)) . . . |
This section provides an example, written in DEC Fortran, of how to open and update a sequential file on a VAX system. A sequential file consists of records arranged one after the other in the order in which they are written to the file. Records can only be added to the end of the file. Typically, sequential files are accessed sequentially.
To create a sequential file, use the OPEN statement and specify the following keywords and keyword values:
The file structure keyword ORGANIZATION also accepts the value 'INDEXED' or 'RELATIVE'.
Example 10-5 creates a sequential file of fixed-length records.
Example 10-5 Creating a Sequential File of Fixed-Length Records |
---|
. . . INTEGER STATUS, 2 LUN, 2 LIB$GET_INPUT, 2 LIB$GET_LUN, 2 STR$UPCASE INTEGER*2 FN_SIZE, 2 REC_SIZE CHARACTER*256 FILENAME CHARACTER*80 RECORD ! Get file name STATUS = LIB$GET_INPUT (FILENAME, 2 'File name: ', 2 FN_SIZE) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) ! Get free unit number STATUS = LIB$GET_LUN (LUN) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) ! Open the file OPEN (UNIT = LUN, 2 FILE = FILENAME (1:FN_SIZE), 2 ORGANIZATION = 'SEQUENTIAL', 2 ACCESS = 'SEQUENTIAL', 2 RECORDTYPE = 'FIXED', 2 FORM = 'UNFORMATTED', 2 RECL = 20, 2 STATUS = 'NEW') ! Get the record input STATUS = LIB$GET_INPUT (RECORD, 2 'Input: ', 2 REC_SIZE) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) DO WHILE (REC_SIZE .NE. 0) ! Convert to uppercase STATUS = STR$UPCASE (RECORD,RECORD) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) WRITE (UNIT=LUN) RECORD(1:REC_SIZE) ! Get more record input STATUS = LIB$GET_INPUT (RECORD, 2 'Input: ', 2 REC_SIZE) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) END DO END |
To update a sequential file, read each record from the file, update it, and write it to a new sequential file. Updated records cannot be written back as replacement records for the same sequential file from which they were read.
Example 10-6 updates a sequential file, giving the user the option of modifying a record before writing it to the new file. The same file name is used for both files; because the new update file was opened after the old file, the new file has a higher version number.
Example 10-6 Updating a Sequential File |
---|
. . . INTEGER STATUS, 2 LUN1, 2 LUN2, 2 IOSTAT INTEGER*2 FN_SIZE CHARACTER*256 FILENAME CHARACTER*80 RECORD CHARACTER*80 NEW_RECORD INCLUDE '($FORDEF)' INTEGER*4 LIB$GET_INPUT, 2 LIB$GET_LUN, 2 STR$UPCASE ! Get file name STATUS = LIB$GET_INPUT (FILENAME, 2 'File name: ', 2 FN_SIZE) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) ! Get free unit number STATUS = LIB$GET_LUN (LUN1) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) ! Open the old file OPEN (UNIT=LUN1, 2 FILE=FILENAME (1:FN_SIZE), 2 ORGANIZATION='SEQUENTIAL', 2 ACCESS='SEQUENTIAL', 2 RECORDTYPE='FIXED', 2 FORM='UNFORMATTED', 2 RECL=20, 2 STATUS='OLD') ! Get free unit number STATUS = LIB$GET_LUN (LUN2) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) ! Open the new file OPEN (UNIT=LUN2, 2 FILE=FILENAME (1:FN_SIZE), 2 ORGANIZATION='SEQUENTIAL', 2 ACCESS='SEQUENTIAL', 2 RECORDTYPE='FIXED', 2 FORM='UNFORMATTED', 2 RECL=20, 2 STATUS='NEW') ! Read a record from the old file READ (UNIT=LUN1, 2 IOSTAT=IOSTAT) RECORD IF (IOSTAT .NE. IOSTAT_OK) THEN CALL ERRSNS (,,,,STATUS) IF (STATUS .NE. FOR$_ENDDURREA) THEN CALL LIB$SIGNAL (%VAL(STATUS)) END IF END IF DO WHILE (STATUS .NE. FOR$_ENDDURREA) TYPE *, RECORD ! Get record update STATUS = LIB$GET_INPUT (NEW_RECORD, 2 'Update: ') IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) ! Convert to uppercase STATUS = STR$UPCASE (NEW_RECORD, 2 NEW_RECORD) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) ! Write unchanged record or updated record IF (NEW_RECORD .EQ. ' ' ) THEN WRITE (UNIT=LUN2) RECORD ELSE WRITE (UNIT=LUN2) NEW_RECORD END IF ! Read the next record READ (UNIT=LUN1, 2 IOSTAT=IOSTAT) RECORD IF (IOSTAT .NE. IOSTAT_OK) THEN CALL ERRSNS (,,,,STATUS) IF (STATUS .NE. FOR$_ENDDURREA) THEN CALL LIB$SIGNAL (%VAL(STATUS)) END IF END IF END DO END |
A user-open routine in Fortran, for example, gives you direct access to the file access block (FAB) and record access block (RAB) (the OpenVMS RMS structures that define file characteristics). Use a user-open routine to specify file characteristics that are otherwise unavailable from your programming language.
When you specify a user-open routine, you open the file rather than
allow the program to open the file for you. Before passing the FAB and
RAB to your user-open routine, any default file characteristics and
characteristics that can be specified by keywords in the programming
language are set. Your user-open routine should not set or modify such
file characteristics because the language might not be aware that you
have set the characteristics and might not perform as expected.
10.6.1 Opening a File
Section 10.4.1.2 provides guidelines on opening a file with a user-open
routine. This section provides an example of a Fortran user-open
routine.
10.6.1.1 Specifying USEROPEN
To open a file with a user-open routine, include the USEROPEN specifier in the Fortran OPEN statement. The value of the USEROPEN specifier is the name of the routine (not a character string containing the name). Declare the user-open routine as an INTEGER*4 function. Because the user-open routine name is specified as an argument, it must be declared in an EXTERNAL statement.
The following statement instructs Fortran to open SECTION.DAT using the routine UFO_OPEN:
! Logical unit number INTEGER LUN ! Declare user-open routine INTEGER UFO_OPEN EXTERNAL UFO_OPEN . . . OPEN (UNIT = LUN, 2 FILE = 'SECTION.DAT', 2 STATUS = 'OLD', 2 USEROPEN = UFO_OPEN) . . . |
Write a user-open routine as an INTEGER function that accepts three dummy arguments:
A user-open routine must perform at least the following operations. In addition, before opening the file, a user-open routine usually adjusts one or more fields in the FAB or the RAB or in both.
The following user-open routine opens an existing file. The file to be opened is specified in the OPEN statement of the invoking program unit.
INTEGER FUNCTION UFO_OPEN (FAB, 2 RAB, 2 LUN) ! Include Open VMS RMS definitions INCLUDE '($FABDEF)' INCLUDE '($RABDEF)' ! Declare dummy arguments RECORD /FABDEF/ FAB RECORD /RABDEF/ RAB INTEGER LUN ! Declare status variable INTEGER STATUS ! Declare system routines INTEGER SYS$CREATE, 2 SYS$OPEN, 2 SYS$CONNECT ! Optional FAB and/or RAB modifications . . . ! Open file STATUS = SYS$OPEN (FAB) IF (STATUS) 2 STATUS = SYS$CONNECT (RAB) ! Return status of $OPEN or $CONNECT UFO_OPEN = STATUS END |
Each field in the FAB and RAB is identified by a symbolic name, such as FAB$L_FOP. Where separate bits in a field represent different attributes, each bit offset is identified by a similar symbolic name, such as FAB$V_CTG. The first three letters identify the structure containing the field. The letter following the dollar sign indicates either the length of the field (B for byte, W for word, or L for longword) or that the name is a bit offset (V for bit) rather than a field. The letters following the underscore identify the attribute associated with the field or bit. The symbol FAB$L_FOP identifies the FAB options field, which is a longword in length; the symbol FAB$V_CTG identifies the contiguity bit within the options field.
The STRUCTURE definitions for the FAB and RAB are in the $FABDEF and $RABDEF modules of the library SYS$LIBRARY:FORSYSDEF.TLB. To use these definitions, do the following:
The following user-open routine specifies that the blocks allocated for the file must be contiguous. To specify contiguity, you clear the best-try-contiguous bit (FAB$V_CBT) of the FAB$L_FOP field and set the contiguous bit (FAB$V_CTG) of the same field.
INTEGER FUNCTION UFO_CONTIG (FAB, 2 RAB, 2 LUN) ! Include Open VMS RMS definitions INCLUDE '($FABDEF)' INCLUDE '($RABDEF)' ! Declare dummy arguments RECORD /FABDEF/ FAB RECORD /RABDEF/ RAB INTEGER LUN ! Declare status variable INTEGER STATUS ! Declare system procedures INTEGER SYS$CREATE, 2 SYS$CONNECT ! Clear contiguous-best-try bit and ! set contiguous bit in FAB options FAB.FAB$L_FOP = IBCLR (FAB.FAB$L_FOP, FAB$V_CBT) FAB.FAB$L_FOP = IBSET (FAB.FAB$L_FOP, FAB$V_CTG) ! Open file STATUS = SYS$CREATE (FAB) IF (STATUS) STATUS = SYS$CONNECT (RAB) ! Return status of open or connect UFO_CONTIG = STATUS END |
This chapter describes how to use system services to perform input and output operations. It contains the following sections:
Section 11.1 describes the QIO operation.
Section 11.2 describes the use of quotas, privileges, and protection.
Section 11.3 describes device addressing modes.
Section 11.4 describes I/O function encoding.
Section 11.5 describes how to assign channels.
Section 11.6 describes how to queue I/O requests.
Section 11.7 describes how to synchronize I/O completions.
Section 11.8 describes the routine to use to wait for completion of an asynchronous event.
Section 11.9 describes executing I/O services synchronously or asynchronously.
Section 11.10 describes the completion status of an I/O operation.
Section 11.11 describes how to deassign I/O channels.
Section 11.12 presents a program example of a complete input and output operation.
Section 11.13 describes how to cancel I/O requests.
Section 11.14 describes how to use logical names and physical device names for I/O operations.
Section 11.15 describes how to use device name defaults.
Section 11.16 describes how to obtain information about physical devices.
Section 11.17 describes device allocation.
Section 11.18 describes how to mount, dismount, and initialize disk and tape volumes.
Section 11.19 describes format output strings.
Section 11.20 describes how to use mailboxes for I/O operations.
Section 11.21 provides a program example of using I/O system services.
Section 11.22 describes the Fast I/O and Fast Path features that improve I/O performance.
Examples are provided to show you how to use the I/O services for simple functions, such as terminal input and output operations. If you plan to write device-dependent I/O routines, see the OpenVMS I/O User's Reference Manual.
On VAX systems, if you want to write your own device driver or connect to a device interrupt vector, see the OpenVMS VAX Device Support Reference Manual.
Besides using I/O system services, you can use OpenVMS Record Management Services (RMS). OpenVMS RMS provides a set of routines for general-purpose, device-independent functions such as data storage, retrieval, and modification.
Unlike RMS services, I/O system services permit you to use the I/O
resources of the operating system directly in a device-dependent
manner. I/O services also provide some specialized functions not
available in OpenVMS RMS. Using I/O services requires more programming
knowledge than using OpenVMS RMS, but can result in more efficient
input/output operations.
11.1 Overview of OpenVMS QIO Operations
The OpenVMS operating system provides QIO operations that perform three basic I/O functions: read, write, and set mode. The read function transfers data from a device to a user-specified buffer. The write function transfers data in the opposite direction---from a user-specified buffer to the device. For example, in a read QIO function to a terminal device, a user-specified buffer is filled with characters received from the terminal. In a write QIO function to the terminal, the data in a user-specified buffer is transferred to the terminal where it is displayed.
The set mode QIO function is used to control or describe the
characteristics and operation of a device. For example, a set mode QIO
function to a line printer can specify either uppercase or lowercase
character format. Not all QIO functions are applicable to all types of
devices. The line printer, for example, cannot perform a read QIO
function.
11.2 Quotas, Privileges, and Protection
To preserve the integrity of the operating system, the I/O operations are performed under the constraints of quotas, privileges, and protection.
Quotas limit the number and type of I/O operations that a process can perform concurrently and the total size of outstanding transfers. They ensure that all users have an equitable share of system resources and usage.
Privileges are granted to a user to allow the performance of certain I/O-related operations, for example, creating a mailbox and performing logical I/O to a file-structured device. Restrictions on user privileges protect the integrity and performance of both the operating system and the services provided to other users.
Protection controls access to files and devices. Device protection is provided in much the same way as file protection: shareable and nonshareable devices are protected by protection masks.
The Set Resource Wait Mode (SYS$SETRWM) system service allows a process to select either of two modes when an attempt to exceed a quota occurs. In the enabled (default) mode, the process waits until the required resource is available before continuing. In the disabled mode, the process is notified immediately by a system service status return that an attempt to exceed a quota has occurred. Waiting for resources is transparent to the process when resource wait mode is enabled; the process takes no explicit action when a wait is necessary.
The different types of I/O-related quotas, privilege, and protection
are described in the following sections.
11.2.1 Buffered I/O Quota
The buffered I/O limit quota (BIOLM) specifies the maximum number of concurrent buffered I/O operations that can be active in a process. In a buffered I/O operation, the user's data is buffered in system dynamic memory. The driver deals with the system buffer and not the user buffer. Buffered I/O is used for terminal, line printer, card reader, network, mailbox, and console medium transfers and file system operations. For a buffered I/O operation, the system does not have to lock the user's buffer in memory.
The system manager, or the person who creates the process, establishes the buffered I/O quota value in the user authorization file. If you use the Set Resource Wait Mode (SYS$SETRWM) system service to enable resource wait mode for the process, the process enters resource wait mode if it attempts to exceed its direct I/O quota.
Previous | Next | Contents | Index |
Copyright © Compaq Computer Corporation 1998. All rights reserved. Legal |
5841PRO_028.HTML
|