Digital PDFs
Documents
Guest
Register
Log In
AA-EF88B-TE
May 1989
480 pages
Original
34MB
view
download
OCR Version
37MB
view
download
Document:
VAX Ada Run-Time Reference Manual
Order Number:
AA-EF88B-TE
Revision:
000
Pages:
480
Original Filename:
OCR Text
VAX Ada Run-Time Reference Manual Order Number: AA—EF88B—TE May 1989 This manual describes implementation details of VAX Ada in the context of the VMS operating system. It contains information on input-output, representation of types and objects, mixed-language programming, calling VMS system services, exception handling, tasking, and increasing program efficiency. It also lists all of the VAX Ada predefined packages and explains where and how to find the package specifications. Revision/Update Information: This revision supersedes the VAX Ada Programmer’s Run-Time Reference Manual (Order No. AA-EF88A-TE) Operating System and Version: VMS Version 5.0 or higher Software Version: VAX Ada Version 2.0 ATEL o THIS PRODUCT CONFORMS UNDER ITS CURRENT TESTING PROCEDURES digital equipment corporation maynard, massachusetts February 1985 Revised, May 1989 The information in this document is subject to change without notice and should not be construed as a commitment by Digital Equipment Corporation. Digital Equipment Corporation assumes no responsibility for any errors that may appear in this document. The software described in this document is furnished under a license and may be used or copied only in accordance with the terms of such license. No responsibility is assumed for the use or reliability of software on equipment that is not supplied by Digital Equipment Corporation or its affiliated companies. © Digital Equipment Corporation 1985, 1989. All Rights Reserved. Printed in U.S.A. The postpaid Reader’s Comments forms at the end of this document request your critical evaluation to assist in preparing future documentation. The following are trademarks of Digital Equipment Corporation: ALL—IN—1 DEC EduSystem IAS DEC/CMS DEC/MMS MASSBUS PDP DECmate P/OS DECnet PDT DECsystem—-10 Professional DECSYSTEM-20 DECUS Q-bus Rainbow DIBOL RSX DECwriter RSTS RT ULTRIX UNIBUS VAX VAXcluster VAXELN VMS VT Work Processor clilgliltiall ZK-3293 Contents Preface ... .... ... . . . New and Changed Features et i et e XV .. .......... ... .. . . . . @i, XiX Chapter 1 Introduction Chapter 2 Object Representation and Storage 2.1 Type and Object Representations et e e e e .......................... 2-2 Enumeration Typesand Objects . . . . ... .............. 2-3 2.1.2 Integer Types and Objects . .. ....... ... .o ... 24 2.1.3 Floating-Point Types and Objects . . .. ... ............. 2-5 2.1.1 2.2 e 2.1.3.1 Pragma LONG_FLOAT . .................. 2-9 2.1.3.2 VAX F_floating Representation. ............. 2-10 2.1.3.3 VAX D_floating Representation. . ............ 2-11 2.1.3.4 2.1.3.5 VAX G_floating Representation VAX H_floating Representation. ............. . ............ 2-13 2—-14 2.1.4 Fixed-Point Types and Objects . . . . . ... .............. 2—-16 2.1.5 Array Typesand Objects . . . . ... ................... 2—18 2.1.6 Record Typesand Objects ........................ 2-18 2.1.7 Access Typesand Objects ........................ 2-22 2.1.8 Address Typesand Objects . . . ... .................. 2-23 2.1.9 Task Typesand Objects .. ............ ... ..., 2-24 Data Optimization. . . ... ....... ... ... .... i i i i it ittt ei et 2-24 2.2.1 Pragma PACK . . . ... e 2-24 2.2.2 Length Representation Clauses ... .................. 2-28 2.2.3 Enumeration Representation Clauses ................. 2-29 2.2.4 Record Representation Clauses . .. .................. 2-29 2.2.5 AlignmentClauses . ... ......... ... ..., 2-33 2.3 Chapter 3 3.1 3.2 3.3 2.2.6 Address Clauses . . .. .. . .. 2.2.7 Determining the Sizes of Types and Objects Storage Allocation and Deallocation i e e e 2-35 .. .......... 2-37 . ....................... 241 2.3.1 Storage Allocation . ... ......... .. ... .. ... 242 2.3.2 Storage Deallocation ............................ 2-43 Input-Output Facilities Filesand File Access .. ......... ... ... ... 3-2 3.1.1 Ada Sequential Files 34 3.1.2 AdaDirectFiles. 3.1.3 Ada Relative Files . . ... ...... ... ... ... .. ... . ..., 34 3.1.4 Adalindexed Files . ... ...... ... ... ... 3-5 3.1.5 AdaTextFiles . ... .... ... ... . 3-5 Naming External Files. ... ........... ... i ... . . ... ... ... .. .. ... .. . . . . 34 ... 3-6 3.2.1 File Specification Syntax . . . ....................... 3-7 3.2.2 LogicalNames ............... .. ... 3-8 Specifying External File Attributes . . . . . ... ... ............... 3-11 3.3.1 . . . ... ... ... .. ... The VMS File Definition Language (FDL): Primary and .. 3-12 3.3.2 Secondary Attributes Creation-Time and Run-Time Attributes . . ... ........... 3-34 3.3.3 Default External File Attributes . . . . . ... .............. 3-35 34 Fille Sharing . . . . ... .. e e 3-36 35 Record Locking . . .. ........ ... . . @ . i, 3-39 3.6 3.7 . . . . ... ... .. . Binary Input-Output . . ......... ... ... . . .e 3-40 3.6.1 Sequential File Input-Output. . . .. ................... 3—44 3.6.2 Direct File Input-Output . . . . . ...... ... .. .. ... ...... 3-47 3.6.3 Relative File Input-Output . . ....................... 3-51 3.6.4 Indexed File Input-Output 3-55 Textlnput-Output . . . . .. ... 3.7.1 . ........................ ... . .. ... Using the Package TEXT_IO for Terminal Input-Output 3-64 .. ... 3-66 3.7.1.1 Line-Oriented Method . . . . ... ............. 3-69 3.7.1.2 3.7.1.3 Data-Oriented Method . . . . ... ............. MixedMethod . ........................ 3-72 3.7.1.4 Flexible Method . . . ... ...e e e e e e e e 3-75 3.7.2 Line Terminators, Page Terminators, and File Terminators.. . . . 3-77 3.7.3 Text Input-Output Buffering 3-80 .. ...................... 3-74 3.8 3.9 Chapter 4 4.1 3.7.4 TEXT_IO Carriage Control . . . . ........... ... ....... 3-81 3.7.5 Predefined Instantiations of TEXT_IO Packages .......... 3-85 Input-Output and Exception Handling. . . ... .................. 3-86 Input-Outputand Tasking . ............ ... ... ... ............ 3-86 3.9.1 Synchronization of Input-Output Operations . ............ 3-87 3.9.2 Task Wait States Caused by Input-Output Operations 3-87 ... ... Exception Handling Relationship Between Ada Exception Handling and VAX Condition Handling . .......... ... . 4.1.1 . . it . ............... 4-5 4.1.2 Copying Exception Signal Arguments ................. 4-6 4.1.3 The Matching of Ada Exceptions and System-Defined VAX Conditions . .. ...... ... ... 4.2 Making the Best Use of Ada ExceptionHandling 4.3 Suppressing Checks. 44 4.5 Chapter 5 4—1 Naming and Encoding Ada Exceptions . . . ... 4-7 ............... 4-8 ... ... i 4-9 Mixed-Language Exception Handling . . ... ................... 4-11 4.4.1 Importing Exceptions . . .. ...... ... ... . .. . . . . . ... 4-12 4.4.2 Exporting Exceptions . . .............. . ... ... ..... 4-14 443 The Exception Choice 4.4.4 Signaling VAX Conditions 4.4.5 Effects of Handling VAX Conditions from an Ada Program 4.4.6 FautHandlers. NON_ADA ERROR ............. 4-15 ... ...................... 4-15 . .. 4-21 .. ........... ... ... .. ... . .. .... 4-25 Exceptionsand Tasking .............. ... ... ... . .. .. 4-27 Mixed-Language Programming 5.1 Calling External Routines from Ada Subprograms .............. 5-2 5.2 Calling Ada Subprograms from External Routines .............. 54 5.3 Conventions for Passing Data in Mixed-Language Programs . ... ... 5-6 5.3.1 Ada Semantics . .......... 5-7 5.3.2 VAX Calling Standard Conventions .. ................. 5.3.2.1 The CallStack .......... ... . ... .. 5.3.2.2 5.3.2.3 5.3.2.4 5.3.2.5 5.4 5.5 5.6 5-12 The Argument List . . ... ................. Parameter-Passing Mechanisms . . . . ......... FunctionReturn. . . . .................... The Call Frame and Register Usage . . . . . ... .. 5-14 5.3.3 VAX Ada Linkage Conventions . . . .. ................. 5-15 5.3.4 The Importance of Data Representation. .. ............. 5-16 VAX Ada Default Parameter-Passing Mechanisms . . . . ... ........ 5-18 5.4.1 Scalar Type Parameters . ................ ... ..... 5-18 5.4.2 Array Type Parameters . . . ... . ... .ot 5.4.3 512 5-13 ii i, 5-18 Record Type Parameters. . . .. ....... ... ... 5-20 5.4.4 Access Type Parameters. . . .. ....... . v i oo, 5-20 5.4.5 Address Type Parameters . . .............. ... ..., 5-20 5.4.6 Task Type Parameters . ......... ..., 5-21 5.4.7 Subprogram Parameters . ............. ... ... ... .. 5-21 5.4.8 Entry Parameters . . . . . ...... ... i 5-21 5.4.9 VAX Ada Equivalents for VAX Data Types . ............. 5-21 VAX Ada Default Function Return Mechanisms . . ............... 524 5.5.1 Scalar, Access, Address, and Task Type Results. 5-25 5.5.2 Array Type Results. e 5-25 5.5.3 Record Type Results . .......... ... ... ... ..., 5-27 . . . .. ... ... .o i . . . . ... .. i Controlling the Mechanisms for Imported Subprogram Parameters . . 528 5.6.1 The VALUE Mechanism Option . .. .................. 528 5.6.2 The REFERENCE Mechanism Option . . ............... 5-29 5.6.3 The DESCRIPTOR Mechanism Option . ............... 5-30 Controlling the Return Mechanisms for Imported Function Results . . 5-35 5.7.1 The VALUE Mechanism Option ..................... 5-36 5.7.2 The REFERENCE Mechanism Option . .. .............. 5-36 5.7.3 The DESCRIPTOR Mechanism Option . ............... 5-36 5.8 Passing Parameters by Descriptor to Exported Subprograms ...... 5-37 5.9 Sharing Storage with Non-Ada Routines 5-38 5.7 vi i . .................... Chapter 6 6.1 Calling System or Other Callable Routines Using the VAX Ada System-Routine Packages ................. Parameter Types . . .. . ... i 6-3 6.1.2 Parameter-Passing Mechanisms . . . . ................. 66 6.1.3 Naming Conventions 6—7 6.1.4 Record Type Declarations . ... ..................... 6-7 6.1.5 Default and Optional Parameters .................... 6—11 6.1.6 Calling Asynchronous System Services . ............... 6-17 6.1.7 Calling Mathematical Routines . . . .. ................. 6—-17 Writing Your Own Routine Interfaces . . . . . . . . ................ 6—-19 6.2.1 Parameter Types . . . . . .. . e 6—21 6.2.2 Determining the Kindof Call .. ....... . ............. 621 6.2.3 Determining the Access Method . . . . . ................ 6—23 6.2.4 Passing Parameters . . ... ... .... ... ... . ... 6—24 6.2.5 Passing Routines or Subprograms as Parameters . . . ... ... 6—-24 6.2.6 Default and Optional Parameters ... ................. 6—-24 6.3 Obtaining Symbol Definitions . . ... . ........ ... ... ... ... 625 6.4 Testing Return Condition Values . ... ... . ... ... ... ... ....... 6—26 6.5 VMS Routine Examples. ... . .. 6—-29 6.2 Chapter 7 ittt it . .............. ... .. ... . . .. ... i it et i ... Using the VAX Common Data Dictionary 7.1 Using the VAX Ada-from-CDD Translator Utility 7.2 Equivalent VAX Ada and CDDL Data Types 7.3 Chapter 8 e 6-3 6.1.1 ................ 7-2 . .................. 7-3 Example of Using the Ada-from-CDD Translator . ............... 7-5 Tasking 8.1 Introduction to Using Ada Tasks on the VMS Operating System 8.2 Task Storage Allocation 8.2.1 . . .. 8—1 . ............. ... ... ... . ... ... 8-7 Storage Created for a Task Object—The Task Control BIOCK . . . . e e e e e e e e 8-8 Vii 8.2.2 8.4 8.5 8.6 8-9 8-12 8.2.2.2 Controlling the Size of a Main Task Stack ...... 8-13 Stack Overflow and Non-AdaCode . . .. ............... 8-14 Task Switchingand Scheduling . . . . ... ......... ... ... ..... 8-15 8.2.3 8.3 Storage Created for a Task Activation—The Task Stack . . . .. 8.2.2.1 Controlling the Stack Sizes of Task Objects . . . .. Special Tasking Considerations . . . . ........................ 8-17 8.4.1 Deadlock . ....... ... ... . 8-17 8.4.2 Busy Waiting and Non-AdaCode .................... 8-22 8.4.3 Tentative Rendezvous . . ... ........ ... .. ... ... 8-23 8.4.4 Using Delay Statements . . .. ...................... 8-24 8.4.5 Using Abort Statements . . ........................ 8-24 8.4.6 Interrupting Your Program with CTRLYY .. .............. 8-25 8.4.7 Using Shared Variables . . . . ... .................... 8-27 8.4.8 Reentrancy . .............c0 it ieennanns 8-31 8.4.8.1 Reentrancy in Mixed-Language Tasking 8.4.8.2 Programs ......... ... iiiiiiinnnn Avoiding Nonreentrancy .................. 9.1 9.2 viii 8-31 8-32 .............. 8-35 8.5.1 Effects of System Service CallsonTasks. . ............. 8-35 8.5.2 System Services Requiring SpecialCare ............... 8-37 ................. 8-40 8.6.1 Handling Asynchronous System Traps (ASTs) The Pragma AST_ENTRY and the AST_ENTRY Attribute. . . . 8-40 8.6.2 Constraints on Handling ASTs .. .................... 843 8.6.3 Calling Ada Subprograms from Non-Ada AST Service Routines . . .. ... Chapter 9 i Calling VMS System Service Routines from Tasks 8.6.4 8.7 i it e 843 Examples of Handling ASTs from Ada Programs . ......... .. i i 8-45 Measuring and Tuning Tasking Performance it .................. 8-48 Compiler Optimizations . . . . ... ............ ... ... . ........ 9-1 Usingthe Pragma INLINE .. ... ... . ..., 9-3 i 94 Improving Run-Time Performance ... ... ... ... .. .. 9.2.1 Explicit Use. . ........... 9.2.2 Implicit Use . . . ... ittt et 9-6 9.2.3 Pragma INLINE Examples . . . . .. ................... 9-7 i it ittt 9.2.3.1 Inline Expansion of Subprogram Specifications andBodies . . ........... ... ... .. ... 9-7 9.23.2 Inline Expansion of Generic Subprograms . . . ... 9-9 9.3 9.4 Making Useof Generics . ................ ... ..., 9—-11 9.3.1 Using the Pragma INLINE_GENERIC .. ............... 9-12 9.3.2 Using the Pragma SHARE_GENERIC . . . . .. ... . ....... 9-14 9.3.3 Library-Level Generic Instantiations . . . . ............... 9-17 Techniques for Reducing CPU Time and Elapsed Time . ... .... ... 9-19 9.4.1 Decreasing the CPU Time of a VAX Ada Program. . ... .... 9.4.1.1 Eliminating Run-Time Checks . . ... ... ....... 9-20 9-21 9.4.1.2 Reducing Function and Procedure Call Costs . . .. 922 9.4.1.3 Using Scalar Variables and Avoiding Expensive Operations on Composite Types . . . ... ... .... 9.4.2 Decreasing the Elapsed Time of a VAX Ada Program .. .. .. 9.4.2.1 9.4.2.2 Controlling Paging Behavior. . . ... .......... Improving Input-Output Behavior. . . .. ........ 9.4.23 Overlapping Unrelated Input-Output and Instruction Execution ... ....... ... .. .. .. .. 9-25 9-27 9-28 9-28 ... 928 10.1 Working with Address Values . . . . ... ........ ... ... ........ 10-1 10.2 Using Low-Level System Features . . . .. ... ... ... ............. 10-2 Chapter 10 Additional Programming Considerations 10.2.1 10.2.2 The VAX Device and Processor Register and Interlocked Operations . ...... ..t e e e 10-3 Unsigned Types in the Package SYSTEM ... ........... 10-6 10.3 Working with Varying Strings 10.4 Assigning Array Values 10.5 Appendix A Appendix B B.1 B.2 . . . . ... .. ... ... ... ... . . . . .. 10-9 .. ... ........ ... . .. .. iy 10-10 Sharing Memory Between VAXCPUs . . . . .. .. .. ... .. ... ... ... 10-13 VAX Ada Predefined Instantiations VAX Ada Packages Packages ASSERT, ASSERT_EXCEPTIONS, and ASSERT GENERIC . . . . .. ... ... . . . . e B-10 Package CDD TYPES . ... ... ... . ... .. i, B-14 B.3 Package CONDITION_ HANDLING . . . ... ............... .. .... B-19 B.4 Package CONTROL_C INTERCEPTION. . ... .................. B-26 B.5 Package MATH LIB .. ........... ... ... ... . . . . . . . . . . . ... B-26 B.6 Package STARLET ............ ... . . ... B-28 B.7 Package SYSTEM_RUNTIME_TUNING ....................... B-39 B.8 Package TASKING SERVICES . . ... ........ ... ... ... ... .... B—42 2-36 Index Examples 2—1 Using an Address Clause and LIB§GET_ VM 2-2 Using UNCHECKED_DEALLOCATION to Control Access Type Storage ... ................. Deallocation . ... ... ... ...ttt e 2—44 3-1 Creating and Opening a Relative File for Read Sharing . ............ 3-37 3-2 UsingaMixed-Type File . . . ... .. 342 3-3 Using the Package SEQUENTIAL_IO ............... ... .. ..... 347 34 Using the Package DIRECT MIXED 10 3-50 3-5 Using the Package RELATIVE_IO. ... .. . ... . ....................... . . ... ... ... ... ... ... ... ... 3-54 3—6 Using the Package INDEXED_1O . ... ..... ... ... ... ... ...... 3-58 3-7 Using the Package INDEXED_MIXED_IO ............. ... ... .... 3-62 3-8 Using the Package TEXT_ 1O . .. ... ... ... . . .. . ... 3-9 Example of Line-Oriented 3-10 Example of Data-Oriented TEXT_IO . . ... ... .. ... 3—11 Example of Flexible TEXT_IO ... 3-67 ... 3-71 . ... .. ...... 3-73 ... .. ..... ... ... . ... 3-75 TEXT IO . ... ... ... ... .. ... 4—1 Use of Pragma SUPPRESS_ALL ... ......... ... ... ... .. .... 410 4-2 Handling SYS$GETJPIW Status Values as Ada Exceptions .......... 4-16 4-3 Handling SYS$GETJPIW Status Values as VMS Conditions . ......... 4-19 6—1 Calling SYS$TRNLNM Using the Package STARLET . .. ............ 6—29 6—2 Calling SYS$GETQUI Using the Package STARLET ............... 6—31 6-3 Calling SYS$CRMPSC Using the Package STARLET .............. 6-34 64 Calling LIBSFILE_SCAN and LIB$FILE_SCAN_END Using the Package LIB . . . . ... .. . . . . 6—-36 6-5 Calling SMG Routines Using the Package SMG .. ................ 640 66 Calling SYS$TRNLNM Using an Import Pragma . ................. 6—43 6—7 Using SYSTEM.IMPORT_VALUE to Obtain a Global Symbol Value . .. .. 6—46 8-1 Interactive Array Sort Using Tasks . . .......... ... ... . 8-3 8-2 Leaving a Master to Release a Task Control Block ................ 8-10 8-3 Controlling the Size ofaTask's Stack .. ....................... 813 84 An Exception-Induced Deadlock . ............... ... .. ... ... 8-19 8-5 A Self-Calling Deadlock ............... ... i, 8-20 8-6 A Circular-Calling Deadlock . ........... ... 8-21 8-7 A Dynamic-Circular-Calling Deadlock . . . .. ... .......... ... ..... 8-22 88 A Nonreentrant Subprogram .. .............. .. ... . i . 8-32 8-9 A Reentrant Subprogram. . ... ....... ... . ... . oo na., 8-33 8-10 Using a Serializing Task to Prevent Reentry . . . .. ................ 8-34 8-11 Deadlock Caused by a Call to SYS$SETAST .. ........... .. .. ... 8-38 8-12 Unpredictability of SYSSEXIT . . . . . ... ... . 8-39 8-183 Simple Use of the Pragma AST_ENTRY and the AST ENTRY Attribute . . .. ... . i i i it it ittt ettt ittt a e n e 845 8-14 Using an AST Entry to Intercepta CTRL/C ... .................. 8-46 10-1 One Use of the Interlocked Queue Operations . .................. 104 10-2 Sharing Memory Between Two or More Programs Running on One or More VAX CPUS ..ttt it i e e e e et e e i ittt et 10-13 Figures 2—1 F_floating Representation ........... ... ... ... ... .. .. 2-10 2-2 D_floating Representation . . ........... ... ... .. .. 2—12 2-3 G_floating Representation .. ............ ... ... .. . i i, 2-13 2-4 H_floating Representation . .. ... .. ... ... ... . ann. 2-15 3-1 Using a Mixed-Type File . .. ......... ... . .. 343 3-2 Usinga Uniform-Type File . . ... ....... ... . it 3—44 it 3-3 An Ada Text File, Showing Line, Page, and File Terminators . . . .. ... .. 3-78 41 Execution of a FORTRAN Program with FORSUNDERFLOW HANDLER ....... ... ... i i 4-23 4-2 The Effect of an Ada Procedure Containing an Others Handler . . ... ... 4-24 4-3 FOR$UNDERFLOW_HANDLER Established for a FORTRAN Subroutine . .. ... ... e e e e 4-26 . . 5-1 ACallStackat Run Time . ... . ... ... ittt rennens 5-10 5-2 An Argument List . . . ... ... ... ... i e e 5-12 5-3 ACall Stack . .... ..t i e 5-15 54 Area Control Block Used in Returning Some Function Results. 5-26 . .. ... .. Xi Tables 2—-1 Range of Values and Storage Sizes for VAX Ada Predefined Integer L5/ = 2-5 2—2 VAX Type Representations and Storage Sizes for VAX Ada Predefined e e 2—6 2-3 Model Numbers Defined for Each Floating-Point Type .............. 2—-8 24 Safe Numbers Defined for Each Floating-Point Type ............... 2-5 Packable Types . . . . ... i ittt Floating-Point Types . . . . .. e ettt e e e e 2-25 2-6 Effects of Packing the Components of Arrays and Records . . ... ...... 2-26 2—7 Comparison of SiZE and MACHINE_SIZE Attribute Results . ......... 2-38 2-8 Results of Size Attributes for Various Types and Objects . ........... 2-40 3—1 Predefined (Default) Logical Names .......................... 3-9 3-2 Equivalence Strings for Default Logical Names for Process-Permanent 1= 3-11 3-3 FDL Primary and Secondary Attribute Descriptions . ............... 3-12 34 Commonly Used FDL Attributes . . .. ......................... 3-20 3-5 SEQUENTIAL_IO: Default File Attributes . . . ... ................. 3-45 3-6 SEQUENTIAL_MIXED_IO: Default File Attributes . . ............... 3-46 3—7 DIRECT_IO: Default File Attributes . . .. .......... ... ... ... ..... 3-48 3-8 DIRECT_MIXED_|O: Default File Attributes . . . . ................. 349 3-9 RELATIVE_IO: Default File Attributes . . ....................... 3-52 3-10 RELATIVE_MIXED_IO: Default File Attributes . . . . ................ 3-52 3-11 INDEXED_IO: Default File Attributes . . . .. ..................... 3-56 3-12 INDEXED_MIXED_IO: Default File Attributes . .. ................. 3-56 3-13 TEXT_IO: Default File Attributes . . . ... ....... ... .. ... 3-65 3-14 VAX Ada Carriage-Control Options . . ......... .. 3-82 3—-15 FORTRAN Carriage-Control Characters . . . . ... ................. 3-84 4—1 Relationship Between Ada Exception Handling andthe CHF . . . ... .. .. 4-3 4-2 Ada Predefined Exceptions . ................... ... . ... 4-5 4-3 VAX Conditions that Match Ada Exceptions . .................... 4-8 44 Run-Time Checks and Their Corresponding Predefined Exceptions .. ... 4-9 5-1 VAX Registers . . . ... .. i ettt 5-14 5-2 Default Descriptor Classes Used by VAX Ada for Array Parameter Passing . . ... e e e e e 5-19 5-3 VAX Ada Equivalents for VAX Data Types and Their Valid Passing Mechanisms in VAX Ada. Xii 2-9 e i i . ........... . ... iiiiiiirnnnnn. 5-22 Default Descriptor Class Names Used for the DESCRIPTOR ittt e e e e e e e e e Mechanism . ... ..o 5-5 e Type Requirements for Descriptor Classes Used by VAX Ada in Importing Routines . . . ....... .. ... . . . i i i Descriptor Data Types Used 5-32 e 5-32 . ... ... ... ... . . ... 5-35 5-7 Program Section Properties . . . . ... .. ... .. . . i 61 VMS Data Structures . . ... 6-2 VAX Ada Equivalents for VMS Access Methods . . ... ............. 6-23 71 Equivalent CDD and VAX AdaData Types . . .. ......... ... ... ... 74 91 Comparison of the Effects of the Pragmas INLINE_GENERIC and . it e e e 9-12 SHARE_GENERIC . . . . . ... VAX Ada Predefined Packages 5-39 . ............. ... ... ... .. ... B-2 xiii Preface This manual describes implementation details of VAX Ada in the context of the VMS operating system. It contains information on input-output, representation of types and objects, mixed-language programming, calling VMS system services, exception handling, tasking, and increasing program efficiency. It also lists and gives the specifications for some of the VAX Ada predefined packages. Intended Audience This manual is intended primarily for systems and applications programmers, or any other programmers whose work requires the use of operating system features outside of the language, advanced Ada features, or more than one VAX language. The reader should have a working knowledge of Ada and some familiarity with the VMS operating system. Structure of This Document This manual has ten chapters and two appendixes: e Chapter 1 introduces VAX Ada. Chapter 2 explains how VAX Ada objects and types are represented and sized; it also gives information on sharing object storage among Ada and non-Ada routines. Chapter 3 discusses VAX Ada input-output, giving details about file sharing, record locking, and the VAX Ada input-output packages. This chapter also summarizes information about the VMS File Definition Language and the specification of file names. XV Chapter 4 describes the implementation of VAX Ada exception handling and discusses the importing and exporting of VAX conditions and Ada exceptions. Chapter 5 describes the VAX Ada parameter-passing mechanisms and import-export pragmas, and discusses how to write mixed-language programs that involve VAX Ada. Chapter 6 explains how to call system and other callable routines (VMS system services, Run-Time Library routines, and so on). Chapter 7 describes how to access the VAX Common Data Dictionary from VAX Ada. Chapter 8 discusses tasking issues, including issues related to calling non-Ada routines (such as VMS system services) from tasks. Chapter 9 gives information on how to make VAX Ada programs more efficient. Chapter 10 discusses additional details of VAX Ada that you need to consider when writing VAX Ada programs. Appendix A lists all of the VAX Ada predefined generic instantiations. Appendix B lists all of the VAX Ada packages, and gives the specifications for the packages that are system-specific or that do not have their specifications given in the VAX Ada Language Reference Manual. Associated Documents The following manuals from the VAX Ada documentation set may be of interest to you: The VAX Ada Language Reference Manual, which gives information on VAX Ada language details Developing Ada Programs on VMS Systems, which gives information on how to develop and run VAX Ada programs using the VAX Ada program library manager and VMS Debugger You should also have access to the VMS system documentation. The following Ada textbooks may also be of interest: Barnes, J.G.P. Programming in Ada. Reading, Massachusetts: Addison- Wesley, second edition, 1984. Booch, Grady. Software Components with Ada: Structures, Tools and Subsystems. Menlo Park, California: The Benjamin/Cummings Publishing Company, Inc., 1987. XVi Booch, Grady. Software Engineering with Ada. Menlo Park, California: The Benjamin/Cummings Publishing Company, Inc., second edition, 1987. Cherry, G.W. Parallel Programming in ANSI Standard Ada. Reston, Virginia: Reston Publishing Company, Inc., 1984. Gehani, Narain. Ada, Concurrent Programming. Englewood Cliffs, New Jersey: Prentice Hall, Inc., 1984. Habermann, A.N., and D.E. Perry. Ada for the Experienced Programmer. Reading, Massachusetts: Addison-Wesley, 1983. ¢ Weiner, Richard, and Richard Sincovec. Programming in Ada. New York: John Wiley & Sons, 1983. Conventions Convention Meaning RETURN In interactive examples, a label enclosed in a box indicates that you press a key on your keyboard, for example, [RETURN]. The phrase CTRL/x indicates that you must press the key labeled CTRL while you simultaneously press another key, for example, CTRL/C, CTRL/Y, CTRL/O. $ SHOW TIME 05-JUN-1988 11:55:22 Interactive examples show all output lines or prompting characters that the system prints or displays in black letters. All user-entered commands are shown in red letters. A horizontal ellipsis in a figure or example indicates that not all of the statements are shown. task type_name Boldface indicates Ada reserved words. Italicized words in syntax descriptions indicate descriptive prefixes that are intended to give additional semantic information rather than to define a separate syntactic category. XVii Convention [expression] Meaning Square brackets indicate that the enclosed item is optional. {, mechanism_name } Braces indicate that the enclosed item may be repeated zero or more times. quotation marks apostrophes The term quotation marks is used to refer to double quotation marks (" ). The term apostrophe (’ ) is used to refer to a single quotation mark. Xviii New and Changed Features For this release, this manual has been reorganized, information has been clarified and corrected, and examples have been added. This version of the manual also discusses the following VAX Ada features, which have been added or changed since VAX Ada Version 1.0: The implementation of fixed-point types has changed (see Chapter 2). Record components may be biased under certain conditions (see Chapter 2). Address representation clauses are allowed for variables (see Chapter 2). The FDL SHARING PROHIBIT attribute is no longer set by the input-output packages (see Chapter 3). Indexed files can be sorted by descending (as well as ascending) keys (see Chapter 3). File sharing and record locking are available for all input-output files (see Chapter 3). In response to Ada interpretation AI-00387, VAX Ada raises CONSTRAINT_ERROR wherever the standard requires that NUMERIC_ERROR be raised (see Chapter 4). Support for the pragma SUPPRESS has been added (see Chapter 4). Improvements have been made to the way in which the VAX Ada run-time library deals with unhandled exceptions signaled by non-Ada code. In addition, messages are now displayed before waiting begins for dependent tasks (see Chapter 4). Changes have been made to the default passing mechanisms for some parameter and function result types (see Chapter 5). The RESULT_MECHANISM mechanism option has been added to the pragma IMPORT _FUNCTION (see Chapter 5). XiX The pragma EXPORT_VALUED_PROCEDURE has been added (see Chapters 5 and 6). The function SYSTEM.IMPORT VALUE has been added (see Chapter 6). The FIRST_OPTIONAL_PARAMETER mechanism option has been added to the import pragmas (see Chapter 6). A set of VMS Run-Time Library (DTK, LIB, MTH, OTS, PPL, SMG, and STR) and utility (CLI, NCS, LBR, and SOR) packages has been added (see Chapter 6). The pragma MAIN_STORAGE has been added (see Chapter 8). Support for the pragma SHARED has been added (see Chapter 8). The effects and restrictions on using the pragma INLINE have been further defined (see Chapter 9). The pragmas INLINE_GENERIC and SHARE_GENERIC have been added (see Chapter 9). A number of hardware-related types and operations have been added to the package SYSTEM (see Chapter 10). The packages SYSTEM_RUNTIME_TUNING, ASSERT _GENERIC, ASSERT_EXCEPTIONS, and the package instantiation ASSERT have been added (see Appendix B). The package TASKING_SERVICES now includes an interface to the VMS $GETQUIW system service, and problems with the TASK_ENQW and TASK_UPDSECW procedures have been identified and corrected (see Appendix B). Changes and corrections have been made to the package STARLET (see Appendix B for type definition changes). XX 1 Chapter Introduction Ada is a general-purpose programming language suitable for writing large-scale and real-time systems programs. For example, Ada is strongly typed, provides for exact or approximate numerical calculations, supports concurrency, and allows separate compilation of program units. The language is specified in ANSI/MIL-STD-1815A-1983 and 1S0O/8652-1987, Reference Manual for the Ada Programming Language, which has been reproduced, with supplementary Digital insertions, as the VAX Ada Language Reference Manual. VAX Ada implements the ANSI and ISO standard Ada programming language on the VMS operating system. VAX Ada provides for all of the standard language features. VAX Ada also provides additional packages, attributes, and pragmas designed to allow Ada programmers to work efficiently in a VMS environment and make use of the VMS operating system. Like other languages in the VAX Common Language Environment, VAX Ada has the following properties: e It conforms to the VAX Procedure Calling Standard. e It interacts with the VMS Run-Time Library. o It uses VAX Record Management Services (RMS) to implement input-output. e It depends on the VAX Condition Handling Facility (CHF) to implement exception handling. The VAX Ada compiler produces highly optimized object code and makes use of the VAX hardware instruction set. Introduction 1-1 VAX Ada is described in the following chapters, with a focus on those VAX Ada features that allow you to interact with the VMS operating system and other VAX languages. Machine- and operating-system-r elated implementation details are provided as appropriate. By being able to call VMS system, Run-Time Library, and callable utility routines from Ada subprograms or tasks, you can write programs that make efficient use of all of the capabilities of the VMS operating system. By being able to call other languages and handle exceptions from both Ada and non-Ada code, you can make use of existing non-Ada routines, or take advantage of features of other languages that may be suitable for your application. 1-2 Introduction Chapter 2 Object Representation and Storage An Ada object is an entity that can have values of a particular type. For each Ada object, the VAX Ada compiler determines how much storage is required, where and when that storage will be allocated and deallocated, and how the different values of the object are represented. The compiler makes these determinations based on the type of the object, the subtype of the object, and the use of the object. In simple cases, the representation and storage of objects is determined at compile time. In more complex cases (such as the case of an array object whose bounds are not computed until run time), the compiler generates code that computes the amount of storage required at run time. In general, the compiler chooses storage sizes and representations that make the best compromise between CPU time and the amount of memory required by the generated code. Pragmas and representation clauses allow you to control how objects are represented and stored. You most often need this control when you are working with the following kinds of objects: e Objects whose addresses are explicitly obtained with the ADDRESS attribute * Objects whose addresses are explicitly specified with an address representation clause e Objects that are passed to imported routines or used in exported subprograms e Objects that are imported/exported using the VAX Ada pragma PSECT_ OBJECT Object Representation and Storage 2-1 When the VAX Ada compiler determines how to store and represent objects, it uses rules that are similar to those used by other VAX language compilers. Thus, you can still use those objects whose storage and representation cannot be controlled in the VAX Common Language Environment. For example, simple objects of the type STANDARD.BOOLEAN are repre- sented as unsigned bytes containing the values 0 (FALSE) and 1 (TRUE). Similarly, the types STANDARD.CHARACTER and STANDARD.STRING correspond to the VAX notions of character and string, and objects of these types are represented as one or more unsigned bytes (although the type STANDARD.CHARACTER does not include the upper half of the DEC Multinational Character Set). To increase efficiency, the VAX Ada compiler may use alternative representations for some objects (for example, it may use a 32-bit longword rather than an 8-bit byte for some objects of the type STANDARD.BOOLEAN, as this representation tends to be more efficient in the use of CPU resources). However, the compiler will not choose an alternative representation for objects that are visible outside the Ada program; that is, it will not choose an alternative representation for an object that is passed to an imported routine, passed into an exported subprogram, or imported/exported using the VAX Ada pragma PSECT _OBJECT. This chapter discusses the following topics: * The representation and storage chosen by the VAX Ada compiler for objects of a variety of VAX Ada types * How to tailor the representation of the objects in your program to suit your particular application * Storage allocation and deallocation You should be familiar with the material in Chapters 3 and 13 of the VAX Ada Language Reference Manual before using the material in this chapter. 2.1 Type and Object Representations The following sections describe the representations and storage sizes chosen by the VAX Ada compiler for objects of the various Ada type classes, including scalar (enumeration, integer, floating-point, and fixed-point), array, record, access, address, and task types. 2-2 Object Representation and Storage 2.1.1 Enumeration Types and Objects Each enumeration literal in an enumeration type has a corresponding in- ternal code. Unless otherwise specified in an enumeration representation clause, the internal codes for an enumeration type are represented by the in- tegers from 0 to N — 1, where N is the number of enumeration literals in the type. For example, the internal codes for the enumeration literals of the Ada predefined types STANDARD.BOOLEAN and STANDARD.CHARACTER are as follows: Enumeration Type Internal Codes STANDARD.BOOLEAN 0 (FALSE) STANDARD.CHARACTER 0..127* 1 (TRUE) 1The internal code for each character is its conventional ASCII value (the NUL character has the internal code 0, ' A’ has the internal code 65, ' a’ has the internal code 97, and so on); see the specification of the package STANDARD in Annex C of the VAX Ada Language Reference Manual. Because Ada does not include the DEC Multinational Character Set in the package STANDARD, the internal codes 128..255 have no meaning in VAX Ada for enumeration literals of the type STANDARD.CHARACTER. Section 2.2.3 explains how to use an enumeration representation clause to specify other values (including negative ones) for internal codes. The amount of storage allocated by the VAX Ada compiler for an object of an enumeration type depends on the range of the internal codes and on any length representation clauses that provide a size for the type or first named subtype. (A first named subtype is a subtype declared by a type declaration; see Chapter 13 of the VAX Ada Language Reference Manual.) Note that when you specify a length representation clause for a first named subtype, the clause may not be applied to the representation of objects of the base type; for example, this effect may occur with loop parameters. Thus, for simple enumeration objects and enumeration components of unpacked arrays and records, the VAX Ada compiler chooses a byte (8 bits), a word (16 bits), or a longword (32 bits)—whichever is smallest—to represent an object of an enumeration type. The size chosen is large enough to represent all of the values of the type, and is greater than or equal to any applicable length representation clause. For most enumeration types, the representation is unsigned; the representation is signed only when the first internal code is negative. Object Representation and Storage 2-3 For example: type ANSWER is (YES, NO, UNDECIDED); An object of the type ANSWER will be stored in an unsigned byte, because a byte is all that is needed to represent the default internal codes (0, 1, and 2) corresponding to YES, NO, and UNDECIDED. To guarantee a particular representation or to achieve a signed representation, you can use an enumeration representation clause. See Section 2.2.3 for more information. 2.1.2 Integer Types and Objects VAX Ada provides three predefined integer types: SHORT_SHORT_INTEGER SHORT_INTEGER INTEGER These types are declared in the predefined package STANDARD (see Annex C of the VAX Ada Language Reference Manual). Values for objects of all three integer types are represented as signed, two’s complement (binary) numbers. You can achieve an unsigned representation for integer objects by declaring an integer type with a length representation clause (see Section 2.2.2). However, because of the way the Ada language defines integer operations, operations on these unsigned objects will involve signed intermediate values. See Chapter 10 for more information on working with unsigned types. Table 2—1 lists the range of integer values and storage sizes for each of these predefined integer types. 2-4 Object Representation and Storage Table 2-1: Range of Values and Storage Sizes for VAX Ada Predefined Integer Types Ada Type Range of Values SHORT_SHORT _INTEGER —27.2" - 1 | -128..127 SHORT_INTEGER Storage Size (Bits) 8 215 2% _ 1 16 —32_768..32_767 INTEGER 231,23 _ 1 32 —2_147_483_648..2_147_483_ 647 2.1.3 Floating-Point Types and Objects Floating-point types provide approximations to the real numbers, with relative bounds on the errors. For each floating-point type—predefined and nonpredefined—the VAX Ada compiler chooses one of the four VAX floating-point data representations, depending on the required range and accuracy: F_floating D_floating G_floating H_floating The chosen representation and size is used for all objects of the type, regardless of the objects’ subtypes, and regardless of whether or not the objects are themselves part of packed array or record objects. Sections 2.1.3.2 through 2.1.3.5 explain the VAX floating-point data representations in detail. VAX Ada provides a number of predefined floating-point types. Table 2-2 lists the representation and storage size for each type. Object Representation and Storage 2-5 Table 2-2: VAX Type Representations and Storage Sizes for VAX Ada Ada Type VAX Representation Predefined Floating-Point Types Storage Size (Bits) Defined in the Package STANDARD: FLOAT F_floating 32 LONG_FLOAT D_floating or 64 G_floating® LONG_LONG_FLOAT H_floating 128 Defined in the Package SYSTEM: F_FLOAT F_floating 32 D_FLOAT D_floating 64 G_FLOAT G_floating 64 H_FLOAT H_floating 128 1By default, or in the presence of the pragma LONG_FLOAT(G_FLOAT), the type LONG_ FLOAT has a G_floating representation; it has a D_floating representation in the presence of the pragma LONG_FLOAT(D_FLOAT). Section 2.1.3.1 of this manual and Chapter 3 of the VAX Ada Language Reference Manual discuss this pragma in more detail. You can also use the ACS CREATE LIBRARY, CREATE SUBLIBRARY, and SET PRAGMA commands to control the representation of the type LONG_FLOAT. These commands are described in Developing Ada Programs on VMS Systems. VAX Ada allows you to define your own floating-point types. The choice of representation for nonpredefined floating-point types that are not explicitly derived depends on the precision (digits) and the range specified. The VAX Ada compiler chooses the first of the types STANDARD.FLOAT, STANDARD.LONG_FLOAT, and STANDARD.LONG_LONG_FLOAT that has adequate precision and range, and uses it as the parent type from which the new type is derived. If the G_floating representation of the type LONG_FLOAT is in effect for the compilation (see Table 2-2 and Section 2.1.3.1), the following representations are used if the specified range can also be accommodated: G_floating Digits Specified 1.. 2-6 Representations 6 F_floating 7. 15 G_floating 16 .. 33 H_floating Object Representation and Storage If the D_floating representation of the type LONG_FLOAT is in effect for the compilation (see Table 2-2 and Section 2.1.3.1), the following representations are used if the specified range can also be accommodated: D_floating Digits Specified Representations 1.. 6 F_floating 7.. 9 D_floating 10 .. 33 H_floating For example, the pragma LONG_FLOAT in the following declaration ensures that the D_floating representation of the type LONG_FLOAT is in effect when the declaration is compiled. However, the compiler will choose the type STANDARD.LONG_LONG_FLOAT as the parent type for the type SIZE because although a D_floating representation satisfies the precision, it does not satisfy the range. pragma package type end LONG FLOAT (D_FLOAT) ; FLOAT TYPES SIZE is is digits 9 range -0.1E-50 .. 0.1E+50; FLOAT TYPES; In all cases, the choice of representation for a floating-point type is determined by the model number limits specified by the Ada language (see Chapter 3 of the VAX Ada Language Reference Manual). However, once the representation is chosen, the full accuracy of the underlying VAX floating- point type 1s used in any calculations involving numbers of that type. For example, the following type declaration causes the full 16 decimal digits of accuracy provided by the VAX D_floating hardware representation to be used 1n calculations involving objects of the type: type VOLUME is digits 9 range -100.0 .. 100.0; Table 2-3 lists the model numbers for each VAX floating-point type (and thereby for each VAX Ada predefined floating-point type). The ranges in the table are approximate; the exact ranges are listed in Appendix F of the VAX Ada Language Reference Manual. You can also find the exact ranges by evaluating language-defined attributes T’ SMALL and T' LARGE, where T is the floating-point type. Table 2-3 lists only the positive ranges; all floating-point numbers are, in fact, signed, and an equivalent negative range (as well as zero) exists for each type. Object Representation and Storage 2-7 Table 2-3: Model Numbers Defined for Each Floating-Point Type VAX Ada Types and Digits Mantissa Bits Exponent Range Representations (D) (B) (-4*B..+4*B) Approximate Range F_floating 6 21 -84 .. 84 2.5E-26 .. 1.9E+25 9 31 -124 .. 124 2.3E-38 .. 2.1E+37 15 51 -204 .. 204 1.9E-62 .. 2.5E+61 33 111 —444 .. 444 1.1E-134 .. 4.5E+133 F_FLOAT FLOAT D_floating D_FLOAT LONG_FLOAT G_floating G_FLOAT LONG_FLOAT H_floating H_FLOAT LONG_LONG_FLOAT For both predefined and nonpredefined types, the Ada language rules about safe numbers also apply (see Chapter 3 of the VAX Ada Language Reference Manual). Table 24 lists the safe numbers for each VAX floating-point type (and thereby for each VAX Ada floating-point type). The ranges in the table are approximate; the exact ranges are listed in Appendix F of the VAX Ada Language Reference Manual. You can also find the exact ranges by evaluating the language-defined attributes T" SAFE_SMALL and T’ SAFE_ LARGE, where T is the floating-point type. As with the model numbers, only the positive ranges are listed; each type includes zero and a set of corresponding negative values. 2-8 Object Representation and Storage Table 2—4: Safe Numbers Defined for Each Floating-Point Type Mantissa Exponent VAX Ada Types and Digits Bits Range Representations (D) (B) (-E..+E) F_floating 6 21 -127 .. 127 29E-39 .. 1.7E+38 9 31 —127 .. 127 29E-39 .. 1.7E+38 15 51 -1023 .. 1023 5.5E-309 .. 8.9E+307 33 111 —16383 .. 16383 Approximate Range F_FLOAT FLOAT D_floating D_FLOAT LONG_FLOAT G_floating G_FLOAT LONG_FLOAT H_floating H_FLOAT 8.4E—4933 .. 5.9E+4931 LONG_LONG_FLOAT 2.1.3.1 Pragma LONG_FLOAT The VAX Ada predefined pragma LONG_FLOAT acts as a program library switch that controls whether the G_floating or D_floating representation is used to represent the type LONG_FLOAT. Use of this pragma implies a recompilation of the predefined environment—the package STANDARD—for a given program library. See the VAX Ada Language Reference Manual for the specific rules governing the use of this pragma; see Developing Ada Programs on VMS Systems for a discussion of the implications of recompiling the package STANDARD. For example, the compilation of the following unit will cause all subsequent compilations in the same library to use the set of representations that include D_floating, as appropriate (see Section 2.1.3): pragma LONG FLOAT (D FLOAT) ; package USE D FLOAT -— D_floating type -— MY type representation will DFLOAT Hfloating is is digits 9 range representation will MY HFLOAT is digits 11 range be used. -100.0 be .. 100.0; used. -100.0 .. 100.0; Object Representation and Storage 2-9 -— D floating representation will be used. D OBJECT: LONG FLOAT; end USE D FLOAT; To return to G_floating representations, you can use one of the following methods: Compile another unit (in the same library) that contains the pragma LONG_FLOAT(G_FLOAT). ¢ TUse the ACS SET PRAGMA command. Recreate your library by first deleting it with either the ACS DELETE LIBRARY or DELETE SUBLIBRARY command, and then creating it with the ACS CREATE LIBRARY or SUBLIBRARY command. See Developing Ada Programs on VMS Systems for information on the ACS commands. 2.1.3.2 VAX F_floating Representation An F_floating-point number (single precision) is represented in memory by 4 contiguous bytes (32 bits). The bits are numbered from the right, 0 through 31, as shown in Figure 2—1. Figure 2-1: F_floating Representation 15 14 S 76 EXPONENT 0 FRACTION A FRACTION 31 16 ZK-1039-GE 2-10 Object Representation and Storage The address of an F_floating-point value is the address of the byte containing bit O (address A in Figure 2-1). The form of the value is signed magnitude as follows: e Bit 15 is the sign bit. e Bits 14 through 7 are an excess 128 binary exponent. e Bits 6 through 0 and 31 through 16 are a normalized 23-bit fraction, with the redundant most significant fraction bit not represented. Within the fraction, bits of increasing significance go from 16 through 31 and from O through 6. The 8-bit exponent field encodes the values 0 through 255 as follows: e e An exponent value of 0 with a sign bit of 0 indicates that the floatingpoint number has a value of 0. Exponent values of 1 through 255 indicate binary exponents of —127 through +127. If you are doing unchecked conversions to floating-point types (see Chapter 13 of the VAX Ada Language Reference Manual), note that an exponent value of 0 with a sign bit of 1 is considered to be a reserved operand. Floating-point instructions that process a reserved operand cause a reserved operand fault. In VAX Ada, the VAX F_floating representation is used to represent the set of model numbers shown in Table 2-3 and the set of safe numbers shown in Table 2—4. On VAX machines, the value of an F_floating-point number is in the approximate range of 0.29*10~38 through 1.7¥1038. The precision of an F_floating-point value is approximately one part in 223, or at least 6 decimal digits. 2.1.3.3 VAX D_floating Representation A D_floating-point number (double precision) is represented in memory by 8 contiguous bytes (64 bits). The bits are numbered from the right, 0 through 63, as shown in Figure 2-2. Object Representation and Storage 2-11 Figure 2-2: D_floating Representation 15 14 S /6 EXPONENT 0 FRACTION A FRACTION FRACTION FRACTION 63 48 ZK-1040-GE The address of a D_floating-point value is the address of the byte containing bit 0 (address A in Figure 2-2). The form of the value is signed magnitude as follows: Bit 15 is the sign bit. e ¢ Bits 14 through 7 are an excess 128 binary exponent. Bits 6 through 0 and 63 through 16 are a normalized 59-bit fraction, with the redundant most significant fraction bit not represented. Within the fraction, bits of increasing significance are numbered 48 through 63, 32 through 47, 16 through 31, and 0 through 6. The 8-bit exponent field encodes the values 0 through 255 as follows: * An exponent value of 0 with a sign bit of 0 indicates that the floatingpoint number has a value of 0. * Exponent values of 1 through 255 indicate binary exponents of —127 through +127. If you are doing unchecked conversions to floating-point types (see Chapter 13 of the VAX Ada Language Reference Manual), note that an exponent value of 0 with a sign bit of 1 is considered to be a reserved operand. Floating-point instructions that process a reserved operand cause a reserved operand fault. 2-12 Object Representation and Storage In VAX Ada, the VAX D_floating representation is used to represent the set of model numbers shown in Table 2-3 and the set of safe numbers shown in Table 2—4. On VAX machines, the exponent conventions and approximate range of values are the same for D_floating-point values as for F_floating-point values. However, the precision of a D_floating-point value is approximately one part in 2°°, or 16 decimal digits. 2.1.3.4 VAX G_floating Representation A G_floating-point number (double precision) is represented in memory by 8 contiguous bytes (64 bits). The bits are numbered from the right, 0 through 63, as shown in Figure 2-3. Figure 2-3: G _floating Representation 15 14 S 4 3 EXPONENT 0 FRACTION A FRACTION FRACTION FRACTION 63 | 48 ZK-1041-GE The address of a G_floating-point value is the address of the byte containing bit 0 (address A in Figure 2-3). The form of a G_floating-point value is signed magnitude as follows: ¢ Bit 15 is the sign bit. * Bits 14 through 4 are an excess 1024 binary exponent. e Bits 3 through 0 and 63 through 16 represent a normalized 53-bit fraction, with the redundant most significant fraction bit not represented. Within the fraction, bits of increasing signficance go from 48 through 63, 32 through 47, 16 through 31, and 0 through 3. Object Representation and Storage 2-13 The 11-bit exponent field encodes the values 0 through 2047 as follows: * An exponent value of 0 with a sign bit of 0 indicates that the G_floating-point number has a value of 0. * Exponent values of 1 through 1047 indicate binary exponents of —1023 through +1023. If you are doing unchecked conversions to floating-point types (see Chapter 13 of the VAX Ada Language Reference Manual), note that an exponent value of 0 with a sign bit of 1 is considered to be a reserved operand. Floating-point instructions that process a reserved operand cause a reserved operand fault. In VAX Ada, the VAX G_floating representation is used to represent the set of model numbers shown in Table 2-3 and the set of safe numbers shown in Table 2—4. On VAX machines, the value of a G_floating-point number is in the approximate range of 0.56%10~3%8 through 0.90%*10308, The precision of a G_floating-point value is approximately one part in 2°2, or 15 decimal digits. 2.1.3.5 VAX H_floating Representation An H_floating-point (quadruple precision) value is represented in memory by 16 contiguous bytes (128 bits). The bits are numbered from the right, 0 through 127, as shown in Figure 2—4. 2-14 Object Representation and Storage Figure 2-4: 15 H_floating Representation 14 S 0 EXPONENT ‘A FRACTION FRACTION FRACTION FRACTION FRACTION FRACTION FRACTION 127 112 ZK-1042-GE The address of an H_floating-point value is the address of the byte containing bit 0 (address A in Figure 2—4). The form of an H_floating-point value is signed magnitude as follows: e Bit 15 is the sign bit. ¢ Bits 14 through 0 are an excess 16,384 binary exponent. e Bits 127 through 16 are a normalized 113-bit fraction, with the redun- dant most significant fraction bit not represented. Within the fraction, bits of increasing significance go from 112 through 127, 96 through 111, 80 through 95, 64 through 79, 48 through 63, 32 through 47, and 16 through 31. The 15-bit exponent field encodes the values 0 through 32,767 as follows: * An exponent value of 0 with a sign bit of 0 indicates that the H_floating-point number has a value of 0. * Exponent values of 1 through 32,767 indicate binary exponents of —16,383 through +16,383. Object Representation and Storage 2-15 If you are doing unchecked conversions to floating-point types (see Chapter 13 of the VAX Ada Language Reference Manual), note that an exponent value of 0 with a sign bit of 1 is considered to be a reserved operand. Floating-point instructions that process a reserved operand cause a reserved operand fault. In VAX Ada, the VAX H_floating representation is used to represent the set of model numbers shown in Table 2-3 and the set of safe numbers shown in Table 2—4. On VAX machines, the value of an H_floating-point number is in the approximate range of 0.84*10~4932 through 0.59*%10%932, The precision of an H_floating-point value is approximately one part in 2112, or 33 decimal digits. 2.1.4 Fixed-Point Types and Objects Fixed-point types provide approximations to the real numbers, with absolute bounds on errors determined by the value T* SMALL, where T is the fixed-point type. T SMALL is defined to be less than or equal to the delta specified in the type declaration. In the absence of a length representation clause for T SMALL, the delta value determines the value of T’ SMALL, and the model numbers chosen for the type are determined from the value of T SMALL and the specified range. VAX Ada supports only values of T SMALL that are powers of two between 2.0762 and 2.031, inclusive. The VAX Ada compiler chooses the largest possible value of T SMALL that is not greater than the specified delta, regardless of the range. Values for objects of a fixed-point type are represented in VAX Ada as signed or unsigned, two’s complement (binary) numbers multiplied by the value of T'SMALL. You can use length representation clauses to achieve unsigned representations; see Section 2.2.2. In VAX Ada, the storage size for an object of any fixed-point type is determined by its delta and range and rounded up to an 8-, 16-, or 32-bit boundary. You can change the size with a representation clause (see Section 2.2 of this manual and Chapter 13 of the VAX Ada Language Reference Manual). Operations on fixed-point types truncate the result towards 0.0, unless the language specifies otherwise. 2-16 Object Representation and Storage Note that both model numbers and model intervals are used to define the permissible legal values for the results of operations on real (in this case, fixed-point) types. Any value that falls in the defined model interval for an operation is a legal result value for that operation. Thus, when you are working with fixed-point numbers, you may obtain results that are not what you expect in some cases. (See Chapter 4 of the VAX Ada Language Reference Manual for more information on model intervals and operations involving real types.) For example, consider the following declaration: type FP_TYPE is delta 0.1 range 0.0..1.0; Because there is no representation clause for the type FP_TYPE, FP_TYPE'SMALL is 0.0625 (2—4); 0.0625 is the largest power of 2 that is not greater than the delta (0.1). Now, suppose that your program uses an object of type FP_TYPE as follows: A: FP_TYPE := 0.1; A‘ =' 3*A; Because FP_TYPE’'SMALL is 0.0625, and the model numbers used to represent objects of the type FP_TYPE are multiples of 0.0625, the model numbers for A are 0.0625, 0.125, 0.1875, 0.25, and so on up to 1.0. In this case, the model interval for A is 0.0625..0.125; the model interval for 3*A 1is 3*0.0625..3*0.125, or 0.1875..0.375. Because 0.125 is too large, it is not a possible value for A. However, the lower bound, 0.0625, is a possible, and legal, value for A. For reasons of efficiency and to guarantee that the value of 3*A is also legal, the compiler could choose 0.0625 for A. Then, 3*A would result in 0.1875, which may be rounded up when printed out with an input-output procedure (rounding occurs when the FORE or AFT parameters constrain the number of decimal digits that the input-output procedure can print). If FP_TYPE’' SMALL were instead 0.03125 (either because of a different delta or because of a representation clause), the model interval for A would be 0.09375..0.125. Again, 0.125 is too large, but this time if the lower bound, 0.09375, is chosen for the value of A, 3*A results in 0.28125. This value is closer to the expected value, and is rounded up to 0.3 when printed out. Therefore, when working with fixed-point types, and the results are not what you expect, consider tuning the distance between the underlying model numbers by using a representation clause (see Chapter 13 of the VAX Ada Language Reference Manual). Object Representation and Storage 2-17 2.1.5 Array Types and Objects In VAX Ada, an object of an array type is stored as a vector of equally spaced storage cells, one cell for each component. Any space between the components is assumed to belong to the array object, and may or may not be read or written by operations on the object. Thus, the storage size for an object of an array type is determined by the following equation: number of components * (component size + distance between components) Multidimensional arrays are stored in row-major order, and the components of all VAX Ada arrays are byte-aligned by default. To force bit alignment and/or to minimize gaps, you must use the pragma PACK with the array type declaration. For example, consider the following declarations: type COLORS type SPECTRUM is is WHITE LIGHT: (RED, ORANGE, YELLOW, array(l..10) of GREEN, BLUE, VIOLET): COLORS; SPECTRUM; Here, because values of the type COLORS are stored in a byte (see Section 2.1.1), and SPECTRUM has 10 components of the type COLORS, 10 bytes are allocated for the object WHITE_LIGHT. In the next example, the object CHAR_ARRAY is stored in 30 bytes (thirty 8-bit components): subtype type INT array (INT CHAR ARRAY: 2.1.6 is INTEGER range TWO DIM ARRAY range 1..10; is <>, INT range <>) of CHARACTER; TWO DIMARRAY(1..5,5..10); Record Types and Objects In VAX Ada, the representation chosen for objects of a record type depends on a complex interaction among any applicable representation clauses and the types and subtypes of the record components. VAX Ada does not place any implementation-defined components within the object. For example, if the offset from the start of the object to a particular component depends on a value of a discriminant of the object, that offset is recalculated rather than stored in a “hidden” component in the record. This implementation allows you to explicitly specify all of the components of a record object, and to expect the result to be suitable for mixed-language programming. 2-18 Object Representation and Storage Record objects are laid out so that all components affected by record representation clauses are first placed at the specified storage places; the remaining components are then laid out in the order in which they appear in the record declaration, discriminants first. Variants are overlaid and any alignment requirements of the components are met. Thus, in the following example, the components are laid out in the order I, J, A, and B: type SIMPLE ARRAY is array (INTEGER range <>) type SIMPLE LAYOUT (I,J: INTEGER) is of BOOLEAN; record A: INTEGER; B: SIMPLE ARRAY(I..J); end record; Consider another example: type SHOW LAYOUT (DISCRIMINANT: BOOLEAN) is record A: INTEGER; case DISCRIMINANT is when TRUE when FALSE => B: => C: CHARACTER; INTEGER; end case; end record; Here, the components are laid out so that DISCRIMINANT appears first, then A. Then, because they are not affected by representation clauses, the variants are laid out starting on the first byte boundary after A. If the type SHOW_LAYOUT from the preceding example were declared with a representation clause that specifically placed a component of one of the variants elsewhere, then that variant would be laid out first. Thus, if SHOW _LAYOUT were declared with the following representation clause, the compiler would lay out B first, then DISCRIMINANT, then A, then C: for SHOW LAYOUT use record B at 0*8 range 0..7; end record; When working with records with discriminants, be aware that the offset from the start of the record object to a particular component may depend on the values of the discriminants, and thus may differ from one object to another. Similarly, the sizes of record objects of the same type may vary because of different discriminant values. Object Representation and Storage 2-19 Within any record type, components whose sizes cannot be determined until run time cause succeeding components unaffected by representation clauses to be allocated at run-time-computed offsets from the start of the record. A component whose size or position cannot be determined until run time is called a dynamic component. The dynamic calculation of component offsets and sizes may be done when the type is elaborated, or it may be done later—when the subtypes of all of the components have been forced, when the type itself is forced, or even at the point where the component is selected (this happens when the actual value of a discriminant is needed to make the calculation). Thus, in the following example, A and B are both dynamically allocated: A because it is a dynamic component (an array with variable bounds), and B because its offset depends on the size of A: type COMPONENT ARRAY type ANOTHER ORDER is array (I,J: (INTEGER INTEGER) range <>) of INTEGER; is record A: COMPONENT ARRAY(I..J); B: INTEGER; : end record; The laying out of a record type allows the compiler to determine the size of the type, where the size of the type is also the size of the largest possible object of that type. The size is related not to the sum of the sizes of the record’s components, but to where the last component was laid out, including any allowances that were made for alignments. In other words, the size of a record type is computed as the position of the last component that physically appears in the layout plus the size of the last component (rounded up to a byte boundary if necessary). (Rounding depends on whether or not the record type itself is packable; see Section 2.2.1.) Consider the following example: BIT ARRAY array pragma PACK subtype N type is (INTEGER is range <>, INTEGER range <>) of (BIT ARRAY); INTEGER range OFFICE_SECTION LAYOUT 1..25; (LENGTH : N WIDTH : N : o type 1; 1) is record OCCUPIED : BITARRAY(1l..LENGTH, end record; FLOOR1 2-20 : OFFICE_SECTION Object Representation and Storage LAYOUT; 1..WIDTH); BOOLEAN; Here, the component OCCUPIED is an array of 1-bit components whose bounds depend on the values of LENGTH and WIDTH. When an unconstrained object, such as FLOOR], is declared, it must be allocated enough storage to accommodate a value in which LENGTH and WIDTH could have any value in the range 1..25. For example, FLOOR1 could be assigned the following aggregate: FLOOR1 := (20, 25, (1..20 => (1..25 => FALSE))): Because the storage size allocated for an object like FLOOR1 must be adequate for any value that could be assigned to that object, the storage size must be the maximum storage size for the object. (The maximum storage size for an object is equal to the size of the type of the object.) For example, you can calculate the maximum storage size of FLOOR1 as follows. The maximum values for LENGTH and WIDTH are each 25, and the largest possible OCCUPIED component is a 25-by-25 array (625 1-bit components). Because LENGTH and WIDTH are each of an integer subtype, one longword (32 bits) is allocated for each; 625 bits are allocated for the component OCCUPIED. The type is not packable (it does not have a compile-time constant size of 32 or fewer bits; see Section 2.2.1), so the estimated storage is rounded up to a byte boundary. Therefore, a total of 88 bytes ((32 + 32 + 625 + rounding bits)/8) will be allocated for FLOORI. The exact calculation of the size of a record can be nontrivial. For example, the size of the following record type can be calculated only by determining each possible record object and then choosing the largest result (which occurs when the value of the discriminant D is 5 or 6): subtype INT is INTEGER range 1..10; is array (INT range <>, INT range <>) type REC (D: INT := 1) is DIM ARRAY type TWO of CHARACTER; record A: TWO_DIM_ARRAY(l..D,D..10); end record; REC_OBJECT: REC; The compiler uses simplifying assumptions to calculate the size of the type REC (REC' SIZE is also the maximum storage size for the object REC_ OBJECT). These assumptions can cause the size allocated (or the values returned by the SIZE and MACHINE_SIZE attributes) to be different from what you might otherwise expect. For example, if you manually calculate the number of bits required for component A, and add that to the number of bits required for discriminant D, you will arrive at one answer. Alternatively, if you ask the compiler for REC_OBJECT' SIZE (or REC_OBJECT'MACHINE_SIZE, as described in Section 2.2.7), you will receive a different answer. In fact, the compiler’s Object Representation and Storage 2-21 answer is based on a value of 10 for the upper bound of the first dimension, and a value of 1 for the lower bound of the second dimension. Therefore, the assumed maximum number of elements is 100, and the assumed storage size—(100*8)+32—is 832 bits. See Section 2.2.7 of this manual and Chapter 13 of the VAX Ada Language Reference Manual for more information on the size attributes. 2.1.7 Access Types and Objects» VAX Ada uses a VAX virtual address to represent the value of an access type; the storage size for this value is a longword (32 bits). The objects designated by values of an access type are sized and represented according to their specified types. If the designated type is an unconstrained array, the virtual address points to an array descriptor that is chosen by the same rules used for choosing descriptors during parameter passing (see Chapter 5). NOTE These addresses do not necessarily point directly to objects of the access type. Thus, it is unsafe (as well as nonportable) to use the predefined generic procedure UNCHECKED_CONVERSION to convert between addresses and access types. Unchecked conversion between VAX addresses and access types is safe only when the accessed object is of a record type. Each nonderived access type is associated with a collection, which is storage to be used for the objects designated by the type when allocators of that type are evaluated. If you specify a nonzero value in a length representation clause for the access type, that value determines the number of bytes (rounded up to an integral number of 512-byte pages) to be allocated for the collection associated with the type. The collection is not extended if it is exhausted. If you specify a zero value (or no length representation clause), the effective size of the collection is all of the available memory; no initial allocation is made, and the collection is extended as needed. The collection associated with an access type is released when the scope of the access type is exited. See Section 2.3.2 for more information on storage deallocation. See Chapter 13 of the VAX Ada Language Reference Manual for more information on length representation clauses and collections. VAX Ada does not do automatic garbage collection. 2-22 Object Representation and Storage In the following example, a 512-byte (1-page) collection is initially allocated for the access type NUM_PTR. One allocator is evaluated for FIRST_NUM, and 64 allocators are evaluated in the loop. Each evaluation causes 8 bytes of storage to be allocated as follows: The designated object in each case is of the type NUM_RECORD, and thus requires a longword (32 bits, or 4 bytes) for the integer component NUM. e Each access type component (NEXT_NUM) requires a longword (32 bits, or 4 bytes). When I reaches 63, a total of 64 allocators has been evaluated, and the collection limit has been reached. When I reaches 64, the collection limit is exceeded and not extended, and the exception STORAGE_ERROR is raised. —— Procedure to construct a linked-list of integers. procedure COLLECTION is type NUM RECORD; type NUM PTR is access NUM RECORD; for NUMPTR’STORAGE_SIZE use 512; type NUM RECORD is record NUM: INTEGER; NEXT NUM: NUM PTR; end record; FIRST NUM,ASSIGN_NUM: I: NUM PTR; INTEGER; begin FIRST NUM ASSIGN NUM for I := new NUM RECORD’ (0,null); := FIRST_NUM; in 1..64 loop ASSIGN NUM.NEXT NUM ASSIGN NUM := new NUM RECORD’ (I,null); := ASSIGN_ NUM.NEXT NUM; end loop; end COLLECTION; 2.1.8 Address Types and Objects VAX Ada uses a VAX virtual address to represent the value of an object of the type SYSTEM.ADDRESS. The storage size for an object of an address type is a longword (32 bits). Object Representation and Storage 2-23 2.1.9 Task Types and Objects VAX Ada uses a VAX virtual address to represent the value of an object of a task type. The storage size for an object of a task type is a longword (32 bits). When you declare an object of a task type, the value of the object is used by the VAX Ada run-time library to determine the address of the task control block created for the task. See Chapter 8 for more information on task storage allocation. 2.2 Data Optimization VAX Ada provides type representation clauses, address clauses, and the language-defined pragma PACK to allow you to tailor the representation of nonpredefined types. Type representation clauses also allow you to control the representation of any new or derived types that you declare. 2.2.1 Pragma PACK The predefined pragma PACK allows you to minimize gaps between the components of composite types (record and array types). When you apply the pragma PACK to a VAX Ada record or array type declaration, it has an effect only on the record or array components that are packable. In VAX Ada, a component is packable if its type allows it to be aligned on an arbitrary bit boundary. For example, if you use the pragma PACK to pack an array of BOOLEAN components, any gaps between the components are minimized because enumeration type components are packable. However, the pragma PACK has no effect on an array of floating-point components. Table 2-5 lists the type categories provided in VAX Ada and shows whether or not components of each type are packable. 2-24 Object Representation and Storage Table 2-5: Packable Types Considered Type Category Packable as a Type Affected by the Pragma PACK if a Component of a Record or Array Integer Yes Yes Enumeration’ Yes Yes Fixed-point Yes Yes Floating-point No No Address No No Access No No Task No No Record Depends? Only if packable Array Depends® Only if packable 1The predefined enumeration type CHARACTER (in the package STANDARD) is implemented as though the following declaration occurred in the package STANDARD: for CHARACTER' SIZE use 8. Thus, even in the presence of the pragma PACK, compositetype components of the type CHARACTER (or derived from the type CHARACTER) are not packed into 7 bits. 20nly if the record type has a compile-time constant size that is less than or equal to 32 bits, and if all of its components are packable. 30nly if the array type is itself a packed array of packable arrays, or if it is an array of 1-bit components. Components of the predefined array type STRING are not packable because the type STRING does not have 1-bit or packable array components. Table 2—6 shows the effect of the pragma PACK on arrays and records with packable components. Object Representation and Storage 2-25 Table 2-6: Effects of Packing the Components of Arrays and Records With Length Without Length Representation Clause Representation Clause on Component Type on Component Type With the Space between array and Space between array and Pragma PACK record components is min- record components is min- imized. Component size is imized. Component size is determined by the length the default allocation for the clause. component type. Saves only as much space as Saves the maximum amount of the length clause allows. storage space. Without the Space between array and Space between array and Pragma PACK record components is not record components is not minimized. Component size minimized. Component size is is determined by the length the default allocation for the clause. component type. Saves only as much space Saves no storage space. as the length clause and the default byte alignment allow. In the following example, the pragma PACK is used to minimize gaps in an array of fixed-point numbers: type SMALL FIXED POINT delta 2.0**(-4) type is range 0.0..0.5; SMALL FIXED POINT ARRAY array (INTEGER pragma PACK range (SMALL FIXED <>) is of SMALL FIXED POINT; POINT ARRAY) ; If SMALL_FIXED_POINT_ARRAY were not packed, the space-saving benefit of the small range of the SMALL_FIXED_POINT components would be lost. All of the components would be aligned on byte boundaries, causing 8-bit instead of the expected 3-bit component representations, and increasing the array size. The next example shows the difference in space saving when length representation clauses are involved (see Section 2.2.2 for more information on length clauses): 2-26 Object Representation and Storage type SMALL INTEGER is new INTEGER range 0..7; for SMALL INTEGER’SIZE use 4; INTEGER_ARRAY is array (1..10) of SMALL INTEGER; SMALL_CKED type UNPA ARRAY is array (1..10) of SMALL_INTEGER; type PACKED SMALLINTEGER (PACKED SMALLINTEGER_ARRAY); pragma PACK In this example, the range of type SMALL_INTEGER causes it to require only 3 bits; however, the length clause specifies a size of 4 bits. For the array UNPACKED_SMALL_INTEGER_ARRAY, the length clause is honored for the SMALL_INTEGER components. However, because the array is declared without the pragma PACK, all of the components will be aligned on byte boundaries, and each component will have an effective size of 8 bits, instead of 4; the size of the array will be 80 bits. For the array PACKED_ SMALL_INTEGER_ARRAY, each component will have a size of 4 bits, and any extra space between the components is eliminated; the size of the array will be 40 bits. When using the pragma PACK, you must be careful to pack at the appropriate level: the pragma packs the components with respect to each other; it does not pack the subcomponents of the components closer together. In the following example, the size of the record UNPACKED_COMPONENTS is significantly larger than the size of the record PACKED_COMPONENTS, even though both are declared with the pragma PACK: type UNSIGNED INTEGER is new INTEGER range 0..7; for UNSIGNED INTEGER’SIZE use 3; type PACKED ARRAY is array (1..10) of BOOLEAN; (PACKED_ ARRAY) ; pragma PACK type UNPACKED ARRAY is array (1..10) of BOOLEAN; type UNPACKED COMPONENTS is record A,B: UNSIGNED INTEGER; C: UNPACKED ARRAY; end record; (UNPACKED COMPONENTS) pragma PACK type PACKED COMPONENTS ; is record D,E: UNSIGNED INTEGER; F: PACKED ARRAY; end record; pragma PACK (PACKED_COMPONENTS) ; UNPACKED COMPONENTS; —-- Size is 88 bits. BIG RECORD: -- Size is 16 bits. COMPACT RECORD: PACKED COMPONENTS; Object Representation and Storage 2-27 Note that the pragma PACK never forces a component that begins a record variant off of a byte boundary. Such components are allocated on the next byte boundary. To force a component that begins a record variant to a boundary other than a byte boundary, you must use a record representation clause (see Sections 2.1.6 and 2.2.4 of this manual and Chapter 13 of the VAX Ada Language Reference Manual). 2.2.2 Length Representation Clauses Length representation clauses allow you to explicitly control the amount of storage allocated for objects of a particular type. The following example shows how length representation clauses are useful for declaring unsigned integer and unsigned fixed-point objects: type UNSIGNED_ INTEGER is new INTEGER range for UNSIGNED INTEGER’SIZE use 16; type UNSIGNED FIXED POINT delta 2.0**(-8) for range 0..2**16-1; is 0.0..255.0*2** (=8) ; UNSIGNED_FIXED POINT’SIZE use 8; The first declaration causes objects of the type UNSIGNED INTEGER to be stored as unsigned words, rather than as signed longwords. The second declaration causes objects of the type UNSIGNED_FIXED POINT to be stored as unsigned bytes, rather than as signed words. Note that because of Ada language rules, arithmetic operations involving these objects is signed. See Chapter 10 for more information on working with unsigned numbers. A length representation clause is also useful for controlling the size of components in packed arrays. For example: type for type SMALL INTEGER is SMALL INTEGER’SIZE new SMALL INTEGER_ARRAY pragma PACK INTEGER use is range 0..7; 4; array (1..16) of SMALL INTEGER; (SMALL_INTEGER ARRAY); In this example, the range of SMALL_INTEGER and the use of the pragma PACK would cause the size of each component of SMALL,_INTEGER ARRAY to be 3 bits. However, the length representation clause causes the size of each component in the packed array to be 4 bits. The VAX Ada Language Reference Manual gives complete information on the use of length representation clauses. Table 2-6 gives information on the interaction between length representation clauses and the pragma PACK. 2-28 Object Representation and Storage 2.2.3 Enumeration Representation Clauses Enumeration representation clauses allow you to specify the internal codes that represent the literals of an enumeration type. When you use an enumeration representation clause, the storage size of each enumeration type is the amount of storage required to represent the full range of codes specified. For example: NO, type ANSWER is (YES, for ANSWER use (YES => 0, MYUNSIGNED_ANSWER: :; UNDECIDED) NO => 8, UNDECIDED => 65535); ANSWER; Here, the storage allocated for MY_UNSIGNED_ANSWER is a word. Even though only three integer codes must be represented, a word (16 bits) is needed to store values in the range 0..65535. If any of the internal codes specified by the representation clause are negative, the representation for the type is signed; otherwise, it is unsigned. Thus, if you were to redeclare the type ANSWER as follows, the internal codes would be signed: type ANSWER is (NO, for ANSWER use (NO => -8, MY SIGNED ANSWER: YES, UNDECIDED) ; YES=> 0, UNDECIDED => 655395); ANSWER; Note that the signed representation requires an additional sign bit. To meet both the range of values (0..65535) and the signed representation, the storage allocated for MY_SIGNED_ANSWER is a longword. 2.2.4 Record Representation Clauses Record representation clauses allow you to force a record type to have a particular representation. Thus, they are useful anytime you need to lay out an area of memory in a particular way. For example, you can use a record with a record representation clause to lay out a series of objects in a particular order. Or, you can use record representation clauses to lay out record types that declare objects that may be passed to other-language routines (including VMS system routines and VMS Run-Time Library routines). In particular, it is good programming practice to specify the layout of any record that is read from or written to an external file. Object Representation and Storage 2-29 The following example defines a 16-bit mask for specifying the protection of a file (this definition is taken from the VAX Ada predefined package STARLET, which also defines the interfaces for various system service and VMS RMS routines). The mask contains four 4-bit fields, each of which specifies the protection to be applied to file access attempts by one of the four categories of user (system, owner, group, world). —— Record —— representing type defining a a 4-bit level of field, file each bit protection. FILE PROTECTIO FLAGS TYPE N is record NOREAD : BOOLEAN; NOWRITE : BOOLEAN; NOEXE "+ BOOLEAN; NODEL : BOOLEAN; end record; for FILE PROTECT FLAGS TYPE'’SIZE ION use for FILEPROTECTIO FLAGS TYPE N use 4; 0 range O.. 0 range 1.. NOEXE at 0 range 2.. NODEL at 0 range 3.. . I'4 S at at s NOREAD NOWRITE WNEHO record ’ - 4 end record; pragma PACK (FILE PROTECTION FLAGS TYPE); —— Record defining a —-— the —-— user; -— out —-— half-bytes. type kind of the the file record 4-bit 16-bit mask that protection representation fields so that FILEPROTECTION REC TYPE determines for each kind of clause they are is record SYS : FILE PROTECTION_ FLAGS TYPE; OWN : FILE PROTECTION FLAGS TYPE; GRP : FILE PROTECTION FLAGS TYPE; WLD : FILE_ PROTECTIO FLAGS TYPE; N end record; for FILE PROTECTION REC TYPE use at 1 range O at 1 range v W GRP WLD TMo range - 4 e range 0 SN W 0 s at at O SYS OWN B record end record; for 2-30 FILE PROTECTI REC TYPE’SIZE ON use Object Representation and Storage 16; lays contiguous When declaring record types with variants, you can use record representation clauses to conserve space. For example: package ALIGN VAR is type SMALL INT is new INTEGER range 0..7; for SMALL INT’'SIZE use type VARIANT RECORD 3; (VAR: BOOLEAN) is => X: CHARACTER; Y: SMALL INT; Z: SMALL INT; record A: SMALL INT; case VAR is when TRUE => when FALSE end case; end record; for VARIANT RECORD use record at 0 range VAR at A 0 range 3..3; 0..2; X at 0 range Y at 0 range 12..14; Z at 0 range 4..6; 4..11; end record:; end ALIGN VAR; Here, the representation clause on the type VARIANT_RECORD causes the variant, VAR, to be aligned on a bit boundary; when an object is declared and a case choice is made, the appropriate component is stored starting on bit 4 of the word of the storage allocated for the record object. (Without the representation clause, the variants would be aligned on byte boundaries.) If you declare a record type with fixed-size components that follow (or are interspersed with) varying-size components, you will generate slower, less efficient code than if you declare a record type where all of the fixed-size components precede the varying-size components. For example: package SLOW LAYOUT is type VARYING ARRAY is array type SLOW _RECORD (I,J: (INTEGER range <>) INTEGER) of BOOLEAN; is record A: INTEGER; B: VARYING ARRAY(I..J); C: INTEGER; D: G ARRAY (I..I); VARYIN end record; SLOW _OBJECT: end SLOW_RECORD (1,10); SLOW_ LAYOUT; Object Representation and Storage 2-31 Here, the layout for the type SLOW_RECORD can be set up by the compiler only to the point of SLOW_RECORD.B; the rest of the layout and the allocation of storage for SLOW_OBJECT must be done at run time. Furthermore, each time you access SLOW_OBJECT.B, the size of SLOW_OBJECT.A must be calculated, thus decreasing the efficiency of any code that uses SLOW_ OBJECT. If the logical layout of a record type such as SLOW_RECORD is important, you can improve the efficiency of your code by declaring the type with a representation clause that forces the fixed-size components to known locations. For example: package NOT SO SLOWLAYOUT is type VARYING ARRAY pragma PACK type is array (INTEGER range <>) of BOOLEAN; (VARYING ARRAY); FASTER RECORD(I,J: INTEGER) is record A: INTEGER; B: VARYING ARRAY(I..J); C: INTEGER; D: VARYING_ARRAY(I..I); end record; for FASTER~RECORD use record at 0 range 0..31; J at I 4 range 0..31; A at 8 range 0..31; C at 12 range 0..31; end record; FASTER;QBJECT: FASTER_RECORD(l,lO); end NOT SO SLOWLAYOUT; Here, FASTER_OBJECT will be laid out so that the components fall in the following order: I, J, A, C, B, and D. The type representation clause forces the allocation of the components FASTER_OBJECT.B and FASTER _ OBJECT.D to the end of the record. Note that when you use a record representation clause to request a very small storage space for a component of a nonfixed-point discrete type, the record component value may be biased (its value may be predictably altered). When biasing occurs, the value stored is the unsigned quantity formed by subtracting COMPONENT _SUBTYPE' FIRST from the original value. (Because subtraction or addition is required to assign or fetch from the 2-32 Object Representation and Storage component storage location, the generated code uses slightly more machine time than the unbiased form.) Thus, in the following example, the values of R.C will be biased to allow them to be stored in the 2 bits required by the record representation clause (without the record representation clause, they would be stored as longwords): subtype type S is INTEGER range 100..103; R is record cC : S; end record; for R use record C at O range 0..1; end record; O 2.2.5 : R; O0.C := 100; Alignment Clauses When you use a record representation clause to define the layout of a particular record type, you have the option of specifying an alignment clause to determine the alignment of all record objects (including record objects that are components) of that type. The VAX Ada Language Reference Manual gives the syntax and rules for using alignment clauses. In VAX Ada, records can be aligned on any byte address that is a power of 2, up to 512 (or 22). Thus, in the following fragment, the value of ALIGN_AT could be any integer in the series 1, 2, 4, 8, ..., 512. A value of 1 indicates byte alignment, a value of 2 indicates word alignment, and a value of 512 indicates page alignment. type for SMALLNUM is new INTEGER range SMALLNUM’SIZE ALIGN AT: use 3; := 2; comnstant 0..7; type ALIGNED RECORD is record Al: BOOLEAN; AZ2: SMALLNUM; end record; Object Representation and Storage 2-33 for ALIGNED RECORD use record at mod ALIGN AT; Al at 0 range 0 .. O; A2 at 0 range 1 .. 3; end record; type SHOW ALIGNMENT is record S1,52,83: end ALIGNED RECORD; record; In this example, the components of the record SHOW_ALIGNMENT are aligned on 2-byte (word) boundaries, and the record SHOW_ALIGNMENT itself is aligned so that its component alignment can be observed. If the value of ALIGN_AT were 16, then the components of the record SHOW_ ALIGNMENT would be aligned on 16-byte boundaries. If you were to declare an array of components of the type ALIGNED_ RECORD, and apply the pragma PACK to the array (which would be legal because the components of ALIGNED_RECORD are packable, and the record could have a compile-time size of less than 32 bits), the pragma would have no effect because the alignment clause interacts with the pragma. VAX Ada places some restrictions on the possible alignments, depending on how objects of an aligned type are allocated (see Chapter 13 of the VAX Ada Language Reference Manual for a list of the restrictions). For example, a record object declared in a subprogram will be stack allocated, and thus can be aligned only at mod 1, 2, or 4 (it can be only byte-, word-, or longword-aligned). To force another alignment, you would have to declare the record type and object in a library package (it would then be statically allocated, and there would be no restrictions). Alternatively, you could declare an access type that designates the record; the designated object would be dynamically allocated, and, again, there would be no restrictions. See Section 2.3 for more information on dynamic storage allocation. Alignment clauses can be useful in a mixed-language environment, where you may want to force objects to particular boundaries. Note, however, that the VAX hardware generally requires very little alignment; only a few instructions and VMS Run-Time Library routines need alignments (for example, queue and interlocked instructions). VAX Ada currently generates very few interlocked instructions. 2-34 Object Representation and Storage 2.2.6 Address Clauses In VAX Ada, address clauses allow you to store objects (constants and variables) at specific memory locations. Thus, you can use address clauses to precisely map memory areas and overlay memory areas during program execution. Chapter 13 of the VAX Ada Language Reference Manual gives the syntax and rules for using address clauses; in particular, note the following rules or effects: e A program that uses address clauses to overlay two or more Ada objects 1S erroneous. e When you declare an object with an address clause, the usual implicit or explicit initialization associated with the type of the object is performed. Thus, access values are initialized to null, and record components may also receive initial values. When you declare an object without an address clause, the compiler chooses an appropriate location for storing the object. However, when you specify an address clause, the compiler does not check that the address you have specified is appropriate. Thus, when you use address clauses, you need to be sure that you choose values that are meaningful in the VMS environment. One way to obtain a meaningful value is to use the VMS Run-Time Library routine LIB$GET_VM to obtain a storage location. Example 2-1 is a complete procedure showing the use of an address clause to overlay an Ada record object onto storage allocated by LIBSGET_VM. The VMS RTL Library (LIB$) Manual describes LIBSGET_VM in more detail. For general information on the VMS environment (including information on VMS virtual address space), see the VAX Hardware Handbook. Object Representation and Storage 2-35 Example 2-1: Using an Address Clause and LIB$GET VM with CONDITION HANDLING; with SYSTEM; with use use CONDITION_ HANDLING; SYSTEM; INTEGER_TEX IO; T use INTEGER TEXT IO; with TEXT IO; with LIB; use TEXT_ IO; procedure ADDRESS CLAUSE USE ——- Declare —— by -- freed by the subtype type a record VMS for Run-Time is which storage Library will routine be allocated LIB$GET VM; and LIBS$FREE VM. STRING 14 is OBJ REC STRING(1l..14); is record A: CHARACTER; B: INTEGER; C: STRING 14; end record; —— Declare -- LIBSFREE_VM. the values NUM_BYTES: constant BASE ADDRESS; ADDR: STATUS: needed INTEGER to := be passed to LIB$GET VM and OBJ REC’MACHINE SIZE/S8; COND VALUE TYPE; begin -— Allocate LIB.GET VM if not the storage (STATUS, for a record NUM BYTES, of type OBJ_ REC. BASE_ADDR) ; CONDITION HANDLING.SUCCESS(STATUS) then PUT_LINE("Failed to allocate memory"); else PUT ("Address of allocated storage is "); PUT(TO_INTEGER(BASE_ADDR)); NEW LINE; end if; —-- Declare an —— storage location —— address clause. object of type OBJ obtained with REC, and place it at LIB$GET VM using an the declare OBJECT: OBJ_REC:; for OBJECT use at O: STRING_14 := BASE ADDR; "Time for fun.."; (continued on next page) 2-36 Object Representation and Storage Example 2-1 (Cont.): Using an Address Clause and LIB$GET_VM -— Do some useful work with the record object, and —— then free the storage by calling LIBSFREE VM. begin OBJECT := (A => 'A’, B => 5, C => "Summer is a..."); PUT LINE (OBJECT.C); OBJECT.C := O; PUT_ LINE (OBJECT.C) ; end; LIB.FREE VM (STATUS, NUM_BYTES, BASE_ADDR) ; end USE ADDRESS_ CLAUSE; 2.2.7 Determining the Sizes of Types and Objects VAX Ada provides a number of methods for determining how much storage has been allocated for particular types and objects: * You can use the predefined attributes T’ SIZE and T' MACHINE_SIZE to determine the number of bits used and allocated for a given type or object. e You can use the /WARNINGS=COMPILATION_NOTES qualifier on any of the compilation commands (DCL ADA and ACS COMPILE and RECOMPILE) to determine how record types and so on have been laid out. * You can use the debugger (after compiling and linking your program) to examine the sizes of your variables. The first of these methods is discussed in this section; the other two are described in Developing Ada Programs on VMS Systems. As indicated by its name, the predefined SIZE attribute returns information on the size of a type or an object (see Chapter 13 of the VAX Ada Language Reference Manual). When using this attribute, note the following differences in the values it returns: e e T/SIZE (where T represents a type) returns the minimum number of bits needed to represent an object of the type. (’SIZE (where O represents an object) returns the actual number of bits used for the object’s current value. Object Representation and Storage 2-37 The minimum number of bits and the actual number of bits can often be quite different. For example, given the following declaration, the value of BOOL17' SIZE will be 1: type BOOL1l7 is new BOOLEAN; One bit is the minimum amount of storage required for an object of the type BOOL17. Even if you used a representation clause to declare BOOL17, as in the following declaration, the value of BOOL17’ SIZE will still be 1; when applied to types, the SIZE attribute is not affected by representation clauses: type BOOL1l7 is new BOOLEAN; for BOOL17’SIZE use 17; The VAX Ada attribute T MACHINE_SIZE provides similar information for a type or subtype that O’ SIZE provides for an object. Table 2—-7 summarizes the differences between T’ SIZE, O’ SIZE, and T MACHINE_SIZE. Table 2-7: Comparison of SIZE and MACHINE_SIZE Attribute Results Type or Subtype T’ SIZE O’ SIZE T’ MACHINE_SIZE Discrete or fixed-point Minimum number Actual number of Total number of without length clause of bits needed to represent an object of bits used by O. If bits allocated for an object of the the type or subtype T. or array component subtype. Result is or is unpacked, the the actual number of result is the same as bits used, rounded O is not a record the T MACHINE _ up to an 8-, 16-, or SIZE result for O’s 32-bit boundary; subtype. If O is a representation is packed component, the signed. result is the number of bits needed so that components can be packed as tightly as possible. (continued on next page) 2-38 Object Representation and Storage | Table 2-7 (Cont.): Comparison of SIZE and MACHINE_SIZE Attribute Results Type or Subtype T’ SIZE Discrete or fixed-point Minimum number Actual number of bits Total number of with length clause of bits needed to used by O; length bits allocated for an represent an object of clause determines object of the type or the type or subtype T. upper bound (except if subtype T. Result is O is a component of a the actual number of record specified with a bits used, rounded O’ SIZE component clause). T' MACHINE_SIZE up to an 8-, 16-, or 32-bit boundary; representation can be unsigned. All other types, with or Minimum number Actual number of bits Total number of without length clauses of bits needed to used by O. bits allocated for an represent an object of object of the type T. the type or subtype T. Result is the actual number of bits used, rounded up to a byte boundary. Note that the T MACHINE_SIZE of a base type can be equal to or greater than the T’ SIZE of the same base type. The T MACHINE_SIZE of a base type can also be less than the T’ SIZE of a first named subtype that has an associated size representation clause. Consider the following declarations: type for I: INT8 is INT8’SIZE range use 0..255; 8; INTS8; An examination of INT8 and I produces the following results: INT8’ SIZE 8 INT8' MACHINE_SIZE 8 I’ SIZE 8 INT8’ BASE’ SIZE 16 INT8’ BASE' MACHINE_SIZE 16 The number of bits needed to represent the specified range values symmetrically about 0 is 16, so that INT8' BASE’ SIZE is 16. This value is greater than the values of INT8' MACHINE_SIZE, INTS8' SIZE, and I' SIZE. Note that the values of INT8 MACHINE_SIZE and I' SIZE are equal, as they should be. Object Representation and Storage 2-39 Table 2-8 gives a set of results for a variety of interesting cases. Table 2-8: Results of Size Attributes for Various Types and Objects Declaration and Attributes Number of Bits type BOOL17 is new BOOLEAN; for BOOL17’ SIZE use 17; B: BOOL17; Type BOOL17’ SIZE Object B’ SIZE Type BOOL17* MACHINE_SIZE 1 17 Type BOOL17’ BASE’ SIZE 32 1 Type BOOL17’ BASE' MACHINE_SIZE 32 type ET is range 0..255; for ET’ SIZE use 8; et Type ET’ BASE' SIZE Type ET' BASE' MACHINE_SIZE o Object E’ SIZE Type ET' MACHINE_SIZE Oy 00 Q0 OO E: ET; Type ET’ SIZE type NET is new ET range 0..7; NET' BASE’ MACHINE_SIZE O Type NET' BASE'’ SIZE Type - Object NE’ SIZE Type NET' MACHINE_SIZE S Type NET' SIZE 0 oW NE: NET; type NT is new INTEGER range 0..255; for NT' SIZE use 8; N:NT; (continued on next page) 2-40 Object Representation and Storage Table 2-8 (Cont.): Results of Size Attributes for Various Types and Objects Declaration and Attributes 'Number of Bits o Type NT’ SIZE OO 00 Object N’/ SIZE Type NT' MACHINE_SIZE DN W Type NT’ BASE'’ SIZE D Type NT' BASE' MACHINE_SIZE C: CHARACTER; 0 00 = Type CHARACTER' SIZE Object C’ SIZE Type CHARACTER'’ BASE’ SIZE Type CHARACTER’ BASE’ MACHINE_SIZE type BIT _ARRAY o -3 Type CHARACTER’ MACHINE_SIZE is array (1..10) of BOOLEAN; pragma PACK (BIT_ARRAY); BA: BIT_ARRAY; Type BIT_ARRAY’ SIZE Object BA’ SIZE 10 10 Type BIT_ARRAY’' MACHINE_SIZE 16 Type BIT_ARRAY’' BASE’ SIZE 10 Type BIT_ARRAY’ BASE’' MACHINE_SIZE 16 2.3 Storage Allocation and Deallocation To make efficient use of storage from your VAX Ada programs, you need to know how and where objects are stored. You also need to know how and when objects, particularly objects designated by access types, are deallocated. The following sections give information on both of these topics. Object Representation and Storage 241 2.3.1 Storage Allocation The VAX Ada compiler stores objects in registers, on a stack, in static memory, or in dynamic memory (on the heap) depending upon the objects’ size, when their size is known, their type, how long their lifetimes are, and how they are used. If you take the address of an object (O’ ADDRESS), an implicit pragma VOLATILE is assumed for the object within the scope of the subprogram or task where the address is taken. Within that scope, the object is guaranteed to be allocated at a unique memory location, regardless of where the object is declared. If the object is also declared within that scope, the object is allocated in memory for the duration of the object’s lifetime; the object receives a unique memory address, and keeps that address from the time it is elaborated until the time when its containing scope is left. See Chapter 10 for more information on working with address values. See the VAX Ada Language Reference Manual and Chapter 8 for more information on the pragma VOLATILE. If you have specified an object with an IMPORT_OBJECT, EXPORT_ OBJECT, or PSECT_OBJECT pragma, the object is initialized each time it is elaborated. See the VAX Ada Language Reference Manual and Chapter 5 for more information on these pragmas. The compiler always stores objects created by allocators in dynamic memory. In accordance with Ada language rules, the dynamic memory allocated for each access type is structured as a collection. A collection 1s a memory area that comes into existence when the access type is elaborated, and goes out of existence when the scope containing the access type is left. Each time an allocator is evaluated, storage for the resulting object is allocated from the collection belonging to the corresponding access type. There is some CPU overhead involved both when the collection is allocated and when the collection is deallocated (see Section 2.3.2 for more information on storage deallocation). By default, no storage is initially allocated for a collection; storage is allocated as needed, until all virtual memory is depleted. You can change the default behavior with a length clause (see the VAX Ada Language Reference Manual). See Section 2.1.7 for more information on the representation and allocation of objects of access types. You may be able to improve the efficiency of your program by carefully sizing the collections allocated for access types. When you use a length representation clause (T STORAGE_SIZE) to specify the sizes of access type collections, choose values that will be integrally related after they have been rounded up to a number of pages (T STORAGE_SIZE specifies the number 2-42 Object Representation and Storage of bytes to be used for a collection; in VAX Ada, this number is rounded up to an integral number of 512-byte pages). For example, values of 512*%4, 512*8, and 512*12 are better than values of 512*2, 512*7, and 512*13. There is no common denominator for 2, 7, and 13, but there is a common denominator for 4, 8, and 12. This practice will result in reduced fragmentation of memory; also, when you free several collections (implicitly) at scope exit, the freed storage will most likely be in blocks large enough to be useful for other collections. 2.3.2 Storage Deallocation VAX Ada does not provide garbage collection. However, there are at least two ways in which you can deallocate objects of access types: * Make use of the fact that the collection associated with an access type is automatically deallocated when the end statement of the scope containing the access type is encountered. * Instantiate the language-defined generic procedure UNCHECKED _ DEALLOCATION and call the instantiation to explicitly deallocate the storage for an object designated by a value of an access type (see Chapter 13 of the VAX Ada Language Reference Manual for the syntax of UNCHECKED_DEALLOCATION). When you call an instantiation of UNCHECKED_DEALLOCATION, storage 1s deallocated for the object within the collection allocated for the access type. Thus, the effect of using UNCHECKED_DEALLOCATION is to conserve the use of the collection, rather than to deallocate the collection for general use by your program. Note that the collections for access types declared in library packages are not deallocated until the entire program has completed executing. The only way you can conserve the use of such storage is to use an instantiation of the procedure UNCHECKED_DEALLOCATION. Example 2-2 shows a main program that depends on an access type declared in a hibrary package. The program uses an instantiation of the procedure UNCHECKED_DEALLOCATION to deallocate the storage for the access type. Object Representation and Storage 243 Example 2-2: Using UNCHECKED DEALLOCATION to Control Access Type Storage Deallocation —- Package —— corresponding deallocation procedure. containing declarations -- set -- application. using a length clause, to of access type and Collection simulate a size is limited-storage with UNCHECKED DEALLOCATION; package ACCESS TYPES is type LISTELEMENTCLASS type LIST ELEMENT(CLASS is LISTELEMENTCLASS) ; type LISTELEMENTPTR access is (HEAD,ELEMENT) ; for LIST ELEMENT PTR’STORAGE type LIST_ELEMENT (CLASS: LISTELEMENT; SIZE use 4*512; LIST_ELEMENT_CLASS) is record NEXT: case LISTELEMENT PTR; CLASS is when ELEMENT => ELEMENT VALUE: when HEAD HEAD VALUE: => INTEGER; INTEGER := 0; end case; end record; procedure new FREE ELEMENT is UNCHECKED DEALLOCATION (LIST ELEMENT, LIST ELEMENT PTR); end ACCESS_TYPES; —-- Main program that —-— quickly: demonstrates —— (including the -- array header); tasks, which, in turn, -—- lengths. If the access types -—- only -—- of —— package —- collection -— program -— used instead to with in the block, block. the a collection 65-element can be linked create linked lists used by the tasks were of types are declared in a type and exits. conserve use end the is maintained until the main Unchecked deallocation must of the library used by both the main program and the block, for the access an wvarious declared storage would be deallocated at Because the finishes used up list the block inside the program creates of the how a the main program creates collection be storage. INTEGER_TEXT_IO; with ACCESS procedure TYPES CONTROL use INTEGER TEXT IO; use ACCESS_TYPES:; STORAGE is (continued on next page) 2-44 Object Representation and Storage Example 2-2 (Cont.): —— Procedure —- list of integers; -- the list length. procedure HEAD to Using UNCHECKED DEALLOCATION to Control Access Type Storage Deallocation create MAKE LIST and initialize (Y in : INTEGER) ELEMENT: LIST ELEMENT NEXT ELEMENT: : INTEGER := unidirectional parameter to the THIS_ELEMENT, N a the PTR procedure linked determines is := new LIST ELEMENT (HEAD) ; LISTELEMENT PTR; Y; begin —- Create —-—- first and initialize wvalues THIS _ELEMENT for I of list, starting at the element. in := HEAD ELEMENT; 1..N loop THIS ELEMENT.NEXT := new LIST ELEMENT’ (CLASS NEXT => ELEMENT, => null, ELEMENT VALUE THIS ELEMENT := => I); THIS ELEMENT.NEXT; end loop; —- Do -- the something with the linked list...and then deallocate storage. loop THIS ELEMENT := exit when THIS HEAD ELEMENT.NEXT; ELEMENT = null; HEAD ELEMENT.NEXT := THIS ELEMENT.NEXT; FREE ELEMENT (THIS ELEMENT) ; end loop; end MAKE LIST; begin —— Create (and deallocate) the list for the main program. MAKE LIST (64); (continued on next page) Object Representation and Storage 2-45 Example 2-2 (Cont.): Using UNCHECKED DEALLOCATION to Control Access Type Storage Deallocation —— Concurrently, create (and -- varied-length lists used by deallocate) an array a series of of tasks. INNER BLOCK: declare task type entry USE SPACE is NUMELEMENTS (X : in INTEGER); end USE SPACE; type TASK ARRAY SPACE ARRAY: is array (1..10) of USE SPACE; TASK ARRAY; task body USE SPACE is begin accept NUM ELEMENTS (X : in INTEGER) MAKE LIST (X); end; end USE_ SPACE; begin for | I in SPACE ARRAY’RANGE loop SPACE_ARRAY (I) .NUM _ELEMENTS (I) ; end loop; end INNER BLOCK; end 2-46 CONTROL_ STORAGE; Object Representation and Storage do Chapter 3 Input-Output Facilities Although VAX Ada allows you to invoke VMS input-output system services and VMS Record Management Services (RMS) directly (see Chapters 5 and 6), for most applications it is not necessary to do so. The VAX Ada predefined input-output packages provide a rich and comprehensive set of file operations, and each input-output package is tailored for operations on a specific kind of file. VAX Ada predefines the following packages: SEQUENTIAL_IO DIRECT_IO RELATIVE_IO INDEXED_IO SEQUENTIAL_MIXED_IO DIRECT _MIXED_IO RELATIVE_MIXED_IO INDEXED_MIXED_IO TEXT_IO Of these, the packages SEQUENTIAL_IO, DIRECT_IO, and TEXT IO are predefined by the Ada language; the rest are predefined by the VAX Ada implementation. All of the package specifications, as well as explanations of the operations provided by each package, are presented in Chapter 14 of the VAX Ada Language Reference Manual. The VAX Ada predefined packages and their operations are implemented using VMS RMS file organizations and facilities. This chapter describes the implementation and explores some of its implications. Input-Output Facilities 3-1 The information in this chapter is based on the information in Chapter 14 of the VAX Ada Language Reference Manual. You should also be familiar with VMS RMS file organizations and access methods, know how to work with VMS file specifications and directories, and be familiar with the VMS File Definition Language (FDL). If you need introductory information on VMS file specifications and directories or FDL, see the Guide to VMS File Applications. For more information about VMS RMS and VMS RMS services, see the VMS Record Management Services Manual; for more information on FDL, see the VMS File Definition Language Facility Manual. 3.1 Files and File Access To input and output data to and from an Ada program, you must first assoclate the file objects in your program with external files. All of the VAX Ada input-output packages supply CREATE and OPEN procedures that allow you to make this association: e * Each CREATE procedure creates a new external file and then associates a file object with it. Each OPEN procedure associates a file object with an existing external file. Thus, in the following example, EXTERNAL_FILE.TXT is created only once, but it is associated with both file objects ONE_FILE and ANOTHER_FILE at different points in the procedure: 3-2 Input-Output Facilities with TEXT IO; procedure use TEXT IO; MAKE FILES is ONE FILE: FILE TYPE; ANOTHER FILE: FILE TYPE; begin —— Create -— the CREATE and associate => ONE FILE, => "EXTERNAL FILE.TXT"); Close the EXTERNAL FILE.TXT file object it with ONE FILE. NAME -— and disassociate it with ONE FILE. (ONE FILE); —-— Reopen -- a EXTERNAL FILE.TXT different OPEN end object (FILE —— CLOSE EXTERNAL FILE.TXT file file and associate it with obiject. (FILE => ANOTHER FILE, MODE => OUT FILE, NAME => "EXTERNAL FILE.TXT"); MAKE FILES; When you create or open a VAX Ada file object, the external file with which it 1s associated is a VMS RMS file that has a particular kind of organization and that allows a particular kind of access. Each element in the file is associated with a VMS RMS record that has a particular kind of format. A default organization, access, and record format is determined by the input-output package that you use to create the file. Depending on the package, you can change these defaults with a CREATE or OPEN FORM parameter. Section 3.3 discusses the FORM parameter and system-dependent external file attributes in more detail; Sections 3.6.1 through 3.6.4 and 3.7 provide tables of default attributes for each VAX Ada input-output package. The following sections summarize how file objects, called Ada files in this chapter, and external files (VMS RMS files) are related. See Chapter 14 of the VAX Ada Language Reference Manual for detailed definitions of Ada files; see the Guide to VMS File Applications for detailed definitions of VMS RMS file organizations and record formats. Input-Output Facilities 3-3 3.1.1 Ada Sequential Files An Ada sequential file is a set of file elements occupying consecutive positions in linear order. Values are transferred in the order in which they are read or written to the file, and when you open a file, the transfer starts from the beginning of the file. You can associate an Ada sequential file with a VMS RMS file of any organization; the records in the VMS RMS file can have fixed-length, variable-length, variable-length with fixed-length control (VFC), or stream format. The packages SEQUENTIAL_IO and SEQUENTIAL_MIXED_IO provide sequential access to Ada sequential files. 3.1.2 Ada Direct Files An Ada direct file is a set of file elements occupying consecutive positions in linear order. You can transfer values to or from an element of the file at any selected position. The position of an element is specified by its index, which is an integer in the range from 1 to 231 — 1 (a value of the subtype POSITIVE_COUNT). The first element, if any, has an index of 1; the index of the last element, if any, is called the current size. The current size is zero if there are no elements. An open Ada direct file has a current index, which is set to 1 when you create or open the file. The current index determines which element will be involved in the next read or write operation. You can associate an Ada direct file only with a VMS RMS file with sequential organization; the records in the VMS RMS file must have fixed-length format. The packages DIRECT_IO and DIRECT_MIXED_IO provide direct access to Ada direct files. 3.1.3 Ada Relative Files An Ada relative file is a set of fixed-length cells occupying consecutive positions in linear order. Cells in a relative file are numbered from 1 to 231 _ 1 (the numbers are values of the subtype POSITIVE_COUNT); the number of a cell is called its index. The cells in a relative file can either be empty or can contain fixed- or variable-length elements. 3-4 Input-Output Facilities An open Ada relative file has a current index, which is set to 1 when the file is created or opened. The current index determines which element will be involved in the next read or write operation. The concept of size does not apply to relative files; end-of-file is true if, starting at the current index, all cells are empty. You can associate an Ada relative file only with a VMS RMS file with relative organization; the records in the VMS RMS file can have fixedlength, variable-length, or variable-length with fixed-length control (VFC) format. The packages RELATIVE_IO and RELATIVE_MIXED IO provide relative access to Ada relative files. 3.1.4 Ada Indexed Files An Ada indexed file is a set of file elements that are ordered by predefined keys. Each element has at least one primary key (numbered 0), and may have as many as 254 alternate keys (numbered 1 to 254). You define keys in the form string (in the FORM parameter) when the file is created. The elements of an indexed file can be accessed by any key. An open Ada indexed file has a next element, which is the first element determined by the primary key when the file is first opened; the next element is redefined after each successful read operation, or it may be reset to the first sequential element according to the specified key. The concept of size does not apply to Ada indexed files: end-of-file is true if, starting at next element in the file, no elements exist. You can associate an Ada indexed file only with a VMS RMS file with indexed organization; the records in the VMS RMS file can have fixed-length or variable-length format. The packages INDEXED_IO and INDEXED_ MIXED_IO provide indexed access to Ada indexed files. 3.1.5 Ada Text Files An Ada text file is a sequence of pages, where a page is a sequence of lines, and a line is a sequence of characters. Characters, lines, and pages are all numbered starting from 1 and range to 23! — 1 (the numbers are values of the subtype POSITIVE_COUNT). The number of a character is called its column number. The line terminator that marks the end of a line has a column number that is one more than the number of characters in the line. Input-Output Facilities 3-5 The current column number in a text file is the column number of the next character or line terminator to be read or written. Similarly, the current line number is the number of the current line, and the current page number is the number of the current page. You can associate an Ada text file only with a VMS RMS file with sequential organization. The records in the VMS RMS file can have fixed-length, variable-length, or variable-length with fixed-length control (VFC) format. The package TEXT IO provides sequential access to Ada text files. 3.2 Naming External Files In VAX Ada, you identify external files using VMS file specifications. All of the VAX Ada input-output packages have CREATE and OPEN procedures which, in turn, have a NAME parameter that allows you to associate the name of an external file with a particular file object. The NAME parameter can have one of two values: * A string that denotes a VMS file specification or a logical name. If the value of NAME is a file specification, the Ada file object given by the FILE parameter in the particular CREATE or OPEN procedure is associated with an external file named by that specification. * A null string (the default). If the value of NAME is a null string, then the external file is a temporary file that is deleted when the file is closed. Temporary files have no file name; however, they are created using the file specification SYS$SCRATCH.:. To redirect temporary files to another device, redefine the logical name SYS$SCRATCH to name a different device. Note that because temporary files are not entered in a directory, they cannot inherit the file ownership of any directory. The CREATE and OPEN procedures also have a FORM parameter that allows you to identify an external file (see Section 3.3). In VAX Ada, the FORM parameter takes as its value a VMS FDL string or a reference to a file of FDL statements. By specifying a value for the FDL FILE DEFAULT _ NAME attribute in a CREATE or OPEN FORM parameter, you can give file specification information that will be used by default if any of that information is omitted from the string given for the NAME parameter. Thus, in the following example, the external file will have the specification SOME_FILE.DAT: 3-6 Input-Output Facilities NAME => F, I MODE OUT_FILE, Il CREATE (FILE "SOME FILE", FORM => "FILE; DEFAULT NAME ' .DAT'"); The value of the NAME parameter governs, even if you give a value using the FORM parameter and FDL attributes. For example, if you omit a value for the NAME parameter and try to specify a complete file name with the FDL FILE DEFAULT_NAME attribute, the default name is ignored, and the external file is still a temporary file that is deleted when the file is closed. You cannot use the FDL FILE NAME attribute to name an external file; a value specified with that attribute is ignored. The following sections summarize how to write and use logical names in place of file specifications. For a full description of file specifications and logical names, see the VMS DCL Concepts Manual and the Guide to VMS File Applications. 3.2.1 File Specification Syntax A file specification identifies an external file or a device on the VMS operat- ing system. The syntax is as follows: node: :device: [directory]filename.type;version node Is the name of a network node. This element applies only to systems that are part of a network (systems that support DECnet-VAX). device Is the name of the physical device on which the file is stored or is to be written. The device name is the only part of a file specification that is used for record-oriented devices (such as printers and card readers). directory Is the name of the directory (and any subdirectories) under which the file is cataloged on the specified device. You must delimit the directory name with square brackets ([]), as shown in the syntax description, or with angle brackets (<>). You must use a period to separate a series of directories or subdirectories within the square or angle brackets. Directory names apply only to files stored on disk devices (as opposed to files stored on tape). Input-Output Facilities 3-7 filename Is the name of the file; the maximum length is 39 characters. The allowed characters are upper- or lowercase letters, digits, underscore (_), hyphen (-), or dollar sign ($). A file name specification is appropriate only for files stored on mass storage devices (such as disks and tape). type Is the type of the file; the maximum length is 39 characters. The allowed characters are upper- or lowercase letters, digits, underscore (_), hyphen (=), or dollar sign ($). The type must begin with a letter or digit. By convention, the type is an abbreviation that describes the kind of data in the file. You must use a period to separate the file name and type. A type specification is appropriate only for files stored on mass storage devices. version Is a decimal number that specifies which version of the file is desired. The version number is incremented by one each time a new version of a file is created. The maximum version number is 32767. You can refer to version numbers in a relative manner by specifying 0 as the latest (highest numbered) version of the file, —1 as the next most recent version, -2 as the version before that, and so on. You can use either a semicolon, as shown in the syntax description, or a period to separate type and version. A version number is appropriate only for files stored on mass storage devices (such as disks and tape). The maximum size of a file specification, including all delimiters, is 255 characters. You do not need to explicitly state all of the elements of a file specification. If you omit an element, a default value is applied. For more information, see the VMS DCL Concepts Manual. You can use VAX Ada form strings (that is, the value of the FORM parameter in an input-output package CREATE or OPEN procedure) to further define or change default file specifications. See Section 3.3.3. 3.2.2 Logical Names A logical name is a name that represents a file, directory, or physical device. Every logical name is paired with an equivalence string (or list of equivalence strings). An equivalence string is a character string denoting a full file specification, a device name, or another logical name. Thus, logical names are a convenient shorthand for file names to which you refer frequently. See the VMS DCL Concepts Manual and Guide to VMS File 3-8 Input-Output Facilities Applications for complete explanations of logical names and examples of their use. See also the descriptions of the DCL ASSIGN and DEFINE commands in the VMS DCL Dictionary or VMS General User’s Manual. Logical names are maintained by the system in four logical name tables: your process table, the job table for your process, your group table, and the system table. These tables are described in the VMS DCL Concepts Manual. By default, VMS creates a set of logical names for you when you log in. Table 3-1 lists the predefined names that are most relevant to VAX Ada input-output. Table 3-1: Predefined (Default) Logical Names Table in Which the Logical Name Name is Stored What the Name Represents SYS$COMMAND Process Original (first-level) SYS$INPUT stream. SYS$DISK Process Default device established at login or changed by the DCL SET DEFAULT command. SYS$ERROR Process Default device or file to which the system writes error messages generated by warnings, errors, and severe errors. SYS$INPUT Process Default input stream for the process. SYS$LOGIN Job Device and directory established at login time as the home directory for the process. (continued on next page) Input-Output Facilities 3-9 Table 3—1 (Cont.): Predefined (Default) Logical Names Logical Name Name is Stored What the Name Represents SYSS$NET Process The source process that invokes Table in Which the a target process in DECnet-VAX task-to-task communication. When opened by the target process, SYSSNET represents the logical link over which that process can exchange data with its partner. SYS$NET is defined only during task-to-task communication. (Taskto-task communication refers to tasks that are VMS images running in the context of a process, not Ada tasks.) ‘ SYS$OUTPUT Process Default output stream for the process. | SYS$SCRATCH Job Default device and directory to which temporary files are written. TT Process ADASINPUT Determined by user Default device name for terminals. Default device or file from which Ada TEXT IO input is read; SYS$INPUT if not defined by the user. ADASOUTPUT Determined by user Default device or file to which Ada TEXT IO output is written; SYS$OUTPUT if not defined by the user. The names SYS$COMMAND, SYS$ERROR, SYS$INPUT, and SYS$OUTPUT represent process-permanent files (files that are open for the life of your process). They have different equivalence strings associated with them depending on whether they are used interactively, in a batch job, or in a command procedure. You can also redefine them. The VMS DCL Concepts Manual explains and demonstrates the use of these names; Table 3—2 shows the source of the equivalence strings associated with them. Note that you can achieve asynchronous input-output in tasking programs by defining the logical names ADASINPUT and ADA$OUTPUT so that they refer to nonprocess-permanent files; for example, by defining ADASINPUT and ADASOUTPUT so that they refer to TT, you can achieve asynchronous terminal input-output. See Section 3.9.2 for more information. 3-10 Input-Output Facilities Table 3-2: Equivalence Strings for Default Logical Names for ProcessPermanent Files Logical Name Mode! Interactive Batch Mode! Command Procedure’ SYS$COMMAND Terminal Disk Terminal SYS$INPUT Terminal Disk Disk SYS$ERROR Terminal Log file Terminal SYS$OUTPUT Terminal Log file Terminal INote the following definition of terms: terminal means the device name of your terminal; disk means the batch input or command file; and log file means the batch job log file. 3.3 Specifying External File Attributes The CREATE and OPEN procedures in the VAX Ada input-output packages all have a FORM parameter that allows you to specify the system-dependent attributes of an external file. Most of the time you will not need to use the FORM parameter when you create or open a file because each input-output package assumes certain attributes for the external file by default (see Section 3.3.3). In fact, you never need to specify a value for FORM when you open an existing file. You do need to specify it under the following conditions when you create a file: e With a relative or direct file where the item by which the input-output package is instantiated is unconstrained, you must specify the maximum size of the file elements (records) in bytes. e With a relative mixed-type or direct mixed-type file, you must specify the maximum size of the file elements (records) in bytes. * With an indexed file, you must specify information about the primary and any alternate keys. The value of the FORM parameter must be a VMS FDL string, or it must be a reference to a file of FDL statements. FDL is a special-purpose language that is written as an ordered sequence of file attribute keywords (sometimes called FDL statements) and their associated values. These keywords and values determine the characteristics of external files. By using an FDL string (or a reference to a file of FDL statements) as the value of the FORM parameter in a CREATE or OPEN input-output operation, you can give your file any of the VMS RMS Input-Output Facilities 3—11 attributes available in FDL, and you thereby supersede the default file attributes of your input-output package (see Section 3.3.3). If you are not familiar with FDL, see the Guide to VMS File Applications:; it introduces FDL and shows how to design files using the Edit/FDL Utility. See the VMS File Definition Language Facility Manual for complete information about FDL, including specific definitions of the FDL statements. The following sections summarize the FDL concepts and statements that you need to know to specify file attributes in VAX Ada FORM parameters. 3.3.1 The VMS File Definition Language (FDL): Primary and Secondary Attributes FDL statements—whether in an FDL file or in a VAX Ada form string— specify predefined VMS RMS file attributes. Primary attributes take a single value or represent a group of related, or secondary, attributes, which also take values. Most of the primary attributes that have secondary attributes do not themselves take a value. Table 3-3 lists the available primary and secondary attributes. Table 3-3: FDL Primary and Secondary Attribute Descriptions Primary Attribute TITLE Function Secondary Attributes Primary attribute gives a title to None the FDL file. IDENT Primary attribute gives the date and time of creation of the None FDL file, and specifies the name of the creating utility (either Edit/FDL or Analyze/RMS_File). SYSTEM Primary attribute takes no DEVICE, SOURCE, TARGET value. Secondary attributes give system identification information. (continued on next page) 3-12 Input-Output Facilities Table 3—-3 (Cont.): FDL Primary and Secondary Attribute Descriptions Primary Attribute FILE Function Secondary Attributes Primary attribute takes no ALLOCATION, value. BEST_TRY_CONTIGUOUS, Secondary attributes determine BUCKET_SIZE, CLUSTER_SIZE, file characteristics: its default name, owner, organization, protection, and revision; what will happen when it is opened or closed; whether or not data checking will be done when the file is read or written; what kind of processing is allowed; how much space is allocated for the file, and whether or not the space is contiguous; and so on. Secondary attributes also allow specification of magnetic tape file operations. Some FILE secondary attributes have corresponding AREA secondary attributes. CONTEXT, CONTIGUOUS, CREATE_IF, DEFAULT_NAME, DEFERRED_WRITE, DELETE_ON_CLOSE, DIRECTORY_ENTRY, EXTENSION, FILE_MONITORING, GLOBAL_BUFFER_COUNT, MAXIMIZE_VERSION, MAX_RECORD_NUMBER, MT_BLOCK_SIZE, MT_CLOSE_REWIND, MT_CURRENT_POSITION, MT_NOT_EOF, MT_OPEN_REWIND, MT_PROTECTION, NAME, NON_FILE_STRUCTURED, ORGANIZATION, OUTPUT_FILE_PARSE, OWNER, PRINT_ON_CLOSE, PROTECTION, READ_CHECK, REVISION, SEQUENTIAL_ONLY, SUBMIT_ON_CLOSE, SUPERSEDE, TEMPORARY, TRUNCATE_ON_CLOSE, USER_FILE_OPEN, WINDOW_SIZE, WRITECHECK (continued on next page) Input-Output Facilites 3-13 Table 3—3 (Cont.): FDL Primary and Secondary Attribute Descriptions Primary Attribute DATE Function Secondary Attributes Primary attribute takes no BACKUP, CREATION, value. EXPIRATION, REVISION Secondary attributes specify dates and times for backup, creation, expiration, and revision of the file. In general, the only secondary attribute that can be routinely and safely set is EXPIRATION; the others should be set by the system, and thus are not useful in an Ada FORM parameter. RECORD Primary attribute takes no value. BLOCK_SPAN, CARRIAGE_CONTROL, Secondary attributes specify the characteristics of records CONTROL_FIELD, FORMAT, SIZE in the file: their size; the kind of carriage control; and their format. ACCESS Primary attribute takes no BLOCK_IO, DELETE, GET, PUT, value. RECORD_IO, TRUNCATE, UPDATE Secondary attributes specify the file-processing operations allowed on the file. NETWORK SHARING Primary attribute takes no BLOCK_COUNT value. LINK_CACHE_ENABLE Secondary attributes set runtime network access parameters. LINK_TIMEOUT NETWORK_DATA_CHECKING Primary attribute takes no value. DELETE, GET, MULTISTREAM, PROHIBIT, PUT, UPDATE, Secondary attributes specify USER_INTERLOCK whether or not multiple readers or writers can concurrently access the file. (continued on next page) 3-14 Input-Output Facilities Table 3—3 (Cont.): FDL Primary and Secondary Attribute Descriptions Primary Attribute CONNECT Function Secondary Attributes Primary attribute takes no ASYNCHRONOUS, BLOCK_IO, value. BUCKET_IO, CONTEXT, Secondary attributes specify END_OF_FILE, FAST DELETE, run-time attributes that are application dependent and related to record access and performance. FILL_BUCKETS, KEY_GREATER_EQUAL, KEY_GREATER_THAN, KEY_LIMIT, KEY_OF_REFERENCE, LOCATE_MODE, LOCK_ON_READ, LOCK_ON_WRITE, MANUAL_UNLOCKING, MULTIBLOCK_COUNT, MULTIBUFFER_COUNT, NOLOCK, NONEXISTENT _RECORD, READ_AHEAD, READ_REGARDLESS, TIMEOUT ENABLE, TIMEQUT_PERIOD, TRUNCATE_ON_PUT, TT_CANCEL_CONTROL_O, TT_PROMPT, TTPURGE_TYPE_AHEAD, TT_READ_NOECHO, TTREAD_NOFILTER, TT_UPCASE_INPUT, UPDATE_IF, WAIT_FOR_RECORD, WRITE_BEHIND (continued on next page) Input-Output Facilites 3-15 Table 3-3 (Cont.): FDL Primary and Secondary Attribute Descriptions Primary Attribute AREA Function Secondary Attributes Primary attribute takes an ALLOCATION, integer value in the range 0 to BEST _TRY_CONTIGUOUS, 254, which identifies the area in an indexed file. (Multiple areas BUCKET_SIZE, CONTIGUOUS, = EXACT_POSITIONING, must have a separate AREA EXTENSION, POSITION, section defined for each.) VOLUME Secondary attributes specify characteristics of the area: how much space is allocated; whether or not the space is contiguous; positioning of the area; the volume on which the area will reside, and so on. Most AREA secondary at- tributes have corresponding FILE secondary attributes. KEY Primary attribute takes an CHANGES, COLLATING_SEQUENCE, integer value in the range 0 to DATA_AREA,DATA_FILL, 254, which gives the number DATA_KEY_COMPRESSION, of a key in an indexed file; the DATA_RECORD_COMPRESSION, primary key number must be 0. DUPLICATES, INDEX_AREA, Secondary attributes specify the characteristics of keys in the INDEX_COMPRESSION, INDEX_FILL, LENGTH, indexed file. LEVEL1_INDEX_ AREA, NAME, NULL_KEY, NULL_VALUE, POSITION, PROLOG, SEGn_LENGTH, SEGn_POSITION, TYPE ANALYSIS_OF_ AREA Result of using Analyze/RMS_ File Utility; will appear only in RECLAIMED_SPACE FDL files that describe indexed files. Neither primary nor secondary attributes are useful in an Ada FORM parameter. (continued on next page) 3-16 Input-Output Facilities Table 3-3 (Cont.): FDL Primary and Secondary Attribute Descriptions Primary Attribute Function Secondary Attributes ANALYSIS_OF_ KEY Result of using Analyze/RMS_ File Utility; will appear only in DATA_FILL, DATA_KEY_COMPRESSION, FDL files that describe indexed DATA_RECORD_COMPRESSION, files. Neither primary nor secondary attributes are useful in an Ada FORM parameter. DATA_RECORD_COUNT, DATA_SPACE_OCCUPIED, DEPTH, DUPLICATES_PER_SIDR, INDEX_COMPRESSION, INDEX_FILL, INDEX_SPACE_OCCUPIED, LEVEL1_RECORD_COUNT, MEAN_DATA_LENGTH, MEAN_INDEX LENGTH When using FDL to specify the attributes of an Ada external file, observe the following FDL rules. Any FDL errors occurring in a FORM parameter will raise the Ada predefined exception USE_ERROR. ¢ The primary attributes must appear in the order shown in Table 3-3. ¢ Each attribute string (primary or secondary) constitutes an FDL statement, and must be terminated with a semicolon. In the following example, RECORD, FORMAT FIXED, and SIZE 120 are three separate FDL statements: -— Create -—- a " SOME FILE.DAT with record size of fixed record format and 120 bytes. — CREATE (FILE => MY FILE, MODE => OUT FILE, NAME => "SOME FILE.DAT", FORM => "RECORD; FORMAT FIXED; SIZE 120;"); The exclamation point is the comment character in FDL, and anything following it is ignored. For example: —-— Create SOME FILE.DAT with CREATE (FILE 80-byte records. => MY FILE, MODE => NAME => FORM => OQOUT_FILE, "SOME FILE.DAT", "RECORD; SIZE 80; !'80-byte records"):; Input-Output Facilities 3-17 e Each FDL statement can represent only one primary or secondary attribute and its associated value. Each statement can have no more than 132 characters (including blanks). To format your program without adding extra blanks to the form string, use the Ada catenation operator (&) to break up the form string into individual statement strings. Thus, you could rewrite the preceding example as follows: CREATE (FILE => MY FILE, MODE => OUT FILE, NAME => "SOME FORM => "RECORD; FILE.DAT "FORMAT "SIZE * ", " & FIXED; " 120;" & ) 7 [If you are working with an indexed file that has two or more AREA primary attributes, they must follow one another in numerical order. * If you are working with an indexed file that has two or more KEY primary attributes, they must follow one another in numerical order. In addition, any SEGn secondary attributes must follow one another in numerical order, and the SEGn numbers must be dense. In other words, if you use SEG3 to label a key segment, then segments SEGO0, SEG1, and SEG2 must also exist. * Keywords can be truncated to their shortest unique abbreviations, and strings must be enclosed either in a pair of apostrophes (’ double quotation marks (" ) or a pair of ). Note that Ada based integers or integers with underscores are not legal FDL syntax. In addition to allowing you to specify file attributes directly in a form string, VAX Ada also allows you to give a reference to an FDL file using a VMS file specification. The specification must be preceded by an at sign (@). For example: —— Create —-— the SOME_FILE.DAT FDL file with specifications CREATE (FILE => MY FILE, MODE => OUT FILE, NAME => "SOME FILE.DAT", FORM => declared in FILE ATTRIBUTES.FDL. "Q@FILE ATTRIBUTES.FDL"); An advantage of being able to give a reference to an FDL file is that you can use the Edit/FDL Utility to construct the FDL file. The utility is designed to help you choose file attributes that will help optimize the efficiency of your program. In particular, the utility is helpful in tuning indexed files. For example, it can plot graphs to help you determine appropriate bucket sizes for specific indexed files. See the Guide to VMS File Applications for more information on the Edit/FDL Utility and file design. 3-18 Input-Output Facilities Table 3—4 describes the primary and secondary FDL attributes that you will be most likely to use in a VAX Ada program, and gives their default values. For convenience, primary attributes are shown in boldface type; secondary attributes are shown in regular type and indented. The intent of the table is to provide a quick reference and to summarize information presented in the VMS File Definition Language Facility Manual; see that manual for details. As shown in the table, the value assigned to an attribute can take one of the following forms: Switch A logical value, set to TRUE, YES, FALSE, or NO. TRUE (or YES) sets the attribute; FALSE (or NO) clears it. (You can also use the abbreviations T, Y, F, and N for TRUE, YES, FALSE, and NO.) Keyword An actual word that you must type (in either upper- or lowercase) after the attribute name. You can truncate a keyword to its shortest unique abbreviation. Integer A decimal integer (based integers or underscores are not allowed). String A character string (enclosed in either a pair of apostrophes or a pair of double quotation marks) that you must type after the attribute name. The null string is a valid string value. Note that to use double quotation marks in the same statement, you must write the form string following Ada conventions. For example: CREATE (FFILE => F, MODE => OUT FILE, FORM => "FILE;" & ""SOME FILE.DAT"";"& "DEFAULT NAME -— A pair of quotation marks -—- inside a string represents one -— quotation mark. "RECORD; " & "FORMAT FIXED;" & "SIZE ) ; 100;" Alternatively, you can use apostrophes to make your code easier to read: OUT _FILE, & "FILE;" "DEFAULT NAME ‘SOME_FILE.DAT’;" "RECORD; " R FORM => "FORMAT FIXED;" "SIZE o F, => 100;" Input-Output Facilities R => MODE - CREATE (FILE 3-19 Table 3—4: Commonly Used FDL Attributes FDL Attributes TITLE Kind of Value and Default Function String of up to 132 charac- Names the FDL file. ters, including the TITLE keyword. No default value. IDENT String of up to 132 charaec- Record identifying file information. ters, including the IDENT keyword. Default value is the date, time of creation, name of creating utility if cre- ated with Edit/FDL or Analyze/RMS_File; otherwise, no default value. SYSTEM DEVICE String. Comment (names the disk model on Default value is a null which the file will reside). string. FILE ALLOCATION Integer in the range 0 to Sets the number of blocks that will 4294967295. be initially allocated for the file. If O, Default value is 0. the system will not preallocate space for the file. BEST_TRY_ Switch. CONTIGUOUS Default value is NO. Controls whether the file will be allocated contiguously if there is enough space for it. If set to YES, and there is enough space for the file, the file will be allocated contiguously; if there is not enough space, the file will not be allocated contiguously. If set to NO, this attribute is ignored. (continued on next page) 3-20 Input-Output Facilities Table 3—4 (Cont.): Commonly Used FDL Attributes FDL Attributes BUCKET_SIZE Kind of Value and Default Function Integer in the range 0 to 63. Sets the number of blocks per bucket. Default value is 0. If 0, VMS RMS computes the bucket size to be the smallest bucket size capable of holding the largest record. CONTIGUOUS Switch. Controls whether the file must be Default value is NO. allocated contiguously. When set to YES and there is not enough space for the file’s initial allocation, an error message results. When set to NO or no allocation is specified, the attribute is ignored. DEFAULT _NAME String. Default value 1s a null string. Uses its string value to define portions of the file specification of the file to be created. If you supply only a partial file specification in the NAME parameter to an Ada OPEN or CREATE operation, the DEFAULT_NAME value is used for the missing part of the file specification. If you have not specified a value for DEFAULT _ NAME, the VMS RMS defaults are used for the missing part. EXTENSION Integer in the range 0 to Sets the number of blocks for the 65535. default extension value for the file. Default value is 0. Each time the file is extended, the specified number of blocks is added. If 0, the extension size is determined by the system each time the file must be extended. FILE_MONITORING Switch. Turns on VMS RMS statistics gath- Default value is NO. ering for subsequent use in doing performance analysis. (continued on next page) Input-Output Facilities 3—21 Table 3—4 (Cont.): Commonly Used FDL Attributes Kind of Value and Default Function MAX_RECORD_ Integer in the range 0 to NUMBER 2147483647. Specifies the maximum number of records that can be placed in a FDL Attributes Default value is O. relative file. If 0, then you can place as many records as you want in the file, up to 2,147,483,647 (or 23! — 1). ORGANIZATION Keyword. Default value is SEQUENTIAL. PRINT_ON_CLOSE Switch. Default value is NO. Defines the kind of file organization. Value must be one of the keywords SEQUENTIAL, RELATIVE, or INDEXED. Controls whether the data file is to be spooled to the process default print queue (SYS$PRINT) when the file is closed. When set to YES, the data file is spooled; when set to NO, the attribute is ignored. (This attribute applies to sequential files only.) PROTECTION String. Default value is the system or process default. Defines the levels of file protection for the file. Its value can take one of two forms (SYSTEM=code, OWNER=code, GROUP=code, WORLD=code) or (SYSTEM:code, OWNER:code, GROUP:code, WORLD:code) where the code is a protection specification for READ, WRITE, EXECUTE, and DELETE in the form RWED. To deny a specific access right, you omit it from the code. To give no access rights to a user classification, you omit the classification from the list. For example, the following string gives all access rights to SYSTEM and OWNER, gives only READ access to GROUP, and gives no access rights to WORLD: (SYSTEM=RWED, OWNER=RWED, GROUP=R). (continued on next page) 3-22 Input-Output Facilities Table 3—4 (Cont.): Commonly Used FDL Attributes Kind of Value and FDL Attributes SEQUENTIAL_ONLY Default Function Switch. Indicates that the file can only be Default value is NO. processed sequentially, thus allowing certain processing optimizations. Any attempt to perform random access results in an error. SUBMIT_ON_CLOSE Switch. Determines whether the data file Default value is NO. is submitted to the process batch queue (SYS$BATCH) when the file is closed. When set to YES, the data file is submitted to the process default batch queue; this setting makes sense only if the file 1s a command file with sequential organization. When set to NO, this attribute is ignored. DATE EXPIRATION String in the form dd- Sets the date and time after which mmm-yyyy hh:mm:ss.cc. a disk file can be considered for Default value is a null string. deletion. For magnetic tape files, this attribute sets the date and time after which you can overwrite the file. This is the only DATE secondary attribute that you can routinely and safely set. (continued on next page) Input-Output Facilities 3-23 Table 3-4 (Cont.): Commonly Used FDL Attributes Kind of Value and FDL Attributes Default Function Keyword. Default value is CARRIAGE RETURN. Specifies the kind of carriage control for the records in the file. Value must be one of the keywords RECORD CARRIAGE_ CONTROL - CARRIAGE_RETURN, FORTRAN, NONE, or PRINT. See Section 3.7.4 of this manual and the VMS File Definition Language Facility Manual for more information. FORMAT Keyword. Default value is VARIABLE. Sets the record format for the data file. Value must be one of the key_ words FIXED, STREAM, STREAM CR, STREAM_LF, UNDEFINED, VARIABLE, VFC. See the VMS File Definition Language Facility Manual for more information. Integer. No default value. SIZE Sets the maximum record size in bytes. With fixed-length records, this value is the length of every record in the file. With variable-length records, this value is the length of the longest record that can be placed in the file. If the file has sequential or indexed organization, you can specify 0 and the system will not impose a maximum record length. The records in an indexed file, however, cannot cross bucket boundaries. If the file has relative organization, the SIZE attribute is used with the BUCKET_SIZE attribute to set the size of the fixed-length cells. (continued on next page) 3-24 Input-Output Facilities Table 3—4 (Cont.): Commonly Used FDL Attributes Kind of Value and FDL Attributes Default Function If the records have variable-length with fixed control (VFC) format, the fixed-control portion of the record is not included in the SIZE calculation; only the data portion is set by this attribute. The fixed area is the size, in bytes, of the fixed-control portion of VFC records. Regular variable-length records have a fixedcontrol size of 0. See the VMS File Definition Language Facility Manual for the maximum sizes allowed for the various record organizations and formats. ACCESS DELETE Switch. Permits VMS RMS delete operations. The default value is FALSE. GET Switch. Permits VMS RMS get or find Default value is GET when operations. a file is being opened and no other ACCESS secondary attribute has been specified and SHARING DELETE or SHARING UPDATE have been specified. PUT TRUNCATE UPDATE Switch. Permits VMS RMS put or extend PUT when creating a file. operations. Switch. Permits VMS RMS truncate Default value is FALSE. operations. Switch. Permits VMS RMS update or extend Default value is FALSE. operations. (continued on next page) Input-Output Facilities 3—25 Table 3—4 (Cont.): Commonly Used FDL Attributes Kind of Value and FDL Attributes Default Function SHARING DELETE GET Switch. Allows other users to delete records No default value. from the file. Switch. Allows other users to read the file. TRUE if ACCESS GET has also been specified. PROHIBIT Switch. YES if ACCESS DELETE, ACCESS PUT, ACCESS TRUNCATE, or ACCESS UPDATE has been specified; otherwise, no default value. Prohibits any kind of file sharing by other users. When set to YES, this attribute takes precedence over all other ACCESS secondary attributes. A value of YES in a VAX Ada form string takes precedence over any other default values that may be implied by values of other SHARING secondary attributes. When an OPEN or CREATE form string specifies any SHARING secondary attribute without specifying SHARING PROHIBIT, then no default is chosen (equivalent to a value of NO). PUT Switch. UPDATE Allows other users to write records to No default value. the file. Switch. Allows other users to update records No default value. that currently exist in the file. (continued on next page) 3-26 Input-Output Facilities Table 3—4 (Cont.): Commonly Used FDL Attributes Kind of Value and FDL Attributes Default Function MULTIBUFFER_ Integer in the range 0 to COUNT 127. Specifies the number of buffers to be allocated when the file is opened. If No default value. the value is not set or 0, VMS RMS CONNECT chooses a default value (see the VMS File Definition Language Facility Manual). This attribute is ignored for DECnet operations. READ_AHEAD Switch. Indicates read-ahead operations; to No default value. be used with multiple buffers. When one buffer is filled, the next record is read into the next buffer while the input-output operation takes place for the first buffer. Because the system does not have to wait for input-output completion, input and computing can overlap. This attribute is ignored for DECnet oper- ations. See the VMS File Definition Language Facility Manual for more information. TIMEOUT_ENABLE Switch. No default value. Specifies the maximum time, in seconds, that will be allowed for a record input wait (see TIMEOUT_ PERIOD). The input wait can be caused by a locked record if the WAIT_FOR_RECORD attribute has also been specified, or it can be caused by the input of a character from the terminal. If the timeout period expires, VMS RMS returns an error status. This attribute is ignored for DECnet operations. (continued on next page) Input-Output Facilities 3-27 Table 3—4 (Cont.): Commonly Used FDL Attributes Kind of Value and FDL Attributes TIMEOUT_PERIOD Default Function Integer in the range 0 to 255. No default value. Specifies the maximum number of seconds that a VMS RMS get operation can take; if the operation is specified from the terminal and you specify 0, the current contents of the type-ahead buffer are returned. You must use the TIMEOUT_ENABLE attribute with TIMEOUT_PERIOD. This attribute is ignored for DECnet operations. TRUNCATE_ON_PUT Switch. No default value. Specifies that a VMS RMS put or write operation can occur at any point in a file, truncating the file at that point. A write operation causes the end-of-file mark to immediately follow the last byte written. You can use this attribute only with VMS RMS sequential files. UPDATE_IF Switch. No default value. Indicates that if a put operation is specified for a record that exists in the file, the operation is converted to an update. This attribute is necessary to overwrite (as opposed to update) an existing record in VMS RMS relative and indexed sequential files. Indexed files using this attribute must not allow duplicates on the primary key. WAIT_FOR_RECORD Switch. No default value. Specifies that VMS RMS should wait for a currently locked record until it becomes available. You can use this attribute with the TIMEOUT_ ENABLE and TIMEOUT_PERIOD attributes to limit waiting periods to a specified time. (continued on next page) 3-28 Input-Output Facilities Table 3-4 (Cont.): FDL Attributes WRITE_BEHIND Commonly Used FDL Attributes Kind of Value and Default Function Switch. Indicates that write-behind oper- No default value. ations are to occur when multiple buffers are used. When one buffer 1s filled, the next record is written into the next buffer while the inputoutput operation takes place for the first buffer. Because the system does not have to wait for input-output completion, computing and output can overlap. See the VMS File Definition Language Facility Manual for more information. AREA This attribute and its secondary attributes apply only to files with indexed organization. See the VMS File Definition Language Facility Manual for details. KEY Integer in range 0 to 254. Denotes the key number for a file No default value. with indexed organization. The value for the primary key must be 0; the value for alternate keys can be any integer in the range 1 to 254. This attribute and its secondary attributes apply only to files with indexed organization. CHANGES Switch. Determines whether or not key Default value is NO. values can be changed with a VMS RMS update operation. Note that a value of YES for primary keys is an error; a value of YES for alternate keys is allowed. (continued on next page) Input-Output Facilites 3-29 Table 3-4 (Cont.): Commonly Used FDL Attributes Kind of Value and FDL Attributes DATA_KEY_ COMPRESSION Default Function Switch. Default value is YES. Controls whether leading and trailing repeating characters in the primary key will be compressed. For compression to occur, you should define your indexed file as a Prolog 3 file with the FDL attributes KEY PROLOG; KEY PROLOG 3 is the default. You should set this attribute for indexed files involved in DECnet operations. DATA_RECORD_ COMPRESSION Switch. Default value is YES. Controls whether repeating characters are compressed in data records. For compression to occur, your indexed file must be defined as a Prolog 3 file with the FDL attributes KEY PROLOG; KEY PROLOG 3 is the default. You should set this attribute for indexed files involved in DECnet operations. DUPLICATES Switch. Default value is NO for the primary key; YES for alternate keys. Controls whether duplicate keys are allowed in files with indexed organization. When set to YES, this attribute specifies that there can be more than one record with the same specific key value. When set to NO, duplicate keys are not allowed, and any attempt to write a record where the key would be a duplicate will result in an error. (continued on next page) 3-30 Input-Output Facilities Table 3—4 (Cont.): Commonly Used FDL Attributes Kind of Value and FDL Attributes INDEX_COMPRESSION Default Function Switch. Controls whether leading repeat- Default value is YES. ing characters in the index are compressed. For compression to occur, you should define your indexed file as a Prolog 3 file with the FDL attributes KEY PROLOG; KEY PROLOG 3 is the default. You should set this attribute for indexed files involved in DECnet operations. LENGTH Integer. Sets the length of the key, in No default value. bytes. This value, along with the POSITION and TYPE attributes, is used when the key is unsegmented. Because there is no default, this value must be specified. NAME NULL_VALUE String of from 1 to 32 characters. Assigns a name to a key. This value is optional. The specified string is Default value is a null padded with ASCII null characters to string. a length of 32 bytes. Character or unsigned deci- Defines the null value that will in- mal integer representing an struct the system not to create an ASCII value. alternate index entry for the record Default value is the ASCII null character (0). that has the null value in every byte of the key field. If the alternate key is of the type STRING or DSTRING, you can specify the null value by either specifying the character itself or by specifying an unsigned decimal number denoting the character’s ASCII value. To specify the character, enclose it in apostrophes; to specify the decimal ASCII value, type it without enclosing apostrophes. (continued on next page) Input-Output Facilites 3-31 Table 3—4 (Cont.): Commonly Used FDL Attributes Kind of Value and FDL Attributes POSITION Default Function Integer. No default value. Defines the byte position of the beginning of the key field within the record. The first position is 0; primary keys work best if they start at byte 0. You can use this attribute along with the KEY LENGTH and TYPE attributes, when the key is unsegmented. PROLOG Integer in the range 1 to 3. Default value is the system or process default. SEGn_LENGTH Integer in the range 0 to 7. No default value. SEGn_POSITION Defines the internal structure of a file with indexed organization. See the VMS File Definition Language Facility Manual for details. Defines the length of the key segment, in bytes. This attribute is used with the SEGn_POSITION attribute when the key is segmented. The “n” is the number of the segment and may be numbered from 0 to 7; the first segment must be numbered 0. Segmented keys must be of the type STRING or DSTRING, and segments may not overlap for Prolog 3 files. Integer. Defines the key segment’s starting No default value. position within the record. The first position is 0. Segmented keys must be of the type STRING or DSTRING, and segments may not overlap for Prolog 3 files. (continued on next page) 3-32 Input-Output Facilities Table 3-4 (Cont.): Commonly Used FDL Attributes Kind of Value and FDL Attributes TYPE Default Function Keyword. Default value is STRING. Defines the type of the key. May have any of the following values: BIN2, BIN4, BIN8, COLLATED, DCOLLATED, DBIN2, DBIN4, DBINS, DECIMAL, DDECIMAL, DINTZ2, DINT4, DINT8, DSTRING, INT2, INT4, INT8, STRING. See the VMS File Definition Language Facility Manual for more information. Certain FDL attributes can significantly improve application performance. In other words, if the files used by the application are designed and tuned properly, the application will run more efficiently, often because a minimum number of input-output operations will occur. File design and tuning are important for large files, especially indexed files. The characteristics you specify when you create a file often have a significant effect on application performance at run time. The following FDL attributes from Table 3—4 can affect application performance: FILE ALLOCATION FILE BESTTRY_CONTIGUOUS FILE BUCKET_SIZE FILE CONTIGUOUS FILE EXTENSION CONNECT READ_AHEAD CONNECT WRITE_BEHIND ACCESS and SHARING attributes certain KEY attributes The following attributes not listed in Table 3—4 can also affect performance: FILE DEFERRED_WRITE CONNECT FAST_DELETE CONNECT GLOBAL_BUFFER_COUNT CONNECT MULTIBLOCK_COUNT CONNECT MULTIBUFFER_COUNT Input-Output Facilites 3-33 FILE SEQUENTIAL_ONLY FILE WINDOW_SIZE See the Guide to VMS File Applications for more information. 3.3.2 Creation-Time and Run-Time Attributes Of the many attributes that you can associate with an external file, some exist as long as the external file exists. These are called creation-time attributes. FILE ORGANIZATION and RECORD SIZE are examples of creation-time attributes. The rest of the attributes exist only as long as the external file is associated with a particular file object. These are called run-time attributes. Any of the attributes secondary to the primary CONNECT, ACCESS, or SHARING attributes, as well as the FILE secondary PRINT_ON_CLOSE attribute, are run-time attributes. Run-time attributes can change dynamically at run time, and must be respecified each time the file is opened. The Guide to VMS File Applications identifies all creation-time and run-time attributes and discusses them in more detail. You can change a file’s creation-time characteristics only by creating or recreating the file. Inside an Ada program, you can give creation-time attributes to an external file with a call to a CREATE procedure; the file inherits these attributes in subsequent calls to OPEN procedures. Outside of an Ada program, you can change the creation-time characteristics of an external file by using the Edit/FDL and Convert or Convert/Reclaim Utilities to create a new external file and populate it with elements of the old file. Any creation-time file attributes specified in an OPEN procedure are considered to be only assertions; they do not affect the external file’s characteristics. VAX Ada protects you from making wrong assertions of creation-time attributes in a call to an OPEN procedure. If you specify a form string value for the FORM parameter in an OPEN procedure call, the OPEN procedure checks the following creation-time attributes of the external file against any assertions of the attributes in the form string: 3-34 * The FILE secondary attribute ORGANIZATION * The RECORD secondary attribute CARRIAGE_CONTROL e The RECORD secondary attribute FORMAT * The RECORD secondary attribute SIZE e Every KEY section (in an indexed file) Input-Output Facilities If there is a mismatch, then the exception USE_ERROR is raised. For example, if a form string asserts that the organization of the external file is indexed, but the external file being opened is sequential, the exception USE_ERROR is raised. If no creation-time-attribute assertions are made, then no check is performed. 3.3.3 Default External File Attributes When you open a file (using either a CREATE or an OPEN procedure), the input-output package you are using provides a set of default external file attributes. One purpose of the default attributes is to allow your program to pass a null form string (the default) to an OPEN procedure and still open the external file. Thus, you do not need a form string (a FORM parameter value) when you use an OPEN procedure to open a file. However, in some situations you must specify certain external file attributes when you call a CREATE procedure (see Section 3.3). Sections 3.6.1 through 3.6.4 and Section 3.7 provide tables of default attributes for each VAX Ada input-output package. Note the following points about the default external file attributes: * Creation-time attributes specified in the FORM parameter of an OPEN procedure have no effect, except to cause a consistency check against the creation-time attributes that exist for the file (see Section 3.3.2). e Many FDL default attributes are applied automatically, but they are not shown in the default attribute tables; see the VMS File Definition Language Facility Manual for the FDL defaults. The VAX Ada input- output packages impose certain restrictions on the attributes of the external files that they open: — If the file is being created, these restrictions are checked against any external file characteristics given in the FORM parameter of the CREATE procedure. — If the file is being opened, the restrictions are checked after any assertions in the FORM parameter of the OPEN procedure have been checked against the existing attributes of the file. If the restrictions are violated at either point, the exception USE_ ERROR is raised. Input-Output Facilities 3-35 3.4 File Sharing File sharing in VAX Ada enables concurrent access to the same external file. In other words, file sharing permits multiple file objects to be associated with the same external file. File sharing can take place in the same VMS process or across multiple processes. You can share external files for reading, writing, or modification. Because VAX Ada files are layered on VMS RMS file organizations, the rules that apply to read and write sharing of VMS RMS files also apply to Ada files. The Guide to VMS File Applications gives complete information on file sharing in the VMS environment. For descriptions of the organizations chosen for Ada files, see Section 3.1. The FDL ACCESS and SHARING primary attributes have secondary attributes that control the scope of access and sharing of an external file. The ACCESS secondary attributes determine the kinds of operations (read, write, update, and so on) that your program can perform on the external file. The SHARING secondary attributes determine the kinds of operations other concurrently active programs can perform on the file. When you open a file, VAX Ada uses the MODE parameter to select appropriate default ACCESS and SHARING secondary attributes (see Section 3.3.3 and Tables 3-5 through 3-13). If the FORM parameter in an OPEN or CREATE procedure specifies values for the ACCESS or SHARING attributes, those values supersede any previously specified or default values. To determine whether or not you need to specify ACCESS or SHARING attributes, follow these steps: 1. Check the table of default attributes for the package you are working with. For example, if you are working with relative files, look at Table 3-9. 2. If the table does not show a default for a particular attribute, check Table 3—4 or the VMS File Definition Language Facility Manual. 3. If the combined set of default values does not reflect the action you want, use the form string to set the attribute values. When choosing attribute values, note the following points: * The ACCESS and SHARING attributes interact to some degree. For example, YES values for ACCESS DELETE, PUT, TRUNCATE, or UPDATE cause a value of YES for SHARING PROHIBIT. 3-36 Input-Output Facilities In any attempt to open an external file that has already been opened, the value of the ACCESS attribute must match the value of the SHARING attribute given to the file when it was first opened (or created). Also, the value of the SHARING attribute must match the value of the ACCESS attribute given to the file when it was first opened (or created). Otherwise, the attempt to open the external file will raise the exception e USE_ERROR. If you specify any SHARING attribute and do not specify PROHIBIT, then PROHIBIT has no default value (which is equivalent to a default e of NO). The SHARING attributes are ignored for record-oriented devices and magnetic tape files that are mounted foreign. For ANSI magnetic tape files, a concurrent OPEN operation raises the exception USE_ERROR, even though a SHARING attribute may be specified in the initial OPEN operation. The number of shared files is restricted by the system-wide e shared-file database. Although write sharing is allowed for all files, you can improve the performance of your program if you avoid write sharing. See the Guide e to VMS File Applications for more information. In Example 3-1, read sharing is desired for the relative file REL_FILE. Example 3-1: Creating and Opening a Relative File for Read Sharing with RELATIVE IO; package REL PKG is new RELATIVE_IO (STRING); — . — S — — A, TR THW T N with REL PKG; — — o o S W — ——— W e - ) I — —— — use REL_PKG; procedure CREATE RELATIVE REL FILE: — ——— — S Sa— ——— — is FILE TYPE; begin CREATE (FILE => REL FILE, (1 MODE => INOUT FILE, NAME => FORM => "REL FILE.DAT", & " "RECORD; "SIZE 30;" " "SHARING; & & "GET YES;"); end CREATE RELATIVE; —-—-—- n-—————-—————.—--———.—---—-—-—-—————n.-.p—-—p—————-..-———-————-——-—q———— (continued on next page) Input-Output Facilites 3-37 Example 3-1 (Cont.): with REL PKG; use Creating and Opening a Relative File for Read Sharing REL PKG; with CREATE RELATIVE; procedure SHARE RELATIVE IO _FILE: is FILE TYPE; begin CREATE RELATIVE; OPEN (FILE MODE © => IOFILE, => INFILE, NAME => "REL FILE.DAT", FORM => "RECORD; " (4 & "SIZE 30;" "PUT YES;"); "SHARING; " & & (5 CLOSE (I0_FILE); end SHARE RELATIVE; Key to Example 3-1: @ The CREATE statement creates a relative, in-out file. VAX Ada gives it the following attributes by default (see Table 3-9): ACCESS; DELETE YES; ACCESS; GET YES; ACCESS; PUT YES; ACCESS; UPDATE YES; SHARING; GET NO; Because YES values are in effect for ACCESS DELETE, PUT, and UPDATE, the value of SHARING PROHIBIT is also YES (see Table 3—4). @® The CREATE statement specifies a value of YES for SHARING GET; by default, SHARING GET is disallowed and all other sharing is prohibited. SHARING GET indicates that the external file REL_FILE.DAT can be shared with other users who wish to read the file. ® The procedure SHARE_RELATIVE calls the procedure CREATE RELATIVE. Because CREATE_RELATIVE does not close REL_ FILE.DAT, the file will still be open and will need to be shared when SHARE_RELATIVE tries to access it. 3-38 Input-Output Facilities ® The OPEN statement opens REL_FILE.DAT as an in file, as only reading is required. ©@ The OPEN statement specifies a value of YES for SHARING PUT, which allows SHARE_RELATIVE to open the external file REL_FILE.DAT. If SHARING PUT is not specified, the file cannot be opened, and the exeception USE_ERROR will be raised. 3.5 Record Locking The VMS RMS record locking facility allows more than one program to concurrently add, delete, or update a VMS RMS record in a controlled manner. Record locking is available to external files in the same VMS process and across different processes. The Guide to VMS File Applications explains VMS RMS record locking in detail. In VAX Ada, record locking is available for all files. When you open a file for which the attributes SHARING GET, SHARING PUT, or SHARING UPDATE have been specified in the FORM parameter, VMS RMS locks each record as it is accessed. The same external file may then be reopened and associated with another Ada file according to the kind of sharing specified. When a record of a relative or indexed external file is locked as the result of an operation on a particular Ada file, any other operation on another Ada file that attempts to access the same record will fail, and the exception LOCK_ERROR is raised. When an attempt is made to access a record of any other kind of external file, the exception USE_ERROR is raised. For all files, any subsequent file operation (for example, read, write, modify, delete, end-of-file, and so on) could potentially unlock a previously locked record. See Chapter 14 of the VAX Ada Language Reference Manual for descriptions of the effects of the various file operations on locking and unlocking the elements of Ada files. The following example shows a technique for handling LOCK_ERROR. In this example, attempts to access the record are continued each time a Y (Yes) answer is given to an interactive prompt. Input-Output Facilities 3-39 ~— REL FILE -- it is has REL PKG.READ and opened external for file => REL FILE, ITEM => READ VALUE, FROM => REL PKG.COUNT(I)); processing of the could take place L] created (FILE —— Additional —-— been associated with the record at read sharing; "REL FILE.DAT". location COUNT (I) here. - —- IO_FILE —-— "REL -~ statement —-— could occur. —— Thus, a —— HAVE RECORD checks —-— prompt lock -- the has been FILE.DAT". access loop if opened to Because a the same until while not this same for record, error the lock HAVE RECORD lock has external and the error occurred. control is cleared or lock READ errors BOOLEAN variable and can file previous potential conditionalized on the application user -- waits read the both issues By an interactive answering the whether the prompt, application execution is terminated. loop begin RELPKG.READ(FILE => IO FILE, ITEM => READ VALUE, FROM => HAVE RECORD := RELPKG.COUNT(I)) TRUE; exception when LOCK_ERROR => TEXT TI0.PUT("Record locked - try again? (Y or N)"); TEXT TO.GET (RESPONSE) ; if RESPONSE raise; = "N" then —-— Re-raise LOCK_ERRCR. end if; end; end loop; 3.6 Binary Input-Output VAX Ada provides two kinds of binary input-output packages: One kind—SEQUENTIAL_IO, DIRECT_IO, RELATIVE_IO, and INDEXED_IO—allows you to work with binary files containing elements that are all of the same type (a file of elements of an integer type, a file of elements of a record type, a file of elements of an array type, and so on). These packages are all generic; you must instantiate them with the type of the elements in the file before you can use their operations. 3-40 Input-Output Facilities e The second kind—SEQUENTIAL_MIXED_IO, DIRECT_MIXED_IO, RELATIVE_MIXED_IO, and INDEXED_MIXED_IO—allows you to work with binary files of mixed types. For example, you can have a mixed-type file that contains elements of three different integer types, or a file that contains elements that are a mixture of integer types, array types, string types, and so on. The mixed-type packages are nongeneric, but they involve buffer operations that are generic. For example, you must instantiate the generic GET_ ITEM and PUT _ITEM operations to move values in and out of a buffer; you then read or write the buffer to transfer a record to or from your file. Example 3-2 and Figure 3-1 show the use of a mixed-type file (using the package DIRECT_MIXED_IO). The circled numbers in Figure 3-1 match statements in the program EXPENSE_ACCOUNT (Example 3-2) to elements in the file EXPENSES. Figure 3-2 shows the use of a file with elements of the same type (using the package DIRECT_IO). Sections 3.1.1 through 3.1.5 describe the structure of VAX Ada files and give their relationship to VMS RMS files; Chapter 14 of the VAX Ada Language Reference Manual describes the packages and their operations in more detail. The following sections give more information (including default file attributes) and present examples that show the features of each kind of package. If you are interested in information about designing files and tuning them for optimum performance, see the Guide to VMS File Applications. Input-Output Facilites 3—41 Example 3-2: Using a Mixed-Type File with DIRECT MIXED IO; procedure type EXPENSE AMOUNT is subtype DATE COUNT: NATURAL use DIRECT MIXED IO; ACCOUNT delta TYPE is := is 0.01 range 0.00..5000.00; STRING(1l..8); 0; procedure PUT DATE procedure PUT COUNT procedure PUT COST is new PUT ITEM (AMOUNT) ; is new GET_ITEM(DATE TYPE); is procedure GET DATE procedure GET_COUNT procedure GET COST EXPENSES: FILE new PUT_ITEM(DATE TYPE); is new PUT ITEM(NATURAL) ; is is new GET new GET ITEM (NATURAL); ITEM (AMOUNT) ; TYPE; CREATE (FILE => EXPENSES, MODE => INOUT FILE, NAME => "EXPENSES.DAT", FORM => "RECORD;" "FORMAT "SIZE PUT DATE (EXPENSES, FIXED;" 32;"); "01-08-84"); WRITE (EXPENSES, 1) ; PUT COST (EXPENSES, COUNT := COUNT + PUT COST (EXPENSES, COUNT := COUNT + := COUNT + WRITE (EXPENSES, PUT 35.00); 1; 3); COUNT (EXPENSES, WRITE (EXPENSES, 27.95); 1; PUTCOST(EXPENSES, COUNT 0.80); 1; COUNT) ; 2): RESET (EXPENSES) ; READ (EXPENSE2) S, ; GET COUNT (EXPENSES, CLOSE (EXPENSES) ; end EXPENSE ACCOUNT; 3-42 Input-Output Facilities COUNT) ; 00 00 ® © ®de .. begin Figure 3-1: Using a Mixed-Type File € Fie EXPENSES: Buffer (32-byte) : Empty. | 01-08-84 element @ Fie EXPENSES Buffer (32—-byte): Empty. element € Fie EXPENSES Buffer (32-byte) : Buffer (32-byte) . | 0.80 Buffer (32-byte) . @ Fie EXPENSES 1 | 01-08-84 | 0.80 27.95 element © File EXPENSES 1 | 01-08-84 element @ ricexpensES 1 | 01-08-84 1. | 01-08-84 | 0.80 27.95 35.00] element 1 | 01-08-84 To.80 27.95 35.00 | Buffer (32—byte): element @ Fic EXPENSES 1 | 01-08-84 | 0.80 27.95 35.00 | | 0.80 27.95 35.00 | | 0.80 27.95 35.00 | Buffer (32—byte): | 3 element @ Fic EXPENSES Buffer (32-byte): Empty element © rie ExPENSES Buffer (32-byte): 1 | 01-08-84 1 | 01-08-84 | 3 { count=s. Buffer is empty. ZK-4043-2-GE Input-Output Facilites 3-43 Figure 3-2: Using a Uniform-Type File with DIRECT _IO; procedure POWERS_OF_TEN is package TEN_|O is new DIRECT_IO (NATURAL); use TEN IO; TEN: NATURAL :=10; POWER: NATURAL; TEN_FILE: FILE_TYPE; begin CREATE (TEN_FILE, INOUT_FILE, "TEN_FILE.DAT"); for POWER in 0..5 loop WRITE (TEN_FILE, TEN ** POWER); end loop; RESET (TEN_FILE); READ (TEN_FILE, TEN, 3); end POWERS _OF _TEN; element (index) State of TEN_FILE at end of loop: Element read by READ statement: 1 2 3 1 10 100 4 5 . 1000 || 10000 | end_of_file I TEN =100 ZK-4042-GE 3.6.1 Sequential File Input-Output For creating and working with sequential files of uniform-type elements, VAX Ada provides the generic package SEQUENTIAL _IO; for creating and working with sequential files of mixed-type elements, VAX Ada provides the nongeneric package SEQUENTIAL_MIXED _IO. When you create a file with the package SEQUENTIAL_IO, VAX Ada gives 1t the default attributes listed in Table 3-5. When you create a file with the package SEQUENTIAL_MIXED_IO, VAX Ada gives it the default attributes listed in Table 3-6. You can use the operations in the packages 3-44 Input-Output Facilities SEQUENTIAL_IO and SEQUENTIAL_MIXED_IO to open and read files of any VMS RMS organization. Table 3-5: SEQUENTIAL _IO: Default File Attributes File Attribute Default Value FILE ORGANIZATION SEQUENTIAL SEQUENTIAL_ONLY YES RECORD CARRIAGE_CONTROL FORMAT CARRIAGE_RETURN FIXED if ELEMENT TYPE is constrained; VARIABLE if unconstrained SIZE (ELEMENT_TYPE’' MACHINE_SIZE + 7)/8 if ELEMENT _TYPE is constrained; 0 (unlimited) if not (note, however, that there are physical limitations to SIZE; see the VMS Record Management Services Manual) ACCESS GET YES PUT YES if MODE is OUT_FILE; NO if MODE is IN_FILE TRUNCATE YES if MODE is OUT_FILE; NO if MODE is IN_FILE SHARING GET YES if MODE is IN_FILE; NO if MODE is OUT_FILE CONNECT READ_AHEAD YES TRUNCATE_ON_PUT YES if MODE is OUT_FILE; NO if MODE is IN_FILE WRITE_BEHIND YES if MODE is OUT_FILE Input-Output Facilites 3-45 Table 3-6: SEQUENTIA MIXED 10: L Default File Attributes File Attribute Default Value FILE ORGANIZATION SEQUENTIAL SEQUENTIAL_ONLY YES RECORD CARRIAGE_CONTROL CARRIAGE_RETURN FORMAT VARIABLE SIZE 0 (record size is unlimited; note, however, that SIZE has physical limitations; see the VMS Record Management Services Manual) ACCESS GET YES PUT YES if MODE is OUT_FILE; NO if MODE is IN_FILE TRUNCATE YES if MODE is OUT _FILE; NO if MODE is IN_FILE SHARING GET YES if MODE is IN_FILE; NO if MODE is OUT_FILE CONNECT READ_AHEAD YES TRUNCATE_ON_PUT YES if MODE is OUT_FILE; WRITE_BEHIND YES if MODE is OUT_FILE NO if MODE is IN_FILE Example 3-3 shows how to instantiate the package SEQUENTIAL I0. It also shows how to open, close, read, and write from an Ada sequential file. The item input-output operations provided by the package SEQUENTIAL MIXED_IO are basically the same as those provided for the other mixed-type packages. See Figure 3-1, and Examples 3—4 and 3-7 for examples of using the item input-output operations. 3-46 Input-Output Facilities Example 3-3: Using the Package SEQUENTIAL 1O with SEQUENTIAL IO; procedure type SHOW SEQ STRING TYPE package use is is new STRING(1..10); INOUT_ STRING is new SEQUENTIAL IO (STRING TYPE); INOUT_STRING; STRING FILE : FILE STRING_VAR : STRING TYPE; TYPE; begin —-— Write a string to the file CREATE (FILE => STRING FILE, MODE => OUT FILE, NAME => "STRINGDAT.DAT") ; WRITE (STRING CLOSE (STRING _FILE); —— Read a OPEN STRINGDAT.DAT. FILE, string "tenletters"); from the same file. (FILE => STRING FILE, MODE => IN FILE, NAME => "STRINGDAT.DAT") ; READ (STRING FILE, STRING VAR); CLOSE (STRING FILE) ; end SHOW SEQ; 3.6.2 Direct File Input-Output For creating and working with direct files of uniform-type elements, VAX Ada provides the generic package DIRECT_IO; for creating and working with direct files of mixed-type elements, VAX Ada provides the nongeneric package DIRECT _MIXED_IO. When you create a file with the package DIRECT _I0, VAX Ada gives it the default file attributes listed in Table 3—7. When you create a file with the package DIRECT_MIXED_IO, VAX Ada gives it the default file attributes listed in Table 3-8. You can use these packages only with files having the FDL attributes ORGANIZATION SEQUENTIAL and RECORD FORMAT FIXED. If you try to use DIRECT IO or DIRECT _MIXED_IO with a file that has different ORGANIZATION and RECORD FORMAT attributes, the exception USE_ERROR will be raised. Input-Output Facilites 347 When creating files with the package DIRECT_IO, you must specify a maximum record size with the FORM parameter if you instantiate the package with an unconstrained element type. When creating files with the package DIRECT_MIXED_IO, you must specify a maximum record size with the FORM parameter. The maximum record size determines the maximum size of an element in the file. In the case of DIRECT_MIXED_IO, the maximum record size also determines the size of the file buffer for performing item input-output. If you write a value to a direct file element that is smaller than the size specified, the corresponding external file record is padded with zeros. Table 3-7: DIRECT I10: Default File Attributes File Attribute Default Value FILE ORGANIZATION SEQUENTIAL RECORD CARRIAGE_CONTROL CARRIAGE_RETURN FORMAT FIXED SIZE (ELEMENT_TYPE’' MACHINE_SIZE + 7)/8 if ELEMENT_TYPE is constrained; otherwise, a value must be specified (no default if ELEMENT_TYPE is unconstrained) ACCESS GET YES PUT YES if MODE is OUT_FILE; NO if MODE is IN_FILE SHARING GET YES if MODE is IN_FILE; NO if MODE is OUT_FILE CONNECT UPDATE_IF Input-Output Facilities YES Table 3-8: DIRECT_MIXED_lO: Default File Attributes File Attribute Default Value FILE ORGANIZATION SEQUENTIAL RECORD CARRIAGE_CONTROL CARRIAGE_RETURN FORMAT FIXED SIZE None; this attribute must be specified in the FORM parameter ACCESS GET YES PUT YES if MODE is OUT_FILE; NO if MODE is IN_FILE SHARING GET YES if MODE is IN_FILE; NO if MODE is OUT_FILE CONNECT UPDATE_IF YES Example 3—4 shows the reading and writing of items into a direct file using the package DIRECT_MIXED_IO. For an example of using the package DIRECT_I10, see Figure 3-2. Note from Fxample 3—4 that read and write operations to direct files do not have to be to consecutive elements. However, if you read from an empty element, the value returned will be unpredictable. Input-Output Facilities 3—49 Example 3—4: with Using the Package DIRECT_MIXED 10 DIRECT MIXED IO; procedure use DIRECT MIXED IO; SHOW DIRECT MIXED is OLD_STRING : STRING(1l..5) NEW : STRING(1l..5) STRING := OLD_ INT : INTEGER := 1; NEW_INT : INTEGER := 4; MY FILE : FILE -—- Instantiate "FOUR "; "FIVE "; TYPE; the GET and PUT procedures. is new GETITEM(INTEGER); procedure GET INT procedure GET_ STR is new GET_ITEM(STRING) ; procedure PUT INT is new PUTITEM(INTEGER) ; procedure PUT STR is new PUT_ITEM(STRING) ; begin Create the but specified is must be file; sequential for specified organization completeness; (there is no a is the record default, size default). => MY FILE, CREATE (FILE MODE => NAME => "MY FORM => "PFILE;" INOUT FILE, FILE.DAT", "ORGANIZATION SEQUENTIAL;"TM "RECORD; " "SIZE Alternately put to as PUT the STR(MY WRITE (FILE TO file a a FILE,OLD string buffer record. MY FILE, => 1); => in and write it STRING); => PUT STR (MY FILE,OLD WRITE(FILE the single-element - String will be written to element 1. will be written to element 2. ] —— -— 120;" String will be written to element 5. -- Reposition file STRING); -- String MYFILE); PUT_STR(MY_FILE,OLD_STRING); WRITE (FILE TO => MY_FILE, => 5); SETINDEX (MY FILE, 7); pointer to element 7. written element 7. PUT INT (MYFILE,OLD INT); WRITE (FILE => MYFILE); Integer will be to (continued on next page) 3-50 Input-Output Facilities Example 3—4 (Cont.): —— Reset for Using the Package DIRECT_MIXED_IO reading. RESET (MY FILE) ; —-- Read values from the file. READ (MY FILE); —— Put the record from element 1 -- into the buffer. GET STR(MY FILE,NEW_STRING) ; READ (FILE => MY FILE, FROM => 7); —-— Put the record from element 7 -— into the buffer. DIRECT MIXED; end SHOW 3.6.3 Relative File Input-Output For creating and working with relative files of uniform-type elements, VAX Ada provides the generic package RELATIVE_IO; for creating and working with relative files of mixed-type elements, VAX Ada provides the nongeneric package RELATIVE_MIXED_IO. When you create a file with the package RELATIVE_IO, VAX Ada gives it the default file attributes listed in Table 3-9. When you create a file with the package RELATIVE_MIXED_IO, VAX Ada gives it the default file attributes listed in Table 3-10. You can use these packages only with files having the attribute ORGANIZATION RELATIVE. If you try to use RELATIVE_IO and RELATIVE_MIXED_IO with a file with any other ORGANIZATION attribute, the exception USE_ERROR will be raised. When creating files with the package RELATIVE_IO, you must specify a maximum record size with the FORM parameter if you instantiate the package with an unconstrained element type. When creating files with the package RELATIVE_MIXED_IO, you must specify a maximum record size with the FORM parameter. The maximum record size determines the maximum size of an element in the file. In the case of RELATIVE_MIXED_ 10, the maximum record size also determines the size of the file buffer for performing item input-output. Input-Output Facilities 3-51 Table 3-9: RELATIVE_|O: Default File Attributes File Attribute Default Value FILE ORGANIZATION RELATIVE RECORD CARRIAGE_CONTROL FORMAT CARRIAGE_RETURN FIXED if ELEMENT_TYPE is constrained; VARIABLE if not SIZE (ELEMENT_TYPE’' MACHINE_SIZE + 7)/8 if ELEMENT_TYPE is constrained; if not, a value must be specified (there is no default if ELEMENT_TYPE is unconstrained) ACCESS DELETE YES if MODE is OUT_FILE or INOUT_FILE; GET YES PUT YES if MODE is OUT_FILE or INOUT _FILE; NO if MODE is IN_FILE UPDATE YES if MODE is OUT_FILE or INOUT _FILE; NO if MODE is IN_FILE NO if MODE is IN_FILE SHARING GET YES if MODE is IN_FILE; NO if MODE is OUT_FILE or INOUT_FILE Table 3-10: RELATIVE_MIXED 10: Default File Attributes File Attribute Default Value FILE ORGANIZATION RELATIVE RECORD CARRIAGE_CONTROL CARRIAGE_RETURN FORMAT VARIABLE (continued on next page) Input-Output Facilities Table 3—10 (Cont.): RELATIVE_MIXED_lO: Default File Attributes File Attribute SIZE Default Value None; a value must be specified in the FORM parameter ACCESS DELETE YES if MODE is OUT_FILE or INOUT_FILE; NO if mode is IN_FILE GET YES PUT YES if MODE is OUT_FILE or INOUT_FILE; NO if MODE is IN_FILE UPDATE YES if MODE is OUT_FILE or INOUT_FILE; NO if MODE is IN_FILE SHARING GET YES if MODE is IN_FILE; NO if MODE is OUT_FILE or INOUT_FILE Example 3—5 shows the reading and writing of records to cells in a relative file using the package RELATIVE_IO. Read and write operations to relative files do not have to be to consecutively numbered; however, if you try to read at a position for which there is no element, the exception EXISTENCE_ ERROR will be raised. The item input-output operations provided by the package RELATIVE_ MIXED_IO are basically the same as those provided for the other mixed- type packages. See Figure 3-1 and Examples 3—4 and 3-7 for examples of using the item input-output operations. Input-Output Facilities 3-53 Example 3-5: Using the Package RELATIVE_IO with RELATIVE IO; procedure type SHOWRELATIVE IO is SMALL RECORD is record NUM: INTEGER LET: CHARACTER := 0; ’Af; := end record; —-— Instantiate -— that package REC IO on elements a of RELATIVE IO type package SMALL RECORD. is new RELATIVE IO(SMALL RECORD) ; REC I0; to be used. RELATIVE FILE FILE_TYPE; POS POSITIVE REC SMALL RECORD; SMALL RECORD SMALL RECORD I INTEGER; (NUM (NUM il RECX RECY > N COUNT; vV objects ] Declare the il —— I use and make wvisible operates , LET =2 , LET => X" "Y"): begin -- Create the file. CREATE (RELATIVE FILE,OUT_FILE, "RELATIVE FILE.DAT"); incrementing the NUM value, -— Write records, —— cells in positions for I in 1..10 1 through to file 10. loop WRITE (RELATIVE FILE,REC); REC.NUM := REC.NUM + 1; end loop; —-— Prepare the file for reading. RESET (RELATIVE FILE, IN FILE); —- Read POS := contents of records in cells at positions 2 and 3. INDEX (RELATIVE FILE); READ (RELATIVE FILE,RECX, 2); POS := INDEX (RELATIVE FILE); READ(RELATIVE_FILE,REEY); (continued on next page) 3-54 Input-Output Facilities Example 3-5 (Cont.): —— Prepare the RESET (RELATIVE -— Write to := file for writing. FILE,OUT FILE) records WRITE (RELATIVE REC.NUM Using the Package RELATIVE IO in cells at positions 12 and 16. FILE,REC,12); REC.NUM + 1; WRITE (RELATIVE FILE,REC,16); end 3.6.4 SHOW RELATIVE IO; Indexed File Input-Output For creating and working with indexed files of uniform-type elements, VAX Ada provides the generic package INDEXED_IO; for creating and working with indexed files of mixed-type elements, VAX Ada provides the nongeneric package INDEXED_ MIXED_IO. When you create a file with the package INDEXED_IO, VAX Ada gives it the default file attributes listed in Table 3-11. When you create a file with the package INDEXED_MIXED_IO, VAX Ada gives it the default file attributes listed in Table 3—-12. You can use these packages only with files having the attribute ORGANIZATION INDEXED. If you try to use INDEXED_IO or INDEXED_MIXED_IO with a file that has a different ORGANIZATION attribute, the exception USE_ERROR will be raised. When creating indexed files, you must use the FORM parameter to specify any information about the keys (no default key values are provided by the CREATE procedures). Note that there is no default bucket size; if you do not specify a bucket size with the FORM parameter, VMS RMS calculates the bucket size based on the maximum record size (the default is 0). Input-Output Facilites 3-55 Table 3—11: INDEXED_lO: Default File Attributes File Attribute Default Value FILE ORGANIZATION INDEXED RECORD CARRIAGE_CONTROL CARRIAGE_RETURN FIXED if ELEMENT_TYPE is constrained; FORMAT VARIABLE if not SIZE (ELEMENT _TYPE’ MACHINE_SIZE + 7)/8 if ELEMENT_TYPE is constrained; O if not (there 1s no maximum record size; note, however, that SIZE is also limited by the bucket size; see the VMS Record Management Services Manual) ACCESS DELETE YES if MODE is OUT_FILE or INOUT_FILE; NO if MODE is IN_FILE GET YES PUT YES if MODE is OUT_FILE or INOUT_FILE; NO if MODE is IN_FILE UPDATE YES if MODE is OUT_FILE or INOUT_FILE; NO if MODE is IN_FILE SHARING GET YES if MODE is IN_FILE; NO if MODE is OUT_FILE or INOUT_FILE Table 3—12: INDEXED_MIXED 1O: Default File Attributes File Attribute Default Value FILE ORGANIZATION INDEXED RECORD CARRIAGE_CONTROL CARRIAGE_RETURN FORMAT VARIABLE (continued on next page) 3-56 Input-Output Facilities Table 3—-12 (Cont.): File Attribute SIZE INDEXED_MIXED_IO: Default File Attributes Default Value 0 (the record size is unlimited; note, however, that the record size is limited by the bucket size; see the VMS Record Management Services Manual) ACCESS DELETE YES if MODE is OUT_FILE or INOUT_FILE; NO if MODE is IN_FILE GET YES PUT YES if MODE is OUT_FILE or INOUT_FILE; NO if MODE is IN_FILE UPDATE YES if MODE is OUT FILE or INOUT_FILE; NO if MODE is IN_FILE | SHARING GET YES if MODE is IN_FILE; NO if MODE is OUT_FILE or INOUT_FILE You can access indexed files with both sequential and keyed access methods. Sequential access retrieves consecutive components, which are sorted according to the specified key field. Keyed access retrieves components randomly, according to the value of a particular key field. Once you select a key (using the RESET or READ_BY_KEY procedures), a sequential read (using the READ procedure) retrieves components with ascending or descending key field values. Example 3-6 shows the use of the package INDEXED_IO to create an indexed file that has a string-type primary key that sorts the file in ascending order, and a string-type alternate key that sorts the file in descending order. In particular, the example shows how to do comparative key searching in an indexed file. In VAX Ada, the way to do comparative key searching is to use the indexed input-output package READ_BY_KEY procedures (see Chapter 14 of the VAX Ada Language Reference Manual for their specifications). The kind of comparison (equal or next, equal, or next) is determined by the value of the READ_BY_KEY RELATION parameter. The parameter is of the type RELATION_TYPE, and its default value for both packages INDEXED_I10 and INDEXED_MIXED_IO is EQUAL. The value of a READ_BY_KEY RELATION parameter overrides any search option setting you may have made in a CREATE or OPEN FORM parameter. In other words, the FDL Input-Output Facilities 3-57 CONNECT EQUAL_NEXT and CONNECTNEXT attributes never have an effect when you are using a READ_BY_KEY procedure. Example 3-6: Using the Package INDEXED IO —-— Create -— string data. with an INDEXED_ IO package for indexed files containing INDEXED IO; package with STRING_INDEXED IO is new INDEXED IO (STRING):; TEXT IO; use TEXT IO; STRING_INDEXED IO; use with procedure SHOW INDEX STRING_INDEXED IO; is IFILE : STRING_INDEXED IO.FILE STR : STRING (1..10) := : STRING (1..1); KEY STR —— Instantiate —— string matching procedure generic TYPE; " "; READ BY KEY (as opposed to READ BYSTRING_KEY is procedure numeric for ascending key matching). new READ BY KEY (STRING, 0); begin PUT LINE ("-- Test PUT ("-- Creating file"):; procedure must LINE —— The —— ascending CREATE sort —-— order —— attributes —— not is of INDEXED order; KEY determined by confuse in the this the IO0."); give 1 key has string: STRING with information. descending value form - of the KEY STRING or the Ada -- type KEY the 0 has sort TYPE DSTRING. (Do STRING.) (continued on next page) 3-58 Input-Output Facilities Example 3-6 (Cont.): Using the Package INDEXED IO —— Because this is -- the Ada type STRING —— also —— is —-— record CREATE an indexed is file of specify the maximum record used so that the the Ada type an unconstrained type, size. system will not and of 0 bytes a maximum length. (FILE => IFILE, MODE => INOUT FILE, NAME => "INDEXED FORM => "FILE;" STRING.TXT", & "ORGANIZATION INDEXED;" "RECORD; " O;" & O;" & -— Key —— ascending "TYPE value "LENGTH & & 1;" & YES;" 1;" & & —-— Key —— descending "TYPE causes sort. 0;" "DUPLICATES value DSTRING "LENGTH O;" 1;" "DUPLICATES causes sort. DSTRING; " "POSITION —— Populate STRING STRING;" "POSITION "KEY & & "SIZE "KEY — A size impose STRING, you must & & & YES;" ) [4 file. p— PUT LINE WRITE ("-- (IFILE, Populating file"); "Mary n) ") : WRITE (IFILE, "Larry WRITE (IFILE, "Charlie "); WRITE (IFILE, "Kirk ") WRITE (IFILE, "Spencer ") WRITE (IFILE, "Susan "), (continued on next page) Input-Output Facilities 3-59 Example 3—-6 (Cont.): -— Read file PUT LINE RESET Using the Package INDEXED IO sequentially using ("-- Read file ascending sequentially: (FILE => IFILE MODE => INOUT FILE, index. ascending sort"); , KEY NUMBER => 0); not END OF FILE (IFILE) while loop READ PUT (IFILE, LINE STR); (STR); end loop:; —-- Read file PUT _LINE RESET sequentially using ("-- Read (FILE MODE KEY while not NUMBER file descending sequentially: => TFILE, => INOUT_ FILE, => 1); index. descending sort"); END OF FILE (IFILE) loop READ (IFILE, PUT LINE STR); (STR); end loop:; —-- Change -— of -— file by PUT _LINE RESET KEY the := -— Read the —-— whose whole ascending index"); IFILE):; first item that equal to "M". Use character match, key number set translates character is is —— to an BYSTRING KEY ascending key), (FILE => IFILE, ITEM => STR, KEY => KEY STR, KEY NUMBER => RELATION LINE instantiation read the "M"; -—- PUT and key. READ BY KEY: => first the EQUAL NEXT using the (READ BY STRING KEY), ascending ("-- (FILE STR READ search to READ BY KEY => or that follows a string READ BYSTRING KEY to and (0 in this example relation. 0, EQUAL NEXT); (STR); (continued on next page) 3-60 Input-Output Facilities Example 3—6 (Cont.): —— Read the —-—- Using the Package INDEXED_IO rest of the requirements strings that meet the specified in the READ BYSTRING KEY statement -—- using READ (a loop of READ BY KEY will endlessly —— first match). return the while not END OF FILE (IFILE) loop READ (IFILE, PUT LINE STR):; (STR); end loop; -- Read by descending key only those records that begin —-— with "S". Use READ BYSTRING KEY to set the character —— match, key number (1 in this example translates to a ~- descending key), and relation. PUT LINE RESET ("-- READ_BY KEY: (FILE KEY STR := => descending index"); IFILE); "S"; KEY READ BYSTRING (FILE => IFILE, ITEM => STR, KEY => KEY STR, RELATION => EQUAL):; PUT_LINE (STR); while not END OF FILE (IFILE) loop READ (IFILE, PUT LINE STR); (STR); end loop; —— Finish. PUT _LINE ("-- Closing file"); CLOSE (FILE => IFILE ); end SHOW_INDEX; Example 3-7 shows the use of the package INDEXED_MIXED_IO, shows how to create a mixed-type indexed file, and then shows how to read and write from the file using the primary key. Input-Output Facilities 3-61 Example 3—-7: with Using the Package INDEXED MIXED IO INDEXED procedure MIXED IO; SHOW INDEXED use type INTEGER ARRAY TYPE type COLORS -— — Declare is INDEXED MIXED IO; MIXED is is array(INTEGER range <>) of INTEGER; (RED,BLUE, YELLOW) ; objects to be used to fill the file with wvalues. — INDEXED FILE FILE INTEGER ARRAY INTEGER_ARRAY TYPE (1..3); INT1, INT2 , INT3, INT4, INTS , INT6, CHAR1, CHAR3, INT7 TYPE; INTEGER; CHARZ, CHAR4 CHARACTER; COLl, COLZ COLORS; ARRAY INDEX INTEGER; —— Instantiate the generic READ BY KEY procedures. procedure READ O is new READ procedure READ 1 is new READ BY KEY (CHARACTER,1); —- Instantiate the generic BY KEY (INTEGER,O) ; GET_ITEM and PUT ITEM procedure GET INT is new GET ITEM (INTEGER) ; procedure GET_FLOAT is new GET ITEM (FLOAT) ; procedure GET CHAR is new GET_ITEM (CHARACTER) ; procedure GET ENUM is new GET_ITEM (COLORS) ; procedure PUT INT is new PUT_ITEM (INTEGER) ; PUT_ITEM (FLOAT) ; procedure PUT FLOAT is new procedure PUT CHAR is new PUT_ITEM (CHARACTER) ; procedure PUT ENUM is new PUT procedure GET_ARRAY INT is new procedures. ITEM (COLORS) ; GET ARRAY (INTEGER, INTEGER, INTEGER ARRAY TYPE) ; (continued on next page) 3-62 Input-Output Facilities Example 3-7 (Cont.): Using the Package INDEXED_ MIXED_IO begin file. CREATE (FILE => INDEXED FILE, MODE => OUT FILE, NAME => "F.DAT", "ORGANIZATION R "DUPLICATES "LENGTH "TYPE R 1;" STRING;" "DUPLICATES "POSITION "LENGTH the element v 4;" 1 ;" "INDEX FILL Fill YES;" O;" 27 "POSITION 4;" Y INT4;" 22 FILL "TYPE R "INDEX "KEY INDEXED;" 0;" YES;" 4;" Y "KEY & "FILE;" 22 2 FORM => R Create the ) ; 1;" buffer with a character, an integer, and an enumeration value. INT1 = CHAR1 := 1; 'A’; COLl := YELLOW; PUT INT (INDEXED FILE, INT1); PUT CHAR(INDEXED_ FILE,CHARL) ; PUT ENUM (INDEXED FILE,COLl) ; Write the element to the file. WRITE (INDEXED FILE); Prepare to read the record from the file. RESET (INDEXED FILE,INOUT FILE) ; Read the record from the the primary key file sorting on (integer). READ O (INDEXED FILE, INT1,0); GET INT (INDEXED FILE, INTZ2); GET CHAR (INDEXED FILE, CHARZ) ; GET ENUM (INDEXED FILE,COLZ2); (continued on next page) Input-Output Facilites 3-63 Example 3-7 (Cont.): Using the Package INDEXED MIXED IO ~— Prepare to add more elements to the file. RESET (INDEXED FILE); SET POSITION (INDEXED FILE,1); —- Fill the buffer with an -- and three more —— the file. INT3 := CHAR3 := ’'B’; INT4 = 4; INTS = 5; INT6 := 6; integer, integers, a character, and write the buffer to 3; PUT INT (INDEXED FILE, INT3) PUT CHAR(INDEXED FILE,CHAR3); PUT INT (INDEXED FILE, INT4); PUT INT (INDEXED FILE,INTS); PUT INT (INDEXED FILE,INT6) ; WRITE (INDEXED FILE) ; —~—- Read the —- key 1 record from the file sorting on (string). READ 1 (INDEXED FILE,CHAR3,1); —— Get the —-- three items from the integers directly buffer; in particular, into the read integer array. GET_INT (INDEXED FILE, INT7); GET CHAR (INDEXED FILE,CHARY); GET_ARRAY INT (INDEXED FILE, INTEGER ARRAY,ARRAY INDEX); —— Do some more work and then close the file. CLOSE (INDEXED FILE) ; end SHOW 3.7 INDEXED MIXED; Text Input-Output VAX Ada provides the package TEXT_IO for creating and working with text files. TEXT_IO is not generic, but it does include generic packages for the input and output of integers, floating-point numbers, fixed-point numbers, 3-64 Input-Output Facilities and enumeration values. When you create a file with this package, VAX Ada gives it the defaults listed in Table 3-13. You can use this package only with files that have the attribute ORGANIZATION SEQUENTIAL. For example, you can use TEXT_IO operations to open and read files created with the packages SEQUENTIAL_ I0, SEQUENTIAL_MIXED_IO, DIRECT IO, or DIRECT_MIXED_IO, as well as TEXT IO. If you try to use this package with files that have a different ORGANIZATION attribute, the exception USE_ERROR will be raised. Table 3-13: TEXT_IO: Default File Attributes File Attribute Default Value FILE ORGANIZATION SEQUENTIAL SEQUENTIAL_ONLY YES RECORD CARRIAGE_CONTROL PRINT if device is a terminal; CARRIAGE_ RETURN otherwise FORMAT VFC if device is a terminal; VARIABLE otherwise SIZE 0 (record size is unlimited; note, however, that the record size has physical limitations; see the VMS Record Management Services Manual) ACCESS GET YES PUT YES if MODE is OUT_FILE; NO if MODE is IN_FILE TRUNCATE YES if MODE is OUT_FILE; NO if MODE is IN_FILE (continued on next page) Input-Output Facilites 3-65 Table 3—-13 (Cont.): TEXT _IO: Default File Attributes File Attribute Default Value SHARING GET YES if MODE is IN_FILE; NO if MODE is OUT_FILE CONNECT READ_AHEAD YES WRITE_BEHIND YES if MODE is OUT_FILE As shown in Table 3-13, VAX Ada text files are implemented as VMS RMS sequential files. Each line in a text file corresponds to a single VMS RMS record; VAX Ada text files are not stream files. Although VAX Ada creates text files with variable-length records by default, you can use the FORM parameter (see Section 3.3) to create text files with fixed-length records. When a text file with fixed-length records is being written, the line length (if nonzero) must be less than or equal to the record size. The exception USE_ERROR is raised if you try to change the line length to a value greater than the record size. This exception is also raised when a line being written is longer than the record size. When you write a program that creates text files with fixed-length records, set the line length to the record size. If the line being written does not fill the entire (fixed-length) record, spaces are used to pad the rest of the record (and the spaces are then regarded as characters in the file). 3.7.1 Using the Package TEXT_lO for Terminal Input-Output When using the package TEXT_IO to read from or write to a terminal, keep the following points in mind: * VAX Ada TEXT_IO operations are implemented with VMS RMS inputoutput operations, and VMS RMS operations always involve complete records. 3-66 * Buffering is used in both terminal input and output (see Section 3.7.3). ®* Terminal input is not processed until a line (a VMS RMS record) is terminated by a carriage return (or other line terminator). Input-Output Facilities e CTRL/Z is interpreted sometimes as a file terminator, and sometimes as a line terminator followed by a page terminator followed by a file terminator (the importance and interpretation of the various terminators is discussed in Section 3.7.2). The difference in interpretation can cause a difference in effect. * You can achieve asynchronous input-output in tasking programs by defining the logical names ADA$INPUT and ADA$OUTPUT so that they refer to nonprocess-permanent files; for example, by defining ADASINPUT and ADA$OUTPUT so that they refer to TT, you can achieve asynchronous terminal input-output. See Section 3.9.2 for more information. Example 3-8 shows the use of TEXT_IO operations to write text from a terminal to a file. Sections 3.7.1.1 to 3.7.1.4 discuss a number of coding methods for accomplishing interactive terminal input-output. Example 3-8: Using the Package TEXT IO with TEXT IO; use TEXT IO; procedure MY COPY COPY is : FILE INPUT 80 : STRING CURRENT PAGE : POSITIVE COUNT; LAST : NATURAL; TYPE; (1..80); begin CREATE (MY _COPY, OUT FILE, PUT LINE ("Start typing PUT LINE ("Type CTRL/Z "MY your to COPY.TXT"); book."); finish."); loop —— Remember —— 80 characters, current —-—- to the text CURRENT PAGE GET_LINE PUT then write get out at the most line file. := PAGE (INPUT 80, (MY COPY, page, then (CURRENT_INPUT) ; LAST); INPUT 80 (1..LAST)); (continued on next page) Input-Output Facilites 3-67 Example 3-8 (Cont.): -— Using the Package TEXT IO If a new page —— the page is in the —— end-of-page —— an end-of-file -— a new line. started, file. if the page write an explicit change (CTRL/Z). if CURRENT PAGE < PAGE then terminate Do not a result Otherwise, is start (CURRENT INPUT) of then if not END OF FILE then NEW PAGE (MY COPY); end if; else NEW LINE (MY COPY):; end if; end loop; exception when END ERROR NEW _LINE PUT ("Your CLOSE => (3); text is in file MYCOPY.TXT"); (MY COPY) ; end COPY; When working with text input-output in general, and with terminal inputoutput in particular, keep in mind that each VAX Ada TEXT_IO operation behaves exactly as it is described in the VAX Ada Language Reference Manual. For example: with TEXT IO; procedure use INOUT LINE: LAST TEXT IO; SHOW_GETS CHAR: is STRING(1..10) := "tenletters"; NATURAL; begin PUT LINE ("Do a GET LINE"); GET LINE (INOUT LINE,LAST CHAR); PUT_LINE (INOUT LINE); PUT LINE ("Do another GET LINE"); GET LINE (INOUT LINE,LAST CHAR); PUT (INOUT LINE) ; end SHOW GETS; If you run this program and press CTRL/Z as the only input to the GET_ LINE operation, the immediate result is that the VMS exit prompt appears on your screen, and then the string "tenletters" is printed. This result occurs because GET_LINE is defined as a procedure that replaces the characters of its string argument with input characters until it encounters a line terminator. 3-68 Input-Output Facilities Because CTRL/Z in this case represents a line terminator followed by a page terminator followed by a file terminator (see Section 3.7.2), GET _ LINE immediately encounters a line terminator. Then, according to the language definition of GET_LINE, SKIP_LINE is called, and the subsequent page terminator is skipped. The initial string is output because it was not changed by GET_LINE. Because the file terminator remains as input for the next GET_LINE operation, the exception END_ERROR is raised when the next GET_LINE operation is executed. If the first GET_LINE had been a GET, the exception END_ERROR would have been raised immediately. Similarly, if you use the GET_LINE procedure to read a value into a string variable of N characters, and you enter exactly N characters followed by a carriage return, the END_OF _LINE function will return the value FALSE. However, another call to GET_LINE will read in a null string, indicating that there was a line terminator in the input buffer (the carriage return), which was entered after the N characters were entered. This effect occurs because when you read in exactly as many characters as are on the line, the SKIP_LINE procedure is not called after the characters are transferred. The effect is in accordance with the description of the GET_LINE procedure in the VAX Ada Language Reference Manual. You should also be aware that when you do a SKIP_LINE operation in VAX Ada (or any operation that, in effect, does a SKIP_LINE, such as a GET_ LINE; see Chapter 14 of the VAX Ada Language Reference Manual), the skipping of the page terminator (if any) is delayed. A subsequent operation may require that the skipped page terminator be retrieved, and the result is a request for more input from the file. This delaying process enables a GET_LINE operation from a terminal device to be (partially) satisfied immediately after a carriage return and then for execution of the program to continue. 3.7.1.1 Line-Oriented Method Example 3-9 shows a line-oriented method of using TEXT IO operations for interactive terminal input-output. Arbitrary lines are obtained using the procedure GET_LINE within a loop. The actual interpretation of data on each line is deferred to other code, so this method is very flexible and adaptable. The method expects the user to enter one of the following: e A line of data * A null line (carriage return) * An end-of-file indicator (CTRL/Z) Input-Output Facilites 3-69 If you want to allow the user to respond with multiple CTRL/Zs, you need to declare a file variable to serve as the input file, rather than using the default standard input file. You need to use a file variable because the only way to get past the first CTRL/Z is to reset the file, and you cannot pass the standard input file as a parameter to the procedure RESET (RESET’s file parameter has a mode of in out; the standard input file can be used only with a mode of in). Example 3-9 declares the variable TERMINAL for this purpose. Example 3-9 can be extended to obtain whatever data is on each line by using those TEXT IO operations that read data from a string (in this case, the string variable LINE). After trying Example 3-9, note that a CTRL/Z is interpreted sometimes as a file terminator and sometimes as a line terminator followed by a page terminator followed by a file terminator. The simplest explanation for this follows: e CTRL/Z requires a prior line. e If there is a prior line, the CTRL/Z is interpreted as a file terminator. e If there is no prior line, the CTRL/Z inserts a null line, and is interpreted as a line terminator followed by a page terminator followed by a file terminator. In other words, a call to GET_LINE that encounters a CTRL/Z may or may not return a null line before resulting in an END_ERROR. 3-70 Input-Output Facilities Example 3-9: Example of Line-Oriented TEXT_IO with TEXT IO; use TEXT IO; procedure IOEXAMPLE is —— This example shows how to input a command line from a —— terminal. It shows how to prompt using PUT followed by GET, -—- and shows how to recover from END_ERROR (CTRL/Z). —— To run this program, you must define the —— USER_INPUT to point to your terminal. logical name For example: $ DEFINE USER_INPUT TT - TERMINAL : subtype LINE FILE TYPE; TYPE is LEN : NATURAL; LINE : LINE STRING(1..132); TYPE; begin PUT LINE ("This example is programmed so that PUT LINE ("a RETURN or CTRL/Z PUT LINE ("All PUT LINE ("To is entering"); ignored."); other entries are echoed."); quit, type Q or g."): —— NOTE: To recover from CTRL/Z (end-of-file) on a terminal, you -- must do a RESET. To do a RESET, you must have a file variable. -—- Thus, you must —— terminal. —-— as ‘the file so that and the ’'in’ parameter. —— This example uses -—- opened, it is an standard input the it "speaks" standard input file because RESET takes —-— parameter, -—- open the You cannot use the ’'in out’ file file variable associated with the to the file (ADASINPUT) file as a can be used only as TERMINAL. external When TERMINAL file an is "USER_INPUT:", —— which you have defined as a logical name that points to the —— terminal. The file variable TERMINAL can be used as an actual -- parameter to the RESET procedure. OPEN (TERMINAL, IN FILE, "USER INPUT:"); loop begin -- Note that -— a GET is entered from the calls to PUT are buffered until -— sequence 'PUT GET’ PUT ("Command> same device. results a NEW LINE Thus, or the in prompting. ") ; GET_LINE(TERMINAL, LINE, LEN); (continued on next page) Input-Output Facilities 3-71 Example 3-9 (Cont.): if LEN = 0 Example of Line-Oriented TEXT IO then PUT LINE ("Thank you for entering a null PUT_LINE ("Thank you for entering the line."); else command " & LINE(1l..LEN)); if LINE(1..LEN) = "g" PUTLINE("Exiting or LINE(l..LEN) = "Q" then now..."); exit; end if; end if; exception when END ERROR => RESET (TERMINAL) ; PUT LINE ("Thank you for entering a CTRL/Z."); end; end loop; end 3.7.1.2 IOEXAMPLE; Data-Oriented Method Example 3-10 shows a data-oriented method of using TEXT IO operations. A sequence of data values is obtained using a series of calls to the GET procedure within a loop. The interpretation of the data is important and embedded in the code that does the input-output, but how the data is laid out across lines is not important. The user is expected to enter one data value (not necessarily a line) at a time. If the wrong kind of data is entered, the exception DATA_ERROR is raised. 3-72 Input-Output Facilities Example 3-10: with TEXT I0; Example of Data-Oriented TEXT_IO use TEXT IO; with FLOAT_TEXT_ IO; with INTEGER TEXT IO; use FLOAT_ TEXT IO; use INTEGER TEXT IO; procedure ANOTHER IO EXAMPLE TERMINAL : FILE_TYPE; : FLOAT; : INTEGER; is FLT1 VALUE, FLT2 VALUE, FLT3 VALUE INT1 VALUE, INT2 VALUE, INT3 VALUE begin PUT _LINE ("This example is programmed PUT LINE("a RETURN or CTRL/Z PUT_LINE("All other entries OPEN (TERMINAL, INFILE, so that is ignored."); are echoed."); entering"): "USER INPUT:"); loop begin PUT ("Enter PUT (" (to 3 integers quit enter GET (TERMINAL, exit when on arbitrary INT1l VALUE) ; INT1 VALUE = 0O; GET (TERMINAL, INTZ2_ VALUE) ; GET (TERMINAL, INT3 VALUE) ; PUT("Ok, we lines"); 0)"); got: "); PUT (INT1 VALUE) ; PUT (INT2_VALUE) ; PUT (INT3_VALUE) ; NEW LINE; (continued on next page) Input-Output Facilities 3-73 Example 3—-10 (Cont.): Example of Data-Oriented TEXT_IO PUT ("Enter 3 floats PUT (" (to quit enter GET (TERMINAL, FLT1 exit when FLT1 on arbitrary VALUE) ; VALUE = 0.0; GET (TERMINAL, FLT2Z VALUE); GET (TERMINAL, FLT3 VALUE); PUT ("Ok, we PUT (FLT1 VALUE) ; got: lines"):; 0.0)"); "); PUT(FLTZ“VALUE); PUT (FLT3 VALUE) ; NEW LINE; exception when END ERROR => RESET (TERMINAL) ; PUTLINE("Ok, let’s try again"); end; end loop; end ANOTHER IO EXAMPLE; 3.7.1.3 Mixed Method The mixed method of using TEXT IO operations sometimes obtains whole lines using the GET_LINE procedure, and sometimes obtains individual data values using the GET procedure. This method is much trickier than the line-oriented or data-oriented method because GET and GET_LINE treat line terminators differently: ¢ GET skips leading line terminators before reading data. e GET_LINE (usually) skips line terminators after reading data. Thus, if you follow a GET with a GET_LINE, the GET_LINE is likely to return a null string found at the end of the current line. To make GET and GET_LINE compatible, you need to follow the last GET on every line with a SKIP_LINE. However, the SKIP_LINE will ignore any data that the user may have typed after the GET. The incompatible nature of GET and GET_LINE makes this style complicated and error-prone. 3-74 Input-Output Facilities 3.7.1.4 Flexible Method In some cases, you may want to mix the kinds of data the user can enter. For example, you may want to allow users to enter integers where real numbers are normally expected; that is, to enter 3 when 3.0 is expected. You can accomplish this by handling the exception DATA_ERROR as follows: e Try to read a real number. e If DATA_ERROR is raised, handle it by trying to read an integer. Example 3—11 shows the use of this method. The example also shows how you can display a default value that will be used if the user enters no data (a carriage return or CTRL/Z). NOTE When you enter a CTRL/Z after entering a line that ends with a carriage return, the CTRL/Z is considered to be the end-of-file. A sequence of two CTRL/Zs is equivalent to the sequence RETURN CTRL/Z. Example 3—11: I0; Example of Flexible TEXT_IO with TEXT with INTEGER TEXT IO; use TEXT IO; use with LONGFLOAT TEXT IO; procedure GET NUM NUM : subtype LINE L, (INPUT: LAST: LONGFLOAT TEXT IO; in out FILE TYPE; X: in out LONG_FLOAT) is INTEGER; LINE TYPE : INTEGER TEXT IO; use is STRING(1l..132); LINE TYPE; INTEGER; (continued on next page) Input-Output Facilities 3-75 Example 3-11 (Cont.): Example of Flexible TEXT IO begin PUT(X,3,2,0); PUT("] . u) ; loop begin GET LINE (INPUT, exit when L = LINE, L); 0; GET (LINE(1l..L),X,LAST); exit; exception when END ERROR => RESET (INPUT) ; exit; when DATA ERROR => begin GET (LINE(1..L),NU LAST) M, ; X := LONG_FLOAT (NUM) ; exit; exception when DATA ERROR => PUT (" Invalid data, try again: end; ; ") end; end loop; end GET NUM; VD ST Bt SN D M . — — —— — . W T T T G W S— —— — — — — — . T W T— A WY GG W S ——— — — — — with GET NUM; with TEXT IO; with INTEGER TEXT IO; use TEXT IO; use INTEGER TEXT IO; with LONG_FLOAT_TEXT_IO; procedure NUM : INPUT: use LONGFLOA TEXT T IO; THIRD IO EXAMPLE LONG FLOAT TEXT := IO.FILE is 1.0; TYPE; (continued on next page) 3-76 Input-Output Facilities Example 3-11 (Cont.): Example of Flexible TEXTIO begin OPEN (INPUT, INFILE, "USER _INPUT:"); loop PUT ("Enter a real exit when NUM = or integer format number (0 to exit) "); 0.0; GET_ NUM (INPUT, NUM) ; NEW LINE; PUT ("Ok, we received: "); PUT (NUM) ; NEW LINE; end loop; end THIRD IO EXAMPLE; 3.7.2 Line Terminators, Page Terminators, and File Terminators The Ada language defines “logical” text files and text file operations in terms of line terminators, page terminators, and file terminators (see Chapter 14 of the VAX Ada Language Reference Manual). This definition means that a text file is logically structured so that the end of a line is marked by a line terminator (LT), the end of a page is marked by a line terminator followed by a page terminator (LT PT), and the end of a file is marked by a line terminator followed by a page terminator followed by a file terminator (LT PT FT). Figure 3-3 shows a simple, three-page text file. Input-Output Facilites 3-77 Figure 3-3: An Ada Text File, Showing Line, Page, and File Terminators Column Number 1 2 3 4 5 6 7 1 T H | S | ) F | R S 3 T H E 4 P A G E Line 8 9 10 11 12 S T H E@ P G E @ N D@ IS B L AN I T H E@ G E @ E N D 13 14 15 Number 5 | @@ T S E C 6 T H 1 S 7 T H | R 8 A N D T H 9 T H E F 1L D O S P A E E K - 0 F@ -O@® ZK-4041-GE VAX Ada interprets these terminators is as follows: e A line terminator (LT) is designated by the end of a VMS RMS record, except when the next record in the file logically represents a line terminator followed by a page terminator (LT PT; see the next item). In an empty file, a line terminator is designated by the end of the file. e A line terminator followed by a page terminator (LT PT) is designated by one of the following: — ‘ An entire record consisting of a single form-feed control character (for text files with variable-length records). — An entire record with a form-feed control character as the first byte of the record (for text files with fixed-length records). 3-78 Input-Output Facilities — An empty record with VMS RMS PRN information that indicates a form-feed control character (for variable-length with fixed-length control records and files created with the CARRIAGE_CONTROL PRINT attributes). — The end of the file, whenever the last record of the file does not itself represent a page terminator (that is, when the last record does not represent a line terminator followed by a page terminator; LT PT). * A file terminator (FT) is designated by the end of the file. An empty file thus represents a line terminator followed by a page terminator followed by a file terminator (LT PT FT). If the file is not empty and the last record of the file does not represent a line terminator followed by a page terminator (LT PT) (if, for example, the file consists of a single line ending in only a line terminator), then the end of the file represents a page terminator followed by a file terminator (PT FT). When the last record of the file represents a line terminator followed by a page terminator (LT PT), the end of the file is a file terminator (F'T). For example, an external file created by the following three operations contains exactly one empty record: CREATE (MY FILE); NEW_LINE (MY CLOSE FILE); (MY FILE); Because the NEW_LINE procedure uses the default spacing of 1, and because no new pages are created, the NEW_LINE in this example produces one line terminator (LT). In this case, a line terminator is represented by a single, empty VMS RMS record in the corresponding external file. (See the VAX Ada Language Reference Manual for a complete description of the NEW_LINE procedure.) By replacing the NEW_LINE procedure with a NEW_PAGE procedure, you would produce a file with one record consisting of a single form-feed control character. (MY_FILE has variable-length records because it is created using the default attributes provided by TEXT I0.) By completely eliminating the NEW_LINE operation, you would produce an empty file. All three cases mentioned produce the same logical file consisting of a line terminator followed by a page terminator followed by a file terminator (LT PT FT). Input-Output Facilites 3-79 3.7.3 Text Input-Output Buffering VAX Ada TEXT_IO operations are implemented with VMS RMS inputoutput operations. Because VMS RMS operations always involve complete records, the transfer of characters between a physical input-output device and a VAX Ada text file is complete only when a line terminator is detected. Therefore, in most cases, as characters are read or written to a VAX Ada text file, they are stored in an internal line buffer until a complete record can be transferred through VMS RMS. Thus, when you are performing either terminal or nonterminal input, information from the external file is transferred and processed a line (a VMS RMS record) at a time. Hence, terminal input is not processed until the line 1s terminated by a carriage return (or other line terminator). It is possible to provide more information in a line than the current input operation needs. In that case, the remaining characters are kept in a buffer to be processed by subsequent input operations. Each time an operation requires more input from the external file, a new read operation from that file is initiated. When you are performing either terminal or nonterminal output, the output is also buffered until a line terminator is encountered. In other words, the output is buffered until a NEW_LINE or a NEW_PAGE (or any other operation that in effect performs a NEW_LINE or a NEW_PAGE, such as PUT_LINE) is executed. Partial buffering is done when you are performing terminal output and you have specified the attributes FDL. CARRIAGE_CONTROL CARRIAGE _ RETURN or CARRIAGE_CONTROL PRINT in a CREATE or OPEN FORM parameter (see Section 3.3). (PRINT is the default CARRIAGE_CONTROL attribute provided by the package TEXT IO for external files that are terminals; see Table 3-13.) Partial buffering means that PUT operations to the terminal output file are buffered until one of the following actions occurs: * Input is attempted for any other file that is associated with the same terminal device (for example, your program executes a PUT, or a series of PUT operations, followed by a GET). * Execution of one or more PUT operations causes 1000 or more characters to be written to the buffer. 3-80 Input-Output Facilities When one of these actions occurs, the contents of the file buffer is output to your terminal, whether or not the record represented by the buffer is complete. For example, the following program buffers the four characters produced by the PUT operations. Then, when the GET is executed, the program prints the letters “abcd” on the screen as a single line and waits for input. with TEXT IO; use TEXT IO; procedure PRINTCHAR is C: CHARACTER; begin PUT("a’); PUT(’b’); PUT('c’); PUT(’d’); GET (C) ; PUT (C) ; end PRINTCHAR; The contents of any text file buffers (partial or full) are also written to your terminal (flushed) whenever your program image exits (such as when an unhandled exception propagates out of a main program). In this situation, all unclosed files are also closed by an exit handler. 3.7.4 TEXT_lIO Carriage Control The FDL CARRIAGE_CONTROL attribute specifies the carriage-control format for a file. You can also use this attribute to control line buffering for files being written to terminal devices. As describedin Section 3.3, you can specify the CARRIAGE CONTROL attribute with a FORM parameter as follows: TEXT_TO.CREATE (FILE => file MODE => OUT FILE, NAME => external file name, FORM => TEXT IO.OPEN object name, "RECORD; CARRIAGE CONTROL (FILE => file MODE => QUT FILE, NAME => external file name, FORM => "RECORD; value;"); object name, CARRIAGE CONTROL value;"); The CARRIAGE_CONTROL attribute is a creation-time attribute (see Section 3.3.2), and you cannot use an OPEN procedure to change what was specified when the file was created. Input-Output Facilities 3-81 The possible CARRIAGE_CONTROL values are as follows: CARRIAGE_RETURN The default if the device is not a terminal; generally provides the desired behavior for most terminal and nonterminal applications. PRINT The default if the device is a terminal and the file mode is OUT_FILE; results in the use of a variable-length with fixed-length control (VFC) record format. The control portion of each record contains carriage-control information that indicates line and page boundaries. NONE Useful in applications that need to move the cursor randomly and update the screen. Output to files specified with this option is buffered until an operation that requires a line terminator is executed. Calls to PUT_LINE or NEW_ LINE can be used to control when the actual VMS RMS line termination operation occurs. FORTRAN Useful for applications that want to use FORTRAN carriage-control characters. Table 3-14 summarizes the meaning of the FDL CARRIAGE_CONTROL values when they are applied to VAX Ada text files (for both terminal and nonterminal input-output). Table 3—-14: VAX Ada Carriage-Control Options Option CARRIAGE_RETURN Kind of InputOutput Carriage Control Terminal input Nonterminal input Each record corresponds to a single line. A 1-byte record containing a form feed designates a page. Terminal output A VFC record format with a 2-byte control portion is used regardless of what is specified in the form string. The control portion of the record specifies the carriage- control information (line feed, carriage return, null, or page). (continued on next page) 3-82 Input-Output Facilities Table 3—14 (Cont.) : VAX Ada Carriage-Control Options Kind of Input- Option Output Carriage Control Nonterminal output The record attributes for the file imply that each record is preceded by a line feed and followed by a carriage return when the file is displayed or printed. A 1-byte record containing a form feed designates a page. PRINT Terminal input Each record corresponds to a single line. A 1-byte record containing a form feed designates a page. Nonterminal input Control information indicates that a page is interpreted as a page terminator. Otherwise, a record is assumed to correspond to a line. Terminal output Nonterminal output A VFC record format with a 2-byte control portion is used regardless of what is specified in the form string. The control portion of the record specifies the carriagecontrol information (line feed, carriage return, or page). NONE Nonterminal input Terminal input Each record corresponds to a single line. A 1-byte record containing a form feed designates a page. (continued on next page) Input-Output Facilites 3-83 Table 3—-14 (Cont.): VAX Ada Carriage-Control Options Kind of Input- Option Output Carriage Control Terminal output A VMS RMS record is written Nonterminal output whenever an operation is executed that requires a line terminator. However, no carriage-control information is written for lines, and the record attributes for the file do not imply that records are preceded by a line feed or followed by a carriage return. A 1-byte record containing a form feed designates a page. FORTRAN Terminal input Nonterminal input The first byte of each record (containing carriage-control information) is considered to be data. Each record corresponds to a single line. A 1-byte record containing a form feed designates a page. Terminal output Nonterminal output No carriage-control information is supplied by VAX Ada. The first byte PUT by the user in each line is interpreted as a FORTRAN carriage-control character (see Table 3-15). Table 3—-15: FORTRAN Carriage-Control Characters Character Meaning r Overprinting: starts output at the beginning of the current line. ! ros Single spacing: starts output at the beginning of the next line. rQ Double spacing: skips a line before starting output. (continued on next page) 3-84 Input-Output Facilities Table 3—-15 (Cont.): FORTRAN Carriage-Control Characters Character Meaning 4 Paging: starts output at the top of a new page. r Prompting: starts output at the beginning of the next line and suppresses the carriage return at the end of the line. ASCII.NUL 3.7.5 Prompting with overprinting: suppresses the line feed at the beginning of the line and the carriage return at the end of the line. Predefined Instantiations of TEXT IO Packages To make your use of the generic TEXT_IO operations more efficient, VAX Ada provides the following predefined library packages that instantiate the integer and floating-point operations for the predefined integer and floating-point types: Package Name Instantiation INTEGER_TEXT 10 INTEGER_IO(INTEGER) SHORT_INTEGER_TEXT_IO INTEGER_IO(SHORT_INTEGER) SHORT_SHORT_INTEGER_TEXT_IO INTEGER_IO(SHORT_SHORT_ INTEGER) FLOAT_TEXT 10 FLOAT_IO(FLOAT) LONG_FLOAT _TEXT_IO FLOAT_IO(LONG_FLOAT) LONG_LONG_FLOAT _TEXT IO FLOAT_IO(LONG_LONG_FLOAT) Thus, instead of writing out the instantiation for INTEGER_IO in each program unit that does text input-output of integers, you can make the predefined package INTEGER_TEXT IO available to the applicable units (or to your whole program). For example: with INTEGER TEXT IO; procedure A,B: use INTEGER TEXT IO; WRITEOUT INTEGERS is INTEGER; begin A := 10; PUT (A) ; B := A**2; PUT (B) ; end WRITEOUT INTEGERS; Input-Output Facilites 3-85 Each predefined package is produced by compiling the equivalent of the following instantiation: with TEXT IO; package INTEGER TEXT IO is new TEXTIO.INTEGER IO (INTEGER); If you want to use other TEXT_IO operations, such as string operations or INTEGER_TEXT_IO operations that involve files other than standard files (files that you declare in your program), you must also make the package TEXT_IO available to your program. For example: with TEXT IO; with INTEGER TEXT IO; procedure use TEXT IO; use INTEGER TEXT IO; is WRITE_STRINGS AND INTS X: INTEGER; F: FILE TYPE; begin PUT ("The X end 3.8 1= value of X is "); -- TEXT IO.PUT =24; PUT (X) ; —-— INTEGER_TEXT NEW LINE; —-— TEXT IO.NEW LINE IO.PUT CREATE (F) ; —— TEXT IO.CREATE PUT (F, X) ; -— INTEGER TEXT IO.PUT WRITE STRING AND INTS; S Input-Output and Exception Handling The VAX Ada input-output packages raise errors that are defined in the packages IO_EXCEPTIONS and AUX_IO_EXCEPTIONS. See the VAX Ada Language Reference Manual for descriptions of these errors and the operations that raise them. See Chapter 4 of this manual for information on exception handling. 3.9 Input-Output and Tasking The following sections discuss topics related to tasking and input-output. For more information on tasking and tasking concepts, see Chapter 8. 3-86 Input-Output Facilities 3.9.1 Synchronization of Input-Output Operations In VAX Ada, each file operation is synchronized so that a series of operations to the same file takes place sequentially, rather than concurrently. In other words, operations on the same file are “indivisible.” Thus, if one task is performing an operation on a file and another task attempts to perform an operation on the same file, VAX Ada causes the second task to wait until the earlier operation is finished. Any number of tasks may be waiting for a file to be released by a task that is performing an operation on that file. This synchronized access allows multiple tasks to perform concurrent input-output operations on the same file without corrupting the file. For example, if one task executes TEXT_IO.PUT(F,"Reach") and another task concurrently executes TEXT_IO.PUT(F, "Out"), where F is a file object, the external file associated with F receives either "ReachOut" or "OutReach". VAX Ada will not produce "ReOuacth". If you want to execute concurrent input-output operations from multiple processes, you should use VMS RMS record locking to provide synchronization among the various files. 3.9.2 Task Wait States Caused by Input-Output Operations In general, VAX Ada input-output operations cause only the executing task to wait until the operation is completed. Other tasks in the process can continue executing while the task executing the input-output operation is waiting. An exception to this behavior occurs when you perform input-output opera- tions on process-permanent files; for example SYS$INPUT, SYS$OUTPUT, SYS$COMMAND, or SYS$ERROR. (See Section 3.2.2 and the VMS DCL Concepts Manual for more information on process-permanent files.) An input-output operation to a process-permanent file will cause most tasks in your program to wait until the input-output operation on the file is completed. Unlike the read and write operations in the other input-output packages, the GET and PUT procedures in the package TEXT_IO operate on default input and output files if you do not specify a file parameter in the procedure call. In VAX Ada, the default input and output files are represented by the logical names ADASINPUT and ADA$OUTPUT. If you do not define these logical names, the default input and output files are represented by the default system input and output logical names SYS$INPUT and SYS$OUTPUT. Input-Output Facilities 3-87 SYS$INPUT and SYS$OUTPUT are process-permanent files. Thus, if you define ADASINPUT and ADA$OUTPUT to refer to files that are not processpermanent files, your TEXT 10 GET and PUT operations will cause only the executing task to wait until the operation is completed. Conversely, if you do not define ADASINPUT and ADA$OUTPUT to refer to files that are not process-permanent files, your TEXT_IO GET and PUT operations will cause most tasks in your process to wait until the operation is completed. For example, the following commands associate ADASINPUT and ADAS$OUTPUT with TT: $ DEFINE ADASINPUT TT $ DEFINE ADASQUTPUT TT TT is a VMS default logical name that represents the terminal associated with your process (see Table 3-1); it is not a process-permanent file. Chapter 8 has an example program that uses tasks to sort an array of integers while performing terminal input-output; the program shows a situation where the association of ADASINPUT with TT allows the program to run properly. | If your program does perform input-output operations on process-permanent files, the wait for completion of an input-output operation may be interrupted if an asynchronous system trap (AST) is delivered to the VAX Ada run-time library. For example, an AST may be delivered when the time in a delay statement has expired or when time slicing is in effect. When the wait state is interrupted, tasks of higher priority than the task executing the input-output operation will be allowed to execute. If time slicing is in effect, tasks of equal priority will also be allowed to execute. See Chapter 8 for more information on delay statements, time slicing, task scheduling, and ASTs in tasking programs. 3-88 Input-Output Facilities Chapter 4 Exception Handling VAX Ada exception handling, as defined in Chapter 11 of the VAX Ada Language Reference Manual, is implemented using the routines and related VMS system services that comprise the VAX Condition Handling Facility (CHF). However, VAX Ada exception handling is implemented so that you do not need to call CHF routines and services directly. This chapter outlines how VAX Ada exception handling is related to VAX condition handling, and explains how to do exception handling in an Ada program that calls or is called from the external environment. Ada exception handling and the rules for using the VAX Ada pragmas to import and export exceptions are covered in Chapters 11 and 13 of the VAX Ada Language Reference Manual. The CHF is described in the VMS Run-Time Library Routines Volume. You should be familiar with the material in these manuals before using the information in this chapter. 4.1 Relationship Between Ada Exception Handling and VAX Condition Handling All VAX Ada exceptions are encoded as VAX condition values as follows: e Each predefined exception is encoded as a unique 32-bit condition value. e Each user-defined exception is encoded either as a unique 32-bit condition value or as the general VAX Ada condition value denoted by the name ADA$_EXCEPTION plus a signal argument that is the address of the exception name. Section 4.1.1 lists the predefined exceptions and explains the encoding and naming of exceptions in more detail. Exception Handling 4-1 Once defined, an exception can be raised. Raising generally causes the CHF procedure LIB$STOP to be called, and the exception’s condition value to be passed as one of the signal arguments. A vector of signal arguments and a vector of mechanism arguments are built, and a search is then made for an exception handler. The same sequence of events also occurs if a signaled VAX condition is propagated to an Ada program from the external environment. In VAX Ada, a general condition handler is automatically established for all stack frames that have exception handlers, and a run-time table of active exception parts is maintained for each frame. (Because blocks generally do not have their own stack frames, this condition handler is established for the subprogram, package body, or task body that contains one or more blocks with exception handlers.) The general condition handler determines which specific Ada exception handler in the frame eventually gains control (if any). Each frame on the stack is searched for a handler. When a handler is found, the stack is unwound to the handler, and execution continues from there. If no handler is found, and the exception propagates as far as it can go—to the level of a task or a main program—a VMS or VAX Ada run-time catch-all handler gains control. Catch-all handlers are located in the frames enclosing the main program and library packages, each task body, and each accept body. The catch-all handler produces a message and program execution proceeds as follows: e If an Ada exception or a VAX condition with a severity of severe reaches an Ada run-time library catch-all handler, the handler displays the exception or condition message, and then the task, main program, or rendezvous becomes completed. (However, when an exception or severe condition leaves an accept body, the message is not displayed because the exception or condition will propagate to both of the tasks involved in the rendezvous.) * If an unhandled VAX condition (not an Ada exception) with a severity of success, information, warning, or error (any severity except severe) reaches an Ada run-time library catch-all handler, the handler displays the condition message and continues program execution. This behavior is consistent with the behavior of VMS catch-all handlers. * The Ada run-time library catch-all handlers display a warning when an unhandled exception may have to wait for dependent tasks to terminate. 4-2 Exception Handling - Catch-all handler messages are sent to the output files denoted by the logical names SYS$OUTPUT and SYS$SERROR (see Chapter 3 for more information on how these names are interpreted). See the Introduction to the VMS Run-Time Library for more information about VMS default handlers. See Section 4.5 for more information on exception handling and tasks. Table 4-1 summarizes the VAX Ada implementation of exception handling. Table 4-1: Relationship Between Ada Exception Handling and the CHF Ada Exception Handling CHF Implementation Enter an Ada frame with an exception Establish the general VAX Ada condi- part.’ tion handler for the surrounding stack frame; if the general handler is already established, maintain information about currently active exception parts with a pointer to an internal VAX Ada run-time table. Raise an exception. Signal a condition with a call to ‘ LIB$STOP, or signal a hardwaregenerated condition. Invoke an exception handler. Unwind (SYS$UNWIND) to the stack frame of the Ada frame containing the exception part, and to the PC at the start of the appropriate exception handler. Re-raise the same exception. Call LIB$STOP with a copy of the signal arguments that caused invocation of the currently active exception part. Note that the SS$_RESIGNAL feature of the CHF is not used to re-raise an exception. No handler for the exception. Signal a condition with a call to LIB$SIGNAL (which may result in program continuation at the point after the signal). 1The term Ada frame refers to a frame, as defined by the Ada language: a block statement or the body of a subprogram, package, task unit, or generic unit. The term stack frame (synonymous with the term call frame) refers to a run-time VAX structure that stores information about a subprogram, package, task, or instantiated generic unit, and includes information about any contained blocks. (continued on next page) Exception Handling 4-3 Table 4-1 (Cont.): Relationship Between Ada Exception Handling and the CHF Ada Exception Handling Raise an Ada format exception.? CHF Implementation Call LIB$STOP with the condition value ADA$_EXCEPTION and one signal argument. The signal argument is the address of a counted ASCII string (ASCIC string) that is the text of the name of the exception. Raise a VMS format exception.? Call LIB$STOP with a unique 32-bit VAX condition value. 2Exceptions with an Ada format are any user-defined exceptions declared without the importexport pragmas, or any user-defined exceptions declared with the import-export pragmas that specify a value of ADA for the pragma FORM parameter. Exceptions with VMS format are any predefined exceptions or any user-defined exceptions declared with import-export pragmas that specify a value of VMS for the pragma FORM parameter. See Sections 4.1.1, 4.4.1, and 4.4.2. Note from Table 4-1 that the raising of an exception in an Ada program involves calling the CHF routine LIB$STOP. This action implements the Ada language requirement that the occurrence of an exception must terminate the current Ada frame and transfer control to an exception handler. The effect is that once an exception is raised in an Ada program, control cannot return to the point at which the exception occurred: execution is noncontinuable. See Sections 4.4.4 and 4.4.5 for a discussion of the consequences in mixed-language programs. In some cases, the exception’s signal argument vector may be copied before control is transferred to a handler. For example, if the handler re-raises the exception, the signal argument vector must be copied so that the same signal arguments can be used to raise the exception again. A copy is also needed when an exception is raised at the point of a task rendezvous (the language requires that the exception be propagated to both the called and the calling task). Section 4.1.2 describes how signal argument copying is done, and outlines some side effects. 4-4 Exception Handling 4.1.1 Naming and Encoding Ada Exceptions VAX Ada provides predefined exceptions in the packages STANDARD, I0_EXCEPTIONS, AUX_IO_EXCEPTIONS, and SYSTEM. Each predefined exception is encoded with a VMS format: a unique 32-bit VAX condition value with a symbolic name. The predefined VAX Ada exceptions have symbolic names of the following form: ADAS exception name Thus, the exception CONSTRAINT ERROR (from the package STANDARD) has the symbolic name ADA$_CONSTRAINT_ERROR, the exception DATA_ ERROR (from the package I0_EXCEPTIONS) has the symbolic name ADA$ DATA_ERROR, and so on. The predefined exceptions are listed in Table 4-2; the situations in which they are raised are described in the VAX Ada Language Reference Manual. Table 4-2: Ada Predefined Exceptions Package Exceptions STANDARD CONSTRAINT_ERROR NUMERIC_ERROR PROGRAM_ERROR STORAGE_ERROR TASKING_ERROR NON_ADA_ERROR SYSTEM I0_EXCEPTIONS STATUS_ERROR MODE_ERROR NAME_ERROR USE_ERROR DEVICE_ERROR END_ERROR DATA_ERROR LAYOUT_ERROR AUX_IO_EXCEPTIONS LOCK_ERROR EXISTENCE_ERROR KEY_ERROR Ada allows you to declare your own exceptions so that you can anticipate and handle more specific errors than those covered by the predefined exceptions. For example: INVALID INPUT : exception; Exception Handling 4-5 This declaration allows you to use the exception name INVALIDINPUT in a raise statement and as an exception choice in an Ada frame. In general, user-defined exceptions are encoded with an Ada format: they all have the same general 32-bit VAX condition value with the symbolic name ADA$ _EXCEPTION, plus an additional signal argument that makes each value unique. This signal argument is the address (32-bit) of the counted ASCII string (ASCIC string) that represents the name of the exception. (The first byte of the string contains the number of characters in the exception name; the remaining bytes contain the characters of the exception name.) The string address is assigned at link time and can change each time the program is linked. You can cause user-defined exceptions to be encoded with a VMS format by using the pragmas IMPORT_EXCEPTION and EXPORT_EXCEPTION. See Section 4.4 for more information. 4.1.2 Copying Exception Signal Arguments An exception’s signal argument vector is copied if the exception is re-raised by its handler or if the exception is raised at the point of a task rendezvous. This copying is done so that essentially the same signal arguments are used when the exception is propagated. When a signal argument vector is copied, it is marked as such by being chained to one of two special VAX Ada-specific primary condition values: * ADA$_EXCCOP, which indicates that the copy is complete * ADA$_EXCCOPLOS, which indicates that the original signal has been modified and some information may have been lost The chaining causes ADA$_EXCCOP or ADA$_EXCCOPLOS to become the primary condition in the signal argument vector. The condition that originally caused the exception to be raised then becomes the second condition value in the signal argument vector. The principal reason for chaining the VAX Ada-specific primary condition values to the copied signal argument vector is to prevent incorrect handling—such as continuation—of the original condition. Once a condition has been copied, it has an Ada semantic effect, which does not allow continuation. Information may be lost from the signal argument vector during copying if the VAX Ada run-time library suspects that the vector has an argument that points to a stack area that must be unwound to reach an exception handler. In general, the optional Formatted ASCII Output (FAO) arguments are the only part of the signal argument vector that is likely to point to such a stack 4-6 Exception Handling area. When the VAX Ada run-time library suspects that the FAO arguments point to a stack area, it zeroes the arguments. Information may be lost only for non-Ada conditions with FAO arguments. Information will not be lost in the following cases: e For Ada exceptions * For non-Ada conditions that have no FAO arguments e For hardware conditions e For RMS conditions e For VMS system service conditions Whether or not information has been lost by copying, the handling of an exception in Ada is not affected. The handling of the exception in non-Ada code is affected only if messages that depend on zeroed FAO arguments are involved; such messages are printed with embedded FAO directives (for example, !AS, UL, and so on). 4.1.3 The Matching of Ada Exceptions and System-Defined VAX Conditions In VAX Ada, the matching of exceptions to exception choices depends on the matching of the condition values assigned to the exception and the choice names. In particular, two user-defined, Ada format exceptions—exceptions encoded as ADA$_EXCEPTION plus an ASCIC string—match only if the addresses of their ASCIC strings match. If the raised exception is an imported VAX condition (see Section 4.4.1), it matches an exception choice only if the name in the exception choice matches the internal name of the imported VAX condition. Imported VAX conditions also match the exception choice others and the exception name SYSTEM.NON_ADA_ERROR (see Section 4.4.3). Some VAX conditions are treated as being equivalent to certain Ada predefined exceptions. When one of these conditions is signaled during the execution of an Ada program, the effect is as if the predefined exception were raised, and the condition can be caught by an Ada exception handler that exists to catch the predefined exception. Table 4-3 lists the VAX conditions that have Ada predefined equivalents. Exception Handling 4-7 Table 4-3: VAX Conditions that Match Ada Exceptions Condition Name SS$_INTDIV Meaning Exception Name Integer divide by zero CONSTRAINT_ERROR trap SS$_FLTDIV Floating/decimal divide CONSTRAINT_ERROR by zero trap SS$_FLTDIV_F Floating divide by zero CONSTRAINT_ERROR fault SS$_INTOVF Integer overflow trap CONSTRAINT_ERROR SS$_FLTOVF Floating overflow trap CONSTRAINT_ERROR SS$_FLTOVF_F Floating overflow fault CONSTRAINT_ERROR Note that these VAX conditions match CONSTRAINT_ERROR, but are not converted to CONSTRAINT _ERROR. If one of them is signaled and propagates out of a main program, the result is an informational message identifying the event as a CONSTRAINT _ERROR (that is, you could have caught it with a CONSTRAINT_ERROR handler), as well as the error message and traceback associated with the actual condition. 4.2 Making the Best Use of Ada Exception Handling To make the best use of Ada exception handling, keep these two principles in mind: * Code handlers for specific exceptions. In particular, do not use a general others handler when you could write an explicit handler for a specific exception. e Allow unexpected exceptions to propagate, instead of being absorbed. For example, if you use an others choice to handle the predefined inputoutput exception END_ERROR, the handler will also be invoked for any unexpected exception, such as “disk quota exceeded.” A better solution would be to provide a specific handler for END_ERROR, and allow unexpected exceptions to propagate, thereby making them visible. Similarly, the following construct absorbs all exceptions without allowing them to propagate and without issuing a message: when others => null; Such a statement is unlikely to be able to handle all possible exceptions and recover correctly. 4-8 Exception Handling To ensure that unexpected exceptions do propagate and become visible, end your others exception choices with a raise statement. For example: begin ~— Sequence of statements for a block. exception when SINGULAR | CONSTRAINT ERROR => PUT (" MATRIX IS SINGULAR "); when others => —-— Perform some cleanup operations. raise; end; Here, if an exception other than SINGULAR or CONSTRAINT_ERROR is raised, the when others handler gains control, and the exception will be re-raised in the containing frame. 4.3 Suppressing Checks In accordance with the language definition, VAX Ada provides a set of runtime checks that underlie the predefined exceptions. The VAX Ada Language Reference Manual explains each check that the compiler performs and gives the corresponding exceptions that can arise. Table 4-4 summarizes this correspondence. Table 4-4: Run-Time Checks and Their Corresponding Predefined Exceptions Check Predefined Exception Raised ACCESS_CHECK CONSTRAINT_ERROR DISCRIMINANT_CHECK INDEX_CHECK LENGTH_CHECK RANGE_CHECK DIVISION_CHECK CONSTRAINT_ERROR ELABORATION_CHECK PROGRAM_ERROR STORAGE_CHECK STORAGE_ERROR OVERFLOW_CHECK Exception Handling 4-9 Example 4-1: Use of Pragma SUPPRESS ALL with TEXT use with INTEGER_TEXT IO; use IO; procedure MAIN procedure TEXT IO; INTEGER TEXT IO; is A is begin —— Checks —— suppressed —— Checks —-— suppressed in —— Checks not -—- suppressed are not in A. end; procedure B procedure is C separate; is separate; are are B. in C. to here. begin B; —-—- Exception —— propagated B exception when NUMERIC ERROR | CONSTRAINT ERROR PUT_ LINE ("Division by zero -- W . => propagated up!"); end MAIN; TR PTG D U S T — —— —— T —— . — separate (MAIN) procedure B — — —— — —— —_— O W S - — T — — . Vo — di St . W S —— — owadn S Wi Wb ey . s is A: INTEGER := 1; I: INTEGER := 0; begin A := A/I; PUT (A) ; —-— Exception -— to —— raised, —— SUPPRESS ALL -— specified. corresponding DIVISION CHECK even 1is though is end B; pragma I S G G S S SUPPRESS — —— B . S— A separate (MAIN) procedure C begin end C; 4-10 - Exception Handling is ALL; Wy a— — v — — — ——— G e G S T e W S——— —— Pragma —— unit -—- it — . S e to must follow the which applies. o — — — — — To suppress checks, you can use the pragmas SUPPRESS and SUPPRESS_ ALL (see the VAX Ada Language Reference Manual), or you can use the /NOCHECK qualifier on the ADA and ACS COMPILE and RECOMPILE commands (see Developing Ada Programs on VMS Systems). NOTE When you suppress checks, your program may become erroneous. For example, if you suppress checks in a library unit or subunit that contains a number of arrays, you will suppress INDEX _ CHECK, but array processing will continue, whether or not you exceed the specified ranges. The results of that unit or subunit will be unpredictable. If you are using the pragmas SUPPRESS or SUPPRESS_ALL of the /NOCHECK qualifier to improve the runtime performance of your program, consider using the techniques for eliminating checks discussed in Chapter 9. The presence of the pragmas SUPPRESS or SUPPRESS_ALL or the use of the /NOCHECK qualifier does not guarantee that exceptions will not be raised. For example, certain checks are not suppressed in VAX Ada. These checks are the hardware checks DIVISION_CHECK and OVERFLOW_ CHECK (for floating-point types), where the hardware catches the error and passes control directly to the operating system. STORAGE_CHECK is also not suppressed (except for stack checks). Thus, an exception may be propagated from a called unit in which the corresponding check was suppressed; the predefined exception corresponding to DIVISION_CHECK is propagated from subunit B to MAIN_EXCEPTIONS in Example 4-1. 4.4 Mixed-Language Exception Handling VAX Ada provides the pragmas IMPORT_EXCEPTION and EXPORT_ EXCEPTION for use in a mixed-language programming environment: e The pragma IMPORT EXCEPTION allows you to import an exception declared in a non-Ada program and handle it within your Ada program. * The pragma EXPORT_EXCEPTION allows you to export an Ada exception so that it can be treated as a VAX condition in a non-Ada program. VAX Ada also provides specific facilities for signaling and handling VAX conditions in the VMS environment: the function SYSTEM.IMPORT_ VALUE, the package CONDITION_HANDLING, and the package STARLET. The following sections explain how to use these features. Exception Handling 4-11 For information on testing status values returned by VMS system routines, see Chapter 6. 4.4.1 Importing Exceptions The pragma IMPORT_EXCEPTION associates an Ada exception name with either a VAX condition value or another Ada exception name—both external to your program—and then allows you to use that name in your Ada program. The full syntax and usage rules for this pragma are given in Chapter 13 of the VAX Ada Language Reference Manual. The syntax is summarized here for convenience: pragma IMPORT EXCEPTION (internal name [, external designator] [, [FORM => ] ADA [, [CODE => ] static_integer expression]); ::= [INTERNAL] internal_name simple name | VMS] => simple name ::= identifier external designator ::= external symbol identifier ::= [EXTERNAL] | => external symbol string literal You can use the pragma IMPORT EXCEPTION to associate an Ada exception name with either a numeric condition value or a global symbol that denotes a VAX condition: the CODE parameter represents a numeric condition value, and the external designator represents a global symbol. You can specify the format of the exception with the FORM parameter (see Section 4.1.1 for definitions of Ada and VMS formats; the format for im- ported exceptions is VMS by default). You can raise an imported exception with a raise statement and handle it with an Ada exception handler that names the exception. In the following example, the procedure QUADRATIC_FORMULA computes and prints the real roots of a quadratic equation. The procedure imports the VAX condition MTH$_SQUROONEG; the pragma IMPORT_EXCEPTION assoclates the exception name SQRT NEGATIVE with the VAX condition MTHS$_SQUROONESG. If the call to the SQRT function in the procedure QUADRATIC_FORMULA attempts to compute the square root of a negative number, the exception SQRT _NEGATIVE is raised. Control then transfers to the exception handler, which completes execution of the procedure by printing a message. 4-12 Exception Handling with FLOAT TEXT I0; with FLOAT use FLOAT TEXT IO; MATH LIB; —-— These packages —-— for with use FLOAT MATH LIB; are predefined by VAX Ada convenience. TEXT IO; use TEXT IO; procedure QUADRATIC FORMULA A, B, C, D : FLOAT; SOQRT NEGATIVE pragma is : exception; IMPORT EXCEPTION ( SQRT NEGATIVE, —— Internal name. "MTHS$ SQUROONEG"); -- External designator. —— By -— VMS default use format. begin GET (A); D := GET (B); SQRT(B**2 PUT ("Real GET(C); - Roots 4.0*A*C);—-- : X1 = Exception will -— raised here —— B**2 -— 18 4 — be if 4 0*A*C » negative, "); PUT((-B - D)/ (2.0*1)); PUT(" X2 = "); PUT((-B + D)/ (2.0%*A7)); exception when SQRT NEGATIVE => PUT LINE ("Imaginary Roots."); end QUADRATIC FORMULA; The next example is a declaration that shows how you can import the VAX condition SS$_ACCVIO using its numeric code. No external symbol is referenced in this case (it is illegal if the code option is specified). Because it is the default, the VMS format will be used (the VMS format is the required format for importing VAX conditions). SS _ACCVIO pragma : exception; IMPORT EXCEPTION ( SS_ACCVIO, —— CODE => -- Numeric condition value. 16#0C#); Internal name. You can give a VAX condition value to an Ada exception by first defining a message symbol condition with the VAX Message Utility (see the VMS Message Utility Manual), and then using IMPORT_EXCEPTION to associate the Ada exception name with the message symbol. For example: Exception Handling 4-13 NEW VMS pragma : exception; IMPORT EXCEPTION NEW_VMS, "MSG$ ERRORS", ( -— Internal name. -— External designator of a message -— defined with the VAX Message FORM => VMS) ; —-— Explicitly specify VMS symbol Utility. format. Sections 4.4.4 and 4.4.5 provide additional discussion and examples of importing and handling VAX conditions in the VMS environment. 4.4.2 Exporting Exceptions The pragma EXPORT_EXCEPTION associates an Ada exception with either a VAX condition value or another Ada exception name, and then allows you to use that name in the external environment. The full syntax and usage rules for this pragma are given in Chapter 13 of the VAX Ada Language Reference Manual. The syntax is summarized here for convenience: pragma EXPORT EXCEPTION (internal name [, external designator] [, [FORM => ] ADA [, [CODE ] static integer expression]); internal name simple name => ::= ::= | VMS [INTERNAL] ] => simple name identifier external_ designator ::= external_ symbol identifier ::= [EXTERNAL] | => external symbol string literal If you export a VMS format exception (see Section 4.1.1) to a non-Ada routine, that routine can treat the exception as an ordinary VAX condition. In other words, the routine can process the exception using its own condition- handling mechanisms (for example, with ON units if the routine is written in PI/I, or with LIBSESTABLISH if the routine is written in FORTRAN). If you export an Ada format exception (see Section 4.1.1), the external designator becomes a global symbol, which is the address of the exception’s ASCIC string name. Because an exception with the Ada format is unique only in the address of its ASCIC string, any non-Ada routine to which such an exception is exported must examine the exception’s signal arguments to determine a match. Similarly, any non-Ada routine to which an Ada format exception is propagated must determine if the primary condition is ADA$_EXCEPTION, and, if so, must examine the exception’s first FAQ signal argument to determine if the argument matches the value of the external designator. 4-14 Exception Handling The following examples show how to declare Ada and VMS format excep- tions, so that they can be exported to the external environment: ADA ERROR pragma : exception; EXPORT EXCEPTION (ADA ERROR, —-— Internal name. "MY PACKAGE ADA", -—- External designator. FORM => -— Ada —— Internal VMS ERROR pragma : ADA); exception; EXPORT EXCEPTION (VMS ERROR, 4.4.3 format. name. "MY PACKAGE ADA", -— External designator. FORM => VMS, -- CODE => 16#8018004#); -- VAX condition value. The Exception Choice VMS format. NON ADAERROR To allow you to treat non-Ada conditions as a special subclass of Ada exceptions, VAX Ada provides the exception choice NON_ADA_ERROR in the package SYSTEM. NON_ADA_ERROR matches itself and any VAX condition whose facility field is not ADA. It is encoded as a predefined exception with the unique condition value ADA$_NON_ADA_ERROR. NON_ADA_ERROR also matches Ada exceptions for which the pragma IMPORT_EXCEPTION or EXPORT _EXCEPTION is given and for which the VMS format has been specified. 4.4.4 Signaling VAX Conditions VAX Ada provides two ways to signal a VAX condition from an Ada program: ¢ Import the condition using the pragma IMPORT_EXCEPTION and use an Ada raise statement to raise the imported exception. e Signal the condition directly, using a form of the VMS Run-Time Library routine LIB$SIGNAL or LIB$STOP. The VAX Ada package CONDITION_HANDLING provides the procedures SIGNAL and STOP for this purpose. When you import a condition and signal it with an Ada raise statement, the condition behaves like an Ada exception, according to Ada semantics. Consequently, you can handle it with an Ada exception handler, but regardless of the condition’s severity, the signal is noncontinuable. Exception Handling 4-15 For example, the Ada subprogram in Example 4-2 calls the system ser- vice SYS$GETJIPIW, which returns information about one or more VMS processes. When the condition SS$_NONEXPR occurs in Example 4-2, SYS$GETJPIW returns the appropriate warning status. However, because SS$_NONEXPR is imported and treated as an Ada exception, its severity becomes severe. Because an Ada exception handler exists for the exception SS_NONEXPR, control passes to the handler. Example 4-2: Handling SYS$GETJPIW Status Values as Ada Exceptions with SYSTEM; use SYSTEM; with CONDITION_HANDLING; with STARLET; use with TEXT use TEXT with IO; use CONDITION HANDLING; STARLET; INTEGER TEXT IO; IO; use INTEGER TEXT IO; procedure GETJPI ADA is -— Declare —-— some the variables needed to make the call and print results. JPI_STATUS : COND PID : UNSIGNED : ADDRESS ADDRESS PIDADR VALUE TYPE; LONGWORD := IOSB_VALUE : IOSB_TYPE; ACCOUNT : STRING(1..8); DFPFC : INTEGER; FREPOVA : INTEGER; FREP1VA : INTEGER; FREPTECNT : INTEGER; GPGCNT : INTEGER; JPI_ITEM LIST : constant := 2; PID ADDRESS'ADDRESS; ITEM LIST TYPE := ((8, JPI_ACCOUNT, ACCOUNT’ADDRESS, DFPFC’ ADDRESS, ADDRESS_ZERO) , (4, JPI_FREPOVA, FREPOVA’'ADDRESS, ADDRESS (4, JPI_FREP1VA, FREP1VA’ADDRESS, ADDRESS ZERO), (4, JPI_FREPTECNT, (0, 0, (4, JPI_DFPFC, (4, JPI_GPGCNT, FREPTECNT’ADDRESS, GPGCNT’ ADDRESS, ADDRESS ZERO, ADDRESS_ZERO), ZERO), ADDRESS ZERO), ADDRESS_ZERO), ADDRESS ZERO)); (continued on next page) 4-16 Exception Handling Example 4-2 (Cont.): Handling SYS$GETJPIW Status Values as Ada Exceptions -— Declare the possible errors as Ada exceptions. — — NONEXPR: pragma exception; IMPORT_EXCEPTION(NONEXPR,"SS$_NONEXPR"); NOPRIV : pragma IMPORT EXCEPTION (NOPRIV, exception; "SS$_NOPRIV"); —— Print out the wvalues returned in the item list. procedure PRINT RESULTS is begin PUT_LINE("Account = " PUT ("Default page fault & ACCOUNT) ; cluster size ="); PUT (DFPFC) ; NEW LINE; PUT LINE ("First PUT ("page free program region"); address (PO) ="); PUT (FREPOVA) ; NEW LINE; end PRINT RESULTS; begin —— Call SYSSGETJPIW using the GETJPIW (STATUS => ITMLST => not from the package STARLET. JPI STATUS, PIDADR => PIDADR, JpI1I ITEM LIST, IOSB IOSB _VALUE) ; ——- Check the result -— interface status; => raise exceptions if the result is normal. if JPI STATUS = SS NORMAL then PRINT RESULTS; else if JPI_STATUS = SS_NONEXPR then raise NONEXPR; end if; end if; (continued on next page) Exception Handling 4-17 Example 4-2 (Cont.): —— Handle the Handling SYS$GETJPIW Status Values as Ada Exceptions exceptions. exception when NONEXPR => PUT LINE ("Nonexistent when NOPRIV process"); => PUT LINE("Insufficient privileges"); end GETJPI ADA; When you signal a condition using the CONDITION_HANDLING.SIGNAL procedure (or another Ada equivalent to the VMS Run-Time Library LIB$SIGNAL routine), the condition behaves like a VAX condition, according to CHF rules. If the condition’s severity is not severe (error, warning, or informational), then the signal is continuable. Example 4-3 rewrites Example 4-2 to achieve this effect. In Example 4-3, CONDITION_ HANDLING.SIGNAL is used so that the warning status of the NONEXPR condition is preserved and continuation occurs. 4-18 Exception Handling Example 4-3: with Handling SYS$GETJPIW Status Values as VMS Conditions use SYSTEM; SYSTEM; use CONDITION_ HANDLING; with CONDITION HANDLING; STARLET; use STARLET; with TEXT IO; use TEXT IO; with with INTEGER TEXT IO; use INTEGER_TEXT_IO; procedure GETJPI VMS is -- Declare the variables needed to make the call and print —— some results. JPI_STATUS : COND VALUE TYPE; PID ADDRESS PIDADR : UNSIGNED LONGWORD : ADDRESS IOSB_VALUE : IOSB TYPE; ACCOUNT : STRING(1l..8); DFPFC : INTEGER; FREPOVA : INTEGER; FREP1VA : INTEGER; FREPTECNT : INTEGER; GPGCNT : INTEGER; JPI_ITEM LIST ((8, (4, (4, : := 2; := PID ADDRESS’ADDRESS; constant ITEM LIST TYPE := JpPI_ ACCOUNT, JPI _DFPFC, JPI FREPOVA, ACCOUNT' ADDRESS, DFPFC’ ADDRESS, FREPOVA’ ADDRESS, (4, (4, (4, JPI FREP1VA, JPI_FREPTECNT, JpI_GPGCNT, FREP1VA'’ADDRESS, FREPTECNT'’ADDRESS, GPGCNT'’ ADDRESS, (0, 0, —— Print ADDRESS ZERO, ADDRESS ZERO)) ; out the values returned in the procedure PRINT RESULTS begin PUT LINE ("Account PUT ("Default page ADDRESS ZERO), ADDRESS ZERO), ADDRESS ZERO), ADDRESS ZERO), ADDRESS ZERO), ADDRESS ZERO), item list. is = " fault & ACCOUNT) ; cluster size ="); PUT (DFPFC) ; NEW LINE; PUT LINE ("First free program region"); PUT ("page address (PO) ="); ; PUT (FREPOVA) NEW LINE; end PRINT RESULTS; (continued on next page) Exception Handling 4-19 Example 4-3 (Cont.): Handling SYS$GETJPIW Status Values as VMS Conditions begin —— Call SYSSGETJPIW using the interface from the package GETJPIW (STATUS => JPI STATUS, PIDADR => PIDADR, ITMLST => JPI_ITEM IOSB => I0SB _VALUE) ; —— if Check the result JPI STATUS PRINT = status; LIST, signal if the result is not STARLET. normal. SS NORMAL then RESULTS; else —— SS_NONEXPR -~ execution ——- and —— current if JPI call has can a status continue. GETJPIW process STATUS = again, is of warning; after it In this case, so information that change is signaled, the PID about value the returned. SS NONEXPR then SIGNAL(SS_NONEXPR); PIDADR := ADDRESS ZERO; GETJPIW (STATUS => JPI STATUS, PIDADR => PIDADR, ITMLST => JPI_ITEM~LIST, IOSB => IOSB_VALUE); PRINT RESULTS; end if; end if; end GETJPI VMS; If, in Example 4-3, you were to use the CONDITION _HANDLING.STOP procedure (or another Ada equivalent to the VMS Run-Time Library LIB$STOP routine), the effect would be identical to the effect of an Ada raise statement. Continuation would not occur. In any case, when working in a mixed-language environment with Ada subprograms, do not depend on the severity of a particular status value. Any Ada exception or VAX condition that is raised becomes severe, and is beyond the control of the code that originally signaled it. 4-20 Exception Handling 4.4.5 Effects of Handling VAX Conditions from an Ada Program If an Ada subprogram handles a VAX condition that is signaled and/or propagated from an external routine, the handler causes the signal to behave according to Ada semantics. This rule affects the use of certain VAX RunTime Library fault handlers in a program that calls Ada subprograms (see Section 4.4.6), and it has the following consequences in any mixed-language program: e An Ada subprogram that does not contain any exception handlers (which name the raised exception) is transparent to the CHF when a VAX condition is signaled. * A VAX condition that is handled by an Ada handler is converted to a noncontinuable exception. Thus, when programming in more than one language, be careful about using general or global condition handlers. In the Ada portions of your program, use the following handling mechanisms carefully, because all of them catch VAX conditions: * The exception choice others—catches any VAX condition or Ada exception that does not have an explicit handler * The VAX Ada predefined exception SYSTEM.NON_ADA_ERROR— catches all VAX conditions (see Section 4.4.3) * Predefined Ada exceptions that match VAX conditions (see Section 4.1.3) NOTE The exception choice others does not catch the following VAX conditions: SS$_DEBUG SS$_UNWIND These two VAX conditions are used to implement the VAX Ada run-time environment, and are never caught by an Ada exception handler. Even if you import one of these conditions and name it in an Ada exception handler, the handler is never invoked to respond to the condition. For each subprogram that you write, anticipate the errors that can occur, and explicitly name each possible error in an exception handler. In addition, make sure you understand the behavior of a subprogram (and the main program) if you are adding it to an existing application. Exception Handling 4-21 For example, consider the following situation: * A FORTRAN program P1_FOR calls an Ada subprogram P2_ADA. * The Ada subprogram calls another FORTRAN program, P3_FOR. In this situation, P3_FOR could signal a condition, and P1_FOR could handle the condition and continue the execution of P3_FOR. Because it did not handle the condition, P2_ADA would be unaffected. From the Ada subprogram’s point of view, the condition would never have happened. Alternatively, consider the following situation. You have a working FORTRAN program, called FORTRAN_MAIN, for which you have en- abled underflow conditions at compile time (see the VAX FORTRAN User’s Guide). A default FORTRAN (FOR$UNDERFLOW_HANDLER) is established at the level of the main program to process any underflow conditions that arise. In other words, when an operation in the program underflows and the condition is not processed by another handler, FOR$UNDERFLOW_ HANDLER assumes control. This handler keeps a count of the number of underflow conditions and continues execution from the point of the signal. FORTRAN_MAIN calls several routines, including a FORTRAN subroutine named FOR_ROUT. Figure 4-1 shows the call frames for these routines; the circled numbers indicate the order of execution. If an underflow condition is signaled in FOR_ROUT, FOR$UNDERFLOW_HANDLER gains control, processes the condition, and continues execution of FOR_ROUT. 4-22 Exception Handling Figure 4-1: Execution of a FORTRAN Program with FOR$UNDERFLOW_HANDLER FORSUNDERFLOW_HANDLER PROGRAM FORTRAN_MAIN @) CALL FOR_ROUT END SUBROUTINE FOR_ROUT @ v v X=Y/Z= underflow next statement ) signaled END ZK-3022-GE Now suppose that when enhancing the program, you add a call to an Ada subprogram called ADA_ROUT, which contains an exception handler with the exception choice others. You set the program up so that FORTRAN_ MAIN calls ADA_ROUT, and ADA_ROUT calls FOR_ROUT. Figure 4-2 shows the calling sequence for this series of routines. If FOR_ROUT signals underflow, the handler in ADA_ROUT gains control and converts the condition to a noncontinuable exception. If the handler in ADA_ROUT does not re-raise the exception, execution resumes in FORTRAN_MAIN at the statement after the call to ADA_ ROUT. FOR_ROUT does not continue executing, which was the original intent. If the Ada handler re-raises the exception, the exception is prop- agated to FORTRAN_MAIN and FOR$UNDERFLOW_HANDLER. When FOR$UNDERFLOW_HANDLER attempts to continue from a noncontinuable exception, the result is a fatal error and execution terminates. Exception Handling 4-23 Figure 4-2: The Effect of an Ada Procedure Containing an Others Handler FOR$UNDERFLOW_HANDLER mmmmmmmmmmmmmmmmmm T T mmmn e meem oem e ‘—l | PROGRAM FORTRAN_MAIN EXTERNAL ADA_ROUT | l o I : | CALL ADA_ROUT END procedure ADA_ROUT is e pragma IMPORT_PROCEDURE (FOR_ROUT); FOR_ROUT; @ exception when others => 0 enci;' - SUBROUTINE FOR_RoUT @ v . X=Y/Z= next statement underflow signaled END ZK-3023-GE There are two flaws in this example: * The global error handler, which causes the underflow condition to propagate through the Ada subprogram, instead of remaining local to FOR_ROUT * The others choice in the Ada subprogram, which catches a VAX condi- tion it never intended to catch 4-24 Exception Handling One solution for improving this example is to use VMS Run-Time Library calls to explicitly establish FORSUNDERFLOW_HANDLER in the places where you want to handle underflow. Figure 4-3 shows a repaired version of the FORTRAN program, which instead establishes FOR$UNDERFLOW_ HANDLER for the subroutine FOR_ROUT. Then, when underflow is signaled in FOR_ROUT, the handler gains control, processes the condition, and continues execution of FOR_ROUT. The signal is never propagated to the Ada procedure ADA_ROUT. 4.4.6 Fault Handlers Fault handlers are usually established as catch-all stack handlers, or they are called from condition handlers (such as the VMS Run-Time Library routine LIB$DECODE_FAULT); they need the signal information generated at the time the fault occurred in order to execute properly. Because VAX Ada exception handling involves unwinding the stack frame to the start of the handler, signal information is lost when an exception is handled in Ada (the saved signal arguments described in Section 4.1.2 are accessible only to the Ada run-time library and not to the underlying CHF routines). Thus, you cannot do the following: e e Establish a fault handler in Ada. (Call a VMS Run-Time Library fault handler from an Ada exception part (even if the handler is imported with the pragma IMPORT _ PROCEDURE or using the package STARLET). e (Catch a fault in an Ada program when that program has called a procedure in another language, and then continue from the point of the fault. The only way to set up a fault handler in Ada is to use the VMS vectored exception mechanism. In other words, you must call the system service SYS$SETEXV to assign the address of a fault handler to the primary or secondary exception vector. Because the CHF looks for a handler in the primary and secondary exception vectors before it looks for a handler in an Ada frame, the vectored fault handler gains control before the search for an Ada handler can begin. The fault handler then processes the fault, and the fault is dismissed before it can ever be propagated to an Ada handler. Exception Handling 4-25 Figure 4-3: FOR$UNDERFLOW _ HANDLER Established for a FORTRAN Subroutine PROGRAM FORTRAN_MAIN () EXTERNAL ADA_ROUT CALL ADA_ROUT END procedure ADA_ROUT is @ pragma IMPORT PROCEDURE (FOR_ROUT); FOR_ROUT; @ exception 'v&fien others => FORSUNDERFLOW_HANDLER SUBROUTINE FOR_ROUT @) EXTERNAL FORSUNDERFLOW_HANDLER CALL LIBSESTABLISH (FOR$UNDERFLOW_HANDLER) e+ O next statement e v @ END ZK-3024-GE See Chapter 6 of this manual for information on how to call system services, and see the Introduction to the VMS Run-Time Library for an explanation of exception vectors. 4-26 Exception Handling 4.5 Exceptions and Tasking Exception handling in VAX Ada interacts with tasking in several ways. First, the Ada language requires that an unhandled exception terminate the task in which it is raised or to which it is propagated. When this situation occurs in a VAX Ada program, the VAX Ada run-time library displays the exception message to warn you that the task is terminating. You can also use the VMS Debugger to diagnose this situation (see Developing Ada Programs on VMS Systems). NOTE If you do not want your software to produce task termination messages, you should include exception handlers in those task bodies to which you expect unhandled exceptions to propagate. For example, if you expect that the user-defined exception ALL_DONE will normally cause task termination messages in one of your tasks, you should include the following code (or its equivalent) in the exception part of the affected task body: when ALL DONE => null; The handler absorbs the exception and prevents it from propagating further. The handler also allows a reader of your code to infer that the termination resulting from this exception is to be expected. Second, as required by the Ada language, the propagation of an exception from an Ada frame must await the termination of all tasks that depend on that frame. If a dependent task never terminates, then the exception is never propagated. You can avoid this situation as follows: * By coding an exception handler to call an entry in the task that causes the task to terminate * By making sure that the task will eventually reach a select statement with an open terminate alternative * By using an abort statement (use of the abort statement is not recom- mended except as a last resort; see Section 8.4.5 for a more complete discussion) Exception Handling 4-27 To help you diagnose this situation, the task termination messages displayed by the Ada run-time library appear when waiting begins for dependent tasks. You can also use the VMS Debugger to diagnose situations in which an exception may wait forever for a dependent task (see Developing Ada Programs on VMS Systems). Third, VAX Ada requires that tasks declared in a library package or defined by an access type declared in a library package be terminated before execution is returned to the VMS DCL command interpreter. This additional VAX Ada requirement (which is formally supported by Ada language interpretation AI-00399) means that such tasks are guaranteed to reach one of the language-defined points at which task termination can occur. A consequence of this rule is that propagation of an exception out of the frame of the main program does not occur until all tasks declared in library packages terminate. After all such tasks have terminated, the exception is propagated to a VMS default handler (see Section 4.1). In cases where such a task fails to terminate, you can use the VMS Debugger to diagnose the problem (see Developing Ada Programs on VMS Systems). Fourth, the Ada language requires that exceptions propagating from an accept statement propagate in the calling task as well as in the called task. To implement this requirement, VAX Ada copies the signal arguments from the called task to the calling task. This copy operation is identical to the copying that occurs when an exception is going to be re-raised (see Section 4.1.2). In particular, the copied exception has a different primary condition, either ADA$_EXCCOP or ADA$_EXCCOPLOS, and some information in the signal arguments may have been lost (zeroed). 4-28 Exception Handling Chapter 5 Mixed-Language Programming All native-mode VAX languages, including VAX Ada, conform to a set of econventions—the VAX Procedure Calling and Condition Handling Standard—that determine how routines are entered and exited, how parameters are passed, and how function results are returned. By conforming to this standard, VAX Ada allows calls from Ada subprograms to external routines and vice versa (external routines are routines that are not part of the Ada program; for example, they can be written in another language). This chapter explains how to accomplish mixed-language programming with VAX Ada. The full text of the VAX Procedure Calling and Condition Handling Standard is in the VMS manual, Introduction to VMS System Routines. See Chapter 13 of the VAX Ada Language Reference Manual for the syntax and usage rules for the VAX Ada pragmas that support mixed-language programming; see Chapter 6 of the VAX Ada Language Reference Manual for the Ada semantics rules for subprogram calls. You should be familiar with the material in these two manuals before using the information in this chapter. The calling of system routines and other callable utilities and tools is a specific example of mixed-language programming. See Chapter 6 for more information on that topic. NOTE The calling standard uses the term procedure to mean any routine entered by a VAX CALL instruction. To avoid confusion with Ada’s definition of a procedure, this manual uses the term routine. Mixed-Language Programming 5-1 9.1 Calling External Routines from Ada Subprograms You call an external routine from an Ada program by first writing an Ada specification for the routine. To indicate that the routine body is not part of the Ada program, you must give the predefined pragma INTERFACE with the Ada specification. You should also give one of the VAX Ada 1mport pragmas (IMPORT_FUNCTION, IMPORT_PROCEDURE, or IMPORT _ VALUED_PROCEDURE) and fully specify all of the parameter-passing and function result mechanisms. The syntax and rules for using the pragma INTERFACE and the VAX Ada import pragmas are described in detail in Chapter 13 of the VAX Ada Language Reference Manual. For convenience, the syntax is summarized here (note that the VAX Ada compiler ignores the language name in the pragma INTERFACE): pragma INTERFACE pragma IMPORT | (language name, FUNCTION IMPORT_PROCEDURE (internal_name | IMPORT_VALUED PROCEDURE external =>] [, (parameter types) ] [RESULT TYPE =>] type mark] [, [MECHANISM [, [RESULT MECHANISM =>] —— IMPORT FUNCTION for for IMPORT FUNCTION =>] :: [INTERNAL = =>] mechanism name] only [INTERNAL =>] designator ::= external symbol ::= identifier ::= null parameter types mechanism ::= (mechanism name DESCRIPTOR ::= Mixed-Language Programming simple name [EXTERNAL | type identifier]): | -- Can —— IMPORT FUNCTION =>] external string mark only be {, literal type {, mark} mechanism name}) ::= VALUE [ ([CLASS UBS | UBSB | REFERENCE =>] | class-name) ] UBA | S | SB | A | used symbol mechanism name mechanism name class_name =>] operator_ symbol external | only mechanism] [FIRST OPTIONAL PARAMETER internal name | designator] [PARAMETER TYPES [, 9—2 [, [, —— | subprogram name) ; NCA for For example, the following Ada program imports a routine written in VAX Pascal and uses the MECHANISM option to specify the DESCRIPTOR mechanism for its parameter: procedure SIMPLE IMPORT is procedure PRINT STRING (S : STRING); pragma INTERFACE (PASCAL, PRINT STRING); pragma IMPORT PROCEDURE INTERNAL PARAMETER TYPES => => MECHANISM STR: ( => PRINT_ STRING, STRING(1l..8) (STRING), (DESCRIPTOR(CLASS=>A))); := "Surprise"; begin PRINT STRING (STR) ; end SIMPLE IMPORT; — e —— — — — - G A G TR UM I S S WD D SRR WA MODULE Print String Module G MR SN A S S S D WD G Ges Gl WA GEED GUW G S — G D GRS W S U S GRS ——— — — — (OUTPUT) ; [GLOBAL] PROCEDURE Print String (S: PACKED ARRAY[L1l..V1l: OF INTEGER] ; CHAR) BEGIN WRITELN(S) ; END; END. Once you have coded the Ada specification and the routine to be imported, you compile them using the appropriate compilers (VAX Ada and VAX Pascal, in this case). Then, you link them using the ACS LINK command, and run them using the DCL RUN command. For example: $ ADA SIMPLE IMPORT $ PASCAL PRINT STRING_ MODULE $ ACS LINK SIMPLE IMPORT PRINT STRING MODULE $ RUN SIMPLE IMPORT See Developing Ada Programs on VMS Systems for more information on linking mixed-language programs. When calling an external routine, you must ensure that any parameters or function results are passed with the passing mechanism required by the language in which the routine is written. Each VAX language, VMS routine, and callable utility or tool has default conventions that determine how parameters must be passed and function results returned. The VAX language, VMS, and callable utility or tool documentation provides that information. Mixed-Language Programming 5-3 To determine which mechanisms the VAX Ada compiler has cho- sen for the parameters in an Ada subprogram, you can use the /WARNING=COMPILATION_NOTES qualifier with any of the Ada compilation commands to determine which mechanisms the compiler has chosen. For example: $ ADA/WARNINGS=COMPILATION_NOTES CALL FORTRAN 2 procedure COMPARE (X,Y: INTEGER) ; .............................. 1 51, (1) Selected/specified passing mechanism is REFERENCE ................................ 2 However, to ensure that the correct passing mechanism is used for each pa- rameter of an external routine, you should explicitly specify each mechanism rather than depending on the compiler-chosen default mechanisms. See Section 5.4 for more information on the default passing mechanisms chosen by the VAX Ada compiler. See Section 5.6 for more information on how to control the passing mechanisms for imported subprogram parameters. 9.2 Calling Ada Subprograms from External Routines You call an Ada subprogram from a external routine by first writing the specification and body for the Ada subprogram. To indicate that the subprogram will be called from a external routine, you must also give one of the VAX Ada export pragmas (EXPORT _FUNCTION, EXPORT _ PROCEDURE, or EXPORT_VALUED_PROCEDURE). The syntax and rules for using the VAX Ada export pragmas are described in detail in Chapter 13 of the VAX Ada Language Reference Manual. For convenience, the syntax is summarized here: pragma | EXPORT FUNCTION EXPORT PROCEDURE (internal_name 5-4 [, | EXPORT_VALUED PROCEDURE external designator] [, [PARAMETER TYPES =>] (parameter types) ] [, [RESULT TYPE =>] type mark]); EXPORT FUNCTION only = simple name —— for internal name :: external designator [INTERNAL ::= =>] [EXTERNAL external symbol ::= identifier parameter types ::= null Mixed-Language Programming | type | =>] external string mark ({, symbol literal type mark} For example, the following VAX Ada subprogram (SWAP) is exported, and then is called from a VAX Pascal main program (Use_swap): procedure TEMP: SWAP (A,B: in out INTEGER) is INTEGER; begin TEMP := A := B; A; B := TEMP; end; pragma — W W — EXPORT A T PROGRAM U — — PROCEDURE — W ) Use swap S— — e — — o (SWAP) ; —— —— — ——— T — o — — — — — — — — — —— u—— o— — — (INPUT,OUTPUT); vVar X,Y: INTEGER; PROCEDURE Swap (VAR Swapl, Swap2: INTEGER); EXTERNAL; Begin (* Give X and Y values ¥*) SWAP (X, Y); End. Alternatively, the procedure SWAP could be exported from an Ada package, as follows: package SWAP ROUTINES procedure pragma end SWAP is (A,B: in out EXPORT PROCEDURE INTEGER); (SWAP) ; SWAP ROUTINES; package body SWAP ROUTINES procedure TEMP: SWAP (A,B: is in out INTEGER) is INTEGER; begin TEMP := A := B; A; B := TEMP; end; end SWAP ROUTINES; When you export an Ada subprogram, you must use the ACS EXPORT command to prepare the subprogram for linking. For example: S ADA $ PASCAL SWAP $ ACS $ LINK USE SWAP EXPORT SWAP USE SWAP, SWAP Mixed-Language Programming 5-5 See Developing Ada Programs on VMS Systems for more information on exporting and linking. When calling an Ada subprogram from an external routine, you must ensure that the parameters are passed in the form required by the Ada subprogram. To determine which mechanisms are required by VAX Ada, use the compiler qualifer /WARNINGS=COMPILATION_NOTES when you compile your Ada subprogram. For example: S ADA/WARNINGS=COMPILATION___NOTES 1 procedure SWAP (A,B: in SWAP out INTEGER) is Section 5.4 also provides information on the default parameter-passing mechanisms chosen by the VAX Ada compiler; Section 5.8 provides specific information on exporting Ada subprograms that involve parameters passed by descriptor. NOTE Some VAX languages allow optional and/or default parameters. Calls from external routines to exported VAX Ada subprograms must supply all parameters that are declared as formal parameters. In particular, an actual value must be supplied even when a default expression is given for a formal parameter in the Ada subprogram specification. 9.3 Conventions for Passing Data in Mixed-Language Programs When data is passed between routines that are not written in the same VAX language, the calling routine must pass the data in a form and to a location recognized by the routine being called. In VAX Ada, the manner in which parameters are passed and function results returned is determined by three sets of conventions: * The semantics of the Ada language * The linkage conventions required by the VAX Procedure Calling and Condition Handling Standard -6 Mixed-Language Programming The linkage conventions used by VAX Ada to implement subprogram calls The following sections discuss these conventions. 5.3.1 Ada Semantics The Ada language defines two kinds of semantics for parameter passing: copy-in/copy-back semantics and reference semantics. For parameters of mode in or in out, copy-in/copy-back semantics involves copying the value of the actual parameter into its associated formal parameter at the start of the call; for parameters of mode in out or out, copy-in/copy-back semantics involves copying the value of the formal parameter back into the actual parameter at the end of the call. Reference semantics involves no copies: any modifications to a formal parameter cause the same modifications to happen to the associated actual parameter immediately, and vice versa. The Ada language requires copy-in/copy-back semantics for scalar and access type parameters (see Chapter 6 of the VAX Ada Language Reference Manual). VAX Ada follows these requirements. VAX Ada also uses copyin/copy-back semantics for address type parameters (parameters of the type SYSTEM.ADDRESS). The Ada language allows a choice of copy-in/copy-back semantics or reference semantics for array, record, or task type parameters. The VAX Ada compiler takes advantage of this flexibility, and uses either kind of semantics for parameters of these types. NOTE When the VAX Ada compiler chooses copy-in/copy-back semantics for a record or array parameter, an update of the formal parame- ter during the execution of the subprogram does not result in an immediate update of the actual parameter. VAX Ada implements the Ada semantics for subprogram calls as follows: 1. At the beginning of the subprogram call, if the formal parameter has mode in or in out, a check is performed to ensure that the actual parameter value satisfies the constraints of the formal parameter. If the actual parameter fails this check, the exception CONSTRAINT_ERROR 1S raised. 2. If copy-in/copy-back semantics are used, a local variable is allocated to hold the formal parameter. Mixed-Language Programming 5-7 3. If copy-in/copy-back semantics are used, and if the formal parameter has mode in or in out, the value of the actual parameter is copied to the formal parameter. In addition, access values and discriminants are copied for mode out formal parameters. The subprogram is executed. 5. If copy-in/copy-back semantics are used, and if the formal parameter has mode in out or out, the value of the formal parameter is copied to the actual parameter. The exception CONSTRAINT _ERROR may occur at step 4 for record or array parameters when either copy-in/copy-back or reference semantics is used for those parameters. The exception CONSTRAINT_ERROR may also occur at step 5 for any types except record or array types. 5.3.2 VAX Calling Standard Conventions The primary purpose of the VAX Procedure Calling and Condition Handling Standard is to define how routines are invoked and data is passed between them. Some of the interface attributes that the calling standard specifies follow: ¢ Stack usage ¢ Argument list * Parameter-passing mechanisms * Function return value e Register usage These attributes are examined in more detail in the following sections. The calling standard also defines attributes such as the calling sequence and argument data types and descriptor formats. See Introduction to VMS System Routines for more information on these attributes. 5.3.2.1 The Call Stack A call stack is a last-in-first-out (LIFO) temporary area of storage allocated by the system. In VAX Ada, call stacks are created for the main program and for each task. When an Ada program (or a program written in any language that conforms to the calling standard) is executing, the VAX hardware uses the call stack to maintain information about each routine call. Thus, whenever an Ada program calls a routine (which can be an Ada subprogram or an external routine), or an exported Ada subprogram 1s called, the hardware creates two structures—an argument list and a call 5-8 Mixed-Language Programming frame. Depending on the CALL instruction that implements the call, the argument list is placed on the call stack (CALLS), or it is prebuilt and given as an operand (CALLG); the call frame is always placed on the stack. Note that there are special, separate stacks for non-user-mode code; see the VAX Architecture Reference Manual for more information. The contents of a call stack during a routine call (CALLS) are shown in Figure 5-1; the argument list and call frame are described in Sections 5.3.2.2 and 5.3.2.5. Mixed-Language Programming 5-9 Figure 5-1: A Call Stack at Run Time o Before routine call: Lower addresses :SP Stack grows toward lower calling routine local addresses. data area FP Higher addresses SP=Stack Pointer FP=Frame Pointer e The calling routine’s actions: First: Decrements SP by 4 times number of parameters and stores information about the actual parameters on stack. routine - : parameters parameter n calling routine local data area FP Second: Calculates "static link” /—\fi to allow the called routine to find the stack frame of its declaring routine. Stores static link in R1. Finally: Issues CALLS instruction. ZK-1037-1-GE (continued on next page) 5-10 Mixed-Language Programming Figure 5-1 (Cont.): A Call Stack at Run Time o The CALLS instruction’s actions: First: Finally: Pushes parameter count and gt;iafifaamn: pushes fills with zeroed bytes to a : called longword size. : Condition handler stack frame » Second:: UTM parameter count Sets new argument pointer and zeros (AP) equal to current SP. - PC . as needed cal(;;g ro:gne /_\ar/—\ | longword boundary. FP ‘ called routine Third: Adijusts stack to a old AP o The called routine’s actions: First: Allocates space for local data. > Second: 4 local data Stores the static link (R1) mtCZr::cblaj;e:P as ) Third: Copies copy-in parameters. le dition hand congition hander | PSW ' Finally: ‘PP saves SPin a local variable. old AP called. routine < FP stack frame- PC R2-R11 as needed ~ parameter count and zeros i AP calling routine parameters calling routine ZK~-1037-2-GE Mixed-Language Programming 5-11 5.3.2.2 The Argument List The argument list is a sequence of longword (32-bit) entries that is pointed to by a register called the argument pointer (AP). The argument list is used to carry information about the actual parameters from the calling routine to the called routine. The first longword entry contains, in its low byte, an unsigned integer count of the number of arguments in the list; the remaining three bytes must be zero. Each successive longword entry represents one parameter, and, depending on the parameter-passing mechanism being used, can be a 32-bit value, an address of an object, or an address of a descriptor. Figure 5-2 shows the format of an argument list; parameter-passing mechanisms are explained in Section 5.3.2.3. Figure 5-2: An Argument List Argument Pointer (AP) not used n=Argument count n (bits 4 through 31 argument_1 are reserved by argument_2 be zero) Digital and must ® o o argument_n ] ZK-0091-GE 5.3.2.3 Parameter-Passing Mechanisms The VAX Procedure Calling and Condition Handling Standard defines three mechanisms by which parameters can be passed in the argument list: * By immediate value—the value of the actual parameter is passed. The argument can be at most 32 bits in length. If the called subprogram or routine expects fewer than 32 bits, it accesses the low-order bits and ignores the high-order bits. When you pass a parameter by value, you pass a copy of the actual parameter value to the routine. 5-12 Mixed-Language Programming By reference—The address of a storage location containing the actual parameter value is passed. Note that this storage location may be a copy of the actual parameter. By descriptor—The address of a descriptor of the actual parameter is passed; that is, the value passed is the address of a data structure that contains the address of the parameter, along with other information such as the parameter’s data type and size. However, there is no requirement that the compiler use these mechanisms for parameters in subprograms that are not imported or exported. See Section 5.4 for information on the use of these mechanisms for parameters in imported and exported VAX Ada subprograms. 5.3.2.4 Function Return The VAX Procedure Calling and Condition Handling Standard defines a function as a routine that returns a single value according to the following conventions: If the function value requires 32 bits or less, it is returned in register RO. If the function value requires from 33 to 64 bits, the low-order bits of the value are returned in register R0, and the high-order bits of the value are returned in register R1. If the function value requires more than 64 bits, the calling routine passes an extra parameter—an address—as the first argument in the argument list. The address can point to either the storage for the value or to a descriptor. This kind of function result passing is called the extra parameter method. If the maximum length of the function value is known, the calling program allocates the required storage and passes either the address of the storage or a descriptor. If the maximum length is not known, the calling program can allocate a descriptor and pass its address. The called function allocates storage for the function value and updates the contents of the descriptor. See Section 5.5 for information on how VAX Ada interprets these conventions for imported and exported function results. Mixed-Language Programming 5-13 5.3.2.5 The Call Frame and Register Usage The VAX Procedure Calling and Condition Handling Standard defines several registers. These registers are defined in Table 5-1. Table 5-1: VAX Registers Register Use PC Program counter SP Stack pointer FP Frame pointer AP Argument pointer R1 Environment value (when necessary) RO,R1 Function return values For any ealled routine, the hardware-created call frame contains the follow- ing information: * A pointer to the call frame of the previous (calling) routine. This pointer is called the saved frame pointer (FP). * * The saved argument pointer (AP) of the previous (calling) routine. The address in storage of the point at which the routine was called; that is, the address of the instruction following the call to the current routine. This address is called the program counter (PC), or saved PC. * The saved contents of some of the general registers and other control information (such as the condition codes in the processor status word, or PSW, which is the low-order word of the processor status longword, or PSL). Based on a mask specified in the control information, the system restores these registers when control returns to the caller. The called routine can use registers RO through R11 and the AP register for computation. Figure 5-3 shows a call stack with three call frames: routine A calls routine B, and routine B calls routine C. When a routine finishes executing (in Ada, when a function or procedure reaches a return statement or when control reaches the end of a procedure), the system uses the frame pointer in the call frame of the current routine to locate the call frame of the previous (calling) routine. The system then removes the call frame of the current routine from the stack, and returns control to the calling routine (at the point of the saved PC). 5-14 Mixed-Language Programming Figure 5-3: A Call Stack 0 - Initial zero value (set by hardware): set to nonzero if routine either has exception handler or can generate a predefined exception Copy of argument pointer for function A 0 Mask PSW Pointer to A’s call frame AP Memory location in A at PC Contents of A’s general Ep which B was invoked registers R2 through R11 R2 ~ : C R11 ZK-0090-GE 5.3.3 VAX Ada Linkage Conventions Linkage conventions describe the implementation of subprogram calls. The VAX Procedure Calling and Condition Handling Standard defines the general way in which these conventions can be met for all VAX languages (see Section 5.3.2 for a summary of calling standard conventions). VAX Ada interprets these conventions as follows: Subprogram calls are made using a VAX CALL (CALLS or CALLG) instruction. The JSB instruction is not used or supported for calls to user-written external routines. Parameters are passed in an argument list, except for the first parameters in procedures specified with the pragmas IMPORT_VALUED _ PROCEDURE or EXPORT_VALUED_PROCEDURE. The first parameters in these procedures are treated as function results; see Section 5.5. Mixed-Language Programming 5-15 All other parameters are treated as ordinary parameters, and their mechanisms are determined as described in Sections 5.3.2.3 and 5.4. * Function results are returned to register RO, registers R0 and R1, or are passed as extra leading parameters in the argument list; see Sections 5.3.2.4 and 5.5. Note that in the case of unconstrained arrays and unconstrained records with discriminants with defaults, the calling routine must pass an area control block; see Sections 5.5.2 and 5.5.3. 5.3.4 The Importance of Data Representation When writing mixed-language programs, you must make sure that the representation of the data you are passing (as well as the parameter-passing mechanisms) agree. Chapter 2 explains how VAX Ada represents values of the various Ada types. Table 5-3 lists the VAX Ada equivalents for the VAX data types. For example, when passing strings to non-Ada routines, you must consider any differences that may exist between the Ada string definitions and the other-language string definitions. VAX Ada does not provide a varying string type; instead, you must declare a record like the following: subtype VARYING_ STRING_LENGTH is NATURAL range 0..65 (SIZE: VARYING STRING LENGTH) is 535; type VARYING STRING record STR: STRING(1l..SIZE); end record; for VARYING__STRING use record SIZE at 0 range 0..15; end record; Also, the implementation of similar features in another language may differ. For example, the maximum length of a string in VAX Ada is POSITIVE' LAST, or 231; the maximum length of a string in VAX Pascal is 216 — 1. Thus, when you pass a string between a VAX Ada subprogram and an imported VAX Pascal routine, you must accommodate for this differ- ence by altering the string type you use in the VAX Ada subprogram. For example: —— Package that —-— used by the main —— (VIEW_STRING) package 5-16 declares is (Ada) is string types program. imported STRING PACKAGE Mixed-Language Programming the The from VAX and printing operation printing Pascal. operation —— Declare a short, varying-length string. VARYING_STRING_LENGTH —— is needed so that Pascal receives the string correctly. subtype VARYING STRING_LENGTH is NATURAL range 0..65 535; type STRING is array (VARYING STRING_LENGTH range <>) of CHARACTER; type VARYING_ STRING (SIZE: VARYING_STRING_LENGTH) is record STR: STRING(l..SIZE); end record; for VARYING STRING use record SIZE at 0 range 0..15; end record; —-- Declare a procedure for printing out the string. procedure VIEW_STRING(VAR_STR: VARYING STRING) ; pragma INTERFACE (PASCAL, VIEW_ STRING) ; pragma IMPORT PROCEDURE (INTERNAL => VIEW STRING, => "View String", EXTERNAL PARAMETER TYPES => (VARYING_STRING), ); => (REFERENCE) MECHANISM end STRING PACKAGE; S GMNP SRS e ——— ey oy e w——— S bS —— Main program, which gives a value to and prints out a varying—- length string using the Pascal procedure. with STRING PACKAGE; use STRING PACKAGE; procedure MAIN is VARYING STRING_VALUE: VARYING_STRING(8); begin VARYING STRING VALUE := (SIZE => 8, STR => "I'm here"); ; VIEW STRING (VARYING_STRING_VALUE) end MAIN; MODULE View String (OUTPUT); TYPE Str = VARYING[65535] OF CHAR; [GLOBAL]PROCEDURE View String (Str_Val: Str); BEGIN Val); (Str LN WRITE END; END. See Chapter 10 for more information on varying strings. Mixed-Language Programming 5-17 9.4 VAX Ada Default Parameter-Passing Mechanisms The calling standard requires that parameters for global routines be passed either by the VAX reference or descriptor mechanisms. Paramet ers of private or limited private types are passed according to the mechanisms and semantics of their corresponding full type declarations. The following sections explain the parameter-passing defaults—in terms of both the VAX mechanisms and the Ada semantics—chos en for Ada parameters in imported and exported subprograms. Table 5-3 lists the VAX Ada equivalents for the VAX data types and gives the that are valid in VAX Ada for those types. passing mechanisms NOTE The rules for determining VAX Ada passing mechanisms are complex. The /WARNINGS=COMPILATION NOTES qualifier supplied with any of the compilation commands (DCL ADA or ACS COMPILE or RECOMPILE) gives you the exact mechanism chosen by the compiler for each parameter in an importe d or exported Ada subprogram. When writing a specification for an Ada subprogram whose body is imported, you should use an import pragma and the MECHANISM option to explicitly specify (and thus ensure) the passing mechanism for each paramet er; see Sections 5.1 and 5.6. 5.4.1 Scalar Type Parameters Scalar values (enumeration, integer, floating-point, and fixed-po are passed by the VAX reference mechanism using semantics. 9.4.2 int values) Ada copy-in/copy-back Array Type Parameters Array parameter passing is determined by the kind of array * A string is any one-dimensional array of a discrete type being passed: whose com- ponents occupy successive, unsigned bytes. (In other words, strings are arrays whose component types include, but are not limited to, the predefined type CHARACTER.) * A bit string is any one-dimensional array of a discrete components occupy successive single bits and are 9>-18 Mixed-Language Programming type whose unsigned. e A bit array is any array whose components are not byte aligned, yet which is also not a bit string. e A packed array is any array that has been declared with (and affected e A packable array is any bit string or any packed array whose component type is a packable array (not all bit arrays are packable; see by) the pragma PACK (see Section 2.2.1). Section 2.2.1). Arrays are usually passed by the VAX descriptor mechanism. The Ada semantics can be either copy-in/copy-back or reference. However, con- strained arrays that are neither bit strings nor bit arrays are passed by the VAX reference mechanism (using Ada reference semantics). Descriptor classes are chosen by the compiler according to how much is known about the array type at compile time. In general, the defaults are those shown in Table 5-2. Additional information about passing arrays by descriptor to imported and exported subprograms is given in Sections 5.6.3 and 5.7.3. See Section 2.1.5 for information on how arrays are represented, and see Section 2.2 for an explanation of how to control that representation. Table 5-2: Default Descriptor Classes Used by VAX Ada for Array Parameter Passing Class Associated Ada Type DSC$K_CLASS_SB! Any string where the compiler can determine that the DSC$K_CLASS_UBSB! Any bit string where the compiler can determine that DSC$K_CLASS_UBA Any bit array or any other bit string. (CONSTRAINT_ERROR is raised if DSC$W_LENGTH DSC$K_CLASS_A Any other array. (CONSTRAINT_ERROR is raised if number of components will not exceed 65,535. the number of components will not exceed 65,535. is inadequate.) DSC$W_LENGTH is inadequate.) 1The descriptor classes DSC$K_CLASS_SB and DSC$K_CLASS_UBSB are variants of the VAX DSC$K_CLASS_S and DSC$K_CLASS_UBS descriptors; they have the same fields, plus additional longword fields to hold the lower and upper bounds of the array. All of the VAX descriptors are shown in the Introduction to VMS System Routines. Mixed-Language Programming 5-19 5.4.3 Record Type Parameters Records are passed by the VAX reference mechanism. The Ada semantics can be either copy-in/copy-back or reference. The address in the argument list refers to a byte-aligned representation. If the actual parameter is a record that is not byte-aligned or that does not occupy an integral number of bytes, the compiler creates a temporary copy that meets those requirements. The address in the argument list then refers to the temporary copy. If the record type has discriminants with defaults, the calling routine must pass additional information in the argument list in certain cases. In other words, if the formal parameter is unconstrained and has mode in out or out, the calling routine must provide a “constrainedness bit.” The constrainedness bit indicates whether the discriminants of the actual parameter can be changed. Constrainedness bits are passed by immediate value as an extra longword in the argument list. A subprogram can have up to 32 formal parameters that require a constrainedness bit. The bits are allocated in ascending order, bit 0 being used for the first parameter that requires a constrainedness bit, bit 1 for the second, and so on. 5.4.4 Access Type Parameters Access values are passed by the VAX reference mechanism using copy-in/ copy-back semantics. The rules for passing access values are the same as those for passing scalar values (see Section 5.4.1), except that any necessary constraint checking is done on the object designated by the access value rather than on the access value itself. 5.4.5 Address Type Parameters Values of address types (values of type SYSTEM.ADDRESS and its derivatives) are passed by the VAX reference mechanism using Ada copy-in/ copy-back semantics. 5-20 Mixed-Language Programming 5.4.6 Task Type Parameters Values of task types are passed by the VAX reference mechanism. The Ada semantics can be either copy-in/copy-back or reference. 5.4.7 Subprogram Parameters The Ada language allows you to pass subprograms as parameters only to generic instantiations (see Chapter 12 of the VAX Ada Language Reference Manual). You can, however, pass the address of a subprogram by first ex- porting it (see Section 5.2) and then taking its address with the - ADDRESS attribute. An exported subprogram must be a library unit or must be declared in the outermost declarative part of a library package. If you try to take the address of a subprogram that is not exported, the compiler issues a warning message and uses the value SYSTEM.ADDRESS_ZERO as the result. Note that by default VAX Ada passes addresses by reference (see Section 5.4.5). 5.4.8 Entry Parameters The Ada language allows you to pass task entries as parameters only to generic instantiations (see Chapter 12 of the VAX Ada Language Reference Manual). 5.4.9 VAX Ada Equivalents for VAX Data Types For comparison and reference, Table 5-3 lists the Ada type equivalents and mechanisms chosen for each of the VAX data types defined in the VAX Procedure Calling and Condition Handling Standard. Mixed-Language Programming 521 Table 5-3: VAX Ada Equivalents for VAX Data Types and Their Valid Passing Mechanisms in VAX Ada Data Type Absolute date and time Symbolic Code DSC$K_DTYPE_ ADT Byte integer (signed) DSC$K_DTYPE_B VAX Ada Translation Passing Mechanism STARLET.DATE_ — TIME_TYPE SHORT_SHORT _ Reference’, INTEGER Descriptor? Bound label value DSC$K_DTYPE_BLV Not available — Bound procedure value DSC$K_DTYPE_ Not available — Any enumerated type whose values fit into Descriptor? BPV Byte unsigned DSC$K_DTYPE_BU Reference!, an unsigned byte; SYSTEM.UNSIGNED _ BYTE COBOL intermediate DSC$K_DTYPE_CIT Not available — DSC$K _DTYPE_D SYSTEM.D_FLOAT, LONG_FLOAT if Reference’, Descriptor? temporary D_floating pragma LONG_ FLOAT(D_FLOAT) is in effect D_floating complex DSC$K_DTYPE_DC Not available® See Section 5.4.3 Descriptor DSC$K_DTYPE_ Not available® See Section 5.4.3 FLOAT; SYSTEM.F_ Reference’, Descriptor? DSC F_floating DSC$K_DTYPE_F FLOAT F_floating complex DSC$K_DTYPE_FC Not available® See Section 5.4.3 G_floating DSC$K_DTYPE_G SYSTEM.G_FLOAT, Referencel, Descriptor? LONG_FLOAT if pragma LONG_ FLOAT(G_FLOAT) is in effect G_floating complex DSC$K_DTYPE_GC Not available? See Section 5.4.3 1The default for imported or exported subprograms. 20nly when specified as a MECHANISM option of an import pragma. 3Can be simulated in VAX Ada with a record type definition. (continued on next page) 9—22 Mixed-Language Programming Table 5-3 (Cont.): VAX Ada Equivalents for VAX Data Types and Their Valid Passing Mechanisms in VAX Ada Data Type Symbolic Code VAX Ada Translation Passing Mechanism H_floating DSC$K_DTYPE_H LONG_LONG_FLOAT; SYSTEM.H_FLOAT Reference’, Descriptor? H_floating complex DSC$K DTYPE_HC Not available® See Section 5.4.3 Longword integer (signed) DSC$K _DTYPE_L INTEGER Reference?, Descriptor? Longword (unsigned) DSC$K_DTYPE_LU SYSTEM.UNSIGNED_ LONGWORD Reference’, Descriptor? Numeric string, DSC$K_DTYPE_NL STRING See Section 5.4.2 Numeric string, DSC$K_DTYPE_ STRING See Section 5.4.2 left overpunched sign NLO Numeric string, DSC$K_DTYPE_NR STRING See Section 5.4.2 Numeric string, DSC$K_DTYPE_ STRING See Section 5.4.2 right overpunched sign NRO Numeric string, DSC$K_DTYPE_NU STRING See Section 5.4.2 DSC$K_DTYPE_NZ STRING See Section 5.4.2 DSC$K DTYPE_O Not available® See Section 5.4.3 DSC$K_DTYPE_OU Not available® See Section 5.4.3 Packed decimal string DSC$K_DTYPE_P Not available® See Section 5.4.3 Quadword integer DSC$K_DTYPE_Q SYSTEM.UNSIGNED_ Reference?, Descriptor? left separate sign right separate sign unsigned Numeric string, zoned sign Octaword integer (signed) Octaword logical (unsigned) (signed) QUADWORD, but arithmetic operations are not available 1The default for imported or exported subprograms. 20nly when specified as a MECHANISM option of an import pragma. 3Can be simulated in VAX Ada with a record type definition. (continued on next page) Mixed-Language Programming 5-23 Table 5-3 (Cont.): VAX Ada Equivalents for VAX Data Types and Their Valid Passing Mechanisms in VAX Ada Data Type Symbolic Code Quadword (unsigned) DSC$K_DTYPE_QU VAX Ada Translation Passing Mechanism SYSTEM.UNSIGNED_ Reference? QUADWORD, but arithmetic operations are not available Character string DSC$K DTYPE_T Aligned bit string DSC$K DTYPE_V STRING See Section 5.4.2 Packed BOOLEAN See Section 5.4.2 array Varying character DSC$K_DTYPE_VT Not available® See Section 5.4.2 Packed BOOLEAN See Section 5.4.2 string Unaligned bit string DSC$K_DTYPE_VU array Word integer (signed) DSC$K_DTYPE_W Word (unsigned) DSC$K_DTYPE_WU SHORT_INTEGER Reference!, Descriptor? Any enumerated type Reference!, Descriptor? whose values fit into an unsigned word; SYSTEM.UNSIGNED_ WORD Unspecified Procedure entry mask DSC$K_DTYPE_Z Parameter of any type DSC$K_DTYPE_ Not available Depends on Ada type ZEM Sequence of DSC$K_DTYPE_ZI Not available instructions IThe default for imported or exported subpfograms. 20nly when specified as a MECHANISM option of an import pragma. 3Can be simulated in VAX Ada with a record type definition. 5.5 VAX Ada Default Function Return Mechanisms In general, VAX Ada follows the function return conventions summarized in Section 5.3.2.4. The interpretation of those conventions for each of the VAX Ada types is given in the following sections. Note that for any given function result, the size is determined from the result subtype (a subtype is a type 5-24 Mixed-Language Programming together with a constraint). See Chapter 2 for information on the representation and storage of values of the various Ada types. See Chapter 3 of the VAX Ada Language Reference Manual for information on types and subtypes. 5.5.1 Scalar, Access, Address, and Task Type Results Because they require a maximum of 32 bits, results of enumeration, integer, fixed-point, and F_floating-point types are returned in register R0O. Because they require 64 bits, results of floating-point types that use the D_floating or G_floating representation are returned in registers RO and R1. Results of floating-point types that use the H_floating representation need 128 bits; thus, the calling routine must provide the address of a location that will receive the function result, and the address is passed as the first argument in the argument list. Results of any access, address, or task type are returned in register RO. Note that if the allocation of an enumeration or integer type is less than 32 bits, the returned result is zero- or sign-extended (as appropriate) to a clean 32-bit representation. 5.5.2 Array Type Results The methods by which array function results are returned depend on whether or not the array is constrained. If the type of the function result is a constrained array and all of the following conditions apply, then the function result is returned in register RO or in registers RO and R1: ¢ The array is not a string type (see Section 5.4.2). ¢ The array bounds and the component size are known at compile time. e If the array has a size of 32 bits or less, the function result is returned in register RO. e If the array has a size of 33 to 64 bits, the low-order bits are returned in register RO, and the high-order bits are returned in register R1. Note that string types are never returned in registers. However, if they are constrained, they can be returned with the extra parameter method (see Section 5.3.2.4). Mixed-Language Programming 5-25 If the storage size for an array result is not known at compile time or if the size is known to be greater than 64 bits, the calling routine must pass the result using the extra parameter method (see Section 5.3.2.4). Figure 5-4: Area Control Block Used in Returning Some Function Results 31 0 LENGTH Length (in bytes) of a block of storage for the function return value. POINTER Address of the block of storage. ZONE Zone in which the block of storage is to be freed and/or allocated. 1. f LENGTH is zero, then no storage has been previously allocated, and POINTER is undefined. The called function allocates storage sufficient for the value to be returned using the given ZONE. LENGTH is then set to the size of the block of the storage allocated. 2. If LENGTH is rionzero, then storage has been previously allocated, and POINTER is set to the address of that block of storage. The called function can either reuse the storage (if it is sufficient), or it can deallocate the storage and allocate new storage. (The called - routine has the option of doing either if the previously allocated storage is sufficient.) 3. If ZONE is null, then default process dynamic memory is used. If zone is -1, then there is no zone associated with the storage, and the calling routine guarantees that the storage described by LENGTH and POINTER is sufficient for the return value. Otherwise ZONE is the address of a zone control block. Note that a single storage area control block can be used in multiple calls without explicit freeing between calls. Also note that by allowing the calling routine to allocate storage when it deems appropriate, the overhead of dynamic memory management is avoided. ZK-3021-GE 5-26 Mixed-Language Programming If the function result is of an unconstrained array type (including unconstrained string types), the calling routine must pass the address of an area control block as the first argument in the argument list. The area control block is described and shown in Figure 5—4. In the case of an unconstrained array type, the area control block is concatenated with an array descriptor. The appropriate descriptor class (DSC$K_CLASS_UBSB, DSC$_CLASS_UBA, DSC$K_CLASS_SB, or DSC$K_CLASS_A) is chosen according to the rules given in Section 5.4.2 for passing parameters of array types. The calling routine must initialize the area control block. However, the calling routine does not need to initialize the descriptor or allocate storage for the result. The called function allocates storage in the appropriate zone and fills in the descriptor that refers to the result. The calling routine must release the storage for the result after the storage is used. 5.5.3 Record Type Results For a simple record type whose size is 32 bits or less, the function result 1s returned in register R0. If the record size is 33 to 64 bits, the function result is returned in registers R0 and R1. (A simple record is one that has no variants and that has components and subcomponents whose constraints are static. Simple records can have discriminants. See Chapter 13 of the VAX Ada Language Reference Manual for a complete definition of simple record types and subtypes; see Chapter 4 of the VAX Ada Language Reference Manual for a definition of static.) For a record type whose size is over 64 bits (including large, simple records and constrained records), the calling routine must pass the address of a location to receive the function result as an extra parameter in the argument list (the calling routine must use the extra parameter method; see Section 5.3.2.4). The function returns the result at that location. See Section 2.1.6 for information on how to estimate the storage size of records. For a function result of an unconstrained record type with discriminants with defaults, the caller must pass an area control block for the called function to use in returning the result. The caller is responsible for releasing the storage for that result after the storage has been used. (The area control block is shown in Figure 5—4.) Mixed-Language Programming 5-27 5.6 Controlling the Mechanisms for Imported Subprogram Parameters The MECHANISM option in the VAX Ada import pragmas allows you to control the VAX mechanisms used for passing parameters in imported subprograms. For each parameter, you can specify one of three values— VALUE, REFERENCE, or DESCRIPTOR. For example: package type SHOW MECH is SIMPLE REC is record COMP: SHORT INTEGER; end record; IMPORT (A: INTEGER; pragma procedure INTERFACE (C, IMPORT); pragma IMPORT PROCEDURE INTERNAL => B: STRING; C: SIMPLE REC); ( IMPORT, PARAMETER_TYPES => (INTEGER, MECHANISM => (REFERENCE, STRING, SIMPLE REC), DESCRIPTOR(CLASS => 8S), VALUE) ) ; end SHOW MECH; The following sections discuss the use of each of these values in more detail. See Section 5.3.2.3 for a description of the VAX mechanisms that correspond to these values. NOTE In addition to the VAX mechanism chosen for a particular parameter (see Section 5.4), the Ada parameter-passing semantics and VAX Ada linkage conventions also apply. The Ada semantics are determined by the parameter’s type. See Section 5.38.1 for more information on Ada semantics; see Section 5.3.3 for more information on the VAX Ada linkage conventions. 5.6.1 The VALUE Mechanism Option The VALUE mechanism option causes the compiler to pass the actual parameter by immediate value. This option has two different effects, depending on the kind of parameter you apply it to: * When you apply this mechanism to any parameter except the first parameter in a procedure specified with the pragma IMPORT_VALUED _ PROCEDURE, the immediate value is passed in the argument list. You 5-28 Mixed-Language Programming can use this mechanism to pass a parameter of any subtype, as long as it has a compile-time size of 32 bits or less; the associated formal parameter must be of mode in. e When you apply this mechanism to the first parameter in a procedure specified with the pragma IMPORTVALUED_PROCEDURE, the immediate value is treated as a function result and is returned to registers (see Section 5.7.1). The parameter can have a scalar, access, task, address, simple record, or constrained bit string subtype, but it must have a compile-time size of 64 bits or less. The associated formal parameter must be of mode out. For example: package SHOW MECHANISMS procedure is HYPOTHETICAL ( RESULT: out FLOAT; BASE : in INTEGER; EXPONENT: in INTEGER) ; pragma INTERFACE pragma IMPORT VALUED PROCEDURE ( (OTHER”LANG, HYPOTHETICAL) ; INTERNAL => PARAMETER TYPES => HYPOTHETICAL, (FLOAT, INTEGER, MECHANISM => (VALUE, VALUE, INTEGER), VALUE)):; end SHOW MECHANISMS; In this example, all three parameters are passed by the VALUE mechanism. However, the immediate value of RESULT will be returned in register RO; the immediate values of BASE and EXPONENT will be passed in the argument list. See Chapter 6 for more information on the use of the pragma IMPORT_ VALUED_PROCEDURE. 5.6.2 The REFERENCE Mechanism Option The REFERENCE mechanism causes the address of an actual parameter to be passed in the argument list. You can use this mechanism to pass actual parameters of any type. However, if a non-byte-aligned actual parameter of an array type is passed, the exception CONSTRAINT ERROR is raised. You can use the REFERENCE mechanism even in cases where a descriptor or additional information is usually passed (see Sections 5.4.2 and 5.4.3). However, when you use the REFERENCE mechanism in such cases, you must find a way to pass the additional information to the external routine. For example, in VAX Ada you would normally pass an unconstrained array Mixed-Language Programming 5-29 parameter by descriptor, where the descriptor contains the information about the array bounds. Thus, if you import a routine written in FORTRAN (where all arrays are passed by reference), and pass an unconstrained array parameter, you must pass the array bounds as additional parameters. Consider the following FORTRAN function: FUNCTION QOO0 This INNERPROD (A, routine multiplies element-by-element, and B REAL as arrays A(N), SUM = DO 100 of two then real N) one-dimensional sums the products. arrays, Declare A numbers. B(N) 0 I =1, SUM = 100 B, N SUM + A(I) * B(I) CONTINUE INNERPROD = SUM RETURN END A and B are adjustable arrays whose bounds are passed as a subprogram argument. To call this routine from Ada, you would declare two uncon- strained array parameters to correspond to A and B. By passing the integer parameter N to correspond to the array length parameter, N, in the FORTRAN function, you could then pass the Ada arrays by reference without losing information. The declarations and function call in VAX Ada would be as follows: type ARRAY1 function is array INNERPROD (INTEGER (A, pragma INTERFACE pragma IMPORT FUNCTION Q, ARRAY1(1..100); T P : P := : B : (FORTRAN, range ARRAY1l; <>) N : of FLOAT; INTEGER) return FLOAT; INNERPROD) ; (INNERPROD, MECHANISM => REFERENCE) ; FLOAT; INNERPROD (Q, T, Q’LENGTH): Because Q and T are of the same length, either Q' LENGTH or T LENGTH can be passed to INNERPROD as the actual parameter for N. 5.6.3 The DESCRIPTOR Mechanism Option The DESCRIPTOR mechanism causes the compiler to pass the address of a string, array, or scalar descriptor, as described in the VAX Procedure Calling and Condition Handling Standard (see the Introduction to VMS System Routines). The VAX Ada compiler generates the descriptor and supplies the necessary information. 5-30 Mixed-Language Programming Parameters of all scalar types, array types, and access types can be passed by descriptor; parameters of record and task types cannot. The calling standard defines various descriptor classes that can be used for passing parameters of different VAX data types. For certain array parameters, the VAX Ada compiler automatically generates a subset of these descriptors (see Section 5.4.2). For parameters that must be passed by descriptor to an imported routine, the DESCRIPTOR mechanism name can be given with an optional class name argument that specifies the particular descriptor to be used. If you use the DESCRIPTOR mechanism name, but omit the class name, the VAX Ada compiler chooses an appropriate default class depending on the Ada parameter type. The following example shows the use of the IMPORT PROCEDURE pragma to call the VMS Run-Time Library routine OTS$CVT _L_TZ, where a string is passed by descriptor. The routine converts a longword (in this case an Ada INTEGER) to a hexadecimal ASCII text string. The routine requires two parameters: an integer passed by reference, and a text string passed by descriptor using descriptor class S. procedure OTSCONVERT INTVALUE : is NATURAL; HEXSTRING : STRING procedure CONVERT TO HEX pragma INTERFACE pragma IMPORT (1..11); (RTL, PROCEDURE (I : in NATURAL; HS : out STRING) ; CONVERT TO HEX) ; (INTERNAL => CONVERT TO HEX, EXTERNAL => "OTS$CVT L Tz", MECHANISM => (REFERENCE, DESCRIPTOR (CLASS => 8))):; bagin CONVERT TO HEX (INTVALUE, HEXSTRING); end OTSCONVERT; In this example, the formal parameter I is an integer that is passed by reference. The formal parameter HS is an unconstrained string. By default, unconstrained strings are passed by descriptor using descriptor class DSC$K_CLASS_SB. In this case, passing the parameter HS with class DSC$K_CLASS_SB means passing extra information (the string bounds) that the VMS Run-Time Library routine does not need. Thus, for efficiency, the mechanism argument of the IMPORT PROCEDURE pragma specifies that the second parameter (HS) be passed by descriptor using class DSC$K_ CLASS_S. (Because the formal parameter HS is unconstrained, an actual parameter of any length can be passed to the routine.) Mixed-Language Programming 5-31 Table 54 lists the default descriptor classes generated for imported parameters specified with the DESCRIPTOR mechanism. To determine exactly which descriptor class (and descriptor) is generated for imported parameters, use the /WARNINGS=COMPILATION_NOTES qualifier when you compile the Ada specifications for your imported subprograms. See Section 5.4.2 for definitions of the VAX Ada string, bit-string, and bit-array types. Table 5-4: Default Descriptor Class Names Used for the DESCRIPTOR Mechanism Class Name Use UBS UBSB If the parameter is a bit string. (UBS is used only for a constrained bit string whose lower bound is 1.) A If the parameter is any array type except a bit string or a bit NCA array. S If the parameter is of an integer, enumeration, floating-point, SB fixed-point, access, or address type, or if it is an array of unsigned bytes. (S is used only for a constrained string whose lower bound is 1, or any nonarray type.) UBA If the parameter is of any array type. If you choose to specify class names when you use the DESCRIPTOR mechanism in an import pragma, you must observe the type requirements described in Table 5-5. Table 5-5: Type Requirements for Descriptor Classes Used by VAX Ada in Importing Routines Class Name Requisite Characteristics of Ada Formal Parameter Type UBS Unaligned bit string: the base type of the formal parameter must be a one-dimensional array of 1-bit components. If the formal array parameter is constrained, then the lower bound must be equal to 1. A run-time descriptor check occurs to ensure that the actual array parameter has no more than 65,535 components. If this check fails, then CONSTRAINT ERROR is raised. (continued on next page) 5-32 Mixed-Language Programming Table 5-5 (Cont.): Type Requirements for Descriptor Classes Used by VAX Ada in Importing Routines Class Name Requisite Characteristics of Ada Formal Parameter Type UBSB Unaligned bit string with arbitrary bounds: the base type of the formal parameter must be a one-dimensional array of 1-bit components. A run-time descriptor check occurs to ensure that the actual array parameter has no more than 65,535 components. If this check fails, then CONSTRAINT_ERROR is raised. The value of A’ FIRST’ POS need not be equal to 1. UBA Unaligned bit array: the base type of the formal parameter must be an array. A run-time descriptor check occurs to ensure that the size of each component of the actual parameter requires no more than 65,535 bits. If this check fails, then CONSTRAINT_ERROR is raised. You normally use this descriptor when the formal parameter array components are unaligned (the formal parameter type has been declared with pragma PACK). If the array components are byte-aligned, use descriptor class A. Scalar or access type, or string: the base type of the formal parameter must be a one-dimensional array of 8-bit unsigned components (a VAX Ada string type; see Section 5.4.2 for a definition of string types), a scalar, or an access type. If the parameter is a constrained array, then the lower bound must be equal to 1. A run-time descriptor check occurs to ensure that the actual array parameter has no more than 65,535 components. If this check fails, then CONSTRAINT_ERROR is raised. For a scalar or access type, the DTYPE field of the descriptor is filled in as shown in Table 5-6. SB String with arbitrary bounds: the base type of the formal parameter must be a one-dimensional array of unsigned 8-bit components (a VAX Ada string type; see Section 5.4.2 for a definition of string types). A run-time descriptor check occurs to ensure that the actual array parameter has no more than 65,535 components. If this check fails, then CONSTRAINT_ERROR is raised. (continued on next page) Mixed-Language Programming 5-33 Table 5-5 (Cont.): Type Requirements for Descriptor Classes Used by VAX Ada in importing Routines Class Name Réquisite Characteristics of Ada Formal Parameter Type A Contiguous array: the base type of the formal parameter must be a byte-aligned array type (that is, an array that starts on a byte boundary) with byte-aligned components or 1-bit components. (This excludes any array of packable components whose component size is not 1, 8, 16, or 32 bits and for which the pragma PACK is given.) If the array type has 1-bit components, a run-time descriptor check is performed to ensure that the actual array parameter is byte-aligned. If this check fails, then CONSTRAINT ERROR is raised. In all other cases, a run-time descriptor check is performed to ensure that the size of each component does not exceed 65,535 bytes. If this check fails, then CONSTRAINT_ ERROR is raised. Note that for a one-dimensional array of unsigned 8-bit components that is not a VAX Ada string type (see Section 5.4.2 for a definition of string types), the descriptor class A can be used instead of class SB because the class A descriptor allows more than 65,5635 components to be represented; in other words, class A can be used where it is not known at compile time that there will always be fewer than 65,535 components for all possible values of the type. NCA Noncontiguous array: the restrictions on the formal parameter type and the descriptor checks that are performed are the same as for class A. Because VAX Ada never allocates an array of noncontiguous components, this descriptor class is only provided for cases in which the imported routine requires the NCA descriptor. Table 5—6 lists the data types chosen by the compiler for descriptor DTYPE fields when the DESCRIPTOR mechanism is used in an import pragma. Note that for DSC$K_CLASS_A and DSC$K_CLASS_NCA, the array component type is used to determine the DTYPE, while for all other classes, the formal parameter type is used (that is, the array type is used, except when DSC$K_CLASS_S or DSC$K_CLASS_SB is used to pass nonarrays). 5-34 Mixed-Language Programming Table 5-6: Descriptor Data Types Used Type Name Meaning Use DSC$K_DTYPE_VU Unaligned bit string Always used for parameters specified with the class names UBS, UBSB, and UBA. Used in particular if the formal parameter type is a bit string or a bit array. DSC$K_DTYPE_T Character or character string Used if the formal parameter type is any enumeration type with a non- negative representation of T’ FIRST, with a representation of T’ LAST that is less than 256, and with a size of 8 bits. Also used if the formal parameter type is a string of these enumeration type components, which is specified with the class name S or SB. DSC$K_DTYPE_B DSC$K_DTYPE_BU DSC$K_DTYPE_W DSC$K_DTYPE_WU DSC$K_DTYPE_L DSC$K_DTYPE_LU DSC$K_DTYPE_F DSC$K_DTYPE_D DSC$K_DTYPE_G DSC$K_DTYPE_H DSC$K_DTYPE_Z 5.7 Byte integer (signed) Used as appropriate for 8-, 16-, or Byte logical (unsigned) 32-bit components of discrete types. Word integer (signed) Word logical (unsigned) Longword integer (signed) Longword logical (unsigned) F_floating Used as appropriate for floating-point D_floating types. G_floating H_floating Unspecified Used for all other types. Controlling the Return Mechanisms for Imported Function Results The RESULT_MECHANISM option in the VAX Ada pragma IMPORT_ FUNCTION allows you to control the mechanisms used for returning function results in imported functions. You can specify one of three values—VALUE, REFERENCE, or DESCRIPTOR—with this option. For example: Mixed-Language Programming 5-35 package SHOWRESULT MECH is function CONTROL (X,¥Y: pragma INTERFACE (FORTRAN, pragma IMPORT FUNCTION INTERNAL => INTEGER) return STRING:; CONTROL); ( CONTROL, RESULT MECHANISM => DESCRIPTOR end (CLASS => S)); SHOW RESULT MECH; The following sections discuss the use of these options in more detail. 5.7.1 The VALUE Mechanism Option The VALUE mechanism option causes the function result to be returned in registers. If the function result subtype has a size of 32 bits or less, it is returned in register RO. If the function result subtype has a size of 33 to 64 bits, the low-order bits are returned in register R0, and the high-order bits are returned in register R1. This option 1s valid for scalar, access, task, and address results. It is also valid for simple records and constrained bit strings that have a compile-time size of 64 bits or less. See Section 5.4.2 for a definition of bit strings; see Section 5.5.3 for a definition of simple records. 5.7.2 The REFERENCE Mechanism Option The REFERENCE mechanism option causes the address of the function result to be passed by the extra parameter method (the calling—Ada— subprogram adds an extra parameter as the first parameter in the argument list; see Section 5.3.2.4). This option is valid for any results except unconstrained record or array results. 5.7.3 The DESCRIPTOR Mechanism Option The DESCRIPTOR mechanism option causes the address of a descriptor for the function result to be passed by the extra parameter method. The choice of descriptors, and the rules for choosing them are the same as those for the parameter-passing DESCRIPTOR mechanism option; see Section 5.6.3. This option is valid for any results, except task and record results. 5-36 Mixed-Language Programming In the case of unconstrained arrays, an area control block may be used in addition to a VAX descriptor. See Section 5.5.2 and Section 5.5.3. 5.8 Passing Parameters by Descriptor to Exported Subprograms When passing parameters by descriptor from an external routine to an exported Ada subprogram, be sure that the calling routine uses the correct descriptor class and fills in the descriptor fields in the manner expected by the Ada subprogram. To find the correct descriptor class, use the WARNING=COMPILATION_ / NOTES qualifier when you compile the exported Ada subprogram. When you pass an array using the DSC$K_CLASS_A descriptor for an unconstrained array formal parameter, be sure that the DSC$V_FL_COEFF and DSC$V_FL__BOUNDS bits are set in the DSC$B_AFLAGS field. When you export an Ada subprogram that would normally receive parameters passed by descriptor class DSC$K_CLASS_SB (see Section 5.4.2), the Ada compiler ensures that parameters passed by descriptor class DSC$K_CLASS_S are also accepted. When a DSC$K_CLASS_S descriptor is received by the exported subprogram, the descriptor bounds are defined as 1..N, where N is the length of the string. The compiler also ensures that DSC$K_CLASS_UBS descriptors are accepted in place of DSC$K_CLASS_ UBSB descriptors, with implicit bounds assumed in the same way. As a result, a slight performance penalty is imposed on exported subprograms where such descriptors are involved. For example, the following exported Ada function takes a string and a character, and returns the index of the first string component that matches the character: function NFIND (STR: STRING; C CHARACTER) : return INTEGER is begin for T if in STR’/RANGE loop STR(I) = raturn I; C then end if; end loop; -= If return no match, return O. O; Mixed-Language Programming 5-37 end NFIND; pragma EXPORT FUNCTION (NFIND) ; The following VAX FORTRAN routine uses (imports) the Ada function NFIND: CHARACTER* (12) X CHARACTER* (1) B X = B ="' "7 N = TYPE 71234 6789’ NFIND (X, *, B, S3REF (B)) N END In VAX FORTRAN, string parameters are usually passed by descriptor using the DSC$K_CLASS_S descriptor. However, the Ada function expects the string STR parameter to be passed by DSC$K_CLASS_SB descriptor, and the character C to be passed by reference (the CHARACTER type is an enumeration type, which is passed by reference by default in VAX Ada). Because the Ada function is exported, it will also accept the string STR if the string is passed by DSC$K_CLASS_S descriptor. The %REF mechanism specifier in the FORTRAN routine causes B to be passed by reference. 5.9 Sharing Storage with Non-Ada Routines When you compile a VAX Ada program, the compiler creates up to five contiguous areas of memory, called program sections (psects), to store information about the program. These program sections are named $CODE, $CONSTANT, $DATA, $ADDRESS, and $ZERO. The sections have the following characteristics and properties (see Table 5—7 for a definition of the properties): $CODE Contains machine instructions; it has the properties PIC, USR, CON, REL, LCL, SHR, EXE, RD, NOWRT, NOVEC, ALIGN(2). $CONSTANT Contains compile-time constants; it has the properties PIC, USR, CON, REL, LCL, SHR, NOEXE, RD, NOWRT, NOVEC, ALIGN(2). $DATA Contains static variables (library package data); it has the properties PIC, USR, CON, REL, LCL, NOSHR, NOEXE, RD, WRT, NOVEC, ALIGN(2). 5-38 Mixed-Language Programming $ADDRESS Contains address constants, exception vectors, and data produced by the compiler during the course of compilation; it has the properties PIC, USR, CON, REL, LCL, NOSHR, NOEXE, RD, NOWRT, NOVEC, ALIGN(2). $ZERO Contains compile-time constants whose values are zero; it has the properties PIC, USR, OVR, REL, LCL, SHR, NOEXE, RD, NOWRT, NOVEC, ALIGN(9). Except for $CODE, the predefined program sections are not generated unless they are needed. Table 5-7: Program Section Properties Class Meaning PIC/NOPIC Position independent or position dependent USR/LIB User or library CON/OVR Concatenated or overlaid REIL/ABS Relocatable or absolute LCL/GBL Local or global scope SHR/NOSHR Shareable or nonshareable EXE/NOEXE Executable or nonexecutable RD/NORD Readable or nonreadable WRT/NOWRT Writable or nonwritable VEC/NOVEC Vectors or no vectors (protection) ALIGN Alignment When you link your program, the VMS Linker controls memory allocation and sharing according to the properties of each program section. The linker constructs an executable image by dividing the image into sections that have the same properties as their corresponding program sections. If you try to link two program sections that have the same name, but have different properties, the linker issues a warning. To avoid this warning, the VAX languages (including VAX Ada) choose the same properties for equivalent program sections. In other words, the $CODE section generated by the VAX Ada compiler has the same properties as the $CODE section generated by the VAX Pascal compiler, and so on. Thus, the linker allows you to construct a multilanguage image. For more information on the VMS Linker, see the VMS Linker Utility Manual; for more information on linking mixed-language programs, see Developing Ada Programs on VMS Systems. Mixed-Language Programming 5-39 The only storage that you can explicitly share with non-Ada programs 1s storage allocated for objects declared in library packages. VAX Ada provides the pragmas IMPORT _OBJECT, EXPORT_OBJECT, and PSECT_ OBJECT to allow such sharing. These pragmas are briefly defined as follows (a detailed definition appears in Chapter 13 of the VAX Ada Language Reference Manual). See Chapter 10 for an example of sharing memory between VAX processors. The syntax of the pragmas IMPORT_OBJECT and EXPORT_OBJECT is as follows: pragma IMPORT OBJECT (internal_name [, [SIZE internal_name simple name | [, EXPORT OBJECT external designator] =>] external symboll]); ::= [INTERNAL =>] ::= simple name identifier external_ designator ::= external symbol identifier ::= [EXTERNAL =>] | external symbol string literal These pragmas are equivalent to the GLOBAL and EXTERNAL attributes in Pascal, the GLOBALDEF and GLOBALREF attributes in PL/I, and the globaldef and globalref data types in C. You can also use them to share variables with VAX BLISS and MACRO. For example: —— Ada —- integer package package PAS IMPORTOBJ INT: pragma end that declares imported is INTEGER; IMPORT OBJECT (PAS INT); IMPORTOBJ; — —— Ada -- an object. — — main procedure that value of the imported with TEXT IO; with INTEGER TEXT IO; use with IMPORTOBJ; procedure — o prints —— out the object. TEXT IO; use IMPORTPROC use INTEGER TEXT IO; IMPORTOBJ; is begin PUT ("The value PUT (PAS INT) of ; end IMPORTPROC; 5—40 Mixed-Language Programming PAS INT in Ada is "); —o— o =y { Pascal module that global declares and initializes the integer to be MODULE Pasobj imported by the Ada package. } (INPUT,OUTPUT) ; VAR Pas Int: [GLOBAL] INTEGER := 10; END. This example declares an object in Ada and a variable in Pascal and uses the Ada pragma IMPORT_OBJECT and the Pascal GLOBAL attribute to associate the name Pas_Int with a global symbol. The Pascal module assigns the value 10 to the location referenced by the global symbol, and the Ada main procedure prints it out. An analogous example of the use of the pragma EXPORT_OBJECT follows: { Pascal main program that prints of the exported Ada object. PROGRAM Print Integer out the value } (INPUT,OUTPUT) ; VAR Pas Int: [EXTERNAL] INTEGER; BEGIN WRITE (' The value of Pas Int in PASCAL is '); WRITELN (Pas_Int); END. -- Ada package that —— declares the object to be exported. package EXPORT INT PAS INT: INTEGER is := 25; pragma EXPORT OBJECT (PAS INT); end EXPORT INT; Here, PAS_INT and its initial value are exported from an Ada package to a Pascal program. PAS_INT is initialized when the Pascal program is executed. Note that if you want to use the DCL LINK command instead of the ACS LINK command—in other words, you want to link “from” Pascal instead of “from” Ada—you must use the ACS EXPORT command to obtain the Ada object module from the program library. See Developing Ada Programs on VMS Systems for more information on linking mixed-language programs. Mixed-Language Programming 5-41 When sharing variables with VAX BLISS or VAX MACRO, you can use the size option of these pragmas to compare the size of the Ada object with the size expected by the external routine. The internal and external routines both define the same global literal and give as its value the size (in bytes) of the variable that is stored in the program section. (The size option causes the VAX Ada compiler to automatically compute the size.) If the two defined values of the global symbol are not equal, the linker issues an error. Thus, this feature provides some link-time size checking. For example: ! BLISS ! named by the ! that ! designator of the ! of module that declares global symbol correspond to the storage 100-element imported Ada same allocated a X and global names. longword array literal object XSIZE and XSIZE size represents the amount for X. 1 module INT ARRAY (ident = ’1-003’) = begin global X ¢ global vector[100,longl; literal XSIZE = %allocation (X): end eludom -— Ada package -— of integers -— to the —— IMPORT_OBJECT, same as a name X: IMPORT ARRAY array pragma end IMPORT (1..105) Mixed-Language Programming 105-component as the the symbol specifies a BLISS link-time object array X known with the pragma size designator global literal consistency is of INTEGER; IMPORT_ OBJECT (X, ARRAY; a makes global and in order to obtain package 5-42 declares (longwords), linker —— with the -— that SIZE=>X SIZE); checking. —— Ada main procedure that initializes the array -— object X (all components receive the value 10), —— and prints out the value of the -—= 12th component. with TEXT IO; with INTEGER TEXT IO; use INTEGER_TEXT IO; use TEXT IO; with IMPORT ARRAY; use IMPORT_ARRAY; procedure PRINT COMPONENT is begin X = (1..105=>10); PUT ("The value of X(12) is "); PUT (X (12)); end PRINT COMPONENT; The BLISS and Ada code in this example compiles, but when linking is attempted, the linker issues a warning message saying that X_SIZE is multiply defined (it finds two values for X_SIZE). There is also an example of size checking with the pragma PSECT_OBJECT at the end of this section. The pragma PSECT_OBJECT has the following syntax: pragma PSECT_OBJECT (internal name [, [SIZE internal name simple name [, external designator] =>] external symbol]):; ::= [INTERNAL =>] simple name ::= identifier external designator external symbol ::= [EXTERNAL =>] ::= identifier | external symbol string literal This pragma is provided primarily for use with FORTRAN or BASIC common blocks, Pascal variables declared with the COMMON or PSECT attribute, EXTERNAL variables in PL/I, or variables declared with the extern keyword in C programs. You can also use it to share variables with VAX BLISS and VAX MACRO routines. Program sections established with the pragma PSECT_OBJECT have the following attributes, which are defined in Table 5-7: PIC, USR, OVR, REL, GBL, SHR, NOEXE, RD, WRT, NOVEC, ALIGN Note that the alignment is the greater of the alignment required for the object being exported and ALIGN(2) (that is, longword alignment). This combination of attributes is the same as the one used by the other languages that allow you to allocate storage in common blocks (that is, overlaid program sections). (Other languages generally have longword alignment.) Note that PSECT_OBJECT program sections are overlaid and global. You cannot change program section attributes in VAX Ada. Mixed-Language Programming 5-43 Unlike the VAX languages that allow you to store several variables in a particular common block, VAX Ada allows only one object to be allocated in a particular program section. If you want to share storage with FORTRAN common variables, you must declare an Ada record variable in which each component of the record corresponds to one FORTRAN variable. For example: C FORTRAN declarations: INTEGER DAY, MONTH, CHARACTER*20 NAME COMMON /BDATE/DAY, YEAR MONTH, YEAR / /NAME END —— Corresponding VAX Ada type DATE is DAY, declarations: record MONTH, YEAR : INTEGER; end record; subtype NAME BDATE : STRING(1l..20); DATE; ACCTNAME pragma is : NAME; PSECT OBJECT pragma PSECT OBJECT (BDATE); (ACCTNAME, "S$SBLANK"); This example shows storage allocation in two different program sections. The FORTRAN COMMON statement declares two common blocks. One is named BDATE and contains the three integer variables DAY, MONTH, and YEAR. The second is a blank common block (whose name is $BLANK) and contains the character array variable NAME, which has 20 elements. The Ada record variable BDATE has three components that correspond to the three variables stored in the common block BDATE. The first pragma PSECT_OBJECT establishes the program section BDATE, which contains the record variable BDATE. (The name of the program section is the same as that of the variable because the psect designator parameter is omitted from the pragma statement.) The Ada variable ACCTNAME is a string of 20 characters, which corresponds to the FORTRAN variable NAME. The second pragma PSECT_OBJECT specifies that storage for ACCTNAME is to be allocated in the program section $BLANK. Note that the psect designator must be a quoted string because the name contains a dollar sign ($). 5-44 Mixed-Language Programming As with the pragmas IMPORT_OBJECT and EXPORT_OBJECT, you can use the SIZE option with the pragma PSECT_OBJECT to gain some link-time consistency checking when sharing storage with VAX BLISS or MACRO routines. For example: ! Declaration of a named psect in VAX BLISS: PSECT NODEFAULT = X(OVERLAY, READ, WRITE, NOEXECUTE) ; OWN X: PSECT (X) GLOBAL LITERAL XLEN = VECTORI[10]; SALLOCATION (X) ; —— Corresponding declaration in VAX Ada: type VECTOR is array(l..10) X : of INTEGER; VECTOR; pragma PSECT OBJECT (X, SIZE => XLEN); The fragment of BLISS code declares a program section named X to store a vector of longwords. The GLOBAL LITERAL statement declares the global symbol XLEN to be equal to the allocation size of the variable X. The Ada code declares an array of integers (which are stored as longwords). The pragma PSECT_OBJECT specifies that the array X is to be stored in the program section named X. Furthermore, the size option directs the Ada compiler to calculate the size of X and declare the global symbol XLLEN to be equal to the size of X in bytes. At link time, the linker checks to see that the two declarations of XLEN are equal. If they are not, an error is issued. Mixed-Language Programming 5-45 Chapter 6 Calling System or Other Callable Routines VAX Ada provides a variety of features for calling VMS system service, RMS, Run-Time Library, utility, and other callable routines from an Ada program: The package STARLET provides VAX Ada types, VAX Ada named numbers representing VMS symbol definitions, and VAX Ada operations for calling VMS system service and RMS routines. The specification of the data types is in Appendix B; the complete specification of this package is in the VAX Ada library of predefined units (ADA$PREDEFINED). The package TASKING_SERVICES provides interface routines for calling VMS system services that involve asynchronous system trap (AST) parameters. The specification of this package is in Appendix B, as well as in the VAX Ada library of predefined units (ADA$PREDEFINED). The package SYSTEM provides types and operations for manipulating system-related variables and parameters, as well as for obtaining symbol definitions that are not defined in the package STARLET. The specification of this package is described in Chapter 13 of the VAX Ada Language Reference Manual, and is given in full in Appendix I of that manual. The specification of this package is also in the VAX Ada library of predefined units (ADA$PREDEFINED). The generic package MATH_LIB (and the predefined VAX Ada instantiations FLOAT_MATH_LIB, LONG_FLOAT MATH_LIB, and LONG_LONG_FLOAT_MATH_LIB) provides routine interfaces for calling many of the VMS Run-Time Library mathematics routines. The specifications for this package and these instantiations are in Appendix B, as well as in the VAX Ada library of predefined units (ADA$PREDEFINED). Calling System or Other Callable Routines 6—1 e The packages DTK, LIB, MTH, OTS, PPL, SMG, and STR provide VAX Ada types, VAX Ada named numbers representing VMS symbol definitions, and VAX Ada operations for calling VMS Run-Time Library routines. The specifications of these packages are in the VAX Ada library of predefined units (ADA$PREDEFINED). e The packages CLI, NCS, LBR, and SOR provide VAX Ada types, VAX Ada named numbers representing VMS symbol definitions, and VAX Ada operations for calling VMS Command Language Interpreter, National Character Set, Librarian, and Sort/Merge Utility routines. The specifications of these packages are in the VAX Ada library of predefined units (ADA$PREDEFINED). ¢ The package CONDITION_HANDLING provides a VAX Ada type for VMS condition values, a set of functions for interpreting condition value components, and a set of interface routines for calling the VMS Run-Time Library routines LIB$MATCH_COND, LIB$STOP, and LIB$SIGNAL. The specification of this package is in Appendix B, as well as in the VAX Ada library of predefined units (ADA$PREDEFINED). * The package SYSTEM_RUNTIME_TUNING allows you to tune aspects of run-time behavior that are normally controlled by the VAX Ada run- time library. The specification of this package is in Appendix B, as well as in the VAX Ada library of predefined units (ADA$PREDEFINED). e The VAX Ada import pragmas allow you to write your own interfaces to callable routines; the VAX Ada export pragmas allow you to write Ada subprograms that must be called by or passed as parameters to callable routines (as in the case of call-back routines). These pragmas are discussed in this chapter, in Chapter 5, and in Chapter 13 of the VAX Ada Language Reference Manual. To make copies of the specifications of any of the packages in the library of predefined units (ADA$PREDEFINED), use the ACS EXTRACT SOURCE command. For this command to succeed, either you must have defined ADASPREDEFINED as your current program library or you must have defined a current Ada program library into which the predefined units have been entered. See Developing Ada Programs on VMS Systems for more information. For example: $ ACS EXTRACT SOURCE STARLET The following sections explain how to call VMS system services, Run-Time Library, utility, and other callable routines, and give examples showing the use of the VAX Ada features for accomplishing such calls. You should be familiar with VAX Ada parameter passing and the VAX Procedure Calling and Condition Handling Standard, as well as with the VAX Ada import and 6-2 Calling System or Other Callable Routines export pragmas. See Chapter 5 of this manual and Chapter 13 of the VAX Ada Language Reference Manual for information on these topics. For specific information on the calling standard and VMS routines, see the appropriate VMS documentation: e The Introduction to VMS System Routines gives general information on VMS system routines, and includes the VAX Procedure Calling and Condition Handling Standard. e The VMS System Services Volume provides information on the VMS system service routines. e The VMS Record Management Services Manual provides information on the VMS RMS routines. e The VMS Run-Time Library Routines Volume provides information on the VMS Run-Time Library routines. e The VMS Utility Routines Manual provides information on the VMS utility routines. For specific information on callable interfaces for the various VAX layered products, see the products’ individual reference manuals. 6.1 Using the VAX Ada System-Routine Packages The VAX Ada predefined system-routine packages allow you to call system routines directly, without having to specify your own interfaces. The following sections discuss the characteristics and use of these packages. 6.1.1 Parameter Types As noted in the Introduction to VMS System Routines, the VMS environment provides a set of data structures (VMS usages) for denoting the VAX data types used in VMS system, VMS Run-Time Library, and utility routines. Table 6-1 lists these data structures and gives their VAX Ada equivalents. For information on the underlying VAX data types, see Chapter 5; for information on the representation of the VAX Ada data types, see Chapter 2. NOTE Many of the equivalents are defined in the packages STARLET and CONDITION_HANDLING. For convenience, the VMS RunTime Library and utility packages define subtype equivalents for the STARLET and CONDITION_HANDLING types used in those packages. Calling System or Other Callable Routines 6~3 Table 6-1: VMS Data Structures VMS Data Structure VAX Ada Equivalent access_bit_names STARLET.ACCESS_BIT NAMES_TYPE access_mode STARLET.ACCESS_MODE_TYPE address SYSTEM.ADDRESS address_range STARLET.ADDRESS_RANGE_TYPE arg_list STARLETARG_LIST TYPE ast_procedure SYSTEM.AST HANDLER boolean STANDARD.BOOLEAN byte_signed STANDARD.SHORT_SHORT_INTEGER byte_unsigned SYSTEM.UNSIGNED_BYTE channel STARLET.CHANNEL_TYPE char_string STANDARD.STRING complex_number User-defined record cond_value CONDITION_HANDLING.COND_VALUE_TYPE context STARLET.CONTEXT _TYPE date_time STARLET.DATE_TIME_TYPE device_name STARLET.DEVICE_NAME_TYPE efcluster_name STARLET.EF_CLUSTER_NAME_TYPE ef_number STARLET.EF_NUMBER_TYPE exit_handler_block STARLET.EXIT HANDLER_BLOCK_TYPE fab STARLET.FAB_TYPE file_protection STARLET.FILE_PROTECTION_TYPE floating_point STANDARD.FLOAT STANDARD.LONG_FLOAT STANDARD.LONG_LONG_FLOAT SYSTEM.F_FLOAT SYSTEM.D_FLOAT SYSTEM.G_FLOAT SYSTEM.H_FLOAT function_code STARLET.FUNCTION_CODE_TYPE identifier SYSTEM.UNSIGNED_LONGWORD io_status_block STARLET.IOSB_TYPE (continued on next page) 6—4 Calling System or Other Callable Routines Table 6-1 (Cont.): VMS Data Structures VMS Data Structure VAX Ada Equivalent item_list_pair SYSTEM.UNSIGNED_LONGWORD item_list_2 STARLET.ITEM_LIST_2 TYPE item_list_3 STARLET.ITEM_LIST_3_TYPE item_quota_list User-defined record lock_id STARLET.LOCK_ID_TYPE lock_status_block STARLET.LOCK_STATUS_BLOCK_TYPE lock_value_block STARLET.LOCK_VALUE_BLOCK_TYPE logical_name STARLET.LOGICAL_NAME_TYPE longword_signed STANDARD.INTEGER longword_unsigned SYSTEM.UNSIGNED_LONGWORD mask_byte SYSTEM.UNSIGNED_BYTE mask_longword SYSTEM.UNSIGNED_LONGWORD mask_quadword SYSTEM.UNSIGNED_QUADWORD mask_word SYSTEM.UNSIGNED_WORD null_arg SYSTEM.UNSIGNED_LONGWORD octaword_signed array(1..4) of SYSTEM.UNSIGNED_LONGWORD octaword_unsigned array(1..4) of SYSTEM.UNSIGNED_LONGWORD page_protection STARLET.PAGE_PROTECTION_TYPE procedure SYSTEM.ADDRESS process_id STARLET.PROCESS_ID_TYPE process_name STARLET.PROCESS_NAME_TYPE quadword_signed SYSTEM.UNSIGNED_QUADWORD quadword_unsigned SYSTEM.UNSIGNED_QUADWORD rights_holder STARLET.RIGHTS_HOLDER_TYPE rights_id STARLET.RIGHTS_ID_TYPE rab STARLET.RAB_TYPE section_id STARLET.SECTION_ID_TYPE section_name STARLET.SECTION_NAME_TYPE system_access_id STARLET.SYSTEM_ACCESS_ID_TYPE (continued on next page) Calling System or Other Callable Routines 6-5 VMS Data Structures Table 6-1 (Cont.): VMS Data Structure VAX Ada Equivalent time_name STARLET.TIME_NAME_TYPE uic STARLET.UIC_TYPE user_arg STARLET.USER_ARG_TYPE varying_arg SYSTEM.UNSIGNED_LONGWORD vector_byte_signed array(l..n) of STANDARD.SHORT_SHORT_INTEGER vector_byte_unsigned array(l..n) of SYSTEM.UNSIGNED_BYTE vector_longword_signed array(l..n) of STANDARD.INTEGER vector_longword_unsigned array(l..n) of SYSTEM.UNSIGNED_LONGWORD vector_quadword_signed array(l..n) of SYSTEM.UNSIGNED_QUADWORD vector_quadword_unsigned array(1..n) of SYSTEM.UNSIGNED_QUADWORD vector_word_signed array(1..n) of STANDARD.SHORT_INTEGER vector_word_unsigned array(1l..n) of SYSTEM.UNSIGNED_WORD word_signed array(l..n) of STANDARD.SHORT_INTEGER word_unsigned SYSTEM.UNSIGNED_WORD 6.1.2 Parameter-Passing Mechanisms The VMS system service, RMS, Run-Time Library, and utility routines conform to the VAX Procedure Calling and Condition Handling Standard. The VAX Ada system-routine packages ensure that the parameters for each routine are passed as required by the routine (by value, by reference, or by descriptor). See the appropriate VMS documentation for detailed information on the passing mechanisms for parameters of system routines. Table 6-1 lists the VAX Ada equivalents for the VMS data structures. See Chapter 5 for information on passing Ada parameters in mixed-language programs. NOTE Any parameter described in the VMS documentation as a routine passed by reference is declared in the VAX Ada packages as a parameter of type ADDRESS. To pass the address of an Ada subprogram, you must first export the subprogram with one of the VAX Ada export pragmas (see Chapter 5 of this manual and Chapter 13 of the VAX Ada Language Reference Manual). You 6-6 Calling System or Other Callable Routines can then use the ADDRESS attribute to obtain the address of the subprogram. An exported subprogram must be a library unit or must be declared at the outermost level of a library package. 6.1.3 Naming Conventions The following conventions are used in the VAX Ada predefined systemroutine packages to form names for named numbers, routine names, and record components: e In the package STARLET, underscores (_) are used instead of dollar signs ($) because dollar signs are not legal in Ada identifiers. In the VMS Run-Time Library and utility-routine packages, all symbols have had their package-specific prefix removed; for example, you access LIB$SPAWN as LIB.SPAWN. * Any double underscores are replaced by a single underscore. Leading and trailing underscores are removed. » If the resulting identifier is an Ada reserved word, the last character is dropped. For example, the system service EXIT becomes EXI, the DTK$TERMINATE routine becomes DTK. TERMINAT, and so on. Other Ada reserved words that are frequently used as record component names are ACCESS and TYPE, which become ACCES and TYP respectively. See Section 6.1.4 for information on the naming conventions used for record types and initialization constants. 6.1.4 Record Type Declarations The predefined system-routine packages contain type declarations for VMS control blocks, masks, and so on. For example, the package STARLET declares the following control blocks used by VMS RMS routines: e The file access block (FAB) e The record access block (RAB) e The extended attribute block (XAB) e The name block (NAM) Many VMS control blocks have a multilevel structure. For example, the package STARLET represents control blocks by defining a record type for each nested structure. The following record declaration shows a portion of the record type defined in STARLET for the FOP (file-processing options) field of a FAB (VMS RMS file access block); see the VMSS Record Calling System or Other Callable Routines 6-7 Management Services Manual for a description of the individual options. The name of the type begins with FAB_ to indicate that FAB_FOP_TYPE is a type declared for a component of a record of type FAB_TYPE. type FAB FOP TYPE is record FILLER_l : BOOLEAN; MXV : BOOLEAN; DLT : BOOLEAN; FILLER 3 : BOOLEAN; ESC : BOOLEAN; TEF : BOOLEAN; OF'P : BOOLEAN; KFO : BOOLEAN; FILLER_4 : BOOLEAN; end record; FAB_TYPE is declared in STARLET as a record type that contains a component called FOP whose type is FAB_FOP_TYPE: type FAB TYPE is record BID: UNSIGNED BYTE; BLN: UNSIGNED BYTE; FOP: FABFOP_TYPE; end record; The following example shows how you can access the FOP component: with STARLET; procedure MODIFY FOP (FABl : in out STARLET.FAB TYPE; FAB2 : in out STARLET.FAB TYPE) begin 6-8 —— Set —— those the of file processing FAB2. FAB1.FOP := FAB2.FOP; Calling System or Other Callable Routines options of FABl to is —— Set ~-—- associated with FAB2 the DLT option to indicate that FAB2.FOP.DLT := will be the file deleted when closed. TRUE; end MODIFY FOP; An initialization constant is also provided for each record type defined in the predefined system-routine packages to facilitate the initialization of objects of the type. The name of the constant is formed by appending _INIT to the type name. For example, the following declaration is a portion of the STARLET initialization constant for the type FAB_TYPE: FABTYPE_INIT : constant FAB TYPE (BID => FAB C_BID, BLN => FAB C_BLN, FOP => (FILLER 1 => FALSE, MXV => FALSE, => PFALSE, DLT := ), ) ; A typical use might be as follows: declare -~ FAB Initialize : STATUS FAB to contain STARLET.FAB TYPE : := standard FAB defaults. STARLET.FAB TYPE INIT; CONDITION HANDLING.COND VALUE_ TYPE; begin STARLET.OPEN (STATUS, FAB); end; Likewise, FAB_FOP_TYPE_INIT is defined in STARLET as a constant that you can use to initialize an object or component of the type FAB_FOP_TYPE. A portion of the definition in STARLET is as follows: Calling System or Other Callable Routines 6-9 FABFOP_TYPE INIT : constant (FILLER 1 => FALSE, MXV => FALSE, DLT => FALSE, FILLER 3 => FALSE, ESC => FALSE, TEF => FALSE, OFP => FALSE, KFO => FALSE, FILLER 4 => FAB FOP_TYPE := FALSE); Note that the component names used in this example for the FAB_FOP_ TYPE include several that begin with FILLER_. These names in this example and in similar record declarations in the VMS Run-Time Library and utility packages represent reserved fields that are currently unused, but that might be used in the future. The number of reserved fields in any particular record declaration is likely to change from one VMS release to another. Further, the names assigned to the reserved fields are also likely to change. For example, if a component called FILLER_3 were used in a new VMS release, the name of the FILLER_4 component would change to FILLER_3, and FILLER_4 would no longer exist. Thus, you should never explicitly refer to a component that begins with the text FILLER_ in your program. To initialize such components, use the initialization constants declared in the package you are using. For example, to initialize a variable of type FAB_FOP_TYPE, you would write the following: FOP : FAB FOP TYPE := FAB FOP_TYPE INIT; You can also use FAB_FOP_TYPE_INIT to initialize the FOP component of a FAB. For example: procedure MOD FOP (FAB : in out STARLET.FAB TYPE) is begin FAB.FOP := FAB FOP_TYPE INIT; end MOD FOP; Example 6—3 shows the use of some of the VMS RMS control blocks declared in the package STARLET. The example is a program that maps a file to the first available space using the VMS system service SYS$CRMPSC (Create and Map Section) and the VMS RMS routine SYS$OPEN. 6-10 Calling System or Other Callable Routines 6.1.5 Default and Optional Parameters As discussed in Chapter 5, all native-mode VAX languages, and VMS system service, RMS, Run-Time Library, and utility routines conform to a set of parameter-passing conventions called the VAX Procedure Calling and Condition Handling Standard. In accordance with the standard, each time an Ada subprogram or non-Ada routine is called, an argument list is passed. The first longword of the argument list contains a count of the number of arguments. Each successive longword entry represents one parameter; depending on the parameter-passing mechanism used, that parameter can be a 32-bit value, an address of an object, or an address of a descriptor. Many VMS system routines provide the notion of an optional parameter. By placing a zero in the argument list, you can “omit” an optional parameter that is normally passed by the reference or descriptor mechanism. For example, consider a routine that takes a single optional integer parameter, which is passed by reference. When this routine is called, the first longword contains the value 1, to indicate one argument, and the second longword of the argument list can contain either the value zero, to indicate that the parameter is omitted, or it can contain the address of a memory locatlon containing an integer value. NOTE Passing the value zero by reference (placing in the argument list the address of a memory location that contains the value zero) is different from placing the value zero in the argument list, and is often interpreted differently by the called routine. Ada provides the notion of a default parameter expression. This notion means that you can omit the parameter (specifically only a parameter of mode in) in a call, and a default parameter value is automatically supplied. The default parameter expression is evaluated each time the subprogram is called, so it is not feasible for the subprogram body to provide the default value if the value is not present—the default value must be provided as an actual parameter for every call. The VMS optional-parameter and the Ada default-parameter notions are not equivalent. The VMS system service, RMS, Run-Time Library, and utility routines permit the equivalent of optional in out or out parameters, but Ada allows only in parameters to have default expressions. Further, placing a zero in a VMS argument list to omit an argument can have a different interpretation from a zero passed by reference or a null string passed by descriptor. Calling System or Other Callable Routines 6-11 Also, VMS system service routines generally require a fixed number of arguments, and you must place a value of zero in the argument list to indicate that an optional parameter has been omitted. VMS RMS, Run-Time Library, and utility routines generally allow optional parameters to be indicated by shortened argument lists. Thus, the following rules are true for the routines in all of the VAX Ada predefined system-routine packages: * Default or optional in parameters that are passed by value are declared with a default, zero value. If you omit a parameter association for one such optional formal parameter, the zero value is placed in the argument list. * Default or optional in parameters that are passed by reference or descriptor to VMS system service routines are declared with a default expression using the VAX Ada NULL_PARAMETER attribute. If you omit a parameter association for one such optional formal parameter, the zero value is placed in the argument list, regardless of the parameterpassing mechanism normally used for the argument. * Optional in out or out parameters are overloaded. Two Ada procedure declarations are given for each optional parameter (and the pragma IMPORT_VALUED_PROCEDURE is used to map both Ada subprograms to the same VMS system service). The first declaration specifies the type to be used if an argument is to be passed to the routine; the second specifies the parameter as an in parameter of the type ADDRESS to be passed by value, and gives it a default value of ADDRESS_ZERO. If the original parameter is of the type ADDRESS, then the type UNSIGNED_ LONGWORD is used for the overloading. If the call uses named association, a default argument can be omitted entirely; if it uses positional association, either ADDRESS_ZERO or ADDRESS'NULL_PARAMETER must be specified. For routines with multiple in out or out parameters, overloadings are provided for all combinations, except where two parameters are closely related (for example, a string descriptor is used to hold an output string, and the related parameter is set to the string length). Because they generally fall at the end of the argument list and can be omitted, optional parameters to the VMS RMS routines in the package STARLET, as well as the VMS Run-Time Library and utility routines, follow one additional rule: * The FIRST_OPTIONAL_PARAMETER option is used in the pragma IMPORT_VALUED_PROCEDURE to identify the first parameter (of one or of a series of optional parameters) that can be omitted. Then, when 6-12 Calling System or Other Callable Routines a call to the routine is made, and one or more optional parameters are omitted from the end of the parameter list, a truncated argument list is passed. See the VAX Ada Language Reference Manual for more detailed information on the rules for using this mechanism. In summary, when calling a VMS system service, RMS, Run-Time Library, or utility routine with optional parameters, you should follow these steps: 1. Consult the appropriate VMS system service, RMS, Run-Time Library, or utility routine manual and determine which parameters you want to specify in the call and which you want to omit. 2. Examine the appropriate VAX Ada package for the first routine interface declaration (if it is overloaded) to determine the parameter types. If you are working with the package STARLET, you can also check Appendix B for the declarations of these parameter types. 3. Make the call using named association, giving only the arguments you want to pass. For example, the SYS$ASSIGN system service routine in the package STARLET has two optional parameters, ACMODE and MBXNAM. The parameter mode for ACMODE is in and the passing mechanism is value. Thus, a default value of zero is used to indicate that the value zero is to be placed in the argument list if this parameter is not specified in a call. The parameter mode for MBXNAM is also in, but the passing mechanism is descriptor (MBXNAM is of subtype DEVICE_NAME_TYPE, which is a subtype of STRING); thus a default expression of DEVICE_NAME_ TYPE'NULL_PARAMETER is used to indicate that the value zero is to be placed in the argument list if this parameter is not specified on a call. —-— - SASSIGN Assign I/0O Channel —— SASSIGN - devnam = address -— -= -= devnam ,chan , [acmode] , [mbxnam] of device name or logical name string descriptor chan = address of word to receive channel number assigned -- acmode = access mode associated with channel —- mbxnam = address of mailbox logical name string descriptor, if mailbox associated with device Calling System or Other Callable Routines 6-13 procedure ASSIGN ( STATUS : out COND_ VALUE TYPE; DEVNAM : in DEVICE NAME TYPE; CHAN : out CHANNEL TYPE; ACMODE : in ACCESS MODE TYPE : in DEVICE NAME TYPE DEVICE NAME pragma INTERFACE (EXTERNAL, pragma IMPORTVALUED PROCEDURE return -- 0 TYPE’NULL PARAMETER) ; ASSIGN); (ASSIGN, "SYS$ASSIGN", CHANNELTYPE, DEVICENAMETYPE), (VALUE, DESCRIPTOR(S), VALUE, value := (COND_VALUE_TYPE, DEVICE NAME TYPE, ACCESS_MODE_TYPE, value := ACCESS_MODE ZERO; MBXNAM —— REFERENCE, DESCRIPTOR(S))): A call to STARLET.ASSIGN that omits the ACMODE parameter, but not the MBXNAM parameter, looks like this (assume that the actual parameters STATUS_VAR, DEVNAM_VAR, CHAN_VAR, and MBXNAM_VAR were previously declared as variables elsewhere in the program): ASSIGN (STATUS => STATUS VAR, DEVNAM => DEVNAM VAR, CHAN => CHAN VAR, MBXNAM => MBXNAM VAR) ; Similarly, the SYS$DEQ system service routine in the package STARLET has four optional parameters: three (LKID, ACMODE, and FLAGS) are in parameters passed by value; one (VALBLK) is an in out parameter passed by reference. Thus, default values can be provided for LKID, ACMODE, and FLAGS, but an overloading declaration must be provided to allow the VALBLK parameter to be omitted. -— —— Dequeue Lock _ SDEQ [lkid] -— lkid lock ID of the lock to -- valblk address of the lock wvalue - acmode access mode of the -— flags —- 6—-14 $DEQ = , [valblk] optional , [acmode] flags LCK$M Calling System or Other Callable Routines DEQALL , be locks [flags] dequeued block to be dequeued procedure DEQ ( -— return value ID ZERO; := LOCK STATUS LKID : out COND_VALUE TYPE; ID TYPE : in LOCK VALBLK : in out LOCK VALUE_ BLOCK_TYPE; ACMODE : in FLAGS ACCESS MODE TYPE procedure DEQ := ACCESS MODE ZERO; := LCK_TYPE’NULL PARAMETER) ; LCK TYPE : in ( STATUS : out COND VALUE_TYPE; ID TYPE LOCK : in LKID VALBLK : in ADDRESS -— return value := LOCK_ID_ZERO; ¢:= ADDRESS ZERO; ACMODE FLAGS := ACCESS MODE ZERO; = LCK_TYPE’NULL_PARAMETER); --— To omit optional VALBLK argument : in : in ACCESS MODE_ TYPE LCK TYPE pragma INTERFACE (EXTERNAL, DEQ); pragma IMPORT VALUED PROCEDURE "SYS$DEQ", (DEQ, (COND _VALUE TYPE, LOCK_ID TYPE, ACCESS MODE_TYPE, LCK_TYPE), LOCKVALUE_BLOCK_TYPE, VALUE, VALUE)); pragma IMPORT VALUED PROCEDURE (DEQ, "SYSS$DEQ", (COND_VALUE TYPE, LOCK_ID TYPE, ADDRESS, (VALUE, VALUE, REFERENCE, S LCK_TYPE), MODE TYPE, ACCES (VALUE, VALUE, VALUE, VALUE, | VALUE)); A call to STARLET.DEQ that omits the LKID and ACMODE parameters looks like this (again, assume that the actual parameters were previously defined elsewhere in the program): DEQ => STATUS_ VAR, VALBLK => VALBLK VAR, (STATUS FLAGS => FLAGS_VAR); In this case, the first declaration would be used, and default, zero values would be supplied for the omitted LKID and ACMODE parameters. Alternatively, the following call involves the second declaration, and zeros would automatically be placed in the argument list for the VALBLK, ACMODE, and FLAGS parameters: DEQ STATUS_VAR, (STATUS => LKID => LKID VAR); Calling System or Other Callable Routines 615 The VMS RMS SYS$WRITE routine provides a good example of a STARLET interface for an RMS routine involving optional parameters: SWRITE - Write - Block SWRITE to rab, - rab -- File [err], [suc] = address of err il -— address of user error suc = address procedure WRITE rab of user completion success completion : out RAB : in out RAB TYPE; ERR : in AST HANDLER := NO_AST HANDLER; SUC : in AST HANDLER := NO_AST HANDLER) ; INTERFACE COND VALUE TYPE; (EXTERNAL, (COND VALUE TYPE, REFERENCE, RAB TYPE, VALUE, —-— return value WRITE); pragma IMPORT VALUED PROCEDURE (VALUE, routine ( STATUS pragma routine (WRITE, "SYSSWRITE", AST HANDLER, VALUE), AST HANDLER), ERR); Note that because the two optional parameters (ERR and SUC) are in parameters, they have default values; also, the pragma IMPORT_VALUED_ PROCEDURE specifies ERR as the first optional parameter. The following call involves all four parameters: WRITE (STATUS => STATUS VAR, RAB => RAB_VAR, ERR => ERR VAR, SuC => SUC_VAR) ; The next call omits the two optional parameters, and because the FIRST _ OPTIONAL_PARAMETER mechanism was specified in the routine interface, the argument list will be truncated so that the call involves only the two parameters specified: WRITE (STATUS RAB => STATUS_ VAR, => RAB_VAR) ; If you were to omit ERR, but not SUC, then a zero value would be passed in the argument list for ERR and the argument list would not be truncated. 6—-16 Calling System or Other Callable Routines 6.1.6 Calling Asynchronous System Services Some system services can be executed either synchronously or asynchronously. A synchronous service causes your program to wait while the service request is being processed. An asynchronous service queues a request and returns control to your program while the request is being processed. When the request is satisfied, the system service uses an AST to interrupt program execution and transfer control to a user-specified proce- dure. Examples of asynchronous services are SYS$GETJPI and SYS$QIO; their synchronous forms are SYS$GETJPIW and SYS$QIOW. The VMS System Services Reference Manual describes these system services in more detail. You can call asynchronous system services from a VAX Ada program by using tasks and the VAX Ada predefined pragma AST ENTRY and AST _ ENTRY attribute. See Chapter 9 of the VAX Ada Language Reference Manual and Chapter 8 for information on tasks and the pragma AST_ ENTRY and AST_ENTRY attribute. Chapter 8 also gives several examples of programs where ASTs are handled. Chapter 8 describes the package TASKING_SERVICES, which provides interface routines for calling services that involve AST parameters (SYS$QIO, SYS$GETJIPI, and so on) from tasks. Note that the subprogam specifications in the package TASKING_SERVICES have Ada bodies, and thus the NULL_PARAMETER attribute could not be used for optional parameters (see Sections 6.1.5 and 6.2.6). As a result, multiple overloadings are used for each combination of optional parameters in the same manner as is done for system services that have optional in out or out parameters. The package SYSTEM_RUNTIME_TUNING may also be useful with programs that call asynchronous system services. For example, this package provides operations that allow you to increase the size of the AST packet pool. See Chapter 8 for more information on the AST packet pool and its limitations; see Appendix B for the specification of the package SYSTEM_ RUNTIME_TUNING. 6.1.7 Calling Mathematical Routines VAX Ada provides two packages of operations for calling VMS Run-Time Library mathematical routines: e The package MATH_LIB—provides interfaces for many of the VMS Run-Time Library mathematical routines and declares exceptions that Calling System or Other Callable Routines 6-17 can be raised. The interfaces are streamlined for ease of use, rather than exactly matching the VMS Run-Time Library format. * The package MTH—also provides interfaces for many of the VMS RunTime Library mathematical routines and declares exceptions that can be raised. The interfaces match the VMS Run-Time Library format (for example, giving separate interfaces for MTH$ACOS, MTH$DCOS, and MTH$GCOS). The streamlining of the operations in the package MATH_LIB is possible because the package is a generic package that you can instantiate for real types. For convenience, VAX Ada also provides instantiated versions of this package for the types FLOAT, LONG_FLOAT, and LONG_LONG_FLOAT. For example, you could use the predefined instantiation FLOAT MATH_LIB as follows: with FLOAT MATH LIB; procedure TRIG_FUNCTIONS X, Y : FLOAT := is 3.0; begin Test sine-cosine := —— Find hyperbolic FLOAT MATH [ Y o -— FLOAT (FLOAT identity. MATHLIB.COS(X)**2 MATH —- Find hyperbolic Y := + FLOAT MATHLIB.SIN(X)**2; sine two ways. LIB.SINH(X); LIB.EXP(X) arc - FLOAT MATH LIB.EXP (-X))/2.0; sine. FLOAT MATH LIB.LOG(X + (FLOAT MATH LIB.SQRT(X**2 + 1.0))); end TRIG FUNCTIONS; If you had declared your own floating-point type, you could declare your own package to instantiate MATH_LIB, and then write a similar procedure as follows: with MATH LIB; package MYFLOATING is type MYFLOATING TYPE is digits package MYFLOATING MATH LIB 6; is new MATH LIB (MYFLOATING TYPE); end MYFLOATING; 6-18 Calling System or Other Callable Routines with MYFLOATING; use MYFLOATING; procedure TRIG FUNCTIONS X, Y : is MYFLOATING TYPE := 3.0; begin —— Test Y := sine—cosine identity. MYFLOATING_MATH LIB.COS (X)**2 + MY FLOATING_MATH LIB.SIN(X)**2; Find hyperbolic o o, —— sine two ways. MYFLOATING MATH LIB.SINH (X); (MY FLOATING MATH LIB.EXP (X) - MYFLOATING MATH LIB.EXP(-X))/2.0; —- Find hyperbolic Y := arc sine. MYFLOATING MATH LIB.LOG (X + (MYFLOATING MATH LIB.SQRT (X**2 end + 1.0))); TRIG FUNCTIONS; See Chapter 9 or Appendix A for more information on predefined Instantiations. 6.2 Writing Your Own Routine Interfaces When you need to write your own interface to a callable routine from VAX Ada, you must collect the following information about the routine: * The name of the routine ® The type of call required * The data type of each parameter * The type of access required for each parameter ¢ The mechanisms needed to pass the parameters * Whether any of the parameters are themselves routines or the addresses of routines * Whether or not any parameters are optional The description of the routine in the appropriate VMS or layered product documentation gives this information. Then, you must translate this information into Ada terms, write an equivalent Ada subprogram specification, and use the pragma INTERFACE and one of the VAX Ada import pragmas to import the routine so that you can call it as an Ada subprogram. Calling System or Other Callable Routines 6—19 For example, the system service SYS$TRNLNM (Translate Logical Name) routine has the following format: SYSSTRNLNM [attr], tabnam, lognam[,acmode] [,itmlst] The description of this system service indicates the following information: The routine returns a condition value and has parameters that may be updated, making this a special type of procedure call in VAX Ada. e The data types (VMS usages) required are mask_longword (for the attr parameter), logical_name (for the tabnam and lognam parameters), access_mode (for the acmode parameter), and item_list_3 (for the itmlst parameter). The usage for the condition value returned is cond_value. e The types of access required are read only (for all parameters) and write only (for the returned condition value). e The mechanisms needed are reference (for the atir, acmode, and itmlist parameters) and descriptor (for the tabnam and lognam parameters). e None of the parameters are themselves routines or addresses of routines. e The attr, acmode, and itmlst parameters are optional parameters. Note here that SYS$TRNLNM is a VMS system service, and system services require a fixed number of arguments. Thus, the method for omitting each of these parameters from the argument list is to place a zero in the argument list for each omitted parameter, rather than truncating or otherwise altering the list. The equivalent VAX Ada interface is as follows, assuming that LNM_TYPE, LOGICAL_NAME_TYPE, ACCESS_MODE_TYPE, and ITEM_LIST_3_ TYPE are defined in your program, and that you made use of the predefined packages SYSTEM and CONDITION_HANDLING: procedure TRNLNM STATUS: out ATTR in : ( CONDITION HANDLING.COND_ VALUE TYPE; LNM TYPE LNM TYPE’/NULL PARAMETER; TABNAM: in LOGNAM: in LOGICAL NAME TYPE; LOGICAL NAME TYPE; ACMODE: in ACCESS MODE TYPE ACCESS ITMLST: pragma 6—20 := in ITEMLIST 3 TYPE INTERFACE := MODE TYPE’NULL PARAMETER; (SYSSERV, Calling System or Other Callable Routines := TRNLNM) ; ITEM LIST 3 TYPE’NULL PARAMETER) ; pragma IMPORT VALUED PROCEDURE INTERNAL => TRNLNM, EXTERNAL => "SYSS$STRNLNM", PARAMETER TYPES (CONDITION ( => HANDLING.COND VALUE TYPE, LNM TYPE, LOGICAL NAME TYPE, LOGICAL NAME TYPE, ACCESS_MODE_TYPE, ITEM LIST MECHANISM 3 TYPE), => (VALUE, REFERENCE, DESCRIPTOR (CLASS => S), DESCRIPTOR (CLASS => S), REFERENCE, REFERENCE) ) ; The following sections give detailed information on writing VAX Ada interfaces for callable routine interfaces. For more information on the import pragmas and parameter-passing mechanisms, see Chapter 5. For complete examples of interfaces to system routines coded in Ada, see Section 6.5. 6.2.1 Parameter Types If you are writing your own interface for a VMS routine, see Table 6—1 for a list of the VMS data structures and their VAX Ada equivalents. If you are writing your own interface for another kind of callable routine, see Chapter 5 for information on the VAX Ada equivalents for the VAX data types defined in the VAX Procedure Calling and Condition Handling Standard. For information on the representation of the VAX Ada data types, see Chapter 2. 6.2.2 Determining the Kind of Call The Ada language provides two kinds of subprograms: * Procedures, which can have parameters that are updated within the body of the subprogram * Functions, which return results, but cannot update their parameters Calling System or Other Callable Routines 6-21 System routines must be imported into an Ada program before they can be called. VAX Ada provides the pragma INTERFACE and the import pragmas IMPORT PROCEDURE and IMPORT_FUNCTION to allow you to import external routines as procedures and functions, respectively. To pass an Ada procedure or function as a parameter to a system routine, you must first export the system routine (see Section 6.2.5). VAX Ada provides the export pragmas EXPORT_PROCEDURE and EXPORT_FUNCTION to allow you to export Ada subprograms as procedures and functions, respectively. However, because many system and utility routines return results and update their parameters, VAX Ada provides two pragmas designed specifically to import or export subprograms from or to system routines: ¢ The pragma IMPORT_VALUED_PROCEDURE (in combination with the pragma INTERFACE) allows you to write a VAX Ada interface that will import a routine so that it is interpreted as a procedure in the Ada environment and as a function in the external environment. (For example, all of the routine interfaces in the package STARLET involve the use of this pragma.) e The pragma EXPORTVALUED_PROCEDURE allows you to write a VAX Ada interface that will export an Ada procedure so that it is, again, interpreted as a procedure in the Ada environment and as a function in the external environment. Both pragmas expect the first parameter of the routine or subprogram being imported or exported to receive the result. Thus, the first parameter of the imported or exported “procedure” must be an out parameter. The result is returned in this parameter as any function value is returned (see Section 5.3.2.4). You can specify the other parameters with the modes in, in out, or out, according to the actions required by the imported or exported routine or subprogram. All import and export pragmas involve default parameter-passing mechanisms, as explained in Chapter 5. When you import a system routine, you should explicitly specify the appropriate mechanisms; when you export an Ada subprogram, you must be sure that the calling routine supplies the correct defaults expected by VAX Ada. The /WARNINGS=COMPILATION_ NOTES qualifier for any of the compilation commands (DCL ADA and ACS LOAD, COMPILE, and RECOMPILE) provides diagnostic information about the mechanisms chosen by the compiler for imported and exported subprograms. See Developing Ada Programs on VMS Systems for more information on that qualifier and those commands. 6—22 Calling System or Other Callable Routines When you are working with the pragma EXPORTVALUED_PROCEDURE, note that the first parameter in a subprogram exported with this pragma is passed by reference if the parameter type is an access type, or a type involving discriminants. This passing mechanism allows parameters of all types to be initialized by the calling routine, as is required by the Ada language for components of an access type or for any discriminants, even in the case of an out parameter like the first parameter in a subprogram exported with the pragma EXPORTVALUED_PROCEDURE. See Chapter 5 of this manual and Chapter 18 of the VAX Ada Language Reference Manual for more information on using the import and export pragmas. 6.2.3 Determining the Access Method The various kinds of access required by system and utility routine param- eters can be translated directly into Ada access modes. Table 6-2 lists the Ada equivalents for the three most common VMS access methods. Table 6-2: VAX Ada Equivalents for VMS Access Methods VMS Access Method VAX Ada Access Mode Read only in Write only out Modify in out The other access methods—function call (before return), JMP after unwind, call after stack unwind, and call without stack unwind—have no direct VAX Ada equivalents. Note that when you are using the pragma IMPORT VALUED PROCEDURE or the pragma EXPORT_VALUED_PROCEDURE to write a routine interface, the first parameter is reserved for a returned result. Thus, that parameter must have the mode out, or an access method of modify (it will usually correspond to a condition value or equivalent returned by the applicable routine or subprogram). Calling System or Other Callable Routines 6-23 6.2.4 Passing Parameters Most callable routines (system or layered product) conform to the VAX Procedure Calling and Condition Handling Standard; parameters are passed either by value, by reference, or by descriptor. You should explicitly specify the necessary passing mechanisms in any interface routine you write. See Chapter 5 for more information. 6.2.5 Passing Routines or Subprograms as Parameters Some system routines take as arguments the addresses of other routines or subprograms (for example, SYS$PUTMSGQG). To pass an Ada subprogram as a parameter to a system routine, the subprogram must be exported (see the discussion of export pragmas in Chapter 5 and Section 6.2.2). To be exported, a subprogram must be a library unit or must be declared in the outermost declarative part of a library package. You can then pass the subprogram’s address to the system routine with the Ada ADDRESS attribute. If you try to pass the address of a subprogram that is not exported, the compiler issues a warning message. Example 6—4 has an exported routine that is passed as a parameter to a VMS Run-Time Library routine. 6.2.6 Default and Optional Parameters To specify a default or optional parameter, choose one of the following methods, depending on the access mode of the parameter: e For an in parameter, use the VAX Ada NULL_PARAMETER attribute, which will place a zero in the argument list, regardless of the passing mechanism used for the argument. For addresses (parameters of type SYSTEM.ADDRESS) that are passed by value and that require default values, use the VAX Ada predefined constant SYSTEM.ADDRESS _ ZERO to place a zero value in the argument list. See Chapter 13 of the VAX Ada Language Reference Manual for more information about NULL_PARAMETER and ADDRESS_ZERO; see Section 6.1.5 for an explanation of how these mechanisms are used in the VAX Ada predefined system-routine packages. * 6—24 For in out or out parameters, you can use overloading. Calling System or Other Callable Routines e If the routine you are calling allows a truncated argument list, you can also use the FIRSTOPTIONAL_PARAMETER mechanism in whatever import pragma you are using to import the routine. Section 6.1.5 explains how overloading and FIRST_OPTIONAL_PARAMETER are used in the VAX Ada predefined system-routine packages. Chapter 13 of the VAX Ada Language Reference Manual gives detailed information on the FIRST_OPTIONAL_PARAMETER mechanism. Note that you can apply the FIRST_OPTIONAL_PARAMETER mechanism only to a formal parameter of mode in, and all parameters following that parameter must also be of mode in. 6.3 Obtaining Symbol Definitions Many of the global symbol definitions (condition values, and so on) you will need in calls to system routines are available in the predefined systemroutine packages. However, if you need to obtain symbol definitions that are not available from these packages, you can use the following function from the package SYSTEM: function return IMPORT VALUE (SYMBOL : STRING) UNSIGNED LONGWORD; This function returns the value of the specified (global) symbol. See Chapter 13 of the VAX Ada Language Reference Manual for a complete description of its syntax and behavior. The following example shows the use of the IMPORT_VALUE function to assign the value of the global symbol CMS$_CREATE to the constant CMS_CREATED. A complete example appears in Section 6.5. with SYSTEM; with CONDITION_HANDLING; procedure CREATE LIB —— Assign —— a constant CMS$_CREATED, CMS_CREATED: := is the value to allow a constant of later CONDITION the CMS check global for symbol success HANDLING.COND or failure. VALUE TYPE SYSTEM.IMPORT VALUE ("CMS$ CREATED") ; Calling System or Other Callable Routines 6-25 —— Use the imported condition value to check for success. if RET VAL -- Do /= CMS CREATED then something. else -- Do something else. end if; end CREATE LIB; 6.4 Testing Return Condition Values Many VMS system service, RMS, Run-Time Library, and utility routines return numeric status values that indicate whether or not they successfully completed the requested operation. The first parameter of all of the routines in the VAX Ada predefined system-routine packages is an out parameter, which is set to a status value when the routine finishes execution. This parameter is of the type COND_VALUE_TYPE, which is declared in the predefined package CONDITION_HANDLING. When a system status value is returned, you can test for success or failure by using one of the condition value evaluation functions provided in the package CONDITION_HANDLING. You can also compare the status value to one of the severity codes declared in the predefined package you are using, or you can compare it to one of the specific condition values that the service returns. You can make the latter comparison by using one of the interface routines for the VMS Run-Time Library routine LIB§MATCH_COND, which are also provided in the package CONDITION_HANDLING. For example, the following fragment from Example 6-1 uses the CONDITION_HANDLING function SUCCESS to test for successful logical name translation: procedure ORION is RET STATUS: COND VALUE TYPE; ITEM LIST ITEM LISTTYPE(1..2); : begin TABNAM 6—26 => RET_ STATUS, I TRNLNM (STATUS "LNM$SYSTEM", LOGNAM => "CYGNUS", ITMLST => ITEM LIST); Calling System or Other Callable Routines if not CONDITION_HANDLING.SUCCESS(RET_STATUS) ~- Ralse an then error. else —— Get the name and size and print them out. end if; end ORION; Alternatively, you can compare the severity of the status value with one of the following constants (defined in the package STARLET): STS_K_WARNING STS_K _SUCCESS STS_K_ERROR STS_K_INFO STS_K _SEVERE For example: procedure ORION is RET STATUS: COND VALUE TYPE; ITEM LIST ITEM LIST TYPE(1l..2); : begin > RET TABNAM > "LNM$SYSTEM", > "CYGNUS", i LOGNAM I TRNLNM (STATUS ITMLST STATUS, > ITEM LIST); if CONDITION HANDLING.SEVERITY (RET_STATUS) -— Raise /= STS KSUCCESS then an error. else —-— Get the name and size and print them out. end if; end ORION; Finally, you can use the function CONDITION_HANDLING.MATCH_COND to test the return status for other condition values (also defined in the package STARLET). For example: with SYSTEM; with STARLET; use use SYSTEM; STARLET; with CONDITION HANDLING; with TEXT I0; use CONDITION HANDLING; use TEXT I0O; Calling System or Other Callable Routines 6-27 procedure ORION RET STATUS: is COND MATCH VALUE: ITEM LIST: ERROR: VALUE TYPE; INTEGER; ITEM LIST TYPE(1l..2); exception; begin TRNLNM (STATUS if not => RET STATUS, TABNAM => "LNMS$SYSTEM", LOGNAM => "CYGNUS", ITMLST ITEMMLIST); => CONDITION_HANDLING.SUCCESS(RET_STATUS) then —-— Locate -— given the error; in module MATCH VALUE := condition $SSDEF value codes in the package are STARLET. CONDITION_HANDLING.MATCHmCOND ( RET STATUS, SS_IVLOGTAB, SS_NOLOGNAM) ; —-- Raise an error exception. raise ERROR; else -- Print out the logical name and its size. translate logical name"); end if; exception when ERROR => PUTLINE("Failed to case MATCH VALUE when 1 => is PUT LINE ("TABNAM is "logical when 2 => PUT LINE ("Logical "the when others name not a " & name table"); name is not in " & table"); => null; end case; end ORION; To look at the various condition value components, you can use the set of functions provided by the package CONDITION_HANDLING (see Appendix B). 6—-28 Calling System or Other Callable Routines 6.5 VMS Routine Examples Examples 6—1 through 6-7 show the use of the package STARLET and import and export pragmas to make calls to various VMS system service and Run-Time Library routines. Example 6—1: Calling SYS$TRNLNM Using the Package STARLET with SYSTEM; with STARLET; with CONDITION HANDLING; with TEXT IO; with SHORTINTEGER TEXT IO; use procedure use TEXT IO; ORION —— Declare short string -- translated logical subtype —— storage Pragma VOLATILE -- is --— a for STRING(1l..255); logical specifies to the wvariables local NAME subtype used in retrieving name. SHORT STRING is -- Declare SHORT_INTEGER TEXT IO; is name and name that in memory, BUFFER: SHORT_ INTEGER; (NAME BUFFER); pragma VOLATILE (NAME SIZE); —-— Initialized item list. Zeros —— indicate list. ITEM;LIST: 2 => rather than to SHORT STRING; : pragma VOLATILE => size. read copy. NAME SIZE (1 every the end of the in the STARLET.ITEM_LISTWTYPE(1..2) last element = (BUF_LEN => NAME BUFFER’LENGTH, ITEM CODE => STARLET.LNM STRING, BUF_ADDRESS => NAME_BUFFER’ADDRESS, RET ADDRESS => NAME_SIZE'ADDRESS), (BUF_LEN => 0, ITEM CODE => 0, BUF ADDRESS => SYSTEM.ADDRESS ZERO, RET ADDRESS => SYSTEM.ADDRESS~ZERO)); —— Variable for receiving returned condition value. RET CONDITION HANDLING.COND VALUE TYPE; STATUS: (continued on next page) Calling System or Other Callable Routines 6-29 Example 6-1 (Cont.): Calling SYS$TRNLNM Using the Package STARLET begin the system service; STARLET.TRNLNM (STATUS TABNAM —-— Logical -- completion. if not default values are for ATTR and ACMODE. test > RET > "LNM$SYSTEM", 1 supplied i Call STATUS, LOGNAM > "CYGNUS", ITMLST > ITEM LIST); for i —— -— successful or unsuccessful CONDITION_ HANDLING.SUCCESS (RET_STATUS) then PUTLINE("Failed to translate logical name"); else —-— Output wvalues PUT ("Logical name translates PUT (NAME BUFFER(1 .. PUT ("Logical size name PUT(NAME”SIZE); NEWmLINE; end if; end ORION; 6-30 Calling System or Other Callable Routines to """); INTEGER(NAME SIZE))); is "); Example 6—2: Calling SYS$GETQUI Using the Package STARLET —- This program prompts —— and displays -— a -- job job size size, for a queue information on of 50 blocks user name, all name or more. and (wildcards print It Jjob name jobs are in output also displays information for acceptable) queues queue each with name, job listed. with SYSTEM, STARLET, CONDITION HANDLING, TEXT IO, INTEGER TEXT IO; use SYSTEM, STARLET, CONDITION HANDLING, TEXT IO, INTEGER TEXT IO; procedure GETQUI EXAMPLE is QUEUE_ITEM LIST: ITEM LIST TYPE JOB_ITEM ITEM ITEM LIST LIST : END IOSB (1..4); (1..6); LIST TYPE : ITEM REC TYPE : IOSB_TYPE; := (0,0,ADDRESS ZERO,ADDRESS ZERO); SEARCH NAME, QUEUE NAME : STRING (1..31); JOB_NAME : STRING (1..39); USER_NAME : STRING (1..12); SEARCH QUEUE JOB NAME LEN: NAME LEN NATURAL; : NAME LEN, USER NAME LEN UNSIGNED WORD; : UNSIGNED WORD; SEARCH FLAGS: QUI_SEARCH FLAGS TYPE JOB_STATUS : QUI_JOB JOB_SIZE : INTEGER; RET STATUS QUEUE, Request queue := QUI SEARCH FLAGS TYPE_INIT; STATUS TYPE; RETSTATUS JOB : COND VALUE TYPE; queue operation. begin -PUT ("Enter GET LINE —— queue 2 => name item list QUEUE ITEM LIST => to (SEARCH NAME, Initialize 1 name := search. to search: "); SEARCH NAME LEN) ; for the display ( (ITEM CODE => QUI SEARCH NAME, BUF LEN => UNSIGNED WORD (SEARCH NAME LEN), BUF ADDRESS => SEARCH NAME’ADDRESS, RET ADDRESS => ADDRESS ZERO), (ITEM CODE => QUI SEARCH FLAGS, BUF _LEN => BUF ADDRESS => SEARCH FLAGS’ADDRESS, RET ADDRESS => 4, ADDRESS ZERO), (continued on next page) Calling System or Other Callable Routines 6-31 Calling SYS$GETQUI Using the Package STARLET Example 6—2 (Cont.): 3 4 —— => (ITEM_ CODE => QUI BUF _LEN => 31, BUF ADDRESS => QUEUE NAME'ADDRESS, RET ADDRESS => QUEUE NAME LEN’ADDRESS), ITEM => Initialize 1 => => ( => 4, BUF_ADDRESS => SEARCH_FLAGS’ADDRESS, => ADDRESS_ZERO), => QUI_JOB_SIZE, ADDRESS (ITEM CODE 5 6 => => => => 4, BUF_ADDRESS => JOB_SIZE’ADDRESS, => ADDRESS_ZERO), (ITEM CODE => QUI_JOB_NAME, BUF _LEN => 39, BUF => JOB_NAME’ADDRESS, ADDRESS ADDRESS => JOB_NAME LEN’ADDRESS), (ITEM_CODE => BUF LEN => 12, BUF_ADDRESS => USER_NAME’ ADDRESS, QUI_USERNAME, RET ADDRESS => USER_NAME (ITEM CODE => QUI_JOB_STATUS, BUF _LEN => 4, BUF ADDRESS => JOB_STATUS’ADDRESS, RET ADDRESS => ADDRESS_ZERO), ITEM LEN’ADDRESS), LIST END); —- Request —— force wildcard mode search of --— block after the —— entered -- subsequent (this all jobs present first call when action preserves display in to maintain the FLAGS.SEARCH WILDCARD TRUE ; SYMBIONT TRUE; TRUE; —— context GETQUIW FUNC (STATUS => internal => RET also search context queue SEARCH_FLAGS.SEARCH ALL JOBS any queues; a nonwildcard queue name the SEARCH_FLAGS.SEARCH Dissolve output internal context is for the job operation). Il SEARCH QUI_SEARCH_ FLAGS, LEN RET ADDRESS 4 job operation. => RET = display BUF _LEN BUF 3 := for the (ITEM_CODE RET 2 LIST END); item list JOB_ITEM LIST QUEUE NAME, search STATUS block for the process. QUEUE, QUI_CANCEL OPERATION) ; (continued on next page) 6-32 Calling System or Other Callable Routines Example 6-2 (Cont.): Calling SYS$GETQUI Using the Package STARLET -- Locate next output queue; —— loop until an error status is returned. while SUCCESS GETQUIW if (RET STATUS QUEUE) loop (STATUS => RET STATUS QUEUE, FUNC => QUI DISPLAY QUEUE, ITMLST => QUEUE ITEM LIST, I0SB => TOSB) ; SUCCESS (RET STATUS QUEUE) RET STATUS QUEUE := then SEVERITY (IOSB.STATUS) ; end if; if SUCCESS (RET STATUS QUEUE) then NEW_ LINE; PUT ("Queue PUT LINE RET -- name STATUS _JOB Get "); := (1l..INTEGER(QUEUE NAME LEN))):; SS_NORMAL; information on next —— until while = (QUEUE NAME error SUCCESS GETQUIW job in queue; (RETSTATUS_JOB) loop (STATUS => RET_ STATUS_ JOB, FUNC => QUI DISPLAY JOB, ITMLST => JOB_ITEM LIST, IOSB => TOSB) ; if SUCCESS loop return. (RET STATUS JOB) RETSTATUS JOB then := SEVERITY (IOSB.STATUS) ; end if; if SUCCESS PUT PUT if (RET STATUS JOB) (" Job size = (JOB_SIZE, and (JOB SIZE > 50) then "); WIDTH => 5); JOBSTATUS.JOB_INACCESSIBLE then PUT LINE (" <no read access privilege>"); else PUT (" PUT (USER NAME Username = "); (1..INTEGER(USER NAME LEN))); SET_COL (46); PUT (" Job name = "); PUT LINE (JOB NAME (1..INTEGER(JOB_NAME LEN))); end if; end if; end loop; end if; end loop; end GETQUI EXAMPLE; Calling System or Other Callable Routines 6-33 Example 6-3: with SYSTEM; Calling SYS$CRMPSC Using the Package STARLET use SYSTEM; with STARLET; with CONDITION HANDLING; with TEXT IO; use TEXT IO; procedure MAP FILE is NAME constant STRING : START LOC, END_LOC : := "map file.ada"; ADDRESS; FAB : STARLET.FAB TYPE XAB : STARLET.XAB TYPE (STARLET.XAB C FHC) := := STARLET.FAB TYPE INIT; STARLET.XABFHC INIT; pragma VOLATILE (FAB) ; pragma VOLATILE (XAB) ; STATUS : CHANNEL CONDITION_ HANDLING.COND VALUE TYPE; STARLET .CHANNEL TYPE; RETADR, INADR : STARLET.ADD RANGE RESS TYPE; begin START LOC := END LOC ADDRESS ZERO; —— First, := ADDRESS ZERO; open the file. FAB.FNA := NAME’ADDRESS; FAB.FNS := FAB.FOP.UFO FAB.XAB := NAME’ LENGTH; := TRUE; XAB’'ADDRESS; STARLET.OPEN (STATUS, FAB):; (continued on next page) 6-34 Calling System or Other Callable Routines Example 6-3 (Cont.): if Check for format is the Calling SYS$CRMPSC Using the Package STARLET file’s existence and, if it exists, that its CONDITION_HANDLING.SEVERITY (STATUS) /= STARLET.STS K SUCCESS correct. then PUT LINE ("Cannot find file"); else if (FAB.ORG (not /= STARLET.FAB FAB.RAT.CR) (FAB.RFM /= C_SEQ) or else or else STARLET.FAB C VAR) then PUT LINE ("File is in the wrong format"); else CHANNEL := —— map Now, STARLET.CHANNEL TYPE (FAB.STV) ; INADR (0) INADR (1) it to the Check -- the space. ADDRESS ZERO; to => STATUS, INADR => INADR, RETADR => RETADR, FLAGS => STARLET.SEC M EXPREG, CHAN => CHANNEL) ; see if mapping worked; starting if not available ADDRESS ZERO; := STARLET . CRMPSC (STATUS —— first and if it did, calculate ending points. CONDITION HANDLING.SUCCESS (STATUS) then PUT LINE ("CRMPSC failed"); else START LOC := if XAB.FFB /= RETADR (0) ; 0 END_LOC il then RETADR (0) + + INTEGER (XAB.EBK-1)*512 INTEGER (XAB.FFB) ; else END_ LOC RETADR(0) + INTEGER(XAB.EBK) *512; end if; end if; end if; end if; end MAP FILE; Calling System or Other Callable Routines 6-35 Example 6-4: Calling LIB$FILE_SCAN and LIB$FILE_SCAN_END Using the Package LIB —— This example uses the following LIB$ routines: -— LIBSFILE SCAN Scans a wildcarded file - returning each -— LIBSFILE SCAN END Terminates —— This example contains three specification, file. scan. compilation units: —-— LIBEXAMPLE SCAN SUCCESS To be success of scan. -— LIB_EXAMPLE SCAN FAILURE To be called on failure of scan. —-— Main program. LIB _EXAMPLE called on -- The -—- subprograms are separate compilation units because they function as callable routines. Because the callback routines ——- are passed as parameters using the ADDRESS -—- be exported. Exported subprograms —-—- subprograms (separate compilation units) -— a -- LIB_EXAMPLE SCAN SUCCESS: —— successful is with use must be they must library or must be declared in library package. lookup of -- address of the FAB, -- attribute, (routines) extracted SYSTEM, TEXT a is called by every from LIBSFILE SCAN. from whose NAM block the (starting at STARLET, This procedure file the It is passed the file specification device). TEXT IO; IO; procedure LIBEXAMPLE SCAN SUCCESS (FAB : STARLET.FAB TYPE) is (continued on next page) 6-36 Calling System or Other Callable Routines Example 6—4 (Cont.): Calling LIB$FILE_SCAN and LIB$FILE_SCAN_END Using the Package LIB -- Declare the NAM block, —-— the NAM : and point it to the address in FAB. STARLET.NAM TYPE; for NAM use at FAB.NAM; -- Declare the -- position LEN : length of in memory constant the string, and determine its starting (NAM.L DEV). INTEGER := INTEGER (NAM.B DEV)+INTEGER (NAM.B DIR)+ INTEGER (NAM.B NAME) +INTEGER (NAM.B TYPE)+INTEGER (NAM.B VER) ; STR : for STR use STRING (1l..LEN); at NAM.L DEV; begin PUT end LINE (STR):; LIBEXAMPLE SCAN SUCCESS; pragma EXPORT INTERNAL PROCEDURE => ( LIBEXAMPLE SCAN SUCCESS); -— LIB_EXAMPLE SCAN FAILURE: —-— failure with SYSTEM, use This procedure is called for every reported by LIBSFILE SCAN., STARLET, TEXT IO; TEXT IO; procedure LIBEXAMPLE SCAN FAILURE (FAB : STARLET.FAB TYPE) is begin PUT end LINE pragma EXPORT PROCEDURE INTERNAL -— ("Failure");:; LIBEXAMPL SCAN FAILURE; E LIB => EXAMPLE: ( LIBEXAMPLE SCAN FAILURE); The main with SYSTEM, with LIBEXAMPLE SCAN SUCCESS, use STARLET, program that LIB, directs the CONDITION HANDLING, file scan. TEXT IO; LIBEXAMPLE SCAN FAILURE; TEXT IO; procedure LIB EXAMPLE is (continued on next page) Calling System or Other Callable Routines 6-37 Example 6—4 (Cont.): -— Declare Calling LIB$FILE_SCAN and LIB$FILE_SCAN_END Using the Package LIB FAB, NAM, buffers, MY FAB : STARLET.FAB TYPE; MY NAM : STARLET.NAM TYPE; ESS BUFFER, MYCONTEXT STATUS : RSS BUFFER : to be (l..STARLET.NAM C MAXRSS); string to contain the wildcarded list of files searched. FILE SPECIFICATION —— STRING TYPE; CONDITION_ HANDLING.COND VALUE TYPE; —— Declare the -—- : LIB.CONTEXT and context. Rename function "=" "=" : constant to make the code (LEFT, : RIGHT STRING := "SYSSLIBRARY:*RTL*,*"; read better. SYSTEM.UNSIGNED_ LONGWORD) return BOOLEAN renames -- Import the RMS$ -—- the RMS SYSTEM."="; NMF (no more files) value for testing after call to LIB$FILE~SCAN. NMEF' : constant CONDITION_ HANDLING.COND_ VALUE SYSTEM.IMPORT VALUE TYPE := ("RMS$ NMF"); begin MYCONTEXT := -- Initialize MY FAB := 0; and set up FAB. STARLET.FAB TYPE INIT; MYFAB.FNA := FILESPECIFICATION’ADDRESS; MYFAB.FNS := FILESPECIFICATION’LENGTH; MYFAB.NAM := MYNAM’ADDRESS; -— Initialize MY NAM := and set up NAM. STARLET.NAM TYPE INIT; MYNAM.RSA := MY NAM.RSS := RSS_BUFFER’ADDRESS; SYSTEM.UNSIGNED MY NAM.ESA := ESS MY NAM.ESS := SYSTEM.UNSIGNED BYTE (ESS_BUFFER’ LENGTH) ; -— OQutput a title. PUT ("Files LINE BYTE (RSS_BUFFER’ LENGTH) ; BUFFER’ ADDRESS; that match " & FILE SPECIFICATION & ":"); NEW LINE; (continued on next page) 6-38 Calling System or Other Callable Routines Example 6-4 (Cont.): —— Scan for the LIB.FILE SCAN Calling LIBSFILE_SCAN and LIB$FILE_ SCAN_END Using the Package LIB wildcarded files, and handle errors. ( STATUS => STATUS, FAB => MY FAB, USER_SUCCESS_PROCEDURE => LIB EXAMPLE SCANSUCCESS’ADDRESS, USER_ERROR PROCEDURE => LIB EXAMPLE CONTEXT => MY SCANFAILURE’ADDRESS, CONTEXT) ; if (STATUS /= RMS_NMF) and then (not CONDITION HANDLING.SUCCESS CONDITION_HANDLING.SIGNAL (STATUS)) then (STATUS) ; end if; ~- Scan done. End LIB.FILE SCAN END it correctly. ( STATUS => FAB => MY FAB, CONTEXT => MY CONTEXT) ; if not STATUS, CONDITION HANDLING.SUCCESS CONDITION HANDLING.SIGNAL (STATUS) then (STATUS) ; end if; end LIB EXAMPLE; Calling System or Other Callable Routines 6-39 Example 6-5: —— This program demonstrates -— package —-— Calling SMG Routines Using the Package SMG SMG. The SMG.SELECT_FROM MENU -— uses routines -- selections. SMG.DELETE PASTEBOARD SMG, When the user SYSTEM, procedure to an application that from the menu, clears the the user’s terminal. is subtype STRINGARRAY TYPE CHOSEN: STRING ARRAY __TYPE; the is -— To —- the —-- defines —— CHOICES_ STRINGARRAYTYPE, -- of STRING(1..9):; SMG.CREATE MENU generic package both the routine, you must SMG. CREATE _MENUPKG. SMG.CREATE MENU which routine is an This instantiate package and the type unconstrained array strlngs package LEN create the user to make multiple exits routine VAX Ada predefined SMG.CREATE MENU and CONDITION HANDLING; SMG EXAMPLE call of the the a vertical menu and allows —— with the use program uses MY => CREATE MENU is new SMG.CREATE MENU PKG ( STRING ARRAY TYPE’LENGTH) ; MENU_CHOICES: MY CREATE ( " ONE MENU.CHOICES STRING ARRAY TYPE(1..21) n ’ L1 TWO " ’ "FIVE ", "SIX "NINE ", "TEN "THIRTEEN ", "SEVENTEEN" "BExit n) RET STATUS: " THREE n ’ "FOUR " ’ ", "SEVEN ", "EIGHT ", ", "ELEVEN ", "TWELVE ", "FOURTEEN ", "FIFTEEN ", "SIXTEEN ", "EIGHTEEN "4 "NINETEEN ", "TWENTY " L4 CONDITION_ HANDLING.COND PASTEBOARD ID: SYSTEM.UNSIGNED DISPLAY1l ID, DISPLAYZ2 ID: KEYBOARD ID: SYSTEM.UNSIGNED COUNTER: VALUE := TYPE; LONGWORD; SYSTEM.UNSIGNED LONGWORD; LONGWORD; SYSTEM.UNSIGNE WORD D := 0; begin —— Create —— appear. SMG.CREATE the pasteboard PASTEBOARD on which the wvirtual displays will ( STATUS PASTEBOARD ID => RET STATUS, => PASTEBOARD 1ID); (continued on next page) 640 Calling System or Other Callable Routines Example 6-5 (Cont.): -— Create the Calling SMG Routines Using the Package SMG virtual SMG.CREATE VIRTUAL keyboard to allow => RET_ STATUS, KEYBOARD 1ID => KEYBOARD ID); -- Create show the menu two SMG.CREATE virtual user. displays: one for the menu, and one to choices. VIRTUAL DISPLAY ( STATUS => NUMBER OF ROWS RET_ STATUS, => 10, NUMBER OF COLUMNS => 20, DISPLAY ID => DISPLAY1 ID, DISPLAY ATTRIBUTES => SMG.M BORDER, => SMG.M BOLD) VIDEO from the KEYBOARD ( STATUS —- input ATTRIBUTES ; SMG.CREATE VIRTUAL DISPLAY ( STATUS => RET STATUS, NUMBER OF ROWS => 6, NUMBER OF COLUMNS => 20, DISPLAY ID => DISPLAY2 ID, DISPLAY ATTRIBUTES => SMG.M BORDER) ; —-— Paste —— can the be SMG.PASTE virtual seen on VIRTUAL the user’s => ID PASTEBOARD to the ID DISPLAY2 ID, => PASTEROARD 1ID, PASTEBOARD ROW => 17, GOLUMN => 20) ; VIRTUAL that they DISPLAY ( STATUS DISPLAY (so RET STATUS, => PASTEBOARD SMG.PASTE pasteboard terminal). DISPLAY ( STATUS DISPLAY displays ID => RET STATUS, => DISPLAY1l ID, PASTEBOARD ID, PASTEBOARD ID => PASTEBOARD ROW => 4, PASTEBOARD COLUMN => 20) ; (continued on next page) Calling System or Other Callable Routines 6—41 Example 6-5 (Cont.): Calling SMG Routines Using the Package SMG —- Create the vertical menu, -— "TWENTY" with its 21 choices ("ONE" through and "Exit"). MY CREATE MENU.CREATE_MENU ( => RET STATUS, STATUS ID, => DISPLAYl DISPLAY ID MENU_TYPE => MENU CHOICES, => SMG.K VERTICAL, RENDITION SET => SMG.M_ BOLD, CHOICES RENDITION COMPLEMENT => SMG.M BOLD) ; ~-- Loop while the user chooses items from the menu using the up -- and down arrows and the return key; after each choice, the -- choice name is output on the screen, and then the default ~— choice reverts to the first item left on the menu. -- The choice "Exit" must be chosen to exit from the menu. When -—- "Exit" is chosen, the pasteboard and its two displays are -- deleted, and program execution is completed. while INTEGER (COUNTER) <= 21 SMG.SELECT FROM MENU STATUS KEYBOARD ID ( DISPLAY ID loop => RET STATUS, 1ID, => KEYBOARD ID, => DISPLAY1l SELECTED CHOICE_NUMBER => COUNTER, FLAGS => SMG.M REMOVE_ ITEM, ; SELECTED_CHOICE_STRING => CHOSEN) if CHOSEN = "Exit " then SMG.DELETE_PASTEBOARD ( => RET STATUS, STATUS ID => PASTEBOARD_ID); PASTEBOARD exit; end if; SMG.PUT LINE ( => RET STATUS, STATUS ID, ID => DISPLAY2 DISPLAY ; => CHOSEN) TEXT end loop; end SMG_EXAMPLE; 6-42 Calling System or Other Callable Routines Example 6-6: Calling SYS$TRNLNM Using an Import Pragma with SYSTEM; with CONDITION HANDLING; with TEXT with SHORT INTEGER TEXT IO; use IO; procedure use ORION —— Declare —-— translated subtype TEXT IO; short string logical SHORT STRING —— Declare -— The storage of --— than the is for variables to a local subtype logical must be SHORT_ STRING; SIZE SHORT pragma VOLATILE (NAME SIZE) ; subtypes for LOGICAL NAME TYPE is type the VMS size. read rather SYSSTRNLNM parameters. subtype ACCESS MODE TYPE Define name every INTEGER; VOLATILE (NAME BUFFER) ; ——- and that to memory, pragma subtype retrieving copy. BUFFER: Declare name specifies NAME —-— in STRING(1l..255); NAME : used name. pragma VOLATILE —— SHORT INTEGER TEXT IO; is is item list ITEM REC TYPE STRING; SYSTEM.UNSIGNED WORD; type. is record BUF LEN ITEM CODE : SYSTEM.UNSIGNED WORD; : SYSTEM.UNSIGNED WORD; BUF ADDRESS: SYSTEM.ADDRESS; RET SYSTEM.ADDRESS; ADDRESS: end record; type ITEM LIST TYPE array (NATURAL —— Declare —— be constant specified LNM STRING : in is range <>) of ITEM REC TYPE; representing the constant an item code to item list. := 2; (continued on next page) Calling System or Other Callable Routines 6—43 Example 66 (Cont.): —-— Initialized —— indicate ITEM LIST: (1 => Calling SYS$TRNLNM Using an Import Pragma item list. the ITEM => CODE RET => ADDRESS in the last element list. ITEM LISTTYPE(1l..2) (BUF_LEN BUF_ADDRESS 2 Zeros end of the NAME := BUFFER’ LENGTH, => LNM STRING, => NAMEBUFFER’ADDRESS, => NAME SIZE’ADDRESS), (BUF_LEN => 0, ITEM => 0, BUF ADDRESS => SYSTEM.ADDRESS ZERO, RET => SYSTEM.ADDRESS_ZERO)); CODE ADDRESS —— Variable for receiving RET STATUS: CONDITION_ HANDLING.COND VALUE TYPE; —— Specify the -—- system service. procedure Ada procedure TRNLNM STATUS: out ATTR in : returned condition value. that corresponds to the ( CONDITION_HANDLING.COND VALUE TYPE; SYSTEM.UNSIGNED LONGWORD 1= SYSTEM. UNSIGNED_LONGWORD NULL PARAMETER; TABNAM: in LOGNAM: in LOGICAL NAME TYPE; LOGICAL NAME TYPE; ACMODE: in ACCESS MODE TYPE ACCESS ITMLST: in MODE ITEM LIST := TYPE’NULL TYPE PARAMETER; := ITEM LISTTYPE’NULIL PARAMETER) ; (continued on next page) 644 Calling System or Other Callable Routines Example 66 (Cont.): Calling SYS$TRNLNM Using an Impbrt Pragma —— Use the pragmas -— up the set —— Note INTERFACE interface and to the IMPORT VALUED PROCEDURE actual system the specification of parameter-passing mechanisms -- by means of the pragma IMPORT VALUED PROCEDURE. pragma INTERFACE pragma IMPORT VALUED PROCEDURE INTERNAL => (SYSSERV, to service. TRNLNM) ; ( TRNLNM, EXTERNAL => "SYS$TRNLNM", PARAMETER TYPES => (CONDITION HANDLING.COND VALUE TYPE, SYSTEM.UNSIGNED LONGWORD, LOGICAL NAME TYPE, LOGICAL NAME TYPE, ACCESS MODE TYPE, ITEM LIST TYPE), => MECHANISM (VALUE, REFERENCE, DESCRIPTOR(S), DESCRIPTOR(S), REFERENCE, REFERENCE) ) ; begin —— Call the system service; default values for ATTR and ACMODE. TRNLNM (STATUS > RET TABNAM It supplied > "LNM$SYSTEM", LOGNAM il —- ITMLST are | STATUS, > "CYGNUS", > ITEM LIST); (continued on next page) Calling System or Other Callable Routines 6-45 Example 6—6 (Cont.): —— Logical —-— completion. if not test Calling SYSSTRNLNM Using an Import Pragma for successful or unsuccessful CONDITIONHANDLING.SUCCESS (RET_ STATUS) then PUT LINE ("Failed to translate logical name"); else == Qutput wvalues. PUT ("Logical name translates PUT (NAME BUFFER(1 .. PUT ("Logical size name to """); INTEGER(NAME is SIZE))); "); PUT (NAME_SIZE) ; NEW_LINE; end if; end ORION; Example 6-7: Using SYSTEM.IMPORT_VALUE to Obtain a Global Symbol Value with SYSTEM; with CONDITION HANDLING; with TEXT IO; use SYSTEM; procedure CREATE LIB —— Declare the -— CMS$SCREATE LIBRARY type LIB DB is subtype ELEM TYPE LDB: LIB DB; DIR is is objects needed from an Ada (1..50) STRING of to call program. INTEGER; (1..14):; STRING (1..13); TYPE; ELEM RET VAL: and array DIR TYPE DIR: is types subtype ELEM: use CONDITION HANDLING; use TEXT IO; TYPE; COND_VALUE TYPE; -- COND -— CONDITION VALUE TYPE is in the package HANDLING. (continued on next page) 6—46 Calling System or Other Callable Routines Example 6-7 (Cont.): -—- Assign a Using SYSTEM.IMPORT_VALUE to Obtain a Global Symbol Value constant —— CMS$ CREATED, CMS CREATED: the value to allow a constant of the CMS later check COND_VALUE TYPE global symbol for success or failure. := IMPORT_VALUE(“CMS$_CREATED“); —- Declare the procedure CMS interfaces for the callable CMS routines. CREATE LIBRARY (STATUS : out LDB : in out COND VALUE TYPE; DIR : DIR TYPE); pragma INTERFACE pragma IMPORT VALUED (INTERNAL => EXTERNAL => PARAMETER LIB DB; (CMS, CMS CREATE LIBRARY) ; PROCEDURE CMS CREATE_ LIBRARY, "CMS$SCREATE LIBRARY", TYPES => (UNSIGNED LONGWORD, LIB DB, DIR TYPE), MECHANISM => (VALUE, REFERENCE, DESCRIPTOR) ); procedure CMS CREATE ELEMENT (LDB : in out LIB DB; ELEM : ELEM TYPE); pragma INTERFACE pragma IMPORT PROCEDURE (INTERNAL => EXTERNAL => (CMS, CMS CMS CREATE ELEMENT) ; CREATE ELEMENT, "CMSSCREATE ELEMENT", PARAMETER TYPES => (LIB DB, ELEM TYPE), MECHANISM => (REFERENCE, DESCRIPTOR)) ; begin —= Initialize the names of the CMS library and element —— to be created. DIR ELEM := := " [LENNON.SONGS]"; "LUCY.DIAMONDS"; (continued on next page) Calling System or Other Callable Routines 6-47 Example 6-7 (Cont.): —-- Create the Using SYSTEM.IMPORT_VALUE to Obtain a Global Symbol Value library CMS_CREATE LIBRARY (RET VAL, LDB,DIR); —— Use the if RET VAL imported condition wvalue to /= CMS CREATED then PUT LINE ("Unsuccessful creation"); else CMS_CREATE ELEMENT (LDB, ELEM) ; end if; end CREATE LIB; 648 Calling System or Other Callable Routines | check for success. Chapter 7 Using the VAX Common Data Dictionary The VAX Common Data Dictionary (CDD) is a data dictionary system. It allows you to store data definitions so that they can be shared among various VAX languages and VAX data management products. As such, the CDD provides the basis for a highly effective data management system. The CDD is an optional VAX software product available under a separate license; check with your system manager to determine if it is installed on your system. You should also check to see which version is installed: e Version 3.4 or lower is called the VAX Common Data Dictionary. It provides a central dictionary, uses the Data Management Utility (DMU) format for internally representing data definitions, and provides the DMU utility, Common Data Dictionary Language (CDDL) compiler, and Dictionary Verify/Fix (CDDV) utility for working with the dictionary and data definitions. e Version 4.0 or higher is called VAX CDD/Plus. It provides a new set of features, including the ability to create distributed dictionary configurations. It uses a new Common Dictionary Operator (CDO) format for internally representing data definitions, and provides the CDO utility for working with dictionaries and data definitions. However, VAX CDD/Plus is compatible and can be used with DMU dictionaries. VAX CDD/Plus also provides a call interface. The CDD/Plus documentation explains how to use the CDD. In particular, the VAX CDD /Plus User’s Guide provides tutorial information on both CDO and DMU dictionaries. VAX Ada provides a CDD translator utility to allow you to extract CDD data definitions and translate them into Ada source files. By default, a complete Ada package declaration is produced from a CDD data definition; at your option, you can generate a source fragment that you can combine with other fragments using the DCL COPY command or a text editor. Using the VAX Common Data Dictionary 7-1 7.1 Using the VAX Ada-from-CDD Translator Utility When you install VAX Ada, the files you need to use the VAX Ada-from-CDD translator utility are also installed. After VAX Ada is installed, your system will contain the following files: SYS$LIBRARY:ADA$FROM_CDD.CLD SYS$SYSTEM:ADA$FROM_CDD.EXE In addition, the Ada predefined library (ADA$PREDEFINED) contains the package CDD_TYPES, which you will need to compile the Ada packages or source fragments created by the translator. Before using the CDD translator, you must define the ADA$FROM_CDD command as follows: $ SET COMMAND SYS$LIBRARY:ADASFROM CDD.CLD Once this command is defined, you can call the translator utility as follows: $ ADASFROM CDD [/[NO]JOUTPUT[=filespec]] [/[NO]PACKAGE] pathname filespec Is a legal VMS file specification. pathname Is a character string that represents the full or relative path name of the CDD data definition to be extracted and translated to Ada. The path name must conform to the rules for forming VAX CDD path names (see the VAX CDD/Plus User’s Guide). Note that the different dictionary formats use different notation for the dictionary origin: * For DMU dictionary definitions, a full path name begins with the root name CDD$TOP and specifies the names of all descendants down to the record definition. Descendant names are separated from each other by a period. For example, CDD$TOP.MAIL_ORDER.INFO is a DMU path name for the definition INFO, which is stored in the CDD directory MAIL_ORDER. * For CDO dictionary definitions, a full path name begins with the dictionary anchor, which specifies the VMS directory where the CDO dictionary hierarchy is stored. The anchor can optionally consist of node, device, and directory components. Descendant names are separated from each other by a period. For example, DISK:[JONES.CDDIMAIL,_ ORDER.INFO is the CDD path name for the definition INFO, which is stored in the CDD directory MAIL_ORDER. 7-2 Using the VAX Common Data Dictionary /OUTPUT (D) /INOOUTPUT Specifies the output file; the default is /OUTPUT. If a file specification is not given, a file name is constructed from the CDD path name; SYS$DISK:[ . ADA is used as the default file specification. /PACKAGE (D) /INOPACKAGE Indicates whether or not the output is to be a complete Ada package declaration; the default is /PACKAGE. When the /PACKAGE qualifier is specified, a complete package is output in the following form: with SYSTEM; use with CDD_TYPES; package SYSTEM; use CDD_TYPES; <converted-pathname> <translation of CDD is record> end; When the /NOPACKAGE qualifier is specified, an Ada source fragment containing the translation of the CDD record is output in the following form: <translation 7.2 of CDD record> Equivalent VAX Ada and CDDL Data Types The VAX Ada-from-CDD translator attempts to translate all CDD data types into equivalent VAX Ada data types. However, some CDD data types are not native to VAX Ada. If a data definition contains an unsupported data type, the VAX Ada-from-CDD translator translates it to a bit array or unsigned-byte array (these are defined as subtypes UNSUPPORTED TYPE1 and UNSUPPORTED_TYPE2 in the package CDD_TYPES), and issues an informational message. Table 7-1 summarizes the mapping used by the translator between the CDD data types and the equivalent VAX Ada data types. For more information on the CDD data types, see the VAX CDD /Plus User’s Guide. The specifications of the packages CDD_TYPES and SYSTEM are given in Appendix B; alternatively, you can obtain the Ada source code for the package CDD_TYPES with the ACS EXTRACT SOURCE command. See Developing Ada Programs on VMS Systems for more information on this command. Using the VAX Common Data Dictionary 7-3 Table 7-1: Equivalent CDD and VAX Ada Data Types CDDL Data Type Ada Data Type UNSPECIFIED Unsupported type SIGNED BYTE STANDARD.SHORT_SHORT_INTEGER UNSIGNED BYTE SYSTEM.UNSIGNED_BYTE SIGNED WORD STANDARD.SHORT_INTEGER UNSIGNED WORD SYSTEM.UNSIGNED_WORD SIGNED LONGWORD STANDARD.INTEGER UNSIGNED LONGWORD SYSTEM.UNSIGNED_LONGWORD SIGNED QUADWORD SYSTEM.UNSIGNED_QUADWORD UNSIGNED QUADWORD SYSTEM.UNSIGNED_QUADWORD SIGNED OCTAWORD CDD_TYPES.OCTAWORD_TYPE UNSIGNED OCTAWORD CDD_TYPES.OCTAWORD_TYPE F_FLOATING STANDARD.FLOAT F_FLOATING COMPLEX Unsupported type D_FLOATING SYSTEM.D_FLOAT D_FLOATING COMPLEX Unsupported type G_FLOATING SYSTEM.G_FLOAT G_FLOATING COMPLEX Unsupported type H_FLOATING STANDARD.LONG_LONG_FLOAT H_FLOATING COMPLEX Unsupported type UNSIGNED NUMERIC Unsupported type LEFT OVERPUNCHED Unsupported type NUMERIC LEFT SEPARATE NUMERIC Unsupported type RIGHT OVERPUNCHED NUMERIC Unsupported type RIGHT SEPARATE Unsupported type NUMERIC PACKED DECIMAL Unsupported type ZONED NUMERIC Unsupported type (continued on next page) 7-4 Using the VAX Common Data Dictionary Table 7-1 (Cont.): Equivalent CDD and VAX Ada Data Types CDDL Data Type BIT Ada Data Type One of the subtypes of UNSIGNED_LONGWORD in package SYSTEM (UNSIGNED_1 through UNSIGNED_31); unsupported if larger than 31 bits 7.3 DATE CDD_TYPES.DATE_TIME_TYPE TEXT STANDARD.STRING VARYING STRING Unsupported type POINTER SYSTEM.ADDRESS VIRTUAL FIELD Ignored SEGMENTED STRING Unsupported type Example of Using the Ada-from-CDD Translator The following example shows the translation of a CDD record definition into an Ada package. A CDD record definition containing mail order information is extracted and translated from the CDD using the VAX Ada-from-CDD translator. Once the resulting package has been compiled, it can be used by an Ada program that manipulates data based on the type information in the mail order package. The CDD record definition is as follows: NOTE For the purpose of illustration, this definition is written in the CDD Data Definition Language (CDDL) used with DMU dictionaries; you can construct a similar record definition using most of the same statements with the VAX CDD/Plus CDO utility. See the VAX CDD /Plus User’s Guide for information on the CDO utility. Using the VAX Common Data Dictionary 7-5 DEFINE RECORD CDD$STOP.MAIL ORDER.INFO. MAIL ORDER STRUCTURE. ORDER NUM DATATYPE IS LONGWORD. NAME DATATYPE IS TEXT ADDRESS DATATYPE SIZE IS SIZE CITY IS STATE IS 20 ZIP CODE IS IS IS TEXT CHARACTERS. IS 2 DATATYPE SIZE TEXT CHARACTERS. 19 DATATYPE SIZE CHARACTERS. IS DATATYPE SIZE TEXT CHARACTERS. IS 5 TEXT CHARACTERS. ITEM NUM DATATYPE IS LONGWORD. SHIPPING DATATYPE IS F_FLOATING. END END 20 MAIL ORDER MAIL STRUCTURE. ORDER.INFO RECORD. To translate this definition to an Ada package, you first define the ADASFROM_CDD command, and then execute the command so that it extracts and translates the CDD record (assumed in this example to have a DMU path name of CDD$TOP.MAIL_ORDER.INFO). For example: $ SET COMMAND SYSS$SLIBRARY:ADASFROM CDD.CLD $ ADASFROM_CDD/OUTPUT=INFO.ADA/PACKAGE CDD$TOP.MAIL ORDER.INFO You need to define the ADASFROM_CDD command only once for any given terminal session; thus, for your own convenience, you may want to define it in your LOGIN.COM file. See the Introduction to VMS for more information on LOGIN.COM files. The Ada-from-CDD translator produces the following translation in the file INFO.ADA: with SYSTEM; use with CDD_TYPES; package —— SYSTEM; use CDD_TYPES; CDD_TOP MAIL ORDER INFO CDD Path Name type MAIL is "CDD$TOP.MAIL ORDER.INFO" ORDER TYPE is record ORDER_NUM NAME ADDRESS CITY STATE end 7-6 : : : : : UNSIGNED_LONGWORD; -- unsigned STRING(1 .. 20); —-—- text STRING(1 .. 20); —— text STRING(1 .. 19); -- text STRING(1 .. 2); -— text .. 5); —-- text longword ZIP CODE : STRING(1 ITEM NUM : UNSIGNED LONGWORD; =-- unsigned SHIPPING : FLOAT; -- Ffloating record; Using the VAX Common Data Dictionary longword for MAIL ORDER TYPE use record end for end ORDER NUM at 0 range 0 31; NAME at 4 range O 159; ADDRESS at 24 range 0 159; CITY at 44 range 0 151; STATE at 63 range 0 15; ZIP CODE at 65 range 0O 39; ITEM NUM at 70 range O 31; SHIPPING at 74 range O 31; record; MAIL ORDER TYPE’SIZE use 624; CDD_TOP ORDER _MAIL INFO; You can then use this package in an Ada program as you would use of any other Ada package. For example: with CDD_TOP_MAIL ORDER_INFO; procedure USE MAILDATABASE use CDD_ MAIL ORDER TOP INFO; is begin —- Work with the mail database using the type MAIL ORDER TYPE. - end USE MAILDATABASE; Using the VAX Common Data Dictionary 7-7 Chapter 8 Tasking Ada tasks are entities that execute in parallel. For example, you can use tasks to take data concurrently from several sources, you can use them to do terminal input-output and a series of calculations at the same time, or you can use them to call asynchronous VMS system services. This chapter provides information on how to use VAX Ada tasks effectively, giving, in particular, information on how to use tasks in the VMS environment. If you are not familiar with Ada tasking, read Chapter 9 of the VAX Ada Language Reference Manual before reading this chapter. For information on the VMS concepts presented in this chapter, see the Introduction to VMS System Services and the Introduction to the VMS Run-Time Library. For information on the interaction of tasks with VAX Ada input-output facilities and exception handling, see Chapters 3 and 4. 8.1 Introduction to Using Ada Tasks on the VMS Operating System A task is an entity whose execution proceeds in parallel with the execution of other tasks. The Ada language allows you to declare both task types and task objects. A special kind of task—an environment task—is automatically created when you run a main VAX Ada program. This task—the main task—first elaborates any library packages associated with the program, and then calls the main program (see Chapter 10 of the VAX Ada Language Reference Manual). When execution of the main program is completed, and all tasks that depend on its library packages terminate, the main task is deleted, and control returns to the VMS operating system. Tasking 8-1 Any task is said to depend on a number of masters. Blocks, tasks, subprograms, or library packages can all be the master of a task. If you declare a task object in a block, for example, the block is the master of the created task, and the task depends on the block. If the block is executed within the statement part of a subprogram, then the subprogram is another master of the task and the task depends on it too. An immediate master is the master that immediately contains the declaration of a task object, or that immediately contains the definition of the access type whose designated type is a task type. A key rule is that control cannot leave a master until all of its dependent tasks have terminated. Thus, if some dependent task chooses not to terminate, none of its masters can exit, and the program, or a portion of it, appears to “hang.” Each time you create a task (for example, by declaring a task object, or evaluating an allocator that points to a task object), VAX Ada automatically creates a task control block to manage the task. When the task is activated, VAX Ada creates a stack to be used by the statements that the task will execute, and allows the task to compete for the processor on which your process is executing. Because all tasks in any Ada program (including the main task) run in the context of a single process, control can switch from one task to another very quickly. This switch can occur at or during any of the several machine instructions that make up an Ada program statement; that is, the switch can occur midway through the execution of an Ada source line. Because of task switching, you will often need to synchronize the execution of tasks in your program to get the behavior you desire. Synchronization involves making sure that the right things happen in the right order. The usual means of synchronizing tasks is to use Ada’s rendezvous mechanism. Example 8-1 shows the use of tasks to do input-output and another activity in parallel. The example program reads in an array of integers, and sorts them using a quick sort. The sorting is done by one task, and another task (running in parallel) allows you to see how the sort is progressing by executing input-output statements while the sort is being done. The comments in the example point out various tasking concepts (activation, synchronization, and so on). These concepts are defined fully in the VAX Ada Language Reference Manual. 8-2 Tasking Example 8-1: This Interactive Array Sort Using Tasks example waits for shows that The main program has another task task, during the file the with command, can execute while another the will terminal sorts user. display the an array while The array at interactive any time sort. running this is task a background task that interacts upon user Before one input-output. not program, make a process-permanent lower-priority using SYSSINPUT, sure file sorting task will first type the that the input (SYS$SINPUT); not run. otherwise, To avoid sort and following: $ DEFINE ADASINPUT TT Program to it as it sort is with TEXT IO; an array by means of a quick examine sorted. use TEXT IO; with INTEGER TEXT IO; use INTEGER TEXT IO; with FLOAT TEXT IO; use FLOAT TEXT IO; procedure TASKSORT is —— Enable time pragma slicing. TIME SLICE(0.3); type QUICKARRAY -—- Array to be is array sorted and (INTEGER range <>) shared A : QUICKARRAY (1..120); ASIZE : INTEGER; —-— Force array —— storage —— array references (rather among to be made to than to a of INTEGER; tasks. actual copy). p— pragma VOLATILE (A); SENTINEL —— : Task to STRING(1..120) synchronize := access (1..120 => " ’); to the array being sorted. task GRANTOR is entry GRAB ACCESS; entry RELEASE ACCESS; end GRANTOR; (continued on next page) Tasking 8-3 Example 8-1 (Cont.): Interactive Array Sort Using Tasks -- Lower priority background task to do sorting. task QUICK is entry QSORT (ARG I, ARG J: INTEGER); (3) ; pragma PRIORITY end QUICK; ~— Higher priority interactive task to display -—- sort results. task USER is pragma PRIORITY (7); end USER; task body GRANTOR is begin loop select accept GRAB ACCESS; accept RELEASE ACCESS; or terminate; end select; end loop; end GRANTOR; task body QUICK is : INTEGER; KEY INDEX I, J, MIDDLE KEY : INTEGER; KEY : INTEGER; function FIND MIDDLE FIRST : INTEGER; KEY : INTEGER; (I,J: INTEGER) return INTEGER is begin FIRST := A(I); for KEY in (I if A(KEY) return + KEY; elsif A(KEY) return 1)..J loop > FIRST then < FIRST then I; end if; end loop; return end FIND O; MIDDLE; (continued on next page) 8-4 Tasking Example 8-1 (Cont.): Interactive Array Sort Using Tasks function DIVIDE ARRAY return LEFT, (I,J : INTEGER; MIDDLE KEY : INTEGER) INTEGER is RIGHT, TEMP : INTEGER; begin —— Rendezvous -— array for partitioning. to synchronize access to the GRANTOR.GRAB ACCESS; LEFT := I; RIGHT := J; loop TEMP := A(LEFT): A(LEFT) := A (RIGHT) A(RIGHT):; := TEMP; while A (LEFT) - < MIDDLE KEY loop LEFT := LEFT + 1; end loop; while A (RIGHT) >= MIDDLE KEY loop RIGHT := RIGHT - 1; end loop; exit when LEFT > RIGHT; end loop:; -- Rendezvous —— array to synchronize end of access. GRANTOR.RELEASE ACCESS; PUT_LINE ("Partial return sort complete."); LEFT; end DIVIDE ARRAY; procedure QUICK SORT (I,J: INTEGER) is begin KEY INDEX if KEY := INDEX FIND MIDDLE(I,J):; /= 0 then delay 8.0; MIDDLE KEY KEY := := A(KEY INDEX):; DIVIDE ARRAY(I,J,MIDDLE KEY) QUICK SORT (I,KEY-1); QUICK SORT (KEY,J); end if; end QUICK SORT; (continued on next page) Tasking 8-5 Example 8-1 (Cont.): Interactive Array Sort Using Tasks begin select accept QSORT (ARG_I,ARG_J: I := J := ARG_J; INTEGER) do ARG _I; end QSORT; or terminate; end select; PUT LINE ("The sorting task has started."); QUICK_SORT (I, J): PUT LINE ("The sorting task has completed."); end QUICK; procedure PRINT ARRAY is begin -- Again, use GRANTOR task rendezvous -—- synchronize array access to for printing. GRANTOR .GRAB_ACCESS; for I in 1..ASIZE loop PUT (A (I) ,WIDTH=>3) ; end loop; NEW LINE; GRANTOR.RELEASE ACCESS; end PRINT ARRAY; task body USER is I : INTEGER; LAST : NATURAL; begin PUT LINE ("Type in the number of "integers you want PUT LINE ("and then press " & sorted,"):; RETURN."); GET (ASIZE) ; PUT_LINE ("Now, type in a "separated by PUT LINE ("that you want string of spaces, sorted. integers, " & "): End the " & "string with a RETURN."):; for I in 1..ASIZE loop GET (A(I)) ; end loop: PUT ("The initial array is "); PRINT ARRAY; (continued on next page) 8-6 Tasking Example 8-1 (Cont.): —-—- Start the Interactive Array Sort Using Tasks sorting task. QUICK.QSORT (1,ASIZE) ; —— Allow the terminal user to see the array at any time. —— loop PUTLINE("Press RETURN to "sorted array GET LINE (SENTINEL, if LAST >= 1 or see e partially to " & exit."); LAST); and then (SENTINEL(1l) = 'E’ or else SENTINEL (1) = 'e’) then exit; end if; PRINT ARRAY; end loop; exception when END ERROR => PUT_LINE ("That’s when others PUT_LINE ("You’ve SKIP all folks!"); => made a mistake; try again."); LINE; TASKSORT; -- Re-call main program. end USER; begin -- Activate tasks all tasks depend (GRANTOR, on the QUICK, —— all environment —— for the main program TASKSORT. USER):; task created null; end TASKSORT; 8.2 Task Storage Allocation Each task created in your program requires a certain amount of storage: when your program creates a task, a task control block is allocated; when the task is activated, a stack is allocated. Because the VMS operating system is a virtual memory operating system, the number of tasks you can create is limited only by the amount of virtual storage available to your process. The following sections discuss task storage allocation, and explain how you can control it and how it can be important in a mixed-language environment. Tasking 8-7 8.2.1 Storage Created for a Task Object—The Task Control Block When your program creates a task object, VAX Ada allocates a block of storage—a task control block—to keep track of that task’s execution. For example, a task control block is allocated for each of the following task objects: task type T : MY TASK; MY TASK; task type MY TASK; type MY TASK POINTER PT : MY PT := is access MY TASK; TASK POINTER; new MY TASK; The task control block is deallocated when control leaves the immediate master (another task or a currently executing block or subprogram) upon which the task depends—not when the task terminates. See Section 8.1 of this manual and Chapter 9 of the VAX Ada Language Reference Manual for a definition of masters and dependence. The size of a task control block depends on the characteristics of the task’s type. In other words, its size increases in proportion to the number of single entries in the task type, the total number of members of all of its entry families, and the number of single entries that have been specified to receive ASTs (see Section 8.6). In particular, if you specify an entry family with a very large discrete range, a large amount of storage is allocated when a task of the type is created; to maximize execution speed, an entry-call queue is allocated for each member of an entry family. For example, the following declaration will cause a large amount of storage to be allocated: entry X (1..100 _000); You can estimate the number of pages (512 bytes per page) to be allocated for a task control block as follows; remember that you need to round up fractional results to a whole number: TCB_SIZE (pages) = FIXED_AMOUNT + (E+12.2) + (AST-Ex28) 512 where FIXED_AMOUNT = 3000 bytes E = the number of single entries plus the number of members in all entry families 8-8 Tasking AST E = the number of single entries that have been specified to receive ASTs; that is, those entries declared with the pragma AST ENTRY For most task types (that is, those having fewer than a few hundred total entries), the storage consumed by the task control block is relatively small. Note that the main task has no entries, so the main task control block has a constant size. You can reduce the size of the task control block by reducing the number of entries, the number of entry family members, and the number of entries that have been declared with the pragma AST_ENTRY. In addition, you can cause the storage consumed by a task control block of a terminated task to be released by arranging for control to leave its immediate master; see Example 8-2. Note from Example 82 that storage for only one task control block is con- sumed at any one time, even though 100,000 tasks are created. This is because the block is the immediate master of tasks declared to be of type ACCESS_TO_TASK. If X were instead declared to be of type OUTER_ ACCESS, storage for 100,000 task control blocks would need to be allo- cated (even though all blocks but one are terminated), and the exception STORAGE_ERROR may be raised. Thus, as your program creates and terminates many tasks, storage for terminated tasks will accumulate. To reduce the accumulated storage for terminated tasks, you should arrange the program so that the immediate master on which the task depends is as innermost as feasible. This strategy, however, saves space at the expense of more execution time. To minimize execution time, follow this (opposing) strategy: arrange the program so that task types and task declarations are as outermost as feasible to minimize the number of tasks that are created and terminated. 8.2.2 Storage Created for a Task Activation—The Task Stack Each time a task is activated, a task stack is allocated. The storage for the task stack is deallocated as soon as the task is terminated. Tasking 8-9 Example 8-2: procedure Leaving a Master to Release a Task Control Block RELEASE task type type is SOME TASK; OUTER ACCESS task body is SOME TASK access SOME TASK; is begin delay 0.5; —— Simulate doing some useful work. end SOME TASK; begin —— This -—- to loop creates refer to —— terminates for T in 100,000 each new task a short 1..100000 time tasks. X in turn. after is assigned Each task creation. loop declare type ACCESS TO TASK is access X : SOME TASK; ACCESS TO TASK; begin X := delay end; new SOME_TASK; 1.0; =-- Wait long enough to be -— X terminated. is -- Await termination —-— referred to -- and their free by of type sure all that tasks ACCESS TO TASK, storage. end loop; end RELEASE; ——- Await termination -— referred to -- and their free by of type all tasks OUTER ACCESS, storage. In the absence of the VAX Ada pragma MAIN_STORAGE, the stack for a main task is allocated in the P1 region of the process in which the program is running. When it is so allocated, the stack of the main task has no definite limit; as long as your process has not used up all of its virtual memory, the main task stack is automatically expanded as needed. The storage for all other tasks, including a main task declared with the pragma MAIN_STORAGE, is allocated in the PO region. The stacks for these tasks are fixed in size, and are not expanded. The task stack allocated for any VAX Ada task (including the main task) has two areas: a working storage area and a top guard area. The working storage area is used during normal task execution for the storing of vari- ables, call frames, and so on. The top guard area is a set of pages (512 bytes per page) at the top of the stack. These pages are inaccessible to your 8-10 Tasking program—that is, attempts to read or write them will cause a hardware access violation (SS$§_ACCVIO), which will usually terminate your program immediately. The purpose of these guard pages is to help you detect accidental overflow of the working area of the stack. For example, accidental stack overflow can occur as follows: ¢ When a task with a fixed-size stack executes non-Ada code for which stack checking is not performed (see Section 8.2.3) * When storage size checks are suppressed when you compile the program (see Section 4.3) NOTE AST routines execute on the stack of whatever task is currently active. See Section 8.6 for more information on AST routines and tasks. Unless you specify otherwise, the sizes of the working area and the top guard area of all task stacks are set by the VAX Ada run-time library. For tasks with fixed-size stacks, the working area is set by default to 60 pages, and the top guard area is set to 10 pages. The default stack allocation for tasks with fixed-size stacks allows an additional 10 pages of stack for calls to non-Ada routines, which is adequate for most routines, including VMS system service and Run-Time Library routines. You may need to specify the sizes of a task’s stack areas for a number of reasons: * You may find that a task is raising the exception STORAGE_ERROR, and you want to increase its working area. * You may find that a task does not need all of its default stack allocation, and you may wish to reduce the working area so that the unused storage can be put to other use by your program (for example, if your program creates many tasks). * You have not called any non-Ada routines, and you are not having any stack overflow (you have not suppressed checks and STORAGE_ERROR is not being raised). You may thus wish to decrease the top guard area and put the storage to other use. * You may suspect that some non-Ada routine might be overflowing the stack, and you may wish to increase the top guard area in an attempt to detect the overflow. ¢ In the case of a main task, you may wish to emulate the behavior of tasks on a VAX system running the VAXELN executive (see the VAXELN Ada User’s Manual for more information on VAXELN Ada). Tasking 8-11 To control the storage allocated for a main task stack (and to force a fixedsize, PO space stack allocation), use the pragma MAIN_STORAGE; to control the storage allocated for all other task stacks, use the STORAGE_ SIZE length representation clause attribute and the VAX Ada pragma TASK_STORAGE. The following sections describe how to control task stack storage. 8.2.2.1 Controlling the Stack Sizes of Task Objects To control the working storage area of the stack of a task object, you can apply a representation clause to the type used to declare that object. For example, the following length clause sets the working storage size for the task type NEEDS_BIG_STACK to 300 pages: for NEEDS BIG STACK’ STORAGE SIZE use 300*512; Any task objects of this type will have 300-page working storage areas. Note that if you specify a size of zero (bytes) with ' STORAGE_SIZE, a default stack size is used. Also, regardless of the size you specify, at least 21 pages of additional space are allocated for task management purposes. In any case, the VMS Debugger can help you to determine and tune the amount of storage you need for a stack working area; see Developing Ada Programs on VMS Systems. To control the top guard area of a task object, you can use the VAX Ada pragma TASK_STORAGE to set the amount of guard storage allocated for the task type used to declare that object. For example, the following statement sets the top guard area of the task type NEEDS_BIG_STACK to Z€ero: pragma TASK STORAGE (NEEDS BIG_STACK, O0) Any object of this type will have a default working storage size (unless a representation clause was also specified) and no guard area. Note from the VAX Ada Language Reference Manual that ' STORAGE_SIZE and the pragma TASK_STORAGE apply only to task ¢£ypes; to apply them to a single task, you must convert the single task to a task type declaration and then a task object declaration. You should use task types when you begin coding your tasking programs, if you anticipate using representation clauses or the pragma TASK_STORAGE later on; you may have to rewrite your program if you have single tasks that are later declarations and that need to be converted to task types (a task type declaration cannot be a later declaration). See Chapter 3 of the VAX Ada Language Reference Manual for more information on later declarations; see Chapter 13 of the VAX Ada 812 Tasking Language Reference Manual for a description of the syntax and rules for using ' STORAGE_SIZE and the pragma TASK_STORAGE. Example 8-3 shows the control of stack areas using ' STORAGE_SIZE. and the pragma TASK_STORAGE. Example 8-3: Controlling the Size of a Task’s Stack procedure CONTROL task type is NEEDS BIG_STACK; -— Set the -- so0 that -—- recursive procedure -- storage for -— stack working area these tasks for one CALL SELF. tasks the no guard top pages guard area are of not the call : call 76 is of the sufficient 30000*76; stack to 0 because the outside Ada. Thus, needed. pragma TASK STORAGE (NEEDS BIG STACK, T type NEEDS BIG_STACK (The value NEEDS BIGSTACK’STORAGE SIZE use Decrease of deepest activation of the procedure CALL SELF.) -- task NEEDS BIG _STACK does —-— of can handle the 0):; NEEDS BIG_STACK; task body NEEDS BIG STACK procedure CALL SELF (I is : INTEGER) is begin if T < 30000 then CALL SELF(I + 1); end if; end CALL SELF; begin CALL SELF (1) ; end NEEDS BIG STACK; begin null; end CONTROL; 8.2.2.2 Controlling the Size of a Main Task Stack Main task stacks usually have no definite limit, and are automatically expanded as needed in the VMS environment. However, VAX Ada provides the pragma MAIN_STORAGE to allow you to control the size (and the allocation space) of a main task stack. As noted in previous sections, this pragma causes the size of the main task stack to be fixed; it also causes the stack to be allocated in the PO region rather than in the P1 region. This Tasking 8-13 pragma is intended primarily to allow control over the sizing of main task stacks in a VAXELN environment (with VAXELN Ada); thus, it is generally useful in the VMS environment when you need to simulate the behavior of a VAXELN main task when you are working with VAX Ada and a VMS target. See the VAXELN Ada User’s Manual for more information on VAXELN Ada. The pragma MAIN_STORAGE has two parameters, WORKING_STORAGE and TOP_GUARD, which allow you to specify (in bytes) either or both the working storage and top guard areas of the main task. For example: procedure MAIN PROGRAM is pragma MAIN STORAGE (WORKING_ STORAGE => 100%*512, TOP_GUARD => 0); begin end; Here, the working storage area of the main program is limited to 100*512 bytes (that is, 100 pages), and the top guard area is set to zero. If you specify WORKING_STORAGE or TOP_GUARD alone, a default value is chosen for the omitted parameter. A default stack size is also used if you specify a value of 0 for WORKING_STORAGE; regardless of the value specified for WORKING_STORAGE, at least three pages of additional space are allocated for task management purposes. In any case, the VMS Debugger can help you to determine and tune the amount of storage you need for a stack working area; see Developing Ada Programs on VMS Systems. See Chapter 13 of the VAX Ada Language Reference Manual for a description of the syntax and rules for using the pragma MAIN_STORAGE. 8.2.3 Stack Overflow and Non-Ada Code You are protected from stack overflow in an Ada program because VAX Ada raises the exception STORAGE_ERROR when an attempt is made to overflow either the main stack or an Ada task stack. In addition, the default 10-page stack storage allocated for each non-Ada call should be adequate protection against stack overflow for most non-Ada routine calls (see Section 8.2.2). However, be aware that non-Ada routines, VMS system services, Run-Time Library routines, and so on do not check for stack overflow. Thus, when you call a non-Ada routine from an Ada program, it may be possible that the stack of the main task or an individual task will overflow, and the Ada program will not be able to detect it because the exception STORAGE_ ERROR will not be raised. Such an undetected stack overflow could result 8-14 Tasking in random changes to various locations beyond the storage allocated for the stack. Because the correct operation of the Ada program may depend on such locations, undetected stack overflow could make your program erroneous. Thus to be safe, do not mix Ada and non-Ada programs without checking for stack overflow. You can use the top guard areas of tasks in your program to detect if a non-Ada routine causes the stack to overflow (see Section 8.2.2 for information about the top guard area). If you make the size of the guard pages in the top guard area large enough, then undetected overflows that are not larger than the guard pages will raise a hardware access violation (SS$_ACCVIO) exception, which will usually terminate your image immediately. The VMS Debugger can be of great help in detecting stack overflow. The debugger will perform an automatic stack check for you, and can display the amount of stack space in use in any task. For further information, see Developing Ada Programs on VMS Systems. 8.3 Task Switching and Scheduling VAX Ada implements the Ada language requirement that when two tasks are eligible for execution, and they have different priorities, the lower priority task will not execute while the higher task is waiting. Thus, the VAX Ada run-time library keeps a task running until either the task is suspended or a higher priority task becomes ready. NOTE The term “suspend” is used in this chapter (as it is used in the VAX Ada Language Reference Manual) to mean that execution of the task is temporarily stopped—the task is waiting for another event, such as the acceptance of an entry call, to occur before execution resumes. “Suspend” does not refer to the VMS system service $SUSPND. The default VAX Ada task scheduling may be described as “first-in-first-out (FIFO), with preemption.” This phrase means that tasks of equal priority are processed in first-in-first-out order: a task is run until it suspends; when it later resumes, it is placed at the rear of the ready queue for its priority level. The term “with preemption” means that VAX Ada will preempt a running task if a higher priority task becomes ready; this behavior is required by Ada rules (see Section 9.8 of the VAX Ade Language Reference Manual). The preempted task is placed at the front of the ready queue for its priority level. Then, when the higher priority task suspends, the Tasking 8-15 preempted task resumes execution. In other words, the preemption of a lower priority task does not imply any cycling of the ready queue for that priority. This scheduling strategy has the benefit that the execution of lower priority tasks is minimally affected by any change in the exact instant at which the higher priority task becomes ready (which can change from run to run). In other words, this scheduling method increases program repeatability, and helps you debug your program. However, FIFO scheduling is not necessarily fair to tasks of equal priority that are eligible for execution but that are not yet running. These waiting tasks can exhibit sluggish response times, especially if they are interacting with a terminal. In fact, they will never get to run if the running task does not become suspended. FIFO scheduling permits a running task to capture the processor. There are a number of ways in which you can control scheduling. You can use the pragma PRIORITY to give the more important tasks higher priorities, and thus increase their responsiveness. The range of possible VAX Ada task priorities is from 0 to 15; in the absence of this pragma, VAX Ada tasks have a default midrange priority of 7. (Note that task priority has no effect on the priority of your process; from the VMS operating system’s point of view, the process priority applies to the execution of every task in your program.) For example, the following statements set the priority of the task IMPORTANTTASK to 14: task IMPORTANT TASK is pragma PRIORITY (14); end IMPORTANT TASK; This pragma can appear only in a task specification or in the outermost declarative part of a main subprogram. See Chapter 9 of the VAX Ada Language Reference Manual for a description of the syntax and use of the pragma PRIORITY. If, instead, you want to increase the fairness of the scheduling by limiting the execution time for any particular task, you can specify a time slice with the VAX Ada pragma TIME_SLICE or with the procedure SYSTEM_ RUNTIME_TUNING.SET TIME_SLICE. By specifying a time slice, you change the default FIFO scheduling strategy to what is known as roundrobin scheduling. Round-robin scheduling causes tasks of the same priority to take turns at the processor, thus preventing a nonsuspending task from capturing the processor. 8-16 Tasking Time slicing is useful during development to help you find race conditions and deadlocks. It tends to make tasks of equal priority execute in an arbitrary order, and thus stresses the tasking logic in your program. However, consider removing the pragma in production code to both reduce overhead and possibly enhance the reliability of your program. (In some applications, time slicing during production may enhance reliability—or may be required—if some tasks have code paths where they fail to suspend.) You specify a time slice with the pragma TIME_SLICE as follows: pragma TIME SLICE (static—-expression):; The static expression must be of the type SYSTEM.DURATION. A value of 0.0 (the default) or less disables time slicing. This pragma has an effect only if it appears in the outermost declarative part of a main program; see Chapter 9 of the VAX Ada Language Reference Manual for a complete description. See the specification of the package SYSTEM_RUNTIME_TUNING in Appendix B for information on using the SET_TIME_SLICE procedure. If you specify a time slice, you must realize that, while you are increasing fairness, you are paying a price in terms of increased task switching overhead (the overhead increases for smaller time-slice values) and more difficult debugging. Time-slice values below 0.01 second do not result in faster time slicing because the smallest time increment supported by the VMS operating system is 0.01 second. 8.4 Special Tasking Considerations Use of tasks in an Ada program requires some care, because, like any other language construct, tasking has its own characteristic set of programming pitfalls. (Infinite looping, for example, is a characteristic pitfall of while loops.) The following topics are discussed in this section: deadlock, busy waiting, tentative rendezvous, delay statements, abort statements, interrupting program execution with CTRL/Y, shared variables, and reentrancy. 8.4.1 Deadlock Deadlock is a condition in which each task in a group of tasks is suspended and no task in the group can resume its execution until some other task in the group executes. Deadlock is also called “circular wait.” Tasking 8-17 The possibility that Ada tasks may deadlock is a property of the Ada language. You can eliminate deadlock with careful program design. In addition, the VMS Debugger provides special task debugging commands that can help you detect deadlocks; see Developing Ada Programs on VMS Systems. The following examples show some of the more common forms of Ada deadlock: exception-induced, self-calling, circular-calling, and dynamiccircular-calling. An exception-induced deadlock occurs when an exception prevents a task from answering one of its entry calls; if the exception had not occurred, there would be no deadlock. This kind of deadlock occurs when an unhandled exception in an Ada task must wait for the termination of local dependent tasks before propagating. Exception-induced deadlock is more subtle than the other kinds of deadlock because, were it not for the exception, the program would be deadlock free. Example 84 shows an exception-induced deadlock. A self-calling deadlock occurs when a task calls one of its own entries. The call cannot be completed until the call is answered, and the call cannot be answered because the task itself becomes suspended at the call. Self-calling deadlock becomes more subtle if the task calls a procedure that calls the task. Example 8-5 shows self-calling deadlock. 8-18 Tasking Example 8—4: An Exception-lnddced Deadlock procedure EXCEPTION INDUCED task PARENT is is entry E; end PARENT; task body PARENT is begin declare task CHILD; UNANTICIPATED EXCEPTION task body CHILD begin PARENT.E; is : exception; —— Exceptions -- task declared within wait for a —— unit a declared within any task. end; begin raise accept UNANTICIPATED EXCEPTION; E; end; -- Exception occurs —— here; CHILD’s —— never accepted. —— Parent —— for —— of waits call here termination CHILD. end PARENT; begin null; end EXCEPTION INDUCED; Tasking 8-19 Example 8-5: A Self-Calling Deadlock is procedure SELF_CALL task type T is entry E; end T; Y : T; procedure P(X : T) is -— Calls entry E in task X. begin X.E; end P; task body T is begin P(Y); —— Never returns. accept E; end T; begin null; end SELF CALL; A circular-calling deadlock occurs when a task calls another task that calls another task, and so on, and the last task calls the first task. One way you can eliminate circular-calling deadlock is by restricting your program so that task calls form a strict hierarchy. Example 8-6 shows circular-calling deadlock. 8-20 Tasking Example 8-6: procedure A Circular-Calling Deadlock CIRCULAR CALL task type T1 is is aentry E; end T1; task type entry T2 is E; end T2; Y : T1; Z : T2; procedure P is begin Z.E; end P; task body T1 is T2 1is begin P; end T1; task body begin Y.E; end T2; begin null; end CIRCULAR_CALL; A dynamic-circular-calling deadlock occurs when a series of entry calls forms a circle as in either of the previous two cases, but at least one of the calls is a timed or conditional entry call in a loop that completes only if the rendezvous occurs. Thus, with dynamic-circular-calling deadlock, at least one task is executing, but no progress can be made. Example 8-7 shows a dynamic-circular-calling deadlock. Tasking 8-21 Example 8-7: procedure A Dynamic-Circular-Calling Deadlock DYNAMIC CALL task type entry T is is E; end T; Y : T; procedure P(X DONE : : T) BOOLEAN is := FALSE; begin while not DONE loop := TRUE; select X.E; DONE or delay 0.5; —— This —— chosen. alternative —— The is always end select; end loop; end P; task body T is begin P(Y) ; accept call to P never returns. E; end T; begin null; end DYNAMIC CALL; 8.4.2 Busy Waiting and Non-Ada Code Busy waiting is a programming technique that repeatedly tests a variable, sometimes called a “flag” or a “spin lock,” to determine if some event has occurred. When the event does occur, another instruction sequence is presumed to execute and set the flag, thereby ending the looping. Busy waiting is sometimes desirable when an event will occur quickly, and it is justifiable to use CPU time to wait for it. It is also desirable when no other suitable synchronization methods (such as rendezvous) are available. Busy waiting has some undesirable characteristics, however. First, assump- tions about an event that were true when the code was written may no longer be true when the code is executed; as a result, a large, unanticipated 8-22 Tasking amount of CPU time may be consumed at execution time. For a process running under the VMS operating system, this usually means that the process 1s using processor resources that another process could use to advantage. Second, when tasks execute busy-waiting code, the effect can be unpredictable. Consider the following situation: * One task is executing a wait loop, while another task is expected to set the flag. ® The task executing the busy-waiting code has the highest priority in the program. If time slicing is not enabled, deadlock will develop because the busy-waiting task does not suspend and no other task (including the flag-setting task) can be scheduled (see Section 8.3 for a discussion of first-in first-out scheduling). (This behavior is in accordance with Ada rules.) The situation can be mmproved only slightly if time slicing is enabled. The deadlock can still develop if the flag is to be set by a task of lower priority (even with time slicing, a low-priority task cannot be scheduled while a higher priority task 1s ready). Because of these potential problems, avoid busy waiting. VAX Ada does not use busy waiting, so if your program uses only VAX Ada, you should not encounter this kind of deadlock. If you do discover that your tasking program is caught in a busy waiting loop by some software over which you have no control, you can probably correct the problem by setting all of your task priorities to the same value (or, equivalently, by eliminating all specifications of the pragma PRIORITY) and by enabling time slicing with the pragma TIME_SLICE (see Section 8.3) or with the procedure SYSTEM_RUNTIME_TUNING.SET TIME_SLICE (see Appendix B.). 8.4.3 Tentative Rendezvous Ada provides a number of “tentative” rendezvous constructs: conditional entry calls, select-with-else combinations, and even timed entry call and select-with-delay combinations. These constructs are most often coded in loops. They have the potential effect of causing the task executing such loops to take over the processor if the task has the same or a greater priority as all of the other tasks available for execution. Then, if the executing task does take over the processor, it could end up executing indefinitely if it depends on any of the tasks it is Tasking 8-23 preventing from executing. Thus, tentative rendezvous constructs require special care; think of them as forms of busy waiting. 8.4.4 Using Delay Statements VAX Ada implements the delay statement as a call to the VMS system service SYS$SETIMR. Thus, each delay statement places an entry in the system timer queue, which, in turn, affects the VMS operating system Timer Queue Entry Limit (TQELM) quota. Each delay statement also makes use of the SYS$SETIMR routine’s ASTADR parameter, which specifies an AST routine. Thus, the use of delay statements can also affect (or possibly exceed) the AST Queue Limit (ASTLM) quota. In effect, the TQELM quota limits the number of concurrent Ada delay statements: when a request is made that would cause the TQELM quota to be exceeded, the call to SYS$SETIMR stalls until a timer entry packet becomes available. In other words, the call stalls until an active delay expires, and the delay will not start until the call is made. A low quota can affect any Ada statement containing the reserved word delay; it can also affect the duration of a time slice, if the main program uses the pragma TIME_SLICE. You can eliminate this delay anomaly by increasing the TQELM quota for your process. The TQELM quota should exceed the number of simultaneous statements involving delay that can be in progress at one time (an upper bound is the peak number of tasks that can exist simultaneously in your program). One additional timer entry is required if your program uses the pragma TIME_SLICE. You may need to increase the TQELM quota further if your program executes any other timer-related system services. To increase the TQELM or ASTLM quota for your process, see your system manager. The Guide to Maintaining a VMS System gives details on how to adjust these quotas. 8.4.5 Using Abort Statements Be careful when you use abort statements: an abort statement can ter- minate a task when it should not be terminated, and thus can lead to erroneous execution. You should use abort statements only when you require unconditional termination, and only when you are sure that it is safe to do so. For example, if you abort a task with an asynchronous system service request in progress (such as SYS$QIO), the task can become terminated and its stack storage reallocated to some other use before the VMS operating 824 Tasking system has written the result data. The result data could be written in some unexpected part of your program’s data area. VAX Ada implements the abort statement in a synchronous rather than an asynchronous form. An asynchronous implementation of the abort statement can cause completion of tasks at arbitrary points in their execution. The synchronous form causes tasks to become completed only at specific points in their execution (see Chapter 9 of the VAX Ada Language Reference Manual for a list of these points). Synchronous abort has several benefits. One benefit is that when a task calls a non-Ada routine (and the routine does not result in a call to an Ada subprogram), the non-Ada routine will execute to completion even though the calling task has been aborted. Synchronous abort thus avoids problems that may result because non-Ada routines typically are not programmed to work correctly if they are only partially executed. Unfortunately, synchronous abort also means that a task in an infinite loop cannot become completed unless it executes code that is a synchronization point for the abort statement. If you want to ensure that a task will become completed due to an abort statement in some section of code, you should insert a delay 0.0 statement there. The Ada language requires that an abnormal task become completed at a delay statement; thus, delay 0.0 is a fully transportable and low-overhead means of ensuring that completion can occur. 8.4.6 Interrupting Your Program with CTRL/Y When you use CTRL/Y to interrupt the execution of an Ada program that contains tasks, you can expect some special side effects when you subsequently try to execute DCL commands. The DCL commands that you are most likely to enter after pressing CTRL/Y are: DEBUG, CONTINUE, EXIT, STOP, or a query such as DIRECTORY. For each of these commands (except CONTINUE), the current execution point of the process is modified by the VMS operating system, and execution resumes at the new location as follows: e The CONTINUE command causes your program to begin execution at the same point at which the CTRL/Y interrupt occurred. ¢ The STOP command immediately terminates execution of your program, as well as terminating any tasks that may be active. e The DEBUG command causes the VMS Debugger to be activated, and your process to continue its execution under control of the debugger. Tasking 8-25 e The EXIT command causes your program to execute the SYS$EXIT system service. e Most other commands, like the DIRECTORY command, have the effect of first entering the EXIT command and then entering the command itself. In addition, if a low-priority task is running when you press CTRL/Y, that task’s priority affects the action taken. In particular, because a higher priority task may be scheduled almost immediately, the desired effect may not occur for a while, or might never occur. (The CONTINUE and STOP commands are not affected by the task’s priority: the CONTINUE command because continuation makes the interruption irrelevant, and the STOP command because it does not resume execution in VAX user mode, where task switches take place.) For example, if you enter the DEBUG command, you may not enter the debugger immediately. If you enter the EXIT command, the process may continue execution and not exit. If you enter the DIRECTORY command, the result is equivalent to first entering the EXIT command and then the DIRECTORY command, so your process may continue executing. There are two ways to control the results of using these commands. First, you can force your program to quit by entering the STOP command. When you do this, however, any established exit handlers will not have a chance to execute. For example, VAX Ada provides an exit handler for the input-output packages, and if you enter the STOP command to interrupt input-output, the VAX Ada handler will not have an opportunity to write the last partial record to whatever external files may be open at the time, to close those files, or to delete Ada temporary files. A second solution is to use CTRL/C in conjunction with the VAX Ada prede- fined package CONTROL_C_INTERCEPTION, which allows you to run the debugger, exit the program, or enter a query command like the DIRECTORY command. The operations this package provides mimic the operations you can perform after pressing CTRL/Y. You invoke these operations by pressing CTRL/C anytime after the package has been elaborated. For example: —- Enable CTRL/C interception prior to main -—- program execution —— all with (but not library packages CONTROL C_INTERCEPTION; pragma ELABORATE (CONTROL procedure MY MAIN PROGRAM begin end 8-26 Tasking necessarily before have been elaborated). MY MAIN PROGRAM; C_INTERCEPTION) ; is The following example shows the response of this handler to CTRL/C: Nothing go wrong go wrong go wrong go wrong can go wrong ~C Ada CTRL/C Interceptor Type: DEBUG, EXIT, CONTINUE, or a DCL command. Ada_ CTRL/C> DEBUG DBG> See Appendix B for the package specification of CONTROL_C_ INTERCEPTION. 8.4.7 Using Shared Variables The code generated by an Ada compiler may store the value of a variable in several, one, or no places in the memory of the machine (see Chapters 2 and 9). The compiler believes, unless instructed otherwise, that it can detect all attempts to read or write a variable, and arranges to have each of those attempts access the correct places. The compiler makes assumptions based on the following rules: ¢ In the absence of a pragma SHARED or VOLATILE, a variable that is read by a task will not be written by another task until the reading task reaches a synchronization point. ¢ Also in the absence of a pragma SHARED or VOLATILE, a variable that is written by a task will not be read or written by another task until the writing task reaches a synchronization point. This rule is described more precisely in Section 9.11 of the VAX Ada Language Reference Manual. These rules avoid the need for specifying either pragma SHARED or pragma VOLATILE for variables that are read or written. by multiple tasks, provided that the reads and writes are implicitly or explicitly synchronized by tasking events such as a rendezvous. If you want your program to read or write a variable in a way that does not satisfy these rules, then you must specify the pragma SHARED or VOLATILE for that variable. Otherwise, your program is erroneous. The pragma SHARED is defined by the Ada language; the pragma VOLATILE is defined by VAX Ada. Tasking 8-27 Chapter 9 of the VAX Ada Language Reference Manual gives the Ada language assumptions about shared variables and gives the usage rules and syntax for the pragma SHARED. The syntax is given here for convenience: pragma SHARED (variable simple name); The named variable must be declared by an object declaration and must be of a scalar or access type. Chapter 9 of the VAX Ada Language Reference Manual also gives the usage rules and syntax for the pragma VOLATILE. The syntax is given here for convenience: pragma VOLATILE (variable simple name); The named variable must be declared by an object declaration but can be of any type. | The pragma SHARED, when applied to a variable, tells the compiler that any write to that variable must be made visible to reads by other tasks immediately, not just when the current task reaches a synchronization point. The pragma SHARED also tells the compiler that two successive reads or a write followed by a read may return two different values, even though there is no intervening synchronization point. Furthermore, the pragma SHARED tells the compiler that it may have to generate special code to guarantee that complete values, not half the bit pattern of an old value and half the bit pattern of the new value, are read. In implementing the pragma SHARED, VAX Ada guarantees that every read or update of a shared variable is a synchronization point. VAX Ada accomplishes this by ensuring the following actions for updates: * When a shared variable is updated, the value is written to the storage allocated for the variable. * Each write is performed as an indivisible operation (to exclude the possibility of another task reading a partially updated value). * An interlocked instruction is executed so that all VAX processors that share memory with the current processor are informed that the update has taken place (to keep other processors from continuing to read an old value for the variable and for any volatile variables out of their memory cache). 8-28 Tasking Similarly, VAX Ada ensures the following actions for reads: e Each read is from the storage allocated for the shared variable. e Each read is performed as an indivisible operation; however, other processors are not informed of the read. VAX Ada ensures the indivisibility of reads and updates of variables specified by a pragma SHARED as follows: Only those scalar or access variables whose storage size does not exceed a longword (32 bits) are allowed. For example, you cannot specify variables of the type D_FLOAT, G_FLOAT, or H_FLOAT in a pragma SHARED. e By allocating longword-aligned longwords for all shared variables whose storage size is larger than a byte. e By using a restricted set of VAX instructions to read and write such variables. The pragma VOLATILE tells the compiler that any write by the current task to the specified variable must be made visible to reads by other tasks before the current task writes a variable for which the pragma SHARED was specified, not just when the current task reaches a synchronization point. The pragma VOLATILE does not guarantee that the change will be seen by another task before then. The compiler must make such writes immediately visible to ASTs and system services that are invoked by the task and read the variable. The pragma VOLATILE also tells the compiler that two successive reads or a write followed by a read may return two different values, even though there is no intervening synchronization point. Unlike the pragma SHARED, the pragma VOLATILE does not guarantee indivisible access. To ensure indivisible access for a variable in your program, you must ensure that sharing of the variable is synchronized by tasking events or a write to a variable for which pragma SHARED has been specified. The following example explains the difference between shared and volatile variables. Suppose that you have an access variable named PTR, which you use to control a loop that is executed by a task: while PTR /= null loop delay 1.0; end loop; Tasking 8-29 If you did not declare PTR with the pragma VOLATILE or SHARED, another task could write a nonnull value into PTR’s location, and the loop would repeat forever. The loop will also repeat forever if it is checking a value of PTR that was read before the loop was entered. If PTR is declared with the pragma VOLATILE, then the loop will repeat only until a synchronization point is reached by the task that wrote PTR (the writing task may be running on a different processor, and the new value is not guaranteed to be made visible to other processors until the synchronization point). Also, the value read for PTR may not equal null, or the value read may have half the bit pattern of null and half the bit pattern of the new value, in which case, the value may not be a legal access value. If PTR is declared with the pragma SHARED, then the loop will not repeat indefinitely even though the task that wrote PTR did not reach another synchronization point. Also, the update and read are guaranteed to be indivisible. You can use the pragmas VOLATILE and SHARED together to coordinate the sharing of information among tasks. For example: INFO : pragma INFORMATION RECORD; VOLATILE (INFO) ; INFO VALID pragma : BOOLEAN INFO.SOME_FIELD INFO := FALSE; SHARED (INFO VALID) ; VALID := := SOME VALUE; TRUE; In this example, the pragma VOLATILE ensures that when INFO.SOME _ FIELD is assigned the value SOME_VALUE, the value is stored in the storage area allocated for INFO.SOME_FIELD, and not into a temporary copy or a register. The pragma SHARED makes the assignment to INFO_ VALID a synchronization point, thus guaranteeing that the values for INFO and INFO_VALID will both be visible to other tasks. The pragma SHARED makes it possible for a task to poll the value of INFO VALID while waiting to access INFO from another task. However, because polling is a kind of busy waiting that takes a fair amount of CPU time, it is usually much better to use a synchronized event to determine completion. For example, you can synchronize a task with event flag wait completion, AST delivery, rendezvous with another task, and so on. 8-30 Tasking 8.4.8 Reentrancy In most VAX languages, three kinds of reentrancy are possible: serial, recursive; and AST reentrancy. A fourth kind, full reentrancy, is important for Ada programs that have tasks. A routine is serially reentrant if it must execute to completion before it is allowed to be called again. FORTRAN routines are usually serially reentrant. To understand recursive reentrancy, consider a routine that executes to the point of another call to itself; it makes the call to itself (a recursive call), and then continues to make recursive calls until a statement is executed or a condition occurs that ends the recursion. Then, the statements after the point of the recursive call execute, until finally the original call completes. If no calls are permitted until the original call has completed, the routine is said to be recursively reentrant. A recursively reentrant routine is also serially reentrant. AST reentrancy means that at a random point during the execution of a routine, an AST can occur and the routine may be reentered (by the AST call). The VMS operating system does not normally allow more than one AST service routine to be called at a time for any given access mode. So, if a routine is AST-reentrant, it may be designed to permit at most two calls to be in progress at any one time. An AST-reentrant routine is also serially reentrant. A routine is fully reentrant if it gives correct results when called by multiple tasks whose execution can be suspended at arbitrary points (and resumed in arbitrary orders) in the routine’s code. A routine that is fully reentrant is also necessarily AST reentrant, recursively reentrant, and serially reentrant. The following sections discuss reentrancy in the context of mixed-language programs involving Ada tasks. Unless explicitly qualified, the term reentrant denotes full reentrancy. 8.4.8.1 Reentrancy in Mixed-Language Tasking Programs You must be careful when calling non-Ada routines from VAX Ada tasks, be- cause the results will be unpredictable if the routines are not fully reentrant. All VMS system service and most VMS Run-Time Library routines are fully reentrant. In particular, most language-independent Run-Time Library routines (LIB$, MTH$, OTS$, and STR$ routines) are fully reentrant (see the VMS Run-Time Library Routines Volume). However, any routine that modifies variables outside its immediate scope or that modifies variables Tasking 8-31 allocated in static storage is potentially nonreentrant. Also, any language- dependent run-time library routines may be nonreentrant. For example, the FORTRAN run-time library is only AST (not fully) reentrant. 8.4.8.2 Avoiding Nonreentrancy The subprogram in Example 88 shows that if you allow a nonreentrant Ada subprogram (or non-Ada routine) to be reentered, the results can be unpredictable. Example 8-8: A Nonreentrant Subprogram package CONTAINER is -— Function to return 1 + I (its argument). function NONREENTRANT (I : INTEGER) return INTEGER; end CONTAINER; package body CONTAINER is GLOBAL VARIABLE : INTEGER function NONREENTRANT (I : := 0; INTEGER) return INTEGER is begin GLOBAL VARIABLE return := I; (GLOBAL VARIABLE + 1); —-— Statement Sl1. -— Statement S2. end NONREENTRANT; begin null; end CONTAINER; In Example 8-8, the function NONREENTRANT returns 1 plus the value of its argument, I. NONREENTRANT is a serially reentrant subprogram. However, it cannot be called simultaneously by multiple tasks and still produce correct results. For example, consider the following sequence of events: * The subprogram NONREENTRANT is called by task A, which passes a value of 3 for L. 8-32 Tasking e A is interrupted just before statement S2 because a higher priority task, B, has become ready. e Then, B calls NONREENTRANT and passes a value of 1000 for I (that is, B reenters the subprogram while a previous call is in progress). Although the execution of NONREENTRANT by A sets GLOBAL_ VARIABLE to 3, the intervening execution by B changes the global variable to 1000. When task A finally resumes execution, NONREENTRANT returns a value of 1001, instead of the correct answer, which is 4. There are three ways to avoid the problem shown in Example 8-8: e Write the routine or subprogram so that it is reentrant. e Ensure that only one task can call the nonreentrant routine or subprogram. e Serialize the calls to the nonreentrant routine or subprogram (see Example 8-10 at the end of this section). To code a reentrant subprogram in VAX Ada, make sure it does not modify any nonlocal or static variables and make sure that it does not call a nonreentrant subprogram (or routine). If you import a non-Ada routine, be aware that it can be reentered if it is imported several times in the same Ada program or if it is imported once and then called from different tasks. In Example 8-9, the function NONREENTRANT from the Example 8-8 is rewritten so that it is reentrant. Advantage has been taken of the fact that each time a subprogram is entered, its local variables are allocated on the stack. If tasks A and B were to call the following subprogram, each activation of function REENTRANT would create a separate copy of LOCAL_ VARIABLE, and interference would not be possible. Example 8-9: A Reentrant Subprogram function REENTRANT (I LOCAL VARIABLE : : INTEGER) INTEGER := return INTEGER is 0; begin LOCAL VARIABLE return := I; (LOCAL VARIABLE + 1); -— Statement S1l. -— Statement SZ2. end REENTRANT; Tasking 8-33 The second solution is to structure your program to ensure that the nonreentrant subprogram can only be called by a single task at a time. For example, if a procedure is defined in the declarative region of the same task that calls it, and the task creates no dependent tasks, then the subprogram cannot be reentered. The third solution applies especially to existing nonreentrant Ada subprograms, non-Ada routines, or software over which you have no control. You can use a task to prevent reentry by serializing the calls to the reentrant code so that it cannot be reentered. Example 8-10 shows one way to perform serialization. Example 8-10: Using a Serializing Task to Prevent Reentry package FIX IT is —— This —— NONREENTRANT. function function ADD should be It ONE (I too : called returns INTEGER) instead of 1 + I return (its argument). INTEGER; end FIX IT; —— —— — ——— N G——— -— out INTEGER); e ew . . — with CONTAINER; use CONTAINER; package body FIX IT task is SERIALIZER is entry DQ_CALL(I : INTEGER; J : end; task body —— This -- cannot SERIALIZER is task calls be NONREENTRANT and ensures that it reentered. begin loop select accept J DO_CALL(I := : INTEGER; J : out INTEGER) do NONREENTRANT (I) ; end; or terminate; end select; end loop; end; (continued on next page) 8-34 Tasking Example 8-10 (Cont.): function ADD ONE RESULT : Using a Serializing Task to Prevent Reentry (I : INTEGER) return INTEGER is INTEGER; begin SERIALIZER.DO CALL(I, RESULT):; return RESULT; end; end FIX IT; In Example 8-10, the task SERIALIZER calls a nonreentrant subprogram in the body of an accept statement. All calls to the nonreentrant code go through the intermediate call to ADD_ONE, and the function NONREENTRANT cannot be reentered. You can also use a serializing task to allow nonreentrant routines or subprograms to be called from multiple tasks. The serializing task prevents reentry, but you must make sure that it makes all of the calls. This method is recommended when you call any routine or subprogram whose reentrancy is uncertain and you cannot guarantee that reentrant calls will not be attempted. 8.5 Calling VMS System Service Routines from Tasks VAX Ada provides the package STARLET (see Chapter 6) as well as import-export pragmas (see Chapter 5) to allow you to call VMS system services and make VMS RMS requests directly from an Ada program. In addition, VAX Ada provides a package of selected asynchronous system routines—TASKING_SERVICES—to make such routine calls easier to make from tasks. The following sections discuss the implications of calling system routines from tasks. If you are coding system services that involve ASTs, see also Section 8.6. 8.5.1 Effects of System Service Cails on Tasks When you call VMS system services from an Ada program, your process 1is not totally “blocked.” Most system services that put your process in a wait state permit that wait state to be interrupted by ASTs (see the Iniroduction to VMS System Services). To VAX Ada, a task that has entered a VMS wait Tasking 8-35 state appears to be continuing to execute (because VAX Ada does not in any way intercept system services); VAX Ada does not know that the task is in any way blocked. Thus, the only tasks that can execute while the system service is executing are tasks that have higher priorities than the calling task, or, if time slicing is 1n effect, tasks that have a priority equal to the calling task. (The transfer of control to these other tasks can occur when an AST for one of these tasks is delivered to the VAX Ada run-time library—for example, when a delay or time slice expires, an Ada input-output request completes, or an AST is delivered to a task entry specified with the pragma AST ENTRY.) This default behavior is not necessarily bad, because waiting for the system service to complete is the default behavior of most nontasking VMS programs. Indeed, if the request is satisfied quickly, allowing any other task to execute could be wasted effort. You may, however, wish to increase concurrency and allow tasks of lower priority to execute while a higher priority task is in a VMS wait state. Provided that the system service request takes a sufficiently long time, this strategy can allow your program to do more useful work in the same elapsed time. VAX Ada provides you with two methods for increasing concurrency during a VMS system service wait interval. One method is to have tasks that call time-consuming system services use asynchronous system services or asynchronous VMS RMS services. Then, your program can do other work until it has to handle the resulting VMS ASTs that signify completion of the request. Handling ASTs is a very general and powerful way to increase concurrency, but it also requires more detailed programming. See Section 8.6. The second method for increasing concurrency is to use the VMS systemroutine operations provided in the VAX Ada package TASKING_SERVICES. Like the system routines provided in the package STARLET, the operations in this package provide an interface to a variety of VMS system service and RMS routines. But the operations in the package TASKING_SERVICES are designed to suspend (in the Ada sense) the calling task if the request cannot be immediately satisfied. Other ready tasks (including lower priority tasks) in your program are free to execute or continue executing. The operations in the package TASKING_SERVICES increase concurrency by calling the asynchronous form ef a system service routine (for example, SYS$QIO instead of SYS$QIOW), and then suspending the task and using an AST to signal when the service has completed and the execution of the task can resume. The details of AST handling are hidden by the package. 8-36 Tasking While this package can help you increase concurrency, in many cases, it has two limitations: you cannot use the operations in the package TASKING_ SERVICES to specify an AST routine address or an AST parameter. If your application depends on being able to use such information, you may wish to do your own AST handling as described in Section 8.6. The specification of the package TASKING_SERVICES is presented in Appendix B. 8.5.2 System Services Requiring Special Care Certain system services are especially likely to interfere with Ada programs that use tasks, ASTs, or the package TASKING_SERVICES (see Section 8.5.1). You should either avoid or use extra care when using the following services: SYS$SETAST STARLET.SETAST SYS$HIBER STARLET.HIBER SYS$EXIT STARLET.EXI SYS$DCLEXH STARLET.DCLEXH Because they affect a VMS process, these services have a global effect on all tasks of the program. For example, SYS$SETAST prevents delivery of ASTs. Because the VAX Ada run-time library relies heavily on the use of ASTs (they are used to implement delay statements, time slicing, input-output, and so on), disabling ASTs with SYS$SETAST can cause deadlocks (see Example 8-11). This effect can cause these tasks to stall until ASTs are reenabled. If you must use SYS$SETAST, do not take any of the following actions while ASTs are disabled: e Execute Ada input-output statements (for example, TEXT 10.PUT_ LINE). e Execute a delay statement. * Propagate an unhandled exception. * Execute any of the tasking operations described in Chapter 9 of the VAX Ada Language Reference Manual (for example, make entry calls, execute accept or select statements, and so on). In other words, do not create or wait for dependent tasks. ~ Tasking 8-37 Example 8-11: Deadlock Caused by a Call to SYS$SETAST procedure SETAST DEADLOCK is task T is entry E; end; task body T is begin delay 10.0; accept E; end; -— Procedure to set AST enablement procedure SETAST (SETTING : BOOLEAN) to SETTING. is separate; begin SETAST (FALSE) ; T.E; —- At -—- this peoint, task T is delayed, for the timer AST that -- the wait. The —— because the -— But, because waiting signifies the end of folleowing entry call must task has the call not reached the to SETAST has -- the delay will never complete, —- will this entry call. suspend accept statement. disabled ASTs, and thus neither SETAST (TRUE) ; end SETAST DEADLOCK; Busy wait on a flag (a variable) that is to be set by another task. Call a subprogram that involves any of the preceding actions. SYS$HIBER suspends execution of a VMS process. The VAX Ada run-time library uses SYS$HIBER to make your process hibernate when there are no currently ready tasks, If your program also uses SYS$HIBER, make sure that the SYS§WAKE it is waiting foris entered only when the process is waiting for your SYS$HIBER request (and not for the SYS$HIBER request of the VAX Ada run-time library)—the SYS$WAKE you enter may be consumed by the call to SYS$HIBER of VAX Ada, and your hibernating process will not wake up. SYS$EXIT causes an unconditional program exit. In particular, it does not wait for dependent tasks to terminate normally. Thus, by using SYS$EXIT, you may prevent your Ada program from executing code that it would otherwise execute normally. Unless you are careful that all tasks are terminated or in a state where termination is not needed, the results can be unpredictable. See Example 8-12. 8-38 Tasking Example 8-12: with TEXT_IO; Unpredictability of SYS$EXIT use TEXT IO; procedure PULL THE RUG OUT pragma TIME SLICE (1.0); type CONDITION is new STATUS : is INTEGER; CONDITION; task T; task body T is begin for I in PUT 1..10 loop LINE("I'm T delgy 1.0; and I’'m not done yet."): end loop; PUT LINE("T is done now."); end; procedure DO EXIT (STATUS EXIT STATUS : out : in CONDITION CONDITION; pragma INTERFACE (VMS, pragma IMPORT VALUED PROCEDURE (DO EXIT, := 1); DO_EXIT); "SYSSEXIT", MECHANISM => (VALUE, VALUE)); begin delay 5.0; PUT LINE ("Pulling the rug out from T NOW."); DO _EXIT (STATUS) ; end PULL THE RUG OUT; If you use SYS$DCLEXH to establish exit handlers, make sure you understand that not all Ada operations can be executed reliably from VMS exit handlers. Thus, there are some restrictions on exit handlers written in Ada. These restrictions are the same as those for AST handlers, and they stem from the fact that exit handlers can be invoked asynchronously, such as when you press CTRL/Y at the terminal. (See Section 8.6.3 for the restrictions on using AST handlers.) Specifically, a VMS exit handler written in Ada must not take any of the following actions: e Execute an Ada input-output statement. e Execute a delay statement. * Propagate an unhandled exception. * Execute any tasking operation. Tasking 8-39 * Busy wait on a flag (a variable) that is to be set by another task. * (Call a subprogram that involves any of the preceding actions. Note that the Ada run-time library makes use of a special input-output exit handler that flushes input-output buffers (those that are unlocked) at the time of exit, so user exit handlers should not be needed for the purpose of flushing and closing files. Another good reason for avoiding Ada exit handlers is that they are nonportable. 8.6 Handling Asynchronous System Traps (ASTs) ASTs are a way for the VMS operating system or VMS RMS to notify a process (which may be actively executing instructions) that some event has occurred. Many VMS system services allow you to specify that an AST be delivered when the service completes or when some event related to the service occurs. Such services often have two forms: * A synchronous form that forces the process to wait until the service is completed * An asynchronous form that initiates the service, and immediately returns, allowing the process to continue and the service to be completed independently For example, the synchronous VMS system service SYS$QIOW makes the process wait until the service completes, but the asynchronous form, SYS$QIO, does not; both forms allow you to specify an AST service routine. By handling ASTs from your Ada program, you can increase concurrency during the process wait states that result after your program executes certain system service or VMS RMS requests. Before you decide to handle ASTs directly, you should investigate the package TASKING_SERVICES to see if you can use any of its operations instead (the operations in the package TASKING_SERVICES are more convenient to use); see Section 8.5.1. 8.6.1 The Pragma AST_ENTRY and the AST_ENTRY Attribute You handle ASTs in VAX Ada with the ENTRY attribute. 8-40 Tasking AST ENTRY pragma and AST_ For a formal description of the AST ENTRY pragma and attribute, see Chapter 9 of the VAX Ada Language Reference Manual. Informally, the AST _ENTRY pragma and attribute provide a mechanism that transforms the delivery of an AST into a special kind of entry call. As in an ordinary entry call, if the task does not immediately accept the call, the AST entry call becomes enqueued on the entry. For example: with STARLET; use STARLET; task HANDLER 1is ~— Entry -- well entry RECEIVE AST can receive AST entry calls as as normal entry calls. RECEIVE AST; pragma AST ENTRY (RECEIVE_AST); end HANDLER; —= The AST ENTRY attribute supplies QIO’s ASTADR parameter -- with the address of a special AST handler that will —— schedule an entry call to RECEIVE AST. QIO( . . . | ASTADR => HANDLER.RECEIVE AST’AST_ENTRY, ) ; An AST entry call acts as if the call were made by a task that has a priority of 8. In accordance with Ada rendezvous rules, the statement list of the accept statement for this entry is executed with the higher of this priority and the priority of the accepting task. The AST parameter passed to the system service (for example, the astprm argument of the SYS$QIO system service) and later delivered by the AST is, in turn, passed to the accept statement (if a formal parameter is specified). For example: with STARLET; use STARLET; task HANDLER is ~-— Entry RECEIVE AST expects to receive an —-— AST parameter. — entry RECEIVE AST(X : INTEGER); pragma AST ENTRY (RECEIVE AST) ; end HANDLER; Tasking 841 task body HANDLER is begin accept RECEIVE AST (X:INTEGER) do end RECEIVE AST; end HANDLER; —-— QIO’s —— passed to —— when ~— receive QIO( . . ASTPRM the the parameter accept rendezvous only zero or (with a statement occurs. value as of 33) parameter (An AST entry is X can one parameter.) . ASTADR => ASTPRM => HANDLER.RECEIVE_ AST’AST ENTRY, 33); Thus, to handle ASTs, you must first specify which entry in a task type can receive AST entry calls. You do this by specifying the entry with the pragma AST_ENTRY when you declare the task type. Only single entries (not entry families) can receive AST entry calls and, therefore, only single entries can be named in the pragma AST ENTRY. To specify an AST service routine, you must use the AST ENTRY attribute. The AST_ENTRY attribute takes a task name and entry as parameters and returns an address of a special service routine created by the VAX Ada run-time library. Then, when the AST occurs, the special service routine is called; the routine enqueues the AST parameter in a special way on the requested entry, making the enqueuing look like an entry call, and then the routine returns from the AST call. Once the AST parameter is enqueued on the entry, the rendezvous can occur. The rendezvous is subject to the Ada rendezvous rules (see Chapter 9 of the VAX Ada Language Reference Manual), and so may not occur immediately. Also, the rendezvous is performed after the special service routine has returned. Thus, other ASTs are not inhibited. (This behavior is required by the nature of ASTs and the nature of Ada rendezvous.) If the entry call were made directly from the AST service routine, no other ASTs could be delivered until the rendezvous had completed, and unpredictable deadlocks could result. Such deadlocks still could develop if a non-Ada program were to call an Ada program from an AST service routine. See Section 8.6.3 for more information. 8-42 Tasking 8.6.2 Constraints on Handling ASTs Any AST delivered to a task that is completed or abnormal is ignored. In other words, the AST is ignored if it occurs for some entry of a task that is not callable but is not yet terminated (both T TERMINATED and T+ CALLABLE are FALSE). If an AST occurs for an entry of a task that is terminated (T TERMINATED is TRUE), then the program is erroneous and execution is unpredictable. The VAX Ada run-time library may not detect this situation; you must code your application so that an AST cannot occur for an entry in a terminated task. Each time an AST is delivered, the VAX Ada run-time library allocates a block of storage (an AST packet) to hold the AST parameter, and the storage is enqueued on the entry to which the AST applies. This block of storage is released only after the rendezvous has completed. If your program generates ASTs at a higher rate than it accepts AST entry calls, the total amount of storage allocated can become very high. To reduce the amount of storage consumed, write any AST-handling programs so that they accept an AST for every AST generated. You can do this easily by having the same task that accepts the AST entry call also generate the next AST. In this manner, you can limit the amount of storage consumed by pending AST entry calls. Another way to prevent this problem is to extend the size of the AST packet pool available to your program, using the package SYSTEM_RUNTIME_ TUNING. See Appendix B for more information on this package and its operations. 8.6.3 Calling Ada Subprograms from Non-Ada AST Service Routines Be very careful when using an AST service routine, or when calling an Ada subprogram from an AST service routine. If the Ada subprogram performs certain kinds of Ada operations, including input-output operations or taskrelated operations, a deadlock can develop (VAX Ada itself uses ASTs to perform these operations). If you call such an Ada subprogram from an AST service routine, or use it as an AST service routine, your program can develop a deadlock with the characteristics that one or more tasks are suspended indefinitely and ASTs can no longer be delivered. Tasking 8-43 For example, consider the following situation: You call Ada subprogram P from a non-Ada AST service routine; the AST may be delivered at any time. When the AST is delivered, the main task or a task Q in your program may have already allocated a resource that will be needed by P. In addition, Q could be currently suspended, awaiting the delivery of an AST. Because the resource is not available to P, the VAX Ada run-time library has no choice but to suspend the execution of P and switch control to another ready task. The invocation of P occurred when the ASTs were disabled, so they remain disabled after P is suspended. A deadlock has developed in this situation for the following reasons: P cannot proceed until the resource becomes available. The resource cannot be released by Q until ASTs are delivered. ASTs cannot be delivered until P and its caller return control back to the VMS environment. All of this occurs because the VMS operating system implicitly disables all AST delivery while an AST-handling routine is active. Thus, you should handle ASTs in VAX Ada as described in Section 8.6.1. If you must write AST routines in Ada, then obey the following rules to avoid the kind of deadlock described in this section. Your routine must not take any of the following actions: Execute an Ada input-output statement (for example, TEXT I0.PUT _ LINE). In other words, your routine must not use any of the inputoutput operations defined in Chapter 14 of the VAX Ada Language Reference Manual or in the VAX Ada package TASKINGSERVICES. Execute a delay statement. Propagate an unhandled exception. Execute any of the tasking operations described in Chapter 9 of the VAX Ada Language Reference Manual (for example, make entry calls, execute accept or select statements, and so on). In other words, you must not create or wait for dependent tasks. Busy wait on a flag (a variable) that is to be set by another task. Call a subprogram that involves any of the preceding actions. 8-44 Tasking 8.6.4 Examples of Handling ASTs from Ada Programs Examples 8-13 and 8-14 show the use of the pragma AST_ENTRY and the AST ENTRY attribute. Example 8-13: Simple Use of the Pragma AST_ENTRY and the AST ENTRY Attribute with TEXT IO, SYSTEM, procedure TRY ASTS STATUS : package ~- CONDITION HANDLING, CONDITION HANDLING.COND VALUE TYPE; INT IO is new TEXTIO.INTEGER IO (INTEGER) ; Task that will handle the ASTs task AST HANDLER pragma AST activated by the main program. is entry RECEIVE AST (X end STARLET; is : INTEGER):; ENTRY (RECEIVE AST) ; ASTHANDLER; task body AST HANDLER FORE : constant is TEXT IO.FIELD := 3; begin loop select accept RECEIVE AST (X INT IO.PUT (X, : INTEGER) do FORE); end RECEIVE AST; or terminate; end select; end loop; end ASTHANDLER; begin (continued on next page) Tasking 8-45 Example 8-13 (Cont.): -— Queue for I 20 ASTs in 1..20 Simple Use of the Pragma AST_ENTRY and the AST_ENTRY Attribute to be activated, and give each an index. loop STARLET .DCLAST ( STATUS, —— Condition value returned. ASTflHANDLER.RECEIVE_AST’AST_ENTRY, -— Entry to receive STARLET. ARG USER TYPE —— —— If AST. The AST parameter. DCLAST if not the (I)); fails to queue an AST, then raise CONDITION_HANDLING.SUCCESS(STATUS) then CONDITION_HANDLING.STOP the error. (STATUS) ; end if; end loop:; end TRY ASTS; Example 8-14: -— Package Using an AST Entry to Intercept a CTRL/C specification for CONTR C HANDLING. OL package CONTRO C HANDLING L is end CONTROL C_HANDLING; —- Package body with SYSTEM, for CONTR C HANDLING. OL TEXT IO, STARLET, CONDITION HANDLING, UNCHECKED CONVERSION; package body CONTRO C HANDLING L is —— Used to type SHORT specify an outband character to QIOW. FORMTERMINATOR is record ZERO : SYSTEM.UNSIGNED LONGWORD; MASK : SYSTEM.UNSIGNED LONGWORD; end record; (continued on next page) 8-46 Tasking Example 8-14 (Cont.): CONTROL_C : Using an AST Entry to Intercept a CTRL/C constant SYSTEM.UNSIGNED LONGWORD := SYSTEM.UNSIGNED LONGWORD (2**CHARACTER’POS (ASCII.ETX)):; TERMINATOR MASK := (ZERO => : constant 0, MASK => SHORT FORMTERMINATOR CONTROL C); STATUS : STATUS1 : CONDITION HANDLING.COND_ VALUE TYPE; CHAN : STARLET.CHANNEL TYPE; TERM DEV : constant —— This task services task AST SERVER entry STARLET.DEVICE NAME TYPE := "TT:"; CONTROL C outband ASTs. is CONTROL_C_HANDLER; pragma end AST CONDITION HANDLING.COND VALUE TYPE; AST ENTRY (CONTROL C HANDLER) ; SERVER; task body AST SERVER 1is ’ begin loop salect accept CONTROL C HANDLER do TEXT IO.PUT LINE("Control C was received."); end CONTROL C HANDLER; or terminate; end select; end loop:; end AST SERVER; function FROM AH TO UL is new UNCHECKED CONVERSION (SYSTEM.AST HANDLER, SYSTEM.UNSIGNED LONGWORD) ; begin —— Assign a channel to the STARLET .ASSIGN (STATUS, TERM DEV, CHAN) ; terminal. —— Condition wvalue returned. -- Terminal device to —— Channel number. if not CONDITION_HANDLING.SUCCESS(STATUS) assign to. then CONDITION_HANDLING.STOP(STATUS); end if; (continued on next page) Tasking 8-47 Example 8-14 (Cont.): Using an AST Entry to Intercept a CTRL/C —— Enable outband ASTs —— to SERVER. AST for CONTROL C; direct the ASTs STARLET .QIOW ( STATUS CHAN => => STATUS, CHAN, FUNC => SYSTEM."OR" (STARLET.IO_SETMODE, Pl => P2 => FROM AH_TO_ UL (AST_SERVER.CONTROL C_HANDLER’AST ENTRY), SYSTEM.TO_UN LONGWORD (TERMINATOR SIGNED MASK’ADDRESS)) _ ; if not CONDITION HANDLING.SUCCESS (STATUS) STARLET.DASSGN (STATUS => STATUS1, CHAN STARLET. M OUTBAND), IO then => CHAN); CONDITION HANDLING.STOP (STATUS) ; end if; end CONT C HANDLING; ROL A program that with CONTROL C_HANDLING; with TEXT IO; procedure uses the package CONTR C HANDLING. OL use TEXT IO; TRYCONTROL C is begin PUT LINE ("Press "the any next PUT LINE ("CTRL/Cs number 30 are "serviced by delay of CTRL/Cs for " & seconds."); trapped and " & CONTR C HANDLING.") OL ; 30.0; NEW LINE; PUT_LINE("Main end 8.7 program terminating ... "); TRYCONTROC; L Measuring and Tuning Tasking Performance When you use tasks in your program, you must frequently trade off between responsiveness and throughput. Responsiveness is how fast a task responds to an asynchronous event, such as a user typing at a keyboard. Throughput is how much useful work, as measured by CPU time, a program accomplishes in a given amount of elapsed time (time spent switching tasks is overhead and takes CPU cycles that could be used for useful work). 8-48 Tasking In general, if you enable time slicing with the pragma TIME_SLICE, you are increasing responsiveness at the expense of more task-switching overhead and therefore decreased throughput. Smaller values of the time-slice interval represent higher amounts of this overhead. Similarly, if you assign a higher priority to a task, you are opting for responsiveness rather than throughput. Assigning a higher priority to some task invariably means that the program will perform more task switches— every time the high priority task becomes eligible for execution, Ada rules require that it displace a currently running lower priority task. In a large program that has many tasks, not all of the effects of changing the program are immediately obvious. To help you measure the effects of a change, VAX Ada provides the VMS Debugger commands SHOW TASK/STATISTICS and SHOW TASK/FULL. See Developing Ada Programs on VMS Systems for information on debugging Ada tasks. Tasking 849 Chapter 9 Improving Run-Time Performance To write VAX Ada programs that compile and execute efficiently, you should be aware of certain compiler and language features that can affect code size, as well as program compilation and execution times. This chapter discusses the following topics: Compiler optimizations Inline expansion of subprograms Improving the performance of generics Techniques for reducing CPU time and elapsed time 9.1 Compiler Optimizations The VAX Ada compiler performs a number of standard optimizations to improve the quality of the generated code. For example, the compiler performs the following optimizations: Elimination of some common subexpressions Code hoisting from structured statements, including the removal of invariant computations from loops Inline code expansion for many predefined operations Rearranging of unary minus and not operations to eliminate unary negation/complement operations Partial evaluation of logical expressions Global assignment of variables to registers Improving Run-Time Performance 9-1 e Forward propagation of constant values ¢ Reordering of the evaluation of expressions to minimize the number of temporary values required e Peephole optimization of instruction sequences In addition, the compiler performs the following Ada-specific optimizations: e Elimination of redundant constraint checks ¢ Evaluation of all static subexpressions, even when evaluation is not required by the language; also evaluation of other compile-time constant expressions that may not be considered to be “static” expressions in the language (for example, expressions involving catenation or attributes such as T' IMAGE) e e Elimination of dead code (for example, elimination of unreachable branches with compile-time constant selectors in if and case statements) Elimination of redundant bounds checking of arrays in array subscripting and slicing ¢ Elimination of redundant address evaluations In cases where address evaluations are eliminated, the address is evaluated only once and a special increment instruction is generated. The address of A(I) in the following example is such a case: A(I) := A(I) + 1; Note that the result of this addition may be assigned to a temporary variable if a constraint check must be performed before A(I) is updated. In addition, in matrix computations like the following (A(I,J)), the address calculation tends to be calculated each time using special VAX hardware addressing for this purpose (context indexing): for I in 1 for .. Jin A(I,J) 1l N loop .. := M loop SOME VALUE; end loop:; end loop:; Depending on various details, strength reduction may alternately be used. 9-2 Improving Run-Time Performance Using the Pragma INLINE To allow you to expand subprograms inline and thereby decrease the amount of time spent in making subprogram calls, the Ada language provides the pragma INLINE. In VAX Ada, the pragma INLINE can affect your program in one of two ways: * * Explicitly—you declare a subprogram to be expanded inline. Implicitly—the compiler automatically expands subprogram bodies inline under certain conditions. Section 9.2.1 gives the conditions for the explicit use of this pragma; Section 9.2.2 gives the conditions under which implicit inline expansion takes place. See Section 9.2.3 for examples showing the use of the pragma INLINE for a variety of interesting cases. The decisions made by the compiler for the pragma INLINE are shown in compilation notes messages. In particular, they are shown at calls to the affected subprograms. For example: WO dbd WN =" 9.2 %I, (1) with INTEGER_TEXT IO; procedure type T 10 is function new "+" renames VAR1,VARZ: function Code INTEGER_TEXT IO; is INTEGER range 1..10; (X,¥Y: return INTEGER) INTEGER STANDARD."+"; T "+" generation expanded use SHOW INLINE inline := 3; (X,Y: T) return suppressed [LRM for 6.3.2; RTR INTEGER is function +, which is always 23 (from RTR 9.2] 9.2.1] begin 11 return 12 end; 13 pragma INTEGER (X*Y) ; INLINE ("+"); 14 15 16 begin PUT (VAR1+VAR2) ; .............. 1. I, %I, (1) (2) Call 2 of procedure PUT TEXT_IO at Call of function [LRM 6.3.2; line RTR 148) + at in INTEGER TEXT IO at expanded line 9 inline [LRM line 6.3.2; expanded inline 9.2] Improving Run-Time Performance 9-3 17 end; To obtain compilation notes messages, use the /WARNINGS=COMPILATION_ NOTES qualifier with the DCL ADA or ACS COMPILE or RECOMPILE commands. See Developing Ada Programs on VMS Systems for more information on these commands and this qualifier. Chapter 6 of the VAX Ada Language Reference Manual gives the syntax and placement rules for this pragma. 9.2.1 Explicit Use A subprogram for which the pragma INLINE has an effect is considered to be inlinable. You can use the pragma INLINE to explicitly expand a subprogram declaration or body inline only under the following conditions. * The parameters can be of any type except the following: — A task type — A composite type that has components of a task type Function results can be of any type except the following: e 94 — A task type — A composite type that has components of a task type — An unconstrained array type — An unconstrained type with discriminants (with or without defaults) The body of the subprogram cannot contain any of the following: — A subprogram body, task or generic declaration or body stub (a subprogram declaration for an imported subprogram is allowed) — A package body (a package specification is allowed) — A generic instantiation — An exception declaration — An access type declaration (a type derived from an access type is allowed) — An array or record type declaration — Any dependent tasks (that is, any constant or variable declaration that implies the creation of a task) Improving Run-Time Performance — Any subprogram call that denotes the given subprogram (direct recursion) or any containing subprogram, either directly or by means of a renaming You can use the pragma INLINE for an implicit operator declaration or for a derived subprogram declaration, as follows: e If you use the pragma INLINE for an implicit operator declaration, the pragma is accepted but has no effect. “Calls” of implicit operators are implemented by inline code in nearly all cases. (Where VMS Run-Time Library routines are used, as for some exponéntiations, no alternative inline code sequence is provided.) ¢ If you use the pragma INLINE for a derived subprogram declaration, the pragma is accepted but has no effect. Calls of derived subprograms are implemented as inline type conversions preceding and/or following a call of the parent subprogram as appropriate to the formal parameters and, in the case of a function, the result. The call of the parent subprogram is expanded inline according to whether a pragma INLINE has been given (explicitly or implicitly) for that parent subprogram and whether the parent subprogram itself is inlinable. You can use the pragma INLINE for a generic subprogram instantiation, for a generic subprogram declaration, or for a subprogram body stub declaration, as follows: e If you use the pragma INLINE for a generic subprogram instantiation, the resulting subprogram must satisfy the preceding restrictions. You can use the pragma INLINE for an instantiation of a predefined generic declaration (such as for UNCHECKED_CONVERSION), but you will not achieve any benefit because such instantiations always result in (implicit) inline code. e If you use the pragma INLINE for a generic subprogram declaration, the resulting effect is that an implicit pragma INLINE (see Section 9.2.2) then applies to every generic subprogram instantiation of that declaration; that implicit pragma is accepted provided the resulting subprogram satisfies the preceding restrictions. (That is, some instantiations may be inlinable, while others may not be, depending on the characteristics of the generic actual parameters.) e If you use the pragma INLINE for a subprogram body stub declaration, the subprogram signature must satisfy the preceding restrictions for the parameters and result. Calls of such stubs are never expanded inline within that same unit because the dependent stub is not necessarily available. Improving Run-Time Performance 9-5 If a pragma INLINE applies to a subprogram resulting from an instanti- ation, and if the instantiation and call are in the same unit, the compiler attempts to expand the instantiation inline so as to expand the subprogram call inline. If the inline expansion of the instantiation is successful, a dependence is established on the generic body. (Do not confuse the inline expansion of instantiations with the inline expansion of subprogram calls; see Section 9.3.1 for more information.) Note that a pragma INLINE contained within a generic declaration or tem- plate is not checked as such. The check occurs, according to the preceding rules, for each instantiation that results in a (nongeneric) subprogram. Also note that code is usually still generated for an inlinable subprogram to allow for normal calls (possibly in previously compiled units) that cannot be or were not expanded inline (see the following paragraph). However, if the subprogram qualifies to be implicitly expanded inline (as described in Section 9.2.2), then code is not generated. A call to a subprogram is expanded inline provided that the following are true: * The subprogram has the pragma INLINE specified and is inlinable. * The call is not contained in the result of expanding a call of that same subprogram (indirect recursion). * The subprogram body is available in either the current unit or in the compilation library (the library secondary unit must not be obsolete). (Note that the inline expansion of a subprogram body from a unit in the compilation library creates a dependence on that unit.) 9.2.2 Implicit Use The VAX Ada compiler may assume an implicit pragma INLINE for a subprogram body that has one or more of the following characteristics: * Satisfies all of the requirements for an inlinable subprogram (see Section 9.2.1). * Is local to the current compilation (so that it cannot be called from any other unit). A pragma INLINE may be assumed for subprograms with nonlocal calls, depending on the value of the /OPTIMIZE=INLINE compilation qualifier (see Developing Ada Programs on VMS Systems). * 9-6 Contains no calls to any other inlinable subprogram. Improving Run-Time Performance e Has an estimated code size when expanded inline that is no greater (or only slightly greater) than the call it replaces. (The estimation of size is based on heuristics and is not exact; however, it is designed to give a close approximation.) When local implicit inline expansion is done, no code is generated for the subprogram declaration and every call is expanded inline. See Developing Ada Programs on VMS Systems for more information on how inline expan- sion affects unit dependences, obsolete units, and recompilation. 9.2.3 Pragma INLINE Examples The following sections show some special cases of the use of the pragma INLINE and give examples of using it with generics. In particular, note that the placement of the pragma is important with nongeneric subprograms: if the pragma appears after a subprogram specification it has a different effect than when it appears after a subprogram body. 9.2.3.1 Inline Expansion of Subprogram Specifications and Bodies When you apply the pragma INLINE to an inlinable subprogram specification, inline expansion takes place for any call of the subprogram. For example: package INLINE SPEC is PKG_VAR: INTEGER function INLINED F pragma end := 20; (X: INTEGER) return INTEGER; return INTEGER is INLINE (INLINED F); INLINE SPEC; package body function INLINE SPEC INLINED F (X: is INTEGER) begin return X*10; end; begin PKG VAR := INLINED F (PKG _VAR); end INLINE SPEC; -— Expanded inline. Improving Run-Time Performance 9-7 with INLINE SPEC; with INTEGER TEXT IO; use INLINE SPEC; use INTEGER TEXT IO; procedure USE INLINE SPEC VAR: INTEGER := is 10; begin PUT (INLINED F (VAR)): —-- Expanded inline as ——- as the package body —— the package —-- is available. long for INLINE SPEC PUT (INLINE SPEC.PKG VAR); end USE INLINE SPEC; Here, INLINED_F is expanded inline both in the body of the package INLINE_SPEC and in the procedure USE_INLINE_SPEC, which also calls INLINED_F. Because a with clause makes the specification (not the body) of a subprogram available to another compilation unit, the application of the pragma INLINE to the body of a subprogram causes inline expansion to take place only where the body is visible. Thus, if the package INLINE_SPEC were rewritten so that the pragma INLINE applied to the body of INLINED_F, inline expansion would occur only in the call to INLINED_F in the body of the package in which it was declared: package INLINE BODY is PKG_VAR: INTEGER function INLINED F := 20; (X: INTEGER) return INTEGER; end INLINE BODY; package body function INLINE BODY INLINED F (X: is INTEGER) return INTEGER is begin return X*10; end; pragma INLINE (INLINED F); begin PKG_VAR := INLINED F (PKG VAR) -=- Expanded inline. end INLINE BODY; with INLINE BODY; with INTEGER TEXT IO; use INLINE BODY; use procedure USE INLINE BODY VAR: INTEGER := INTEGER TEXT IO; is 10; begin PUT (INLINED_ F (VAR)):; PUT (INLINE BODY.PKG VAR) ; end 9-8 USE_INLINE BODY; Improving Run-Time Performance -— Not expanded inline. When you apply the pragma INLINE to a library subprogram body that does not have a corresponding specification, the effect is the same as the effect you get when you apply the pragma INLINE to a specification. For example: function INLINED F (X: INTEGER) return INTEGER is begin return X*10; end INLINED F; pragma INLINE (INLINED F); with INLINED F; with INTEGER_TEXT IO; use procedure USE INLINED F VAR: INTEGER := INTEGER TEXT I0; is 10; begin PUT (INLINED F (VAR)); —-- Expanded inline. end USE_INLINED F; Here, the procedure INLINED_F is expanded inline in the call from the procedure USE_INLINED_F. 9.2.3.2 Inline Expansion of Generic Subprograms When you apply the pragma INLINE to a generic subprogram, any subsequent instantiations are potentially inlinable (assuming they meet the requirements outlined in Section 9.2.1). For example: generic type T procedure pragma limited private; GEN_PROCEDURE; INLINE (GEN PROCEDURE) ; procedure O: is GENPROCEDURE is T; begin null; end GEN_PROCEDURE; with GENPROCEDURE; procedure USE GENPROCEDURE task type TASK TYPE type ARR is procedure array is is end; (1..10) INT PROCEDURE of TASK TYPE; is new GEN PROCEDURE (INTEGER); procedure ARRPROCEDURE -- Inlinable. -- Not is new GENPROCEDURE (ARR) ; inlinable. Improving Run-Time Performance 9-9 task body TASK TYPE is begin null; end; begin INTPROCEDURE; =-- Expanded inline. ARRPROCEDURE; ~-- Not expanded inline. end USE GENPROCEDURE; Here, the procedure USE_GEN_PROCEDURE.INT_PROCEDURE is inlinable, and, in fact, is expanded inline when it is called from USE_ GEN_PROCEDURE. USE_GEN_PROCEDURE.ARR_PROCEDURE is not inlinable, because it instantiates GEN_PROCEDURE with an array of tasks (anything involving dependent tasks cannot be expanded inline; see Section 9.2.1). Note that to expand the call to USE_GEN_PROCEDURE.INT_PROCEDURE inline, the procedure USE_GEN_PROCEDURE establishes a dependence on the generic procedure body GEN_PROCEDURE. Because of the dependence, the instantiations USE_GEN_PROCEDURE.INT _PROCEDURE and USE_ GEN_PROCEDURE.ARR_PROCEDURE are expanded inline (do not confuse the inline expansion of instantiations with the inline expansion of subprogram calls; for example, see Section 9.3.1). The dependence means that if the body for the generic procedure GEN_PROCEDURE is later compiled again or replaced, the procedure USE_GEN_PROCEDURE will become obsolete and will need to be recompiled. See Developing Ada Programs on VMS Systems for more information. When you apply the pragma INLINE to subprograms that are declared inside a generic package or subprogram, they are potentially inlinable in an instantiation (again, assuming that they meet the requirements outlined in Section 9.2.1). For example: generic type T package is limited private; GEN INLINE is procedure DECLARE VAR; pragma INLINE (DECLARE VAR) ; end GEN_ INLINE; - — — — — — — — — —— — — — package body GEN INLINE procedure DECLARE VAR X: T; begin null; end; end GEN INLINE; 9-10 Improving Run-Time Performance W is is G G G AU U (R SRR WG GNP SRR SIS W NN QRN W IS G ST SRR TR WG with GEN_ INLINE; procedure USE GENINLINE task type TASK TYPE type ARR is array is is end; (1..10) of TASK TYPE; package INLINE INT is new GEN INLINE (INTEGER); -- Inlinable. package INLINE ARR new GEN_ INLINE (ARR); -- Not task body TASK TYPE is inlinable. is begin null; end; begin INLINE INT.DECLARE VAR; -- Expanded INLINE -- Not ARR.DECLARE VAR; inline. expanded inline. end USE_GEN INLINE; Here, procedure DECLARE_VAR is inlinable in the instantiation INLINE_ INT; it is not inlinable in the instantiation INLINE_ARR (again, because INLINE_ARR involves tasks). Thus, the call to INLINE_INT.DECLARE_ VAR expands DECLARE_VAR inline; the call to INLINE_ARR.DECLARE_ VAR does not. Note that to expand the call to INLINE_INT.DECLAR_VAR inline, the procedure USE_GEN_INLINE establishes a dependence on the generic package body GEN_INLINE. Because of the dependence, the instantiations INLINE_ INT.DECLARE_VAR and INLINE_ARR.DECLARE_VAR are expanded inline. 9.3 Making Use of Generics VAX Ada offers a number of features that allow you to improve the compilation time and performance of programs that use generics. For example: * You can control how code is generated for generics by using the pragmas INLINE_GENERIC and SHARE_GENERIC or by using a number of equivalent /OPTIMIZE compilation qualifier options. The pragma INLINE_GENERIC causes the compiler to expand the generic body inline at the point of instantiation. The pragma SHARE_ GENERIC causes the compiler to generate code that can be shared by several instances of the same generic. Table 9-1 compares the effects of these two pragmas with the default behavior. Improving Run-Time Performance 9-11 The decisions made by the compiler for these pragmas are shown in compilation notes messages, which you can obtain with the /WARNINGS=COMPILATION_NOTES qualifier at compile time. See Developing Ada Programs on VMS Systems for more information on the /WARNINGS and /OPTIMIZE qualifiers and their options. e You can use the predefined library-level instantiations provided for commonly used generics; for example, LONG_FLOAT TEXT_IO, LONG_ FLOAT_MATH_LIB, and so on. Table 9—1: Comparison of the Effects of the Pragmas INLINE_GENERIC and SHARE_GENERIC Pragma INLINE_ Neither Pragma Pragma SHARE_ GENERIC Effect Applies (Default) GENERIC Applies Applies Instances are com- Yes Yes piled separately from No; generic is expanded inline the unit in which the instantiation occurred. at the point of instantiation The unit containing the instantiation depends on the unit containing the No No Yes No Usually No Yes, if suitable Yes, if suitable No generic body. The code generated for the instance can potentially be shared by subsequent instances. The instance shares code from previous instances to which the pragma SHARE_GENERIC applied. 9.3.1 Using the Pragma INLINE_GENERIC VAX Ada implements generics so that the bodies resulting from each instance of a generic are compiled separately from the unit in which the generic instantiation occurs. This implementation is similar to the way in which a subunit is compiled separately from its parent unit. It means that a compilation unit that contains an instantiation does not depend on the instantiation’s corresponding generic body, and thus does not need to be recompiled when the generic body changes. 9-12 Improving Run-Time Performance You can modify this behavior by specifying a pragma INLINE_GENERIC for the generic declaration or for a particular instance of a generic declaration. Chapter 12 of the VAX Ada Language Reference Manual gives the syntax and rules for using the pragma INLINE_GENERIC. For convenience, the syntax is summarized here: pragma INLINE GENERIC (name {,name}); The pragma INLINE_GENERIC causes the compiler to expand the generic body in the unit containing the instantiation provided that the corresponding body has been compiled and is current. Like subprogram inline expansion, generic inline expansion generally optimizes execution time. Generic inline expansion also changes the dependences among instantiations and generic bodies. For example, a unit containing an instantiation for which the pragma INLINE_GENERIC is in effect may depend on the unit that contains the generic body. The dependence means that if the unit containing the generic body is compiled again or replaced, the unit containing the instantiation becomes obsolete and must be recompiled. See Developing Ada Programs on VMS Systems for more mformatmn on dependences, obsolete units, and recompilation. — For example: generic type ITEM is private; procedure USE ITEM (A, B: ITEM); procedure USE ITEM (A, B: ITEM) is begin null; end USE_ITEM; with USE_ITEM; procedure USE_GENERIC_INLINE is procedure USE INTEGER is new USE_ITEM(INTEGER) ; pragma INLINE GENERIC (USE_INTEGER) ; X,Y: INTEGER; begin USE_INTEGER (X, Y) ; end USE GENERIC INLINE; Improving Run-Time Performance 9-13 In this example, the procedure USE_GENERIC_INLINE depends on the body for the generic procedure USE_ITEM because a pragma INLINE _ GENERIC is specified for USE_INTEGER (which is an instantiation of USE_ITEM), and because the generic procedure body USE_ITEM is available (see the restrictions at the end of this section). You can maximize generic inline expansion either by specifying a pragma INLINE_GENERIC for all instantiations, or by using the /OPTIMIZE=INLINE:GENERICS or /OPTIMIZE=INLINE:MAXTIMAL qualifiers at compile time. See Developing Ada Programs on VMS Systems for more information on the /OPTIMIZE qualifier and its options. Maximal generic inline expansion is often most effective in combination with maximal subprogram inline expansion. However, maximal generic inline expansion is usually most effective for applications that contain relatively few generic instantiations. If your application uses generics extensively, you may find that maximal generic inline expansion substantially increases program size. In such cases, generic inline expansion may increase elapsed time at run time because of increased paging. 9.3.2 Using the Pragma SHARE_GENERIC When generic inline expansion is not in effect, you can use the pragma SHARE_GENERIC to cause the same code that is generated for one instance to be shared or used by another instance. In other words, if a pragma SHARE_GENERIC applies to a generic declaration or to a specific instance, the compiler tries to generate code that can be shared by subsequent instantiations of the same generic. Chapter 12 of the VAX Ada Language Reference Manual gives the syntax and rules for using the pragma SHARE_GENERIC. For convenience, the syntax is summarized here, as follows: pragma SHARE GENERIC (name {,name}); For example: generic type INPUT TYPE is private; procedure pragma USE OFTEN procedure USE OFTEN begin null; end USE OFTEN; 9-14 (X: INPUT TYPE); SHARE GENERIC (USE_ OFTEN) ; Improving Run-Time Performance (X: INPUT TYPE) is with USE_ OFTEN; package USE SHARE GENERIC is procedure USE INTEGER is procedure USE FLOAT procedure is new USE OFTEN (INTEGER) ; new USE OFTEN (FLOAT) ; USE STRING is new USE_OFTEN (BOOLEAN) ; end USE SHARE GENERIC; In this example, the compiler generates shareable code for each of the instantiations declared in the package USE_SHARE_GENERIC. The code generated for one instance cannot be shared by another instance unless you specify a pragma SHARE_GENERIC for the instance or for the generic from which the instance was generated. You can also control generic code sharing with the /OPTIMIZE qualifier at compile time (see Developing Ada Programs on VMS Systems). Generic code sharing provides four important benefits: e It saves compilation time when the generated machine code would otherwise be large. When generic code sharing is in effect, the compiler does not have to generate code for each instantiation. e It makes a program significantly smaller when generic instantiations would otherwise generate a large amount of machine code or a large number of constants. e It gives Ada programmers the engineering advantages of a strongly typed language without consuming extra memory for multiple copies of essentially identical algorithms. In a strongly typed language, such as Ada, a program often uses generics to define operations such as mathematical functions, sorting, symbol table management, list management, and so on. The program instantiates these generics to provide the same operations on a variety of types. In an older language that does not support or encourage the use of large numbers of types (for example, FORTRAN, C, BLISS, or assembly language), such operations would have been written as one piece of code, and then “shared” among the various types. For example the VMS Run-Time Library routine MTH$SQRT would be used to take the square root of an F_floating variable regardless of whether that variable was logically meters-per-second or kilograms-per-square-meter. Similarly, to write an input-output subsystem where files of many different types needed to be supported, C or BLISS programmers would use common code to which just the address and the length of the data were passed. The same piece of code could be used to manipulate the data, regardless Improving Run-Time Performance 9-15 of the fact that one piece of data would be a file-of-STRING, another a file-of-COMPLEX_NUMBER, and so on. In effect, the programmer was organizing the sharing of the machine instructions to avoid having multiple copies of essentially identical code. Before generic code sharing was available, writing generics for oper- ations such as list management saved rewriting the same algorithms many times, but did not save the amount of code that was generated. Thus, generic code sharing eliminates one of the possible advantages of a less strongly typed language over Ada. e It allows Ada programmers to write subprograms with call-back rou- tines, again, without incurring the penalty of generating duplicate code. Another feature of older languages is the ability to provide a “call-back routine” as a variable or parameter, so that an algorithm can be tailored by its caller. For example, a SORT routine might accept COMPARE and EXCHANGE routines as parameters. The SORT routine executes the general flow of the sorting algorithm, but calls back to the specific COMPARE and EXCHANGE routines to achieve a particular kind of sort. In Ada, you pass subprograms as parameters by declaring them as formal subprogram parameters in generic declarations. For example: generic type ITEM is private; type VECTOR is with function array (NATURAL "<" (LEFT, RIGHT with procedure EXCHANGE (LEFT, procedure GENERIC SORT (LIST : range : <>) ITEM) RIGHT VECTOR) : of ITEM; return BOOLEAN; in out ITEM); is begin end; Without shared generics, this approach causes extra memory to be consumed for each instantiation; duplicate code is generated, even though the only difference between instantiations may be the call-back routines. Generic code sharing reintroduces this ability into Ada without any penalties. You can maximize generic code sharing either by specifying the /OPTIMIZE=SHARE:MAXIMAL qualifier at compile time or by specifying a pragma SHARE_GENERIC for all generic declarations and/or instantiations in your application. In some cases, maximal generic code sharing can result in a dramatic decrease in the size of your program and can greatly improve 9-16 Improving Run-Time Performance run-time performance (particularly elapsed time). However, the benefits of maximal sharing depend on the characteristics of your application. Often you can obtain the best results by specifying the pragma SHARE _ GENERIC for particular generic declarations and/or instantiations rather than compiling all units with the /OPTIMIZE=SHARE:MAXIMAL qualifier. Generic code sharing is intended to reduce the size of your program. Shared code generally executes more slowly than nonshared code because sharing adds some processing overhead and prevents optimizations that are based on the actual parameters provided for a particular instantiation. However, generic code sharing will occur only if the code that is generated for one instance is similar to the code generated for another. Thus, the execution times for shared code are often similar to those for nonshared code, particularly for larger generic packages. Note that although generic code sharing is intended to reduce the size of your program, it can increase program size under some conditions. For example: ¢ ¢ Shared code for one instance is always larger than the corresponding nonshared code. Thus, the size of your program will increase if shareable code is generated for one instance, but is never shared by another. Sharing can also increase the size of your program if generics are instantiated a relatively small number of times or if the actual parameters for each instantiation of a particular generic are sufficiently different to preclude sharing. Sharing the code for two instantiations of a large generic reduces the size of your program, but you may need to share the code for many instantiations of a smaller generic to achieve a net reduction in program size. 9.3.3 Library-Level Generic Instantiations If you have a program that makes multiple instantiations of the same generic, you can save compile time and often make your program more efficient by first creating a library package that instantiates the generic and then making that package available to your program (by using with and use clauses). For example, suppose that you have defined a package containing a floatingpoint type and operations on that type. Also suppose that you want to be able to include the predefined VAX Ada mathematics functions (in the generic package MATH_LIB) as operations, and you want to be able to use TEXT_IO operations to perform input and output. The most efficient way of making your type, its operations, and the instantiations of MATH_LIB and Improving Run-Time Performance 9-17 TEXT JO.FLOAT _IO available to your program is to make a library package as follows: with TEXT IO; with MATH package type use TEXT IO; LIB; MYFLOAT TYPE OPS MYFLOAT is digits is 13; package MY FLOAT TEXT IO is new FLOAT IO (MY_FLOAT); package end MYFLOAT MATH LIB is new MATH LIB (MYFLOAT); MYFLOAT TYPE OPS; When you make this package available to your program (or to parts of your program), the instantiations of TEXT_IO.FLOAT IO and MATH_LIB will be done only once (when the package is initially compiled and added to your program library), not each time you use them. VAX Ada supplies a set of predefined library packages that instantiate commonly used generics, notably the generic TEXT IO packages for integer and floating-point input and output, and the generic package MATH_LIB for floating-point mathematical operations. (See Chapter 3, Chapter 6, and Appendix B for the descriptions and specifications of these predefined packages.) For example, if you needed to use the operations in MATH_LIB and TEXT_ I0.FLOAT_IO many times throughout your program on objects of the type LONG_FLOAT, you could use the appropriate predefined packages, as follows, to save compile time and object code size: with LONGFLOAT TEXT IO; use with LONGFLOAT MATH LIB; use LONG_FLOAT MATH LIB; procedure X: MY MAIN LONGFLOAT_ TEXT IO; is LONG FLOAT; begin PUT (SIN (X)) ; end MYMAIN; The instantiations of TEXTIO.FLOAT IO and MATH_LIB for the type LONG_FLOAT are done once, but are available at all levels of MY_MAIN. 9-18 Improving Run-Time Performance 9.4 Techniques for Reducing CPU Time and Elapsed Time You can use a variety of techniques to significantly reduce the CPU time and elapsed time required to execute a VAX Ada program on a VMS system. To decrease the program’s CPU time on a particular VAX processor, you can make three basic changes to the program: ®* Decrease the number of instructions being executed. ®* Decrease the number of expensive instructions being executed. * Decrease the amount of data being read from and written to memory. To decrease the program’s elapsed time, you can also make three basic changes to the program: ® * Decrease the CPU time. Decrease the amount of time spent waiting for input-output and page faults. * Overlap the CPU time with the time spent waiting for input-output. The following sections discuss these changes and some of the techniques for making them. NOTE The VAX Performance and Coverage Analyzer (PCA) is an optional layered product, which is also included among the VAXset tools. It measures the performance characteristics of user-mode programs running on VMS systems. While the following discussions may offer some general assistance, the techniques they propose are best used in conjunction with VAX PCA. To use VAX PCA, you must have it installed on your system, and you must compile and link your program with /DEBUG qualifiers in effect. See the VAX PCA documentation for information on how to use VAX PCA. Improving Run-Time Performance 9-19 9.4.1 Decreasing the CPU Time of a VAX Ada Program The first step in decreasing the CPU time of a VAX Ada program is to use VAX PCA to identify the parts of the program that are using the most CPU time. In the parts of the program that do not use significant amounts of CPU time, you will not gain much of a performance improvement by suppressing checks, explicitly expanding subprograms inline, or otherwise writing anything other than straightforward Ada code. Thus, you should also first compile your program without the effects of the pragmas INLINE, SUPPRESS, or SUPPRESS_ALL. You can use the /OPTIMIZE=(INLINE:NONE) and /CHECK compilation qualifiers to cause the compiler to ignore any INLINE and SUPPRESS pragmas that are already in your source files. Once you have identified the part of the program that uses most of the CPU time, you should next evaluate the algorithms that you have used in that part. Wherever possible, you should replace the algorithms with significantly more efficient algorithms or you should use more efficient data structures. For example, if the algorithm in question is an expensive calculation, you may be able to replace it with some form of table lookup. Furthermore, you may be able to reorganize the program as a whole to decrease the number of times the expensive algorithms are executed. Once you have implemented the most efficient algorithms, the next step is to decrease the number of instructions executed in places where significant amounts of CPU time are being used. There are some techniques that you can use to significantly decrease the number of instructions. These techniques are discussed in the following sections. NOTE Because these techniques involve changing code (often converting small pieces of code into larger and more complex forms), you should use them only in the parts of the program that would really benefit. Again, VAX PCA can help you correctly identify the parts of the program that you should consider rewriting. Before you rewrite your Ada code, examine the machine code produced by the compiler to determine if any improvement is possible. You can examine the machine code either by stepping through it using the VMS Debugger or by examining a listing file that you have produced with the /LIST/MACHINE_CODE qualifier at compile time. 9-20 Improving Run-Time Performance 9.4.1.1 Eliminating Run-Time Checks Run-time checks are the easiest of all overhead checks to eliminate. You can eliminate run-time checks completely with the pragma SUPPRESS_ALL. However, eliminating checks in this way is not safe: an error condition that would trigger a check may still occur (for example, a null access value is deaccessed, an array is indexed outside of its bounds, and so on). Instead, you should write your program so that the compiler can deduce reliably that a check would never be triggered, and code would not be generated for the check. For example: Use subranges so that range checks are removed from loops. The compiler uses extensive knowledge of subtypes to eliminate checks or move them out of loops. If the compiler has not deduced that a check either does not need to be done or can be moved out of a loop, you can give it extra clues by defining subtypes outside of the loop. The compiler will then perform the check outside of the loop, and will use the information it gains inside of the loop to eliminate a check. For example, the following code causes a check to be done inside a loop: procedure ZERO( N, M : POSITIVE; ARRAY PARAMETER : in out -- Check ARRAY TYPE) is begin for I in N..M loop ARRAY PARAMETER(I) := 0; needed inside. end loop; end; This 1s a more efficient version: procedure ZERO( N, M ARRAY subtype S INTEGER range : PARAMETER POSITIVE; : in out ARRAY TYPE) is is ARRAY PARAMETER’'FIRST..ARRAY PARAMETER’LAST; begin for I in ARRAY S range N..M loop PARAMETER(I) := 0; -- Check done -- loop, so —-— no here, check outside the needed inside. end loop; end; Use renaming to remove checks from loops. Names involving the following constructs require checks to determine if the exception CONSTRAINT ERROR should be raised (see Chapter 4 of the VAX Ada Language Reference Manual): — An access value used as a prefix (for example, A.all) — Indexing (for example, A(23)) or slicing (for example, A(1..10)) Improving Run-Time Performance 9-21 — Selecting a component of a variant part of a record (for example, A.C) Usually the compiler detects such names as being loop-invariant, and moves them out of the loop. If the machine code indicates that this optimization has not happened, you can use a renaming outside of the loop to move the checking code outside of the loop. For example, the following block does not do an INDEX CHECK each time the loop is executed: declare COMPONENT : POSITIVE renames ARRAY OF POSITIVE (I-4); begin loop COMPONENT := {expression}; end loop; end; You can also use this technique to avoid repeated checks in code that has no loops. 9.4.1.2 Reducing Function and Procedure Call Costs You can reduce function and procedure call costs with the following techniques: Use the pragma INLINE to eliminate call and return overhead for calls of trivial subprograms. For larger subprograms, this technique helps only if the inline-expanded version of the subprogram can then be significantly optimized. This effect often happens when one of the actual parameters is a constant. The compiler automatically expands some subprograms inline, but it cannot do so if extra dependences are created. The pragma INLINE gives the compiler permission to add these dependences. The pragma INLINE also forces the compiler to expand calls inline when it would have otherwise decided that the inline expansion was not worthwhile. Use the /OPTIMIZE=INLINE:SUBPROGRAMS or /OPTIMIZE=INLINE:MAXIMAL compilation qualifier to direct the compiler to eliminate call and return overhead for calls to trivial subprograms in other units. See Developing Ada Programs on VMS Systems for more information on the /OPTIMIZE qualifier. Use the pragma ELABORATE to eliminate access-before-elaboration checks on subprograms that have been expanded inline. 9-22 Improving Run-Time Performance For very small subprograms in other units, the cost of the run-time check to see if the subprogram body has been elaborated may be significant. The pragma ELABORATE provides a way of forcing the elaboration order, and the compiler uses this knowledge to eliminate the check. For example: ~— First compilation unit. package PKG is function TRIVIAL pragma return INTEGER; INLINE (TRIVIAL); end; -—- Second compilation unit. package body PKG is I : INTEGER := 0; function TRIVIAL return INTEGER is begin I := I+1; return I; end; end; —— Third compilation unit. with PKG; pragma ELABORATE (PKG) ; procedure EXAMPLE J : INTEGER is := PKG.TRIVIAL; -- Pragma ELABORATE —— that -- been elaborated, —-= guarantees TRIVIAL’s body must so no have check 1is needed. begin null; end; Use records to pass multiple parameters quickly, and to move the evaluation of parameters to less frequently executed regions of the code. For example, the procedure EXAMPLE in the following code incurs some run-time overhead when it makes the call to PKG.PROC, because of the number of parameters and parameter evaluations: Improving Run-Time Performance 9-23 —— First compilation unit. package PKG is procedure PROC (P1, P2 : INTEGER; P3, P4 : FLOAT; P5 : BOOLEAN):; end; —-— Second compilation unit. with PKG; procedure EXAMPLE is begin for I in 1..10 PKG.PROC(1, loop I, 0.0, FLOAT(I)*3.0, FALSE); end loop; end; This example would run more efficiently if it were rewritten as follows: —— First compilation unit. package PKG is type PROC_PARAMETERS is record Pl, P2 : INTEGER; P3, P4 : FLOAT; P5 : BOOLEAN; end record; procedure PROC (P : PROC PARAMETERS) ; end; -—- Second compilation unit. with PKG; procedure EXAMPLE is P : PKG.PROC_PARAMETERS; begin P.P1 := 1; -— Notice that the P.P3 := 0.0; -— these parameters has been moved out P.P5 := FALSE; for I in 1..10 -— the of setting up loop... loop P.P2 := P.P4 := FLOAT(I)*3.0; I; PKG.PROC(P) ; “ .. -— And that end loop; end; Improving Run-Time Performance it requires —-— instructions to pass —-—= 9-24 cost one parameter. fewer Jjust of 9.4.1.3 Using Scalar Variables and Avoiding Expensive Operations on Composite Types In general, the current state of optimizing compilers is such that they are much better at generating code for operations involving simple types than they are at generating code for operations involving composite types. For this reason, and because of slight differences in the results if exceptions occur, the following changes may make a significant difference in frequently executed code: Replace complex operations on composite types with a series of simpler operations, especially if the result can be assigned directly into its final place. For example, replace an assignment like this: A (1..A’LENGTH - B’LENGTH => ' :=B & ’); With the following operations: A(l..B’LENGTH) := B; for I in A’LENGTH + 1..B’LENGTH loop A(I) =" 7; end loop; Rather than using aggregates, especially those involving run-time expressions, build values in place. For example, replace this single operation: A := (I*I, 2*J, K+0.3); With this series of smaller operations: A.Cl := I*I; A.C2 := 2*J; A.C3 := K+0.3; Sometimes it pays to pull components out into a scalar constant, so that the compiler knows that various values are not modified by assignments to other components. For example, an examination of the machine code for the following Ada code may show that V.C is being repeatedly fetched from memory: A.Cl := A.C1*V.C; A.C2 := A.C2+V.C; A.C3 := A.C3/V.C; Improving Run-Time Performance 9-25 If that is true, you should replace the Ada code with something like this: declare X : comnstant FLOAT := V.C; begin A.Cl := A.C2 := A.C2+X; A.C3 := A.C3/X; A.C1*X; end; Use access-to-composite types rather than returning large composite objects as values. For example, code like this: package AIRPLA INFONE PKG type AIRPLA INFO NE TYPE is is record WEIGHT : KILOGRAMS; end record; function GET_AIRPLANE INFO (NAME : STRING) return AIRPL INFO ANE TYPE; end; Should be replaced with code like this: package ATIRPLANE_INFO PKG type AIRPLA INFO NE TYPE is is record WEIGHT : KILOGRAMS; end record; type ACCESS AIRPLA INFO NE TYPE access function is AIRPLA INFO NE TYPE; GET AIRPLANE INFO(NAME : STRING) return ACCESS_AIRPL INFO ANE TYPE; end; Use in or in out parameters to allow the compiler to assign values directly to target variables, rather than making assignments with function results. For example: 9-26 Improving Run-Time Performance package VECTOR PKG is type VECTOR is record I, J, K : FLOAT; end record; —— Provide all three forms of ADD, —— can choose the most efficient. so that the caller function "+" (LEFT, RIGHT return VECTOR; procedure ADD (LEFT : procedure ADD (LEFT, : VECTOR) VECTOR; RIGHT : RIGHT : VECTOR; in out VECTOR); RESULT : out VECTOR) ; end; with VECTOR PKG; use VECTOR_PKG; procedure EXAMPLE (A, B begin- R := A + B; ADD(A, B, R); : VECTOR; R : out VECTOR) is \ -- Less efficient. -- More efficient. end; 9.4.2 Decreasing the Elapsed Time of a VAX Ada Program Elapsed time is a consequence of time spent executing instructions, paging, and doing input-output. You may be able to decrease the instruction execution time as described in Section 9.4.1. Once you have done that, the only alternatives are to obtain either a faster CPU or more CPUs. You should wait to explore these last two alternatives until you have examined the program’s paging and input-output behavior. The following sections discuss paging and input-output effects in more detail. Note the following information about using different or more CPUs: If you obtain a faster CPU, your program’s run-time performance will improve just by running the program if the elapsed time was spent executing instructions, rather than waiting for input-output. If you have chosen to use more than one CPU to improve performance, then you should consider breaking your single VAX Ada program into multiple VAX Ada programs, and then using either networking or shared global sections to communicate the data between them. Chapter 10 includes a section with an example program that shares memory between one or more CPUs on a VMS system. Improving Run-Time Performance 9-27 9.4.2.1 Controlling Paging Behavior Experience has shown that, in general, the VMS Linker and image activator do an excellent job of controlling the paging of a program’s instructions. The most likely cause of excessive paging is having an insufficient working set or processing the data in a “jump-around” manner. A solution to the working-set problem is either to increase the working set size, or to design your program so that it handles its data in “workingset-sized” pieces. The latter solution is very difficult to apply to existing code. The worst examples of jumping around are caused when large multidimen- sional arrays are accessed so that the first index changes the fastest. Note that this effect occurs in an opposite way in FORTRAN, where it is desirable to change the first index the fastest. 9.4.2.2 Improving Input-Output Behavior Input-output is usually bounded by the device you are using. You can gain improvements by taking one of the following actions: * Reading or writing more data to the device in a single operation e Packing the types involved, so that fewer bytes are needed for the values * Using a faster device You can also gain significant improvements by calling asynchronous inputoutput routines (RMS and system service routines), and starting read requests some time before the data being obtained is actually needed. See the VMS Record Management Services Manual for more information on RMS routines; see the VMS System Services Volume for more information on VMS system service routines. 9.4.2.3 Overlapping Unrelated Input-Output and Instruction Execution An application can sometimes exploit Ada multitasking to overlap the time spent waiting for an input-output operation with some computation. You can achieve this effect by putting the input-output in a high-priority task and the computation in a low-priority task. The difference in priorities is required so that the input-output-bound task will access the CPU of the computing task, get its next input-output started, and then wait—thus returning control to the computing task. If the computing task is given the higher, or even the same, priority, then the input-output-bound task will not be able to start its input-output as soon as possible, and thus its elapsed time will be extended. 9-28 Improving Run-Time Performance For example: —— A high-priority task to drive a graphics device at task GRAPHICS ENGINE pragma PRIORITY full speed. is (8); entry PUTPICTURE(P : ACCESS_PICTURE) ; end; task body GRAPHICS ENGINE P : is ACCESS PICTURE; begin loop accept PUT PICTURE(P : GRAPHICS ENGINE.P ACCESS PICTURE) := do P; end; DRAW (P) ; —— Draw to a hidden plane of graphics -—- memory. The device takes a while to -— do this, delay 0.1; but returns immediately. —— Give the device a chance to draw —-— the picture. FLIP VISIBLE; —-— Make the hidden plane visible -— ERASE; 0ld plane and the invisible. —-—- Erase the hidden plane of graphics. —— Again, the device takes —-— returns a while, but immediately. end loop:; end; -— A lower-priority task to task GENERATE PICTURE pragma PRIORITY decide what to draw. is (7); end; task body GENERATE PICTURE is begin loop —- {compute a new picture}; GRAPHICS ENGINE.PUT PICTURE (P) ; end loop; end; Most of the computation in this example will be done while the GRAPHICS_ ENGINE is executing its delay statement; if 0.1 second is sufficient time to do all of the computation, the device will be driven at full speed. Improving Run-Time Performance 9-29 Chapter 10 Additional Programming Considerations This chapter documents VAX Ada programming considerations that may not be immediately obvious, but that may affect the run-time behavior or performance of your VAX Ada programs. It also documents the use of some of the low-level, system-specific features of VAX Ada. 10.1 Working with Address Values To allow you to work with storage addresses, the Ada language provides the predefined type ADDRESS (in the package SYSTEM) and the ADDRESS attribute. To avoid difficult-to-isolate problems when working with values of this type or values returned by this attribute in VAX Ada, make sure that you do not use them to do any of the following: * Reference an object whose lifetime has expired. * Reference an object in an inappropriate manner (for example, you try to change a declared constant, or the value of an in parameter). * Access storage beyond the end of the amount allocated for an object. * Access a variable by more than one path, unless that variable has been declared with the pragma VOLATILE. ¢ Place a value into a variable that is inconsistent with the variable’s declared type or subtype. If a subprogram body, task body, or library package elaboration code uses the ADDRESS attribute of an out or in out formal parameter, or of a variable whose declaration does not include a pragma VOLATILE, the VAX Ada compiler will implicitly treat that parameter or variable as being locally volatile. (Being locally volatile means being volatile for all of the Additional Programming Considerations 101 immediate block statement, body, or library package elaboration code; not for any surrounding or enclosed subprogram bodies, tasks, or library package elaboration code.) The effect of this rule is to suppress optimizations that assume the compiler can detect all changes to the value of the parameter or variable. For example, the statements in the following procedure leave X with a value of 0, rather than 1. If X is not implicitly treated as being locally volatile (because of the use of X’ ADDRESS), the optimizer may generate code using the most recent assignment, or 1, when it assigns the value of X to Y. However, because X has been marked as being locally volatile, the optimizer instead generates code that causes the value at the address of X, in this case 0, to be retrieved when the assignment to Y is made. with SYSTEM; use SYSTEM; with UNCHECKED CONVERSION; procedure SHOW CONVERT is type ACCESS INTEGER is access INTEGER; function CONVERT ADDRESS TOACCESS_INTEGER is new UNCHECKED CONVERSION (ADDRESS, ACCESS_INTEGER) ; : INTEGER; Vvl : ADDRESS; V2 : ACCESS_ INTEGER; X, Y begin V1 V2 X := X’ADDRESS; := CONVERT_ADDRESS”TO_ACCESS_INTEGER(Vl); := 1; v2.all := 0; Y := X; end 10.2 -- X 1is now O, -- so0 Y is O. SHOW CONVERT; Using Low-Level System Features The predefined package SYSTEM provides a number of useful, low-level type declarations and operations. The following sections give advice on using these declarations and operations, and, where appropriate, provide some examples of possible applications. 10-2 Additional Programming Considerations 10.2.1 The VAX Device and Processor Register and Interlocked Operations Applications accessing VMS input-output space or using shared memory have special restrictions on which VAX instructions can be used. You can force the VAX Ada compiler to meet these restrictions by using the following operations defined in the package SYSTEM: Operation Equivalent VAX Instruction Function READ_REGISTER — Function WRITE_REGISTER — Move from Process Register (MFPR) Function MFPR Move to Process Register (MPTR) Procedure MTPR Procedure CLEAR_INTERLOCKED Branch on Bit Clear and Clear Interlocked (BBCCI) Procedure SET_INTERLOCKED Procedure ADD_INTERLOCKED Procedure INSQHI Procedure REMQHI Procedure INSQTI Procedure REMQTI Branch on Bit Set and Set Interlocked (BBSSI) Add Aligned Word Interlocked (ADAWI) Insert Entry into Queue at Head (INSQHI) Remove Entry from Queue at Head (REMQHI) Insert Entry from Queue at Tail (INSQTI) Remove Entry from Queue at Tail (REMQTI) The VAX Ada Language Reference Manual specifies and gives the syntax for these operations. The VAX Architecture Reference Manual and VAX Hardware Handbook give detailed information on the VAX instructions themselves. Example 10-1 shows one method of implementing a queue using the interlocked queue operations. Note that the interlocked queue operations all require quadword alignment of the queue elements. To satisfy this requirement, you can use Ada alignment clauses. However, remember that VAX Ada has some allowed restrictions on the alignments that you can specify in alignment clauses. In particular, the maximum alignment for stack-allocated record objects is a longword. See the VAX Ada Language Reference Manual for more information on the alignment clauses and the allowed restrictions. See Chapter 2 for additional information on the use of alignment clauses and for information on how and where storage for objects is allocated. Additional Programming Considerations 10-3 Example 10-1: One Use of the Interlocked Queue Operations package DEFI DYN NE QUEUE type FORWARD BACKWARD is is record FORWARD, end for BACKWARD: INTEGER := 0; record; FORWARD BACKWARD FORWARD at BACKWARD 0 at use record at mod 8; range 4 0..31; range 0..31; end record; for FORWARD BACKWARD’ SIZE type R use 64; is record FB: FORWARD_BACKWARD; VALUE: end INTEGER; record; for R use record FB end at 0 range 0..63; record; type H_PTR is access FORWARD BACKWARD; type QPTR is access R; end DEF DYN INE QUEUE; with SYSTEM; use SYSTEM; with DEFI DYN QUEUE; NE with use DEFINE DYN QUEUE; UNCHECKED CONVERSION; procedure DYNAMIC QUEUE —- This —— queue, —— the procedure add —- elements package does entries nothing more the head by removing the entries. are defined as —— implementing the —— record —— the -— queue. type package —— Example addresses of queue elements An a conversion access (not The types to delete queue head and (declared a type and then create this the of static set elements) or converting in in means declare for interlocked then access used an and of function types create tail, alternative would be (instead DEFI DYN QUEUE, NE to and access DEFINE_DYN QUEUE). -— than to queue —= is delete of in the from program) . function ADDR TOACCESS R is new UNCHECKED_CONVERSION (ADDRESS,Q PTR); (continued on next page) 104 Additional Programming Considerations Example 10-1 (Cont.): One Use of the Interlocked Queue Operations ——- Define variables for use with the interlocked queue -—- operations. INSTATUS: ) INSQ STATUS; REM STATUS: REMQ STATUS; OUT_ ADDRESS: ADDRESS; —— Define queue head and element variables for use in —— constructing the queue. HEAD: H PTR ELEMENT: := new FORWARD BACKWARD; QPTR; begin —— Given the head (HEAD), create —-— at the head (INSQHI) and tail ELEMENT := and insert them new R; ELEMENT.VALUE INSQHI some elements (INSQTI). 1; (ITEM => ELEMENT.all’ADDRESS, HEADER => HEAD.all’ADDRESS, STATUS := ELEMENT.VALUE INSQHI => IN_STATUS); new R; (ITEM := I ELEMENT 2; => ELEMENT.all’ADDRESS, HEADER => HEAD.all’ADDRESS, STATUS ELEMENT := => INSTATUS):; new R; ELEMENT.VALUE := INSQTI => ELEMENT.all’ADDRESS, (ITEM 3; HEADER => HEAD.all’ADDRESS, STATUS ELEMENT := => ELEMENT .VALUE INSQTI IN_STATUS) ; new R; (ITEM 4; => ELEMENT.all’ADDRESS, HEADER => HEAD.all’ADDRESS, STATUS => —-— Now, remove all the REMQHI (HEADER => HEAD.all’ADDRESS, ITEM IN_STATUS) ; elements from the queue. => OUT_ADDRESS, STATUS REMQHI => REM STATUS) ; (HEADER => HEAD.all’ADDRESS, ITEM => OUT ADDRESS, STATUS => REM STATUS) ; (continued on next page) Additional Programming Considerations 10-5 REMOTI REMQTI (HEADER \ Example 10-1 (Cont.): One Use of the Interlocked Queue Operations HEAD.all’ ADDRESS, ITEM => OUT ADDRESS, STATUS => REM_STATUS) ; (HEADER => HEAD.all’ADDRESS, ITEM => OUT ADDRESS, STATUS => REM STATUS) ; end DYNAMIC QUEUE; 10.2.2 Unsigned Types in the Package SYSTEM When working with the unsigned types declared in the package SYSTEM, note that they have the following ranges: UNSIGNED_BYTE 0..255 0..16#FF# UNSIGNED_WORD 0..65535 0..16#FFFF# UNSIGNED_LONGWORD -2,147,483,648..2,147,483,647 (—231..231 — 1 or MIN_INT..MAX_INT) —16#80000000#..16#7TFFFFFFF# Note in particular that the type UNSIGNED_LONGWORD is really a signed type; its range is MIN_INT..MAX_INT, not 0..2137483647 (0..16#FFFFFFFF#). The choice of range and representation for the type SYSTEM.UNSIGNED_LONGWORD is based on the following constraints: * VMS system routines often require that unsigned longwords be of an integer type, rather than, for example, an array of BOOLEAN components. * The Ada language requires that integer types be symmetric about 0. * The VAX hardware poses difficulties for operations on an integer type larger than 32 bits. For example, consider the expected declaration: type 10-6 UNSIGNED LONGWORD is Additional Programming Considerations range 0..2%*32-1; According to the Ada language rules, this declaration is equivalent to the following declarations: type UNSIGNEDLONGWORD type is new predeflned integer type; subtype UNSIGNED LONGWORD is UNSIGNED LONGWORD _type range 0..2**32-1; Because the Ada language requires that predefined integer types be symmetric about 0, the predefined type chosen for UNSIGNED_LONGWORD must have at least the following range: type predefined integer type is range - (2**32)..2**32-1; This symmetry is required because the language specifies that the predefined operations on integer types can raise the exception NUMERIC_ERROR or CONSTRAINT_ERROR only if the result is not a value of the predefined type (see Chapter 4 of the VAX Ada Language Reference Manual). If you were to declare variables A, B, C, and D to be of the type UNSIGNED_ LONGWORD in the preceding example, then an assignment statement like the following would raise an exception because it involves intermediate negative calculations (B — C), which are not values of the predefined type: A :=B - C + D; If this definition of UNSIGNED_LONGWORD were represented with the expected representation (0..16#FFFFFFFF#), then operations involving negative intermediate results would have to account for at least the value —232 — 1. The need for an extra sign bit would cause UNSIGNED_ LONGWORD operations to be carried out as quadword operations (a 32-bit longword is one bit too small to handle the value —232 — 1). Because the VAX hardware does not support all arithmetic operations on quadwords, this implementation would be inefficient. So the VAX Ada implementation defines UNSIGNED_LONGWORD as if it were an integer type, with the range MIN_INT. MAX_INT (—231, 231 _ 1) and the representation (16#800000004#.. 16#7FFFFIF#). A similar analysis applies to SYSTEM.UNSIGNED_WORD, although the inefficiency of the implementation is not as high as for UNSIGNED_WORD because longword instructions can be used for the operations on the type. Thus, the definition of UNSIGNED_WORD is the expected definition (0..65535). An alternative to the type SYSTEM.UNSIGNED_LONGWORD is the type SYSTEM.BIT_ARRAY_ 32, which is a 32-bit array type with components of the type STANDARD.BOOLEAN. The package SYSTEM also provides conversion functions so that you can convert values of the type SYSTEM.UNSIGNED_LONGWORD to the type SYSTEM.BIT ARRAY_32 and vice versa. For example, you can define your unsigned longword variables using the type SYSTEM.BIT _ARRAY_ 32 and then convert them to the Additional Programming Considerations 107 type SYSTEM.UNSIGNED_LONGWORD using the function SYSTEM.TO_ UNSIGNED_LONGWORD. For example: with SYSTEM; with TEXT IO; use TEXT IO; procedure UNSIGNED LONGWORD USE package UL_TEXT IO is new use is INTEGER IO (SYSTEM.UNSIGNED LONGWORD) ; UL TEXT IO; BASE 16: OUTPUT: VAR1l, NUMBER BASE := SYSTEM.UNSIGNED VAR2Z, RESULT: 16; LONGWORD SYSTEM.BIT := O; ARRAY 32; begin VARl := SYSTEM.BIT ARRAY 32’ (0..2 30..31 => TRUE, => TRUE, others => FALSE) ; OUTPUT := SYSTEM.TO_UNSIGNEDHLONGWORD(VARl); PUT(ITEM => BASE => OUTPUT, BASE 16); NEW_LINE; VAR2 := SYSTEM.BIT ARRAY 32’ (0 => TRUE, others => FALSE):; OUTPUT := SYSTEM.TO_UNSIGNED_LONGWORD(VAR2); PUT (ITEM => BASE OUTPUT, => BASE 16) ; NEW_LINE; end RESULT := SYSTEM."xor" (VAR1,VAR2) ; OUTPUT := SYSTEM.TO UNSIGNED PUT (ITEM => OUTPUT, BASE => BASE 16); LONGWORD (RESULT) ; USE_UNSIGNED LONGWORD; When you are working with SYSTEM.UNSIGNED_LONGWORD, note also that the following declaration will raise the exception CONSTRAINT_ERROR: X : SYSTEM.UNSIGNED LONGWORD := 16#80000000%#; Recall that —1 is not a literal; it is an expression consisting of a unary adding operator followed by a decimal literal. 16#80000000# is the decimal literal representing 231, which is 1 greater than UNSIGNED_LONGWORD' LAST. Thus, CONSTRAINT_ERROR is raised. If you need to work with “unsigned” numbers with this particular bit pattern or a pattern similar to it, use negative numbers, or the FIRST attribute. For example, the following declarations and assignments will not raise CONSTRAINT_ERROR: 108 Additional Programming Considerations with SYSTEM; procedure TRY LONGWORD is A: constant := -16#80000000%; B: SYSTEM.UNSIGNED LONGWORD C: INTEGER := := A; A; begin end 10.3 TRYLONGWORD; Working with Varying Strings Because Ada does not have a predefined varying string type, you must use a record or an access type to declare a varying string in Ada. When working with varying strings, be aware that one of the most common ways to raise the exception CONSTRAINT_ERROR occurs in the following case: subtype STRING SIZE type V_STRING (SIZE is NATURAL range 0..NATURAL’LAST; : 0) STRING SIZE := is record L : STRING SIZE; S : STRING(l..SIZE):; end record; X: V_STRING; —— The —-— (NATURAL’LAST maximum size —-— than —— in —— Unconstrained the a VAX + of 8) records is a largest wvalue 32-bit integer of this number that that can be type is greater computed (NATURAL’LAST). object. In this case, X is an unconstrained object, to which any value of the type V_STRING can be assigned. For such objects, the Ada language standard permits an implementation to allocate the maximum size required for any value of the type at the time the object is elaborated; VAX Ada, in fact, does just this. So, when X is elaborated, the compiler tries to allocate space for the largest object of the type V_STRING. First, the compiler computes the maximum size for an object of the type. This computation, like any integer computation in VAX Ada, must not exceed the implementation- defined limit for type INTEGER (SYSTEM.MAX_INT, or 231 — 1; otherwise, CONSTRAINT_ERROR must be raised (see Chapter 11 and Appendix F of the VAX Ada Language Reference Manual). For the type V_STRING, the component S requires up to 231 — 1 bytes, the component L requires another 4 bytes, and the discriminant SIZE requires another 4. The run-time computation of the maximum size of X (231 — 1 + 4 + 4) thus raises CONSTRAINT_ERROR. Replacing NATURAL’ LAST with NATURAL'LAST - 8 in the definition of STRING_ SIZE will allow the maximum size to be computed; however, the compiler Additional Programming Considerations 10-9 will then attempt to allocate the maximum size (231 — 1), and STORAGE_ ERROR is raised. One possible solution is to declare a subtype, STRING_SIZE, with a more realistic range, so that neither CONSTRAINT ERROR nor STORAGE_ ERROR will be raised. For example: subtype STRING SIZE is NATURAL range 0..256; Another possibility is to declare the type as follows: subtype V_STRING SIZE is NATURAL range 0..256; type V_STRING is record CURRENT_ LAST: S: V_STRING_SIZE; STRING(l..V_STRING_SIZE'’LAST); end record; V: V_STRING; This formulationis similar to a PL/I varying string. Assignments involve setting the component that indicates the current end of the string, and then using slice assignments to set the relevant portions of the text. For example, the following procedure appends VS2 to VS1.: procedure APPEND (VSl: in out V_STRING; VS2: in out V_STRING) is begin VS1.S(VS1.CURRENT LAST+1..VS1l.CURRENT_ LAST+VS2.CURRENT_LAST) := VS2.S(1..VS2.CURRENT_ LAST) ; VS1.CURRENT LAST := VS1.CURRENT LAST + VS2.CURRENT_LAST; end; A third possible solution is to use an intermediate access type. For example: type 10.4 ACCESS STRING is access STRING; X: ACCESS_STRING; X := new STRING’ ("This can be as long a string as you need!"); Assigning Array Values When you assign array values, consider that Chapter 5 of the VAX Ada Language Reference Manual has some specific rules about assignments. In particular, note that bounds sliding does not occur in the following cases: 10-10 e During assignment of a record having array components * During execution of a return statement Additional Programming Considerations For example, consider the following procedure: procedure SUBSTR is S1: constant STRING(1..10) S2: STRING(1l..5); type REC := "1234567890"; is record INT: INTEGER; STR: STRING(1l..5); end record; R1: REC; begin S2 Rl := S1(6..10); := (555, S1(6..10)); -- Assignment is ok. —-- Assignment unconditionally raises -~ CONSTRAINT ERROR if executed. declare subtype S 1 TO 5 is STRING(l..5); function F return S 1 TO 5 is begin return S1(6..10); -- Assignment unconditionally raises —-— CONSTRAINT ERROR if executed. end F; begin null; end; end SUBSTR; In this procedure, the assignment to S2 follows the rules for array assignments because the variable on the left side is an array variable (see Section 5.2.1 of the VAX Ada Language Reference Manual): S2 := S1(6..10); Thus, the expression S1(6..10) is implicitly converted to the subtype of the left side (STRING(1..5)); that is, bounds sliding occurs. Consider the same procedure, rewritten with exphclt subtypes to better show whatis happening: procedure SUBSTR is subtype S subtype S 6 TO 10 1 TO 5 is is STRING(1l..5); STRING(6..10); S1 LASTPART: constant (6 =>'6’, 7 =>"'7", S2: S 1 S 6 TO 10 8=>'8", := 9 =>79", 10 => "0"); TO 5; begin S2 := S 1 TO 5(S1_LAST PART); -- Array type conversion. end SUBSTR; Additional Programming Considerations 10-11 In the assignment to S2 in this example, the bounds of S2 are 1..5, but the bounds of S1_LAST PART are 6..10. The array type conversion converts the bounds of S1_LAST_ PART to the bounds of S2. According to Chapter 5 of the VAX Ada Language Reference Manual, you could also write this assignment as follows, in which case the compiler would do the same conversion implicitly: S2 := S1 LAST PART In contrast, the array assignment rules in Section 5.2.1 of the VAX Ada Language Reference Manual do not apply to the assignment to R1, because R1 is not an array variable: R1 := (555, S1(6..10)); Here, the rules in Section 5.2 of the VAX Ada Language Reference Manual apply. According to these rules, the value of the expression (S1(6..10)) must be checked to see if it belongs to the subtype of the variable on the left side (STRING(1..5)), but no mention is made of implicit subtype conversions. Thus, this assignment raises the exception CONSTRAINT ERROR because the bounds of the slice (6..10) do not match the bounds of STR (1..5). Likewise, the rules for the return statement do not specify that an implicit subtype conversion should be done. Thus, the return statement also raises CONSTRAINT_ERROR: return S1(6..10); You can get the desired effect (bounds sliding) by using explicit array type conversions. The following example rewrites the procedure SUBSTR again, this time using type conversions in the return statement and the assignment to R1: procedure S1l: SUBSTR is STRING(1..10); subtype S5 SUBTYPE is type REC STRING(1l..5); is record INT: INTEGER; STR: S5 SUBTYPE; end record; R1: REC; function F return S5 SUBTYPE is begin return S5 SUBTYPE (S1(6..10)); -—- Type conversion. end; begin Rl := (555, S5 SUBTYPE(S1(6..10))); end SUBSTR; 10-12 Additional Programming Considerations -- Type conversion. 10.5 Sharing Memory Between VAX CPUs Example 10-2 shows how to write a VAX Ada program that shares memory between two or more VAX Ada programs running on one or more CPUs on a VMS system. The program uses VMS global sections to share memory between processors. It does not use the lock manager for communicating between processes. The approach used in this example is recommended if there are fewer processes than CPUs. If there are more processes than CPUs, using the VMS lock manager may significantly improve performance. Example 10-2: Sharing Memory Between Two or More Programs Running on One or More VAX CPUs -- First, -— (SHARED_OBJECTS_TYPE) —— This —— components. —— You —-— that —— the declare a package record type It should not should have can modify this could be same that has for the a have an INTERLOCK approach to use to allocate is any task specified in a pragma technique record type data that a to be or shared. access component. SHARED OBJECTS TYPE SHARED. the variable You would use in shared memory. with SYSTEM; package type SHARED MEMORY DATA TYPES SHARED OBJECTS TYPE is is record INTERLOCK : SYSTEM.ALIGNED WORD VALUE AVAILABLE : BOOLEAN; VALUE : INTEGER; := (VALUE => 1); end record; (continued on next page) Additional Programming Considerations 10-13 Example 10-2 (Cont.): for Sharing Memory Between Two or More Programs Running on One or More VAX CPUs SHARED OBJECTS_TYPE use record at 0 range 0..15; VALUE AVAILABLE at INTERLOCK 4 range 0..7; VALUE 8 range 0..31; at end record; end SHARED Next, MEMORY DATA TYPES; write a procedure that can call the VMS SYSSCRMPSC system service to create memory that is shared between two processes. In this example, a groupwide section is either created (if it did not already exist) or is mapped. The caller is returned two pieces of information: o The address of the section (in this process’s address space; it may be at a different address in a different process) o A boolean value creating call indicating whether or not this was the to SYSSCRMPSC with SYSTEM; procedure CREATE GLOBAL SECTION ( NAME : STRING; SIZE : NATURAL; SECTION ADDRESS : out CREATED : out BOOLEAN) ; with STARLET, procedure SYSTEM.ADDRESS; CONDITION HANDLING, NAME : STRING; SIZE : NATURAL; SECTION ADDRESS : out CREATED : out BOOLEAN) STATUS LIB; CREATE_ GLOBAL_ SECTION ( SYSTEM.ADDRESS; is : CONDITION_ HANDLING.COND VALUE TYPE; : STARLET.ADDRESS RANGE TYPE INADR, RETADR (others => := SYSTEM.ADDRESS ZERO) ; FAILED TO CREATE_SECTION MATCH_COND_RESULT : : exception; SYSTEM.UNSIGNED LONGWORD; (continued on next page) 10-14 Additional Programming Considerations Example 10-2 (Cont.): Sharing Memory Between Two or More Programs Running on One or More VAX CPUs begin STARLET.CRMPSC STATUS => ( STATUS, => INADR, => RETADR, FLAGS => Il INADR RETADR SYSTEM.UNSIGNED LONGWORD (STARLET.SEC M GBL + STARLET.SEC_M DZRO + STARLET.SEC_M EXPREG M WRT STARLET.SEC_ + + STARLET.SEC M PAGFIL), NAME, PAGCNT => SYSTEM.UNSIGNED LONGWORD (( (SIZE+7)/8+511)/512), I \Y GSDNAM => -~ W G 0 S --DEWR DEWR DEWR DEWR PROT => if not STARLET.FILE PROTECTION TYPE’ (240000 0000 1011 0000%#)); CONDITION HANDLING.SUCCESS (STATUS) raise FAILED then TO CREATESECTION; end if; LIB.MATCH COND (MATCH COND_RESULT, SECTION ADDRESS := RETADR(O); CREATED := end STATUS, STARLET.SS_CREATED) ; SYSTEM."=" (MATCH_COND_ RESULT, 1); CREATE GLOBAL SECTION; Now, write a function that uses the procedure CREATE GLOBAL SECTION to place the particular set to be The This shared into call that creates the shared memory initializes the objects. function sets up a race condition: other callers may arrive after the section has been created, There are a number of ways to handle this in this example use the of objects shared memory. is for the user to but before it start shared variable only after the is situation. initialized. The approach running the programs first program has that created and initialized it. with SYSTEM; function CREATE MY SHARED OBJECTS with SHARED SYSTEM, MEMORY DATA TYPES, return SYSTEM.ADDRESS; CREATE GLOBAL SECTION, TEXT IO; pragma ELABORATE (CREATE GLOBAL SECTION) ; (continued on next page) Additional Programming Considerations 10-15 Example 10-2 (Cont.): function CREATE Sharing Memory Between Two or More Programs Running on One or More VAX CPUs MY SHARED OBJECTS return SYSTEM.ADDRESS SECTION ADDRESS : SYSTEM.ADDRESS; CREATED : BOOLEAN; is begin CREATE GLOBAL SECTION ( "SHARED MEMORY", SHARED MEMORY DATA TYPES.SHARED OBJECTS TYPE’MACHINE SIZE, SECTION ADDRESS, CREATED) ; if CREATED then —— Cause -- happen the shared variable only to be initialized; this should once. declare SHARED OBJECTS SHARED MEMORY_DATATYPES.SHARED OBJECTS_ TYPE; for SHARED OBJECTS pragma use at SECTION_ ADDRESS; VOLATILE (SHARED OBJECTS) ; begin null; end; TEXT_TO.PUT_LINE ("Section "Start is created other and programs initialized. " & now."); end if; return SECTION ADDRESS; end CREATE —— Now, —— object MY use piece appear with SYSTEM, with SHARED pragma a SHARED OBJECTS; of clever in the area package SHARED MEMORY is code to make a widely visible shared memory. UNCHECKED CONVERSION; MEMORY DATA TYPES, ELABORATE (CREATE MY type A Ada of access CREATE MY SHARED OBJECTS; SHARED OBJECTS) ; is SHARED_ MEMORY_DATA TYPES.SHARED OBJECTS TYPE; (continued on next page) 10-16 Additional Programming Considerations Example 10-2 (Cont.): Sharing Memory Between Two or More Programs Running on One or More VAX CPUs function TO A is new UNCHECKED CONVERSION (SYSTEM.ADDRESS, —— Here is —-—- the —- have SHARED the key to this code makes by renaming a but ’'.all’ ensures that construct, it will not initialization problems. OBJECTS : SHARED MEMORY DATATYPES.SHARED OBJECTS TYPE renames -- code: an object visible, A); Provide simple names TO A (CREATE for the MY SHARED OBJECTS) .all; components. VALUE : INTEGER renames SHARED OBJECTS.VALUE; VALUE AVAILABLE : BOOLEAN renames SHARED —-— Provide -- (SYSTEM.ADD INTERLOCKED) an interlock. —-- memory modifications and become visible to —— The —- do —— can ——- locking use of spinning stall shown here —-—- readers. —-- not the and a delay long, one does rest interlocked statements instruction causes flushed through the multiCPU statement means and other tasks stalls waiting not Extending to that affect an these all caches all participating processes. for very continue while within to be —— not The use of OBJECTS.VALUE AVAILABLE; of this that within for the lock. support multiple case straightforward, is things the program The simultaneous and does example. procedure ACQUIRE; procedure RELEASE; end SHARED MEMORY ; with SYSTEM; package body INTERLOCK MAX SPIN SHARED : MEMORY SYSTEM.ALIGNED WORD COUNT : constant procedure ACQUIRE SIGN : is renames POSITIVE := SHARED OBJECTS.INTERLOCK; 10; 1is INTEGER; SPIN COUNT : INTEGER := O0O; begin loop SYSTEM.ADD INTERLOCKED (-1, exit when SIGN = INTERLOCK, SIGN) ; 0; (continued on next page) Additional Programming Considerations 10-17 Example 10-2 (Cont.): Sharing Memory Between Two or More Programs Running on One or More VAX CPUs SYSTEM.ADDwINTERLOCKED( SPIN COUNT 1, := SPIN_COUNT + INTERLOCK, SIGN):; 1; if SPIN COUNT > MAX SPIN COUNT then delay DURATION’ SMALL; end if; end loop; end; procedure RELEASE SIGN : is INTEGER; begin SYSTEM.ADD INTERLOCKED( 1, INTERLOCK, SIGN); end; end SHARED MEMORY; —— Here is a main program that is going to write values into the ~- shared memory. It waits until each previous value is read by ~—- a reader before writing the next wvalue. with SHARED MEMORY, TEXT_ IO; use SHARED MEMORY, TEXT IO; procedure Z SHARE MEMORY WRITER is baegin for I in NATURAL loop loop ACQUIRE; if not VALUE AVAILABLE then VALUE_AVAILABLE VALUE := := TRUE; I; PUT LINE ("Writing VALUE =" & INTEGER’'IMAGE (VALUE)) ; RELEASE; exit; end if; RELEASE; end loop; end loop:; end 7Z SHARE MEMORY WRITER; (continued on next page) 10-18 Additional Programming Considerations Example 10-2 (Cont.): Sharing Memory Between Two or More Programs Running on One or More VAX CPUs -—- Here are two readers (each a main program in itself). with SHARED MEMORY, TEXT IO; use SHARED MEMORY, TEXT IO; procedure Z SHARE MEMORY READERI1 is begin loop ACQUIRE; if VALUE AVAILABLE then VALUE AVAILABLE := FALSE; PUT LINE ("READER1 VALUE =" & INTEGER’ IMAGE (VALUE) ) ; & INTEGER’IMAGE (VALUE)) ; end if; RELEASE; end loop:; end Z SHARE MEMORY READERI; with SHARED MEMORY, TEXT IO; use TEXT IO; SHARED MEMORY, procedure Z SHARE MEMORY READER2 begin is | loop ACQUIRE; if VALUE AVAILABLE then VALUE AVAILABLE := FALSE; PUT LINE ("READER2 VALUE =" end if; RELEASE; end loop:; end Z SHARE MEMORY READER2; Additional Programming Considerations 10-19 Appendix A VAX Ada Predefined Instantiations For convenience, and for the purpose of saving compilation time and object code space, VAX Ada predefines the instantiations of some commonly used generic packages: Unit Name Instantiation of For Type INTEGER_TEXT IO TEXT_IO.INTEGER_IO INTEGER SHORT_INTEGER_TEXT_IO TEXT IO.INTEGER_IO SHORT_INTEGER SHORT SHORT INTEGER_TEXT 10 TEXT IO.INTEGER_IO SHORT_SHORT _INTEGER FLOAT_TEXT_IO TEXT_IO.FLOAT_IO FLOAT LONG_FLOAT_TEXT IO TEXT I0.FLOAT_IO LONG_FLOAT LONG_LONG_FLOAT TEXT_IO TEXT _I0.FLOAT_IO LONG_LONG_FLOAT FLOAT MATH_LIB MATH_LIB FLOAT LONG_FLOAT _MATH_LIB MATH_LIB LONG_FLOAT LONG_LONG_FLOAT MATH_LIB MATH_LIB LONG_LONG_FLOAT The representation used for the type LONG_FLOAT in these packages is G_floating. Thus, to use LONG_FLOAT TEXT_IO and LONG_FLOAT _ MATH_LIB, you must be sure that the G_floating representation for LONG_FLOAT is in effect for any compilations involving these packages. Note the following information: e G_floating is the default whenever you create or reinitialize a program library or sublibrary. VAX Ada Predefined Instantiations A-1 e You can set the representation for LONG_FLOAT either with the VAX Ada pragma LONG_FLOAT or with a number of program library manager commands (ACS SET PRAGMA, ACS CREATE LIBRARY/LONG_FLOAT, and ACS CREATE SUBLIBRARY/LONG_ FLOAT). ¢ You can determine whether or not G_floating is in effect for a program library or sublibrary by first making the library the current library (use the ACS SET LIBRARY command) and then entering an ACS SHOW PROGRAM or ACS DIRECTORY command. If you change the representation of the type LONG_FLOAT to D_floating for your current program library, you will need to recompile the instantiations LONG_FLOAT_TEXT 10 and LONG_FLOAT MATH_LIB in the context of the D_floating representation in order to use them. To do this, extract the source of these packages into the current program library, and then compile them using the DCL ADA command (or ACS LOAD and COMPILE commands). For example: $ ACS $ IO AT TEXT ACS EXTRACT SOURCE LONG_FLO SET PRAGMA/LONG_FLOAT=D_FLOAT $ TEXT IO ADA LONGFLOAT Any change in the setting of the representation for the type LONG_FLOAT implies a recompilation of the predefined STANDARD environment. See Section 3.5.7a of the VAX Ada Language Reference Manual for more information on the pragma LONG_FLOAT. See Developing Ada Programs on VMS Systems for more information on ACS commands, compiling Ada programs, and the implied recompilation of the predefined STANDARD environment. See Chapter 3 of this manual for information on using the predefined mstantiations for TEXTIO.INTEGER_IO and TEXT_IO.FLOAT IO. See Chapter 6 of this manual for information on using the predefined instantiations of MATH_LIB. A-2 VAX Ada Predefined Instantiations Appendix B VAX Ada Packages VAX Ada provides the packages listed in Table B-1. As noted in Table B-1, this appendix and the VAX Ada Language Reference Manual provide specifications or parts of the specifications for some of these packages. You can obtain the complete specifications and, in some cases, the bodies for any of these packages by using the ACS EXTRACT SOURCE command. For example, the following command causes the specifications of the packages STARLET, STANDARD, and TEXT IO, to be placed in your current default directory: $ ACS EXTRACT SOURCE STARLET, $STANDARD, TEXT IO You must have defined a current program library to execute this command. The current program library can be either the library ADA$PREDEFINED or a library into which the predefined units from ADA$PREDEFINED have been entered. See Developing Ada Programs on VMS Systems or type HELP ACS EXTRACT SOURCE at the VMS prompt for more information. VAX Ada Packages B-1 Table B-1: VAX Ada Predefined Packages Location of Specification in the VAX Ada Package Name ASSERT Description Documentation Set’ Instantiation of the pack- VAX Ada Run-Time Reference Manual, Appendix B age ASSERT_GENERIC. Assumes all of the defaults in the package ASSERT_ GENERIC, including the use of the procedure TEXT_ I0.PUT_LINE to report failures. ASSERT_EXCEPTIONS ASSERT_GENERIC Declares all exceptions VAX Ada Run-Time Reference Manual, Appendix B Provides types and operations that allow you to insert and enable code-checking assertions in your Ada source VAX Ada Run-Time Reference Manual, Appendix B that can be raised by instantiations of the package ASSERT_GENERIC. code. Depends on the packages ASSERT_EXCEPTIONS and TEXT_IO. AUX_IO_EXCEPTIONS Defines the exceptions needed by the VAX Ada relative and indexed input-output VAX Ada Language Reference Manual, Chapter 14 packages. CALENDAR Provides time-related types and operations. VAX Ada Language Reference Manual, Chapter 9 Depends on the package SYSTEM. 1All of the package specifications are also available from the VAX Ada library of predefined units, ADAS$PREDEFINED. (continued on next page) B-2 VAX Ada Packages Table B-1 (Cont.): VAX Ada Predefined Packages Location of Specification in the VAX Ada Documentation Set! Package Name Description CDD_TYPES Provides Ada equivalents VAX Ada Run-Time Reference for VAX CDD data types; Manual, Appendix B additional equivalents are in the packages STANDARD and SYSTEM. Depends on the package SYSTEM. CLI Provides types and operations for calling VMS Command Language Utility routines. Depends on the packages SYSTEM and CONDITION_ HANDLING. CONDITION_HANDLING Provides types and operations VAX Ada Run-Time Reference needed to evaluate the Manual, Appendix B condition values returned by system routines. Depends on the package SYSTEM. CONTROL_C_INTERCEPTION Establishes a VAX Ada VAX Ada Run-Time Reference CTRL/C handler when it is Manual, Appendix B elaborated. DIRECT_IO Provides types and operations VAX Ada Language Reference for working with direct files Manual, Chapter 14 of uniform-type elements. Depends on the package IO_EXCEPTIONS. DIRECT_MIXED_IO Provides types and operations VAX Ada Language Reference for working with direct files Manual, Chapter 14 of mixed-type elements. Depends on the package I0_EXCEPTIONS. 1All of the package specifications are also available from the VAX Ada library of predefined units, ADASPREDEFINED. (continued on next page) VAX Ada Packages B-3 Table B—1 (Cont.): VAX Ada Predefined Packages Location of Specification in the VAX Ada Package Name Description Documentation Set! DTK Provides types and operations for calling the VMS Run- — Time Library DTK$ routines. Depends on the packages SYSTEM, STARLET, and CONDITION_HANDLING. INDEXED_IO Provides types and operations for working with indexed files of uniform-type elements. VAX Ada Language Reference Manual, Chapter 14 ‘ Depends on the packages IO_EXCEPTIONS and AUX_ IO_EXCEPTIONS. INDEXED_MIXED_IO Provides types and operations for working with indexed files of mixed-type elements. VAX Ada Language Reference Manual, Chapter 14 Depends on the packages I0_EXCEPTIONS and AUX _ IO_EXCEPTIONS. IO_EXCEPTIONS Defines exceptions needed by all of the input-output VAX Ada Language Reference Manual, Chapter 14 packages. LBR Provides types and operations for calling the VMS Librarian — Utility routines. Depends on the packages SYSTEM, STARLET, and CONDITION_HANDLING. LIB Provides types and operations for calling the VMS Run- — Time Library LIB$ routines. Depends on the packages SYSTEM, STARLET, and CONDITION_HANDLING. 1All of the package specifications are also available from the VAX Ada library of predefined units, ADAS$PREDEFINED. (continued on next page) B4 VAX Ada Packages Table B-1 (Cont.): VAX Ada Predefined Packages Location of Specification in the VAX Ada Package Name Description MATH_LIB Provides a set of opera- tions and exceptions that correspond to some of the VMS Run-Time Library Documentation Set! VAX Ada Run-Time Reference Manual, Appendix B Mathematical Library routines and conditions. MTH Provides types and operations for calling the VMS Run- Time Library MTHS$ routines. Depends on the package SYSTEM. NCS Provides types and operations for calling the National Character Set Utility routines. Depends on the packages SYSTEM and CONDITION_ HANDLING. OTS Provides types and operations for calling the VMS Run- Time Library OTS$ routines. Depends on the packages SYSTEM, STARLET, and CONDITION_HANDLING. PPL Provides types and operations for calling the VMS Run- Time Library PPL$ routines. Depends on the packages SYSTEM, STARLET, and CONDITION_HANDLING. 1A11 of the package specifications are also available from the VAX Ada library of predefined units, ADAS$PREDEFINED. (continued on next page) VAX Ada Packages B-5 Table B—1 (Cont.): VAX Ada Predefined Packages Location of Specification in the VAX Ada Package Name Description Documentation Set’ RELATIVE_IO Provides types and operations for working with relative files Manual, Chapter 14 VAX Ada Language Reference of uniform-type elements. Depends on the packages IO_EXCEPTIONS and AUX_ IO_EXCEPTIONS. RELATIVE_MIXED_IO Provides types and operations VAX Ada Language Reference for working with relative files Manual, Chapter 14 of mixed-type elements. Depends on the packages JO_EXCEPTIONS and AUX_ IO_EXCEPTIONS. RMS_ASYNCH_OPERATIONS Provides supporting operations for the package TASKING_SERVICES. Depends on the packages SYSTEM, STARLET, and CONDITION_HANDLING. SEQUENTIAL_IO Provides types and operations VAX Ada Language Reference for working with sequen- Manual, Chapter 14 tial files of uniform-type elements. Depends on the package IO_EXCEPTIONS. SEQUENTIAL_MIXED_IO Provides types and operations for working with sequential VAX Ada Language Reference Manual, Chapter 14 files of mixed-type elements. Depends on the package IO_EXCEPTIONS. 1All of the package specifications are also available from the VAX Ada library of predefined units, ADAS$PREDEFINED. (continued on next page) B-6 VAX Ada Packages Table B-1 (Cont.): VAX Ada Predefined Packages Location of Specification in the VAX Ada Package Name SMG Description Documentation Set! Provides types and operations for calling the VMS RunTime Library SMG$ routines. Depends on the packages SYSTEM, STARLET, and CONDITION_HANDLING. SOR Provides types and operations for calling the Sort/Merge Utility routines. Depends on the packages SYSTEM, STARLET, and CONDITION_HANDLING. STANDARD Provides all the predefined VAX Ada Language Reference types, operations, and ex- Manual, Chapter 8 and ceptions defined by the Annex C language, as well as the additional VAX Ada types SHORT_INTEGER, SHORT_ SHORT_INTEGER, LONG_ FLOAT, and LONG_LONG_ FLOAT. STARLET Provides the types, opera- VAX Ada Run-Time Reference tions, constants, and so on Manual, Appendix B: type that you need to call VMS declarations only system service and RMS routines. Depends on the packages SYSTEM and CONDITION_ HANDLING. 1A1l of the package specifications are also available from the VAX Ada library of predefined units, ADASPREDEFINED. (continued on next page) VAX Ada Packages B-7 Table B—1 (Cont.): VAX Ada Predefined Packages Location of Specification in the VAX Ada Package Name STR Description Documentation Set! Provides types and operations for calling the VMS Run- Time Library STR$ routines. Depends on the packages SYSTEM, STARLET, and CONDITION_HANDLING. SYSTEM Provides implementation- VAX Ada Language Reference defined types, operations, Manual, Chapter 13 and constants, and named num- Appendix F bers, some of which are required by the language standard, and some of which are provided by VAX Ada. SYSTEM_RUNTIME_TUNING Provides operations for changing system parameters VAX Ada Run-Time Reference Manual, Appendix B that are normally controlled by the VAX Ada run-time library. TASKING_SERVICES Provides task-synchronous, VAX Ada Run-Time Reference process-asynchronous forms Manual, Appendix B of the VMS system ser- vices SYS$BRKTHRU, SYS$ENQ, SYS$GETDVI, SYS$GETJPI, SYS$GETLKI, SYS$GETQUI, SYS$GETSYI, SYS$QIO, SYS$SNDJBC, SYS$UPDSEC, and any VMS RMS record or block operation. Depends on the packages SYSTEM, STARLET, CONDITION_HANDLING, and RMS_ASYNCH_ OPERATIONS. 1All of the package specifications are also available from the VAX Ada library of predefined units, ADA$PREDEFINED. (continued on next page) B-8 VAX Ada Packages Table B-1 (Cont.): VAX Ada Predefined Packages Location of Specification Package Name TEXT_IO Description in the VAX Ada Documentation Set’ Provides types and operations VAX Ada Language Reference for working with text files. Manual, Chapter 14 Depends on the package IO_EXCEPTIONS. 1All of the package specifications are also available from the VAX Ada library of predefined units, ADASPREDEFINED. VAX Ada Packages B-9 B.1 Packages ASSERT, ASSERT_EXCEPTIONS, and ASSERT GENERIC with ASSERT GENERIC; package ASSERT is new ASSERT GENERIC; -—- This package -— ASSERT GENERIC. is a predefined -— the package ASSERT GENERIC, —-— TEXT IO.PUT LINE It to package ASSERT EXCEPTIONS —-— This —— instantiations package ASSERT ERROR : assumes report instantiation all of the of the default package values including the use of assertion warnings and defined in the procedure failures. is declares the exceptions of the package that can be raised by any ASSERT GENERIC. exception; end; with ASSERT EXCEPTIONS; with TEXT IO; generic —— This package provides -- debuggging -— package —— Features: -— 0 A number of defines two kinds -— generated code, the - is on. —- o0 The —— allow you to 0 By and default failures so action is -— generation -— routines —— out —— o0 No action assertion code is EXAMPLE: routines routine allow you to put warnings with default effect to be The and failures. values of assertions are provided on called when the assertion for announcing assertion warnings generic parameters package set to with the FALSE, for your assertions without that statically assertions: control the instantiating the CHECK_FAILURES —— of that in your Ada programs. and TEXT IO.PUT LINE. - ~— and operations generic parameters that true, types or assertions, -- -= B-10 checks, call into the assertion you CHECK WARNINGS can eliminate having to package. change Thus, checks for your production programs. generated for assertions are that true. Using the preinstantiated package ASSERT. - with ASSERT; —— ASSERT.WARN (expression, VAX Ada Packages "failure description"):; you and code all can of the leave - -— ASSERT.FAIL (expression, EXAMPLE: Creating your —— hide the preinstantiated -- code for all —- with —= package -— own "failure description"); assertion package package ASSERT is new ASSERT your preinstantiated package -= use —- with -= procedure a special assertion FALSE, Creating the own GENERIC( hide action MAIN package new Determine actually be —— FAIL WARN) —— optimization —— impact (or if on PROGRAM ASSERT —— will is the failure inserted routine. is any (or warning) into If enabled, caller of the these there the in BOOLEAN TRUE; in TRUE; routine of when —— DESCRIPTION —— procedure). greater to the it be called when ITEM parameter a is (which is passed value of WARN LIMIT —— is routine, than —— ASSERT ERROR. —-— NOTE: and the Subsequent 0, only last that call assertion is WARN PREFIX TEXT number as of a with procedure WARN_ACTION_ROUTINE (ITEM or will caller of and inline no run-time calls just : with is the to false. two string parameter (see followed by warnings checks assertion concatenated string —-— SPECIAL REPORT) ; the false, little warning output: the of => routine. is If the are should be assertion BOOLEAN code values : value assertion generated : strings will that is CHECK FAILURES —— ); routine. CHECK_WARNINGS The that and ASSERTGENERIC(FAIL ACTION ROUTINE —— Action package FALSE ASSERT GENERIC; —— —— the ASSERT GENERIC; EXAMPLE: —— will disable checks. —— —= that and other and the the WARN private declaration) is to the raise STRING) made raising the is of the action exception exception. TEXT IO.PUT LINE; VAX Ada Packages B-11 -~ Action routine to be called when a failure assertion is false. —— The value of the ITEM parameter is concatenated with two other -— strings when it ~— DESCRIPTION string —-— procedure). is greater than 0, —-— routine, —= ASSERT ERROR. —— NOTE: (which the FAIL PREFIX TEXT string and the is passed as only that and the last Subsequent call is assertion failures The maximum number of times will be —— to how many times the action —— NOTE: -- initialize The wvalues the for is that just INIT : in NATURAL := 50; FAIL INIT : in NATURAL := 1 If 0, limit and FAIL LIMIT (see inhibits the raising of the exception when the (see private declaration) is exceeded. The value for INHIBIT EXCEPTION INIT INHIBIT : EXCEPTION INIT in BOOLEAN initializes the (see private declaration). := FALSE; Strings used to prefix action routine messages. PREFIX TEXT : in STRING := "**** Agsertion failure. "; WARN PREFIX TEXT : in STRING := "**** Assertion warning. "; package ASSERT GENERIC is —— The exception raised on assertion failures —— (or 3 INHIBIT EXCEPTION FAIL (unless inhibited by INHIBIT EXCEPTION). ASSERT ERROR B-12 TEXTIO.PUT_LINE; then there 1is no WARN LIMIT -- tailoring parameter —-— is r —— value of WARN LIMIT or FAIL LIMIT —— NOTE: STRING) WARN LIMIT INIT and FAIL LIMIT INIT WARN LIMIT reached or : routine will be called. declarations). —— the exception. the FAIL ACTION ROUTINE tailoring parameters —— When set to TRUE, raise 1. called. —— private LIMIT action followed by the raising of exception The default value of FAIL LIMIT —— WARN ACTION ROUTINE) (see private declaration) number of calls is made to the with procedure FAIL ACTIONROUTINE (ITEM —— a parameter to the FAIL If the value of FAIL LIMIT -—- -—- is ouput: : exception renames ASSERTEXCEPTIONS.ASSERT ERROR; VAX Ada Packages If the boolean condition is FALSE, called and passed the DESCRIPTION WARN LIMIT has been the reached, exception ASSERT ERROR warnings result only of CHECK_WARNINGS caller of this the WARN ACTION ROUTINE string. the action is raised; If the value routine any routine, little or no called and subsequent in the exception being is FALSE, is assertion raised. code is of If the value is generated in the provided inline optimizations are not inhibited. procedure WARN (ASSERTION DESCRIPTION pragma : STRING INLINE (WARN) ; If the boolean condition called is FALSE, the FAIL ACTION ROUTINE and passed the DESCRIPTION string. FAIL LIMIT has been reached, exception warnings ASSERT ERROR is result only of CHECK FAILURES caller of this in the is FALSE, routine, the raised; If the value action routine any is subsequent exception being called and the assertion raised. little or no code is of If the value is generated in the provided inline optimizations are not inhibited. NOTE: You because cannot rely on exceptions your program might following execution. The program can check if any warnings procedure FAIL (ASSERTION : DESCRIPTION pragma terminating the program absorb the exception and continue functions BOOLEAN are provided so that or failures your occurred: := FALSE; = STRING nuy . INLINE (FAIL); A means of checking if an assertion warning or failure has occurred in the program. function HAD ASSERT WARNING return BOOLEAN; A means — of checking if an assertion failure has occurred in the program. function HAD ASSERT FAILURE return BOOLEAN; private Tailoring Parameters. The following parameters instantiated, are initialized when the generic package is but you can change them when you execute the program under the control of the VMS Debugger. with debugger commands, failures while you are debugging. private part so that they cannot executes without the By changing their values you can modify the treatment The be of assertion initial values are in the changed by the program as it debugger. VAX Ada Packages B-13 —- When ——- its value is TRUE, it inhibits the raising of assertion exceptions. INHIBIT_ EXCEPTION —- These ——- respective values —- then the : BOOLEAN determine action action := INHIBIT EXCEPTION INIT; the maximum number routine will routine is be called. called on every WARN LIMIT : NATURAL := FATL LIMIT : NATURAL := FAIL LIMIT INIT; of times that they are If failure the set to WARN LIMIT INIT; end ASSERT GENERIC; pragma B.2 INLINE GENERIC (ASSERT GENERIC); Package CDD TYPES with SYSTEM; package —- use SYSTEM; CDD TYPES This is package -- translator —— Special defines types are names to use is BIT ARRAY; is UNSUPPORTED TYPE2 Declare the CDD-to-Ada for unsupported data types. subtype -—- needed by (ADASFROM CDD). subtype UNSUPPORTED TYPE1l — an octaword UNSIGNED BYTE ARRAY; type. — subtype OCTAWORD_TYPE ~— Declare subtype a DATE_TIME TYPE For -- the package - type completeness, BIT ARRAY is 3); UNSIGNED QUADWORD; show BIT ARRAY is array (it is defined (INTEGER range is (INTEGER range <>, INTEGER <>) BITARRAY 3D array .. in SYSTEM) : BITARRAY 2D array type is UNSIGNED LONGWORD ARRAY (0 date/time. -— type range of BOOLEAN; is (INTEGER range <>, INTEGER range <>, INTEGER range <>) pragma PACK (BITARRAY 2D); pragma PACK (BIT_ARRAY 3D); B-14 that VAX Ada Packages of BOOLEAN; <>) 0, (or warning). of BOOLEAN; —— For completeness, -— the -— package show STRING type STRING is array type STRING 2D array type array (POSITIVE range <>, INTEGER range <>) (INTEGER range <>, range <>, INTEGER range <>) —-— For completeness, -— the package CHARACTER; of CHARACTER; show UNSIGNED BYTE ARRAY (INTEGER range type UNSIGNED BYTE ARRAY 2D (INTEGER <>, INTEGER range <>) (INTEGER range INTEGER <>, <>) For completeness, the package of is <>) of UNSIGNED BYTE; UNSIGNED BYTE; of UNSIGNED BYTE; show UNSIGNED WORD ARRAY (it is defined in SYSTEM) : type UNSIGNED WORD_ARRAY array (INTEGER range type UNSIGNED WORD ARRAY 2D array defined in <>, INTEGER range —— - is is range -— - (it is range type UNSIGNED BYTE ARRAY 3D array of CHARACTER; SYSTEM) : array array range <>) of type UNSIGNED BYTE ARRAY - defined in is INTEGER - is is (INTEGER STRING 3D (it STANDARD) : is <>) of UNSIGNED WORD; is (INTEGER range <>, INTEGER range <>) of UNSIGNED WORD; type UNSIGNED WORD ARRAY 3D is array (INTEGER range <>, range <>, INTEGER INTEGER range <>) -— For completeness, -— package the — type -- type show UNSIGNED LONGWORD ARRAY UNSIGNED LONGWORD ARRAY (INTEGER range UNSIGNED LONGWORD ARRAY 2D range <>, INTEGER range <>) (INTEGER is defined in (INTEGER range <>, INTEGER range <>, INTEGER range <>) <>) is of UNSIGNED LONGWORD; is of UNSIGNED LONGWORD; UNSIGNED LONGWORD ARRAY 3D array (it SYSTEM): array array type of UNSIGNED WORD; of is UNSIGNED LONGWORD; VAX Ada Packages B-15 —-— For completeness, —- the package - type - type show UNSIGNED UNSIGNED QUADWORDARRAY array (INTEGER range UNSIGNED QUADWORD ARRAY 2D array (INTEGER range (INTEGER range <>, INTEGER range <>, INTEGER range <>) type type type (INTEGER range (INTEGER range <>, INTEGER range <>) (INTEGER range <>, INTEGER range <>, <>) type SHORT_ INTEGERARRAY is type SHORT INTEGER ARRAY 2D array (INTEGER |range<>, INTEGER range <>) SHORTINTEGER ARRAY 3D array (INTEGER range <>, INTEGER range <>, INTEGER range <>) type INTEGERARRAY is array type INTEGER ARRAY 2D array type (INTEGER range <>, <>) of is SHORT SHORT INTEGER; of is SHORT SHORT INTEGER; is of SHORT SHORT array (INTEGER INTEGER; range <>) of of SHORT INTEGER; is of SHORT INTEGER; (INTEGER range <>) of INTEGER; of INTEGER; of INTEGER; is INTEGER range <>, INTEGER range <>) FLOATARRAY type FLOAT ARRAY 2D is (INTEGER (INTEGER range <>, <>) of FLOAT; is (INTEGER range <>, INTEGER range <>, INTEGER range <>) VAX Ada Packages range is INTEGER range FLOAT ARRAY 3D array array SHORT INTEGER; is array (INTEGER .range <>, type type is is INTEGER range INTEGERARRAY 3D array B-16 <>) INTEGER range type of UNSIGNEDQUADWORD; is SHORT SHORTINTEGER ARRAY 3D array in is <>) SHORT_SHORT_INTEGER ARRAY 2D array defined of UNSIGNED QUADWORD; SHORT SHORTINTEGER ARRAY array is of UNSIGNED QUADWORD; UNSIGNED QUADWORD ARRAY 3D array (it <>, INTEGER range <>) type QUADWORD ARRAY SYSTEM) : of FLOAT; <>) of FLOAT; type D FLOATARRAY is array type D FLOAT ARRAY 2D array type D (INTEGER range <>, INTEGER range <>) FLOAT ARRAY 3D array of D FLOAT; of DFLOAT; is <>, (INTEGER range INTEGER (INTEGER range <>) is range <>, INTEGER range <>) of D FLOAT; type LONG LONGFLOAT_ ARRAY is array type (INTEGER range <>) of LONG LONG FLOAT; LONG_LONGFLOATARRAY 2D array (INTEGER range <> INTEGER range <>) of type LONG LONG FLOAT ARRAY 3D array (INTEGER range <>, INTEGER range <>, INTEGER range <>) type GFLOATARRAY is array type G FLOAT ARRAY 2D is LONG_LONG FLOAT; is of LONG LONG_ FLOAT; (INTEGER range <>) of G_FLOAT; is array (INTEGER |range <>, INTEGER range <>) type G FLOAT ARRAY 3D array of G_FLOAT; is (INTEGER range <>, INTEGER <>, range INTEGER range <>) type OCTAWORD ARRAY type OCTAWORD ARRAY 2D array (INTEGER is of GFLOAT; array (INTEGER range range OCTAWORD ARRAY 3D array type DATE (INTEGER range <>, INTEGER range <>, INTEGER range <>) of TIME ARRAY is array OCTAWORD TYPE; (INTEGER range <>) range <>, INTEGER range <>) <>, INTEGER range <>, INTEGER range <>) of DATE TIME TYPE; of DATE TIME TYPE; type ADDRESSARRAY is array (INTEGER range <>) ARRAY 2D TIME TYPE; is (INTEGER range type ADDRESS of DATE is (INTEGER type DATE TIMEARRAY 3D array of OCTAWORD TYPE; is type DATE TIMEARRAY 2D array of OCTAWORD TYPE; <>, INTEGER range <>) type <>) is of ADDRESS; is array (INTEGER |range <>, INTEGER range <>) type ADDRESS ARRAY 3D array of ADDRESS; is (INTEGER range <>, INTEGER range <>, INTEGER range <>) of ADDRESS; VAX Ada Packages B-17 2k % O 2k k 1) is INTEGER range - (2** 2) % 2k SIGNED 4 is INTEGER range - (2*%* 3) D%k % subtype SIGNED 5 is INTEGER range -(2%* 4) 2% % subtype SIGNED 6 is INTEGER range - (2%* 5) % 2% subtype 7 SIGNED is INTEGER range - (2*%* 6) 2% % subtype SIGNED 8 is INTEGER range - (2*%* 7) Dk % subtype SIGNED_ 9 is INTEGER range - (2** 8) Dk % 9) 2*7\' Ne We TMo | R Ng Ne I IS N SIGNED 3 subtype | subtype R Q) —-(2*%* oOo~Joud - (2%* range g range INTEGER R INTEGER is O is SIGNED 2 AT 1 SIGNED subtype Wy INTEGER. My of type subtype SIGNED 10 is INTEGER range —(2** 11 is SIGNED INTEGER range — (2**10) subtype SIGNED 12 is INTEGER range - (2*%%11) 2*%*11-1; subtype SIGNED 13 is INTEGER range - (2**12) 2**12-1; subtype SIGNED 14 is INTEGER range - (2**13) 2%%]13-1; subtype SIGNED 15 is INTEGER range - (2%*14) 2*%%x14-1; subtype SIGNED 16 is INTEGER range - (2**15) 2**15-1; subtype 17 SIGNED is INTEGER range -(2%*16) 2*%*16-1; subtype SIGNED 18 is INTEGER range -(2**17) 2*%*17-1; subtype SIGNED 19 is INTEGER range - (2**18) 2*%*18-1; subtype SIGNED 20 is INTEGER range - (2*%*19) 2*%*%19-1; subtype SIGNED 21 is INTEGER range - (2%*20) 2**%20-1; subtype SIGNED 22 is INTEGER range -(2*%*21) 2*%%21-1; subtype SIGNED 23 is INTEGER range - (2%*22) 2*%*%22-1; subtype SIGNED 24 is INTEGER range - (2%*23) 2%%23-1; subtype SIGNED 25 is INTEGER range - (2%*24) 2*%*%24-1; subtype SIGNED 26 is INTEGER range ~(2**25) 2**25-1; subtype SIGNED 27 is INTEGER range - (2%*26) 2**26-1; subtype SIGNED 28 is INTEGER range —(2%*277) 2%%2°1=1; subtype SIGNED 29 is INTEGER range —(2%*28) 2**28-1; subtype SIGNED 30 is INTEGER range 2*%%29=7; subtype SIGNED 31 is INTEGER range 2*%%30-1; VAX Ada Packages | subtype subtype end; B-18 subtypes WNE static RRRPRRRR -- Define 2**10-1; B.3 with Package CONDITION_HANDLING SYSTEM; package use SYSTEM; CONDITION HANDLING is -- This package defines -- 1. The VMS condition value type — 2. Functions —— for the following: accessing the components of a condition wvalue 3. - —-— VMS to the VMS Run-Time Library LIBS$STOP, system services subtype -—- VMS Interfaces LIB$SIGNAL, return values COND VALUE TYPE severity codes is are defined in the STS_K WARNING : constant - STS : constant := 1; - STS_K ERROR : constant := 2; - STS : constant := 3; —= STS K SEVERE : constant := 4; K INFO of type COND VALUE TYPE. SYSTEM.UNSIGNED LONGWORD; - KSUCCESS routines and LIBSMATCH COND package STARLET as: 0; VAX Ada Packages B-19 -— You can obtain components of a condition value with -— the See Appendix C following functions. —— VAX Architecture —— handling in the —— The partial Handbook or the Introduction to VMS - returned by Severity code: STS_K ERROR, for - SUCCESS - Is TRUE - for a -— if for STS KWARNING, at low bit of of STS KSUCCESS, or STS 0 range severity STS_K SUCCESS is SUCCESS at 0 KSEVERE. 0 .. on. or range 2; This STS_K 0 occurs INFO. .. O; a system-wide basis. COND_1ID —— for the conditions COND_ID uniquely on at 0 range 3 .. 27; FAC NO a— Identifies - value. - for CUST the software FAC NO component at 0 generating the range 16 .. condition 27; DEF —— Is -= facilities. - for TRUE for customer facilities CUST_DEF at and FALSE 0 range that is, 27 .. for Digital 27; MSG_NO - A status identification; - hardware exception that —— value. — condition functions. STS K INFO, severity Identifies —- the SEVERITY - —- following SEVERITY —— for MSG_NO a description of the occurred or a at 0 range 3 software-defined .. 15; FAC_SP - Is —-— single facility and FALSE for system-wide message numbers. - -= B-20 each of - - System Services. indicates the portion of the -= —-= on condition representation specification —— each description —— value of the section TRUE for message for FAC SP Message number numbers at that 0 are range 15 specific .. to 15; CODE VAX Ada Packages (without facility specific flagqg). a -— for -— CODE at 0 range 3 .. 14; INHIB MSG - Is TRUE -- and FALSE - for function SEVERITY return function function inhibited on image exit INHIB MSG (STATUS : at 0 range 27 .. 27; COND_VALUE TYPE) (STATUS : COND_VALUE_TYPE) (STATUS : COND VALUE TYPE) BOOLEAN; COND ID return should be otherwise. UNSIGNED LONGWORD; SUCCESS return if the message UNSIGNED LONGWORD; function FAC NO (STATUS : COND_VALUE_TYPE) return UNSIGNED LONGWORD; function CUST DEF return function MSG_NO return function COND_VALUE_ TYPE) (STATUS : COND_VALUE_TYPE) (STATUS : COND_VALUE TYPE) (STATUS : COND_VALUE TYPE) BOOLEAN; function CODE return : UNSIGNED_ LONGWORD; function FAC_SP return (STATUS BOOLEAN; UNSIGNED LONGWORD; INHIB MSG (STATUS : COND_VALUE TYPE) raturn BOOLEAN; -—- Some —-— system services use input-output -- word of ~— are —-— a status blocks status block) that condition value. provided for SEVERITY, (for example, an contain only the low-order Component SUCCESS, accessing and MSG NO functions for such status values. subtype WORD COND VALUE_TYPE function SEVERITY (STATUS is : UNSIGNED WORD; WORD COND VALUE TYPE) return UNSIGNED LONGWORD; function SUCCESS (STATUS : WORD_COND_VALUE TYPE) return BOOLEAN; function MSG NO (STATUS : return UNSIGNED LONGWORD; WORD_ COND VALUE TYPE) VAX Ada Packages B-21 —— Signaling errors. -—- The -- Run-Time —-— value -- routine. —- exception handler using an —-— for the VAX Ada predefined exception —— importing a VMS —-- IMPORT - - following an returned The interface routine from a VMS or This a VMS STATUS * : Run-Time Library ’others’ condition as an Ada exception choice, NON ADAERROR, a exception using the pragma COND_VALUE TYPE; ASSIGN sets STATUS to ASSIGN (STATUS, ...): - if not SUCCESS (STATUS) a condition then value. SIGNAL (STATUS) (LIBS$) Manual. Parameters: CVv Condition code wvalue Notes: - procedure See the VMS SIGNAL VAX Ada Packages (STATUS RTL Library : in handler or by 9 - VMS condition EXCEPTION. — - LIB$SIGNAL. signal system service —-— - to used to resulting exception can be handled in an Ada - —_— routine can be Usage: * B-22 is Library COND VALUE TYPE); end if; -— The following is —— Run-Time —-—- value an Library interface routine returned from a VMS system service resulting exception can be signal This VMS a VMS routine. -- exception handler using an -- for the VAX Ada predefined exception NON ADAERROR, -—- importing a VMS ——- IMPORT EXCEPTION. ‘others’ condition as STATUS - —-— - ASSIGN (STATUS, ...): —— if SUCCESS (STATUS) - : an Ada exception an Ada choice, a handler or by using the pragma COND VALUE TYPE; ASSIGN not sets STATUS to a condition then STOP wvalue. (STATUS) end if; Parameters: CVv - handled in exception Usage: - o e condition or Run-Time Library -—- - The routine to LIB$SSTOP. can be used to Condition code value Notes: - procedure See the VMS RTL Library STOP (STATUS : (LIBS) Manual. in COND VALUE TYPE); VAX Ada Packages B-23 ——- Matching —— The condition following are ~= Run-Time —— - code Library interface function value matches routines to LIBSMATCH COND. can be used to determine one or more Usage: INDEX := MATCH COND (CV COND_VALUE TYPE, - INDEX := MATCH COND (CV COND_VALUE TYPE, - Cv1l COND_VALUE TYPE, -- « o - Cvn - -— : Value of condition 8 the list. CVi Condition code values, compared to for i from 1 to 8, to be CV. Return value: INDEX : INTEGER -= 0 If -— i-1 For a match between the - COND_VALUE TYPE); COND VALUE TYPE); code to match against - - : Ccv - -— for n up to CV1l Parameters: - This VMS if a condition condition values. -— - the no match found. first argument and ith argument. Notes: - The algorithm for matching condition codes is described in — the function VMS MATCH COND RTL Library (LIBS) : COND_VALUE TYPE; COND_VALUE 1 : COND VALUE TYPE) function INTEGER; MATCH COND ( COND VALUE : COND VALUE TYPE; COND_VALUE_1 : COND_VALUE_TYPE; return COND_VALUE 2 : COND VALUE_ TYPE) COND_VALUE 2 : COND_ VALUE TYPE; INTEGER; function MATCH_COND ( COND_ VALUE : COND_VALUE_ TYPE; COND_VALUE 1 : COND_VALUE TYPE; COND_VALUE 3 : COND_VALUE TYPE) return Manual. ( COND VALUE return B-24 code values. INTEGER; VAX Ada Packages function MATCH_COND ( COND_VALUE COND_VALUE TYPE; COND_VALUE 1 COND_VALUE_TYPE; COND_VALUE 2 COND_VALUE_TYPE; COND_VALUE_3 COND_VALUE COND_VALUE_4 COND_ VALUE TYPE) return TYPE; INTEGER; function MATCH COND ( COND_VALUE COND_VALUE_TYPE; COND_VALUE 1 COND_VALUE_TYPE; COND_VALUE 2 COND_VALUE 3 COND_VALUE_TYPE; COND VALUE 4 COND VALUE 5 COND_VALUE TYPE) return function Ll L COND_VALUE TYPE; COND_ VALUE_TYPE; INTEGER; MATCH COND ( COND VALUE COND VALUE_TYPE; COND_VALUE 1 COND_VALUE_TYPE; COND_VALUE_2 COND_VALUE TYPE; COND_VALUE_3 COND_VALUE_TYPE; COND_VALUE_4 COND_VALUE TYPE; COND_VALUE_5 COND_VALUE_TYPE; COND_VALUE 6 COND VALUE return function TYPE) INTEGER; MATCH COND COND VALUE : ( COND_VALUE TYPE; COND VALUE_1 COND_VALUE_TYPE; COND_VALUE_2 COND_VALUE TYPE; COND_VALUE_3 COND_VALUE_TYPE; COND_VALUE 4 COND VALUE COND VALUE TYPE; COND_VALUE 6 COND_VALUE_TYPE; COND_VALUE TYPE; COND VALUE 5 : COND_VALUE_7 raturn COND_VALUE_TYPE) TYPE; INTEGER; function MATCH COND_VALUE COND ( COND_VALUE_TYPE; COND_VALUE_1 COND_VALUE_TYPE; COND_VALUE_2 COND VALUE_3 COND_VALUE_TYPE; 4 COND_VALUE COND VALUE_ 5 COND_VALUE_TYPE; COND_VALUE_ 6 COND_VALUE COND_VALUE_TYPE; COND_VALUE_8 7 retu;n INTEGER; COND_VALUE_TYPE; L] -» * L COND_VALUE TYPE; COND VALUE_TYPE) private -- implementation-defined end CONDITION HANDLING; VAX Ada Packages B-25 B.4 Package CONTROL_C _INTERCEPTION package CONTROL C INTERCEPTION is This package establishes a CTRL/C handler when it is elaborated. If your tasking program fails to stop when you type CTRL/Y EXIT, debugger when you type or fails CTRL/Y DEBUG, the package to invoke the VMS using this package can cure the problem. in a creating tasks ’'with’ clause, and elaborate it Name before in the program. Example: WITH CONTR C_ INTERCEPTION; OL pragma ELABORATE (CONTROL C INTERCEPTION) ; procedure Then, MY MAIN PROGRAM is if CTRL/Y does not work as debugger or to exit, type CTRL/C. the VAX Ada CTRL/C interceptor, the same NOTE: options that which will also be CTRL/C able DCL Use SET of this to and get any Ada program that captive user from gaining same command can override command. CTRL/C in degree of uses files It control is pragma IDENT Square digits files control by typing CTRL/Y). B-26 Version 2.0"); root. function SQRT Natural <>; is ("VAX Ada (A : REAL) logarithm - VAX Ada Packages are also return REAL; log base e (A). intentions user to of type over the program. (command generic MATH LIB a package Package MATH LIB type REAL the allows this end CONTROL_C INTERCEPTION; package in the (provided they its prompt. Hence, used execute package NOCONTROL Y the of either before or after the VAX Ada interceptor gives CAUTION: invoke give you most CTRL/Y would. outband AST handlers), B.5 invoke the Typing CTRL/C will Other CTRL/C handlers that might be present program will the a way to should not that prevent be a function LOG (A : REAL) —— Common logarithm function LOG1l0 ——- Base 2 — (A return REAL; log base : REAL) 10 (A). return REAL; logarithm - log base 2 (A). *** not in FORTRAN — function LOG2 (A : REAL) return REAL; function EXP (A : REAL) return REAL; —-— Sine, and tangent of an angle given in radians. -—- Exponential. cosine, function SIN (A : REAL) return REAL; function COS (A : REAL) return REAL; function TAN (A : REAL) return REAL; -— Arc —-— sine, arc cosine, and arc tangent - return an angle expressed in radians. function ASIN (A : REAL) return REAL; function ACOS (A : REAL) return REAL; function ATAN (A : REAL) return REAL; —-— Arc tangent with two parameters - Arc Tan (Al/A2) - returns -—- an angle expressed in radians. function ATANZ2 (Al, -— Hyperbolic sine, function A2 : REAL) cosine, return REAL; and tangent of an angle in radians. SINH (A : REAL) return REAL; function COSH (A : REAL) return REAL; function TANH (A : REAL) return REAL; -— Trigonometric functions for angles expressed in degrees. function SIND (A : REAL) return REAL; function COSD (A : REAL) return REAL; function TAND (A : REAL) return REAL; function ASIND (A : REAL) return REAL; function ACOSD (A : REAL) return REAL; function ATAND (A : REAL) function ATAN2D (Al, A2 : return REAL; REAL) return REAL; -- Exponentiation. function "**" (Al, A2 : REAL) return REAL; -—- Exceptions: The following exceptions are raised by various —— VMS Run-Time Library mathematics routines. See the VMS RTL —-— Mathematics (MTH$) Manual for details. VAX Ada Packages B-27 ROPRAND : exception; INVARGMAT —-- Reserved exception; -- operand fault. Invalid argument. FLOOVEMAT : exception; -- Floating-point overflow in Math FLOUNDMAT : exception; -- Floating-point underflow LOGZERNEG : exception; -- SQUROONEG : exception; -- Square Logarithm of root Library. in Math Library. zero or negative value. of a negative number. private —— end implementation defined MATH LIB; pragma B.6 INLINE GENERIC (MATH LIB); Package STARLET The specification of the types declared in this package follows. Ada parameter types Types as and subtypes for VMS system service defined in the predefined package STANDARD that parameter BOOLEAN, types INTEGER, for VMS SHORT INTEGER, the predefined package AST_ HANDLER, Additional system service and STRING. SYSTEM are used, UNSIGNED LONGWORD, parameter types are and calls calls. are used include Several types including ADDRESS, other unsigned types. defined as follows: DESCRIPTOR TYPE Record structure type DESCRIPTOR TYPE that is the prototype for is record LENGTH: SYSTEM.UNSIGNED WORD; DTYPE: SYSTEM.UNSIGNED BYTE; CLASS: SYSTEM.UNSIGNED BYTE; POINTER: SYSTEM.ADDRESS; end record; type DESCRIPTOR_ARRAY TYPE array B-28 (NATURAL range VAX Ada Packages <>) is of DESCRIPTOR TYPE; a VAX descriptor. in -- ACCESS_BIT NAMES TYPE -—- Array of 32 elements -—- descriptor; in which each element is a CLASS_ S each descriptor names one of the 32 bits -— access mask. -—- service is The ACCNAM parameter of this of the FORMAT ACL string in an system type. subtype ACCESS BIT NAMES TYPE is STARLET.DESCRIPTOR ARRAY TYPE -- ACCESS_MODE TYPE -- Hardware -— (0) access mode. specifies (2) specifies SYSTEM.UNSIGNED WORD -— MODE_ZERO : of address array O .. and PSL C USER (3) 3; ACCESS MODE TYPE addresses denoting a in the := 0; in the (0 .. 1) range of virtual The range; first the address addresses, which specifies the second specifies the ending range. of is SYSTEM.ADDRESS; ARG _LIST TYPE ——- Procedure argument -— the longword contains first -- number of longword -—- a VAX CALL subtype list successive, -- —— PSL_C_KERNEL specifies executive mode; is identify an area of memory. type ADDRESS RANGE TYPE —— (1) supervisor mode; range constant -—- beginning address -— four values: ADDRESS RANGE TYPE —— Array -— can take PSL C EXEC user mode. subtype ACCESS MODE TYPE ACCESS This specifies kernel mode; -- PSL C SUPER -- (0..31); is consisting of one or more an unsigned integer contiguous longwords. a parameter to be passed to longwords; count Each of the subsequent a procedure by means of instruction. ARG LIST TYPE is SYSTEM.UNSIGNED LONGWORD ARRAY; ASTPROCEDURE TYPE —— Address of —— level. (Procedures the entry mask -— called PROCEDURE_IYPE.) that to are a procedure not to be to be called called at AST at AST level are subtype ASTPROCEDURE TYPE is SYSTEM.ADDRESS; VAX Ada Packages B-29 —— CHANNEL TYPE —— Unsigned word integer that is an index to an input-output channel. subtype CHANNEL TYPE is SYSTEM.UNSIGNED WORD; CHANNEL ZERO CHANNEL TYPE —— : COND VALUE —-= VMS constant TYPE condition COND VALUE ZERO (See the package : CONDITION HANDLING.) constant CONDITION HANDLING.COND VALUE COND VALUE 1 0O; (CONDITION HANDLING.COND_ VALUE TYPE) value. : := TYPE := 0; constant CONDITION HANDLING.COND -— CONTEXT TYPE —-- Longword value —-— some that is VALUE TYPE used by a 1; called procedure to maintain context. —— subtype CONTEXT TYPE -- is SYSTEM.UNSIGNED LONGWORD; DATE_TIME_TYPE —— 64-bit -- representing the number of elapsed 100-nanosecond units unsigned binary integer denoting a date —— 00:00 o’clock, November subtype DATE TIME TYPE DEVICE is Character -- logical —— name. SYSTEM.UNSIGNED QUADWORD; string denoting the name name, but if it subtype DEVICE NAME TYPE is, is of it must It can be a to a wvalid device STRING; EF_CLUSTER NAME TYPE It can be a —— valid event logical flag name, cluster but VAX Ada Packages if it name. subtype EF CLUSTER NAME TYPE is B-30 a device. translate ——- Character string denoting the name of -—- since 1858. NAME TYPE —— -- 17, and time STRING; an event is, it must flag cluster. translate to a —— EF NUMBER —-— Unsigned subtype TYPE longword EF_NUMBERTYPE EF_NUMBER_ZERO -- integer : is denoting the number of an event flag. SYSTEM.UNSIGNED LONGWORD; constant EF _NUMBER_TYPE := O; EXIT HANDLER BLOCK TYPE —— Variable-length —— block. —— this The structure denoting DESBLK parameter of an exit the handler control DCLEXH system service is of subtype. subtype EXITHANDLER BLOCK TYPE is SYSTEM.UNSIGNED LONGWORD ARRAY; —— FAB TYPE RMS -— VMS —-— STARLET. —— FILE _PROTECTION_ TYPE -— 16-bit -- fields, -— file file file access block. Type protection mask. each of which access attempts : The mask is contains in the four specifies the protection to be by one subtype FILE _PROTECTION TYPE FILE PROTECTION ZERO definition of the is four categories package 4-bit applied to of user. SYSTEM.UNSIGNED WORD; constant FILE PROTECTION TYPE := 0; type FILE PROTECTION_FLA TYPE GS is record NOREAD : BOOLEAN; —— Deny read NOWRITE : BOOLEAN; —- Deny write NOEXE : BOOLEAN; —-—- Deny execution NODEL : BOOLEAN; —— Deny delete access. access. access. access. end record; pragma type PACK (FILE_PROTECTION FLAGS TYPE); FILEPROTECTI REC ON TYPE is record SYS : FILE _PROTECTION_FLAGS TYPE; OWN : FILE GRP : FILE PROTECTION_FLAGS TYPE' WLD : FILE PROTECTION TYPE' PROTECTION_FLAGS TYPE; FLAGS end record; VAX Ada Packages B-31 for FILEPROTECTION REC TYPE use at 1 range at 1 range W, GRP WLD Nsg range Ne range 0 AT 0 O O SYS = at OWN at <N W dWw record end record; for —— FILEPROTECTI REC TYPE’SIZE ON use 16; FUNCTION_ CODE TYPE —— Unsigned word specifying the —-— perform. —--— this The FUNC type. argument See also operations to the QIO a system service system service subtype FUNCTION_CODE TYPE is SYSTEM.UNSIGNED WORD; FUNCTION_CODE_ TYPE —— constant := O; IDENTIFIER TYPE —-— Unsigned longword that —— to of ITEM LIST_3 TYPE. FUNCTION_CODE_ZERO : is is identifies an object returned by the system. subtype IDENTIFIER TYPE —— IO _STATUS -—- 8-byte —— service that SYSTEM.UNSIGNED TLONGWORD; BLOCK TYPE record containing completes ~—- returned varies —-- the type is depending on the system services IO STATUS information QIO, BLOCK TYPE returned by a asynchronously. GETDVI, system The information service. For example, see and GETJPI. is raecord STATUS : CONDITION_HANDLING.WORD_ COND_ VALUE_TYPE; COUNT : SYSTEM.UNSIG WORD; NED DEV_INFO : SYSTEM.UNSIGNED LONGWORD; end recorxd; subtype IOSB_TYPE is IO_STATUS BLOCK TYPE; -- For VAX Ada Version —— -~ ITEM LIST 2 TYPE -— Array -- of one or more longword containing —-— structure that —-— of the FILESCAN type VAX Ada Packages item descriptors 0. contains Each is that is item descriptor three system service ITEM REC 2 TYPE record B-32 compatibility. fields. is of terminated by is a a 2-longword The VALUELST parameter this subtype. 1 —— --—— A word in which the service writes the length (in If the service characters) of the requested component. does not locate the component, it writes the value 0 in this field and in the COMPONENT ADDRESS field and -- returns the SSNORMAL condition code. COMPONENT LENGTH SYSTEM.UNSIGNED_WORD; : —-- A user-supplied, word-length symbolic code that specifies -— the component desired. ITEM CODE STARLET.FUNCTION CODE_TYPE; : -— A longword in which the service writes the starting This address points to a -- address of the component. —— location in the input string itself. COMPONENT ADDRESS : SYSTEM.ADDRESS; end record; type ITEM LIST 2 TYPE is array (NATURAL range <>) -- REC 2 TYPE; of ITEM 3 TYPE ITEMLIST -- Array that consists of one or more item descriptors and that is Each item descriptor is -- terminated by a longword containing 0. The ITMLST -- a 3-longword structure that contains four fields. Also -- parameter of the GETDVI system service is of this type. —— known as ITEM LIST TYPE. REC _TYPE is type ITEM record -- Length of the buffer (in bytes) containing or -- receiving the information specified by -- ITEM CODE. BUF LEN : SYSTEM.UNSIGNED WORD; -— Code indicating the operation to be performed. ITEM CODE : STARLET.FUNCTION CODE TYPE; -- Address of the buffer containing or receiving ~— the information specified by ITEM CODE. BUF_ ADDRESS : SYSTEM.ADDRESS; —— Address of a word to receive the length of the -— information RET ADDRESS : returned. SYSTEM.ADDRESS; end record; VAX Ada Packages B-33 type ITEMLIST 3 TYPE is array (NATURAL range <>) of ITEM REC TYPE; ITEM LIST TYPE is ITEMLIST 3 TYPE; subtype —--— ITEM LIST PAIR TYPE —-— —-— -- Structure that consists of one or more longword pairs, or doublets, and is terminated by a longword containing O. Typically, the first longword contains an integer value such as a code. The second longword can contain a real or integer —-— wvalue. type ITEM LIST PAIR REC TYPE is record L0: SYSTEM.UNSIGNED LONGWORD; L1l: SYSTEM.UNSIGNED LONGWORD; end record; type ITEM LIST PAIR TYPE array -- is (NATURAL range <>) of ITEM LIST PAIR REC _TYPE; ITEM QUOTA LIST TYPE —— Array of one or more quota item descriptors that is terminated -- by an item code of 0. Each quota item descriptor is an —— unsigned byte —— item. -- code followed by a longword value for that quota The QUOTA parameter of the CREPRC system service is of this type. type ITEMQUOTA REC TYPE is record —-—- Code indicating the quota to be assigned. -- is list ITEM CODE : SYSTEM.UNSIGNED BYTE; -- Value of the quota to be assigned. ITEM VALUE : SYSTEM.UNSIGNED LONGWORD; end record; type ITEM QUOTA LIST TYPE is array B34 The end of the designated by an item code of PQL LISTEND. (NATURAL range <>) VAX Ada Packages of ITEM QUOTA REC_TYPE; -- LOCK ID TYPE -- Longword value denoting a lock identifier. -~ identifier is assigned by the lock manager -- when the lock is This lock facility to a lock granted. type LOCK ID TYPE is new SYSTEM.UNSIGNED_ LONGWORD; LOCK_ID ZERO -- : constant LOCK_ID TYPE := 0; LOCK_VALUE BLOCK TYPE —- 16-byte block that the lock manager facility includes in a lock -- status block if the user requests it; the contents of the lock -— value block are user-defined and are not interpreted by the -- lock manager facility. type LOCK VALUE BLOCK TYPE is new SYSTEM.UNSIGNED BYTE ARRAY -- (1 .. 16); LOCK_STATUS BLOCK_TYPE —— Structure into which the lock manager facility writes -~ ---—- status information about a lock. A lock status block always contains at least two longwords: the first word of the first longword contains a status code; the second word of the first longword 1is reserved by Digital; and the second longword contains the —-— lock identifier. In addition to these -- block may optionally include a type 16-byte fields, a lock status lock value block. LOCK STATUS BLOCK_TYPE is record STATUS : RESERVED : CONDITION HANDLING.WORD CONDVALUE TYPE; SYSTEM. UNSIGNED__WORD; ID : STARLET.LOCK ID TYPE; VALU : STARLET.LOCK VALUE BLOCK TYPE; end record; —- LOGICAL NAME TYPE —— Character string of from 1 to 255 characters that identifies a —— logical name or equivalence name to be manipulated by VMS -- logical name system services. subtype LOGICAL NAME TYPE is STRING; VAX Ada Packages B-35 -— MASK PRIVILEGES TYPFE —— 64-bit record wherein each -- privilege. -- is of this subtype -- MASKPRIVILEGES TYPE Longword value the VAX specifying is subtype. service protection of this are —— PROCEDURE TYPE protection of Symbolic the values to be SETPRT applied by system for page PRT C_ xxx. —— Address -— called at AST level. —-— called at AST level of the entry mask is SYSTEM.UNSIGNED LONGWORD; to a procedure that is not to be (Arguments have subtype PROCEDURE TYPE 1 page PROT parameter subtype PAGE_PROTECTION_TYPE is the specifying procedures type AST_PROCEDURE_ TYPE.) to be SYSTEM.ADDRESS; PROCESS_ID TYPE Longword —-— process -— a -— of value process the denoting identifier when DELPRC is the -- PROCES NAME TYPE S —-— Character a process identifier assigned by the process system subtype PROCESS ID TYPE is service is string that VMS created. is of The this (PID). This operating system to PIDADR parameter subtype. SYSTEM.UNSIGNED LONGWORD; specifies the name of — a process. [ subtype PROCESS NAME TYPE -- a process system service STARLET.PRV_ TYPE; the The —— is STRING; RIGHTS_ID TYPE —— Longword —-—- an —-- environment. -—- 0of value interest a user’s denoting group This User : rights rights identifier, which context of the VMS security identifier may Identification is constant VAX Ada Packages a in the subtype RIGHTS_ID TYPE RIGHTS_ID_ZERO B-36 is hardware. —-— -— denotes PAGE_PROTECTIO TYPFE N —— —— bit subtype. —— — individual The PRVADR parameter of the CREPRC Code consist (UIC). SYSTEM.UNSIGNED LONGWORD; RIGHTS ID TYPE := 0; of identifies all or part RIGHTS HOLDER TYPE 64-bit record specifying a user’s access rights to a system object. The RACCESS component is a longword bit mask wherein each bit specifies an access right. The HOLDER parameter of the ADD HOLDER system service type RIGHTS HOLDER_TYPE is of this type. is record RIGHTS_ID : STARLET.RIGHTS_ID TYPE; RACCESS : STARLET.KGB ATTRIBUTES_ TYPE; end record; RAB TYPE VMS RMS record access block. Type definition is in the package STARLET. RU_HANDLE TYPE Longword value that is used by the recovery unit services to identify a particular recovery unit. type RU HANDLE TYPE is new SYSTEM.UNSIGNED_TLONGWORD; SECTION ID TYPE Quadword value denoting a global section identifier. This identifier specifies the version of a global section and the criteria to be used in matching that global section. The IDENT parameter of the MGBLSC system service is of this subtype. type SECTION ID TYPE is new SYSTEM.UNSIGNED_ QUADWORD; SECTION_ NAME TYPE Character string denoting a global section name. This character string can be a logical name, but it must translate to a valid global section name. MGBLSC system service is of this The GSDNAM parameter of the subtype. subtype SECTION NAME TYPE is STRING; VAX Ada Packages B-37 -- SYSTEM ACCESS ID_ TYPE —— Quadword value —-— is —-- parameter to be that denotes associated with a of the CREATE_RDB subtype SYSTEMACCESS ID TYPE SYSTEM.UNSIGNED -— TIME —~ Character TIMBUF -- subtype. subtype string parameter TIME NAME TYPE -— l6-byte value that service value The SYSID of this is that subtype. is a time value the ASCTIM is STRING; uniquely TRANSACTION_ ID TYPE UIC TYPE —— Longword value subtype UICLONGWORD TYPE -- USER ARG TYPE : —-— Longword value ~— is —— the —— ASTPRM parameter passed to : User is denoting the is constant —— The —— documentation following —— defined here for are a VAX Ada Packages Code (UIC). QIO := argument. a parameter, but interpreted by system 0; service the the is of This longword contents user. this of The subtype. SYSTEM.UNSIGNED LONGWORD; type aliases is subtype BYTE UNSIGNED _TYPE CHARSTRING TYPE Identification user-defined completeness subtype BYTE_SIGNEDTYPE The this (0..15); USER ARG TYPE additional and of transaction. UICLONGWORD TYPE defined and of a format. is SYSTEM.UNSIGNED LONGWORD; constant subtype USERARGTYPE USER_ARG_ZERO a a procedure as longword are in VMS service is denoting UIC_LONGWORD_ZERO system identifies SYSTEM.UNSIGNED BYTE ARRAY -- B-38 system specifying of TRANSACTION ID TYPE subtype database. QUADWORD, —— new system identification NAME TYPE —— type a rights is names of := are 0; used in the VMS existing Ada and ease types. of use. SHORT SHORT INTEGER; is SYSTEM.UNSIGNED _BYTE; STRING; They are subtype LONGWORD SIGNED TYPE is INTEGER; subtype LONGWORD UNSIGNED TYPE is SYSTEM.UNSIGNED_LONGWORD; subtype subtype subtype subtype MASK BYTE TYPE is SYSTEM.UNSIGNED_BYTE; MASKLONGWORD TYPE is SYSTEM.UNSIGNED_LONGWORD; D is SYSTEM.UNSIGNED_QUADWORD; TYPE MASKQUADWOR MASK WORD TYPE is SYSTEM.UNSIGNED_WORD; TYPE is OR BYTE SIGNED type VECT array (NATURAL range <>) of SHORT SHORT_ INTEGER; subtype VECTORBYTEUNSIGNEDTYPE is SYSTEM.UNSIGNEDBYTEARRAY; type VECTORLONGWORD SIGNED_TYPE is array (NATURAL range <>) of INTEGER; subtype VECTOR LONGWORD UNSIGNED_ TYPE is SYSTEM.UNSIGNED LONGWORD_ARRAY; R is WORD SIGNED TYPE type VECTO array (NATURAL range <>) of SHORT_ INTEGER; subtype VECTORWORDUNSIGNED_TYPE is SYSTEM. UNSIGNED WORD ARRAY, B.7 Package SYSTEM_RUNTIME_TUNING This package defines interfaces to allow user programs to change various parameters that affect Ada program execution and that are normally chosen by the VAX Ada run-time library. package SYSTEM RUNTIME TUNING is subtype AST PACKET REQUEST TYPE is NATURAL range O .. 1_048_576; AST PACKET_POOL procedure EXPAND ( REQUESTED PACKETS : in AST PACKET REQUEST TYPE; ACTUAL NUMBER : out NATURAL; TOTAL NUMBER : ; out NATURAL) VAX Ada Packages B-39 —— FUNCTIONAL —— This —— by the 1048576 routine adds AST ENTRY more AST packets attribute. It —-— to —-- being enough virtual memory to —= AST packet —— When —— packet == parameter. —— is you packets. use is The currently the AST ENTRY An AST Ada packet delivered by the VMS —— task parameter. If —— operating system, —— AST packet pool, completes the accept peak but an of 32 bytes attribute run-time is in yet use error the AST packet routine can —— 1increasing" the the packet of —— Before increasing the AST packet == number of —= to ensure —- is not -- during the AST packets that delayed the by —— concluded that —— momentarily —— should you —— the accepting an accept required the AST exceeds has the rate your program’s consider using this when the the the AST receiving AST the VMS the occurs, stating size of the that that error by try to minimize the peak program. this, very any for the AST. arrival time eliminate a interaction with statement an AST pool. your task an AST, to hold the AST The help pool, by there memory.) exceeds exhausted. AST on used up (A single delivered by accepted, EXPAND_ASTPACKETPOOL size dynamic receiving of ASTs of request. handle from —— been depends of to —— has call system until unrecoverable pool creation library statement number not the of packets the satisfy the operating the to the pool supports success consumes used by the —— is routine high other do priority, task before Only after so rate To high of that try and or you have it servicing the ASTs to increase if your program’s the size of pool. —-- NOTE: —— AST B-40 DESCRIPTION Using this arrival —- because routine will rate is eventually —— packets. —— the -- application. ——- INPUT —— REQUESTED_PACKETS -- desired. AST 1In this arrival greater not than help its average AST your program will case, rate -- you need to how you do still revise that run service out average rate, of AST your program to depends on reduce your PARAMETERS: is the More may be —- storage == can —— OUTPUT —— ACTUAL_NUMBER -— the boundary. specify 0 To minimum number of additional allocated because of rounding to the next determine the current size of packets the pool, you were added to for REQUESTEDPACKETS. PARAMETERS: indicates the number of packets that pool. —— TOTAL_NUMBER indicates the -- pool. that this number —— currently use for the (Note in VAX Ada Packages total number includes delivery of of AST AST packets packets an AST.) that in the might be EXCEPTIONS: STORAGEERROR is raised if the request could not be satisfied because of insufficient memory. When STORAGEERROR is raised, an attempt is made to release any AST packets allocated in partial fulfillment of the request. PROGRAM ERROR may be raised for certain other errors. If PROGRAM ERROR is raised, a chained Other condition indicates a detailed reason for the failure. exceptions may be raised as well. pragma INTERFACE (RTL, EXPAND_ ASTPACKET_POOL) ; pragma IMPORT PROCEDURE(EXPAND AST PACKETPOOL, "ADA$EXPAND ASTPACKET_ POOL"); T LICE TIME procedure REQUES (REQUESTED_VALUE : DURATION) ; FUNCTIONAL DESCRIPTION: This routine conditionally modifies the time-slice setting of the program. This entry point can only make time slicing run faster than it is already running, or enable it if it is not enabled. The request will be overridden by the value specified by a pragma TIME SLICE in an Ada main program or by a debugger SET TASK /TIME SLICE command. This routine is primarily intended to be called from within an Ada shareable image or an object file exported by an ACS EXPORT command, where it cannot be decided in advance whether there will However, this routine can also be used be an Ada main program. to override the wishes of an Ada main program that does not specify a pragma TIME SLICE (and as often as desired). This call has no effect if any of the following are true: 1. REQUESTED VALUE is 0.0 or negative (time slicing cannot be disabled by this routine). 2. REQUESTED VALUE is greater than a previously specified time-slice value that successfully set the time slice. 3. Time slicing has either been activated or turned off by a pragma TIME SLICE. 4. A debugger SET TASK/TIME SLICE=t command has been issued. If none of these conditions is true, then REQUESTED_VALUE will set the time slice. In the following cases, the time slice set by this call will be overridden: VAX Ada Packages B-41 - l. - An image containing an Ada is TASK/TIME SLICE=t 2. A - 3. REQUEST_TIME SLICE is greater “than 0 less debugger —— INPUT == REQUESTED_VALUE program that but called than command again the is with value a -=— EXCEPTIONS: PROGRAM ERROR —— is —— the raised, a failure. is may the be requested raised for chained condition Other exceptions pragma INTERFACE (RTL, pragma IMPORTPROCEDURE(REQUEST new time-slice certain indicates may be errors. a REQUEST TIMESLICE) ; TIME SLICE, use use STARLET; SYSTEM; with CONDITION__HANDLING; use CONDITION_HANDLING; with RMS ASYNCH_OPERATIONS; use RMS _ASYNCHOPERATIONS; package TASKING SERVICES is pragma B—42 this call. IDENT ("VAX VAX Ada Packages Ada Version 2.0"); value. If PROGRAM[ ERROR detailed reason for raised as well. Package TASKING_ SERVICES SYSTEM; by PARAMETERS: —— with STARLET; with pragma REQUESTED_VALUE set SYSTEM RUNTIME TUNING; B.8 a issued. "ADASSETTIME SLICE"); end has activated. - - main TIME SLICE DESCRIPTION: Certain VMS system services allow the calling routine to synchronize with the completion of the service. In other words, after issuing (queuing) the system service call, the calling routine may continue executing until the service completes. Then, the routine can synchronize with the service using an event flag and/or an AST handler. If one of these services is called by a VAX Ada task in a program where time slicing has not been enabled, and event-flag synchronization has been chosen (for example, SYSSQIOW has been called), the process in which the calling task is executing will be suspended until the event flag is set. This effect may not be desired because suspension of the process causes all other executing tasks to be suspended, even if they are ready for execution. This package provides a convenient interface to VMS system services that have both synchronous and asynchronous forms (for example, SYS$QIOW and SYSS$QIO). The package is designed for those situations in which you would like a particular task to wait for the completion of a system service, but do not want to prevent other tasks in your program from executing. Although the pragma AST_ENTRY and attribute T’AST_ENTRY provide a more general way of achieving the same effect, they require more detailed programming. This package provides an interface to the following VMS system services: System service TASKING SERVICES name $BRKTHRU TASK_BRKTHRUW SENQ TASK ENQW $GETDVI TASK GETDVIW $GETJPI $GETLKI TASK GETJPIW $GETQUI TASK GETQUIW $GETSYI TASK GETSYIW $QI0 TASK_QIOW $SNDJBC TASK SNDJBCW $UPDSEC all RMS operations TASK GETLKIW TASK UPDSECW TASK RMS * (for example, TASK RMS_GET) The signatures of the subprogram declarations generally correspond to those in the package STARLET, and use the same parameter types declared in the VAX Ada Packages B—43 —— package -— Run-Time STARLET. -— system services; —— both the packages -- Differences STARLET are: -- 1. AST The Manual the Chapter same considerations STARLET handler and AST - package. In the package STARLET, input -- descriptor. In - loadings used to -— used to a type-nam NULL PARAMETER e’ -- arguments are for in the package parameter omitted because they are 2. apply and TASKING SERVICES. - - 6 of the VAX Ada information on calling for from the declarations -- - parameters implement default is used value for that are passed by this package, of optional reference multiple achieve the are this same or over- effect. TASK_BRKTHRUW -- Write - task — Parameters: to terminal until the breakthrough system service and is efn Number —— msgbuf Address of a message = Address of a descriptor of the event —= sendto - the - sndtyp = - iosb = Address —— carcon = Carriage control. - flags = Flags modify - reqid = Broadcast e timout = Address suspend the completed. —— procedure B-44 Refer to Reference flag to be buffer set on completion. descriptor. specifying the receiver message. Terminal TASK BRKTHRUW type of to a to which message quadword input-output class of the the is timeout status identification. value. ( : out COND VALUE TYPE; EFN : in EF_NUMBER TYPE MSGBUF : in STRING; SENDTO : in STRING; SNDTYP : in UNSIGNED LONGWORD JOSB : out IO_STATUS“BLOCK_TYPE; CARCON : in UNSIGNED LONGWORD FLAGS : in BRK_TYPE; sent. broadcast. requestor STATUS VAX Ada Packages the := EF_NUMBER ZERO; := 0; := 32; block. of REQID Ll - TIMOUT procedure in UNSIGNED LONGWORD in UNSIGNED LONGWORD TASK BRKTHRUW 0); ( STATUS out COND_VALUE_TYPE; EFN in EF_NUMBER TYPE IGNORED in ADDRESS EF_NUMBER ZERO; = in STRING; SNDTYP in UNSIGNED IOSB out BLOCK TYPE; I0STATUS SENDTO - 0; LONGWORD 32; in UNSIGNED in BRK_TYPE; REQID in UNSIGNED LONGWORD 0; TIMOUT in UNSIGNED LONGWORD I LONGWORD CARCON FLAGS 0); I L] ADDRESS_ZERO; EF _NUMBER ZERO; procedure TASK BRKTHRUW — ( STATUS out COND_VALUE_TYPE; EFN in EF_NUMBER TYPE MSGBUF in STRING; IGNORED in ADDRESS ADDRESS_ZERO; UNSIGNED LONGWORD 0; SNDTYP CARCON I0 STATUS_BLOCK_TYPE; 32; UNSIGNED LONGWORD FLAGS BRK TYPE; REQID UNSIGNED LONGWORD 0; TIMOUT UNSIGNED LONGWORD 0); TASK BRKTHRUW ( STATUS out COND_VALUE_TYPE; EFN in EF_NUMBER TYPE SNDTYP in UNSIGNED LONGWORD IOSB out CARCON in UNSIGNEDLONGWORD FLAGS in BRK TYPE; REQID in UNSIGNED LONGWORD TIMOUT in UNSIGNEDLONGWORD procedure 10 STATUS_BLOCK_TYPE; TASKBRKTHRUW EF_NUMBER ZERO; 0; — 32; = 0; » — - 0); ( STATUS out COND_VALUE TYPE; EFN in EF MSGBUF in STRING; SENDTO in STRING; SNDTYP in UNSIGNED LONGWORD TOSB in ADDRESS CARCON in UNSIGNED FLAGS in BRK_TYPE; REQID in TIMOUT in procedure — — NUMBER TYPE I procedure EF NUMBER ZERO; = 0; I IOSB ADDRESS_ZERO; LONGWORD 32; UNSIGNED LONGWORD 0; UNSIGNED LONGWORD 0); TASK BRKTHRUW ( STATUS out COND_VALUE TYPE; EFN in EF NUMBER_TYPE EF IGNORED in ADDRESS ADDRESS SENDTO in STRING; NUMBER ZERO; ZERO; 0; SNDTYP in UNSIGNED TIOSB in ADDRESS ADDRESS ZERO; CARCON in in UNSIGNED LONGWORD 32; BRK_ TYPE; FLAGS LONGWORD VAX Ada Packages B-45 procedure TASK BRKTHRUW : EFN out COND [X ) in [X ) IGNORED in [ 2] STRING; in [2 ) EF NUMBER TYPE in FLAGS [ X in in in REQID L2 ) : MSGBUF in TIMOUT : in SNDTYP IOSB CARCON procedure UNSIGNED LONGWORD ADDRESS ADDRESS_ZERO; UNSIGNED LONGWORD 32; BRK _TYPE; UNSIGNED LONGWORD 0; UNSIGNED 0):; ADDRESS TOSB : in ADDRESS CARCON : in UNSIGNED LONGWORD FLAGS : in BRK_TYPE; REQID UNSIGNED LONGWORD 0; Il in COND_ VALUE TYPE; EF ADDRESS_ZERO; il .0 [ X in TIMOUT 32; NUMBER TYPE EF_NUMBER : in UNSIGNED LONGWORD 0; in UNSIGNED_LONGWORD 0):; : ZERO; 0; ( out SNDTYP = LONGWORD [) STATUS EF_NUMBER ZERO; ADDRESS TASK BRKTHRUW EFN Y ( VALUE TYPE; e STATUS e UNSIGNED LONGWORD I UNSIGNED LONGWORD in N in : o : TIMOUT e REQID ZERO; TASK ENQW Enqueue lock lock request and suspend the task until the is either granted or converted. Paramete rs: efn lkmode Number —— — Type of of the lock mode to be requested. LCK_K_NLMODE null concurrent read LCK_K_CWMODE concurrent write LCK_K_PRMODE protected protected write LCK_K_EXMODE exclusive Address flags Flags of the defining the These LCK_M NOQUEUE LCK_M SYNCSTS LCK_M SYSTEM LCK_M VALBLK LCK_M lock CONVERT are: set Modes on completion. are: lock LCK_K_PWMODE lksb VAX Ada Packages flag LCK_K_CRMODE lock. B-46 event read lock status block. characteristics of the Address resnam - of the string descriptor of the resource name. —= parid Lock identification of the parent - blkast Address of entry mask of the blocking AST routine; this AST handler must ignore its AST 1lock. parameter. - acmode Access mode to be associated with the lock. - reserv ed Reserved procedure TASK ENQW for future use. ( STATUS : out COND VALUE_TYPE; EFN : in EF NUMBER TYPE LKMODE : in UNSIGNED LONGWORD; := EF_NUMBER ZERO; LKSB : in out BLOCK TYPE; LOCK_ STATUS FLAGS : in LCK_TYPE; RESNAM : in STRING; PARID : in LOCK ID TYPE := LOCK ID ZERO; BLKAST in AST HANDLER := NO ASTHANDLER; ACMODE in ACCESS_MODE_TYPE := ACCESS_MODE_ZERO; RESERVED: in ADDRESS := ADDRESS ZERO) ; TASK ENQW ( STATUS : out COND_VALUE EFN : in EF NUMBER TYPE UNSIGNED : in in LKSB FLAGS in LCK TYPE; LOCK_ID TYPE BLKAST in AST HANDLER ACMODE in RESERVED: in ACCESS_MODE_TYPE ADDRESS : EF_NUMBER ZERO; out LOCK_ STATUS_ BLOCK_TYPE; in PARID := LONGWORD; := LOCK ID ZERO; [ LKMODE TYPE; NO AST HANDLER; i procedure ACCESS MODE_ZERO; := ADDRESS ZERO) ; VAX Ada Packages B-47 -- TASK_GETDVIW —— Get —— until — Parameters: device/ volume the information operation is -- efn = Number of - chan = Number of O if the and suspend the task complete. the a event flag to be channel device is set assigned to on the completion. device or specified by the devnam parameter. -— devnam = Address of the device name or logical name descriptor. -— itmlst = Address of a list - iosb = Address of a quadword - nullarg= e DEVNAM COND_VALUE_TYPE; L3 ) CHAN in EF_NUMBER in CHANNEL : in DEVIC NAME TYPE; E : in ITEM LIST 3 TYPE; IOSB : out IO_STATUS_BLOC TYPE; K NULLARG : in ADDRESS procedure TASK GE TDVIW status EF_NUMBER ZERO; := CHANNEL ZERO; := ADDRESS_ZERO) ; STATUS : out COND_VALUE_TYPE; : in EF_NUMBER CHAN : in CHANNEL TYPE TYPE ITMLST : in ITEM LIST 3 TYPE; IOSB : out IO_STATUS_BLOCK_TYPE; : in ADDRESS TASK GETDVIW := ( EFN NULLARG := EF_NUMBER ZERO; := CHANNEL_ ZERO; := ADDRESS_ ZERO) ; ( STATUS : out COND VALUE TYPE; EFN : in EF_NUMBER TYPE := CHAN EF_NUMBER ZERO; : in CHANNEL TYPE := CHANNEL DEVNAM : in DEV NAME ICE TYPE; ADDRESS_ZERO; ZERO; ITMLST : in ITEM LIST 3 TYPE; IOSB : in ADDRESS := NULLARG : in ADDRESS := ADDRESS ZERO) ; procedure TASK GE TDVIW STATUS B-48 TYPE TYPE ITMLST procedure input-output ( out [X ] EFN item descriptors. Reserved argument. procedure TASK GE TDVIW STATUS of : ( out COND_VALUE_ TYPE; EFN : in EF_NUMBER_TYPE := EF_NUMBER CHAN : in CHANNEL TYPE := CHANNEL_ZERO; ZERO; ITMLST : in ITEM LIST 3 _TYPE; IO0SB : in ADDRESS NULLARG := ADDRESS_ZERO; : in ADDRESS := ADDRESS_ZERO) ; VAX Ada Packages block. -— TASK_GETJPIW -— Get -— until the operation is job/process information and suspend the task —-— Parameters: complete. Number of the event flag to be set - efn - pidadr -- prcnam = Address of the process - itmlst = Address of a - iosb = Address of a quadword input-output = Address procedure TASKGETJPIW of the process list of out COND VALUE TYPE; EFN : in EF NUMBER TYPE PIDADR : in out PROCESS ID TYPE; PRCNAM : in PROCESS NAME TYPE; ITMLST : in ITEM LIST 3 TYPE; IOSB : out IOSTATUS BLOCK TYPE) ; : out EFN PIDADR : : in EF _NUMBER TYPE in out PROCESS_ ID TYPE; status block. EF_NUMBER_ ZERO; COND_VALUE TYPE; ITMLST : in ITEM LIST 3 TYPE; IOSB : out IO STATUS BLOCK_ TYPE) ; procedure TASKGETJPIW EF_NUMBER ZERO; ( STATUS : out COND _VALUE TYPE; EFN : in EF PIDADR : in sutPROCESS ID TYPE; PRCNAM : in ITMLST : in ITEMLIST 3 TYPE; IOSB : in ADDRESS EF NUMBER TYPE NUMBER ZERO; PROCESS NAME TYPE; procedure TASK GETJPIW STATUS : out COND VALUE TYPE; : in EF NUMBER TYPE PIDADR : in out PROCESS_ ID TYPE; ITMLST : in ITEM LIST 3 TYPE; IOSB : in ADDRESS TASK GETJPIW e ADDRESS ZERO) ; ( EFN EF NUMBER ZERO; ADDRESS ZERO) ; ( STATUS : EFN : in EF NUMBER TYPE = EF_NUMBER PIDADR : in ADDRESS = ADDRESS ZERO; PRCNAM : in PROCESS_NAME TYPE; ITMLST : in ITEM LIST 3 TYPE; I0SB : in ADDRESS procedure out string descriptor. ( STATUS procedure name ( : TASK GETJPIW identification. item descriptors. STATUS procedure on completion. COND VALUE TYPE; TASK GETJPIW ZERO; ADDRESS ZERO) ; ( STATUS : out COND_VALUE TYPE; EFN : in EF NUMBER TYPE EF_NUMBER ZERO; VAX Ada Packages B-49 PIDADR L - ITMLST IOSB procedure ADDRESS ITEM LIST 3 TYPE; in ADDRESS TASK GETJPIW ADDRESS_ZERO) ; ( STATUS out COND_VALUE_TYPE; in EF _NUMBER TYPE PIDADR in ADDRESS PRCNAM in PROCE NAME SS TYPE; ITMLST in ITEM LIST 3 TYPE; - TASK GETJPIW STATUS out EFN L] - PIDADR EF_NUMBER = ADDRESS ZERO; ZERO; out IO_STATUS BLOCK TYPE) ; - procedure L] COND ( VALUE TYPE; in EF_NUMBER TYPE = EF _NUMBER in ADDRESS = ADDRESS_ZERO; ITMLST in ITEMLIST 3 TYPE; I0SB out IO STATUS BLOCKTYPE); ZERO; TASK_GETLKIW -= Get -— operation - Parameters: lock information is and suspend the task until the complete. :: efn :: lkidadr = Address of the lock identification. :: itmlst = Address of a list of item descriptors. :: iosb = Address of a quadword input-output status block. - reserved = procedure = Number of the event flag to be set on completion. Reserved TASK GETLKIW parameter. ( STATUS out COND_VALUE TYPE; EFN in EF NUMBER TYPE LKIDADR in out IOSB RESERVED: procedure in ADDRESS TASK GETLKIW STATUS out EFN in LKIDADR : in out in ITEM LIST 3 TYPE; ADDRESS RESERVED: in ADDRESS procedure TASKGETLKIW EFN LKIDADR - L] L4 : out EF_NUMBER ZERO; LOCK ID TYPE; in Ld ZERO) ; COND_VALUE TYPE; EF NUMBER TYPE ITMLST STATUS ADDRESS ( I0SB ITMLST EF_NUMBER ZERO; LOCK ID TYPE; in ITEM LIST 3_TYPE; out IO STATUS BLOCK__TYPE; ITMLST B-50 ADDRESS_ZERO; EFN IOSB -— in in = ADDRESS ZERO; ADDRESS ZERO) ; ( CONDVALUE TYPE; in EF NUMBERTYPE = EF NUMBERZERO; in ADDRESS = ADDRESS in ITEM LIST 3 TYPE; VAX Ada Packages ZERO = ADDRESS ADDRESS : in IOSB RESERVED: in ADDRESS procedure TASK GETLKIW ( STATUS : out COND_VALUE_TYPE; EFN : in EF_NUMBER LKIDADR : in ADDRESS ITMLST : in ITEM LIST 3 TYPE; IOSB : out IO in ADDRESS RESERVED: -- ZERO; ADDRESS_ZERO); EF NUMBER ZERO; TYPE ADDRESS_ZERO; STATUS BLOCK_TYPE; ADDRESS ZERO) ; TASK_GETQUIW - Get queue information and suspend the task until the operation is complete. - Parameters: efn Number of the event flag to be set on completion. - func Code specifying the function to be performed. -— nullarg Reserved for —-— itmlst Address of a list of item descriptors. - io0sb Address of a quadword input-output status block. I - future use. procedure TASK GETQUIW ( : out COND VALUE_ TYPE; STATUS EEFN : : in in EF_NUMBER TYPE FUNC NULLARG : in ADDRESS ITMLST : in ITEM IOSB : out IO STATUS BLOCK_TYPE); = EF NUMBER ZERO; FUNCTION CODE TYPE; procedure TASK GETQUIW ( STATUS : out COND VALUE TYPE; EFN : in EF NUMBER TYPE FUNC : in FUNCTION CODE_TYPE; NULLARG ITMLST : in ADDRESS : in ITEM LIST 3 TYPE; IOSB : in ADDRESS procedure TASK GETQUIW = ADDRESS_ZERO; LIST 3 TYPE; = EF_NUMBER ZERO; ADDRESS_ZERO; ADDRESS_ZERO) ; ( STATUS : out COND_VALUE_TYPE; EFN : in EF_NUMBER TYPE FUNC : in FUNCTION CODE_TYPE; NULLARG : in ADDRESS ADDRESS ZERO; ITMLST : in ADDRESS = ADDRESS_ZERO; IOSB : out BLOCK TYPE) ; I0STATUS procedure TASK GETQUIW EF_NUMBER ZERO; ( STATUS : out COND_VALUE_TYPE; EFN : in EF FUNC : in CODE TYPE; FUNCTION NULLARG : in ADDRESS NUMBER TYPE = EF_NUMBER ZERO; = ADDRESS ZERO; VAX Ada Packages B-51 -- ITMLST : in ADDRESS := I0OSB : in ADDRESS := ADDRESS ZERO) ; TASK_GETSYIW -— Get system—-wide - the operation - Parameters: is information and suspend the task event flag to be set = Number of the - csidadr = Address of the cluster -— nodename = Address of the node -- itmlst Address of a - iosb Address of a TASK GETSYIW list name of COND VALUE TYPE; EFN : in EF NUMBER TYPE CSIDADR : in out in ITMLST : in ITEMLIS 3 TYPE; T I0SB : out IO_STAT BLOCK TYPE); US GETSYIW out COND VALUE TYPE; EFN : in EF_NUMBER TYPE CSIDADR : in out = EF_NUMBER ZERO; := EF_NUMBER ZERO; := EF_NUMBER ZERO; := ADDRESS_ ZERO) ; := EF NUMBER ZERO; := ADDRESS ZERO) ; PROCESS ID TYPE; ITMLST : in ITEMLIST 3 TYPE; I0SB : out IO_STATUS TASK GETSYIW BLOCK_TYPE) ; ( STATUS : out COND EFN : in EF_NUMBER TYPE CSIDADR : in out PROCES ID TYPE; S VALUE TYPE; PROCESS_NAME TYPE; ITMLST : in ITEM LIST 3 TYPE; IOSB : in ADDRESS procedure status ( : in item descriptors. PROCES NAME TYPE; S STATUS NODENAME: descriptor. PROCES ID TYPE; S NODENAME: procedure completion. ( out TASK string quadword input-output : procedure on system identification. LAl I efn STATUS until complete. -— procedure TASK GETSYIW ( STATUS : out COND_ VALUE TYPE; EFN : in EF_NUMBER_TYPE CSIDADR : in out PROCES ID TYPE; S ITMLST : in ITEM LIST 3 TYPE; I0SB : in ADDRESS procedure TASK GETSYIW B-52 ADDRESS ZERO; ( STATUS : EFN : in EF_NUMBER TYPE CSIDADR := EF_NUMBER_ZERO; : in ADDRESS := NODENAME: ADDRESS ZERO; in PROCESS_NAME TYPE; ITMLST : in ITEM LIST 3TYPE; I0SB : in ADDRESS = ADDRESS_ZERO) ; VAX Ada Packages *e out COND VALUE TYPE; block. procedure TASK GETSYIW out STAT UsS EFN CSID ADR ITML ST : L4 - . IOSB procedure in EF_NUMBER TYPE := EF_NUMBER ZERO; in ADDRESS := ADDRESS_ZERO; in ITEM LIST in ADDRESS TASK GETSYIW STAT US ( COND_VALUE TYPE; 3 TYPE; := ADDRESS_ZERO) ; ( out COND_VALUE_TYPE; in EF_NUMBER TYPE := EF_NUMBER : in ADDRESS := ADDRESS_ZERO; NODENAME : in PROCESS_NAME TYPE; ITML ST in ITEM IOSB out IO_STATUS BLOCK TYPE) ; - EFN CSIDADR CSID ADR [X ] EFN ( out COND_VALUE_TYPE; e TASK GETSYIW STAT UsS 3 TYPE; in EF_NUMBER [R ] procedure LIST in ADDRESS TYPE ITMLST in ITEM IOSB out IOSTATUS BLOCK TYPE); —— TASK QIOW - Queue - input-output - Parameters: := EF_NUMBER := ADDRESS_ZERO; ZERO; LIST 3 TYPE; input-output is ZERO; request and suspend the task until completed. efn Number of the event flag to be chan Number of the channel on which set on completion. input-output is directed. Function func code specifying the action to be performed. 10sb Address of receive final Optional quadword input-output completion status block to status. device— and function-specific parameters. olololelNele) FUNCTION out IO STATUS ZERO; in UNSIGNED LONGWORD : in UNSIGNED LONGWORD : in UNSIGNED LONGWORD in UNSIGNED LONGWORD := in UNSIGNED LONGWORD ;= in UNSIGNED LONGWORD := CODE_TYPE; g g TM ~ .« "TM e Wy nou BLOCK_TYPE; ' P6 [X ] P5 in [X ] P4 EF_NUMBER e P3 := [X 4 P2 TYPE TYPE; . Pl CHANNEL [X ] IOSB EF_NUMBER [X ] FUNC in in e CHAN COND_VALUE_TYPE; [} ) EFN ( out o0 STAT UsS LX ] procedure TASK QIOW VAX Ada Packages B-53 procedure TASK QIOW ( STATUS : out COND_VALUE_TYPE; EFN : in EF_NUMBER CHAN : in CHANNEL_TYPE; FUNC : in FUNCTION CODE TYPE; IOSB : in ADDRESS Pl : in UNSIGNED LONGWORD P2 : in UNSIGNED LONGWORD P3 : in UNSIGNED LONGWORD P4 : in UNSIGNED LONGWORD P5 : in UNSIGNED LONGWORD P6 : in UNSIGNED LONGWORD EF_NUMBER ZERO; TYPE .o [X] *e [X ] ADDRESS_ZERO; TASK SNDJBCW Send message to the job controller and suspend the task until the operation completes. Parameters: efn = Number func = nullarg = Reserved argument Code of the specifying the SGETxxx itmlst event = Address flag to be set on completion. function to be performed. for similarity with of item descriptors services. of a list for the operation. iosb = Address of a receive the procedure TASK SNDJBCW STATUS : : in EF : in FUNCTION NULLARG in ADDRESS ITMLST in ITEM out IO : TASK NUMBER TYPE ADDRESS_ZERO; BLOCK TYPE); ( STATUS out COND in EF_NUMBER FUNC in FUNCTI CODE TYPE; ON NULLARG : in ADDRESS IOSB out IOSTATUS BLOCK TYPE) ; : TASK SNDJBCW VALUE TYPE; TYPE ( out COND_VALUE_TYPE; EFN in EF_NUMBER TYPE FUNC in FUNCTION CODE_TYPE; in ADDRESS ITMLST : in ITEM IOSB : in ADDRESS VAX Ada Packages EF_NUMBER ZERO; ADDRESS_ZERO; STATUS NULLARG EF_NUMBER ZERO; LIST 3 TYPE; STATUS SNDJBCW status CODE_TYPE; EFN procedure B-54 COND_VALUE_TYPE; EFN I0SB input-output status. ( out FUNC procedure quadword final LIST EF_NUMBER ZERO; ADDRESS ZERO; 3 TYPE; ADDRESS ZERO) ; block to procedure TASK SNDJBCW ( STATUS out COND VALUETYPE; EFN in EF_NUMBERTYPE FUNC in FUNCTION EF NUMBER ZERO; CODE_TYPE; in ADDRESS ADDRESS ZERO; IOSB in ADDRESS ADDRESS ZERO) ; i NULLARG TASK_UPDSECW Update until section the file on disk operation is complete. and suspend the task Parameters: inadr Address the pages retadr = = = a 2-longword be array of a potentially 2-longword addresses of the queued in the Access mode on service is the updflg to Address the acmode of containing starting and ending addresses Update first indicator of the written. array first to receive and last input-output of behalf page request. which performed. for read/write global sections. 0 -> write all in the 1 -> write the efn Number file i0sb procedure STATUS of 1is Address TASKUPDSECW read/write pages section all pages modified by caller the event flag to be set when the of the quadword input-output status COND_VALUE TYPE; in ADDRESS_RANGE TYPE; out ADDRESS_RANGE_TYPE; ACMODE in ACCESS_MODE_TYPE ACCESS_MODE_ZERO; UPDFLG in BOOLEAN FALSE; EFN in EF_NUMBER TYPE IOSB out IOSTA BLOCK TUS TYPE) ; il INADR RETADR EF _NUMBER ZERO; ( out CONDVALUE TYPE; INADR in ADDRESS_RANGETYPE; RETADR out ADDRESS_RANGE_TYPE; ACMODE in ACCESS_MODE_TYPE UPDFLG in BOOLEAN EFN in EF_NUMBER IOSB in ADDRESS i STATUS block. ( out procedure TASKUPDSECW section updated. ACCESS MODE ZERO; FALSE; TYPE = EF_NUMBER ZERO; ADDRESS ZERO) ; VAX Ada Packages B-55 out COND_VALUE_TYPE; INADR LX ] in ADDRESS RANGETYPE; o0 in ADDRESS ADDRESS_ZERO; LX ( STATUS in ACCESS_MODE_TYPE ACCESS MODE_ZERO; [X J procedure TASKUPDSECW in BOOLEAN FALSE; in EF NUMBER TYPE EF NUMBER ZERO; in ADDRESS ADDRESS_ZERO) ; RETADR ACMODE UPDFLG EFN IOSB L4 L] procedure TASK UPDSECW INADR in ADDRESSRANGETYPE; RETADR in ADDRESS ADDRESS_ZERO; ACMODE o COND_VALUETYPE; in ACCESS MODE_TYPE ACCESS_MODE_ZERO; .. out in BOOLEAN FALSE; [X ] - in EF NUMBER out IO UPDFLG EFN IOSB -— TASK RMS CLOSE - Close the - Parameter: — ( STATUS EF_NUMBER ZERO; TYPE STATUS BLOCK_ TYPE) ; file. fab = Address of the file access block. procedure TASKRMS CLOSE is new RMS ASYNCH FABOPERATION -— TASK RMS CONNECT - Connect the - Parameters: - file. rab = Address of the record access block. procedure TASK RMS CONNECT is new RMS ASYNCH RAB OPERATION -— TASK_RMS_CREATE - Create the - Parameters: e fab (STARLET.CLOSE); (STARLET.CONNECT); file. Address of the file access block. procedure TASK RMS CREATE is new RMS ASYNCH FAB OPERATION B-56 VAX Ada Packages (STARLET.CREATE):; —-- TASK_RMS DELETE -- Delete - Parameters: - rab procedure the record. = Address of the TASK RMS DELETE record Disconnect - Parameters: -- rab procedure new the = Address the record - Parameters: fab procedure block. is (STARLET.DISCONNECT) ; file. = Address of the TASK RMS DISPLAY RMS access DISPLAY Display the new of stream. TASK RMS DISCONNECT TASK_RMS -— record RMS ASYNCH RAB OPERATION -- -- (STARLET.DELETE):; TASK _RMS DISCONNECT -- -- block. is new RMSASYNCH RAB OPERATION —— access ASYNCH file access block. is FABOPERATION (STARLET.DISPLAY):; TASK _RMS ENTER - Enter - Parameters: -- fab the file. = Address of the file access block. procedure TASK RMS ENTER is new -~ RMSASYNCH FAB OPERATION (STARLET.ENTER) ; TASK_RMS_ERASE - Erase - Parameters: —— the file. fab = Address of the file access block. procedure TASK RMS ERASE new is RMS ASYNCH FAB OPERATION (STARLET.ERASE); VAX Ada Packages B-57 -— RMS EXTEND TASK —— Extend the —— Parameters: -— file. fab = Address of the file access block. RMS EXTEND is procedure TASK new RMS ASYNCH FAB OPERATION RMS FIND TASK -— -— Find a record in the - Parameters: -— file. rab = Address of the record access block. RMS FIND is procedure TASK new RMSASYNCH RAB OPERATION -- TASK_RMS_ FLUSH -— Flush the - Parameters: - (STARLET.FIND):; record. rab = Address of the record access block. procedure TASK RMS FLUSH is new RMS ASYNCH RAB OPERATION -- TASK_RMS_ FREE -— Free the - Parameters: -— —— rab = Address of the record access block. (STARLET.FREE) ; TASK RMS GET - Get a record from the file. - ‘Parameters: -— (STARLET.FLUSH); record. RMS FREE is procedure TASK new RMS ASYNCH RAB OPERATION rab = Address of the record access block. procedure TASK RMS GET is new RMS ASYNCH RAB OPERATION B-58 (STARLET.EXTEND):; VAX Ada Packages (STARLET.GET):; -- TASK RMS NXTVOL -— Go to - Parameters: —= the rab next volume. = Address of the record access block. procedure TASK RMS NXTVOL is new RMS ASYNCH RAB OPERATION —— TASK_RMS OPEN —— Open the - Parameters: - (STARLET.NXTVOL) ; file. fab = Address of the file access block. procedure TASK RMS OPEN is new RMS ASYNCH FAB OPERATION -- TASK RMS PARSE -- Parse - Parameters: -- the file name. fab = Address procedure new the TASK RMS PARSE TASK RMS -— Insert - Parameters: -— of file access rab procedure a record in = Address of TASK RMS PUT the file. the record Read a block -~ Parameters: rab procedure new access block. is (STARLET.PUT); READ - - (STARLET.PARSE); PUT new RMS ASYNCH RAB OPERATION TASK_RMS block. is RMS ASYNCH FAB OPERATION -— -— (STARLET.OPEN) ; from the = Address of TASK RMS READ the file. record access block. is RMS ASYNCH RAB OPERATION (STARLET.READ); VAX Ada Packages B-59 —— TASK RMS RELEASE —= Release - Parameters: - the record. rab = Address procedure of the TASK RMS RELEASE record access is new RMS ASYNCH RAB OPERATION -- TASK_RMS_REMOVE -= Remove the - Parameters: —— new —— of the TASK RMS REMOVE file access block. is RMS ASYNCH FAB OPERATION TASK_RMS (STARLET.RELEASE); file. fab = Address procedure block. (STARLET.REMOVE) ; RENAME —_— Rename the - Parameters: :: :: oldfab err = Address of the old file access block. = Address of a user error completion routine. :: suc = Address of a user success completion routine. :: newfab = Address of the new file access block. procedure TASK RMS RENAME new RMS TASK RMS REWIND -- Rewind the —— Parameters: new of TASK RMS REWIND the record access block. is RMS ASYNCH RAB OPERATION VAX Ada Packages (STARLET.RENAME) ; file. rab = Address procedure is ASYNCH 2FABOPERATION —= -- B-60 file. (STARLET.REWIND) ; -- TASK_RMS_ SEARCH -- Search - Parameters: - for the file name. fab = Address of the file access block. procedure TASK RMS SEARCH is new RMS ASYNCH FAB OPERATION ——- TASK RMS SPACE - Space to - Parameters: -- skip in the rab = Address procedure new -- (STARLET.SEARCH) ; of the TASK RMS SPACE record access Truncate the - Parameters: record. = Address of the procedure TASK RMS TRUNCATE record -- TASK_RMS - Update - Parameters: access block. is new RMS ASYNCH RAB OPERATION - (STARLET.SPACE) ; TRUNCATE —-= rab block. is RMS ASYNCH RAB OPERATION TASK_RMS -— file. (STARLET.TRUNCATE); UPDATE the record. rab = Address of the record access block. procedure TASK RMS UPDATE is new RMS ASYNCH RAB OPERATION (STARLET.UPDATE) ; VAX Ada Packages B-61 -- TASK_RMS - Wait -- renaming of - Parameters: - for asynchronous TASK record service completion. This is a STARLET.WAIT. Address rab procedure -- WAIT of the RMS WAIT record access block. ( STATUS out COND VALUE TYPE; RAB in out RAB TYPE) renames STARLET.WAIT; TASK RMS WRITE - Write - Parameters: —_— a block to the rab Address file. of the record access block. procedure TASK RMS WRITE is new RMS ASYNCH RAB OPERATION —— Additional declarations ( EFN in EF _NUMBER TYPE MSGBUF in STRING; SENDTO in STRING; SNDTYP in UNSIGNED LONGWORD IOSB out IOSTATUS BLOCK EF_NUMBER ZERO; CARCON in UNSIGNED LONGWORD FLAGS in UNSIGNED REQID in UNSIGNED LONGWORD in UNSIGNED TIMOUT procedure TASK BRKTHRUW 0; TYPE; g LONGWORD “e COND VALUE TYPE; oW N out LONGWORD N STATUS OO procedure TASK BRKTHRUW ( STATUS out COND VALUE TYPE; EE'N in EF NUMBER TYPE EF_NUMBER ZERO; IGNORED in ADDRESS ADDRESS ZERO; STRING; in UNSIGNED IOSB out IOSTATUS BLOCK TYPE; LONGWORD UNSIGNED LONGWORD in UNSIGNED REQID in UNSIGNED LONGWORD TIMOUT in UNSIGNED LONGWORD STATUS EFN MSGBUF » * - . a— OO AT LONGWORD W in e’ CARCON FLAGS 0; s in SNDTYP OoOWw N SENDTO procedure TASK BRKTHRUW B-62 for compatibility with earlier versions TASKING SERVICES. " of ( out CONDVALUE_TYPE; in EF_NUMBER TYPE in STRING; VAX Ada Packages il —— (STARLET.WRITE):; EF NUMBER ZERO; IGNORED SNDTYP in in ADDRESS UNSIGNED LONGWORD = ADDRESS ZERO; := 0; IOSB out IO STATUS BLOCK_TYPE; CARCON in UNSIGNED LONGWORD := 32; FLAGS in UNSIGNED LONGWORD := REQID TIMOUT in in UNSIGNED LONGWORD UNSIGNED LONGWORD procedure TASK BRKTHRUW 0; := O0; := 0); ( STATUS out CONDVALUE TYPE; EFN in EF NUMBER TYPE := EF NUMBER ZERO; SNDTYP in UNSIGNED LONGWORD := 0; IOSB out IO_STATUS“BLOCK_IYPE; CARCON FLAGS in in in in UNSIGNED LONGWORD UNSIGNED LONGWORD REQID TIMOUT procedure STATUS EEF'N UNSIGNED LONGWORD UNSIGNED LONGWORD TASKBRKTHRUW ( out CONDVALUE_TYPE; in EF NUMBER TYPE MSGBUF in SENDTO in STRING; SNDTYP IOSB CARCON FLAGS REQID TIMOUT in in in in in in UNSIGNED_ LONGWORD ADDRESS UNSIGNED LONGWORD UNSIGNED LONGWORD UNSIGNED LONGWORD UNSIGNED LONGWORD procedure := 32; := O0; := O0; 0); = EF NUMBER ZERO; STRING, TASKBRKTHRUW := = := := := := 0; ADDRESS ZERO; 32; O; O0; 0); ( STATUS out COND _VALUE TYPE; EFN IGNORED in in EF NUMBER TYPE ADDRESS SENDTO in STRING; SNDTYP in UNSIGNED LONGWORD := 0; TOSB CARCON FLAGS REQID in in in in in ADDRESS UNSIGNED UNSIGNED UNSIGNED UNSIGNED = := := := := ADDRESS ZERO; 32; 0; 0; 0); TIMOUT procedure TASKBRKTHRUW LONGWORD LONGWORD LONGWORD LONGWORD = EF NUMBER ZERO; := ADDRESS ZERO; ( STATUS out COND_VALUETYPE; in EF NUMBER TYPE MSGBUF in STRING; IGNORED SNDTYP IOSB in in in ADDRESS UNSIGNED LONGWORD ADDRESS := ADDRESS ZERO; := 0; := ADDRESS ZERO; EFN CARCON : := EF_NUMBER ZERO; in UNSIGNED LONGWORD := 32; FLAGS in UNSIGNED LONGWORD := 0; REQID TIMOUT in in UNSIGNED LONGWORD UNSIGNED LONGWORD := 0; := 0); procedure TASKBRKTHRUW EFN SNDTYP ( out COND _VALUETYPE; STATUS : in EF _NUMBER TYPE := EF NUMBER ZERO; in UNSIGNED LONGWORD := 0; VAX Ada Packages B-63 IOSB in ADDRESS CARCON in UNSIGNED FLAGS in UNSIGNED LONGWORD REQID in UNSIGNED LONGWORD in UNSIGNED LONGWORD TASK ENQW e W, ’ S~ Il I o OO [X] STATUS out COND_VALUE TYPE; in EF_NUMBER TYPE LKMODE in UNSIGNED LONGWORD; LKSB in out LOCK_STATUS_ BLOCK_TYPE; FLAGS in UNSIGNED RESNAM in STRING; : LONGWORD EF_NUMBER i= ZERO; 0; in LOCK_ID TYPE LOCK_ID ZERO; BLKAST in AST NO ACMODE in ACCESS MODE TYPE RESERVED: procedure in TASK ENQW HANDLER i= ADDRESS AST HANDLER; ACCESS_MODE ZERO; ADDRESS_ZERO) ; ( STATUS out COND_VALUE TYPE; EFN in EF LKMODE in UNSIGNED LONGWQRD; NUMBER TYPE ZERO; LKSB in out LOCK_STATUS BLOCK_TYPE; in UNSIGNED PARID in LOCK_ID TYPE LOCK_ID_ZERO; BLKAST in AST NO_AST HANDLER; ACMODE in ACCESS_MODE_TYPE il EF_NUMBER FLAGS ACCESS MODE_ZERO; RESERVED: in ADDRESS = ADDRESS ZERO) ; implementation-defined end TASKING SERVICES; VAX Ada Packages 0; LONGWORD HANDLER — private B-64 32; ( EFN PARID —- t= i TIMOUT procedure ADDRESS_ZERO; LONGWORD Index A ADA$ EXCCOPLOS condition value Abort statement, for marking copied and modified signal arguments 8-24 asynchronous implementation of, 8-25 synchronous implementation of, 8-25 ADDRESS attribute, 6-23 effect on storage allocation, 2-42 using to pass Ada subprograms as parameters, allocation of collection for, 2-22 deallocation of storage for, 2-22, 2—43 effect of length representation clauses on 2-22 declaration of, 2-25 passing as parameters by descriptor, 5-31 passing parameters of, 5-7, 5-20 representation of, 2-22 returning as function results, 5-25 storage size for values of, 2-22 ACCESS_BIT_NAMES_TYPE, B-28 ACCESS_MODE_TYPE, B-28 ACOS, ACOSD, B-26 2-24, 2-35 example of use of, 2-35 $ADDRESS program section, ADDRESS type, 5-39 2-23, 10-1 Address types packing, 2-25 passing parameters of, representation of, 520 2-23 returning as function results, 5-25 Address values working with, 10-1 B-28 ADDRESS_ZERO Ada 1-1 ADASINPUT logical name, 3-10, 3—-87 ADASOUTPUT logical name, 3-10, 3—-87 ADAS$PREDEFINED extracting predefined package specifications from, 6-2, B-1 ADA$_EXCCOP condition value for marking copied signal arguments in an exception, 6-24 Address clauses, ADDRESS_RANGE_TYPE, B-26 overview of VAX, 10-1 10-1 6-23 Access types packing, 4-1, 44, 4-6, causing locally volatile parameter or variable, Access modes VMS equivalents for VAX Ada, 4-6 4-7, 414 Access methods Ada equivalents for VMS, in an exception, ADA$ EXCEPTION condition value, 4-6 as default expression for optional parameter, ADDRESS_ZERO constant, Alignment clauses, 6-12 6-24 2-33 restrictions on possible values for, 2-34 Area control block using to return array type function results, 5-27 using to return record type function results, 5-27 Argument list, 5-12 creation of, 5-9 passed between languages and system service routines, 6-11 Index-1 Argument list (cont'd.) state of optional parameters in calls to system routines, 6-11, 6—12 Argument pointer (AP), ARG_LIST_TYPE, ATAN2D, ATAND, B-26 B-26 AUX_IO_EXCEPTIONS package, 5-14 exceptions predefined in, B-28 3-86, B-2 4-5 Arrays assigning values to, 10-10 definition of packable components of, example of calculating size of, examples of packing, 2-24 2-18 sharing common blocks with, 2-26, 2-27 properties of multidimensional, 2—-18 Array types default alignment of components in, effects of packing components of, packable, packing, 2-18 representation of, exporting and importing objects from, as masters of tasks, 5-31 stack frames for, 2-18 packing, 2-24 5-25 representation of, B-26 2-2, 2-3 control of terminal text file, B-2 flushing of text file, ASSERT package instantiation specification of, specification of, B-10 ASSERT_GENERIC package, specification of, avoiding during task call to SYS$SETAST, avoiding to avoid AST deadlock, 844 BYTE_SIGNED_TYPE, B-28 B-2 B-2 BYTE_UNSIGNED_TYPE, B-10 ASTLM (AST Queue Limit) quota effect of delay statements on, ASTs (Asynchronous System Traps), 8-37, 8—40 8-43 delivered to completed or abnormal tasks, effect on input-output operations, effect on size of task control block, examples of handling, 845 execution of in tasks, 8-11 handling from tasks, 842 rules for Ada routines, 8-44 storage allocated for, 8-43 AST_ENTRY attribute, 8-40 AST_ENTRY pragma, 8-40 B-28 3-88 8-8 8-43 C sharing variables with, 5-43 CALENDAR package, B-2 CALLABLE attribute value of during task AST handling, 8-43 Callable utilities writing interfaces to/from VAX Ada, 6-19 Call-back routines and generic code sharing, 9-16 example of writing and calling from VAX Ada, 6-36 Call frame, effect on size of task control block, AST_PACKET_REQUEST_TYPE, 8-38 C 8-24 8-31 constraints on handling, 3-81 3-81 Busy waiting B-10 ASSERT_EXCEPTIONS package, 8-9 B-39 AST_PROCEDURE_TYPE, B-28 Asynchronous input-output, 3-10, 3-67, 3-88 Index-2 4-2 4-2 Buffers ASSERT package, B-26 8-2 BOOLEAN type 2-18 B-26 B-26 5-40 5-43 exception handlers for, 5-7, 5-18 returning as function results, ATAN, 5-18 5-43 Blocks representation of multidimensional, ATAN2, Bit string, sharing variables with, 5-19 AST reentrancy, 5-19 BLISS 2-25 passing parameters of, ASIND, Bit array, 2-26 passing as parameters by descriptor, ASIN, BASIC 5-14 CALLG instruction, 5-9, 5-15 CALLS instruction, 5-9, 515 Call stack, 5-8 at run time, 5-9 Carriage control FORTRAN control characters for, options for Ada text files, 3-82 3-84 Conditions (VAX) Catch-all exception handlers and fault handlers, continuing the signals for from an Ada program, 4-25 4-18 4-2 behavior of, CDD (Common Data Dictionary) examples of using with VAX Ada, using with VAX Ada, 7-1 effects of handling from an Ada program, 4-21 equivalent Ada predefined exceptions for, 4-7 examples of calling from an Ada program, 4-16 importing into an Ada program, 4-12 matching Ada exceptions with, 4-7 7-5 VAX Ada translator utility for, 7-2 CDDL (Common Data Dictionary Language) VAX Ada equivalent data types for, 7-3 CDD_TYPES package, 7-2, B-3 specification of, B-14 CHANNEL_TYPE, B-28 noncontinuable execution of, 4-21 not caught by Ada exception handlers, signaling from an Ada program, 4-15 unhandled, See also Exceptions, Exception handling 4-13 CONDITION_HANDLING package, 6-2, B-3 example of using MATCH_COND function, 2-2, 2-3, 2-25 giving to Ada exceptions, B-28 CHAR_STRING_TYPE, Checks method for eliminating run-time, 4-11 6-27 provision of interface to LIBEMATCH_COND, 6-26 9-21 suppressing run-time, CHF (VAX Condition Handling Facility) summary of exception-handling implementation, 4-1 COND_ID, See also System-routine packages 3-11 CMS (DEC/Code Management System) example of calling a routine from Ada, 6-25 B-19 optional parameter to the pragma IMPORT_ EXCEPTION, 4-12 CONSTRAINT_ERROR exception checks that raise, 2-22 raised with varying strings, VAX condition equivalent for, Condition handling See Exception handling 4-9 4-8 CONTEXT_TYPE, B-28 CONTINUE command (DCL) entering after CTRL/Y in tasking program, 8-25 Control blocks 6—7 example of using VMS RMS, 6-34 structure of in the system-routine packages, See Conditions (VAX) 4-3 5-29, 5-32, 10-9 underlying run-time checks for, packages, Condition codes Condition handlers calling fault handlers from, 9-21 raised when passing parameters, declarations of types for in the system-routine See CDD general VAX Ada, COND_VALUE_TYPE, B-19, B-28 $CONSTANT program section, 5-38 Constrainedness bit, 5-20 CONSTRAINT_ERROR VAX condition equivalent for, 4-8 10-8 5-38 Collections allocation of for access types, 2-22 deallocation of for access types, 2-22, 2-43 default allocation for, 242 Common Data Dictionary 6-26 B-19 raised when using UNSIGNED_LONGWORD type, See CMS effect of length representation clauses on, efficient allocation of, 242 4-15 5-33, 5-34 Code Management System (CMS) $CODE program section, B-19 using to signal VAX conditions from an Ada using to test status values, 6-2, B-3 CLOSE procedure FORM parameter, CODE, specification of, program, 4-3 used to implement exception handling, CLI package, 4-2 Condition values CHARACTER type representation of, 4-21 4-25 CONTROL_C_INTERCEPTION package, 6—7 8-26, B-3 specification of, B-26 Copy-in/copy-back semantics, 5-7 for passing access type parameters, 5-20 for passing address type parameters, 5-20 for passing array type parameters, 5-7 Index—-3 Copy-in/copy-back semantics (cont'd.) for passing record type parameters, 5-7, 5-20 for passing scalar, access, and address type parameters, avoiding to avoid AST deadlock, 5-7, 5-21 using with abnormal tasks, B-26 COSD, B-26 COSH, B-26 techniques for reducing, CREATE procedure, 3-6 descriptor data types used with, for imported function results, , 3-3, 3-6 MODE parameter, 3-36 NAME parameter, 3-6 - for imported subprogram parameters, valid class names for, parameters, 5-19 returning function results with, 8-46 subprograms, DESCRIPTOR_TYPE, 8-25 B-19 5-37 B-28 DEVICE_NAME_TYPE, Direct files, D B-28 3-4 default attributes for, 2-5, 2-6, 2-7, 2-8, 2-9, 2-11 representation of, DIRECT_IO package, 2-5 3-48 Ada features for optimizing, 2-24 representing in mixed-language programs, sharing with non-Ada routines, $DATA program section, 3-1, 3-4, 341, B-3 default file attributes provided by, example of using, 5-16 5-38 5-38 6-4 B-28 Deadiock Discriminants See Record discriminants DSC$K_CLASS_A, 5-19, 5-27, 5-37 DSC$K_CLASS_UBA, 5-19, 5-27 DSC$K_CLASS_UBS, 5-37 DSC$K_CLASS_UBSB, See Task deadlock of storage associated with access types, | 2-22, 2-43 DTK package, entering after CTRL/Y in tasking program, See CMS DEC Multinational Character Set See Multinational Character Set 5-19, 5-27, 5-37 6-2, B4 See also System-routine packages Dynamic memory use of to allocate storage, DEBUG command (DCL) DEC/CMS 3-48 3—49 DSC$K_CLASS_S, 5-37 DSC$K_CLASS_SB, 5-19, 5-27, 5-37 Data structures Deallocation 348 3-1, 34, 3-40, B-3 DIRECT_MIXED_IO package, 2-5 Data DATE_TIME_TYPE, 3—47 specifying record size for, DIRECT_IO default file atiributes provided by, D_FLOAT type storage size of, 5-27 using to pass parameters to exported Ada CTRLY D_floating representation, 5-32 5-32 default used by VAX Ada for passing array type CTRL/C interrupting tasks with, 5-30 Descriptors 3-34 interception with AST entry, 5-34 5-36 type requirements for descriptor classes for, Creation-time attributes of input-output files, 5-19 DESCRIPTOR mechanism option 9-19 FORM parameter, 5-31 5-13 passing array type parameters by, 9-20 3-2, 3-34, 3-35 FILE parameter, Index—4 8-25 explanation of for VAX Ada, Descriptor mechanism, decreasing for a VAX Ada program, VMS, 8-37 8-44 Descriptor classes CPU time CUST_DEF, 6-11 8-24 avoiding during task call to SYS$SETAST, 5-18 for passing task type parameters, COS, in system routines vs. Ada, Delay statement, 5-7 for passing scalar parameters, Default parameters 8-25 2-42 E Edit/FDL Utility using to optimize external files, EF_CLUSTER_NAME_TYPE, 3-18 B-28 EF_NUMBER_TYPE, Exceptions (cont'd.) B-28 example of handling in mixed-language ELABORATE pragma using to improve run-time performance, 9-22 Elaboration order of for programs involving tasks, 8-—1 Elapsed time decreasing in a VAX Ada program, techniques for reducing, 3-69 input-output, 9-19 declaring signed internal codes for, example of representation of, 2-29 2-4 examples of using representation clauses with, 2-29 internal codes for literals of, passing parameters of, representation of, storage allocated for objects of, 2-29 2-3 3-10 3-8 4-21 4-2 4-9, 411 underlying run-time checks for, 4-9 unhandled in tasking programs, 4-2, 4-27 4-1 3-53 8-26 Exit handlers 4-1 4-7 4-8 relationship to VAX condition handling, 4-1 Exceptions associating VAX conditions with, 4-13 avoiding propagation of unhandled, 8-37 avoiding propagation of unhandled to avoid AST 8-44 copying of signal arguments for, 3-81 restrictions on writing in Ada, 8-39 EXIT_HANDLER_BLOCK_TYPE, EXP, B-26 B-28 EXPAND_AST_PACKET_POOL, B-39 Exporting subprograms, 44, 4-5, 46, 4-14 effect on text file buffers, 4-7 4-1 entering after CTRL/Y in tasking program, 4-2, 4-28 deadlock, signal argument vectors for, suppressing checks that raise, EXIT command (DCL) 4-2 making the best use of, Ada format, 4--3 4-3, 44 raised when reading Ada relative files, 4-2 in non-Ada code, re-raising, 4-4 4-12 VMS format, 44, 4-5, 4-6, 4-14 EXISTENCE_ERROR 4-2 VMS default, 4-4, 4-27, 4-28 4-2, 4-3 VAX condition values for user-defined, 4-2 4-3 Exception handling, 44 4-4, 4-5, 4-7 VAX condition values for predefined, 4-2 VAX Ada run-time, noncontinuable execution of, predefined, 4-2 4-5 user-defined, 44, 4-5, 46 VAX condition equivalents for predefined, Exception handlers general VAX Ada run-time, naming and encoding, relationship to CHF, 5-25 Equivalence strings pairing with logical names, 4-7 mechanism argument vectors for, raising imported, specifying internal codes for literals of, for process-permanent files, 4-14 raising at point of task rendezvous, 5-18 returning as function results, 4-7 matching VAX conditions with, raising, 2-3 and VAX conditions, 4-27 4-7 matching signal arguments of, propagation of, 2-3 2-25 unwinding to, 3-86 interaction with tasking, matching of user-defined, 2-29 See also Representation clauses Enumeration types search for, information lost during signal argument copying, matching of imported, See Task entries Enumeration clauses, 4-11 4-12 4-6 raised during terminal input-output, invoking, 4-14 handling in mixed-language programs, importing from other languages, Entries catch-all, 4-22 9-27 END_ERROR packing, environment, exporting to other languages as VAX conditions, 4-4, 4-6, 4-28 Export pragmas, 54 5-4, 5-40 EXPORT_EXCEPTION pragma, 4-11, 4-14 and NON_ADA_ERROR exception, examples of using, syntax of, 4-15 4-15 4-14 using to associate an Ada exception with a VAX condition, 4-14 Index-5 EXPORT_EXCEPTION pragma (cont'd.) FDL (File Definition Language) (cont'd.) using to give user-defined exceptions VMS format, 46 rules for using, 3-17 secondary attributes of, EXPORT_FUNCTION pragma syntax for, 54 using to tune external files, use of in routine interfaces, 6-22 File objects, EXPORT_OBJECT pragma syntax of, 3-2 creating or opening, EXPORT_PROCEDURE pragma FILE parameter, 54 3-3 3-2 3-6 Files use of in routine interfaces, 6-22 Ada direct, using in a run-time library routine call, 6-36 EXPORT_VALUED_PROCEDURE pragma default passing mechanism for first parameter of, 6—23 parameter modes for, 6-22 34, 3—11 Ada indexed, 3-5, 3—11 Ada relative, 3—4, 3—11 Ada sequential, Ada text, 623 54 3—4 3-5 buffering text, required mode of first parameter of, syntax for, 3-80 carriage-control attributes for Ada text, carriage control of text, treatment of first parameter of, 5-15 use of to write call-back routines, 3-34 consistency checking of attributes of external, 3-35 See also Files creation-time attributes of external, creation- and run-time attributes of, default attributes of, 3-34 3-35 3-6 relationship to file objects, specifying attributes of, default attributes for Ada direct, 3-34 3-48 default attributes for Ada indexed, 3-55 default attributes for Ada relative, 3-51 naming, 3-3 default attributes for Ada sequential, 3—11 F default attributes for Ada text, 3-65 default attributes for external, 3-35 345 default characteristics of input-output, default logical names for VMS, F_floating representation, 2-5, 26, 2-7, 2-8, 2-9, 2-10 F_FLOAT type default specifications for, defining keys in indexed, storage size of, 2-5 definition of external, 2-5 external, FAB (file access block) 3-3 3-9 3-8 3-5 definition of Ada input-output, representation of, 3-3 3-3 3-2 FDL attributes for tuning external, record type declared for in the package STARLET, 6-7 3-33 FORTRAN carriage-control characters for Ada text, 3-84 B-28 input-output, 3-2 FAC_NO, B-19 locking records in, 3-39 FAC_SP, B-19 logical names for, 3-8 FAO signal arguments mixed-type, matching of in non-Ada code, 4-14 Fault handlers, 4-7 4-25 naming external, 3-6 optimizing external, effect of Ada exception handling on, method for setting up in VAX Ada, 4-21 4-25 restrictions on using in an Ada program, FDL (File Definition Language), 3-11 most likely attributes for Ada files, primary attributes of, 3—41 most likely FDL attributes for external, zeroed during signal argument copying, Index—6 3-82 3-81, 3-82 changing creation-time attributes of external, 6-22 External files FAB_TYPE, 3-11 3-33 association with VMS RMS files, 5-40 syntax for, 3-12 using to give values to FORM parameters, 3-12 3-19 process-permanent, 4-25 3-18 optimizing performance of, reading indexed, 3-37 3-10, 3-87 3-57 run-time attributes of external, sharing input-output, 3-34 3-36 specifying attributes for external, 3-11 3—-19 Floating-point types (cont'd.) Files (cont'd.) VAX representations and storage sizes for, specifying FDL attributes for external, 3-17 specifying key information for indexed, 3-55 specifying record size for Ada direct, 3-48 specifying record size for Ada relative, 3-51 representation of, 2-5 storage size of, 2-5 FLOAT_MATH_LIB package, A-1 example of using, 6-18 FLOAT_TEXT_IO package, 3-85, A-1 specifying VMS RMS atiributes of, 3-12 terminators in Ada text, 3-77 using FORM parameter to control attributes of external, 3-11 using FORM parameter to control sharing of, writing VMS specifications for, 3—-36 3-7 in Ada text file, 3-77 FILE_PROTECTION_FLAGS_TYPE, EXCEPTION, B-28 FORM parameter, using to obtain unsigned numbers, rules for specifying, 3-12 specifying record locking with, 10-8 3-39 using to name an external file, 3-6 using to specify carriage-control attributes, Fixed-point type 2-16 Fixed-point types 3-81 FORTRAN 2-16 exporting an Ada function to, 5-38 handling exceptions propagated from, packing, 2-25 passing parameters of, 5-18 representation of, -2-16 importing a routine from, returning as function results, 5-25 truncation of operations on, 2-16 FLOAT as parent type for nonpredefined floating-point type, 2-6 nonreentrancy of run-time library, sharing common blocks with, Frame pointer (FP), 4-22 5-30 8-32 543, 544 5-14 Frames call, 5-9, 5-14 definition of Ada versus VMS, 4-3 distinction between Ada and stack, 4-2 exception handlers for, 4-2 Floating-point type 2-5 Floating-point types accuracy of, 2-7 Full reentrancy, D_floating representation, 2-11 2-10 G_floating representation, 2-13 how compiler chooses representation of, H_floating representation, 2-14 model numbers defined for, 2-7 2-7 2-25 passing parameters of, area control block for returning array type, 5-27 controlling the mechanisms for imported, 5-35 default VAX Ada mechanisms for returning, 5-24 linkage conventions for VAX Ada, 5-18 5-36 passing imported by reference, 5-36 5-36 registers used for, 5-13 VAX Calling Standard conventions for returning, 5-25 safe numbers defined for, 2-9 unchecked conversions to or from, 5-16 passing imported by descriptor, passing imported by value, 2-5, 2—-6 returning as function results, 8-31 Function results F_floating representation, representation of, 4-12 3-11, 3-35, 3-36 See also CREATE procedure, OPEN procedure association with FDL string or file, 3-11 FIRST attribute packing, B-26 See also Exceptions, VMS format optional parameter to the pragma IMPORT_ FILE_PROTECTION_REC_TYPE, B-28 FILE_PROTECTION_TYPE, B-28 definition of, B-26 FLOUNDMAT, See also Exceptions, Ada format VMS syntax for, File terminator accuracy of, FLOOVEMAT, FORM 3-7 File specifications definition of, 2-5 FLOAT type 5-13 2-11, 2-12, 2-14, 2-16 See also UNCHECKED_CONVERSION Functions See Subprograms FUNCTION_CODE_TYPE, B-28 procedure Index—7 G IMPORT_EXCEPTION pragma, G_floating representation, 2-5, 2—6, 2-8, 2-9, 2-10, 2-13 representation of, storage size of, 4-6 IMPORT_FUNCTION pragma 9-15 effect on your program, syntax for, 9-17 performance of code generated for, 9-17 Generic instantiations creating library packages of, 9-17 syntax of, 5-40 syntax for, using to improve program efficiency, 9-17 Generics 9-13 9-11 sharing code for, 5-2 use of in routine interfaces, 9-14 parameter modes for, 9-5 GET procedure GET_LINE procedure, 3-69 Indexed files, 3-87 646 3-55 specifying key information for, INDEXED_IO package, 3-55 3-1, 3-5, 340, B4 default file attributes provided by, See Symbol definitions example of using, 3-1, 3-5, 3-41, B—4 default file attributes provided by, H_floating representation, 2-5, 2-6, 2-7, 2-8, 2-9, 2-14 example of using, INHIB_MSG, representation of, storage size of, B-19 definition of, 2-5 94 Inline expansion 2-5 of generic bodies, of subprograms, INLINE pragma, IDENTIFIER_TYPE, Importing exceptions, examples of, explicit use of, 5-2 5-2, 540 using in routine interfaces, 5-28 using to write system- and utility-routine interfaces, Index-8 9-3 9-6 9-7 9-4 implicit use of, See also individual pragmas by name 6-19 using the MECHANISM option for, 9-12 9-3 and dependences on generic bodies, B-28 4-12 Importing subprograms, 6-2 3-56 3-61 Inlinable H_FLOAT type Import pragmas, 3-55 3-58 INDEXED_MIXED_|O package, H 6—43 6-25 3-5 default attributes for, Global literals 5-15 6-22 using to call SYS$TRNLNM system service, IMPORT_VALUE function, example of using, 3—41 6-23 5-2 use of in routine interfaces, using the pragma INLINE with instantiations of, default files for TEXT 10, 6-22 required mode of first parameter of, treatment of first parameter of, 9-12 Generic subprograms GET_ITEM procedure, 6-22 IMPORT_VALUED_PROCEDURE pragma syntax for, VAX Ada implementation of, 6-22 IMPORT_OBJECT pragma IMPORT_PROCEDURE pragma 9-14 inline expansion of bodies of, 5-2 use of in routine interfaces, 9-16 making use of, 4-13 using to give user-defined exceptions VMS format, 2—43 sharing code for, 4-12 condition, 2-5 Generic code sharing maximizing, 4-15 4-12 using to associate an Ada exception with a VAX 2-5 Garbage collection, benefits of, examples of using, syntax of, G_FLOAT type 4-11, 4-12 and NON_ADA_ERROR exception, 9-6 using to improve run-time performance, INLINE_GENERIC pragma, 9-11, 9-12 9-22 comparison with the pragma SHARE_GENERIC, 9-12 effect on compilation unit dependences, examples of, 9-13 9-13 INLINE_GENERIC pragma (cont'd.) Interlocked instructions, 2-34 Interlocked queue instructions example of using, 10-3 operations in the package SYSTEM for, 9-13 syntax of, Input 3-80 nonterminal, terminal, 3-80 Input-output, 3-1 achieving asynchronous, 3-10, 3-67, 3—-88 and exception handling, 3—-86 3-87 and task wait states, avoiding during task call to SYS$SETAST, avoiding to prevent AST deadlock, binary, 3-40 buffering text, 3-80 carriage control in text, direct, 8-44 3-81 example of using tasks with, 8-2 flushing of buffers at program exit, 8-40 9-28 3-55 interaction of with tasking, relative, 3-51 3-86 3—44 364 Instantiations See Generic instantiations 2-5 2-28 2-25 passing parameters of, 5-18 range of values for predefined, representation of, 2-5 2—-4 required symmetry of, 10-6 returning as function results, 5-25 INTEGER_TEXT_IO package, 3-85, A-1. INTERFACE pragma syntax for, 5-2 using in routine interfaces, 6-2, B4 2-28 LIB$FILE_SCAN_END routine example of calling from Ada, 6-36 LIBSMATCH_COND routine interface for in the package CONDITION_ HANDLING, 6-26 provided in CONDITION_HANDLING package, 6-2 LIB$SIGNAL routine 6-19, 6-22 Interfaces (routine) access methods for parameters in, 6-23 default and optional parameters in, 6-24 determining kind of subprogram for, 6—21 determining parameter types for, 6-3 parameter passing mechanisms for, 6—24 writing in VAX Ada, L LBR package, See also Representation clauses effect of on first named subtypes, 2-3 efficient use of, 2-42 LIB$FILE_SCAN routine example of calling from Ada, 6-36 Integer types packing, 5-15 Length representation clauses, range of values for, 2-5 representation of, 2—4 declaring unsigned, B-28 ITEM_REC_2_TYPE, B-28 ITEM_REC_TYPE, B-28 2-22 INTEGER type storage size of, ITEM_LIST_2_TYPE, B-28 ITEM_LIST_3_TYPE, B-28 ITEM_LIST_PAIR_REC_TYPE, B-28 ITEM_LIST_PAIR_TYPE, B-28 See also System-routine packages Length representation clause effect on collections allocated for access types, 3—1 Input-output packages, B-28 IO_EXCEPTIONS package, 3-86, B—4 exceptions predefined in, 4-5 IO_STATUS_BLOCK_TYPE, B-28 JSB instruction, synchronization of operations for, 3-87 terminal, 3-66, 3-69, 3-72, 3-74 text, IOSB_TYPE, 10-3 J indexed, sequential, B-26 ITEM_QUOTA_REC_TYPE, 3-47 improving, 8-37 INVARGMAT, 6-19, 6-20 provided in CONDITION_HANDLING package, 62 use of to implement the raising of exceptions, using to signal VAX conditions from an Ada program, 4-3 4-15 LIB$STOP routine provided in CONDITION_HANDLING package, 6-2 used in exception handling, 4-2 Index-9 LIB$STOP routine (cont'd.) | use of to implement the raising of exceptions, 4-3, 4-4 using to signal VAX conditions from an Ada program, LIB package, 4-15 6-2, B4 LONG_LONG_FLOAT type representation of, storage size of, 2-5 2-5 LONG_LONG_FLOAT_MATH_LIB package, A-1 LONG_LONG_FLOAT_TEXT_IO package, 3-85, A—1 Loop parameters See also System-routine packages example of using to call LIB$FILE_SCAN and LIB$FILE_SCAN_END routines, 6-36 Library packages effect of length representation clauses on, 2-3 Low-level features using, 10-2 extracting specifications for VAX Ada predefined, 6-2, B-1 VAX Ada predefined, 9-18, B-1 MACHINE_SIZE attribute Line terminator in Ada text file, comparison with SIZE attribute, 3-77 results of for types, Linker program section allocation by, using with types, 5-39 using to perform link-time object size checking, 542, 545 LOCK_ERROR raised on access to a locked record, LOCK_ID_TYPE, LOCK_STATUS_BLOCK_TYPE, LOCK_VALUE_BLOCK_TYPE, LOG, B-28 B-28 See also Main task as environment task, execution of, 3-8 VMS tables for, 3-8 3-9 8-2 8-1 LOGICAL_NAME_TYPE, B-28 B-26 LONGWORD_SIGNED_TYPE, B-28 B-28 LONG_FLOAT as parent type for nonpredefined floating-point type, 2-6 2-9 effect on nonpredefined floating-point types, 2-6 effect on the type LONG_FLOAT, 2-6 using ACS commands to change the value of, 2-10 LONG_FLOAT type representation of, of, of, LONGWORD_UNSIGNED_TYPE, LONG_FLOAT pragma, 8-13 increasing and decreasing the top guard stack area 8-14 increasing and decreasing the working storage area LOGZERNEG, 2-5 storage size of, 2-5 LONG_FLOAT_MATH_LIB package, A-1 LONG_FLOAT_TEXT_IO package, 3-85, A-1 LONG_LONG_FLOAT as parent type for nonpredefined floating-point type, 8-14 program region for allocating task stack for, size of task control block for, 8-13 8-9 MAIN_STORAGE pragma effect on program region for task stacks, 8-10 to control size and allocation of main task stack, 8-13 using to control size and allocation of main task stack, 8-12 MASK_BYTE_TYPE, B-28 MASK_LONGWORD_TYPE, B-28 MASK_PRIVILEGES_TYPE, B-28 MASK_QUADWORD_TYPE, B-28 MASK_WORD_TYPE, B-28 MATCH_COND, B-19 Math routines example of importing from VAX Run-Time Library, 4-12 MATH_LIB package, 6-1, 6-17, B-5 predefined instantiations of operations in, specification of, Index-~10 8-1 8-1 controlling size of stack for, using to denote file specifications, 2-6, 2-7 5-40 See also Task stack B-26 Logical names, exporting and importing objects from, sharing variables with, 5-43 Main program Main task, B-26 2-38 MACRO termination of, B-26 LOG10, LOG2, 3-39 B-28 2-38 2-39, 2—40 B-26 9-18 Objects (cont'd.) Mechanism arguments in raising exceptions, MECHANISM option, 4-2 5-28 Memory sharing between VAX CPUs, Mixed-language programming, and data representation, 10-13 representation of, 5-8 2-29 2-1 2-1 representation of array, 2-16 representation of floating-point, representation of record, representation of task, 6-2, 6-18, B-5 See also System-routine packages 2-5 2-18 2-24 results of size attributes for, 2—40 sharing storage of with non-Ada code, Multinational Character Set relationship to the type CHARACTER, 2-23 2-18 representation of fixed-point, 2-7 3-36 2-2, 2-3 N access types, 2-22 stack allocation of, 2-42 storage size of address, record type declared for in the package STARLET, 67 NCS package, 2-24 storage sizes of array, 2-18 8-1,8-2 using SIZE attribute with, See also System-routine packages NEW_LINE, 3-79, 3-80 NEW_PAGE, 3-79, 3-80 OPEN procedure, 3-6 FORM parameter, as match for imported VAX conditions, 4-7 4-15 NON_ADA_ERROR exception, 4-15 NULL_PARAMETER attribute, 6-12, 617, 624 example of use in the package STARLET, 6-13 2-2 2-37, 2-38 3-2, 3-34, 3-35 FILE parameter, NON_ADA_ERROR 2-3 2-23 used in mixed-language programs, 6-2 encoding of, storage size of task, task, 3-6 540 size and representation of those designated by storage allocated for enumeration, NAM (name block) NAME parameter, 24 2-2 representation of address, B-19 MTH package, 2-35 representation and storage of, 8-31 defined for each floating-point type, MSG_NO, 2-3 representation and storage of integer, 4-11, 4-21 Model numbers MODE parameter, loop parameter, relationship to types, 4-22 VAX Calling Standard conventions for, with tasks, 2-35 passing to non-Ada routines, 5-6 5-3, 5-5 exception handling in, 2-2 initialization of, clauses, 5-16 example of handling exceptions in, examples of, 2-42 how the compiler represents and stores, overlaying onto storage locations using address 5-1 conventions for passing data in, effect of lifetimes on storage allocation, 3-3, 3-6, 3—11, 3-36 MODE parameter, 3-36 NAME parameter, 3-6 Operators inline expansion of implicit declarations of, Optimizations, 9-5 9-1 suppressing, 10-2 /OPTIMIZE qualifier (compilation commands) O effect on generics, Object definition of an, 9-11 Optional parameters in system routines versus Ada, 2-1 OTS package, Objects aligning components of record, allocation of storage for, See also System-routine packages 2-33 Output 2-42 controlling stack sizes of task, nonterminal, 8-12 control over representation and storage of, 2-1 declaring for mixed-language programming, 2-34 determining size of, dynamic allocation of, 6-11 6-2, B-5 terminal, 3-80 3-80 2-37 242 Index-11 P Parameters (cont'd.) Packable types, passing access type, 2-24 Packages as masters of tasks, 6-24 8-2 passing address type, extracting specifications of VAX Ada predefined, passing array type, 6-2, B-1 summary of VAX Ada predefined, 5-37 6-3 2-24 effect on CHARACTER type, 2-25 using to change default array representations, 5-29 5-28 6-6 in Ada text file, 3-77 PAGE_PROTECTION_TYPE, B-28 9-28 5-7 6-11 6-6 mechanisms for in system routines, 6—24 of subprograms in system routines, 6-24 VAX Ada default mechanisms for, 5-18 VAX Calling Standard mechanisms for, 5-12 Parameters access methods for system or utility routines, 6-23 Ada semantics for passing, 5-7 5-28 default Ada passing mechanisms for, 5-18 default and optional in system routines, 6-11 default and optional to callable routines, 6-24 default descriptor classes for passing array type, 5-19 5-4, 5-6, 5-18 determining types for in routine interfaces, 6-3 example of passing by descriptor, 5-31 mechanisms for passing VAX data type, 5-21 modes of for imported or exported subprograms, 6-22 optional in system and run-time library routines, optional in VAX Ada, 5-6 6-23 5-12 Pascal exporting an Ada subprogram to, 5-5 exporting and importing objects from, 5-40 sharing variables with, 5-43 Path name CDD, 72 9-19 Performance See also Run-time performance improving CPU, 9-19 improving run-time, 9-1 Performance and Coverage Analyzer See PCA PL/I exporting and importing objects from, 5-6, 6-11 6-11 subprograms, using to improve performance, 5-12 determining mechanisms for passing, 6-24 required modes for in imported and exported PCA controlling the passing mechanisms for imported default in VAX Ada, 5-21 VAX Calling Standard mechanisms for passing, in VMS system routines, argument list for passing, 5-21 5-21 passing to system or utility routines, between languages and VMS system service 5-6 5-18 passing task type, Ada semantics for, subprogram, 5-20 passing scalar type, passing task entries as, Parameter passing routines, passing record type, passing subprograms as, Paging Index—-12 5-30 passing imported by reference, passing imported by value, 2-18 passing, passing imported by descriptor, passing mechanisms for VMS system routines, Page terminator controlling, 5-20 5-18 passing by descriptor to exported subprograms, B-1 using the VAX Ada system-routine, PACK pragma, 5-20 passing Ada subprograms to system routines, sharing variables with, PPL package, 5-40 5-43 6-2, B-5 See also System-routine packages Pragmas using to control object representation and storage, 2—1 PRIORITY pragma for controlling task scheduling, for setting task priorities, using to overcome busy waiting, Procedures See Subprograms 8-16 8-16 8-23 PROCEDURE_TYPE, Records (cont'd.) B-28 Processor status word (PSW), PROCESS_ID_TYPE, PROCESS_NAME_TYPE, Program counter (PC), Program sections, examples of using representation clauses with, 5-14 2-30 B-28 examples of variant, B-28 simple, 5-39 establishing with PSECT_OBJECT pragma, 543 PROGRAM_ERROR exception underlying run-time checks for, aligning components of, representation of, 543 PUT procedure PUT_ITEM procedure, 3-41 PUT_LINE procedure, 3-80 2-18, 2-29 2-18 returning as function results, size of, 2-26 5-7, 5-20 representation clauses with, 543 default files for TEXT_IO, 2-33 2-25 passing parameters of, 2-2 attributes of objects specified with, syntax of, Record types packing, See Program sections 5-27 2-20 using representation clauses to force efficient 3-87 storage of, 2-32 Record variants effect of the pragma PACK on, 2-28 representation clauses with, 2-31 Q representation of in record layouts, Queue instructions, Recursive reentrancy, 2-34 avoiding nonreentrancy, definition of kinds of, record type declared for in the package STARLET, 6—7 Reference mechanism, 8-31 5-13 passing access type parameters by, 5-20 passing address type parameters by, B-28 passing array type parameters by, Record discriminants effect on size of record objects, passing task type parameters by, 2-19 for imported function results, 2-34 Reference semantics, effect on the laying out of records in storage, 2-19 2-30 5-7, 519 for passing record type parameters, for passing task type parameters, 5-7, 5-20 5-7, 5-21 Registers 2-31 using to force efficient storage of records, 2-32 Records 2-32 definition of packable components of, dynamic components in, 5-29 5-7 for passing array type parameters, See also Representation clauses biasing of component values of, 5-36 for imported subprogram parameters, See also Alignment clauses using to conserve space, 5-20 5-21 REFERENCE mechanism option Record objects controlling allocation of with alignments, Record representation clauses, 2-29 5-20 5-19 passing record type parameters by, 2-19 representation of in record layout, efficient storage of, 8-32 8-31 in mixed-language tasking programs, RAB (record access block) example of use of, 2-19 8-31 Reentrancy R RAB_TYPE, 2-34 5-27 effects of packing components of, 4-9 Psects PSECT_OBJECT pragma, 2-19 restrictions on aligning components of, 5-38 definition of attributes, 2-19 how the compiler lays out, 5-14 2-24 2-20 examples of aligning components of, examples of discriminants in, 2-19 2-21 2-34 5-14 operations in the package SYSTEM for, 10-3 used to allocate object storage, 2-42 used to return function results, 5-13, 5-16 VAX, 5-14 Relative files, 2-32 example of calculating storage size of, defined by the VAX Calling Standard, 3—4 default attrbutes for, 3-51 specifying record size for, RELATIVE_IO package, 3-51 3-1, 3-5, B-6 default attributes provided by, 3-51 Index-13 RELATIVE_IO package (cont'd.) example of using, Scalar types 3-53 RELATIVE_MIXED_IO package, 3-1, 3-5, 341, B—6 default file atiributes provided by, Rendezvous, 8-23 for fixed-point types, 2-24 effect on result of SIZE attribute, enumeration, length, 2-28 record, 2-29 5-25 2-38 SECTION_ID_TYPE, use of to control object representation and storage, 2—1 3-44 SEQUENTIAL_IO package, 3-1, 34, 3—40, B-6 default file attributes provided by, example of using, REQUEST_TIME_SLICE, B-28 34 default attributes for, 2-33 B-28 B-28 SECTION_NAME_TYPE, Sequential files, SEQUENTIAL_MIXED_|O package, RIGHTS_HOLDER_TYPE, default file attributes provided by, Serial reentrancy, 8-31 B-28 RMS (Record Management Services) See also System-routine packages, STARLET package, Interfaces (routine) 6-13 example of calls to/from the package STARLET, 6-16 testing condition values returned by, example of between VAX CPUs, SHARED pragma, effect of, in tasking program, RMS services 8-27 SHARE_GENERIC pragma, 8-36 9-11, 9-14 comparison with the pragma INLINE_GENERIC, B—6 9-12 B-26 examples of using, Run-time attributes syntax of, 3-34 9-14 9-14 SHORT_INTEGER type Run-Time Library routines range of values for, See VMS Run-Time Library routines representation of, 2-5 2—4 controlling paging to improve, 9-28 storage size of, 2-5 SHORT_INTEGER_TEXT_IO package, eliminating checks to improve, 9-21 SHORT_SHORT_INTEGER type Run-time performance improving, range of values for, 9-1 overlapping execution to improve, reducing subprogram call costs to improve, improve, representation of, 9-28 using scalar types and simple operations to 9-22 3-85, A-1 2-5 2-4 storage size of, 2-5 SHORT_SHORT_INTEGER_TEXT_IO package, 3-85, A-1 9-25 RU_HANDLE_TYPE, 8-29 8-28 Shared variables 6-26 RMS_ASYNCH_OPERATIONS package, 10-13 8-27 comparison with the pragma VOLATILE, example of using control blocks, 6-34 STARLET type declarations for, 6-7 of input-output files, 5-38 Shared memory calling from the package STARLET, ROPRAND, 3—45 SEVERITY, B-19 Shared data in mixed-language programs, 6-1 calling asynchronous from tasks, 3-1, 34, 341, B-6 B-28 calling from an Ada program, 3-45 3-46 B-39 RESULT_MECHANISM option, 5-35 RIGHTS_ID_TYPE, 9-25 2-16 SECTION_ACCESS_ID_TYPE, 2-29 specifying alignment with, 5-31 5-7, 5-18 using to improve run-time performance, Scale factor 8-42 Representation clauses, passing parameters of, returning as function results, 8-2 during AST handling, tentative, 3-52 passing as parameters by descriptor, SIGNAL, B-28 B-19 Signal arguments S copying of during exception handling, Safe numbers in raising exceptions, 4-6, 4-28 information lost during exception handling, defined for each floating-point type, Index-14 2-9 4-2 4-6 STARLET package (cont'd.) Signal arguments (cont'd.) matching in mixed-language exception handling, 4-14 Simple record, SIN, B-26 SIND, SINH, 6-2 severity codes provided in, 6-26 specification of types defined in, B—28 B-26 B-26 type declarations in for VMS RMS control blocks, comparison of results of for types and objects, 2-39, 2-40 comparison with MACHINE_SIZE attribute, 2-38 using to determine the size of objects and types, 2-37 SKIP_LINE procedure, 3-69 SMG package, 6-2, B—7 See also System-routine packages B-26 SQUROONEG, B-26 SS$_ACCVIO violation occurrence of in mixed-language tasking programs, 8-15 occurrence of in tasking programs, 8-11 SS$_DEBUG condition and Ada exception handlers, 4-21 SS$_FLTDIV condition VAX Ada equivalent for, 'S§S$_FLTDIV_F condition VAX Ada equivalent for, SS$_FLTOVF condition VAX Ada equivalent for, SS$_FLTOVF_F condition VAX Ada equivalent for, SS$_INTDIV condition VAX Ada equivalent for, SS$_INTOVF condition VAX Ada equivalent for, SS$_UNWIND condition 4-8 4-8 4-8 242 constants defined in the package STARLET, STOP, 6-27 B-19 STOP command (DCL) entering after CTRL/Y in tasking program, 8-25 Storage controlling for programs ‘with tasks, 8-9 Storage allocation, for tasks, 241, 2-42 8-9 improving efficiency of, 2-42 Storage deallocation, 2-41, 2—43 for tasks, 8-9 STORAGE_ERROR exception not being raised in mixed-language programs, String definition of, 4-8 5-18 Strings 4-21 4-5 6-1, 8-35, B—7 See also System-routine packages example of using to call SYS$GETQUI system | example of using to call SYS$TRNLNM system 6-29 6-7 8-12 4-8 2-9 service, 6-31 Static memory use of to allocate storage, 8-14 recompilation of with the pragma LONG_FLOAT, STARLET package, 6-22 PROCEDURE in, use of underscores in routine names in, raising of for task stack overflow, 8-11, 8-14 raising of in tasking programs, 8-9 underlying run-time checks for, 4-9 STORAGE_SIZE attribute application of to tasks, 8-12 using to control size and allocation of task stacks 4-8 and Ada exception handlers, STANDARD package, B-7 exceptions predefined in, 6-7 use of the pragma IMPORT_VALUED_ Status values See also System-routine packages SOR package, 6-2, B-7 service, 6-34 obtaining specifications for types and operations in, 5-27 SIZE attribute SQRT, example of using VMS RMS control blocks from, working with varying, STRING type packability of, 10-9 2-25 representation of, String types 2-2 passing as parameters with DESCRIPTOR mechanism option, 5-30 returning as function results, 5-25 STR package, 6-2 See also System-routine packages Subprograms Ada semantics for calling, 5-7 Index-15 Subprograms (cont'd.) as masters of tasks, SYS$HIBER system service 8-2 calling Ada from external routines, 54 calling external routines from Ada, 5-2 avoiding calls to/from tasks, 8-38 SYS$INPUT logical name, 3-9, 3-87 calling from non-Ada AST service routines, 8-43 controlling the parameter-passing mechanisms for imported, 5-28 effect of implicit inline expansion on, explicit inline expansion of, 94 implicit inline expansion of, 9-6 inline expansion of, 9-9 example of calling, 9-7 equivalence strings for, 9-5 9-7 5-21 passing as parameters to system routines, 6-24 9-22 special effects of the pragma INLINE on generic, 9-9 use of in routine interfaces, 6-21 VAX Ada linkage conventions for calls to, 5-15 SUCCESS, B-19 SUPPRESS pragma using to suppress run-time checks, 4-11 4-11, 921 Symbol definitions example of specification and calls to, 6-13 SYS$COMMAND logical name, 3-9, 3-87 3-11 representing process-permanent file, 3-10 SYS$CRMPSC system service example of using, 8-37 use of to implement delay statements, 6-14 SYS$DISK logical name, 3-9 SYS$ERROR logical name, 3-9, 3-87 example of Ada routine interface for, SYS$TRNLNM system service 6-29 example of calling using the pragma IMPORT_ VALUED_PROCEDURE, 6-43 SYS$SUNWIND system service use of to invoke an exception handler, SYS$WRITE RMS routine 4-3 example of specification and calls to, 6-16 SYSTEM package, 6-1, B-8 exceptions predefined in, 4-5 4-7 type ADDRESS in, 2-23, 101 unsigned types in, 10-6 using types and operations declared in, System-routine packages See also individual packages by name default and optional parameters in, 6—11 629 6-7 6-2, B—1 3—-10 6-6 6-3 provision of initialization constants for record types, 6-7 rules for default and optional parameters, System routines 6-31 6-10 6-12 steps for calling routines with optional parameters, 6-13 8-38 SYS$GETQUI system service calling using the package STARLET, parameter types used in, reserved fields in record components in, SYSS$EXIT system service avoiding calls to/from tasks, 10-2 6-9 4-3 representing process-permanent file, 6-20 calling using the package STARLET, record type declarations in, 3-11 output file for error messages, 8-24 SYS$TRNLNM parameter-passing mechanisms in, example of specification and calls to, 3-10 SYS$SETIMR routine obtaining specifications for, SYS$DEQ system service Index—16 SYS$SETAST system service, naming conventions in, 8-39 equivalence strings for, 3-10 examples of using, 6-34 SYS$DCLEXH system service calling from tasks, SYS$SCRATCH logical name, NON_ADA_ERROR in, obtaining, 6-25 SYS$ASSIGN system service equivalence strings for, 4-3 representing process-permanent file, 9-6 using to suppress run-time checks, SUPPRESS_ALL pragma 3-10, 3-87 3—11 output file for error messages, inline expansion of specifications and bodies, reducing costs for calls of, 6-34 SYS$OUTPUT logical name, inline expansion of derived, 9-5 inline expansion of generic instantiations of, passing as parameters, 3-10 3-9 3-10 SYS$OPEN RMS routine 9-3 inline expansion of calls to, 3-11 SYS$LOGIN logical name, SYSS$NET logical name, 9-7 effect of the pragma INLINE on library, examples of inline expansion of, equivalence strings for, representing process-permanent file, declaring record types for, 2-29 writing interfaces to/from VAX Ada, 6-19 Tasks (cont'd.) System services effects of system service calls on, See VMS system services SYSTEM_RUNTIME_TUNING package, specification of, 6-2, B-8 B-39 using in programs that call asynchronous system services, 6—17 environment, 8-35 8-1 example of serializing, example of using, 8-34 8-2 first-in-first-out scheduling of, handling ASTs from, 8-15 8-42 improving run-time behavior with, T in context of single process, TAN, increasing concurrency of when calling system B-26 TAND, B-26 TANH, B-26 services, 8-36 definition of, interaction with exception handling, 8-1 Task control block, estimating size of, interrupting with CTRLYY, 224 main, 8-8 8-17 priorities and responsiveness of, 8-20 8-23 during AST handling, 8-42 reentrancy with, during call from non-Ada AST service routine, 843 dynamic-circular-calling, 8-18 storage allocated for, 5-21 TASKING_SERVICES package, switching of, 6-1, 8-35, 8-36, B—42 use of overloading for optional parameters in, 6-17 8-1 See also Main task 8-2 calling system services from, 8-35, 8-37 changing priority to improve performance, tentative rendezvous with, 8-23 termination messages for, 4-28 termination of, 3-87 8-37 4-28, 8-2, 8-24 using abort statements in, 8-24 using delay statements in, 8-24 8-25 8-49 3-87 Task scheduling, 8-15 during system service calls, 8-30 round-robin, 8-17 definition of suspension of, 8-15 delivery of ASTs to completed or abnormal, 8-15 wait states caused by input-output operations, 8-12 coordination of information among, Task stack, 8-43 8-2, 8-8 effect of priority on action taken after CTRL/Y, 8-26 system services to avoid calling from, abnormal, 8-31 dependence on masters, synchronization of input-output operations in, VAX Ada scheduling strategy for, calling non-Ada routines from, deadlock with, 8-43 8-15 using delay statement to force completion of 8-22, 8-24 controlling stack sizes of, 8-17 8-7 storage allocated for when AST delivered, 3-86 8-37, 840, B-8 busy waiting of, 8-36 8-27 special considerations in using, interaction of with input-output, as masters of tasks, 8-16 8-15 sharing variables with, Tasking Tasks, round-robin scheduling of, scheduling of, 4—4 8-31 serializing to prevent reentry, Task entries specification of, 4-27 8-16 scheduling of during system service calls, 8-35 8-21 8-18 passing as parameters, 8-48 raising exceptions at point of rendezvous, due to busy waiting, exception-induced, 8-1, 8-9 preventing termination messages from, 8-37 8-23 8-25 measuring and tuning performance, caused by SYS$SETAST, circular-calling, 4-27 interference of busy waiting with scheduling, 8-2, 8-8 address of as value of task object, self-calling, 8-36 increasing concurrency with TASKING_SERVICES, Task Task deadlock, 9-28 8-2 8-36 8-16 8-2, 8-9 See also Main task default top guard area of, default working area of, detecting overflow of, 8-11 8-11 8-11 Index—-17 Task stack (cont'd.) fixed-size, TASK_RMS_SEARCH, 8-10, 8-11 for main task, 8-10 increasing and decreasing the top guard area of, 8-11 increasing and decreasing the working area of, 8-11 limits of, overflow when calling non-Ada code, program region for allocating main, reasons for specifying size of, top guard area of, 8-14 8-11 8-10 working storage area of, 8-10 Task switching, 8-2, 8~15 Task synchronization, 8-2 Task types packing, 2-25 representation of, 5-7, 5-21 2-24 returning as function results, TASK_BRKTHRUW, B—42 B-42 TASK_GETDVIW, B—42 TASK_GETJPIW, B-42 TASK_GETLKIW, B—42 TASK_GETQUIW, B-42 TASK_GETSYIW, B-42 TASK_QIOW, 5-25 8-15 application of to tasks, 8-12 to control task stack top guard area, 8-12 using to control size of task stacks, 8-12 TASK_UPDSECW, B-42 Terminal input-output, 3-66 achieving asynchronous, buffering, 3-80 3-10, 3-67, 3-88 data-oriented method for, 3-72 3-69 3-74 TERMINATED attribute value of during task AST handling, Text files, 8-43 3-5 3-81 3-65 3-77 VAX Ada implementation of, 3-66 TEXT_IO TASK_RMS_DISPLAY, B—42 TASK_RMS_ENTER, B-42 B—42 TASK_RMS_EXTEND, 3-74 line-oriented method for, mixed method for, terminators in, TASK_RMS_DELETE, B-42 TASK_RMS_DISCONNECT, B-42 B-42 B—42 TASK_RMS_FLUSH, B-42 TASK_RMS_FREE, B—42 TASK_RMS_GET, B42 TASK_RMS_NXTVOL, B-42 TASK_RMS_OPEN, B—42 TASK_RMS_PARSE, B-—42 TASK_RMS_PUT, B—42 TASK_RMS_READ, B-42 TASK_RMS_RELEASE, B—42 TASK_RMS_REMOVE, B-42 TASK_RMS_RENAME, B-42 TASK_RMS_REWIND, B-42 index-18 B-42 carriage control in, TASK_RMS_CLOSE, B—42 TASK_RMS_CONNECT, B-42 TASK_RMS_CREATE, B-42 TASK_RMS_FIND, TASK_RMS_WAIT, B—42 TASK_RMS_WRITE, B—42 default attributes for, B—42 TASK_RMS_ERASE, B-42 B—42 flexible method for, passing parameters of, TASK_ENQW, TASK_RMS_UPDATE, TASK_STORAGE pragma 8-13 using top guard area for detecting overflow, B-—42 TASK_RMS_TRUNCATE, TASK_SNDJBCW, 8-10 B-42 TASK_RMS_SPACE, predefined instantiations of packages in, TEXT_lO package, 3-1, 3-6, 3—-64, B-9 carriage control in, 3-81 3-85 default file attributes provided by, 3-65 default files for GET procedures, 3-87 default files for PUT procedures, 3-87 example of using, 3-67 predefined instantiations of operations in, using for terminal input-output, 3-66 TIME_NAME_TYPE, B-28 9-18 TIME_SLICE pragma, 8-49 effect on TQELM quota, 8-24 See also TQELM recommended values for, 8-17 using to cause round-robin task scheduling, using to control task scheduling, 8-16 using to overcome busy waiting, 8-23 TQELM (Timer Queue Entry Limit) quota effect on delay statements, 8-24 TRANSACTION_ID_TYPE, B-28 TT logical name, 3-10, 3-88 Types See also individual types by name Ada equivalents for VAX data, 5-21 8-16 vV Types (cont'd.) determining size of, 2-37 packable, 2-24 relationship to objects, representation of, 5-12 VALUE mechanism option 2-1 for imported function results, 2-2 results of size attributes for, task, Value mechanism, unsigned, in the package SYSTEM, 10-6 using MACHINE_SIZE attribute with, 2-38 using SIZE attribute with, 2-37 effect of the pragma SHARED on, 8-28 effect of the pragma VOLATILE on, 8-29 Varying strings declaring in VAX Ada, working with, 10-9 7-3 VAX Calling Standard, U 5-16 5-8 VAX Common Language Environment, UIC_LONGWORD_TYPE, UIC_TYPE, B-28 VAX Ada equivalents for, Unchecked conversions See also UNCHECKED_CONVERSION procedure between address and access types, 2-22 2-11, 2-12, 2-14, 2-16 using to control access type storage, 2-43 UNCHECKED_CONVERSION procedure between address and access types, 2-22 effect of the pragma INLINE on an instantiation of, 5-21 VAX Performance and Coverage Analyzer See PCA VAX Procedure Calling and Condition Handling Standard conformance of Run-Time Library routines to, 6-11 conformance of system services to, conformance of VAX Ada to, 6-11 5-1 VAX Procedure Calling Standard interface for function return values, 9-5 UNCHECKED_DEALLOCATION procedure, example of using, 2-43 2-43 using to control access type storage, characteristics of, B-28 B-28 VMS data structures, B-28 B-28 VECTOR_WORD_UNSIGNED_TYPE, B-28 6-4 VMS Linker 10-6 See Linker 10-6 UNSIGNED_WORD type, VECTOR_BYTE_UNSIGNED_TYPE, VECTOR_WORD_SIGNED_TYPE, 10-6 UNSIGNED_LONGWORD type, 5-13 B-28 VECTOR_LONGWORD_UNSIGNED_TYPE, explanation of Ada, 10-6 in the package SYSTEM, 10-6 UNSIGNED_BYTE type, VECTOR_BYTE_SIGNED_TYPE, VECTOR_LONGWORD_SIGNED_TYPE, 2-43 Unsigned types VMS Run-Time Library routines 10-6 Usages (VMS) See also System-routine packages, individual packages by name, Interfaces (routine) See VMS data structures calling from an Ada program, USER_ARG_TYPE, B-28 USE_ERROR exception raised for concurrent opening of magnetic tape files, 2-2 VAX data types B-28 to floating-point types, Unchecked deallocation 5-28 Variables 8-1 VAX Ada equivalents for CDD, 5-36 for imported subprogram parameters, 240 declaring record types for, 3-37 raised for FDL errors in FORM parameter, raised for mismatch of file attributes, raised for opening an open file, 3-37 raised on access to a locked record, raised when writing text files, Utility routines See VMS utility routines 3-66 3-17 3-34, 3-35 6-1 calling from tasks, 8-11 calling mathematical from VAX Ada, 6-17 2-29 example of calling, 6-36 testing condition values returned by, 6-26 VMS system routines 3-39 See System routines VMS system services See also System-routine packages, STARLET package, Interfaces (routine) calling asynchronous, 6-17 calling asynchronous from tasks, 8-36 Index-19 VMS system services (cont'd.) calling from an Ada program, using with address objects, 6—1 calling from tasks, 8-11 calling from the package STARLET, 10-1 with address determined by ADDRESS attribute, 10-1 6-13 example of calling using the package STARLET, 6-29, 6-31 example of item-list structure in call to, 6-29, 6-31 examples of calls to/from the package STARLET, WOHD__CON D_VALUE_TYPE, B-19 6-13 testing condition values returned by, VO LATILE pragma, 6-26 8-27 comparison with the pragma SHARED, effect of, 8-29 6-7 2-42 example of use in system service call, 6-29 example of using with VMS RMS control blocks, Index—20 record type declared for in the package STARLET, 8-29 effect on storage allocation, 6-34 XAB (extended attribute block) Z $ZERO program section, 5-39 How to Order Additional Documentation Technical Support If you need help deciding which documentation best meets your needs, call 800-343-4040 before placing your electronic, telephone, or direct mail order. Electronic Orders To place an order at the Electronic Store, dial 800-DEC-DEMO (800-332-3366) using a 1200- or 2400-baud modem. If you need assistance using the Electronic Store, call 800-DIGITAL (800-344-4825). Telephone and Direct Mail Orders Your Location Call Contact Continental USA, 800-DIGITAL Digital Equipment Corporation Alaska, or Hawaii P.O. Box CS2008 Nashua, New Hampshire 03061 Puerto Rico 809-754-7575 Local DIGITAL subsidiary Canada 800-267-6215 Digital Equipment of Canada Attn: DECdirect Operations KAO2/2 P.O. Box 13000 100 Herzberg Road Kanata, Ontario, Canada K2K 2A6 International Local DIGITAL subsidiary or approved distributor Internall SDC Order Processing - WMO/E15 or Software Distribution Center Digital Equipment Corporation Westminster, Massachusetts 01473 1For internal orders, you must submit an Internal Software Order Form (EN-01740-07). VAX Ada Run-Time Reference Manual Reader’s Comments AA-EF88B-TE Please use this postage-paid form to comment on this manual. If you require a written reply to a software problem and are eligible to receive one under Software Performance Report (SPR) service, submit your comments on an SPR form. Thank you for your assistance. I rate this manual’s: Excellent Good Fair Poor O [ O O O] [ ] O L] o [ O O [ [ [ O O [ O [ [ O O ] ] O O [ [ [] [ Accuracy (software works as manual says) Completeness (enough information) Clarity (easy to understand) Organization (structure of subject matter) Figures (useful) Examples (useful) Index (ability to find topic) Page layout (easy to find information) I would like to see more/less What I like best about this manual is What I like least about this manual is I found the following errors in this manual: Page Description Additional comments or suggestions to improve this manual: I am using Version Name/Title of the software this manual describes. Dept. Company Date Mailing Address Phone -w== Do Not Tear - Fold Here and Tape z | - — I No Postage digitaly Necessary if Mailed in the United States ] ] R BUSINESS REPLY MAIL FIRST CLASS PERMIT NO. 33 MAYNARD MASS. POSTAGE WILL BE PAID BY ADDRESSEE ] I R R ] ] DIGITAL EQUIPMENT CORPORATION Corporate User Publications—Spit Brook ZK01-3/J35 110 SPIT BROOK ROAD NASHUA, NH 03062-9987 ~=== Do Not Tear - Fold Here ] Reader’s Comments VAX Ada Run-Time Reference Manual AA-EF88B-TE Please use this postage-paid form to comment on this manual. If you require a written reply to a software problem and are eligible to receive one under Software Performance Report (SPR) service, submit your comments on an SPR form. Clarity (easy to understand) Organization (structure of subject matter) Figures (useful) Examples (useful) Index (ability to find topic) Page layout (easy to find information) Fair Poor OO0000000 Completeness (enough information) Good Oooodoooo Accuracy (software works as manual says) Excellent OO0O0000o0a0 I rate this manual’s: OoOo0oOooooa Thank you for your assistance. I would like to see more/less What I like best about this manual is What I like least about this manual is I found the following errors in this manual: Page Description Additional comments or suggestions to improve this manual: I am using Version Name/Title of the software this manual describes. Dept. Company Date Mailing Address Phone —— Do Not Tear - Fold Here and Tape - . | - — I No Postage dlilgliltiall Necessary if Mailed in the United States . ] I ] BUSINESS REPLY MAIL I FIRST CLASS PERMIT NO. 33 MAYNARD MASS. ] POSTAGE WILL BE PAID BY ADDRESSEE ] . ] DIGITAL EQUIPMENT CORPORATION Corporate User Publications—Spit Brook ZK01-3/J35 110 SPIT BROOK ROAD NASHUA, NH 03062-9987 -« Do Not Tear - Fold Here —~— ] ———
Home
Privacy and Data
Site structure and layout ©2025 Majenko Technologies