Programming Concepts Manual, Volume I
- Operating System and Version:
- VSI OpenVMS IA-64 Version 8.4-1H1 or higher
VSI OpenVMS Alpha Version 8.4-2L1 or higher
VSI OpenVMS x86-64 Version 9.2-1 or higher
Preface
1. About VSI
VMS Software, Inc. (VSI) is an independent software company licensed by Hewlett Packard Enterprise to develop and support the OpenVMS operating system.
2. Intended Audience
This manual is intended for system and application programmers. It presumes that its readers have some familiarity with the VSI OpenVMS programming environment.
3. Document Structure
Part I, “Process and Synchronization”, Process and Synchronization
Part II, “Interrupts and Condition Handling”, Interrupts and Condition Handling
Part III, “Addressing and Memory Management”, Addressing and Memory Management
Part IV, “Appendixes: Macros and Examples of 64-Bit Programming”, Appendixes: Macros and Examples of 64-Bit Programming
Chapter 1, Overview of Manuals and Introduction to Development on OpenVMS Systems describes the structure of the two-volume manual, and offers an introduction to the OpenVMS operating system and to the tools that are available in the programming environment.
Chapter 2, Process Creation defines the two types of processes, and describes what constitutes the context of a process, and the modes of execution of a process. It also describes kernel threads and the kernel threads process structure.
Chapter 3, Process Communication describes communication within a process and between processes.
Chapter 4, Process Control describes how to use the creation and control of a process or kernel thread for programming tasks. It also describes how to gather information about a process or kernel thread and how to synchronize a program by using time.
Chapter 5, Symmetric Multiprocessing (SMP) Systems describes overview concepts of symmetric multiprocessing (SMP) systems.
Chapter 6, Synchronizing Data Access and Program Operations describes synchronization concepts and the differences between synchronization techniques on VAX systems, Alpha systems, and I64 systems. It presents methods of synchronization such as event flags, asynchronous system traps (ASTs), parallel processing RTLs, and process priorities, and the effects of kernel threads upon synchronization. It also describes how to use synchronous and asynchronous system services, and how to write applications in a multiprocessing environment.
Chapter 7, Synchronizing Access to Resources describes the use of the lock manager system services to synchronize access to shared resources. This chapter presents the concept of resources and locks; it also describes the use of the SYS$ENQ and SYS$DEQ system services to queue and dequeue locks.
Chapter 8, Using Asynchronous System Traps describes how to use asynchronous system traps (ASTs). It describes access modes and service routines for ASTs and how ASTs are declared and delivered. It also describes the effects of kernel threads on AST delivery.
Chapter 9, Condition-Handling Routines and Services describes the OpenVMS Condition Handling facility. It describes VAX system, Alpha system, and I64 system exceptions, arithmetic exceptions, and Alpha and I64 system unaligned access traps. It describes the condition value field, exception dispatcher, signaling, and the argument list passed to a condition handler. Additionally, types of condition handlers and various types of actions performed by them are presented. This chapter also describes how to write and debug a condition handler, and how to use an exit handler.
Chapter 10, Overview of Alpha and I64 Virtual Address Space describes the 32-bit and 64-bit use of virtual address space.
Chapter 11, Support for 64-Bit Addressing (Alpha and I64 Only) describes all the services, routines, tools, and programs that support 64-bit addressing.
Chapter 12, Memory Management Services and Routines on OpenVMS Alpha and OpenVMS I64 describes system services and RTLs of Alpha and I64 systems to manage memory. It describes the page size and layout of virtual address space on Alpha and I64 systems. This chapter also describes how to add virtual address space, adjust working sets, control process swapping, and create and manage sections on Alpha and I64 systems.
Chapter 13, Memory Management Services and Routines on OpenVMS VAX describes the of system services and RTLs of VAX systems to manage memory. It describes the page size and layout of virtual address space on VAX systems. This chapter also describes how to add virtual address space, adjust working sets, control process swapping, and create and manage sections on VAX systems.
Chapter 14, Using Run-Time Routines for Memory Allocation describes how to use RTLs to allocate and free pages and blocks of memory, and how to use RTLs to create, manage, and debug virtual memory zones.
Chapter 15, Alignment on VAX, Alpha, and I64 Systems describes the importance and techniques of instruction and data alignment.
- Chapter 16, Memory Management with VLM Features describes the VLM memory management features, such as the following:
- Memory-resident global sections
- Fast I/O and buffer objects for global sections
- Shared page tables
- Expandable global page table
- Reserved memory registry
Appendix A, C Macros for 64-Bit Addressing describes the C language macros for manipulating 64-bit addresses, for checking the sign extension of the low 32 bits of 64-bit values, and for checking descriptors for the 64-bit format.
Appendix B, 64-Bit Example Program illustrates writing a program with a 64-bit region that was created and deleted by system services.
Appendix C, VLM Example Program demonstrates the memory management VLM features described in Chapter 16, Memory Management with VLM Features.
4. Related Documents
For a detailed description of each run-time library and system service routine mentioned in this manual, see the OpenVMS Run-Time Library documentation and the VSI OpenVMS System Services Reference Manual.
VSI OpenVMS DCL Dictionary
VSI OpenVMS User's Manual
VSI OpenVMS Guide to OpenVMS File Applications
VSI OpenVMS Guide to System Security
OpenVMS Record Management Services documentation
VSI OpenVMS Utility Routines Manual
VSI OpenVMS I/O User's Reference Manual
5. VSI Encourages Your Comments
You may send comments or suggestions regarding this manual or any VSI document by sending electronic mail to the following Internet address: <docinfo@vmssoftware.com>
. Users who have VSI OpenVMS support contracts through VSI can contact <support@vmssoftware.com>
for help with this product.
6. OpenVMS Documentation
The full VSI OpenVMS documentation set can be found on the VMS Software Documentation webpage at https://docs.vmssoftware.com.
7. Typographical Conventions
The following conventions are used in this manual:
Convention | Meaning |
---|---|
Ctrl/x | A sequence such as
Ctrl/x
indicates that you must hold down the key labeled Ctrl while you
press another key or a pointing device button. |
PF1
x | A sequence such as PF1
x indicates that you
must first press and release the key labeled PF1 and then press and
release another key (x )
or a pointing device button. |
Enter | In examples, a key name in bold indicates that you press that key. |
… |
A horizontal ellipsis in examples indicates one of the
following possibilities:
|
. . . | A vertical ellipsis indicates the omission of items from a code example or command format; the items are omitted because they are not important to the topic being discussed. |
( ) | In command format descriptions, parentheses indicate that you must enclose choices in parentheses if you specify more than one. |
[ ] | In command format descriptions, brackets indicate optional choices. You can choose one or more items or no items. Do not type the brackets on the command line. However, you must include the brackets in the syntax for directory specifications and for a substring specification in an assignment statement. |
| | In command format descriptions, vertical bars separate choices within brackets or braces. Within brackets, the choices are optional; within braces, at least one choice is required. Do not type the vertical bars on the command line. |
{ } | In command format descriptions, braces indicate required choices; you must choose at least one of the items listed. Do not type the braces on the command line. |
bold type | Bold type represents the name of an argument, an attribute, or a reason. In command and script examples, bold indicates user input. Bold type also represents the introduction of a new term. |
italic type | Italic type indicates important information, complete titles of manuals, or variables. Variables include information that varies in system output (Internal error number), in command lines (/PRODUCER=name), and in command parameters in text (where dd represents the predefined code for the device type). |
UPPERCASE TYPE | Uppercase type indicates a command, the name of a routine, the name of a file, or the abbreviation for a system privilege. |
Example |
This typeface indicates code examples, command examples, and interactive screen displays. In text, this type also identifies website addresses, UNIX commands and pathnames, PC-based commands and folders, and certain elements of the C programming language. |
– | A hyphen at the end of a command format description, command line, or code line indicates that the command or statement continues on the following line. |
numbers | All numbers in text are assumed to be decimal unless otherwise noted. Nondecimal radixes—binary, octal, or hexadecimal—are explicitly indicated. |
Chapter 1. Overview of Manuals and Introduction to Development on OpenVMS Systems
This chapter describes the structure of this two-volume manual. This chapter also provides an overview of the OpenVMS operating system, its components, and the tools in programming software.
1.1. Overview of the Manual
Volume |
Part |
Description |
---|---|---|
Volume I | ||
Part I |
Process and Synchronization. Describes the creation, communication, and control of processes. It also describes symmetric multiprocessing (SMP), and the synchronizing of data access, programming operations, and access to resources. | |
Part II |
Interrupts and Condition Handling. Describes the use of asynchronous system traps (ASTs), and the use of routines and services for handling conditions. | |
Part III |
Addressing and Memory Management. Describes 32-bit and 64-bit address space, and the support offered for 64-addressing. It also provides guidelines for 64-bit application programming interfaces (APIs); and Alpha, I64, VAX, and VLM memory management with run-time routines for memory management, and alignment on OpenVMS Alpha, VAX, and I64 systems. | |
Part IV |
Appendixes: Macros and Examples of 64-Bit Programming. Describes the macros used in 64-bit programming, along with two examples of 64-bit programming. | |
Volume II | ||
Part I |
OpenVMS Programming Interfaces: Calling a System Routine. Describes the basic calling format for OpenVMS routines and system services. It also describes the STARLET structures and definitions for C programmers. | |
Part II |
I/O, System and Programming Routines. Describes the I/O operations, and the system and programming routines used by run-time libraries and system services. | |
Part III |
Generic Macros for Calling System Services. Describes in appendixes the generic macros used for calling system services, OpenVMS data types, and the distributed name services on OpenVMS VAX systems. |
1.2. Overview of the OpenVMS Operating System
The OpenVMS operating system is a highly flexible, general-purpose, multiuser system that supports the full range of computing capabilities, providing the high integrity and dependability of commercial-strength systems along with the benefits of open, distributed client/server systems.
OpenVMS operating systems can be integrated with systems from different vendors in open systems computing environments. OpenVMS supports software that conforms to international standards for an open environment. These industry-accepted, open standards specify interfaces and services that permit applications and users to move between systems and allow applications on different systems to operate together.
The OpenVMS operating system configuration includes OpenVMS integrated software, services and routines, applications, and networks. The system supports all styles of computing, from time-sharing to real-time processing to transaction processing. OpenVMS systems configured with optional software support distributed computing capabilities and can function as servers in multivendor client/server configurations.
The OpenVMS operating system is designed to provide software compatibility across all the processors on which it runs.
The following sections describe the components of the OpenVMS operating system, give a general overview of the system software, and describe the various styles of computing that OpenVMS software supports. The sections also summarize the basic ways in which OpenVMS software can be configured and connected to other software, and the hardware platforms and processors on which the OpenVMS software runs.
1.3. Components of the OpenVMS Operating System
The OpenVMS operating system is a group of software programs (or images) that control computing operations. The base operating system is made up of core components and an array of services, routines, utilities, and related software. The OpenVMS operating system serves as the foundation from which all optional software products and applications operate. The services and utilities in the base OpenVMS operating system support functions such as system management, data management, and program development. Other integrated software that adds value to the system provides functions such as clustering and volume shadowing.
Optional software products, including application programs developed by OpenVMS programmers and other programmers, run on the core operating system. The OpenVMS system supports a powerful, integrated development environment with a wide selection of software development tools. Application programs written in multiple languages provide computational, data-processing, and transaction-processing capabilities.
Compatibility Between Software Versions
User-mode programs and applications created under earlier versions of OpenVMS VAX, OpenVMS Alpha, and OpenVMS I64 run under subsequent versions with no change.
Command procedures written under one version of OpenVMS continue to run under newer versions of the software.
Most user-mode OpenVMS VAX sources can be recompiled, relinked, and run on an OpenVMS Alpha and OpenVMS I64 system without modification. Code that explicitly relies on the VAX architecture requires modification.
Most OpenVMS Alpha images run under translation on OpenVMS I64.
Translation is available for OpenVMS VAX applications without sources or that you do not want to recompile.
1.3.1. OpenVMS Systems on Multiple Platforms
A complex instruction set computer (CISC) architecture based on the VAX architecture.
A reduced instruction set computer (RISC) architecture based on the Alpha architecture.
The explicitly parallel instruction computing (EPIC) architecture used by Itanium systems.
1.3.1.1. System Compatibility and Program Portability Across Platforms
The OpenVMS Alpha and OpenVMS I64 operating systems are compatible with OpenVMS VAX systems in terms of user, system manager, and programmer environments. For general users and system managers, OpenVMS Alpha and OpenVMS I64 have the same interfaces as OpenVMS VAX. Virtually all OpenVMS VAX system management utilities, command formats, and tasks are identical in the OpenVMS Alpha and OpenVMS I64 environments. Mixed-architecture and mixed-version clusters that contain both Alpha systems and VAX systems are supported.
1.3.2. OpenVMS Computing Environments
Open system capabilities
Distributed processing capabilities
Production system capabilities
System and network management capabilities
OpenVMS software capabilities include both the standardized features of open systems computing and the commercial-strength functionality of traditional OpenVMS systems. System and network management software provides for control of heterogeneous, integrated environments.
The following sections describe the capabilities supported in OpenVMS computing environments and summarize the software resources available in each kind of environment.
1.3.2.1. Open System Capabilities
OpenVMS offers the benefits of an open system environment, which permits both applications and users to move between systems. In addition, applications on different open systems can operate together.
The OpenVMS operating system makes available a set of services in an open domain, while still offering its traditional high-integrity computing services. Incorporation of open computing capabilities enhances the traditional feature-rich OpenVMS environment.
Software in the OpenVMS open systems environment enables the development and use of portable applications and consistent user interfaces and also permits systems to operate together. The keys to openness of OpenVMS systems are standard programming interfaces, standardized user interfaces, and standard protocols.
1.3.2.2. Application Portability
Applications can be written once and run on other open platforms that support the standards used in the applications.
Users can access the wide range of applications available on open platforms.
Applications can be supplied by different vendors.
Applications that are developed on the three supported platforms and conform to open standards can be easily ported to other systems that conform to the same standard interfaces. Applications written in ISO and ANSI languages are portable to other systems. In addition, the Open Group/Motif graphical user interface supports application portability.
1.3.2.2.1. Other Application Portability Features
Applications written in ISO/ANSI languages are easily portable to other platforms that support them. OpenVMS VAX, OpenVMS Alpha, and OpenVMS I64 provide support for such languages as C, COBOL, and Fortran.
1.3.3. Distributed Computing Capabilities
In a distributed computing environment, an application is distributed over two or more systems or processors, each of which has its own autonomous operating environment. A distributed application is composed of separate modules, running on different systems, that communicate with each other by passing data between modules or by sharing access to files or databases. A distributed application must be able to coordinate its activities over a dispersed operating environment.
The distributed computing environment can consist of software located either in a single box or a single room or can comprise a worldwide network of computers. The systems in the distributed configuration can be uniprocessor, multiprocessor, or OpenVMS Cluster systems; systems from different vendors can be included in the same configuration.
1.3.3.1. Client/Server Style of Computing
A server is any system that provides a service or resource to other systems.
The client is the system requesting the service.
This style of computing allows each portion of a distributed application to run in its own optimal environment. The whole application does not have to run on one centralized system (such as a mainframe system), but enterprisewide cohesiveness can still be maintained. For example, individuals or local offices, using their own computers and running software appropriate to their needs, can be linked to large computers or OpenVMS Cluster systems in a network. A distributed computing system can function as though it were a single system that connects all parts of an enterprise. The client can have transparent access to the integrated resources of the enterprise.
Any system can be a client or a server, and some systems may include both client software for certain applications and server software for other applications. Servers can be connected to many clients, and a client can be connected to more than one server at a time. (Client and server relationships may change frequently: at times it may not be possible to tell which is the client and which is the server.) In some cases, the application is stored on the server and run on the client, using the resources of the client. The user, who does not need to know what system is serving the application, can function in a familiar, local environment.
1.3.3.2. OpenVMS Client/Server Capabilities
OpenVMS systems support a wide variety of client/server configurations. Clients requiring resources can be personal computers, workstations, point-of-sale devices, OpenVMS systems, or systems from other vendors that are running the appropriate client software. Users on client systems can use character-cell terminals or windowing desktops.
Servers fulfilling clients' requests can be located on OpenVMS systems or other operating systems running appropriate server software. OpenVMS servers, for example, can provide file access, printing, application services, communication services, and computing power as application engines to clients on desktop devices or in laboratories or factories. Client/server configurations permit the commercial-strength capabilities of OpenVMS host systems to be integrated with the personal-computing capabilities of desktop systems.
Middleware, which runs on OpenVMS and other systems from multiple vendors, can be used to tie together clients and servers. Middleware integrates various client and server systems through application, communication, data interchange, and multivendor support. Complex information-sharing environments involving PC clients and operating system servers are supported.
An essential feature of the OpenVMS operating system is its support of a rich environment for developing software application programs. The programming software integrated in the OpenVMS system provides the tools required to effectively develop new software applications. You also have the option of using additional powerful tools to enhance the productivity of software development in the OpenVMS environment.
The following sections summarize the primary program development features available on all three supported platforms. The sections also introduce the OpenVMS programming environment and present brief functional descriptions of the OpenVMS programming tools.
1.4. The OpenVMS Programming Environment
The OpenVMS system supports a flexible programming environment that offers a wide range of tools and resources to support efficient program development. This robust OpenVMS programming environment permits the development of mixed-language application programs and portable programs, as well as application programs with distributed functions that run in client/server environments. This environment also provides tools that allow you to use the web and other information technologies.
Creating, controlling, and deleting processes
Communicating with other components
Sharing resources
Implementing input/output procedures
Using security features
Managing memory
Managing files
Synchronizing events
Providing for condition handling
Calling utility routines
Language compilers, interpreters, and assemblers
Linkers and debuggers
Text processors and other program development utilities
Callable system routines such as run-time routines, system services, and other utility routines
Record Management Services (RMS) routines and utilities
Optional software development tools that run on the OpenVMS system enhance programmer productivity, saving programming time and promoting the development of error-free code. OpenVMS supports optional integrated software products that enhance program development capabilities in an organization. These software development products can make use of middleware services that facilitate the development of applications for multivendor networks and for web-enabling tools to help develop client/server applications.
Provide web access to data
Provide web access to applications
Provide web tools for commercial web servers
Provide other web tools including freeware
Middleware products and capabilities include Distributed Computing Environment (DCE), COM for OpenVMS, and Reliable Transaction Router for OpenVMS. Web-enabling tools include DECforms Web Connector, and TP Web Connector.
1.4.1. Programming to Standards
Coding of programs for the OpenVMS environment and for other environments involves conforming to software development standards. OpenVMS standards that define modular programming techniques and procedure calling and condition handling practices pertain to applications specific to OpenVMS. IEEE and international standards apply to applications developed on OpenVMS that are designed to run on other systems as well as on OpenVMS.
1.4.1.1. Common Environment for Writing Code
OpenVMS software programmers can write code in a common environment, following standard OpenVMS modular programming practices. This standard approach establishes the minimum criteria necessary to ensure the correct interface at the procedure level between software written by different programmers. If all programmers coding OpenVMS applications follow this standard approach, modular procedures added to a procedure library will not conflict with other procedures in the library. Standard modular programming practices apply to OpenVMS programs that have a public entry point. For details of this standard approach, see the Guide to Creating OpenVMS Modular Procedures.
1.4.1.2. Common Language Environment
The OpenVMS system supports a common language environment, which permits using a mixture of languages in programming. A program written in any of the programming languages supported by OpenVMS can contain calls to procedures written in other supported languages. Mixed-language programming is possible because all supported languages adhere to the OpenVMS calling standard. This standard describes the techniques used by all supported languages for invoking routines and passing data between them. It also defines the mechanisms that ensure consistency in error and exception handling routines, regardless of the mix of programming languages. Information about the calling standard appears in the VSI OpenVMS Calling Standard, and descriptions of how to use the calling interface are given in VSI OpenVMS Programming Concepts Manual, Volume II.
1.5. OpenVMS Programming Software
This section describes the integrated programming tools available on the OpenVMS operating system to help implement software development.
The phases of a typical software development life cycle can include proposal of the concept; formulation of requirements and specifications for the software product; design, implementation, and testing of the software; and integration and maintenance of the product. Implementing the software product involves building and modifying source code modules and compiling, linking, and executing the resulting images. Testing involves refining code to optimize performance.
Type of Software |
OpenVMS Software Components |
---|---|
Text processors |
|
Major programming utilities |
|
Other program development utilities |
|
Callable system routines |
|
The commands used to invoke some of the programming utilities (for example, linker, debugger, LIBRARIAN) vary slightly for the three supported platforms.
1.5.1. Creating Program Source Files
OpenVMS text-processing utilities can be used to create and modify program source files. The DEC Text Processing Utility (DECTPU) is a high-performance text processor that can be used to create text-editing interfaces such as EVE. DECTPU includes a high-level procedure language with its own compiler and interpreter, as well as the customizable EVE editing interface. DECTPU features multiple buffers, windows, and subprocesses, and provides for text processing in batch mode. The EDT editor is an interactive text editor that provides editing in keypad and line modes. EDT supports multiple buffers, startup command files, and journaling. In general, the EVE editing interface offers more capability than EDT for complex editing tasks.
The vi editor is a display-oriented interactive text editor used in the POSIX for OpenVMS environment. POSIX also supports the ed and ex editors.
Other optional tools for creating source files on OpenVMS systems are available separately or as part of the VSI software development environment. The Language-Sensitive Editor/Source Code Analyzer for OpenVMS (LSE/SCA) provides a multilanguage, multivendor editor for program development and maintenance and also supplies cross-referencing features and the capability to analyze source code.
1.5.2. Creating Object Files
OpenVMS supports a variety of optional language compilers, interpreters, and assemblers that translate source code to object code (in the form of object modules). These language implementations adhere to industry standards, including ISO, ANSI, and X/Open standards as well as U.S. Federal Information Processing Standards (FIPS) and Military Standards (MIL-STD), as applicable.
Language | Characteristics |
---|---|
VSI Ada |
Complete production-quality implementation of Ada language; fully conforms to ANSI and MIL-STD standards; has Ada validation. |
VAX APL |
Interpreter with built-in editor, debugger, file system, communication facility. |
VAX BASIC |
Either an interpreter or a compiler; fully supported by the OpenVMS debugger; fully reentrant code. |
VSI BASIC for OpenVMS |
An optimizing compiler; highly compatible with VAX BASIC; no environment or interpreter support; also available on I64. |
BLISS-32 for OpenVMS |
Advanced set of language features supporting development of modular software according to structured programming concepts; also available on I64. |
BLISS-64 for OpenVMS |
Development of modular software support for 64-bit programs; not available on VAX. |
VAX C |
Full implementation of C programming language with added features for performance enhancement in the OpenVMS environment. |
VSI C for OpenVMS Alpha and I64 systems |
Compliant with ANSI/ISO C International Standard with VSI extensions; includes standard-conformance checking and many optional code-quality and portability diagnostics; supports 64-bit virtual addressing; generates optimized and position-independent code. |
VSI C++ for OpenVMS Alpha and I64 systems |
Compliant with ANSI/ISO C++ International Standard with VSI extensions; supports the ARM, GNU, and MS dialects; supports 64-bit virtual addressing; generates highly optimized object code; facilitates object-oriented program design. |
VSI COBOL for OpenVMS |
Compliant with ANSI-standard COBOL; includes as enhancements screen-handling, file-sharing, and report-writing facilities; is supported on I64. |
VAX DIBOL |
For interactive data processing; includes a compiler, debugger, and utility programs for data handling, data storing, and interprogram communication. |
VSI Fortran 77 for OpenVMS VAX |
Extended implementation of full language FORTRAN-77, conforming to American National Standard FORTRAN, ANSI X3.9-1978. It includes optional support for programs conforming to ANSI X3.9-1966 (FORTRAN IV) and meets Federal Information Processing Standard Publication FIPS-69-1 and MIL-STD-1753. |
VSI Fortran for OpenVMS |
ANSI-standard Fortran 90 and Fortran 95 optimizing compiler; available on I64 and Alpha systems. |
VAX MACRO |
Assembly language for programming the VAX computer under the OpenVMS operating system; uses all OpenVMS resources; supports large instruction set enabling complex programming statements. |
MACRO-32 Compiler |
Available on OpenVMS I64 and Alpha systems to port existing VAX MACRO code to an Alpha or I64 system. |
MACRO-64 Assembler |
Available on OpenVMS Alpha systems; a RISC assembly language that provides precise control of instructions and data. |
VSI Pascal for OpenVMS |
ANSI-standard Pascal features and language extensions that go beyond the standard; available on VAX, Alpha, and I64. |
1.5.3. Creating Runnable Programs
After a program source file is coded, it must be compiled or assembled into object modules by a language processor and then linked. The OpenVMS Linker binds the object modules into an image that can be executed on the OpenVMS operating system.
The linker processes object modules and shareable image files, as well as symbol table files, library files, and options files (used to manage the linking operation and simplify the use of complex, repetitious linker operations). The most common output of the linker is an executable image of the program. The linker can also produce a shareable image, a system image, an image map, or a symbol table file to be used by other programs being linked. Certain linking tasks, such as creating shareable images, are performed differently on OpenVMS VAX than on OpenVMS Alpha and OpenVMS I64 systems.
The Librarian utility provides for efficient storage in central, easily accessible files of object modules, image files, macros, help text, or other record-oriented information.
1.5.4. Testing and Debugging Programs
The debugger allows users to trace program execution and to display and modify register contents using the same symbols as are in the source code.
The OpenVMS Debugger (debugger), which debugs user-mode code.
TheDelta/XDelta Debugger (DELTA/XDELTA), which debugs code in other modes as well as user mode. (The DELTA debugger has not yet been ported to the OpenVMS I64 operating system).
The OpenVMS symbolic debugger is more useful than DELTA/XDELTA for most programs: the symbolic commands entered using different interfaces (keypad, command line, or file of commands) display source code lines on the screen, have more descriptive error messages, and provide help information.
Control program execution on a line-by-line basis or at a user-specified breakpoint
Display breakpoints, tracepoints, watchpoints, active routine calls, stack contents, variables, symbols, source code, and source directory search list
Define symbols
Create key definitions
Change values in variables
Evaluate a language or address expression
Create or execute debugger command procedures
The OpenVMS symbolic debugger provides enhanced support for programs that have multiple threads of execution within an OpenVMS process, including any program that uses POSIX Threads Library for developing real-time applications.
The debugger has been modified to support debugging of programs that contain 64-bit data addresses.
An additional debugger utility is available only on an OpenVMS Alpha system: the OpenVMS Alpha System-Code Debugger, which can be used to debug non-pageable system code and device drivers. The system-code debugger is a symbolic debugger that lets the user employ the familiar OpenVMS Debugger interface to observe and manipulate system code interactively as it executes. The system-code debugger can display the source code where the software is executing and allows the user to advance by source line.
Control the system software's execution, stopping at points of interest, resuming execution, intercepting fatal exceptions, and so on
Trace the execution path of the system software
Monitor exception conditions
Examine and modify the value of variables
In some cases, test the effect of modifications without having to edit the source code, recompile, and relink
You can use the OpenVMS Alpha System-Code Debugger to debug code written in the following languages: C, BLISS, and MACRO. Information about using the system-code debugger and how it differs from the OpenVMS Debugger is given in Writing OpenVMS Alpha Device Drivers in C.
1.5.4.1. Special Modes of Operation for Debugging
MULTIPROCESSING
POOLCHECK
BUGCHECKFATAL
SYSTEM_CHECK
MULTIPROCESSING is useful for debugging privileged code that uses spinlocks, such as device driver code. POOLCHECK is useful for investigating frequent and inexplicable failures in a system. When POOLCHECK is enabled, pool-checking routines execute whenever pool is deallocated or allocated. BUGCHECKFATAL is useful for debugging the executive. SYSTEM_CHECK turns on the previous three system parameters and also activates other software that aids in detecting problems. It enables a number of run-time consistency checks on system operation and records some trace information.
If you are using one of these special modes, for example, to debug a device driver or other complex application, under certain conditions generally related to high I/O loads, it is possible to incur a CPUSPINWAIT bugcheck. To prevent a CPUSPINWAIT bugcheck, use either the system default settings for these system parameters, or reduce the loading of the system.
If you have reason to change the default settings, you can reduce the likelihood of encountering a problem by setting the SMP_LNGSPINWAIT system parameter to a value of 9000000.
1.5.5. Using Other Program Development Utilities
Utility | Function |
---|---|
Command Definition Utility (CDU) |
Enables an application developer to create commands with a syntax similar to DIGITAL Command Language (DCL) commands. |
Message utility |
Permits user to create application messages to supplement the OpenVMS system messages. |
Patch utility? |
Permits users to make changes (in the form of patches) to an image or data file. If the change was made to an image, the new version can then be run without recompiling or relinking. |
SUMSLP utility |
Supplies batch-oriented editor used to make several updates to a single source file; one update program can be applied to all versions of a file. |
National character set utility |
Permits users to define non-ASCII string collating sequences and to define conversion functions; allows an RMS indexed file to be collated using user-specified collating sequences. |
System Dump Analyzer utility |
Determines the cause of system failures; reads the crash dump file and formats and displays it; also used to diagnose root causes that lead to an error. |
1.5.6. Managing Software Development Tasks
VSI Code Management System (CMS) for OpenVMS provides an efficient method of storing project files (such as documents, object files, and other records) and tracking all changes to these files.
VSI Module Management System (MMS) for OpenVMS automates building of software applications.
1.6. Using Callable System Routines
OpenVMS provides extensive libraries of prewritten and debugged routines that can be accessed by programs. Libraries specific to the supported platforms supply commonly needed routines optimized for the OpenVMS environment; these libraries include run-time library routines, system services, utility routines, and RMS services. These libraries are described in this section.
1.6.1. Using the POSIX Threads Library Routines
OpenVMS includes a user-mode, multithreading capability called POSIX Threads Library. POSIX Threads Library provides a POSIX 1003.1-1996 standard style threads interface. Additionally, POSIX Threads Library provides an interface that is the OpenVMS implementation of Distributed Computing Environment (DCE) threads as defined by The Open Group.
POSIX Threads Library is a library of run-time routines that allows the user to create multiple threads of execution within a single address space. With POSIX Threads Library Kernel Threads features enabled, POSIX Threads Library provides for concurrent processing across all CPUs by allowing a multithreaded application to have a thread executing on every CPU (on both symmetric and asymmetric multiprocessor systems). Multithreading allows computation activity to overlap I/O activity. Synchronization elements, such as mutexes and condition variables, are provided to help ensure that shared resources are accessed correctly. For scheduling and prioritizing threads, POSIX Threads Library provides multiple scheduling policies. For debugging multithreaded applications, POSIX Threads Library is supported by the OpenVMS Debugger. POSIX Threads Library also provides Thread Independent Services (TIS), which assist in the development of threadsafe APIs.
On OpenVMS Alpha and OpenVMS I64 systems, POSIX threads provide support to accept 64-bit parameters.
General threads
Object attributes
Mutex
Condition variable
Thread context
Thread cancellation
Thread priority and scheduling
Debugging
For more information about threads, see the Guide to POSIX Threads Library.
1.6.2. Using OpenVMS Run-Time Library Routines
The OpenVMS Run-Time Library (RTL) is a set of language-independent procedures for programs to be run specifically in the OpenVMS environment. RTL routines establish a common run-time environment for application programs written in any language supported in the OpenVMS common language environment. RTL procedures adhere to the OpenVMS calling standard and can be called from any program or program module in a language supported by OpenVMS (see Section 1.5.2, “Creating Object Files”).
Routine |
Description |
---|---|
LIB$ routines |
Library routines that perform generally needed system functions such as resource allocation and common I/O procedures; provide support for 64-bit virtual addressing on Alpha and I64 systems. |
MTH$ routines? |
Math routines that perform arithmetic, algebraic, and trigonometric functions. |
DPML$ routines |
Portable Mathematics Library for OpenVMS Alpha and OpenVMS I64; a set of highly accurate mathematical functions. |
OTS$ routines |
Language-independent routines that perform tasks such as data conversion. |
SMG$ routines |
Screen management routines used in the design of complex images on a video screen. |
STR$ routines |
String manipulation routines. |
In addition, language-specific RTL routines support procedures in Ada, BASIC, C, COBOL, Fortran, Pascal, and PL/I (VAX only) as well as in POSIX C. VSI C RTL routines support 64-bit programming on OpenVMS Alpha and OpenVMS I64 systems.
CXML is a collection of mathematical routines optimized for Alpha systems. These subroutines perform numerically intensive operations that occur frequently in engineering and scientific computing, such as linear algebra and signal processing. CXML can help reduce the cost of computation, enhance portability, and improve productivity.
1.6.3. Using OpenVMS System Services
OpenVMS system services are procedures that control resources available to processes, provide for communication among processes, and perform basic operating system functions such as I/O coordination. Application programs can call OpenVMS system services to perform the same operations that the system services provide for the OpenVMS operating system (for example, creating a process or subprocess).
At run time, an application program calls a system service and passes control of the process to it. After execution of the system service, the service returns control to the program and also returns a condition value. The program analyzes the condition value, determines the success or failure of the system service call, and alters program execution flow as required.
Service Group | Function |
---|---|
Security |
Provides mechanisms to enhance and control system security |
Event flag |
Clears, sets, and reads event flags; places process in wait state until flags are set |
AST |
Controls handling of software interrupts called asynchronous system traps (ASTs) |
Logical names |
Provide a generalized logical name service |
Input/output |
Performs input and output operations directly at the device driver level, bypassing RMS |
Process control |
Creates, deletes, and controls the execution of processes (on a clusterwide basis); permits a process on one node to request creation of a detached process on another node |
Process information |
Provides information about processes |
Timer and time conversion |
Permits scheduling of program events at specific times or time intervals; supplies binary time values |
Condition handling |
Designates condition-handling procedures that gain control when an exception/condition occurs |
Memory management |
Permits control of an application program's virtual address space |
Change mode |
Changes the access mode of a process |
Lock management |
Permits cooperating processes to synchronize their access to shared resources |
DECdtm services |
Provide for complete and consistent execution of distributed transactions and for data integrity |
Cluster event notification? |
Requests notification when an OpenVMS Cluster configuration event occurs |
OpenVMS I/O system services perform logical, physical, and virtual I/O and network operations, and queue messages to system processes. The $QIO system service provides a direct interface to the operating system's I/O routines. These services are available from within most programming languages supported by OpenVMS and can be used to perform low-level I/O operations efficiently with a minimal amount of system overhead for time-critical applications.
On OpenVMS Alpha and OpenVMS I64 systems, new system services provide access to 64-bit virtual address space for process private use. Additionally, new system services are available to provide high CPU performance and improved symmetric multiprocessing (SMP) scaling of I/O operations. These services exhibit high-performance gains over the $QIO service.
DECdtm services ensure consistent execution of applications on the OpenVMS operating system. In transaction processing applications, many users may be simultaneously making inquiries and updating a database. The distributed transaction processing environment typically involves communication between networked systems at different locations. DECdtm services coordinate distributed transactions by using the two-phase commit protocol and implementing special logging and communication techniques. DECdtm services ensure that all parts of a transaction are completed or the transaction is aborted.
1.6.4. Using OpenVMS Utility Routines
Routine |
Utility/Facility |
---|---|
ACL$ |
Access control list editor (ACL editor) |
CLI$ |
Command Definition Utility (CDU) |
CONV$ |
Convert and Convert/Reclaim utilities (CONVERT and CONVERT/RECLAIM) |
DCX$ |
Data Compression/Expansion facility (DCX) |
EDT$ |
EDT editor |
FDL$ |
File Definition Language utility (FDL) |
LBR$ |
Librarian utility (LIBRARIAN) |
LGI$ |
LOGINOUT routines |
MAIL$ |
Mail utility (MAIL) |
NCS$ |
National Character Set utility (NCS) |
PSM$ |
Print Symbiont Modification facility (PSM) |
SMB$ |
Symbiont/Job-Controller Interface facility (SMB) |
SOR$ |
Sort/Merge utility (SORT/MERGE) |
TPU$ |
DEC Text Processing Utility (DECTPU) |
You can use an optional, portable library of user-callable routines to perform high-performance sorting on OpenVMS Alpha systems. The high-performance sort supports a subset of the functionality present on the OpenVMS Sort/Merge utility, using the callable interface to the SOR$ routine. The high-performance sort/merge provides better performance for most sort and merge operations.
1.7. Programming User Interfaces
User interfaces to the OpenVMS VAX, OpenVMS Alpha, and OpenVMS I64 operating systems include the DCL interface and the optional DECwindows Motif for OpenVMS graphical user interface. Another user interface is through electronic forms.
You can use DCL commands to invoke program development software (compilers, editors, linkers) and to run and control execution of programs. You can use DCL command procedures to perform repetitious operations in software development.
The Command Definition Utility (CDU) enables application developers to create DCL-level commands with a syntax similar to OpenVMS DCL commands. Using CDU, the developer can create applications with user interfaces similar to those of operating system applications. The Message utility permits an application developer to create application messages to supplement the system messages supplied by the OpenVMS operating system.
The DECwindows Motif for OpenVMS software provides a consistent user interface for developing software applications and includes an extensive set of programming libraries and tools. DECwindows Motif for OpenVMS supports both the OSF/Motif standards-based graphical user interface and the X user interface (XUI) in a single run-time and development environment. DECwindows Motif requires a DECwindows X11 display server (device driver and fonts) that supports the portable compiled format (PCF), permitting use of vendor-independent fonts.
A user interface toolkit composed of graphical user interface objects (widgets and gadgets); widgets provide advanced programming capabilities that permit users to create graphic applications; gadgets, similar to widgets, require less memory to create labels, buttons, and separators
A user interface language to describe visual aspects of objects (menus, labels, forms) and to specify changes resulting from user interaction
The OSF/Motif Window Manager, which allows users to customize the interface
Standard X Window System libraries such as Xlib and the intrinsics
Libraries needed to support the current base of XUI applications
OSF/Motif toolkit support for developing applications using the Motif user interface style
VSI libraries that give users capabilities beyond the standards
1.8. Optional VSI Software Development Tools
VSI supplies optional software development tools for the OpenVMS environment, such as DECset. DECset is a set of tools that supports software coding, testing, and maintenance of applications and data. These tools can be used individually or as part of the optional VSI software development environment.
1.9. Managing Data
The basic OpenVMS tool for transparent, intuitive management of data is the Record Management Services (RMS) subsystem. RMS is a collection of routines that gives programmers a device-independent method for storing, retrieving, and modifying data for their application. RMS also provides extensive protection and reliability features to ensure data integrity.
RMS is a higher level interface to the file system and OpenVMS I/O subsystem. It is used by all products that run on OpenVMS VAX, OpenVMS Alpha, and OpenVMS I64 for file and record operations. A subset of RMS services permits network file operations that are generally transparent to the user.
On OpenVMS Alpha and OpenVMS I64 systems, RMS supports I/O operations to and from 64-bit addressable space.
1.9.1. RMS Files and Records
RMS supports a variety of file organizations, record formats, and record-access modes. RMS supports sequential, relative, and indexed disk file organizations, and fixed- and variable-length records. It supports a number of record-access modes: sequential, by key value, by relative record number, or by record file address. RMS is designed primarily for mass storage devices (disks and tapes), but also supports unit-record devices such as terminals or printers.
Creating new files, accessing existing files, extending disk space for files, closing files, and obtaining file characteristics
Getting, locating, inserting, updating, and deleting records in files
RMS promotes safe and efficient file sharing by providing multiple access modes, automatic record locking when applicable, and optional buffer sharing by multiple processes.
1.9.2. RMS Utilities
RMS file utilities allow users to analyze the internal structure of an RMS file and to determine the most appropriate set of parameters to tune an RMS file. RMS utilities can also be used to create, efficiently load, and reclaim space in an RMS file.
Analyze/RMS_File utility
File Definition Language utilities (Create/FDL and Edit/FDL)
Convert and Convert/Reclaim utilities
The Analyze/RMS_File utility allows the programmer to analyze the internal structure of an OpenVMS RMS file and generate a report on its structure and use, as well as interactively explore the file's structure. The utility can generate an FDL file from an RMS file for use with the Edit/FDL utility to optimize the data file.
File Definition Language (FDL) is a special-purpose language for specifying file characteristics; it is useful with higher level languages or for ensuring that files are properly tuned. FDL makes use of RMS control blocks: the file access block (FAB), the record access block (RAB), and the extended attribute block (XAB).
The Edit/FDL utility creates a new FDL file according to user specifications. The Create/FDL utility uses the specifications of an existing FDL file to create a new empty data file.
You can use the Convert utility to copy records from one file to another, while changing the record format and file organization, and to append records to an existing file. The Convert/Reclaim utility reclaims empty bucket space in an indexed file to allow new records to be written to it.
Part I. Process and Synchronization
This part describes the creation, communication, and control of processes. It also describes symmetric multiprocessing (SMP), and the synchronizing of data access, programming operations, and access to resources.
Chapter 2. Process Creation
This chapter describes process creation and the different types of processes. It also describes kernel threads and the kernel threads process structure.
2.1. Process Types
A process is the environment in which an image executes. Two types of processes can be created with the operating system: spawned subprocesses or detached processes.
A spawned subprocess is dependent on the process that created it (its parent), and receives a portion of its parent process's resource quotas. The system deletes the spawned subprocess when the parent process exits.
A detached process is independent of the process that created it. The process the system creates when you log in is, for example, a detached process. If you want a created process to continue after the parent exits, or not to share resources with the parent, use a detached process.
Characteristic |
Subprocess |
Detached Process |
---|---|---|
Privileges |
Received from creating process. |
Specified by creating process. |
Quotas and limits |
Some shared with creating process. |
Specified by creating process, but not shared with creating process. |
User authorization file |
Used for information not given by creating process. |
Used for most information not given by creating process. |
User identification code |
Received from creating process. |
Specified by creating process. |
Restrictions |
Exist as long as creating process exists. |
None. |
How created |
SYS$CREPRC, or LIB$SPAWN from another process. |
SYS$CREPRC from another process. |
When deleted |
When creating process exits, or at image exit or logout, depending on whether a CLI is present. |
At image exit or logout, depending on whether a CLI is present. |
Command language interpreter (CLI) present |
Usually not if created with SYS$CREPRC; always yes if spawned. |
Usually present, but not necessarily. |
2.2. Execution Context of a Process
Image that the process is executing
Input and output streams for the image executing in the process
Disk and directory defaults for the process
System resource quotas and user privileges available to the process
When the system creates a detached process as the result of a login, it uses the system user authorization file (SYSUAF.DAT) to determine the process's execution context.
The process created for you executes the image LOGINOUT.
The terminal you are using is established as the input, output, and error stream device for images that the process executes.
Your disk and directory defaults are taken from the user authorization file.
The resource quotas and privileges you have been granted by the system manager are associated with the created process.
A command language interpreter (CLI) is mapped into the created process.
2.3. Modes of Execution of a Process
Interactive—Receives input from a record-oriented device, such as a terminal or mailbox
Batch—Is created by the job controller and is not interactive
Network—Is created by the network ancillary control program (ACP)
Other—Is not running in any of the other modes (for example, a spawned subprocess where input is received from a command procedure)
2.4. Creating a Subprocess
You can create a subprocess using the LIB$SPAWN run-time library routines, the SYS$CREPRC system service, or the C system() call. A subprocess created with LIB$SPAWN is called a spawned subprocess.
2.4.1. Naming a Spawned Subprocess
As of OpenVMS Version 7.3-1, the way OpenVMS names spawned
subprocesses was changed to improve performance. Prior to OpenVMS
Version 7.3-1, if no process name was supplied, the system
constructed a name by appending _n
to the user
name, where n
was the next available nonduplicate
integer for any process currently in the system. For example, the
first spawned process from the SYSTEM would be called SYSTEM_1, the
second, SYSTEM_2, and so on. The next available number was chosen as
soon as a gap was found.
With OpenVMS Version 7.3-1, the default-constructed process name for subprocesses was changed. Instead of searching incrementally for the next unique number, a random number is chosen to append to the user name. Therefore, the first processes that are spawned from user SYSTEM might be SYSTEM_154, SYSTEM_42, SYSTEM_87, and so on. This procedure results in a very high probability of finding a unique name on the first try, because it is unlikely that the same number is already in use. This procedure greatly reduces the cost of process creation, and applications that rely on spawned subprocesses might see a dramatic performance improvement with this change.
However, some applications might rely on the prior method of assigning subprocess names. The DCL_CTLFLAGS parameter, a bitmask used to alter default behavior for certain commands on a systemwide basis, is available to allow you to configure the system as necessary. The low bit of the bitmask is defined, and it controls the default process-name assignment for a subprocess created using the SPAWN command or LIB$SPAWN routine.
If the bit is clear, the new behavior (beginning with OpenVMS Version 7.3-1) is used. If you do not specify a process name, the system assigns the user name with a random number suffix. This is the default setting.
If the bit is set, the old behavior is used. If you do not specify a process name, the system assigns the user name with the next available number.
2.4.2. Using LIB$SPAWN to Create a Spawned Subprocess
The LIB$SPAWN routine enables you to create a subprocess and to set some context options for the new subprocess. LIB$SPAWN creates a subprocess with the same priority as the parent process (generally priority 4). The format for LIB$SPAWN is:
LIB$SPAWN ([command_string],[input_file],[output_file],[flags],[process-name], [process_id],[completion_status],[completion_efn],[completion_astadr], [completion_astarg],[prompt],[cli])
For complete information on using each argument, refer to the LIB$SPAWN routine in VSI OpenVMS RTL Library (LIB$) Manual.
Specifying a Command String
Use the command_string
argument to specify a
single DCL command to execute once the subprocess is initiated. You
can also use this argument to execute a command procedure that, in
turn, executes several DCL commands
(@command_procedure_name).
Redefining SYS$INPUT and SYS$OUTPUT
Use the input_file
and
output_file
arguments to specify
alternate input and output devices for
SYS$INPUT and
SYS$OUTPUT. Using alternate values
for SYS$INPUT and
SYS$OUTPUT can be particularly
useful when you are synchronizing processes that are executing
concurrently.
Passing Parent Process Context Information to the Subprocess
Use the flags
argument to specify which
characteristics of the parent process are to be passed on to the
subprocess. With this argument, you can reduce the time required to
create a subprocess by passing only a part of the parent's context.
You can also specify whether the parent process should continue to
execute (execute concurrently) or wait until the subprocess has
completed execution (execute in line).
After the Subprocess Completes Execution
Use the completion_status
,
completion_efn
, and
completion_astadr
arguments to
specify the action to be taken when the subprocess completes
execution (send a completion status, set a local event flag, or
invoke an AST procedure). For more information about event flags and
ASTs, refer to Chapter 8, Using Asynchronous System Traps.
The LIB$SPAWN routine and SPAWN command do not return a completion status code of 0 from a subprocess command procedure.
The LIB$SPAWN routine can fail in a detached process as well, because it is dependent upon and requires the presence of a command language interpreter (CLI), such as DCL. Without a CLI present in the current process, this call fails with a"NOCLI, no CLI present to perform function" error. Note that a detached process may not have a CLI present.
You can use SYS$CREPRC in place of LIB$SPAWN; though with SYS$CREPRC the context of the parent process (symbols and logical names) is not propagated into the subprocess.
When using LIB$SPAWN asynchronously (with CLI$M_NOWAIT), you have to synchronize completion. For if the parent process should exit, all subprocesses exit, potentially resulting in an unexpected series of failures of all subprocesses of the exiting parent process.
Specifying an Alternate Prompt String
Use the prompt
argument to specify a prompt
string for the subprocess.
Specifying an Alternate Command Language Interpreter
Use the cli
argument to specify a command
language interpreter for the subprocess.
Examples of Creating Subprocesses
! Declare status and library routine INTEGER STATUS, LIB$SPAWN STATUS = LIB$SPAWN ('@COMMANDS')
#include <descrip.h> #include <lib$routines.h> #include <ssdef.h> #include <stsdef.h> main() { int RetStat; $DESCRIPTOR( CmdDsc, "@COMMANDS" ); RetStat = lib$spawn( &CmdDsc ); if (!$VMS_STATUS_SUCCESS( RetStat )) return RetStat; return SS$_NORMAL; }
! Mask for LIB$SPAWN INTEGER MASK EXTERNAL CLI$M_NOCLISYM, 2 CLI$M_NOLOGNAM, 2 CLI$M_NOKEYPAD ! Declare status and library routine INTEGER STATUS, LIB$SPAWN ! Set mask and call LIB$SPAWN MASK = %LOC(CLI$M_NOCLISYM) .OR. 2 %LOC(CLI$M_NOLOGNAM) .OR. 2 %LOC(CLI$M_NOKEYPAD) STATUS = LIB$SPAWN ('@COMMANDS.COM', 2 ,, 2 MASK)
#include <clidef.h> #include <descrip.h> #include <lib$routines.h> #include <ssdef.h> #include <stsdef.h> main() { int RetStat; int FlagsMask = CLI$M_NOCLISYM | CLI$M_NOLOGNAM | CLI$M_NOKEYPAD; $DESCRIPTOR( CmdDsc, "@COMMANDS.COM" ); RetStat = lib$spawn( &CmdDsc, 0, 0, &FlagsMask ); if (!$VMS_STATUS_SUCCESS( RetStat )) return RetStat; return SS$_NORMAL; }
! Mask for LIB$SPAWN EXTERNAL CLI$M_NOWAIT ! Declare status and library routine INTEGER STATUS, LIB$SPAWN STATUS = LIB$SPAWN ('RUN $DISK1:[USER.MATH]CALC', ! Image 2 'DATA84.IN', ! Input 2 'DATA84.RPT', ! Output 2 %LOC(CLI$M_NOWAIT)) ! Concurrent
#include <clidef.h> #include <descrip.h> #include <lib$routines.h> #include <ssdef.h> #include <stsdef.h> main() { int RetStat; int FlagsMask = CLI$M_NOWAIT; $DESCRIPTOR( CmdDsc, "RUN $DISK1:[USER.MATH]CALC" ); $DESCRIPTOR( InpDsc, "DATA84.IN" ); $DESCRIPTOR( OutDsc, "DATA84.RPT" ); RetStat = lib$spawn( &CmdDsc, &InpDsc, &OutDsc, &FlagsMask ); if (!$VMS_STATUS_SUCCESS( RetStat )) return RetStat; return SS$_NORMAL; }
2.4.3. Using the C system() Call
#include <ssdef.h>
#include <stdio.h>
#include <stdlib.h>
main()
{
printf("calling system() \n");
system("show system");
printf("done\n");
return SS$_NORMAL;
}
This example shows the use of the system() call to spawn a DCLSHOW SYSTEM command; it subsequently returns and the execution of the main() image continues.
2.4.4. Using SYS$CREPRC to Create a Subprocess
The Create Process (SYS$CREPRC) system
service creates both subprocesses and detached processes. This
section discusses creating a subprocess; Section 2.5, “Creating a Detached Process” describes creating a detached
process. When you call the SYS$CREPRC
system service to create a process, you define the context by
specifying arguments to the service. The number of subprocesses a
process can create is controlled by its
PQL$_PRCLM subprocess quota, an
individual quota description under the quota
argument.
Though SYS$CREPRC does not set many context values for the subprocess by default, it does allow you to set many more context values than LIB$SPAWN. For example, you cannot specify separate privileges for a subprocess with LIB$SPAWN directly, but you can with SYS$CREPRC.
By default, SYS$CREPRC creates a subprocess rather than a detached process. The format for SYS$CREPRC is as follows:
SYS$CREPRC ([pidadr] ,[image] ,[input] ,[output] ,[error] ,[prvadr] ,[quota], [prcnam] ,[baspri] ,[uic] ,[mbxunt] ,[stsflg] ,[itemlst] ,[node])
Ordinarily, when you create a subprocess, you need only assign it an image to execute and, optionally, the SYS$INPUT, SYS$OUTPUT, and SYS$ERROR devices. The system provides default values for the process's privileges, resource quotas, execution modes, and priority. In some cases, however, you may want to define these values specifically. The arguments to the SYS$CREPRC system service that control these characteristics follow. For details, see the descriptions of arguments to the SYS$CREPRC system service in the VSI OpenVMS System Services Reference Manual.
The default values passed into the subprocess might not be complete enough for your use. The following sections describe how to modify these default values with SYS$CREPRC.
Redefining SYS$INPUT, SYS$OUTPUT, and SYS$ERROR
Use the input
, output
,
and error
arguments to specify alternate
input, output, and error devices for
SYS$INPUT,
SYS$OUTPUT, and
SYS$ERROR. Using alternate values
for SYS$INPUT,
SYS$OUTPUT, and
SYS$ERROR can be particularly
useful when you are synchronizing processes that are executing
concurrently. By providing alternate equivalence names for the
logical names SYS$INPUT,
SYS$OUTPUT, and
SYS$ERROR, you can place these
logical name/equivalence name pairs in the process logical name
table for the created process.
#include <descrip.h> #include <ssdef.h> #include <starlet.h> #include <stdio.h> #include <stsdef.h> // Comment syntax here assumes compiler support main() { int RetStat; $DESCRIPTOR(input,"SUB_MAIL_BOX"); // Descriptor for input stream $DESCRIPTOR(output,"COMPUTE_OUT"); // Descriptor for output and error $DESCRIPTOR(image,"COMPUTE.EXE"); // Descriptor for image name // Create the subprocess RetStat = sys$creprc( 0, // process id &image, // image &input, // input SYS$INPUT device &output, // output SYS$OUTPUT device &output, // error SYS$ERROR device 0,0,0,0,0,0,0); if (!$VMS_STATUS_SUCCESS( RetStat )) return RetStat; return SS$_NORMAL; } }
The | |
The | |
The |
The SYS$CREPRC system service does not provide default equivalence names for the logical names SYS$INPUT, SYS$OUTPUT, and SYS$ERROR. If none are specified, any entries in the group or system logical name tables, if any, may provide equivalences. If, while the subprocess executes, it reads or writes to one of these logical devices and no equivalence name exists, an error condition results.
The SYS$CREPRC system service also does not provide default equivalence names for the logical names SYS$LOGIN, SYS$LOGIN_DEVICE, and SYS$SCRATCH. These logical names are available to the created process only when the specified image is LOGINOUT, and when the PRC$M_NOUAF flag is not set.
Use the Get Device/Volume Information (SYS$GETDVIW) system service to obtain the device name for the logical name SYS$INPUT, SYS$OUTPUT, or SYS$ERROR.
Specify the address of the descriptor returned by the SYS$GETDVIW service when you specify the
input
,output
, orerror
argument to the SYS$CREPRC system service.
#include <descrip.h> #include <dvidef.h> #include <efndef.h> #include <lib$routines.h> #include <ssdef.h> #include <starlet.h> #include <stdio.h> #include <stsdef.h> // Comment syntax used here assumes compiler support main() { #define MAXTERMLEN 64 #define MAXITMLST 3 char TermName[MAXTERMLEN]; int BasPri = 4; int RetStat; int TermLen; unsigned short int IOSB[4]; // ItemList data structures used to acquire device name int i; struct { unsigned short int BufLen; unsigned short int ItmCod; void *BufAdr; void *BufRLA; } ItmLst[MAXITMLST]; // Descriptors for sys$getdviw call $DESCRIPTOR( SysInput, "SYS$INPUT" ); // Descriptors for sys$creprc call $DESCRIPTOR( ImageDesc,"SYS$SYSTEM:LOGINOUT.EXE"); struct dsc$descriptor TermDesc = { MAXTERMLEN, DSC$K_DTYPE_T, DSC$K_CLASS_S, TermName }; // Assign values to the item list i = 0; ItmLst[i].BufLen = MAXTERMLEN; ItmLst[i].ItmCod = DVI$_DEVNAM; ItmLst[i].BufAdr = &TermName; ItmLst[i++].BufRLA = &TermLen; ItmLst[i].BufLen = 0; ItmLst[i].ItmCod = 0; ItmLst[i].BufAdr = NULL; ItmLst[i++].BufRLA = NULL; // Acquire the terminal device name RetStat = sys$getdviw( EFN$C_ENF, // no event flag needed here 0, // Channel (not needed here) &SysInput, // Device Name ItmLst, // item list IOSB, // Address of I/O Status Block 0,0,0); if (!$VMS_STATUS_SUCCESS( RetStat )) lib$signal( RetStat ); if (!$VMS_STATUS_SUCCESS( IOSB[0] )) lib$signal( IOSB[0] ); // Create the subprocess RetStat = sys$creprc( 0, &ImageDesc, // The image to be run &TermDesc, // Input (SYS$INPUT device) &TermDesc, // Output (SYS$OUTPUT device) &TermDesc, // Error (SYS$ERROR device) 0,0,0, &BasPri, // Process base priority 0,0,0); if (!$VMS_STATUS_SUCCESS( RetStat )) lib$signal( RetStat ); return SS$_NORMAL; }
Use OpenVMS RMS to open the device for reading or writing, or both.
Use the Assign I/O Channel (SYS$ASSIGN) system service to assign an I/O channel to the device for input/output operations.
int RetStat; unsigned short int IOchan; $DESCRIPTOR(DevNam,"SYS$OUTPUT"); . . . RetStat = sys$assign( &DevNam, /* Device name */ &IOchan, /* Channel */ 0, 0, 0); if ($!VMS_STATUS_SUCCESS( RetStat )) return RetStat;
For more information about channel assignment for I/O operations, see VSI OpenVMS Programming Concepts Manual, Volume II.
Setting Privileges
Set different privileges by defining the privilege list for the
subprocess using the prvadr
argument. This is
particularly useful when you want to dedicate a subprocess to
execute privileged or sensitive code. If you do not specify this
argument, the privileges of the calling process are used. If you
specify the prvadr
argument, only the
privileges specified in the bit mask are used; the privileges of the
calling process are not used. For example, a creating process has
the user privileges GROUP and TMPMBX. It creates a process,
specifying the user privilege TMPMBX. The created process receives
only the user privilege TMPMBX; it does not have the user privilege
GROUP.
If you need to create a process that has a privilege that is not one of the privileges of your current process, you must have the user privilege SETPRV.
unsigned int PrivQuad[2] = { (PRV$M_GRPNAM | PRV$M_GROUP), 0}; // could also use: __int64 PrivQuad = PRV$M_GRPNAM | PRV$M_GROUP;
Setting Process Quotas
Set different process quotas by defining the quota list of system
resources for the subprocess using the quota
argument. This option can be useful when managing a subprocess to
limit use of system resources (such as AST usage, I/O, CPU time,
lock requests, and working set size and expansion). If you do not
specify this argument, the system defines default quotas for the
subprocess.
#pragma environment save #pragma nomember_alignment struct { unsigned char pql_code; unsigned long int pql_value; } pql[] = { { PQL$_ASTLM, 600 }, { PQL$_BIOLM, 100 }, { PQL$_BYTLM, 131072 }, { PQL$_CPULM, 0 }, { PQL$_DIOLM, 100 }, { PQL$_FILLM, 50 }, { PQL$_PGFLQUOTA, 40960 }, { PQL$_PRCLM, 16 }, { PQL$_TQELM, 600 }, { PQL$_WSDEFAULT, 512 }, { PQL$_WSQUOTA, 2048 }, { PQL$_ENQLM, 600 }, { PQL$_WSEXTENT, 4096 }, { PQL$_JTQUOTA, 4096 }, { PQL$_LISTEND, 0 } }; #pragma environment restore
For more information about process quotas and process quota lists, see Section 2.6, “Process Quota Lists”.
Setting the Subprocess Priority
Set the subprocess priority by setting the base execution priority
with the baspri
argument. If you do not set
the subprocess priority, the priority defaults to 2 for MACRO and
BLISS and to 0 for all other languages. If you want a subprocess to
have a higher priority than its creator, you must have the user
privilege ALTPRI to raise the priority level.
Specifying Additional Processing Options
Enable and disable parent and subprocess wait mode, control process
swapping, control process accounting, control process dump
information, control authorization checks, and control working set
adjustments using the stsflg
argument. This
argument defines the status flag, a set of bits that controls some
execution characteristics of the created process, including resource
wait mode and process swap mode.
Defining an Image for a Subprocess to Execute
image
argument to provide the process
with the name of an image to execute. For example, the following
lines of C create a subprocess to execute the image named
CARRIE.EXE:$DESCRIPTOR(image,"CARRIE"); . . . RetStat = sys$creprc(0, &image, ...);
In this example, only a file name is specified; the service uses current disk and directory defaults, performs logical name translation, uses the default file type .EXE, and locates the most recent version of the image file. When the subprocess completes execution of the image, the subprocess is deleted. Process deletion is described in Chapter 4, Process Control.
2.4.4.1. Disk and Directory Defaults for Created Processes
When you use the SYS$CREPRC system service to create a process to execute an image, the system locates the image file in the default device and directory of the created process. Any created process inherits the current default device and directory of its creator.
If a created process runs an image that is not in its default directory, you must identify the directory and, if necessary, the device in the file specification of the image to be run.
There is no way to define a default device or directory for the created process that is different from that of the creating process in a call to SYS$CREPRC. The created process can, however, define an equivalence for the logical device SYS$DISK by calling the Create Logical Name ($CRELNM) system service.
If the process is a subprocess, you, in the creating process, can define an equivalence name in the group logical name table, job logical name table, or any logical name table shared by the creating process and the subprocess. The created process then uses this logical name translation as its default directory. The created process can also set its own default directory by calling the OpenVMS RMS default directory system service, SYS$SETDDIR.
Make a call to SYS$SETDDIR to change its own default directory.
Make a call to SYS$CREPRC to create the new process.
Make a call to SYS$SETDDIR to change its own default directory back to the default directory it had before the first call to SYS$SETDDIR.
The creating process now has its original default directory. The new process has the different default directory that the creating process had when it created the new process. If the default device is to change, you must also redefine the SYS$DISK logical name. For details on how to call SYS$SETDDIR, see the VSI OpenVMS System Services Reference Manual.
2.5. Creating a Detached Process
The creation of a detached process is primarily a task the operating system performs when you log in. In general, an application creates a detached process only when a program must continue executing after the parent process exits. To do this, you should use the SYS$CREPRC system service.
You can use the uic
argument to the
SYS$CREPRC system service to define whether
a process is a subprocess or a detached process. The
uic
argument provides the created process
with a user identification code (UIC). If you omit the
uic
argument, the
SYS$CREPRC system service creates a
subprocess that executes under the UIC of the creating process. If you
specify a uic
argument with the same UIC as the
creating process, the system service creates a detached process with the
same UIC as the creating process.
You can also create a detached process with the same UIC as the creating
process by specifying the detach flag in the stsflg
argument. You do not need the IMPERSONATE privilege to create a detached
process with the same UIC as the creating process. The IMPERSONATE privilege
controls the ability to create a detached process with a UIC that is
different from the UIC of the creating process.
Examples of Creating a Detached Process
EXTERNAL PRC$M_DETACH ! Declare status and system routines INTEGER STATUS,SYS$CREPRC . . . STATUS = SYS$CREPRC (, 2 'SYS$USER:[ACCOUNT]INCTAXES', ! Image 2 'TAXES.DAT', ! SYS$INPUT 2 'TAXES.RPT', ! SYS$OUTPUT 2 ,,,, 2 %VAL(4), ! Priority 2 ,, 2 %VAL(%LOC(PRC$M_DETACH))) ! Detached
. . . STATUS = SYS$CREPRC (, 2 'SYS$SYSTEM:LOGINOUT', ! Image 2 'SYS$USER:[TEST]COMMANDS.COM',! SYS$INPUT 2 'SYS$USER:[TEST]OUTPUT.DAT', ! SYS$OUTPUT 2 ,,,, 2 %VAL(4), ! Priority 2 ,, 2 %VAL(%LOC(PRC$M_DETACH))) ! Detached
2.6. Process Quota Lists
The SYS$CREPRC system service uses the
quota
argument to create a process quota list
(PQL). Individual quota items such as paging file quota (PQL_PGFLQUOTA) and
timer queue entry quota (PQL_TQELM) of the
SYS$CREPRC system service make up the PQL.
In allocating the PQL, SYS$CREPRC constructs a
default PQL for the process being created, assigning it the default values
for all individual quota items. Default values are SYSGEN parameters and so
can be changed from system to system. SYS$CREPRC
then reads the specified quota list, if any is indicated, and updates the
corresponding items in the default PQL. Any missing values are filled in
from the default items (PQL_D xxxxx
) SYSGEN parameter,
where xxxxx are the characters of the quota name that follow
PQL$_ in the quota name. The PQL is then
complete.
The SYS$CREPRC service next reads the PQL, comparing
each value against the corresponding minimum (PQL_M
xxxxx
) SYSGEN parameter. If the SYSGEN parameter is
greater than the resulting value, SYS$CREPRC
replaces it with the SYSGEN value. Thus no process on the system has a quota
value lower than the minimum (PQL_M xxxxx
) SYSGEN
parameter.
The SYS$CREPRC service also determines what kind of
process is being created — whether batch, interactive, or detached. If
it is a batch or interactive process, the process derives all its quotas
from the user authorization file (UAF) and completely overwrites the PQL.
These quotas are unaffected by the default (PQL_D xxxxx
)
SYSGEN parameters, but are affected by the minimum (PQL_M
xxxxx
) values. If the process is a detached
process, it determines what items have been passed in the quota list and
only then overwrites these items in the PQL.
SYS$CREPRC makes sure the PQL values are
greater than the minimum (PQL_M xxxxx
) values.
With subprocesses, some quotas are pooled, such as PQL_PGFLQUOTA and PQL_TQELM. SYS$CREPRC establishes pooled quotas when it creates a detached process, and they are shared by that process and all its descendant subprocesses. All the related processes report the same quota because they are accessing a common location in the job information block (JIB).
To determine the maximum virtual page count of the paging file quota of a process, use the JPI$_PGFLQUOTA item code of the SYS$GETJPI system service. The JPI$_PGFLQUOTA on VAX systems returns the longword integer value of the paging file quota in pages; on Alpha and I64 systems, it returns the longword integer value of the paging file quota in pagelets.
To determine the remaining paging file quota of the process, use the JPI$_PAGFILCNT item code of the SYS$GETJPI system service. The JPI$_PAGFILCNT on VAX systems returns the longword integer value of the paging file quota in pages; on Alpha and I64 systems, it returns the longword integer value of the paging file quota in pagelets.
For a complete description of quotas, refer to the VSI OpenVMS System Services Reference Manual: A-GETUAI.
2.7. Debugging a Subprocess or a Detached Process
Using the kept debugger configuration
Using DBG$ logical names
Using the workstation device (see Section 2.4.4, “Using SYS$CREPRC to Create a Subprocess”)
Using a DECwindows DECterm display
See the VSI OpenVMS Debugger Manual for more details on debugging subprocesses and detached processes.
Kept Debugger
With the kept debugger configuration, you start the debugger user interface using the DCL command DEBUG/KEEP.
At the DBG> prompt, you then issue either the RUN or the CONNECT command, depending on whether or not the program you want to debug is already running.
If the program is not running, use the debugger's RUN command to start the program in a subprocess.
The detached process UIC must be in the same group as your process.
The detached process must have a CLI mapped.
$ RUN/DETACH/INPUT=xxx.com SYS$SYSTEM:LOGINOUT
where xxx.com
is a command procedure that starts the
program with /NODEBUG.
After you have started or connected to the program, the remainder of the debugging session is the same as a normal debugger session.
DBG$ Logical Names
You can allow a program to be debugged within a subprocess or a detached process by using DBG$INPUT and DBG$OUTPUT. To allow debug operations with DBG$INPUT and DBG$OUTPUT, equate the subprocess logical names DBG$INPUT and DBG$OUTPUT to the terminal. When the subprocess executes the program, which has been compiled and linked with the debugger, the debugger reads input from DBG$INPUT and writes output to DBG$OUTPUT.
If you are executing the subprocess concurrently, you should restrict debugging to the program in the subprocess. The debugger prompt DBG> should enable you to differentiate between input required by the parent process and input required by the subprocess. However, each time the debugger displays information, you must press the Return key to display the DBG> prompt. (By pressing the Return key, you actually write to the parent process, which has regained control of the terminal following the subprocess' writing to the terminal. Writing to the parent process allows the subprocess to regain control of the terminal).
DECwindows DECterm Display
#pragma module CREATE_DECTERM #include <descrip.h> #include <lib$routines.h> #include <pqldef.h> #include <prcdef.h> #include <ssdef.h> #include <starlet.h> #include <stsdef.h> // To build and run: // $ cc CREATE_DECTERM // $ link CREATE_DECTERM,sys$input/option // sys$share:DECW$TERMINALSHR.EXE/share // $ run CREATE_DECTERM // This routine is not declared in a currently-available library extern int decw$term_port(void *,...); main( void ) { int RetStat; int StsFlg; int DbgTermLen = 0; #define DBGTERMBUFLEN 50 char DbgTermBuf[DBGTERMBUFLEN]; $DESCRIPTOR( Customization, "DECW$TERMINAL.iconName:\tDebugging Session\n\ DECW$TERMINAL.title:\tDebugging Session" ); $DESCRIPTOR( Command, "SYS$SYSDEVICE:[HOFFMAN]DEBUG_IMAGE.EXE" ); struct dsc$descriptor DbgTerm; DbgTerm.dsc$w_length = DBGTERMBUFLEN; DbgTerm.dsc$b_dtype = DSC$K_DTYPE_T; DbgTerm.dsc$b_class = DSC$K_CLASS_S; DbgTerm.dsc$a_pointer = DbgTermBuf; // Request creation of a DECterm display RetStat = decw$term_port( 0, // display (use default) 0, // setup file (use default) &Customization, // customization &DbgTerm, // resulting device name &DbgTermLen, // resulting device name length 0, // controller (use default) 0, // char buffer (use default) 0 ); // char change buffer (default) if ( !$VMS_STATUS_SUCCESS (RetStat )) lib$signal( RetStat ); DbgTerm.dsc$w_length = DbgTermLen; // Create the process as detached. StsFlg = PRC$M_DETACH; // Now create the process RetStat = sys$creprc( 0, // PID &Command, // Image to invoke &DbgTerm, // Input &DbgTerm, // Output 0, 0, 0, 0, 0, 0, 0, StsFlg ); // Process creation flags if ( !$VMS_STATUS_SUCCESS( RetStat )) lib$signal( RetStat ); return SS$_NORMAL; }
2.8. Kernel Threads and the Kernel Threads Process Structure (Alpha and I64 Only)
Note
For information about the concepts and implementation of user threads with POSIX Threads Library, refer to the Guide to POSIX Threads Library.
2.8.1. Definition and Advantages of Kernel Threads
A thread is a single, sequential flow of execution within a process's address space. A single process contains an address space wherein either a single thread or multiple threads execute concurrently. Programs typically have a single flow of execution and therefore a single thread; whereas multithreaded programs have multiple points of execution at any one time.
More modular code design
Simpler application design and maintenance
The potential to run independent flows of execution in parallel on multiple CPUs
The potential to make better use of available CPU resources through parallel execution
2.8.2. Kernel Threads Features
Multiple execution contexts within a process
Efficient use of the OpenVMS and POSIX Threads Library schedulers
2.8.2.1. Multiple Execution Contexts Within a Process
Before the implementation of kernel threads, the scheduling model for the OpenVMS operating system was per process. The only scheduling context was the process itself, that is, only one execution context per process. Since a threaded application could create thousands of threads, many of these threads could potentially be executing at the same time. But because OpenVMS processes had only a single execution context, in effect, only one of those application threads was running at any one time. If this multithreaded application was running on a multiprocessor system, the application could not make use of more than a single CPU.
After the implementation of kernel threads, the scheduling model allows for multiple execution contexts within a process; that is, more than one application thread can be executing concurrently. These execution contexts are called kernel threads. Kernel threads allow a multithreaded application to have a thread executing on every CPU in a multiprocessor system. Therefore, kernel threads allow a threaded application to take advantage of multiple CPUs in a symmetric multiprocessing (SMP) system.
The maximum number of kernel threads that can be created in a process is 256.
2.8.2.2. Efficient Use of the OpenVMS and POSIX Threads Library Schedulers
The user mode thread manager schedules individual user mode application threads. On OpenVMS, POSIX Threads Library is the user mode threading package of choice. Before the implementation of kernel threads, POSIX Threads Library multiplexed user mode threads on the single OpenVMS execution context – the process. POSIX Threads Library implemented parts of its scheduling by using a periodic timer. When the AST executed and the thread manager gained control, the thread manager could then select a new application thread for execution. But because the thread manager could not detect that a thread had entered an OpenVMS wait state, the entire application blocked until that periodic AST was delivered. That resulted in a delay until the thread manager regained control and could schedule another thread. Once the thread manager gained control, it could schedule a previously preempted thread unaware that the thread was in a wait state. The lack of integration between the OpenVMS and POSIX Threads Library schedulers could result in wasted CPU resources.
After the implementation of kernel threads, the scheduling model provides for scheduler callbacks, which is not the default. A scheduler callback is an upcall from the OpenVMS scheduler to the thread manager whenever a thread changes state. This upcall allows the OpenVMS scheduler to inform the thread manager that the current thread is stalled and that another thread should be scheduled. Upcalls also inform the thread manager that an event a thread is waiting on has completed. The two schedulers are now better integrated, minimizing application thread scheduling delays.
2.8.2.3. Terminating a POSIX Threads Image
To avoid hangs or a disorderly shutdown of a multithreaded process, VSI recommends that you issue an upcall with an EXIT command at the DCL prompt ($). This procedure causes a normal termination of the image currently executing. If the image declared any exit-handling routines, for instance, they are then given control. The exit handlers are run in a separate thread, which allows them to be synchronized with activities in other threads. This allows them to block without danger of entering a self-deadlock due to the handler having been involved in a context which already held resources.
The effect of calling the EXIT command on the calling thread is the same as calling pthread_exit(): the caller's stack is unwound and the thread is terminated. This allows each frame on the stack to have an opportunity to be notified and to take action during the termination, so that it can then release any resource which it holds that might be required for an exit handler. By using upcalls, you have a way out of self-deadlock problems that can impede image rundown.
You can optionally perform a rundown by using the control y EXIT (Ctrl–Y/EXIT) command. By doing this and with upcalls enabled, you release the exit handler thread. All other threads continue to execute untouched. This removes the possibility of the self-deadlock problem which is common when you invoke exit handlers asynchronously in an existing context. However, by invoking exit handlers, you do not automatically initiate any kind of implicit shutdown of the threads in the process. Because of this, it is up to the application to request explicitly the shutdown of its threads from its exit handler and to ensure that their shutdown is complete before returning from the exit handler. By having the application do this, you ensure that subsequent exit handlers do not encounter adverse operating conditions, such as threads which access files after they have been closed, or the inability to close files because they are being accessed by threads.
Along with using control y EXIT (Ctrl–Y/EXIT) to perform shutdowns, you can issue a control y (Ctrl–Y/STOP) command. If you use a control y STOP (Ctrl–Y/STOP) command, it is recommended that you do this with upcalls. To use a control y STOP (Ctrl–Y/STOP) command, can cause a disorderly or unexpected outcome.
2.8.3. Kernel Threads Model and Design Features
This section presents the type of kernel threads model that OpenVMS Alpha and OpenVMS I64 implement, and some features of the operating system design that changed to implement the kernel thread model.
2.8.3.1. Kernel Threads Model
The OpenVMS kernel threads model is one that implements a few kernel threads to many user threads with integrated schedulers. With this model, there is a mapping of many user threads to only several execution contexts or kernel threads. The kernel threads have no knowledge of the individual threads within an application. The thread manager multiplexes those user threads on an execution context, though a single process can have multiple execution contexts. This model also integrates the user mode thread manager scheduler with the OpenVMS scheduler.
2.8.3.2. Kernel Threads Design Features
Process structure
Access to inner modes
Scheduling
ASTs
Event flags
Process control services
2.8.3.2.1. Process Structure
With the implementation of OpenVMS kernel threads, all processes are a threaded process with at least one kernel thread. Every kernel thread gets stacks for each access mode. Quotas and limits are maintained and enforced at the process level. The process virtual address space remains per process and is shared by all threads. The scheduling entity moves from the process to the kernel thread. In general, ASTs are delivered directly to the kernel threads. Event flags and locks remain per process. See Section 2.8.4, “Kernel Threads Process Structure” for more information.
2.8.3.2.2. Access to Inner Modes
With the implementation of kernel threads, a single threaded process continues to function exactly as it has in the past. A multithreaded process may have multiple threads executing in user mode or in user mode ASTs, as is also possible for supervisor mode. Except in cases where an activity in inner mode is considered thread safe, a multithreaded process may have only a single thread executing in an inner mode at any one time. Multithreaded processes retain the normal preemption of inner mode by more inner mode ASTs. A special inner mode semaphore serializes access to inner mode.
2.8.3.2.3. Scheduling
With the implementation of kernel threads, the OpenVMS scheduler concerns itself with kernel threads, and not processes. At certain points in the OpenVMS executive at which the scheduler could wait a kernel thread, it can instead transfer control to the thread manager. This transfer of control, known as a callback or upcall, allows the thread manager the chance to reschedule stalled application threads.
2.8.3.2.4. ASTs
With the implementation of kernel threads, ASTs are not delivered to the process. They are delivered to the kernel thread on which the event was initiated. Inner mode ASTs are generally delivered to the kernel thread already in inner mode. If no thread is in inner mode, the AST is delivered to the kernel thread that initiated the event.
2.8.3.2.5. Event Flags
With the implementation of kernel threads, event flags continue to function on a per-process basis, maintaining compatibility with existing application behavior.
2.8.3.2.6. Process Control Services
With the implementation of kernel threads, many process control services continue to function at the process level. SYS$SUSPEND and SYS$RESUME system services, for example, continue to change the scheduling state of the entire process, including all of its threads. Other services such as SYS$HIBER and SYS$SCHDWK act on individual kernel threads instead of the entire process.
2.8.4. Kernel Threads Process Structure
Process control block (PCB) and process header (PHD)
Kernel thread block (KTB)
Floating-point registers and execution data block (FRED)
Kernel threads region
Per-kernel thread stacks
Per-kernel thread data cells
Process status bits
Kernel thread priorities
2.8.4.1. Process Control Block (PCB) and Process Header (PHD)
Software process control block (PCB)
Process header (PHD)
The PCB contains fields that identify the process to the system. The PCB comprises contexts that pertain to quotas and limits, scheduling state, privileges, AST queues, and identifiers. In general, any information that is required to be resident at all times is in the PCB. Therefore, the PCB is allocated from nonpaged pool.
The PHD contains fields that pertain to a process's virtual address space. The PHD contains the process section table. The PHD also contains the hardware process control block (HWPCB) and a floating-point register save area. The HWPCB contains the hardware execution context of the process. The PHD is allocated as part of a balance set slot.
2.8.4.1.1. Effect of a Multithreaded Process on the PCB and PHD
With multiple execution contexts within the same process, the multiple threads of execution all share the same address space, but have some independent software and hardware context. This change to a multithreaded process results in an impact on the PCB and PHD structures, and on any code that references them.
Before the implementation of kernel threads, the PCB contained much context that was per-process. Now, with the introduction of multiple threads of execution, much context becomes per-thread. To accommodate per-thread context, a new data structure, the kernel thread block (KTB), is created, with the per-thread context removed from the PCB. However, the PCB continues to contain context common to all threads, such as quotas and limits. The new per-kernel thread structure contains the scheduling state, priority, and the AST queues.
The PHD contains the HWPCB that gives a process its single execution context. The HWPCB remains in the PHD; this HWPCB is used by a process when it is first created. This execution context is also called the initial thread. A single threaded process has only this one execution context. A new structure, the floating-point registers and execution data block (FRED), is created to contain the hardware context of the newly created kernel threads. Since all threads in a process share the same address space, the PHD and page tables continue to describe the entire virtual memory layout of the process.
2.8.4.2. Kernel Thread Block (KTB)
The kernel thread block (KTB) is a new per-kernel-thread data structure. The KTB contains all per-thread software context moved from the PCB. The KTB is the basic unit of scheduling, a role previously performed by the PCB, and is the data structure placed in the scheduling state queues.
Typically, the number of KTBs a multithreaded process has is the same as the number of CPUs on the system. Actually, the number of KTBs is limited by the value of the system parameter MULTITHREAD. If MULTITHREAD is zero, the OpenVMS kernel support is disabled. With kernel threads disabled, user-level threading is still possible with POSIX Threads Library. The environment is identical to the OpenVMS environment prior to the OpenVMS Version 7.0 release. If MULTITHREAD is nonzero, it represents the maximum number of execution contexts or kernel threads that a process can own, including the initial one.
The KTB, in reality, is not an independent structure from the PCB. Both the PCB and KTB are defined as sparse structures. The fields of the PCB that move to the KTB retain their original PCB offsets in the KTB. In the PCB, these fields are unused. In effect, if the two structures are overlaid, the result is the PCB as it currently exists with new fields appended at the end. The PCB and KTB for the initial thread occupy the same block of nonpaged pool; therefore, the KTB address for the initial thread is the same as for the PCB.
2.8.4.3. Floating-Point Registers and Execution Data Blocks (FREDs)
To allow for multiple execution contexts, not only are additional KTBs required to maintain the software context, but additional HWPCBs must be created to maintain the hardware context. Each HWPCB has allocated with it space for preserving the contents of the floating-point registers across context switches. Additional bytes are allocated for per-kernel thread data.
The combined structure that contains the HWPCB, floating-point register save area, and the per-kernel thread data is called the floating-point registers and execution data (FRED) block. Prior to Version 7.2, OpenVMS supported 16 kernel threads per process. As of Version 7.2, OpenVMS supports 256 kernel threads per process. Also, prior to Version 7.3-1, OpenVMS allocated the maximum number of FRED blocks for a given process when that process was created, even if the process did not become multithreaded. With Version 7.3-1 and higher, OpenVMS allocated all FRED blocks as needed.
2.8.4.4. Kernel Threads Region
Much process context resides in P1 space, taking the form of data cells and the process stacks. Some of these data cells need to be per kernel thread, as do the stacks. During initialization of the multithread environment, a kernel thread region in P1 space is initialized to contain the per-kernel-thread data cells and stacks. The region begins at the boundary between P0 and P1 space at address 40000000x, and it grows toward higher addresses and the initial thread's user stack. The region is divided into per-kernel-thread areas. Each area contains pages for data cells and the access mode stacks.
2.8.4.5. Per-Kernel Thread Stacks
A process is created with separate stacks in P1 space for the four access modes. On Alpha systems, each access mode has a memory stack. A memory stack is used for storing data local to a procedure, saving register contents temporarily, and recording nested procedure call information. On I64 systems, memory stacks are used for storing data local to a procedure and for saving register contents temporarily, but not for recording nested procedure call information.
To reduce procedure call overhead, the Intel ® Itanium ® architecture provides a large number of registers. Some, the so-called static registers, are shared by a caller and the procedure it calls; others, the dynamic or stacked registers, are not shared. When a procedure is called, it allocates as many dynamic general registers as it needs. On I64 systems, nested procedure call information is recorded in the dynamic registers.
The I64 systems manage the dynamic registers like a stack, keeping track of each procedure's allocation. Each procedure could, in fact, allocate all the dynamic registers for its own use. Whenever the dynamic register use by nested procedures cannot be accommodated by physical registers, the hardware saves the dynamic registers in an in-memory area established by OpenVMS called the register backing store or register stack. On I64 systems, OpenVMS creates a register stack whenever it creates a memory stack. Unlike memory stacks, register stacks grow from low addresses to high addresses.
Stack sizes are either fixed, determined by a SYSGEN parameter, or expandable. The parameter KSTACKPAGES controls the size of the kernel stack. Supervisor and executive mode stack sizes are fixed.
For the user stack, a more complex situation exists. OpenVMS allocates P1 space from high to lower addresses. The user stack is placed after the lowest P1 space address allocated. This allows the user stack to expand on demand toward P0 space. With the introduction of multiple sets of stacks, the locations of these stacks impose a limit on the size of each area in which they can reside. With the implementation of kernel threads, the user stack is no longer boundless. The initial user stack remains semi-boundless; it still grows toward P0 space, but the limit is the per-kernel thread region instead of P0 space. The default user stack in a process can expand on demand to be quite large, so single threaded applications do not typically run out of user stack.
When an application is written using POSIX Threads Library, however, each POSIX thread gets its own user stack, which is a fixed size. POSIX thread stacks are allocated from the P0 heap. Large stacks might cause the process to exceed its memory quotas. In an extreme case, the P0 region could fill completely, in which case the process might need to reduce the number of threads in use concurrently or make other changes to lessen the demand for P0 memory.
If the application developer underestimates the stack requirements, the application may fail due to a thread overflowing its stack. This failure is typically reported as an access violation and is very difficult to diagnose. To address this problem, yellow stack zones were introduced in OpenVMS Version 7.2 and are available to applications using POSIX Threads Library.
Yellow stack zones are a mechanism by which the stack overflow can be signaled back to the application. The application can then choose either to provide a stack overflow handler or do nothing. If the application does nothing, this mechanism helps pinpoint the failure for the application developer. Instead of an access violation being signaled, a stack overflow error is signaled.
2.8.4.6. Per-Kernel-Thread Data Cells
Several pages in P1 space contain process state in the form of data cells. A number of these cells must have a per-kernel-thread equivalent. These data cells do not all reside on pages with the same protection. Because of this, the per-kernel-thread area reserves two pages for these cells. Each page has a different page protection; one page protection is user read, user write (URUW); the other is user read, executive write (UREW).
2.8.4.7. Summary of Process Data Structures
Process creation results in a PCB/KTB, a PHD/FRED, and a set of stacks. All processes have a single kernel thread, the initial thread.
A multithreaded process always begins as a single threaded process. A multithreaded process contains a PCB/KTB pair and a PHD/FRED pair for the initial thread; for its other threads, it contains additional KTBs, additional FREDs, and additional sets of stacks. When the multithreaded application exits, the process returns to its single threaded state, and all additional KTBs, FREDs, and stacks are deleted.
2.8.4.8. Kernel Thread Priorities
The SYS$SETPRI system service and the SET PROCESS/PRIORITY DCL command both take a process identification value (PID) as an input and therefore affect only a single kernel thread at a time. If you want to change the base priorities of all kernel threads in a process, you must either make a separate call to SYS$SETPRI or invoke the SET PROCESS/PRIORITY command for each thread.
In addition, a value for the 'policy' parameter to the SYS$SETPRI system service was added. If JPI$K_ALL_THREADS is specified, the call to SYS$SETPRI changes the base priorities of all kernel threads in the target process.
The same support is provided by the ALL_THREADS qualifier to the SET PROCESS/PRIORITY DCL command.
2.9. THREADCP Command Not Supported on OpenVMS I64
The THREADCP command is not supported on OpenVMS I64. For OpenVMS I64, the SET
IMAGE and SHOW IMAGE commands can be used to check and modify the state of
threads-related image header bits, similar to the THREADCP command on
OpenVMS Alpha. For example, the THREADCP/SHOW image
command is analogous to the SHOW IMAGE image
command. As
another example, the THREADCP/ENABLE= flags
image
command is analogous to the SET IMAGE/LINKFLAGS=
flags
image
command.
The SHOW IMAGE and SET IMAGE commands are documented in the VSI OpenVMS DCL Dictionary: N–Z.
2.10. KPS Services (Alpha and I64 Only)
As of OpenVMS Version 8.2, KPS services enable a thread of execution in one access mode to have multiple stacks. These services were initially developed to allow a device driver to create a fork process with a private stack on which to retain execution context across stalls and restarts. They have been extended to be usable by process context code running in any access mode.
Various OpenVMS components use KPS services to multithread their operations. RMS, for example, can have multiple asynchronous I/O operations in progress in response to process requests from multiple access modes. Each request is processed on a separate memory stack and, on I64, separate register stack as well.
Chapter 3. Process Communication
This chapter describes communication mechanisms used within a process and between processes. It also describes programming with intra-cluster communication (ICC).
Synchronize events
Share data
Obtain information about events important to the program you are executing
3.1. Communication Within a Process
Local event flags
Logical names (in supervisor mode)
Global symbols (command language interpreter symbols)
Common area
For passing information among chained images, you can use all four methods because the image reading the information executes immediately after the image that deposited it. Only the common area allows you to pass data reliably from one image to another in the event that another image's execution intervenes the two communicating images.
For communicating within a single image, you can use event flags, logical names, and symbols. For synchronizing events within a single image, use event flags. See Chapter 6, Synchronizing Data Access and Program Operations, for more information about synchronizing events.
Because permanent mailboxes and permanent global sections are not deleted when the creating image exits, they also can be used to pass information from the current image to a later executing image. However, VSI recommends that you use the common area because it uses fewer system resources than the permanent structures and does not require privilege. (You need the PRMMBX privilege to create a permanent mailbox and the PRMGBL privilege to create a permanent global section).
You can also use symbols, but only between a parent and a spawned subprocess that has inherited the parent's symbols.
3.1.1. Using Local Event Flags
Event flags are status-posting bits maintained by the operating system for general programming use. Programs can set, clear, and read event flags. By setting and clearing event flags at specific points, one program component can signal when an event has occurred. Other program components can then check the event flag to determine when the event has been completed. For more information about using local and common event flags for synchronizing events, refer to Chapter 6, Synchronizing Data Access and Program Operations.
3.1.2. Using Logical Names
Logical names can store up to 255 bytes of data. When you need to pass information from one program to another within a process, you can assign data to a logical name when you create the logical name; then, other programs can access the contents of the logical name. See VSI OpenVMS Programming Concepts Manual, Volume II for more information about logical name system services.
You can create a logical name under three access modes—user, supervisor, or executive. If you create a process logical name in user mode, it is deleted after the image exits. If you create a logical name in supervisor or executive mode, it is retained after the image exits. Therefore, to share data within the process from one image to the next, use supervisor-mode or executive-mode logical names. Creating an executive-mode logical name requires privilege.
3.1.2.1. Creating and Accessing Logical Names
Create the logical name and store data in it. Use LIB$SET_LOGICAL to create a supervisor logical name. No special privileges are required. You can also use the system service SYS$CRELNM. SYS$CRELNM also allows you to create a logical name for the system or group table and to create a logical name in any other mode, assuming you have appropriate privileges.
Access the logical name. Use the system service SYS$TRNLNM. SYS$TRNLNM searches for the logical name and returns information about it.
Once you have finished using the logical name, delete it. Use the routine LIB$DELETE_LOGICAL or SYS$DELLNM. LIB$DELETE_LOGICAL deletes the supervisor logical name without requiring any special privileges. SYS$DELLNM requires special privileges to delete logical names for privileged modes. However, you can also use this routine to delete either logical name tables or a logical name within a system or group table.
3.1.3. Using Command Language Interpreter Symbols
The symbols you create and access for process communication are command language interpreter (CLI) symbols. These symbols are stored in symbol tables maintained for use within the context of DCL, the default command language interpreter. They can store up to 255 bytes of information. The use of these symbols is limited to processes using DCL. If the process is not using DCL, an error status is returned by the symbol routines.
3.1.3.1. Local and Global Symbols
Local – A local symbol is available to the command level that defined it, any command procedure executed from that command level, and lower command levels.
Global – A global symbol can be accessed from any command level, regardless of the level at which it was defined.
3.1.3.2. Creating and Using Global Symbols
If you need to pass information from one program to another within a process, you can assign data to a global symbol when you create the symbol. Then, other programs can access the contents of the global symbol. You should use global symbols so the value within the symbol can be accessed by other programs.
Create the symbol and assign data to it using the routine LIB$SET_SYMBOL. Make sure you specify that the symbol will be placed in the global symbol table in the tbl-ind argument. If you do not specify the global symbol table, the symbol will be a local symbol.
Access the symbol with the LIB$GET_SYMBOL routine. This routine uses DCL to return the value of the symbol as a string.
Once you have finished using the symbol, delete it with the LIB$DELETE_SYMBOL routine. If you created a global symbol, make sure you specify the global symbol table in the tbl-ind argument. By default, the system searches the local symbol table.
See the VSI OpenVMS RTL Library (LIB$) Manual for additional information.
3.1.4. Using the Common Area
Use the common area to store data from one image to the next. Such data is unlikely to be corrupted between the time one image deposits it in a common area and another image reads it from the area. The common area can store 252 bytes of data. The LIB$PUT_COMMON routine writes information to this common area; the LIB$GET_COMMON routine reads information from this common area.
3.1.4.1. Creating the Process Common Area
The common area for your process is automatically created for you; no special declaration is necessary. To pass more than 255 bytes of data, put the data into a file instead of in the common area and use the common area to pass the specification.
3.1.4.2. Common I/O Routines
[min(256, the length of the data in the common storage area) - 4]
This maximum length is normally 252.
In BASIC and Fortran, you can use these routines to allow a USEROPEN routine to pass information back to the routine that called it. A USEROPEN routine cannot write arguments. However, it can call LIB$PUT_COMMON to put information into the common area. The calling program can then use LIB$GET_COMMON to retrieve it.
You can also use these routines to pass information between images run successively, such as chained images run by LIB$RUN_PROGRAM.
3.1.4.3. Modifying or Deleting Data in the Common Block
You cannot modify or delete data in the process common area unless you invoke LIB$PUT_COMMON. Therefore, you can execute any number of images between one image and another, provided that you have not invoked LIB$PUT_COMMON. Each subsequent image reads the correct data. Invoking LIB$GET_COMMON to read the common block does not modify the data.
3.1.4.4. Specifying Other Types of Data
Although the descriptions of the LIB$PUT_COMMON and LIB$GET_COMMON routines in the VSI OpenVMS RTL Library (LIB$) Manual specify a character string for the argument containing the data written to or read from the common area, you can specify other types of data. However, you must pass both noncharacter and character data by descriptor.
.
.
.
! Enter statistics
.
.
.
! Put the name of the stats file into common
STATUS = LIB$PUT_COMMON (FILE_NAME (1:LEN))
.
.
.
.
.
.
! Read the name of the stats file from common
STATUS = LIB$GET_COMMON (FILE_NAME,
2 LEN)
! Compile the report
.
.
.
3.2. Communication Between Processes
Shared files
Common event flags
Logical names
Mailboxes
Global sections
Lock management system services
Each approach offers different possibilities in terms of the speed at which it communicates information and the amount of information it can communicate. For example, shared files offer the possibility of sharing an unlimited amount of information; however, this approach is the slowest because the disk must be accessed to share information.
Like shared files, global sections offer the possibility of sharing large amounts of information. Because sharing information through global sections requires only memory access, it is the fastest communication method.
Logical names and mailboxes can communicate moderate amounts of information. Because each method operates through a relatively complex system service, each is faster than files, but slower than the other communication methods.
The lock management services and common event flag cluster methods can communicate relatively small amounts of information. With the exception of global sections, they are the fastest of the interprocess communication methods.
Common event flags: Processes executing within the same group can use common event flags to signal the occurrence or completion of particular activities. For details about event flags, and an example of how cooperating processes in the same group use a common event flag, see Chapter 6, Synchronizing Data Access and Program Operations.
Logical name tables: Processes executing in the same job can use the job logical name table to provide member processes with equivalence names for logical names. Processes executing in the same group can use the group logical name table. A process must have the GRPNAM or SYSPRV privilege to place names in the group logical name table. All processes in the system can use the system logical name table. A process must have the SYSNAM or SYSPRV privilege to place names in the system logical name table. Processes can also create and use user-defined logical name tables. For details about logical names and logical name tables, see VSI OpenVMS Programming Concepts Manual, Volume II.
Mailboxes: You can use mailboxes as virtual input/output devices to pass information, messages, or data among processes. For additional information on how to create and use mailboxes, see Section 3.2.2, “Mailboxes”. Mailboxes may also be used to provide a creating process with a way to determine when and under what conditions a created subprocess was deleted. For an example of a termination mailbox, see Section 4.9.4.3, “Terminating Mailboxes”.
Global sections: Global sections can be either disk files or page-file sections that contain shareable code or data. Through the use of memory management services, these files can be mapped to the virtual address space of more than one process. In the case of a data file on disk, cooperating processes can synchronize reading and writing the data in physical memory; as data is updated, system paging results in the updated data being written directly back into the disk file. Global page-file sections are useful for temporary storage of common data; they are not mapped to a disk file. Instead, they page only to the system default page file. Global sections are described in more detail in Chapter 13, Memory Management Services and Routines on OpenVMS VAX and Chapter 12, Memory Management Services and Routines on OpenVMS Alpha and OpenVMS I64.
Lock management system services: Processes can use the lock management system services to control access to resources (any entity on the system that the process can read, write, or execute). In addition to controlling access, the lock management services provide a mechanism for passing information among processes that have access to a resource (lock value blocks). Blocking ASTs can be used to notify a process that other processes are waiting for a resource. Using lock value blocks is a practical technique for communicating in cluster environments. With lock value blocks, communication between two processes from node to node in a distributed environment is an effective way of implementing cluster communication. For more information about the lock management system services, see Chapter 7, Synchronizing Access to Resources.
While common event flags and lock management services establish communication, they are most useful for synchronizing events and are discussed in Chapter 6, Synchronizing Data Access and Program Operations. Global sections and shared files are best used for sharing data and are discussed in VSI OpenVMS Programming Concepts Manual, Volume II.
3.2.1. Using Logical Name Tables
If both processes are part of the same job, you can place the logical name in the process logical name table (LNM$PROCESS) or in the job logical name table (LNM$JOB). If a subprocess is prevented from inheriting the process logical name table, you must communicate using the job logical name table. If the processes are in the same group, place the logical name in the group logical name table LNM$GROUP (requires GRPNAM or SYSPRV privilege). If the processes are not in the same group, place the logical name in the system logical name table LNM$SYSTEM (requires SYSNAM or SYSPRV privilege).
3.2.2. Mailboxes
A mailbox is a virtual device used for communication among processes. You must call OpenVMS RMS services, language I/O statements, or I/O system services to perform actual data transfers.
3.2.2.1. Creating a Mailbox
To create a mailbox, use the SYS$CREMBX system service. SYS$CREMBX creates the mailbox and returns the number of the I/O channel assigned to the mailbox.
The format for the SYS$CREMBX system service is as follows:
SYS$CREMBX
([prmflg] ,chan ,[maxmsg] ,[bufquo] ,[promsk] ,[acmode] , [lognam],
[flags] ,[nullarg])
Specify a variable to receive the I/O channel number using the
chan
argument. This argument is required.Specify the logical name to be associated with the mailbox using the
lognam
argument. The logical name identifies the mailbox for other processes and for input/output statements.
The SYS$CREMBX system service also allows you to specify the message size, buffer size, mailbox protection code, and access mode of the mailbox; however, the default values for these arguments are usually sufficient. For more information on SYS$CREMBX, refer to the VSI OpenVMS System Services Reference Manual.
3.2.2.2. Creating Temporary and Permanent Mailboxes
By default, a mailbox is deleted when no I/O channel is assigned to it. Such a
mailbox is called a temporary mailbox. If you have PRMMBX privilege, you can
create a permanent mailbox (specify the prmflg
argument
as 1 when you invoke SYS$CREMBX). A permanent mailbox
is not deleted until it is marked for deletion with the
SYS$DELMBX system service (requires PRMMBX). Once a
permanent mailbox is marked for deletion, it is like a temporary mailbox; when
the last I/O channel to the mailbox is deassigned, the mailbox is
deleted.
! I/O channel
INTEGER*2 MBX_CHAN
! Mailbox name
CHARACTER*(*) MBX_NAME
PARAMETER (MBX_NAME = 'MAIL_BOX')
STATUS = SYS$CREMBX (,
2 MBX_CHAN, ! I/O channel
2 ,,,,
2 MBX_NAME) ! Mailbox name
Note
If you use MAIL as the logical name for a mailbox, then the system will not execute the proper image in response to the DCL command MAIL.
INTEGER STATUS, 2 SYS$CREMBX INTEGER*2 MBX_CHAN ! Create permanent mailbox STATUS = SYS$CREMBX (%VAL(1), ! Permanence flag 2 MBX_CHAN, ! Channel 2 ,,,, 2 'MAIL_BOX') ! Logical name IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS)) ! Create subprocess to delete it STATUS = LIB$SPAWN ('RUN DELETE_MBX') IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS)) END
INTEGER STATUS, 2 SYS$DELMBX, 2 SYS$ASSIGN INTEGER*2 MBX_CHAN ! Assign channel to mailbox STATUS = SYS$ASSIGN ('MAIL_BOX', 2 MBX_CHAN,,) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS)) ! Delete the mailbox STATUS = SYS$DELMBX (%VAL(MBX_CHAN)) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS)) END
3.2.2.3. Assigning an I/O Channel Along with a Mailbox
A mailbox is a virtual device used for communication between processes. A channel is the communication path that a process uses to perform I/O operations to a particular device. The LIB$ASN_WTH_MBX routine assigns a channel to a device and associates a mailbox with the device.
Normally, a process calls the SYS$CREMBX system service to create a mailbox and assign a channel and logical name to it. In the case of a temporary mailbox, this service places the logical name corresponding to the mailbox in the job logical name table. This implies that any process running in the same job and using the same logical name uses the same mailbox.
Sometimes it is not desirable to have more than one process use the same mailbox. For example, when a program connects explicitly with another process across a network, the program uses a mailbox both to obtain the data confirming the connection and to store the asynchronous messages from the other process. If that mailbox is shared with other processes in the same group, there is no way to determine which messages are intended for which processes; the processes read each other's messages, and the original program does not receive the correct information from the cooperating process across the network link.
MB |
indicates that the device is a mailbox. |
c |
is the controller. |
u |
is the unit number. |
The routine returns this device name to the calling program, which then must pass the mailbox channel to the other programs with which it cooperates. In this way, the cooperating processes access the mailbox by its physical name instead of by its jobwide logical name.
The calling program passes the routine a device name, which specifies the
device to which the channel is to be assigned. For this argument (called
dev-nam
), you can use a logical name. If you do so,
the routine attempts one level of logical name translation.
The privilege restrictions and process quotas required for using this routine are those required by the $GETDVI, $CREMBX, and $ASSIGN system services.
3.2.2.4. Reading and Writing Data to a Mailbox
Synchronous I/O—Reads or writes to a mailbox and then waits for the cooperating image to perform the other operation. Use I/O statements for your programming language. This is the recommended method of addressing a mailbox.
Immediate I/O—Queues a read or write operation to a mailbox and continues program execution after the operation completes. To do this, use the SYS$QIOW system service.
Asynchronous I/O—Queues a read or write operation to a mailbox and continues program execution while the request executes. To do this, use the SYS$QIO system service. When the read or write operation completes, the I/O status block (if specified) is filled, the event flag (if specified) is set, and the AST routine (if specified) is executed.
VSI OpenVMS Programming Concepts Manual, Volume II describes the SYS$QIO and SYS$QIOW system services and provides further discussion of mailbox I/O. See the VSI OpenVMS System Services Reference Manual for more information. VSI recommends that you supply the optional I/O status block parameter when you use these two system services. The contents of the status block varies depending on the QIO function code; refer to the function code descriptions in the VSI OpenVMS I/O User's Reference Manual for a description of the appropriate status block.
3.2.2.5. Using Synchronous Mailbox I/O
Use synchronous I/O when you read or write information to another image and cannot continue until that image responds.
3.2.2.6. Using Immediate Mailbox I/O
Use immediate I/O to send or receive a message from another process without waiting for a response from that process. To ensure that the other process receives the information that you write, either do not exit until the other process has a channel to the mailbox, or use a permanent mailbox.
Queueing an Immediate I/O Request
To queue an immediate I/O request, invoke the SYS$QIOW system service. See the VSI OpenVMS System Services Reference Manual for more information.
Reading Data from the Mailbox
Since immediate I/O is asynchronous, a mailbox may contain more than one message or no message when it is read. If the mailbox contains more than one message, the read operation retrieves the messages one at a time in the order in which they were written. If the mailbox contains no message, the read operation generates an end-of-file error.
To allow a cooperating program to differentiate between an empty mailbox and the end of the data being transferred, the process writing the messages should use the IO$_WRITEOF function code to write an end-of-file message to the mailbox as the last piece of data. When the cooperating program reads an empty mailbox, the end-of-file message is returned and the second longword of the I/O status block is 0. When the cooperating program reads an end-of-file message explicitly written to the mailbox, the end-of-file message is returned and the second longword of the I/O status block contains the process identification number of the process that wrote the message to the mailbox.
3.2.2.7. Using Asynchronous Mailbox I/O
Use asynchronous I/O to queue a read or write request to a mailbox. To ensure that the other process receives the information you write, either do not exit the other process until the other process has a channel to the mailbox, or use a permanent mailbox.
To queue an asynchronous I/O request, invoke the SYS$QIO system service; however, when specifying the function codes, do not specify the IO$M_NOW modifier. The SYS$QIO system service allows you to specify either an AST to be executed or an event flag to be set when the I/O operation completes.
Example 3.5, “Asynchronous I/O Using a Mailbox” calculates gross income and taxes and then uses the results to calculate net income. INCOME.FOR uses SYS$CREPRC, specifying a termination mailbox, to create a subprocess to calculate taxes (CALC_TAXES) while INCOME calculates gross income. INCOME issues an asynchronous read to the termination mailbox, specifying an event flag to be set when the read completes. (The read completes when CALC_TAXES completes, terminating the created process and causing the system to write to the termination mailbox.) After finishing its own gross income calculations, INCOME.FOR waits for the flag that indicates CALC_TAXES has completed and then figures net income.
3.3. Intracluster Communication
Intracluster communication (ICC), available through ICC system services, forms an application program interface (API) for process-to-process communications. For large data transfers, intracluster communication is the highest performance OpenVMS application communication mechanism, better than standard network transports and mailboxes.
Intracluster communication enables application program developers to create distributed applications with connections between different processes on a single system or between processes on different systems within a single OpenVMS Cluster system. Intracluster communication does not require a network product. It uses memory or System Communication Services (SCS).
Allow the creation of both client and server processes
Maintain a simple registry of servers and services
Manage security of the server process namespace and access to server processes
Establish connections between these processes and transmit data between these processes
Provide 64-bit buffer and address support
An easy-to-use conventional system service interface for interprocess communications within a cluster
An interface usable for communications between processes within a single, nonclustered node
An interface callable from all modes and from execlets as well as from images
An easy-to-use interface giving access to high-speed interconnects such as Memory Channel
An interface independent of the installation of any networking product
An interface usable for nonprivileged clients and authorized (but not necessarily privileged) servers
Open Association: SYS$ICC_OPEN_ASSOC
Close Association: SYS$ICC_CLOSE_ASSOC
Connect: SYS$ICC_CONNECT and SYS$ICC_CONNECTTW
Accept: SYS$ICC_ACCEPT
Reject: SYS$ICC_REJECT
Disconnect: SYS$ICC_DISCONNECT and SYS$ICC_DISCONNECTW
Transmit Data: SYS$ICC_TRANSMIT and SYS$ICC_TRANSMITW
Receive Data: SYS$ICC_RECEIVE and SYS$ICC_RECEIVEW
Transceive Data: SYS$ICC_TRANSCEIVE and SYS$ICC_TRANSCEIVEW
Reply: SYS$ICC_REPLY and SYS$ICC_REPLYW
See the VSI OpenVMS System Services Reference Manual: GETUTC-Z for additional information about the ICC system services.
3.3.1. Programming with Intracluster Communications
The following sections provide information on how to program with intracluster communications (ICC) using ICC system services.
3.3.1.1. ICC Concepts
The following terms and their definitions are central to creating and using intracluster communication.
An ASSOCIATION is a named link between an application and ICC. The association name, combined with the node name of the system on which the application is running, identifies this application to other applications that want to communicate within a node or cluster.
An ASSOCIATION NAME is a string that identifies an ASSOCIATION. Association Names are 1 to 31 characters in length and must be unique within a node. Association Names are case-sensitive. Associations are created by calling the SYS$ICC_OPEN_ASSOC service (or by the first call to SYS$ICC_CONNECT if OPEN was not previously called) and are identified by an Association Handle.
An ASSOCIATION HANDLE is an opaque identifier that represents an association to ICC. Association Handles are passed as unsigned longwords.
A NODE is either a standalone system or a member of an OpenVMS Cluster. It is identified by a one-to-six-character case-blind name that matches the SYSGEN parameter SCSNODE.
A CONNECTION is a link between two associations created by calling the SYS$ICC_CONNECT or SYS$ICC_ACCEPT service. An association may have multiple simultaneous connections at any given time. A connection is identified by a Connection Handle. A given application may choose to either only initiate connections, or initiate and accept connections as well. Connections support both synchronous and asynchronous communications.
A CONNECTION HANDLE is an opaque identifier that represents a connection to ICC. Connection Handles are passed as unsigned longwords.
In ICC terminology, a SERVER is an application that has declared to ICC that it is willing to accept connections. A server must call SYS$ICC_OPEN_ASSOC and supply the address of a connection routine. Upon receipt of a connection request AST, a server completes its side of the connection by calling the SYS$ICC_ACCEPT service. It may also choose not to accept the connection request by calling SYS$ICC_REJECT.
A CLIENT, in the ICC model, is an application that calls SYS$ICC_CONNECT to request a connection to a server. Note that a server may also be a client. A client need not call SYS$ICC_OPEN_ASSOC (although there are certain benefits to doing so) but may instead call SYS$ICC_CONNECT using the supplied constant Default Association Handle. An association opened in this manner is called the Default Association. Only one default association is permitted per process; however, any number of connections may be established even when there is only one association.
The ICC SIMPLE CLUSTERWIDE REGISTRY provides a method for servers to register their node and association names under a single logical name, thus eliminating the need for clients to determine on which node the server process is running. Multiple servers can register under the same logical name, and ICC will randomly select one from the list. The selection algorithm leads to load sharing, but not necessarily to load balancing.
3.3.1.2. Design Considerations
This section contains information about ICC design considerations.
3.3.1.2.1. Naming
An ICC server may have two visible names – the association name and, if the ICC registry is used, a registry name. The registry name may be the same as the association name.
If, however, you wish to run multiple copies of the server on a single node, the registry name should be the more general name, while the association name should reference a particular instance of the server.
3.3.1.2.2. Message Ordering
ICC guarantees that messages will be delivered in the order in which they were transmitted. There is no provision for out-of-order delivery.
3.3.1.2.3. Flow Control
ICC implements flow control on a per-association basis. You can change this value by specifying a value for the MAXFLOWBUFCNT parameter to the SYS$ICC_OPEN_ASSOC service.
In addition to flow control, ICC uses the value of MAXFLOWBUFCNT to determine preallocation of certain resources cached by the services for performance reasons. Increasing this value results in a larger charge against process quotas. The default value of MAXFLOWBUFCNT is 5.
Because all ICC connections within the association are subject to flow control, failure to receive data in a timely manner will eventually cause all connections in the association to stall.
3.3.1.2.4. Transfer Sizes and Receiving Data
ICC supports two models for receiving data. In the simple receive model, a SYS$ICC_RECEIVE call either completes immediately if data is present, or else the receive buffer is queued up to be filled when data arrives from the sender. SYS$ICC_RECEIVEW does not return to the caller until either data is present, or the connection has disconnected.
The major disadvantage to this method is that the buffer you supply to SYS$ICC_RECEIVE must be large enough to receive the largest message the sender might transmit. Receipt of a message larger than the queued buffer causes ICC to disconnect the link to preserve order. There is no provision within ICC to break a single message over multiple receive calls.
The second model is data event driven. In this method, the application provides SYS$ICC_OPEN_ASSOC (parameter recv_rtn) the address of a routine to be called whenever a connection established over this particular association is the target of a TRANSMIT. The data routine is called at AST level in the original mode of the caller and supplied with the size of the incoming transfer, the connection handle for this transfer, and a user-supplied context value. Once notified of incoming data, the application must then allocate a sufficiently large buffer and issue a SYS$ICC_RECEIVE call to obtain the data. The maximum transfer size using this method is 1 Mb.
The SYS$ICC_RECEIVE call does not have to be made from the data routine; however, a receive request cannot be made before receipt of a data event. Therefore, receive operations are never queued within ICC when you use a data event.
Because there is a single data routine per association, all connections on the association share the same data routine. To have some connections use both methods, at least two associations must be opened.
3.3.1.2.5. Transfer Sizes and Transceive
SYS$ICC_TRANSCEIVE is a single service that sends a message and completes when the other side responds with a call to SYS$ICC_REPLY. The maximum size of the return message is fixed by the size of the buffer the caller provides to the transceive service at the time the call is made. The maximum transmission size for both SYS$ICC_TRANSCEIVE and SYS$ICC_REPLY is 1 Mb. The minimum length of the reply transmission is zero bytes.
3.3.1.2.6. Disconnection
In a properly coded communications protocol, responsibility for disconnecting the connection should be left to the side of the protocol that last received data. This rule assures that there is no data in transit in which the state may be uncertain at the time the disconnect event occurs.
One side of the connection calls either SYS$ICC_DISCONNECT or SYS$ICC_CLOSE_ASSOC.
The client or server process in the connection is deleted.
The node on which one side of the connection is running is either shut down, crashes, or loses communication with the rest of the cluster.
An unrecoverable error within the ICC services occurs, and the only possible recovery by the service is to disconnect the link.
A pending receive buffer is too small to receive all the incoming data. To preserve message order, ICC will disconnect the link.
No matter what the cause of the disconnection, the application should be prepared to deal with disconnection other than that as an expected part of the application communication protocol.
3.3.1.2.7. Error Recovery
Whenever possible, ICC services attempt to return an appropriate status value to the caller, either as the routine status value or in the status fields of the IOSB or IOS_ICC structure. Sometimes the only recovery method available to ICC is to disconnect the connection. ICC disconnects only when it lacks sufficient context to return status to the calling application.
3.3.1.3. General Programming Considerations
The ICC public structures and constants are declared in the module $ICCDEF (MACRO), within STARLET.REQ for BLISS and ICCDEF.H in SYS$LIBRARY:SYS$STARLET_C.TLB for C. STARLET.H provides full system service prototypes for C.
3.3.1.4. Servers
Parameter |
Description |
---|---|
assoc_handle |
Address to receive the association handle. (longword) Required. |
assoc_name |
Address of a string descriptor pointing to the desired association name. If you omit this argument, the ICC default association will be opened. Association names are case sensitive. This is also the name used in the ICC security object for this association. |
|
Address of string descriptors describing the logical name and logical table name for use by the ICC simple registry. The logical name table must exist at the time of the call, and the caller must have write access to the table. Unless your application requires a logical name table for exclusive use of the application, use of the default ICC$REGISTRY_TABLE is recommended. The logical name is case sensitive. Table names are always converted to uppercase. The logical name supplied here is the name by which the client using the registry will know the server. If either of these arguments is supplied, they must both be supplied. |
conn_event_rtn |
Address of a routine to be called whenever a client requests a connection to this server. A server may not omit this parameter. See the sections on connection and disconnection routines for more details about what actions a connection routine must take. |
disc_event_rtn |
Optional address of a routine to be called when a disconnect event occurs. This may be the same routine as the connection routine. See the section on connection and disconnection routines for more details about what actions a disconnection routine may take. |
recv_rtn |
Address of routine to be called whenever a connection receives data. Note that all connections on this association use the same routine. Please see the discussion on transfer sizes in Section 3.3.1.2.4, “Transfer Sizes and Receiving Data” for information on how having or not a having a data routine affects maximum receive size. Optional. |
maxflowbufcnt |
Pass by value the maximum number of inbound messages per connection that ICC will allow before initiating flow control on the connection. The default value for this parameter is 5. Optional. |
prot |
The default protection for this association. Refer to VSI OpenVMS Guide to System Security for information on the security attributes of ICC associations. This parameter is effective only if no Permanent Security Object has been created for this association. If prot is zero (0) or not specified, all users may connect to this association. If prot is one (1), only members of the same UIC group, or users with SYSPRV, may connect. If prot is two (2), only the owner or users with SYSPRV may connect. Object protection specified by a Permanent Security Object overrides this parameter. Additionally, if no Permanent Security Object exists, the value specified here may be overridden by the SET SECURITY command issued for the Temporary Security Object while the association is open. |
3.3.1.4.1. Connection Events
Once the association is opened, connection requests are delivered as asynchronous calls to the server's connection routine.
The connection routine (and disconnection routine, if supplied) are each called with seven arguments as described in the $ICC_OPEN_ASSOC system service, located in the VSI OpenVMS System Services Reference Manual: GETUTC-Z.
A single connection or disconnection routine may distinguish between the events based on the first argument (event_type), which will either be the code ICC$C_EV_CONNECT or ICC$C_EV_DISCONNECT.
A connection routine must either call SYS$ICC_ACCEPT to complete the connection or SYS$ICC_REJECT to reject the connection. The EPID and user name of the requesting process are supplied by ICC. Any additional information required by the application for verification either must be supplied by the client via the connection data parameter or must be obtainable by the server itself (for example, via SYS$GETJPI).
Failure to ACCEPT or REJECT the connection will stall all additional attempts to connect to this server.
3.3.1.4.2. Disconnection Events
A disconnection event signals that the partner application of the connection has requested a disconnect, the partner process has been deleted, or that the remote node has left the cluster. Upon receiving a disconnect event, the server should call SYS$ICC_DISCONNECT to clean up the server side of the connection. However, when the partner that received the disconnect event calls SYS$ICC_DISCONNECT, the connection has already been terminated and the link is already gone. The return status from this call to SYS$ICC_DISCONNECT should be SS$_NORMAL, but the completion status returned in the IOSB is SS$_LINKDISCON.
Failure to call DISCONNECT may leave resources allocated to the connection that are not released until the image terminates. In the case of inner mode associations, resources will be released at process termination.
3.3.1.5. Clients
A simple client need not call SYS$ICC_OPEN_ASSOC although there may be some benefits for even the simplest clients. For a client, the major benefit of calling OPEN is declaring a data receive routine.
In cases where a client may wish to connect to multiple servers, calling OPEN_ASSOC multiple times can help isolate the routines related to data receipt and disconnection.
Argument |
Description |
---|---|
IOS_ICC |
Address of an IOS_ICC structure (defined in ICCDEF). |
|
Optional AST address and parameter. |
assoc_handle |
Either the value returned from the OPEN_ASSOC call or the constant ICC$DEFAULT_ASSOC if OPEN_ASSOC was not called. |
conn_handle |
Address of a longword to receive the connection handle for this connection. |
remote_assoc |
A string descriptor pointing to either the association name of the server or the registry name of the server if the server is using the ICC simple registry. Either use is case sensitive. |
remote_node |
If omitted, then the assoc_name argument will be treated as a name to look up in the ICC simple registry. A zero length or blank string represents the local node. Any other string will be converted to uppercase and must match the name of a node in the cluster. |
user_context |
A unique context value for this connection. This value will be passed to data event and disconnection routines. |
|
Address and length of any connection data. This could include additional authentication or protocol setup data required by the application. |
|
Address and length of a buffer to receive any data (accept or reject data) returned from the server. The buffer must be large enough to receive the maximum amount of data the server might return. The actual number of bytes will be written to retlen_addr. |
flags |
The only valid flag is ICC$M_SYNCH_MODE. If you select synch mode, the data transmission routines (TRANSMIT, REPLY, and RECEIVE – TRANSCEIVE can never complete synchronously) may return the alternate success status SS$_SYNCH and not call the AST completion routine. If you do not specify synch mode, the AST routine, if provided, will always be called. |
When the CONNECT call completes, the connection is established and useable only if success status was returned as both the return value of the service and in the status fields (ios_icc$w_status and ios_icc$l_remstat) of the IOS_ICC.
Chapter 4. Process Control
This chapter describes how to use operating system features to control a process or kernel thread.
4.1. Using Process Control for Programming Tasks
Modularize application programs so that each process or kernel thread of the application executes a single task
Perform parallel processing, in which one process or kernel thread executes one part of a program while another process or kernel thread executes another part
Implement application program control, in which one process manages and coordinates the activities of several other processes
Schedule program execution
Dedicate a process to execute DCL commands
- Isolate code for one or more of the following reasons:
To debug logic errors
To execute privileged code
To execute sensitive code
Obtaining process information
Obtaining kernel thread information
Setting process privileges
Setting process name
Setting process scheduling
Hibernating or suspending a process or kernel thread
Deleting a process
Synchronizing process execution
You can use system routines and DCL commands to accomplish these tasks. Table 4.1, “Routines and Commands for Controlling Processes and Kernel Threads” summarizes which routines and commands to use. You can use the DCL commands in a command procedure that is executed as soon as the subprocess (or detached process) is created.
Routine |
DCL Command |
Task |
---|---|---|
|
SHOW PROCESS |
Return process or kernel thread information. SYS$GETJPI(W) can request process and thread information from a specific PID or PRCNAM. If no specific thread is identified, then the data represents the initial thread. |
SYS$SETPRV |
SET PROCESS |
Set process privileges. |
SYS$SETPRI |
SET PROCESS |
Set process or kernel thread priority. This service affects the base and current priority of a specified kernel thread and not the entire process. |
SYS$SETSWM |
SET PROCESS |
Control swapping of process. |
|
SET PROCESS |
Hibernate, suspend, and resume a process or kernel threads. These services hibernate, suspend, or resume all kernel threads associated with the specified process. |
SYS$SETPRN |
SET PROCESS |
Set process name. |
|
EXIT and STOP |
Initiate process and image rundown. All associated kernel threads of a specified process are run down and deleted. |
SYS$DELPRC |
EXIT and STOP |
Delete process. |
SYS$CANTIM |
CANCEL |
Cancel timer for process or kernel threads. This service finds and cancels all timers for all threads associated with the specified process. |
SYS$ADJSTK |
SET PROCESS |
Adjust or initialize a stack pointer. Stack adjustments are performed for the kernel thread requesting the service. |
SYS$PROCESS_SCAN |
SHOW PROCESS |
Scan for a process or kernel thread on the local system, or across the nodes in an OpenVMS Cluster system. |
SYS$SETSTK |
None available |
Allow the current process or kernel thread to change the size of its stacks. This service adjusts the size of the stacks of the kernel thread that invoked the service. |
By default, the routines and commands reference the current process or kernel thread. To reference another process, you must specify either the process identification (PID) number or the process name when you call the routine or a command qualifier when you enter commands. You must have the GROUP privilege to reference a process with the same group number and a different member number in its UIC, and WORLD privilege to reference a process with a different group number in its UIC.
The information presented in this section covers using the routines. If you want to use the DCL commands in a command procedure, refer to the VSI OpenVMS DCL Dictionary.
4.1.1. Determining Privileges for Process Creation and Control
Processes with the same UIC can always issue process control services for one another.
You need the GROUP privilege to issue process control services for other processes executing in the same group.
You need the WORLD privilege to issue process control services for any process in the system.
You need additional privileges to perform some specific functions; for example, raising the base priority of a process requires ALTPRI privilege.
4.1.2. Determining Process Identification
Process identification (PID) number
The system assigns this unique 32-bit number to a process when it is created. If you provide the
pidadr
argument to the SYS$CREPRC system service, the system returns the process identification number at the location specified. You can then use the process identification number in subsequent process control services.Process name
There are two types of process names:Process name
A process name is a 1- to 15-character name string. Each process name must be unique within its group (processes in different groups can have the same name). You can assign a name to a process by specifying the
prcnam
argument when you create it. You can then use this name to refer to the process in other system service calls. Note that you cannot use a process name to specify a process outside the caller's group; you must use a process identification (PID) number.Full process name
The full process name is unique for each process in the cluster. Full process name strings can be up to 23 characters long and are configured in the following way:- 1–6 characters for the node name
- 2 characters for the colons (::) that follow the node name
- 1–15 characters for the local process name
unsigned int orionid=0, status; $DESCRIPTOR(orion,"ORION"); . . . status = SYS$CREPRC(&orionid, /* pidadr (process id returned) */ &orion, /* prcnam - process name */ ...);
The service returns the process identification in the longword at ORIONID. You can now use either the process name (ORION) or the PID (ORIONID) to refer to this process in other system service calls.
/* Descriptor for process name */ $DESCRIPTOR(cygnus,"CYGNUS"); status = SYS$SETPRN( &cygnus ); /* prcnam - process name */
prcnam
or the
pidadr
argument or both. However, you
should identify a process by its process identification number for
the following reasons: The service executes faster because it does not have to search a table of process names.
For a process not in your group, you must use the process identification number (see Section 4.1.3, “Qualifying Process Naming Within Groups”).
If you specify the PID address, the service uses the PID address. If you specify the process name without a PID address, the service uses the process name. If you specify both – the process name and PID address – it uses the PID address unless the contents of the PID is 0. In that case, the service uses the process name. If you specify a PID address of 0 without a process name, then the service is performed for the calling process.
Process Name Specified? |
PID Address Specified? |
Contents of PID |
Resultant Action by Services |
---|---|---|---|
No |
No |
– |
The process identification of the calling process is used, but is not returned. |
No |
Yes |
0 |
The process identification of the calling process is used and returned. |
No |
Yes |
PID |
The process identification is used and returned. |
Yes |
No |
– |
The process name is used. The process identification is not returned. |
Yes |
Yes |
0 |
The process name is used and the process identification is returned. |
Yes |
Yes |
PID |
The process identification is used and returned; the process name is ignored. |
4.1.3. Qualifying Process Naming Within Groups
Process names are always qualified by their group number. The system
maintains a table of all process names and the UIC associated with
each. When you use the prcnam
argument in a
process control service, the table is searched for an entry that
contains the specified process name and the group number of the
calling process.
To use process control services on processes within its group, a calling process must have the GROUP user privilege; this privilege is not required when you specify a process with the same UIC as the caller.
The search for a process name fails if the specified process name does not have the same group number as the caller. The search fails even if the calling process has the WORLD user privilege. To execute a process control service for a process that is not in the caller's group, the requesting process must use a process identification and must have the WORLD user privilege.
4.2. Obtaining Process Information
The operating system's process information procedures enable you to gather information about processes and kernel threads. You can obtain information about either one process or a group of processes on either the local system or on remote nodes in an OpenVMS Cluster system. You can also obtain process lock information. DCL commands such as SHOW SYSTEM and SHOW PROCESS use the process information procedures to display information about processes. You can also use the process information procedures within your programs.
Get Job/Process Information (SYS$GETJPI(W))
Get Job/Process Information (LIB$GETJPI)
Process Scan (SYS$PROCESS_SCAN)
Get Lock Information (SYS$GETLKI)
The SYS$GETJPI(W) and SYS$PROCESS_SCAN system services can also be used to get kernel threads information. SYS$GETJPI(W) can request threads information from a particular process ID or process name. SYS$PROCESS_SCAN can request information about all threads in a process, or all threads for each multithreaded process on the system.
For more information about SYS$GETJPI, SYS$PROCESS_SCAN, and SYS$GETLKI, see the VSI OpenVMS System Services Reference Manual.
SYS$GETJPI operates asynchronously.
SYS$GETJPIW and LIB$GETJPI operate synchronously.
SYS$GETJPI and SYS$GETJPIW can obtain one or more pieces of information about a process or kernel thread in a single call.
LIB$GETJPI can obtain only one piece of information about a process or kernel thread in a single call.
SYS$GETJPI and SYS$GETJPIW can specify an AST to execute at the completion of the routine.
SYS$GETJPI and SYS$GETJPIW can use an I/O status block (IOSB) to test for completion of the routine.
LIB$GETJPI can return some items either as strings or as numbers. It is often the easiest to call from a high-level language because the caller is not required to construct an item list.
SYS$GETLKI returns information about the lock database.
4.2.1. Using the PID to Obtain Information
The process information procedures return information about processes
by using the process identification (PID) or the process name. The
PID is a 32-bit number that is unique for each process in the
cluster. Specify the PID by using the pidadr
argument. You must specify all the significant digits of a PID; you
can omit leading zeros.
With kernel threads, the PID continues to identify a process, but it can also identify a kernel thread within that process. In a multithreaded process each kernel thread has its own PID that is based on the initial threads PID.
4.2.2. Using the Process Name to Obtain Information
prcnam
argument. Although a PID is unique
for each process in the cluster, a process name is unique (within a
UIC group) only for each process on a node. To locate information
about processes on the local node, specify a process name string of
1 to 15 characters. To locate information about a process on a
particular node, specify the full process name, which can be up to
23 characters long. The full process name is configured in the
following way: 1 to 6 characters for the node name
2 characters for the colons (::) that follow the node name
1 to 15 characters for the local process name
Note that a local process name can look like a remote process name. Therefore, if you specify ATHENS::SMITH, the system checks for a process named ATHENS::SMITH on the local node before checking node ATHENS for a process named SMITH.
VSI OpenVMS Programming Concepts Manual, Volume II and the VSI OpenVMS System Services Reference Manual describe these routines completely, listing all items of information that you can request. LIB$GETJPI, SYS$GETJPI, and SYS$GETJPIW share the same item codes with the following exception: LIB$K_ items can be accessed only by LIB$GETJPI.
! Define request codes INCLUDE '($JPIDEF)' ! Variables for LIB$GETJPI CHARACTER*9 UIC INTEGER LEN STATUS = LIB$GETJPI (JPI$_UIC, 2 ,,, 2 UIC, 2 LEN)
4.2.3. Using SYS$GETJPI and LIB$GETJPI
SYS$GETJPI uses the PID or the process name to obtain information about one process and the -1 wildcard as the pidadr to obtain information about all processes on the local system. If a PID or process name is not specified, SYS$GETJPI returns information about the calling process. SYS$GETJPI cannot perform a selective search – it can search for only one process at a time in the cluster or for all processes on the local system. If you want to perform a selective search for information or get information about processes across the cluster, use SYS$GETJPI with SYS$PROCESS_SCAN.
4.2.3.1. Requesting Information About a Single Process
4.2.3.2. Requesting Information About All Processes on the Local System
You can use SYS$GETJPI to perform a
wildcard search on all processes on the local system. When
the initial pidadr
argument is
specified as -1, SYS$GETJPI returns
requested information for each process that the program has
privilege to access. The requested information is returned
for one process per call to
SYS$GETJPI.
To perform a wildcard search, call SYS$GETJPI in a loop, testing the return status.
Status |
Explanation |
---|---|
SS$_NOMOREPROC |
All processes have been returned. |
SS$_NOPRIV |
The caller lacks sufficient privilege to examine a process. |
SS$_SUSPENDED |
The target process is being deleted or is suspended and cannot return the information. |
4.2.4. Using SYS$GETJPI with SYS$PROCESS_SCAN
Using the SYS$PROCESS_SCAN system service
greatly enhances the power of SYS$GETJPI.
With this combination, you can search for selected groups of
processes or kernel threads on the local system as well as for
processes or kernel threads on remote nodes or across the cluster.
When you use SYS$GETJPI alone, you specify
the pidadr
or the
prcnam
argument to locate information
about one process. When you use SYS$GETJPI
with SYS$PROCESS_SCAN, the
pidctx
argument generated by
SYS$PROCESS_SCAN is used as the
pidadr
argument to
SYS$GETJPI. This context allows
SYS$GETJPI to use the selection
criteria that are set up in the call to
SYS$PROCESS_SCAN.
When using SYS$GETJPI with a PRCNAM specified, SYS$GETJPI returns data for only the initial thread. This parallels the behavior of the DCL commands SHOW SYSTEM, SHOW PROCESS, and MONITOR PROCESS. If a valid PIDADR is specified, then the data returned describes only that specific kernel thread. If a PIDADR of zero is specified, then the data returned describes the calling kernel thread.
SYS$GETJPI has the flag, JPI$_THREAD, as part of the JPI$_GETJPI_CONTROL_FLAGS item code. The JPI$_THREAD flag designates that the service call is requesting data for all of the kernel threads in a multithreaded process. If the call is made with JPI$_THREAD set, then SYS$GETJPI begins with the initial thread, and SYS$GETJPI returns SS$_NORMAL. Subsequent calls to SYS$GETJPI with JPI$_THREAD specified returns data for the next thread until there are no more threads, at which time the service returns SS$_NOMORETHREAD.
If you specify a wildcard PIDADR -1 along with JPI$_THREAD, you cause SYS$GETJPI to return information for all threads for all processes on the system on subsequent calls. SYS$GETJPI returns the status SS$_NORMAL until there are no more processes, at which time it returns SS$_NOMOREPROC. If you specify a wildcard search, you must request either the JPI$_PROC_INDEX or the JPI$_INITIAL_THREAD_PID item code to distinguish the transition from the last thread of a multithreaded process to the next process. The PROC_INDEX and the INITIAL_THREAD_PID are different for each process on the system.
Item Code |
Meaning |
---|---|
JPI$_INITIAL_THREAD_PID |
Returns the PID of the initial thread for the target process |
JPI$_KT_COUNT |
Returns the current count of kernel threads for the target process |
JPI$_MULTITHREAD |
Returns the maximum kernel thread count allowed for the target process |
JPI$_THREAD_INDEX |
Returns the kernel thread index for the target thread or process |
This wildcard search is initiated by invoking SYS$GETJPI with a -1 specified for the PID, and is available only on the local node. With kernel threads, a search for all threads in a single process is available, both on the local node and on another node on the cluster.
In a dual architecture or mixed-version cluster, one or more nodes in the cluster may not support kernel threads. To indicate this condition, a threads capability bit (CSB$M_CAP_THREADS) exists in the CSB$L_CAPABILITY cell in the cluster status block. If this bit is set for a node, it indicates that the node supports kernel threads. This information is passed around as part of the normal cluster management activity when a node is added to a cluster. If a SYS$GETJPI request that requires threads support needs to be passed to another node in the cluster, a check is made on whether the node supports kernel threads before the request is sent to that node. If the node supports kernel threads, the request is sent. If the node does not support kernel threads, the status SS$_INCOMPAT is returned to the caller, and the request is not sent to the other node.
You can use SYS$PROCESS_SCAN only with SYS$GETJPI; you cannot use it alone. The process context generated by SYS$PROCESS_SCAN is used like the -1 wildcard except that it is initialized by calling the SYS$PROCESS_SCAN service instead of by a simple assignment statement. However, the SYS$PROCESS_SCAN context is more powerful and more flexible than the -1 wildcard. SYS$PROCESS_SCAN uses an item list to specify selection criteria to be used in a search for processes and produces a context longword that describes a selective search for SYS$GETJPI.
Using SYS$GETJPI with SYS$PROCESS_SCAN to perform a selective search is a more efficient way to locate information because only information about the processes you have selected is returned. For example, you can specify a search for processes owned by one user name, and SYS$GETJPI returns only the processes that match the specified user name. You can specify a search for all batch processes, and SYS$GETJPI returns only information about processes running as batch jobs. You can specify a search for all batch processes owned by one user name and SYS$GETJPI returns only information about processes owned by that user name that are running as batch jobs.
By default, SYS$PROCESS_SCAN sets up a context for only the initial thread of a multithreaded process. However, if the value PSCAN$_THREAD is specified for the item code PSCAN$_PSCAN_CONTOL_FLAGS, then threads are included in the scan. The PSCAN$_THREAD flag takes precedence over the JPI$_THREAD flag in the SYS$GETJPI call. With PSCAN$_THREAD specified, threads are included in the entire scan. With PSCAN$_THREAD not specified, threads are included in the scan for a specific SYS$GETJPI call only if JPI$_THREAD is specified.
Item Code |
Meaning |
---|---|
PSCAN$_KT_COUNT |
Uses the current count of kernel threads for the process as a selection criteria. The valid item-specific flags for this item code are EQL, GEQ, GTR, LEQ, LSS, NEQ, and OR. |
PSCAN$_MULTITHREAD |
Uses the maximum count of kernel threads for the process as a selection criteria. The valid item-specific flags for this item code are EQL, GEQ, GTR, LEQ, LSS, NEQ, and OR. |
4.2.4.1. Using SYS$PROCESS_SCAN Item List and Item-Specific Flags
SYS$PROCESS_SCAN uses an item list to specify the selection criteria for the SYS$GETJPI search.
The attribute of the process to be examined
The value of the attribute or a pointer to the value
Item-specific flags to control how to interpret the value
Item-Specific Flag |
Description |
---|---|
PSCAN$M_OR |
Match this value or the next value |
PSCAN$M_EQL |
Match value exactly (the default) |
PSCAN$M_NEQ |
Match if value is not equal |
PSCAN$M_GEQ |
Match if value is greater than or equal to |
PSCAN$M_GTR |
Match if value is greater than |
PSCAN$M_LEQ |
Match if value is less than or equal to |
PSCAN$M_LSS |
Match if value is less than |
PSCAN$M_CASE_BLIND |
Match without regard to case of letters |
PSCAN$M_PREFIX_MATCH |
Match on the leading substring |
PSCAN$M_WILDCARD |
Match string is a wildcard pattern |
PSCANLIST(1).BUFLEN = LEN('SMITH') PSCANLIST(1).CODE = PSCAN$_USERNAME PSCANLIST(1).BUFADR = %LOC('SMITH') PSCANLIST(1).ITMFLAGS = PSCAN$M_OR PSCANLIST(2).BUFLEN = LEN('JONES') PSCANLIST(2).CODE = PSCAN$_USERNAME PSCANLIST(2).BUFADR = %LOC('JONES') PSCANLIST(2).ITMFLAGS = PSCAN$M_OR PSCANLIST(3).BUFLEN = LEN('JOHNSON') PSCANLIST(3).CODE = PSCAN$_USERNAME PSCANLIST(3).BUFADR = %LOC('JOHNSON') PSCANLIST(3).ITMFLAGS = 0 PSCANLIST(4).END_LIST = 0
Use the PSCAN$M_WILDCARD flag to specify that a character string is to be treated as a wildcard. For example, to find all process names that begin with the letter A and end with the string ER, use the string A*ER with the PSCAN$M_WILDCARD flag. If you do not specify the PSCAN$M_WILDCARD flag, the search looks for the 4-character process name A*ER.
The PSCAN$M_PREFIX_MATCH defines a wildcard search to match the initial characters of a string. For example, to find all process names that start with the letters AB, use the string AB with the PSCAN$M_PREFIX_MATCH flag. If you do not specify the PSCAN$M_PREFIX_MATCH flag, the search looks for a process with the 2-character process name AB.
4.2.4.2. Requesting Information About Processes That Match One Criterion
You can use SYS$GETJPI with SYS$PROCESS_SCAN to search for processes that match an item list with one criterion. For example, if you specify a search for processes owned by one user name, SYS$GETJPI returns only those processes that match the specified user name.
4.2.4.3. Requesting Information About Processes That Match Multiple Values for One Criterion
You can use SYS$PROCESS_SCAN to search for processes that match one of a number of values for a single criterion, such as processes owned by several specified users.
You must specify each value in a separate item list entry, and connect the item list entries with the PSCAN$M_OR item-specific flag. SYS$GETJPI selects each process that matches any of the item values.
4.2.4.4. Requesting Information About Processes That Match Multiple Criteria
You can use SYS$PROCESS_SCAN to search for processes that match values for more than one criterion. When multiple criteria are used, a process must match at least one value for each specified criterion.
((username = "SMITH") OR (username = "JONES"))
AND
(MODE = JPI$K_BATCH)
See the VSI OpenVMS System Services Reference Manual for more information about SYS$PROCESS_SCAN item codes and flags.
4.2.5. Specifying a Node as Selection Criterion
Several SYS$PROCESS_SCAN item codes do not refer to attributes of a process, but to the VMScluster node on which the target process resides. When SYS$PROCESS_SCAN encounters an item code that refers to a node attribute, it creates an alphabetized list of node names. SYS$PROCESS_SCAN then directs SYS$GETJPI to compare the selection criteria against processes on these nodes.
SYS$PROCESS_SCAN ignores a node specification if it is running on a node that is not part of a VMScluster system. For example, if you request that SYS$PROCESS_SCAN select all nodes with the hardware model name VAX 6360, this search returns information about local processes on a nonclustered system, even if it is a MicroVAX system.
All remote SYS$GETJPI operations are asynchronous and must be synchronized properly. Many applications that are not correctly synchronized might seem to work on a single node because some SYS$GETJPI operations are actually synchronous; however, these applications fail if they attempt to examine processes on remote nodes. For more information on how to synchronize SYS$GETJPI operations, see Chapter 6, Synchronizing Data Access and Program Operations.
The CLUSTER_SERVER process is always a current process, because it is executing on behalf of SYS$GETJPI.
Attempts by SYS$GETJPI to examine a node do not succeed during a brief period between the time a node joins the cluster and the time that the CLUSTER_SERVER process is started. Searches that occur during this period skip such a node. Searches that specify only such a booting node fail with a SYS$GETJPI status of SS$_UNREACHABLE.
SS$_NOMOREPROC is returned after all processes on all specified nodes have been scanned.
4.2.5.1. Checking All Nodes on the Cluster for Processes
4.2.5.2. Checking Specific Nodes on the Cluster for Processes
4.2.5.3. Conducting Multiple Simultaneous Searches with SYS$PROCESS_SCAN
Only one asynchronous remote SYS$GETJPI request per SYS$PROCESS_SCAN context is permitted at a time. If you issue a second SYS$GETJPI request using a context before a previous remote request using the same context has completed, your process stalls in a resource wait until the previous remote SYS$GETJPI request completes. This stall in the RWAST state prevents your process from executing in user mode or receiving user-mode ASTs.
If you want to run remote searches in parallel, create multiple contexts by calling SYS$PROCESS_SCAN once for each context. For example, you can design a program that calls SYS$GETSYI in a loop to find the nodes in the VMScluster system and creates a separate SYS$PROCESS_SCAN context for each remote node. Each of these separate contexts can run in parallel. The DCL command SHOW USERS uses this technique to obtain user information more quickly.
Note
When you use SYS$GETJPI to reference remote processes, you must properly synchronize all SYS$GETJPI calls. Before the operating system's Version 5.2, if you did not follow these synchronization rules, your programs might have appeared to run correctly. However, if you attempt to run such improperly synchronized programs using SYS$GETJPI with SYS$PROCESS_SCAN with a remote process, your program might attempt to use the data before SYS$GETJPI has returned it.
To perform a synchronous search in which the program waits
until all requested information is available, use
SYS$GETJPIW with an
iosb
argument.
See the VSI OpenVMS System Services Reference Manual for more information about process identification, SYS$GETJPI, and SYS$PROCESS_SCAN.
4.2.6. Programming with SYS$GETJPI
The following sections describe some important considerations for programming with SYS$GETJPI.
4.2.6.1. Using Item Lists Correctly
When SYS$GETJPI collects data, it makes multiple passes through the item list. If the item list is self-modifying – that is, if the addresses for the output buffers in the item list point back at the item list – SYS$GETJPI replaces the item list information with the returned data. Therefore, incorrect data might be read or unexpected errors might occur when SYS$GETJPI reads the item list again. To prevent confusing errors, VSI recommends that you do not use self-modifying item lists.
The number of passes that SYS$GETJPI needs depends on which item codes are referenced and the state of the target process. A program that appears to work normally might fail when a system has processes that are swapped out of memory, or when a process is on a remote node.
4.2.6.2. Improving Performance by Using Buffered $GETJPI Operations
To request information about a process located on a remote node, SYS$GETJPI must send a message to the remote node, wait for the response, and then extract the data from the message received. When you perform a search on a remote system, the program must repeat this sequence for each process that SYS$GETJPI locates.
To reduce the overhead of such a remote search, use SYS$PROCESS_SCAN with the PSCAN$_GETJPI_BUFFER_SIZE item code to specify a buffer size for SYS$GETJPI. When the buffer size is specified by SYS$PROCESS_SCAN, SYS$GETJPI packs information for several processes into one buffer and transmits them in a single message. This reduction in the number of messages improves performance.
For example, if the SYS$GETJPI item list requests 100 bytes of information, you might specify a PSCAN$_GETJPI_BUFFER_SIZE of 1000 bytes so that the service can place information for at least 10 processes in each message. (SYS$GETJPI does not send fill data in the message buffer; therefore, information for more than 10 processes can be packed into the buffer).
The SYS$GETJPI buffer must be large enough to hold the data for at least one process. If the buffer is too small, the error code SS$_IVBUFLEN is returned from the SYS$GETJPI call.
You do not have to allocate space for the SYS$GETJPI buffer; buffer space is allocated by SYS$PROCESS_SCAN as part of the search context that it creates. Because SYS$GETJPI buffering is transparent to the program that calls SYS$GETJPI, you do not have to modify the loop that calls SYS$GETJPI.
If you use PSCAN$_GETJPI_BUFFER_SIZE with SYS$PROCESS_SCAN, all calls to SYS$GETJPI using that context must request the same item code information. Because SYS$GETJPI collects information for more than one process at a time within its buffers, you cannot change the item codes or the lengths of the buffers in the SYS$GETJPI item list between calls. SYS$GETJPI returns the error SS$_BADPARAM if any item code or buffer length changes between SYS$GETJPI calls. However, you can change the buffer addresses in the SYS$GETJPI item list from call to call.
4.2.6.3. Fulfilling Remote SYS$GETJPI Quota Requirements
- Add the following together:
The size of the SYS$PROCESS_SCAN item list
The total size of all reference buffers for SYS$PROCESS_SCAN (the sum of all buffer length fields in the item list)
The size of the SYS$GETJPI item list
The size of the SYS$GETJPI buffer
The size of the calling process RIGHTSLIST
Approximately 300 bytes for message overhead
Double this total.
The total is doubled because the messages consume system dynamic memory on both the sending node and the receiving node.
This formula for BYTLM quota applies to both buffered and nonbuffered SYS$GETJPI requests. For buffered requests, use the value specified in the SYS$PROCESS_SCAN item, PSCAN$_GETJPI_BUFFER_SIZE, as the size of the buffer. For nonbuffered requests, use the total length of all data buffers specified in the SYS$GETJPI item list as the size of the buffer.
If the BYTLM quota is insufficient, SYS$GETJPI (not SYS$PROCESS_SCAN) returns the error SS$_EXBYTLM.
4.2.6.4. Using the SYS$GETJPI Control Flags
The JPI$_GETJPI_CONTROL_FLAGS item code, which is specified in the SYS$GETJPI item list, provides additional control over SYS$GETJPI. Therefore, SYS$GETJPI may be unable to retrieve all the data requested in an item list because JPI$_GETJPI_CONTROL_FLAGS requests that SYS$GETJPI not perform certain actions that may be necessary to collect the data. For example, a SYS$GETJPI control flag may instruct the calling program not to retrieve a process that has been swapped out of the balance set.
If SYS$GETJPI is unable to retrieve any data item because of the restrictions imposed by the control flags, it returns the data length as 0. To verify that SYS$GETJPI received a data item, examine the data length to be sure that it is not 0. To make this verification possible, be sure to specify the return length for each item in the SYS$GETJPI item list when any of the JPI$_GETJPI_CONTROL_FLAGS flags is used.
Unlike other SYS$GETJPI item codes, the JPI$_GETJPI_CONTROL_FLAGS item is an input item. The item list entry should specify a longword buffer. The desired control flags should be set in this buffer.
Because the JPI$_GETJPI_CONTROL_FLAGS item code tells SYS$GETJPI how to interpret the item list, it must be the first entry in the SYS$GETJPI item list. The error code SS$_BADPARAM is returned if it is not the first item in the list.
The following are the SYS$GETJPI control flags.
JPI$M_NO_TARGET_INSWAP
When you specify JPI$M_NO_TARGET_INSWAP, SYS$GETJPI does not retrieve a process that has been swapped out of the balance set. Use JPI$M_NO_TARGET_INSWAP to avoid the additional load of swapping processes into a system. For example, use this flag with SHOW SYSTEM to avoid bringing processes into memory to display their accumulated CPU time.
Data stored in the virtual address space of the process is not accessible.
Data stored in the process header (PHD) may not be accessible.
Data stored in resident data structures, such as the process control block (PCB) or the job information block (JIB), is accessible.
You must examine the return length of an item to verify that the item was retrieved. The information may be located in a different data structure in another release of the operating system.
JPI$M_NO_TARGET_AST
When you specify JPI$M_NO_TARGET_AST, SYS$GETJPI does not deliver a kernel-mode AST to the target process. Use JPI$M_NO_TARGET_AST to avoid executing a target process in order to retrieve information.
Data stored in the virtual address space of the process is not accessible.
Data stored in system data structures, such as the process header (PHD), the process control block (PCB), or the job information block (JIB), is accessible.
You must examine the return length of an item to verify that the item was retrieved. The information may be located in a different data structure in another release of the operating system.
The use of the flag JPI$M_NO_TARGET_AST also implies that SYS$GETJPI does not swap in a process, because SYS$GETJPI would only bring a process into memory to deliver an AST to that process.
JPI$M_IGNORE_TARGET_STATUS
When you specify JPI$M_IGNORE_TARGET_STATUS, SYS$GETJPI attempts to retrieve as much information as possible, even if the process is suspended or being deleted. Use JPI$M_IGNORE_TARGET_STATUS to retrieve all possible information from a process. For example, use this flag with SHOW SYSTEM to display processes that are suspended, being deleted, or in miscellaneous wait states.
4.2.7. Using SYS$GETLKI
4.2.8. Setting Process Privileges
Use the SYS$SETPRV system service to set process privileges. Setting process privileges allows you to limit executing privileged code to a specific process, to limit functions within a process, and to limit access from other processes. You can either enable or disable a set of privileges and assign privileges on a temporary or permanent basis. To use this service, the creating process must have the appropriate privileges.
4.3. Changing Process and Kernel Threads Scheduling
Prior to kernel threads, the OpenVMS scheduler selected a process to run. With kernel threads, the OpenVMS scheduler selects a kernel thread to run. All processes are thread-capable processes with at least one kernel thread. A process may have only one kernel thread, or a process may have a variable number of kernel threads. A single-threaded process is equivalent to a process before OpenVMS Version 7.0.
With kernel threads, all base and current priorities are per kernel thread. To alter a thread's scheduling, you can change the base priority of the thread with the SYS$SETPRI system service, which affects the specified kernel thread and not the entire process.
To alter a process's scheduling, you can lock the process into physical memory so that it is not swapped out. Processes that have been locked into physical memory are executed before processes that have been swapped out. For kernel threads, the thread with the highest priority level is executed first.
If you create a subprocess with the LIB$SPAWN routine, you can set the priority of the subprocess by executing the DCL command SET PROCESS/PRIORITY as the first command in a command procedure. You must have the ALTPRI privilege to increase the base priority above the base priority of the creating process.
If you create a subprocess with the LIB$SPAWN routine, you can inhibit swapping by executing the DCL command SET PROCESS/NOSWAP as the first command in a command procedure. Use the SYS$SETSWM system service to inhibit swapping for any process. A process must have the PSWAPM privilege to inhibit swapping.
Priority—Increasing a kernel thread's base priority gives that thread more processor time at the expense of threads that execute at lower priorities. VSI does not recommend this unless you have a program that must respond immediately to events (for example, a real-time program). If you must increase the base priority, return it to normal as soon as possible. If the entire image must execute at an increased priority, reset the base priority before exiting; image termination does not reset the base priority.
Swapping—Inhibiting swapping keeps your process in physical memory. VSI does not recommend inhibiting swapping unless the effective execution of your image depends on it (for example, if the image executing in the process is collecting statistics about processor performance).
4.4. Using Affinity and Capabilities in CPU Scheduling (Alpha and I64 Only)
Create and modify a set of user-defined process capabilities
Create and modify a set of user-defined CPU capabilities to match those in the process
Allow a process to apply the affinity mechanisms to a subset of the active CPU set in a symmetric multiprocessing (SMP) configuration
4.4.1. Defining Affinity and Capabilities
The affinity mechanism allows a process, or each of its kernel threads, to specify an exact set of CPUs on which it can execute. The capabilities mechanism allows a process to specify a set of resources that a CPU in the active set must have defined before it is allowed to contend for process execution. Presently, both of these mechanisms are present in the OpenVMS scheduling mechanism; both are used extensively internally and externally to implement parts of the I/O and timing subsystems. Now, however, the OpenVMS operating system provides user access to these mechanisms.
4.4.1.1. Using Affinity and Capabilities with Caution
It is important for users to understand that inappropriate and abusive use of the affinity and capabilities mechanisms can have a negative impact on the symmetric aspects of the current multi-CPU scheduling algorithm.
4.4.2. Types of Capabilities
Capability |
Description |
---|---|
Primary |
Owned by only one CPU at a time, since the primary could possibly migrate from CPU to CPU in the configuration. For I/O and timekeeping functions, the system requires that the process run on the primary CPU. The process requiring this capability is allowed to run only on the processor that has it at the time. |
Run |
Controls the ability of a CPU to execute processes. Every process requires this resource; if the CPU does not have it, scheduling for that CPU comes to a halt in a recognized state. The command STOP/CPU uses this capability when it is trying to make the CPU quiescent, bringing it to a halted state. |
Quorum |
Used in a cluster environment when a node wants another node to come to a quiescent state until further notice. Like the Run capability, Quorum is a required resource for every process and every CPU in order for scheduling to occur. |
Vector |
Like the primary capability, it reflects a feature of the CPU; that is, that the CPU has a vector processing unit directly associated with it. Obsolete on OpenVMS Alpha and OpenVMS I64 systems but is retained as a compatibility feature with OpenVMS VAX. |
4.4.3. Looking at User Capabilities
Previously, the use of capabilities was restricted to system resources and control events. However, it is also valuable for user functions to be able to indicate a resource or special CPU function.
There are 16 user-defined capabilities added to both the process and the CPU structures. Unlike the static definitions of the current system capabilities, the user capabilities have meaning only in the context of the processes that define them. Through system service interfaces, processes or individual threads of a multithreaded process, can set specific bits in the capability masks of a CPU to give it a resource, and can set specific bits in the kernel thread's capability mask to require that resource as an execution criterion.
The user capability feature is a direct superset of the current capability functionality. All currently existing capabilities are placed into the system capability set; they are not available to the process through system service interfaces. These system service interfaces affect only the 16 bits specifically set aside for user definition.
The OpenVMS operating system has no direct knowledge of what the defined capability is that is being used. All responsibility for the correct definition, use, and management of these bits is determined by the processes that define them. The system controls the impact of these capabilities through privilege requirements; but, as with the priority adjustment services, abusive use of the capability bits could affect the scheduling dynamic and CPU loads in an SMP environment.
4.4.4. Using the Capabilities System Services
The SYS$CPU_CAPABILITIES and SYS$PROCESS_CAPABILITIES system services provide access to the capability features. By using the SYS$CPU_CAPABILITIES and SYS$PROCESS_CAPABILITIES services, you can assign user capabilities to a CPU and to a specific kernel thread. Assigning a user capability to a CPU lasts either for the life of the system or until another explicit change is made. This operation has no direct effect on the scheduling dynamics of the system; it only indicates that the specified CPU is capable of handling any process or thread that requires that resource. If a process does not indicate that it needs that resource, it ignores the CPU's additional capability and schedules the process on the basis of other process requirements.
Assigning a user capability requirement to a specific process or thread has a major impact on the scheduling state of that entity. For the process or thread to be scheduled on a CPU in the active set, that CPU must have the capability assigned prior to the scheduling attempt. If no CPU currently has the correct set of capability requirements, the process is placed into a wait state until a CPU with the right configuration becomes available. Like system capabilities, user process capabilities are additive; that is, for a CPU to schedule the process, the CPU must have the full complement of required capabilities.
These services reference both sets of 16-bit user capabilities by the common symbolic constant names of CAP$M_USER1 through CAP$M_USER16. These names reflect the corresponding bit position in the appropriate capability mask; they are nonzero and self-relative to themselves only.
Both services allow multiple bits to be set or cleared, or both, simultaneously. Each takes as parameters a select mask and a modify mask that define the operation set to be performed. The service callers are responsible for setting up the select mask to indicate the user capabilities bits affected by the current call. This select mask is a bit vector of the ORed bit symbolic names that, when set, states that the value in the modify mask is the new value of the bit. Both masks use the symbolic constants to indicate the same bit; alternatively, if appropriate, you can use the symbolic constant CAP$K_USER_ALL in the select mask to indicate that the entire set of capabilities is affected. Likewise, you can use the symbolic constant CAP$K_USER_ADD or CAP$K_USER_REMOVE in the modify mask to indicate that all capabilities specified in the select mask are to be either set or cleared.
For information about using the SYS$CPU_CAPABILITIES and SYS$PROCESS_CAPABILITIES system services, see the VSI OpenVMS System Services Reference Manual: A-GETUAI and VSI OpenVMS System Services Reference Manual: GETUTC-Z.
4.4.5. Types of Affinity
There are two types of affinity: implicit and explicit. This section describes both.
4.4.5.1. Implicit Affinity
Implicit affinity, sometimes known as soft affinity, is a variant form of the original affinity mechanism used in the OpenVMS scheduling mechanisms. Rather than require a process to stay on a specific CPU regardless of conditions, implicit affinity maximizes cache and translation buffer (TB) context by maintaining an association with the CPU that has the most information about a given process.
Currently, the OpenVMS scheduling mechanism already has a version of implicit affinity. It keeps track of the last CPU the process ran on and tries to schedule itself to that CPU, subject to a fairness algorithm. The fairness algorithm makes sure a process is not skipped too many times when it normally would have been scheduled elsewhere.
The Alpha architecture lends itself to maintaining cache and TB context that has significant potential for performance improvement at both the process and system level. Because this feature contradicts the normal highest-priority process-scheduling algorithms in an SMP configuration, implicit affinity cannot be a system default.
The SYS$SET_IMPLICIT_AFFINITY system
service provides implicit affinity support. This service
works on an explicitly specified process or kernel thread
block (KTB) through the pidadr
and
prcnam
arguments. The default
is the current process, but if the symbolic constant
CAP$K_PROCESS_DEFAULT is
specified in pidadr
, the bit is set
in the global default cell
SCH$GL_DEFAULT_PROCESS_CAP.
Setting implicit affinity globally is similar to setting a
capability bit in the same mask, because every process
creation after the modification picks up the bit as a
default that stays in effect across all image
activations.
The protections required to invoke SYS$SET_IMPLICIT_AFFINITY depend on the process that is being affected. Because the addition of implicit affinity has the same potential as the SYS$ALTPRI service for affecting the priority scheduling of processes in the COM queue, ALTPRI protection is required as the base which all modification forms of the serve must have to invoke SYS$SET_IMPLICIT_AFFINITY. If the process is the current one, no other privilege is required. To affect processes in the same UIC group, the GROUP privilege is required. For any other processes in the system, the WORLD privilege is required.
4.4.5.2. Explicit Affinity
Even though capabilities and affinity overlap considerably in their functional behavior, they are nonetheless two discrete scheduling mechanisms. Affinity, the subsetting of the number of CPUs on which a process can execute, has precedence over the capability feature and provides an explicit binding operation between the process and CPU. It forces the scheduling algorithm to consider only the CPU set it requires, and then applies the capability tests to see whether any of them are appropriate.
Explicit affinity allows database and high-performance applications to segregate application functions to individual CPUs, providing improved cache and TB performance as well as reducing context switching and general scheduling overhead. During the IPL 8 scheduling pass, the process is investigated to see to which CPUs it is bound and whether the current CPU is one of those. If it passes that test, capabilities are also validated to allow the process to context switch. The number of CPUs that can be supported is 32.
The SYS$PROCESS_AFFINITY system
service provides access to the explicit affinity
functionality. SYS$PROCESS_AFFINITY
resolves to a specific process, defaulting to the current
one, through the pidadr
and
prcnam
arguments. Like the
other system services, the CPUs that are affected are
indicated through select_mask, and the binding state of each
CPU is specified in modify_mask.
Specific CPUs can be referenced in select_mask and modify_mask using the symbolic constants CAP$M_CPU0 through CAP$M_CPU31. These constants are defined to match the bit position of their associated CPU ID. Alternatively, specifying CAP$K_ALL_ACTIVE_CPUS in select_mask sets or clears explicit affinity for all CPUs in the current active set.
Explicit affinity, like capabilities, has a permanent process as well as current image copy. As each completed image is run down, the permanent explicit affinity values overwrite the running image set, superseding any changes that were made in the interim. Specifying CAP$M_FLAG_PERMANENT in the flags parameter indicates that both the current and permanent processes are to be modified simultaneously. As a result, unless explicitly changed again, this operation has a scope from the current image through the end of the process life.
For information about the SYS$SET_IMPLICIT_AFFINITY and SYS$PROCESS_AFFINITY system services, see the VSI OpenVMS System Services Reference Manual: A-GETUAI and VSI OpenVMS System Services Reference Manual: GETUTC-Z.
4.5. Using the Class Scheduler in CPU Scheduling
The class scheduler gives you the ability to limit the amount of CPU time that a system's users may receive by placing the users into scheduling classes. Each class is assigned a percentage of the overall system's CPU time. As the system runs, the combined set of users in a class are limited to the percentage of CPU execution time allocated to their class. The users may get some additional CPU time if the qualifier /WINDFALL is enabled for their scheduling class. Enabling the qualifier /WINDFALL allows the system to give a small amount of CPU time to a scheduling class when a CPU is idle and the scheduling class's allotted time has been depleted.
Subcommand |
Meaning |
---|---|
Add |
Creates a new scheduling class |
Delete |
Deletes a scheduling class |
Modify |
Modifies the characteristics of a scheduling class |
Show |
Shows the characteristics of a scheduling class |
Suspend |
Suspends temporarily a scheduling class |
Resume |
Resumes a scheduling class |
4.5.1. Specifications for the Class_Schedule Command
The full specifications for Class_Schedule and its subcommands are as follows:
4.5.1.1. The Add Subcommand
SYSMAN>class_schedule add "class name" /cpulimit = ([primary], [h1-h2=time%],[h1=time%], [,...],[secondary],[h1-h2=time%],[h1=time%],[,...]) [/primedays = ([no]day[,...])] [/username = (name1, name2,...name"n")] [/account = (name1, name2,...name"n")] [/uic = (uic1,uic2,...uic"n")] [/windfall]
The Class Name and Qualifiers
The class name is the name of the scheduling class. It must be specified and the maximum length for this name is 16 characters.
Qualifier |
Meaning |
---|---|
/CPULIMIT |
Defines the maximum amount of CPU time that this scheduling class can receive for the specified days and hours. You must specify this qualifier when adding a class. The h1-h2=time% syntax allows you to specify a range of hours followed by the maximum amount of CPU time (expressed as a percentage) to be associated with this set of hours. The first set of hours after the keyword PRIMARY specifies hours on primary days; the set of hours after the keyword SECONDARY specifies hours on secondary days. The hours are inclusive; if you class schedule a given hour, access extends to the end of that hour. |
/PRIMEDAYS |
Allows you to define which days are primary days and which days are secondary days. You specify primary days as MON, TUE, WED, THU, FRI, SAT, and SUN. You specify secondary days as NOMON, NOTUE, NOWED, NOTHU, NOFRI, NOSAT, and NOSUN. The default is MON through FRI and NOSAT and NOSUN. Any days omitted from the list take their default value. You can use the DCL command, SET DAY, to override the class definition of primary and secondary days. |
/USERNAME |
Specifies which user is part of this scheduling class. This is part of a user's SYSUAF record. |
/ACCOUNT |
Specifies which user is part of this scheduling class. This is part of a user's SYSUAF record. |
/UIC |
Specifies which users are part of this scheduling class. This is part of a user's SYSUAF record. |
/WINDFALL |
Specifies that all processes in the scheduling class are eligible for windfall. By enabling windfall, you allow processes in the scheduling class to receive a "windfall," that is, a small percentage of CPU time, when the class' allotted CPU time has been depleted and a CPU is idle. Rather than let the CPU remain idle, you might decide that it is better to let these processes execute even if it means giving them more than their allotted time. The default value is for windfall to be disabled. |
4.5.1.2. The Delete Subcommand
SYSMAN>class_schedule delete "class name"
The Delete subcommand deletes the scheduling class from the class scheduler database file, and all processes that are members of this scheduling class are no longer class scheduled.
4.5.1.3. The Modify Subcommand
SYSMAN>class_schedule modify "class name" /cpulimit = ([primary], [h1-h2=time%],[h1=time%], [,...],[secondary],[h1-h2=time%],[h1=time%],[,...]) [/primedays = ([no]day[,...])] [/username = (name1, name2,...name"n")] [/account = (name1, name2,...name"n")] [/uic = (uic1,uic2,...uic"n")] [/(no)windfall]
The Modify subcommand changes the characteristics of a scheduling class. The qualifiers are the same qualifiers as for the add subcommand. To remove a time restriction, specify a zero (0) for the time percentage associated with a particular range of hours.
To remove a name or uic value, you must specify a minus sign in front of each name or value.
4.5.1.4. The Show Subcommand
SYSMAN>class_schedule show [class name] [/all] [/full]
Qualifier |
Meaning |
---|---|
/ALL |
Displays all scheduling classes. The qualifier must be specified if no class name is given. |
/FULL |
Displays all information about his scheduling class. |
Note
Name
Maximum CPU times for reach range of hours
Primary days and secondary days
Windfall settings
4.5.1.5. The Suspend Subcommand
SYSMAN>class_schedule suspend "class name"
The Suspend subcommand suspends the specified scheduling class. All processes that are part of this scheduling class remain as part of this scheduling class but are granted unlimited CPU time.
4.5.1.6. The Resume Subcommand
SYSMAN>class_schedule resume "class name"
The Resume subcommand complements the suspend command. You use this command to resume a scheduling class that is currently suspended.
4.5.2. The Class Scheduler Database
The class scheduler database is a permanent database that allows OpenVMS to class schedule processes automatically after a system has been booted and rebooted. This database resides on the system disk in SYS$SYSTEM:VMS$CLASS_SCHEDULE.DATA. SYSMAN creates this file as an RMS indexed file when the first scheduling class is created by the SYSMAN command, class_schedule add.
4.5.2.1. The Class Scheduler Database and Process Creation
By using a permanent class scheduler, a process is placed into a scheduling class, if appropriate, at process creation time. When a new process is created, it needs to be determined whether this process belongs to a scheduling class. Since to determine this relies upon data in the SYSUAF file, and the Loginout image already has the process' information from this file, Loginout class schedules the process if it determines that the process belongs to a scheduling class.
There are two other types of processes to consider during process creation: subprocess and detached process. A subprocess becomes part of the same scheduling class as the parent process, even though it may not match the class's criteria. That is, its user and account name and/or UIC may not be part of the class's record. A detached process only joins a scheduling class if it executes the Loginout image (Loginout.exe) during process creation.
Though a process can join a scheduling class at process creation time, you can change or modify its scheduling class during runtime with the SET PROCESS/SCHEDULING_CLASS command.
4.5.3. Determining If a Process Is Class Scheduled
The SHOW SYSTEM DCL command
The SYS$GETJPI system service
The Authorize utility
The SHOW SYSTEM DCL Command
The DCL command, SHOW SYSTEM, with the qualifier, /SCHEDULING_CLASS ="name", displays processes that belong to a specific scheduling class, or if no name is specified, it displays all class scheduled processes and the name of their scheduling class. The SHOW SYSTEM/FULL command shows the scheduling class name of all processes that are class scheduled.
For more information about the DCL command SHOW SYSTEM, see VSI OpenVMS DCL Dictionary: N–Z.
The SYS$GETJPI System Service
The SYS$GETJPI system service item code, JPI$_CLASS_NAME, returns the name of the scheduling class, as a character string, that this process belongs to. If the process is not class scheduled, then a return length of zero (0) is returned to the caller.
For more information about the SYS$GETJPI system service, see the VSI OpenVMS System Services Reference Manual: A-GETUAI.
The Authorize Utility
When a new user is added to the SYSUAF file, or when a user's record is modified. Authorize searches the class scheduler database file to determine if this user is a member of a scheduling class. If it is, then Authorize displays the following message: UAF-I-SCHEDCLASS, which indicates that the user is a member of a scheduling class.
4.5.4. The SYS$SCHED System Service
The SYS$SCHED system service allows you to create a temporary class scheduling database. The processes are class-scheduled by PID, after the process has been created. The SYSMAN interface creates a separate and permanent class scheduling database that schedules you at process creation time. A process cannot belong to both databases, the SYS$SCHED and SYSMAN database. Therefore, the SYS$SCHED system service checks to see if the process to be inserted into a scheduling class is already class scheduled before it attempts to place the specified process into a scheduling class. If it is already class scheduled, then the error message, SS$_INSCHEDCLASS, is returned from SYS$SCHED.
For more information about the SYS$SCHED system service, see the VSI OpenVMS System Services Reference Manual: GETUTC-Z.
4.6. Changing Process Name
Use the system service SYS$SETPRN to change the name of your process. SYS$SETPRN can be used only on the calling process. Changing process names might be useful when a lengthy image is being executed. You can change names at significant points in the program; then monitor program execution through the change in process names. You can obtain a process name by calling a SYS$GETJPI routine from within a controlling process, either by pressing the Ctrl/T key sequence if the image is currently executing in your process, or by entering the DCL command SHOW SYSTEM if the program is executing in a detached process.
. . . ! Calculate approximate tax rates STATUS = SYS$SETPRN ('INCTAXES') IF (.NOT. STATUS) CALL LIB$SIGNAL(%VAL(STATUS)) STATUS = TAX_RATES (TOTAL_HOUSES, 2 PERSONS_HOUSE, 2 ADULTS_HOUSE, 2 INCOME_HOUSE, 2 TAX_PER_HOUSE) IF (.NOT. STATUS) CALL LIB$SIGNAL(%VAL(STATUS)) ! Sort STATUS = SYS$SETPRN ('INCSORT') IF (.NOT. STATUS) CALL LIB$SIGNAL(%VAL(STATUS)) STATUS = TAX_SORT (TOTAL_HOUSES, 2 TAX_PER_HOUSE) IF (.NOT. STATUS) CALL LIB$SIGNAL(%VAL(STATUS)) ! Write report STATUS = SYS$SETPRN ('INCREPORT') IF (.NOT. STATUS) CALL LIB$SIGNAL(%VAL(STATUS)) . . .
4.7. Accessing Another Process's Context
On OpenVMS VAX systems, a system programmer must sometimes develop code that performs various actions (such as performance monitoring) on behalf of a given process, executing in that process's context. To do so, a programmer typically creates a routine consisting of position-independent code and data, allocates sufficient space in nonpaged pool, and copies the routine to it. On OpenVMS VAX systems, such a routine can execute correctly no matter where it is loaded into memory.
On OpenVMS Alpha and I64 systems, the practice of moving code in memory is more difficult and complex. It is not enough to simply copy code from one memory location to another. On OpenVMS Alpha and I64 systems, you must relocate both the routine and its linkage section, being careful to maintain the relative distance between them, and then apply all appropriate fixups to the linkage section.
Code that must read from or write to another process's registers or address space can use the EXE$READ_PROCESS and EXE$WRITE_PROCESS system routines, as described in Section 4.7.1, “Reading and Writing in the Address Space of Another Process (Alpha and I64 Only)”.
Code that must perform other operations in another process's context (for instance, to execute a system service to raise a target process's quotas) can be written as an OpenVMS Alpha or OpenVMS I64 executive image, as described in Section 4.7.2, “Writing an Executive Image (Alpha and I64 Only)”.
4.7.1. Reading and Writing in the Address Space of Another Process (Alpha and I64 Only)
EXE$READ_PROCESS and EXE$WRITE_PROCESS are OpenVMS Alpha and OpenVMS I64 system routines in nonpaged system space. EXE$READ_PROCESS reads data from a target process's address space or registers and writes it to a buffer in the local process's address space. EXE$WRITE_PROCESS obtains data from a local process's address space and transfers it to the target process's context. Both routines must be called from kernel mode at IPL 0.
One of the arguments to these procedures specifies whether or not the procedure is to access memory and registers in the target process. Another argument specifies the memory address or register number. The contents of these arguments are symbolic names (beginning with the prefix EACB$) that are defined by the $PROCESS_READ_WRITE macro in SYS$LIBRARY:LIB.MLB. (They are also defined in LIB.REQ for BLISS programmers).
4.7.1.1. EXE$READ_PROCESS and EXE$WRITE_PROCESS
The following are descriptions of the callable interfaces to EXE$READ_PROCESS and EXE$WRITE_PROCESS.
EXE$READ_PROCESS
EXE$READ_PROCESS — Reads data from a target process's address space or registers and writes it to a buffer in the local process's address space.
Module
PROC_READ_WRITE
Format
status = EXE$READ_PROCESS
(ipid, buffer_size, target_address, local_address,
target_address_type, ast_counter_address)
Arguments
ipid
OpenVMS usage | ipid |
type | longword (unsigned) |
access | read only |
mechanism | by value |
buffer_size
OpenVMS usage | longword_unsigned |
type | longword (unsigned) |
access | read only |
mechanism | by value |
Number of bytes to transfer. If target_address_type is EACB$K_GENERAL_REGISTER, the values of target_address and buffer_size together determine how many 64-bit registers are written, in numeric order, to the buffer. A partial register is written for any value that is not a multiple of 8.
If you specify buffer_size to be larger than 8, more than one register is written from the buffer. Registers are written in numeric order, followed by the PC and PS, starting at the register indicated by target_address.
If target_address_type is EACB$K_GENERAL_REGISTER and the values of buffer_size and target_address would cause a target process read extending beyond the last available register (based on the value of EACB$K_GEN_REGS_LENGTH), EXE$READ_PROCESS returns SS$_ILLSER status.
target_address
OpenVMS usage | longword_unsigned |
type | longword (unsigned) |
access | read only |
mechanism | by reference (if address); by value (if constant) |
If target_address_type is EACB$K_MEMORY, address in target process at which the transfer is to start.
If target_address_type is EACB$K_GENERAL_REGISTER, symbolic constant indicating at which general register the transfer should start. Possible constant values include EACB$K_R0 through EACB$K_R29, EACB$K_PC, and EACB$K_PS.
For I64, if target_address_type is EACB$K_GENERAL_REGISTER, register values extend from eacb$k_r0 through eacb$k_isr (see proc_read_write.h).
If target_address_type type is EACB$K_INVOCATION_CONTEXT, register values represent values in an INVOCATION_CONTEXT. See the VSI OpenVMS Calling Standard for the definition of invocation context.
local_address
OpenVMS usage | longword_unsigned |
type | longword (unsigned) |
access | read only |
mechanism | by reference |
target_address_type
OpenVMS usage | integer |
type | longword (unsigned) |
access | read only |
mechanism | by value |
Symbolic constant indicating whether the target_address argument is a memory address (EACB$K_MEMORY) or a general register (EACB$K_GENERAL_REGISTER). Floating-point registers are not supported as target addresses.
For I64, symbolic constant indicating whether the target_address argument is a memory address (eacb$k_memory), or a general register (eacb$k_general_register), or an invocation context (eacb$k_invocation_context). Floating point registers are not supported as target addresses.
ast_counter_address
OpenVMS usage | longword_unsigned |
type | longword (unsigned) |
access | read only |
mechanism | by reference |
Returns
OpenVMS usage | cond_value |
type | longword (unsigned) |
access | write only |
mechanism | by value |
Return Values
SS$_ACCVIO | Unable to write to the location indicated by local_address or ast_counter_address. |
SS$_ILLSER | Routine was called with IPL greater than 0, or an illegal target_address_type was specified. If target_address_type is EACB$K_GENERAL_REGISTER, this status can indicate that the values of buffer_size and target_address would cause a target process read extending beyond the last available register (based on the value of EACB$K_GEN_REGS_LENGTH). |
SS$_INSFMEM | Insufficient memory available for specified buffer. |
SS$_NONEXPR | The ipid argument does not correspond to an existing process. |
SS$_NORMAL | The interprocess read finished successfully. |
SS$_TIMEOUT | The read operation did not finish within a few seconds. |
Context
The caller of EXE$READ_PROCESS must be executing in kernel mode at IPL 0. Kernel mode ASTs must be enabled.
Description
EXE$READ_PROCESS reads data from a target process's address space and writes it to a buffer in the local process's address space.
EXE$READ_PROCESS allocates nonpaged pool for an AST control block (ACB), an ACB extension, and a buffer of the specified size. It initializes the extended ACB with information describing the data transfer and then delivers an AST to the target process to perform the operation. The data is read in the context of the target process from its address space or registers into nonpaged pool. An AST is then queued to the requesting process to complete the read operation by copying the data from pool to the process's buffer.
EXE$READ_PROCESS does not return to its caller until the read is completed, an error is encountered, or it has timed out. (The current timeout value is 3 seconds).
EXE$WRITE_PROCESS
EXE$WRITE_PROCESS — Reads data from the local process’s address space and writes it either to a target process’s registers or a buffer in a target process’s address space.
Module
PROC_READ_WRITE
Format
status = EXE$WRITE_PROCESS
(ipid, buffer_size, local_address, target_address,
target_address_type, ast_counter_address)
Arguments
ipid
OpenVMS usage | idip |
type | longword (unsigned) |
access | read only |
mechanism | by value |
buffer_size
OpenVMS usage | longword_unsigned |
type | longword (unsigned) |
access | read only |
mechanism | by value |
Number of bytes to transfer. If target_address_type is EACB$K_GENERAL_REGISTER, the values of target_address and buffer_size together determine how many 64-bit registers are written, in numeric order, from the buffer. A partial register is written for any value that is not a multiple of 8.
If you specify buffer_size to be larger than 8, more than one register is written from the buffer. Registers are written in numeric order, followed by the PC and PS, starting at the register indicated by target_address.
If target_address_type is EACB$K_GENERAL_REGISTER and the values of buffer_size and target_address would cause a write extending beyond the last available register (based on the value of EACB$K_GEN_REGS_LENGTH), EXE$WRITE_PROCESS returns SS$_ILLSER status.
local_address
OpenVMS usage | longword_unsigned |
type | longword (unsigned) |
access | read only |
mechanism | by reference |
target_address
OpenVMS usage | longword_unsigned |
type | longword (unsigned) |
access | read only |
mechanism | by reference (if address) by value (if constant) |
If target_address_type is EACB$K_MEMORY, address in target process at which the transfer is to start.
If target_address_type is EACB$K_GENERAL_REGISTER, symbolic constant indicating at which general register the transfer should start. Possible constant values include EACB$K_R0 through EACB$K_R29, EACB$K_PC, and EACB$K_PS.
For I64, if target_address_type is EACB$K_GENERAL_REGISTER, register values extend from each$k_r0 through eacb$k_isr (see proc_read_write.h).
For Alpha and I64, target_address_type may not be set to EACB$K_INVOCATION_CONTEXT.
target_address_type
OpenVMS usage | longword_unsigned |
type | longword (unsigned) |
access | read only |
mechanism | by value |
ast_counter_address
OpenVMS usage | longword_unsigned |
type | longword (unsigned) |
access | read only |
mechanism | by reference |
Returns
OpenVMS usage | cond_value |
type | longword (unsigned) |
access | write only |
mechanism | by value |
Return Values
SS$_ACCVIO | Unable to read from the location indicated by local_address or write to the location indicated by ast_counter_address. |
SS$_ILLSER | Routine was called with IPL greater than 0, or an illegal target_address_type was specified. If target_address_type is EACB$K_GENERAL_REGISTER, this status can indicate that the values of buffer_size and target_address would cause a process write extending beyond the last available register (based on the value of EACB$K_GEN_REGS_LENGTH). |
SS$_INSFMEM | Insufficient memory available for specified buffer. |
SS$_NONEXPR | The ipid argument does not correspond to an existing process. |
SS$_NORMAL | The interprocess write finished successfully. |
SS$_TIMEOUT | The write operation did not finish within a few seconds. |
Context
The caller of EXE$WRITE_PROCESS must be executing in kernel mode at IPL 0. Kernel mode ASTs must be enabled.
Description
EXE$WRITE_PROCESS reads data from the local process's address space and writes it to a target process's registers or a buffer in a target process's address space.
EXE$WRITE_PROCESS allocates nonpaged pool for an AST control block (ACB), an ACB extension, and a buffer of the specified size. It initializes the extended ACB with information describing the data transfer, copies the data to be written to the target process into the buffer, and then delivers an AST to the target process to perform the operation.
The AST routine copies the data from pool into the target location and then queues an AST to the requesting process to complete the write operation.
EXE$WRITE_PROCESS does not return to its caller until the read is completed, an error is encountered, or it has timed out. (The current timeout value is 3 seconds).
4.7.2. Writing an Executive Image (Alpha and I64 Only)
An executive image is an image that is mapped into system space as part of the OpenVMS executive. It contains data, routines, and initialization code specific to an image's functions and features. An executive image is implemented as a form of shareable image. Like any shareable image, it has a global symbol table, image section descriptors, and an image activator fixup section. Unlike a shareable image, however, an executive image does not usually contain a symbol vector.
Universally available procedures and data cells in system-supplied executive images are accessed through entries provided by the symbol vectors in the system base images SYS$BASE_IMAGE.EXE and SYS$PUBLIC_VECTORS.EXE. References to an executive image are resolved through these symbol vectors, whether from an executive image or from a user executable or shareable image.
Unlike a system-supplied executive image, an executive image that you create cannot provide universally accessible entry points and symbols in this manner. Instead, it must establish its own vector of procedure descriptors for its callable routines and make the address of that vector available systemwide.
- On Alpha, an executive image can contain at most one image section of the following types and no others:
Nonpaged execute section (for code)
Nonpaged read/write section (for read-only and writable data, locations containing addresses that must be relocated at image activation, and the linkage section for nonpaged code)
Paged execute section (for code)
Paged read/write section (for read-only and writable data, locations containing addresses that must be relocated at image activation, and the linkage section for pageable code)
Initialization section (for initialization procedures and their associated linkage section and data)
Image activator fixup section
The modules of an executive image define program sections (PSECT) with distinct names. The named PSECT is necessary so that the program sections can be collected into clusters, by means of the COLLECT= linker option, during linking. A COLLECT= option specified in the linking of an executive image generates each of the first five image sections.
The linker creates the image activator fixup section to enable the image activator to finally resolve references to SYS$BASE_IMAGE.EXE and SYS$PUBLIC_VECTORS.EXE with addresses within the loaded executive image. Once the executive image has been initialized, the OpenVMS executive loader deallocates the memory for both the fixup section and the initialization section.
- On I64, an executive image can have any number of image sections of various types. Image sections are loaded using the actual image size, and a type-specific allocation granularity less than the page size. Having more than a minimum number of image sections has some impact on physical memory consumption, but much less than on Alpha. All image sections are loaded into non-pagable memory of the following types:
Nonpaged execute section (for code)
Nonpaged read/write section (for read-only and writable data, and locations containing addresses that must be relocated by the exec loader)
Initialization read/write section (for initialization procedures and their associated data)
Image activator fixup section (the 'dynamic' segment)
An executive image may have a symbol vector, which defines procedures and data that are to be accessed by other executive images. Most procedure and data references between executive images are resolved through the symbol vector in SYS$BASE_IMAGE, which reduces the dependencies between executive images.
Once the executive image has been initialized, the OpenVMS executive loader deallocates the memory for both the fixup section and the initialization section.
You link an executive image as a type of shareable image that can be loaded by the executive loader. When linking an executive image, VSI strongly recommends using the linker options file SYS$LIBRARY:VMS_EXECLET_LINK.OPT, which sets PSECT attributes on COLLECT options to link an executive image appropriately. The option file contents differ between Alpha and I64 for appropriate linking for each architecture.
Note that on OpenVMS Alpha and I64 systems the execute section cannot contain data. You must collect all data, whether read-only or writable, into one of the read/write sections.
On OpenVMS Alpha systems, VSI recommends linking executive images using the /SECTION_BINDING qualifier to the LINK command. The executive loader can then consolidate image sections into granularity hint regions. This process yields a tangible performance benefit. See the VSI OpenVMS Linker Utility Manual for more information about section binding.
On OpenVMS I64 systems, the executive loader may always consolidate image sections into granularity hint regions. No special linker qualifiers are required. However, for compatibility with Alpha, the I64 linker allows, but ignores, the /SECTION_BINDING qualifier.
See Section 4.7.2.2, “Linking an Executive Image (Alpha or I64 Only)” for a template of a LINK command and linker options file used to produce an executive image.
An executive image can contain one or more initialization procedures that are executed when the image is loaded. If the image is listed in SYS$LOADABLE_IMAGES:VMS$SYSTEM_IMAGES.DAT as created by means of System Management utility (SYSMAN) commands, initialization procedures can be run at various stages of system initialization.
An initialization routine performs a variety of functions, some specific to the features supported by the image and others required by many executive images. An executive image declares an initialization routine (see Section 4.7.2.1, “INITIALIZATION_ROUTINE Macro (Alpha and I64 Only)”).
The initialization routine may return information to the caller of LDR$LOAD_IMAGE via a caller-supplied buffer.
4.7.2.1. INITIALIZATION_ROUTINE Macro (Alpha and I64 Only)
The following describes the invocation format of the INITIALIZATION_ROUTINE macro. An equivalent macro, $INITIALIZATION_ROUTINE is provided for BLISS programmers. For C programmers, INIT_RTN_SETUP.H in SYS$LIB_C.TLB is available.
INITIALIZATION_ROUTINE
INITIALIZATION_ROUTINE — Declares a routine to be an initialization routine.
Format
INITIALIZATION_ROUTINE name [,system_rtn=0] [,unload=0] [,priority=0]
Parameters
name
Name of the initialization routine.
[system_rtn=0]
Indicates whether the initialization routine is external to the module invoking the macro. The default value of 0, indicating that the initialization routine is part of the current module, is the only option supported.
[unload=0]
Indicates whether the
name
argument specifies an
unload routine. The default value of 0, indicating
that the argument specifies an initialization
routine, is the only option supported.
[priority=0]
Indicates the PSECT in which the entry for
this initialization routine should be placed.
Routines that specify the
priority
argument as 0 are
placed in the first PSECT
(EXEC$INIT_000); those
that specify a value of 1 are placed in the second
(EXEC$INIT_001). The
routines in the first PSECT are called before
those in the second.
Description
The INITIALIZATION_ROUTINE macro declares a routine to be an initialization routine.
4.7.2.2. Linking an Executive Image (Alpha or I64 Only)
Note
Use of the linker to create executive images (specifically the use of the /ATTRIBUTES switch on the COLLECT= option in SYS$LIBRARY:VMS_EXECLET_LINK.OPT) is not documented elsewhere and is not supported by VSI OpenVMS.
! Replace 'execlet' with your image name $ LINK /NATIVE_ONLY/BPAGES=14 - /REPLACE/SECTION/NOTRACEBACK- /SHARE=execlet- /MAP=execlet /FULL /CROSS - /SYMBOL=execlet - SYS$LIBRARY:VMS_EXECLET_LNK /OPTION, - SYS$INPUT/OPTION ! SYMBOL_TABLE=GLOBALS ! Creates .STB for System Dump Analyzer CLUSTER=execlet,,,- ! SYS$LIBRARY:STARLET/INCLUDE:(SYS$DOINIT), - ! Insert executive object code here sys$disk:[]execlet.obj ! end of executive object code here SYS$LOADABLE_IMAGES:SYS$BASE_IMAGE.EXE/SHAREABLE/SELECTIVE
The CLUSTER= option creates the named cluster execlet, specifying the order in which the linker processes the listed modules. | |
The object module SYS$DOINIT (in STARLET.OLB) is explicitly linked into an executive image. This module declares the initialization routine table and provides routines to drive the actual initialization of an executive image. |
4.7.2.3. Loading an Executive Image (Alpha or I64 Only)
Calling LDR$LOAD_IMAGE to load the executive image at run time. This method lets you pass the address of a buffer to the image's initialization routine by which the caller and the initialization routine can exchange data. Section 4.7.2.4, “LDR$LOAD_IMAGE (Alpha or I64 Only)” describes LDR$LOAD_IMAGE. Note that you must link the code that calls LDR$LOAD_IMAGE against the system base image, using the /SYSEXE qualifier to the LINK command.
Using the SYSMAN SYS_LOADABLE ADD command and updating the OpenVMS system images file (SYS$LOADABLE_IMAGES:VMS$SYSTEM_IMAGES.DATA). This method causes the executive image to be loaded and initialized during the phases of system initialization.(See VMS for Alpha Platforms Internals and Data Structures for information about how an executive image's initialization routine is invoked during system initialization).
Copy the executive image to SYS$LOADABLE_IMAGES.
- Add an entry for the executive image in the data file SYS$UPDATE:VMS$SYSTEM_IMAGES.IDX, as follows:
SYSMAN SYS_LOADABLE ADD _LOCAL_ executive-image - /LOAD_STEP = SYSINIT - /SEVERITY = WARNING - /MESSAGE = "failure to load executive-image"
Invoke the SYS$UPDATE:VMS$SYSTEM_IMAGES.COM command procedure to generate a new system image data file (file name SYS$LOADABLE_IMAGES:VMS$SYSTEM_IMAGES.DATA). During the bootstrap, the system uses this data file to load the appropriate images.
Reboot the system. This causes the new executive image to be loaded into the system.
4.7.2.4. LDR$LOAD_IMAGE (Alpha or I64 Only)
The following is a description of the callable interface to LDR$LOAD_IMAGE.
LDR$LOAD_IMAGE
LDR$LOAD_IMAGE — Loads an OpenVMS executive image into the system.
Module
SYSLDR_DYN
Format
LDR$LOAD_IMAGE filename ,flags ,ref_handle ,user_buf
Arguments
filename
OpenVMS usage | character string |
type | character string |
access | read only |
mechanism | by descriptor |
flags
OpenVMS usage | flags |
type | longword (unsigned) |
access | read only |
mechanism | value |
Bit Field |
Description |
---|---|
LDR$V_PAG |
When set, indicates that the image should be loaded with its pageable sections resident. The flag is generally based on the value of the bit 0 in the S0_PAGING system parameter. This flag is ignored on I64, as all executive image sections are loaded resident (nonpaged). |
LDR$V_UNL |
When set, indicates that the image may be removed from memory. |
LDR$V_OVR |
When set, indicates that the image's read-only sections should not be overwritten during bugcheck processing. This flag is not used on OpenVMS Alpha or I64 systems. |
LDR$V_USER_BUF |
When set, indicates that the caller has passed the address of a buffer that should be passed to the initialization routine. |
LDR$V_NO_SLICE |
When set, indicates that the image's sections should not be loaded into a granularity hint region. This flag is ignored on I64, as all executive image sections may be loaded into a granularity hint region. |
ref_handle
OpenVMS usage | address |
type | longword (signed) |
access | write only |
mechanism | by reference |
+00 |
Address of loaded image or zero if image was loaded sliced. |
+04 |
Address of loaded image data block (LDRIMG). See the $LDRIMGDEF macro definition in SYS$LIBRARY:LIB.MLB and VMS for Alpha Platforms Internals and Data Structures for a description of the LDRIMG structure. |
+08 |
Loaded image sequence number. |
user_buf
OpenVMS usage | address |
type | longword (signed) |
access | read only |
mechanism | by reference |
Context
LDR$LOAD_IMAGE must be called in executive mode.
Returns
OpenVMS usage | cond_value |
type | longword (unsigned) |
access | write only |
mechanism | by value |
Return Values
SS$_ACCVIO | Unable to read the character string descriptor containing the file name of the executive image to be loaded or to write the reference handle. |
LOADER$_BAD_GSD | An executive image was loaded containing a global symbol that is not vectored through either the SYS$BASE_IMAGE or the SYS$PUBLIC_VECTORS image. |
SS$_BADIMGHDR | Image header is larger than two blocks or was built with a version of the linker that is incompatible with LDR$LOAD_IMAGE. |
LOADER$_BADIMGOFF | During a sliced image load request, a relocation or fixup operation was attempted on an image offset that has no resultant address within the image. |
LOADER$_DZRO_ISD | A load request was made for an executive image that illegally contains demand zero sections. |
SS$_INSFARG | Fewer than three arguments were passed to LDR$LOAD_IMAGE, or, with LDR$V_USER_BUF set in the flags longword, fewer than four arguments. |
SS$_INSFMEM | Insufficient nonpaged pool for the LDRIMG structure or insufficient physical memory to load nonpageable portion of an executive image (that is, an image loaded as nonsliced). |
SS$_INSFSPTS | Insufficient system page table entries (SPTEs) to describe the address space required for the executive image to be loaded as nonsliced. |
LOADER$_MULTIPLE_ |
A load request was made for an image that
was not linked correctly because it contains more
than one each of the following types of sections:
|
LOADER$_NO_PAGED_ | SYSBOOT failed to load the executive image because it contains either paged code or paged data sections. |
SS$_NOPRIV | LDR$LOAD_IMAGE was called from user or supervisor mode. |
LOADER$_NO_SUCH_ | A load request was made for an executive image that was linked against a shareable image that is not loaded. The only legal shareable images for executive images are SYS$BASE_IMAGE and SYS$PUBLIC_VECTORS. |
SS$_NORMAL | Normal, successful completion. |
LOADER$_PAGED_ | An executive image has more global symbols in the fixup data than can fit in the loader's internal tables. |
LOADER$_PSB_FIXUPS | A load request was made for an executive image that contains LPPSB fixup because it was linked /NONATIVE_ONLY. Executive images must be linked /NATIVE_ONLY. |
LOADER$_SPF_TOBIG | The loader's internal tables cannot accommodate all of the executive image fixups that must be postponed to later in the bootstrap operation. |
SS$_SYSVERDIF | Image was linked with versions of executive categories incompatible with those of the running system. |
LOADER$_VEC_TOBIG | An attempt to load an executive image failed because the image's symbol vector updates for SYS$BASE_IMAGE and SYS$PUBLC_VECTORS exceed the size of the loader's internal tables. |
Other | Any RMS error status returned from $OPEN failures. Any I/O error status returned from $QIO failures. |
Description
LDR$LOAD_IMAGE loads an executive image into system space and calls its initialization routine. Optionally, LDR$LOAD_IMAGE returns information about the loaded image to its caller.
Address of loaded image data block (LDRIMG)
The flags longword
The longword address of a user buffer passed to the executive image's initialization routine (if LDR$V_USER_BUF is set in the flags longword)
4.7.2.5. LDR$UNLOAD_IMAGE (Alpha or I64 Only)
The following is a description of the callable interface to LDR$UNLOAD_IMAGE.
LDR$UNLOAD_IMAGE
LDR$UNLOAD_IMAGE — Unloads a removable executive image. This routine is called to unload an execlet. All resources are returned.
Module
SYSLDR_DYN
Format
LDR$UNLOAD_IMAGE filename ,ref_handle
Arguments
filename
OpenVMS usage | character string |
type | character string |
access | read only |
mechanism | by descriptor |
ref_handle
OpenVMS usage | address |
type | longword (signed) |
access | read only |
mechanism | by reference |
Context
LDR$UNLOAD_IMAGE must be called in kernel mode.
Returns
OpenVMS usage | cond_value |
type | longword (unsigned) |
access | write only |
mechanism | by value |
Return Values
SS$_INSFARG | LDR$UNLOAD_IMAGE was not called with two parameters. |
SS$_BADPARAMS | Reference handle data inconsistent with LDRIMG block that matches the name in the first argument. |
LOADER$_ | A call was made to the LDR$UNLOAD_IMAGE routine to unload a removable executive image that already has an outstanding unload request against it. |
SS$_NOPRIV | LDR$UNLOAD_IMAGE was not called in kernel mode. |
SS$_NORMAL | Executive image was successfully removed from the system. |
LOADER$_NOT_UNL | A call was made to LDR$UNLOAD_IMAGE to unload an executive image that is not loaded or that was not loaded with the LDR$V_UNL flag bit set. |
LOADER$_UNL_PEN | A call was made to LDR$UNLOAD_IMAGE to unload an executive image that is in use. The image is marked to be unloaded later. |
Description
LDR$UNLOAD_IMAGE removes an executive image from system space and returns all memory resources allocated when the image was loaded. Images can only be removed if they were originally loaded with the bit LDR$V_UNL set in the input flags to LDR$LOAD_IMAGE.
4.8. Synchronizing Programs by Specifying a Time for Program Execution
Executing a program at a specific time
Executing a program at timed intervals
4.8.1. Obtaining the System Time
The process control procedures that allow you to synchronize timed program execution require you to supply a system time value.
You can use either system services or RTL routines for obtaining and reading time. They are summarized in Table 4.10, “Time Manipulation System Services and Routines”. With these routines, you can determine the system time, convert it to an external time, and pass a time back to the system. The system services use the operating system's default date format. With the RTL routines, you can use the default format or specify your own date format. However, if you are just using the time and date for program synchronization, using the operating system's default format is probably sufficient.
When using the RTL routines to change date/time formats, initialization routines are required. Refer to the VSI OpenVMS RTL Library (LIB$) Manual for more information.
Routine |
Description |
---|---|
SYS$GETTIM |
Obtains the current date and time in 64-bit binary format |
SYS$NUMTIM |
Converts system date and time to numeric integer values |
SYS$ASCTIM |
Converts an absolute or delta time from 64-bit system time format to an ASCII string |
SYS$ASCUTC |
Converts an absolute time from 128-bit Coordinated Universal Time (UTC) format to an ASCII string |
LIB$SYS_ASCTIM |
Converts binary time to an ASCII string |
SYS$BINTIM |
Converts a date and time from ASCII to system format |
SYS$BINUTC |
Converts an ASCII string to an absolute time value in the 128-bit UTC format |
SYS$FAO |
Converts a binary value into an ASCII character string in decimal, hexadecimal, or octal notation and returns the character string in an output string |
SYS$GETUTC |
Returns the current time in 128-bit UTC format |
SYS$NUMUTC |
Converts an absolute 128-bit binary time into its numeric components. The numeric components are returned in local time |
SYS$TIMCON |
Converts 128-bit UTC to 64-bit system format or 64-bit system format to 128-bit UTC based on the value of the convert flag |
LIB$ADD_TIMES |
Adds two quadword times |
LIB$CONVERT_DATE_STRING |
Converts an input date/time string to an operating system internal time |
LIB$CVT_FROM_INTERNAL_TIME |
Converts internal time to external time |
LIB$CVTF_FROM_INTERNAL_ |
Converts internal time to external time (F-floating value) |
LIB$CVT_TO_INTERNAL_TIME |
Converts external time to internal time |
LIB$CVTF_TO_INTERNAL_TIME |
Converts external time to internal time (F-floating value) |
LIB$CVT_VECTIM |
Converts 7-word vector to internal time |
LIB$DAY |
Obtains offset to current day from base time, in number of days |
LIB$DATE_TIME |
Obtains the date and time in user-specified format |
LIB$FORMAT_DATE_TIME |
Formats a date and/or time for output |
LIB$FREE_DATE_TIME_CONTEXT |
Frees date/time context |
LIB$GET_DATE_FORMAT |
Returns the user's specified date/time input format |
LIB$GET_MAXIMUM_DATE_ |
Returns the maximum possible length of an output date/time string |
LIB$GET_USERS_LANGUAGE |
Returns the user's selected language |
LIB$INIT_DATE_TIME_CONTEXT |
Initializes the date/time context with a user-specified format |
LIB$SUB_TIMES |
Subtracts two quadword times |
4.8.1.1. Executing a Program at a Specified Time
To execute a program at a specified time, use LIB$SPAWN to create a process that executes a command procedure containing two commands—the DCL command WAIT and the command that invokes the desired program. Because you do not want the parent process to remain in hibernation until the process executes, execute the process concurrently.
You can also use the SYS$CREPRC system service to execute a program at a specified time. However, because a process created by SYS$CREPRC hibernates rather than terminates after executing the desired program, VSI recommends you use the LIB$SPAWN routine unless you need a detached process.
4.8.1.2. Executing a Program at Timed Intervals
To execute a program at timed intervals, you can use either LIB$SPAWN or SYS$CREPRC.
Using LIB$SPAWN
Using LIB$SPAWN, you can create a subprocess that executes a command procedure containing three commands: the DCL command WAIT, the command that invokes the desired program, and a GOTO command that directs control back to the WAIT command. Because you do not want the parent process to remain in hibernation until the subprocess executes, execute the subprocess concurrently. See Section 4.8.1.1, “Executing a Program at a Specified Time” for an example of LIB$SPAWN.
Using SYS$CREPRC
Create and hibernate a process – Use SYS$CREPRC to create a process that executes the desired program. Set the PRC$V_HIBER bit of the
stsflg
argument of the SYS$CREPRC system service to indicate that the created process should hibernate before executing the program.Schedule a wakeup call for the created subprocess – Use the SYS$SCHDWK system service to specify the time at which the system should wake up the subprocess, and a time interval at which the system should repeat the wakeup call.
4.8.2. Placing Entries in the System Timer Queue
When you use the system timer queue, you use the timer expiration to signal when a routine is to be executed. It allows the caller to request a timer that will activate sometime in the future. The timer is requested for the calling kernel thread. When the timer activates, the event is reported to that thread. It does not affect any other thread in the process.
For the actual signal, you can use an event flag or AST. With this method, you do not need a separate process to control program execution. However, you do use up your process's quotas for ASTs and timer queue requests.
SYS$SETIMR ([efn] ,daytim ,[astadr] ,[reqidt] ,[flags])
Specifying the Starting Time
Specify the absolute or delta time at which you want the program to
begin execution using the daytim
argument.
Use the SYS$BINTIM system service to
convert an ASCII time to the binary system format required for this
argument.
Signaling Timer Expiration
Once the system has reached this time, the timer expires. To signal
timer expiration, set an event flag in the
efn
argument or specify an AST
routine to be executed in the astadr
argument. Refer to Section 6.8, “Using Event Flags” and Chapter 8, Using Asynchronous System Traps for more information about using event
flags and ASTs.
How Timer Requests Are Identified
The reqidt
argument identifies each system time
request uniquely. Then, if you need to cancel a request, you can
refer to each request separately.
To cancel a timer request, use the SYS$CANTIM system service.
4.9. Controlling Kernel Threads and Process Execution
Suspending a process – All kernel threads associated with the specified process are suspended.
Hibernating a process – Only the calling kernel thread is hibernated.
Stopping a process – All kernel threads associated with the specified process are stopped.
Resuming a process – All kernel threads associated with the specified process are resumed.
Exiting an image – All kernel threads associated with the specified process are exited.
Deleting a process – All kernel threads associated with the specified process are deleted, and then the process is deleted.
4.9.1. Process Hibernation and Suspension
Hibernation – Performed by the Hibernate (SYS$HIBER) system service, which affects the calling kernel thread.
Suspension – Performed by the Suspend Process (SYS$SUSPND) system service, which affects all of the kernel threads associated with the specified process.
The kernel thread can continue execution normally only after a corresponding Wake from Hibernation (SYS$WAKE) system service (if it is hibernating), or after a Resume Process (SYS$RESUME) system service, if it is suspended.
Suspending or hibernating a kernel thread puts it into a dormant state; the thread is not deleted.
Hibernation | Suspension |
---|---|
Can cause only self to hibernate. |
Can suspend self or another process, depending on privilege; suspends all threads associated with the specified process. |
Reversed by SYS$WAKE/SYS$SCHDWK system service. |
Reversed by SYS$RESUME system service. |
Interruptible; can receive ASTs. |
Noninterruptible; cannot receive ASTs?. |
Can wake self. |
Cannot cause self to resume. |
Can schedule wake up at an absolute time or at a fixed time interval. |
Cannot schedule resumption. |
Routine |
Function |
---|---|
Hibernating Processes | |
SYS$HIBER |
Places the requesting kernel thread in the hibernation state. An AST can be delivered to the thread while it is hibernating. The service puts only the calling thread into HIB; no other thread is affected. |
SYS$WAKE |
Resumes execution of a kernel thread in hibernation. This service wakes all hibernating kernel threads in a process regardless of the caller. Any thread that is not hibernating when the service is called is marked wake pending. Because of the wake pending, the next call to SYS$HIBER completes immediately and the thread does not hibernate. Premature wakeups must be handled in the code. |
SYS$SCHDWK |
Resumes execution of a kernel thread in hibernation at a specified time. This service schedules a wakeup request for a thread that is about to call SYS$HIBER. The wakeup affects only the requesting thread; any other hibernating kernel threads are not affected. |
LIB$WAIT |
Uses the services SYS$SCHDWK and SYS$HIBER. |
SYS$CANWAK |
Cancels a scheduled wakeup issued by SYS$SCHDWK. Unless called with a specific timer request ID, this service cancels all timers for all threads in the process regardless of the calling thread. |
Suspended Kernel Threads and Processes | |
SYS$SUSPEND |
Puts in a suspended state all threads associated with the specified process. |
SYS$RESUME |
Puts in an execution state all threads of the specified process. |
4.9.1.1. Using Process Hibernation
The hibernate/wake mechanism provides an efficient way to prepare an image for execution and then to place it in a wait state until it is needed.
/* Process TAURUS */ #include <stdio.h> #include <descrip.h> main() { unsigned int status; $DESCRIPTOR(prcnam,"ORION"); $DESCRIPTOR(image,"COMPUTE.EXE"); /* Create ORION */ status = SYS$CREPRC(0, /* Process id */ &image, /* Image */ 0, 0, 0, 0, 0, &prcnam, /* Process name */ 0, 0, 0, 0); if ((status & 1) != 1) LIB$SIGNAL(status); . . . /* Wake ORION */ status = SYS$WAKE(0, &prcnam); if ((status & 1) != 1) LIB$SIGNAL(status); . . . /* Wake ORION again */ status = SYS$WAKE(0, &prcnam); if ((status & 1) != 1) LIB$SIGNAL(status); . . . } /* Process ORION and image COMPUTE */ #include <stdio.h> #include <ssdef.h> . . . sleep: status = SYS$HIBER(); if ((status & 1) != 1) LIB$SIGNAL(status); . . . goto sleep; }
Process TAURUS creates the process ORION, specifying the descriptor for the image named COMPUTE. | |
At an appropriate time, TAURUS issues a SYS$WAKE request for ORION.ORION continues execution following the SYS$HIBER service call. When it finishes its job, ORION loops back to repeat the SYS$HIBER call and to wait for another wakeup. | |
The image COMPUTE is initialized, and ORION issues the SYS$HIBER system service. |
The Schedule Wakeup (SYS$SCHDWK) system service, a variation of the SYS$WAKE system service, schedules a wakeup for a hibernating process at a fixed time or at an elapsed (delta) time interval. Using the SYS$SCHDWK service, a process can schedule a wakeup for itself before issuing a SYS$HIBER call. For an example of how to use the SYS$SCHDWK system service, see VSI OpenVMS Programming Concepts Manual, Volume II.
Hibernating processes can be interrupted by asynchronous system traps (ASTs), as long as AST delivery is enabled. The process can call SYS$WAKE on its own behalf in the AST service routine, and continue execution following the execution of the AST service routine. For a description of ASTs and how to use them, see Chapter 8, Using Asynchronous System Traps.
4.9.1.2. Using Alternative Methods of Hibernation
Specify the
stsflg
argument for the SYS$CREPRC system service, setting the bit that requests SYS$CREPRC to place the created process in a state of hibernation as soon as it is initialized.Specify the /DELAY, /SCHEDULE, or /INTERVAL qualifier to the RUN command when you execute the image from the command stream.
When you use the SYS$CREPRC system service, the creating process can control when to wake the created process. When you use the RUN command, its qualifiers control when to wake the process.
If you use the /INTERVAL qualifier and the image to be executed does not call the SYS$HIBER system service, the image is placed in a state of hibernation whenever it issues a return instruction (RET). Each time the image is awakened, it begins executing at its entry point. If the image does call SYS$HIBER, each time it is awakened it begins executing at either the point following the call to SYS$HIBER or at its entry point (if it last issued a RET instruction).
If wakeup requests are scheduled at time intervals, the image can be terminated with the Delete Process (SYS$DELPRC) or Force Exit (SYS$FORCEX) system service, or from the command level with the STOP command. The SYS$DELPRC and SYS$FORCEX system services are described in Section 4.9.3.4, “Initiating Image Rundown for Another Process” and in Section 4.9.4, “Deleting a Process”. The RUN and STOP commands are described in the VSI OpenVMS DCL Dictionary.
These methods allow you to write programs that can be executed once, on request, or cyclically. If an image is executed more than once in this manner, normal image activation and termination services are not performed on the second and subsequent calls to the image. Note that the program must ensure both the integrity of data areas that are modified during its execution and the status of opened files.
4.9.1.3. Using SYS$SUSPND
Using the Suspend Process (SYS$SUSPND) system service, a process can place itself or another process into a wait state similar to hibernation. Suspension, however, is a more pronounced state of hibernation. The operating system provides no system service to force a process to be swapped out, but the SYS$SUSPND system service can accomplish the task in the following way. Suspended processes are the first processes to be selected for swapping. A suspended process cannot be interrupted by ASTs, and it can resume execution only after another process calls a Resume Process (SYS$RESUME) system service on its behalf. If ASTs are queued for the process while it is suspended, they are delivered when the process resumes execution. This is an effective tool for blocking delivery of all ASTs.
At the DCL level, you can suspend a process by issuing the SET PROCESS command with the /SUSPEND qualifier. This command temporarily stops the process's activities. The process remains suspended until another process resumes or deletes it. To allow a suspended process to resume operation, use either the /NOSUSPEND or /RESUME qualifier.
4.9.2. Passing Control to Another Image
The RTL routines LIB$DO_COMMAND and LIB$RUN_PROGRAM allow you to invoke the next image from the current image. That is, they allow you to perform image rundown for the current image and pass control to the next image without returning to DCL command level. The routine you use depends on whether the next image is a command image or a noncommand image.
4.9.2.1. Invoking a Command Image
$ COPY DATA.TMP APRIL.DAT
. . . STATUS = LIB$DO_COMMAND ('COPY DATA.TMP APRIL.DAT') IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS)) END
. . . STATUS = LIB$DO_COMMAND ('@[STATS.TEMP]CLEANUP') IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS))END
4.9.2.2. Invoking a Noncommand Image
$ RUN [STATISTICS.TEMP]TEST
. . . STATUS = LIB$RUN_PROGRAM ('[STATISTICS.TEMP]TEST.EXE') IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS)) END
4.9.3. Performing Image Exit
When image execution completes normally, the operating system performs a variety of image rundown functions. If the image is executed by the command interpreter, image rundown prepares the process for the execution of another image. If the image is not executed by the command interpreter—for example, if it is executed by a subprocess—the process is deleted.
Main programs and main routines terminate by executing a return instruction (RET). This instruction returns control to the caller, which could have been LIB$INITIALIZE, the debugger, or the command interpreter. The completion code, SS$_NORMAL, which has the value 1, should be used to indicate normal successful completion.
Any other condition value can be used to indicate success or failure. The command language interpreter uses the condition value as the parameter to the Exit (SYS$EXIT) system service. If the severity field (STS$V_SEVERITY) is SEVERE or ERROR, the continuation of a batch job or command procedure is affected.
Specific error conditions caused by improper specifications when a process is created. For example, if an invalid device name is specified for the SYS$INPUT, SYS$OUTPUT, or SYS$ERROR logical name, or if an invalid or nonexistent image name is specified, the error condition is signaled in the created process.
An exception occurring during execution of the image. When an exception occurs, any user-specified condition handlers receive control to handle the exception. If there are no user-specified condition handlers, a system-declared condition handler receives control, and it initiates exit activities for the image. Condition handling is described in Chapter 9, Condition-Handling Routines and Services.
A Force Exit (SYS$FORCEX) system service issued on behalf of the process by another process.
4.9.3.1. Performing Image Rundown
Any outstanding I/O requests on the I/O channels are canceled, and I/O channels are deassigned.
Memory pages occupied or allocated by the image are deleted, and the working set size limit of the process is readjusted to its default value.
All devices allocated to the process at user mode are deallocated (devices allocated from the command stream in supervisor mode are not deallocated).
Timer-scheduled requests, including wakeup requests, are canceled.
Common event flag clusters are disassociated.
Locks are dequeued as a part of rundown.
User mode ASTs that are queued but have not been delivered are deleted, and ASTs are enabled for user mode.
Exception vectors declared in user mode, compatibility mode handlers, and change mode to user handlers are reset.
System service failure exception mode is disabled.
All process private logical names and logical name tables created for user mode are deleted. Deletion of a logical name table causes all names in that table to be deleted. Note that names entered in shareable logical name tables, such as the job or group table, are not deleted at image rundown, regardless of the access mode for which they were created.
4.9.3.2. Initiating Rundown
To initiate the rundown activities described in Section 4.9.3.1, “Performing Image Rundown”, the system calls the Exit (SYS$EXIT) system service on behalf of the process. In some cases, a process can call SYS$EXIT to terminate the image itself (for example, if an unrecoverable error occurs).
You should not call the SYS$EXIT system service directly from a main program. By not calling SYS$EXIT directly from a main program, you allow the main program to be more like ordinary modular routines and therefore usable by other programmers as callable routines.
The SYS$EXIT system service accepts a status code as an argument. If you use SYS$EXIT to terminate image execution, you can use this status code argument to pass information about the completion of the image. If an image returns without calling SYS$EXIT, the current value in R0 is passed as the status code when the system calls SYS$EXIT.
The command interpreter uses the status code to display optionally an error message when it receives control following image rundown.
If the image has declared an exit handler, the status code is written in the address specified in the exit control block.
If the process was created by another process, and the creator has specified a mailbox to receive a termination message, the status code is written into the termination mailbox when the process is deleted.
4.9.3.3. Performing Cleanup and Rundown Operations
Use exit handlers to perform image-specific cleanup or rundown operations. For example, if an image uses memory to buffer data, an exit handler can ensure that the data is not lost when the image exits as the result of an error condition.
To establish an exit-handling routine, you must set up an exit control block and specify the address of the control block in the call to the Declare Exit Handler (SYS$DCLEXH) system service. You can call an exit handler by using standard calling conventions; you can provide arguments to the exit handler in the exit control block. The first argument in the control block argument list must specify the address of a longword for the system to write the status code from SYS$EXIT.
If an image declares more than one exit handler, the control blocks are linked together on a last-in, first-out (LIFO) basis. After an exit handler is called and returns control, the control block is removed from the list. You can remove exit control blocks prior to image exit by using the Cancel Exit Handler (SYS$CANEXH) system service.
Exit handlers can be declared from system routines executing in supervisor or executive mode. These exit handlers are also linked together in other lists, and they receive control after exit handlers that are declared from user mode are executed.
Exit handlers are called as a part of the SYS$EXIT system service. While a call to the SYS$EXIT system service often precedes image rundown activities, the call is not a part of image rundown. There is no way to ensure that exit handlers will be called if an image terminates in a nonstandard way.
To see examples of exit handler programs, refer to Section 9.15.4, “Example of Exit Handler”.
4.9.3.4. Initiating Image Rundown for Another Process
$DESCRIPTOR(prcnam,"CYGNUS"); . . . status = SYS$FORCEX(0, /* pidadr - Process id */ &prcnam, /* prcnam - Process name */ 0); /* code - Completion code */
Because the SYS$FORCEX system service calls the SYS$EXIT system service, any exit handlers declared for the image are executed before image rundown. Thus, if the process is using the command interpreter, the process is not deleted and can run another image. Because the SYS$FORCEX system service uses the AST mechanism, an exit cannot be performed if the process being forced to exit has disabled the delivery of ASTs. AST delivery and how it is disabled and reenabled is described in Chapter 8, Using Asynchronous System Traps.
The SYS$DCHEXH system service causes the target process to execute the exit handler. For additional information about exit handlers and examples, see Chapter 9, Condition-Handling Routines and Services and Section 9.15.4, “Example of Exit Handler”.
4.9.4. Deleting a Process
The Delete Process (SYS$DELPRC) system service is called.
A process that created a subprocess is deleted.
An interactive process uses the DCL command LOGOUT.
A batch job reaches the end of its command file.
An interactive process uses the DCL command STOP/ID= pid or STOP username.
A process that contains a single image calls the Exit (SYS$EXIT) system service.
The Force Exit (SYS$FORCEX) system service forces image exit on a process that contains a single image.
When the system is called to delete a process as a result of any of these conditions, it first locates all subprocesses, and searches hierarchically. No process can be deleted until all the subprocesses it has created have been deleted.
The lowest subprocess in the hierarchy is a subprocess that has no descendant subprocesses of its own. When that subprocess is deleted, its parent subprocess becomes a subprocess that has no descendant subprocesses and it can be deleted as well. The topmost process in the hierarchy becomes the parent process of all the other subprocesses.
The image executing in the process is run down. The image rundown that occurs during process deletion is the same as that described in Section 4.9.3.1, “Performing Image Rundown”. When a process is deleted, however, the rundown releases all system resources, including those acquired from access modes other than user mode.
Resource quotas are released to the creating process, if the process being deleted is a subprocess.
If the creating process specifies a termination mailbox, a message indicating that the process is being deleted is sent to the mailbox. For detached processes created by the system, the termination message is sent to the system job controller.
The control region of the process's virtual address space is deleted. (The control region consists of memory allocated and used by the system on behalf of the process).
All system-maintained information about the process is deleted.
Figure 4.1, “Image Exit and Process Deletion” illustrates the flow of events from image exit through process deletion.
4.9.4.1. Deleting a Process By Using System Services
SYS$EXIT—Initiates normal exit in the current image. Control returns to the command language interpreter. If there is no command language interpreter, the process is terminated. This routine cannot be used to terminate an image in a detached process.
SYS$FORCEX—Initiates a normal exit on the image in the specified process. GROUP or WORLD privilege may be required, depending on the process specified. An AST is sent to the specified process. The AST calls on the SYS$EXIT routine to complete the image exit. Because an AST is used, you cannot use this routine on a suspended process. You can use this routine on a subprocess or detached process. See Section 4.9.3.4, “Initiating Image Rundown for Another Process” for an example.
- SYS$DELPRC—Deletes the specified process. GROUP or WORLD privilege may be required, depending on the process specified. A termination message is sent to the calling process's mailbox. You can use this routine on a subprocess, a detached process, or the current process. For example, if a process has created a subprocess named CYGNUS, it can delete CYGNUS, as follows:
$DESCRIPTOR(prcnam,"CYGNUS"); . . . status = SYS$DELPRC(0, /* Process id */ &prcnam); /* Process name */
Because a subprocess is automatically deleted when the image it is executing terminates (or when the command stream for the command interpreter reaches end of file), you normally do not need to call the SYS$DELPRC system service explicitly.
4.9.4.2. $DELPRC System Service Can Invoke Exit Handlers (Alpha and I64 only)
As of OpenVMS Version 7.3-1, the system parameter DELPRC_EXIT provides the default system setting for whether an exit handler is called and at what access mode.
0= Do not enable the EXIT functionality with $DELPRC
4= Execute kernel mode exit handlers
5= Execute exec and more privileged mode exit handlers
6= Execute supervisor and more privileged mode exit handlers
7= Execute user and more privileged mode exit handlers
The system default is 5, which allows components with exec mode exit handlers to execute normal rundown activity, but prevents continued execution of user mode application code or command procedures. In particular, the RMS exec-mode exit handler completes file updates in progress. This prevents file inconsistencies or loss of some file updates made just prior to a process deletion.
As of OpenVMS Version 7.3-1, the $DELPRC system service can call exit handlers prior to final cleanup and deletion of a process. This allows you to override the system default setting determined by the system parameter DELPRC_EXIT.
The $DELPRC flags argument controls whether exit handlers are called by $DELPRC. You can use the flags argument to specify the least-privileged mode for which exit handling will be attempted, or to specify that no exit handling will be attempted.
Flag |
Description |
---|---|
DELPRC$M_EXIT |
When set, exit handlers as specified by DELPRC$M_MODE are called. This flag is ignored for a hard suspended process. |
DELPRC$M_MODE |
2 bit field: values psl$c_kernel, psl$c_exec, psl$c_super, psl$c_user (from the $PSLDEF macro). |
DELPRC$M_NOEXIT |
Set to disable any exit handler execution. |
$DELPRC_S PIDADR = pid,- FLAGS = #<DELPRC$M_EXIT!PSL$C_EXEC>
If the flags argument is not specified or is specified with a zero, the system parameter DELPRC_EXIT controls what exit handlers, if any, are called by $DELPRC.
As of OpenVMS Version 7.3-1 you can also use the DCL STOP command qualifier [NO]EXIT[=access-mode] to override the system default setting determined by the system parameter DELPRC_EXIT. If you specify an access mode of user_mode, supervisor_mode, executive_mode, or kernel_mode, the resulting $DELPRC flag argument is set accordingly.
If you use the DCL STOP command with the /EXIT qualifier but do not specify an access mode, executive_mode is used by default.
If you use the DCL STOP command without the /EXIT qualifier, the system parameter DELPRC_EXIT is used instead.
If you use the DCL STOP command without either the /IDENTIFICATION qualifier or the process-name parameter, then the currently executing image is terminated; the process is not deleted.
Version |
How Exit Handler Determined |
---|---|
OpenVMS Alpha version 7.3-1 and later (local) to OpenVMS Alpha Version 7.3-1 and later (remote) |
Either through exit default in the system parameter DELPRC_EXIT on the remote system, or by setting in the flags argument on the local system and passed to the remote system. |
OpenVMS Alpha version prior to 7.3-1 or OpenVMS VAX (local) to OpenVMS Alpha Version 7.3-1 or later (remote) |
Exit default in the system parameter DELPRC_EXIT on the remote system. |
Any mix of OpenVMS Alpha prior to Version 7.3-1 or any OpenVMS VAX version |
No support for exit functionality in system service $DELPRC. |
Note
$DELPRC called from user mode could call supervisor mode exit handlers.
$DELPRC called from exec mode could only execute kernel mode exit handlers.
$DELPRC called from kernel mode cannot call exit handlers.
4.9.4.3. Terminating Mailboxes
A termination mailbox provides a process with a way of determining when, and under what conditions, a process that it has created was deleted. The Create Process (SYS$CREPRC) system service accepts the unit number of a mailbox as an argument. When the process is deleted, the mailbox receives a termination message.
The first word of the termination message contains the symbolic constant, MSG$_DELPROC, which indicates that it is a termination message. The second longword of the termination message contains the final status value of the image. The remainder of the message contains system accounting information used by the job controller and is identical to the first part of the accounting record sent to the system accounting log file. The description of the SYS$CREPRC system service in the VSI OpenVMS System Services Reference Manual provides the complete format of the termination message.
If necessary, the creating process can determine the process identification of the process being deleted from the I/O status block (IOSB) posted when the message is received in the mailbox. The second longword of the IOSB contains the process identification of the process being deleted.
A termination mailbox cannot be located in memory shared by multiple processors.
#include <stdio.h> #include <descrip.h> #include <ssdef.h> #include <msgdef.h> #include <dvidef.h> #include <iodef.h> #include <accdef.h> unsigned short unitnum; unsigned int pidadr; /* Create a buffer to store termination info */ struct accdef exitmsg; /* Define and initialize the item list for $GETDVI */ static struct { unsigned short buflen,item_code; void *bufaddr; void *retlenaddr; unsigned int terminator; }mbxinfo = { 4, DVI$_UNIT, &unitnum, 0, 0}; /* I/O Status Block for QIO */ struct { unsigned short iostat, mblen; unsigned int mbpid; }mbxiosb; main() { void exitast(void); unsigned short exchan; unsigned int status,maxmsg=84,bufquo=240,promsk=0; unsigned int func=IO$_READVBLK; $DESCRIPTOR(image,"LYRA"); /* Create a mailbox */ status = SYS$CREMBX(0, /* prmflg (permanent or temporary) */ &exchan, /* channel */ maxmsg, /* maximum message size */ bufquo, /* no. of bytes used for buffer */ promsk, /* protection mask */ 0,0,0,0); if ((status & 1 ) != 1) LIB$SIGNAL( status ); /* Get the mailbox unit number */ status = SYS$GETDVI(0, /* efn - event flag */ exchan, /* chan - channel */ 0, /* devnam - device name */ &mbxinfo, /* item list */ 0,0,0,0); if ((status & 1 ) != 1) LIB$SIGNAL( status ); /* Create a subprocess */ status = SYS$CREPRC(&pidadr, /* process id */ &image, /* image to be run */ 0,0,0,0,0,0,0,0, unitnum, /* mailbox unit number */ 0); /* options flags */ if ((status & 1 ) != 1) LIB$SIGNAL( status ); /* Read from mailbox */ status = SYS$QIOW(0, /* efn - event flag */ exchan, /* chan - channel number */ func, /* function modifier */ &mbxiosb, /* iosb - I/O status block */ &exitast, /* astadr - astadr AST routine */ 0, /* astprm - astprm AST parameter */ &exitmsg, /* p1 - buffer to receive message*/ ACC$K_TERMLEN, /* p2 - length of buffer */ 0,0,0,0); /* p3, p4, p5, p6 */ if ((status & 1 ) != 1) LIB$SIGNAL( status ); } void exitast(void) { if(mbxiosb.iostat == SS$_NORMAL) { printf("\nMailbox successfully written..."); if (exitmsg.acc$w_msgtyp == MSG$_DELPROC) { printf("\nProcess deleted..."); if (pidadr == mbxiosb.mbpid) { printf("\nPIDs are equal..."); if (exitmsg.acc$l_finalsts == SS$_NORMAL) printf("\nNormal termination..."); else printf("\nAbnormal termination status: %d", exitmsg.acc$l_finalsts); } else printf("\nPIDs are not equal"); } else printf("\nTermination message not received... status: %d", exitmsg.acc$w_msgtyp); } else printf("\nMailbox I/O status block: %d",mbxiosb.iostat); return; }
The Create Mailbox and Assign Channel (SYS$CREMBX), Get Device/Volume Information (SYS$GETDVI), and Queue I/O Request (SYS$QIO) system services are described in greater detail in VSI OpenVMS Programming Concepts Manual, Volume II.
Chapter 5. Symmetric Multiprocessing (SMP) Systems
5.1. Introduction to Symmetric Multiprocessing
OpenVMS Alpha and OpenVMS I64 support tightly coupled symmetric multiprocessing (SMP). This chapter presents a brief overview of symmetric multiprocessing terms and characteristics. For more information about SMP concepts and hardware configurations, refer to VMS for Alpha Platforms Internals and Data Structures.
A multiprocessing system consists of two or more CPUs that address common memory and that can execute instructions simultaneously. If all CPUs in the system execute the same copy of the operating system, the multiprocessing system is said to be tightly coupled. If all CPUs have equal access to memory, interrupts, and I/O devices, the system is said to be symmetric.
Initiate an I/O request
Service exceptions
Service software interrupts
Service hardware interrupts, such as interprocessor and interval timer interrupts
Execute process context code in any access mode
5.2. CPU Characteristics of an SMP System
The members of an SMP system are characterized in several ways. One important characteristic is that of primary CPU. During system operation the primary CPU has several unique responsibilities for system timekeeping, writing messages to the console terminal, and accessing any other I/O devices that are not accessible to all members. Although the hardware and software permit device interrupts to be serviced by any processor, in practice all device interrupts are serviced on the primary CPU. An SMP configuration may include some devices that are not accessible from all SMP members. The console terminal, for example, is accessible only from the primary processor.
5.2.1. Booting an SMP System
Booting the system is initiated on a CPU with full access to the console subsystem and terminal, called the BOOT CPU. The BOOT CPU controls the bootstrap sequence and boots the other available CPUs. On OpenVMS Alpha and OpenVMS I64 systems, the BOOT CPU and the primary CPU are always the same; the others are called secondary processors.
The booted primary and all currently booted secondary processors are called members of the active set. These processors actively participate in system operations and respond to interprocessor interrupts, which coordinate systemwide events.
5.2.2. Interrupt Requests on SMP System
When a current Kernel thread is preempted by a higher priority computable resident thread, the IPL 3 rescheduling interrupt service routine, running on that processor, takes the current thread out of execution and switches to the higher priority Kernel thread.
When a device driver completes an I/O request, an IPL 4 I/O post-processing interrupt is requested: some completed requests are queued to a CPU-specific post-processing queue and are serviced on that CPU; others are queued to a systemwide queue and serviced on the primary CPU.
When the current Kernel thread has used its quantum of CPU time, the software timer interrupt service routine, running on that CPU, performs quantum-end processing.
Software interrupts at IPLs 6 and 8 through 11 are requested to execute fork processes. Each processor services its own set of fork queues. A fork process generally executes on the same CPU from which it was requested. However, since many fork processes are requested from device interrupt service routines, which currently execute only on the primary CPU, more fork processes execute on the primary than on other processors.
5.3. Symmetric Multiprocessing Goals
One version of the operating system. As part of the standard OpenVMS Alpha and OpenVMS I64 product, SMP support does not require its own version. The synchronization methodology and the interface to synchronization routines are the same on all systems. However, as described in VMS for Alpha Platforms Internals and Data Structures, there are different versions of the synchronization routines themselves in different versions of the OpenVMS Alpha executive image that implement synchronization. Partly for that reason, SMP support imposes relatively little additional overhead on a uniprocessor system.
Parallelism in kernel mode. SMP support might have been implemented such that any single processor, but not more than one at a time, could execute kernel mode code. However, more parallelism was required for a solution that would support configurations with more CPUs. The members of an SMP system can be executing different portions of the Executive concurrently.
The executive has been divided into different critical regions, each with its own lock, called a spinlock. A spinlock is one type of system synchronization element that guarantees atomic access to the functional divisions of the Executive using instructions specifically designed for multi-processor configurations. Section 6.6, “Synchronization Primitives” and Section 6.7, “Software-Level Synchronization” describe both the underlying architecture and software elements that provide this level of SMP synchronization.
The spinlock is the heart of the SMP model, allowing system concurrency at all levels of the operating system. All components that want to benefit from multiple-CPU configurations must incorporate these elements to guarantee consistency and correctness. Device drivers, in particular, use a variant of the static system spinlock (a devicelock) to ensure its own degree of synchronization and ownership within the system.
Symmetric scheduling mechanisms. The standard, default behavior of the operating system is to impose as little binding between system executable entities and specific CPUs in the active set as possible. That is, in general, each CPU is equally able to execute any Kernel thread. The multi-processor scheduling algorithm is an extension of the single-CPU behavior, providing consistent preemption and real-time behavior in all cases.
However, there are circumstances when an executable Kernel thread needs system resources and services possessed only by certain CPUs in the configuration. In those non-symmetric cases, OpenVMS provides a series of privileged, system-level CPU scheduling routines that supersedes the standard scheduling mechanisms and binds a Kernel thread to one or more specific CPUs. System components that are tied to the primary CPU, such as system timekeeping and console processing, use these mechanisms to guarantee that their functions are performed in the correct context. Also, because the Alpha hardware architecture shows significant performance benefits for Kernel threads run on CPUs where the hardware context has been preserved from earlier execution, the CPU scheduling mechanisms have been introduced as a series of system services and user commands. Through the use of explicit CPU affinity and user capabilities, an application can be placed throughout the active set to take advantage of the hardware context. Section 4.4, “Using Affinity and Capabilities in CPU Scheduling (Alpha and I64 Only)” describes these features in greater detail.
Chapter 6. Synchronizing Data Access and Program Operations
This chapter describes the operating system's synchronization features. It focuses on referencing memory and the techniques used to synchronize memory access. These techniques are the basis for mechanisms OpenVMS itself uses and for mechanisms OpenVMS provides for applications to use.
6.1. Overview of Synchronization
Software synchronization refers to the coordination of events in such a way that only one event happens at a time. This kind of synchronization is a serialization or sequencing of events. Serialized events are assigned an order and processed one at a time in that order. While a serialized event is being processed, no other event in the series is allowed to disrupt it.
By imposing order on events, synchronization allows reading and writing of several data items indivisibly, or atomically, in order to obtain a consistent set of data. For example, all of process A's writes to shared data must happen before or after process B's writes or reads, but not during process B's writes or reads. In this case, all of process A's writes must happen indivisibly for the operation to be correct. This includes process A's updates – reading of a data item, modifying it, and writing it back (read-modify-write sequence). Other synchronization techniques are used to ensure the completion of an asynchronous system service before the caller tries to use the results of the service.
6.1.1. Threads of Execution
Mainline code in an image being executed by a kernel thread, or multiple threads
User-mode application threads managed and scheduled through the POSIX threads library thread manager
Asynchronous system traps (ASTs) that interrupt a kernel thread
Condition handlers established by the process, which run after exceptions occur
Inner access-mode threads of execution that run as a result of system service, OpenVMS Record Management Services (RMS), and command language interpreter (CLI) callback requests
Process-based threads of execution can share any data in the per-process address space and must synchronize access to any data they share. A thread of execution can incur an exception, which results in passing of control to a condition handler. Alternatively, the thread can receive an AST, which results in passing of control to an AST procedure. Further, an AST procedure can incur an exception, and a condition handler's execution can be interrupted by an AST delivery. If a thread of execution requests a system service or RMS service, control passes to an inner access-mode thread of execution. Code that executes in the inner mode can also incur exceptions, receive ASTs, and request services.
Multiple processes, each with its own set of threads of execution, can execute concurrently. Although each process has private address space, processes can share data in a global section mapped into each process's address spaces. You need to synchronize access to global section data because a thread of execution accessing the data in one process can be rescheduled, allowing a thread of execution in another process to access the same data before the first process completes its work. Although processes access the same system address space, the protection on system space pages usually prevents outer mode access. However, process-based code threads running in inner access modes can access data concurrently in system space and must synchronize access to it.
Interrupt service routines access only system space. They must synchronize access to shared system space data among themselves and with process-based threads of execution.
A CPU-based thread of execution and an I/O processor must synchronize access to shared data structures, such as structures that contain descriptions of I/O operations to be performed.
Multiprocessor execution increases synchronization requirements when the threads that must synchronize can run concurrently on different processors. Because a process with only one kernel thread executes on only one processor at a time, synchronization of threads of execution within such a process is unaffected by whether the process runs on a uniprocessor or on an SMP system. However, a process with multiple kernel threads can be executing on multiple processors at the same time on an SMP system. The threads of such a process must synchronize their access to writable per-process address space.
Also, multiple processes execute simultaneously on different processors. Because of this, processes sharing data in a global section can require additional synchronization for SMP system execution. Further, process-based inner mode and interrupt-based threads can execute simultaneously on different processors and can require synchronization of access to system space beyond what is sufficient on a uniprocessor.
6.1.2. Atomicity
Atomicity is a type of serialization that refers to the indivisibility of a small number of actions, such as those occurring during the execution of a single instruction or a small number of instructions. With more than one action, no single action can occur by itself. If one action occurs, then all the actions occur. Atomicity must be qualified by the viewpoint from which the actions appear indivisible: an operation that is atomic for threads running on the same processor can appear as multiple actions to a thread of execution running on a different processor.
An atomic memory reference results in one indivisible read or write of a data item in memory. No other access to any part of that data can occur during the course of the atomic reference. Atomic memory references are important for synchronizing access to a data item that is shared by multiple writers or by one writer and multiple readers. References need not be atomic to a data item that is not shared or to one that is shared but is only read.
6.2. Memory Read and Memory Write Operations for VAX and Alpha
This section presents the important concepts of alignment and granularity and how they affect the access of shared data on VAX and Alpha systems. It also discusses the importance of the order of reads and writes completed on VAX and Alpha systems, and how VAX and Alpha systems perform memory reads and writes.
6.2.1. Accessing Memory
The term alignment refers to the placement of a data item in memory. For a data item to be naturally aligned, its lowest-addressed byte must reside at an address that is a multiple of the size of the data item in bytes. For example, a naturally aligned longword has an address that is a multiple of 4. The term naturally aligned is usually shortened to “aligned”.
On VAX systems, a thread on a VAX uniprocessor or multiprocessor can read and write aligned byte, word, and longword data atomically with respect to other threads of execution accessing the same data.
In contrast to the variety of memory accesses allowed on VAX systems, an Alpha processor may allow atomic access only to an aligned longword or an aligned quadword. Reading or writing an aligned longword or quadword of memory is atomic with respect to any other thread of execution on the same processor or on other processors. Newer Alpha processors with the byte-word extension also provide atomic access to bytes and aligned words.
VAX and Alpha systems differ in granularity of data access. The phrase granularity of data access refers to the size of neighboring units of memory that can be written independently and atomically by multiple processors. Regardless of the order in which the two units are written, the results must be identical.
VAX systems have byte granularity: individual adjacent or neighboring bytes within the same longword can be written by multiple threads of execution on one or more processors, as can aligned words and longwords.
VAX systems provide instructions that can manipulate byte-sized and aligned word-sized memory data in a single, noninterruptible operation. On VAX systems, a byte-sized or word-sized data item that is shared can be manipulated individually.
Alpha systems guarantee longword and quadword granularity. That is, adjacent aligned longwords or quadwords can be written independently. Because earlier Alpha systems support instructions that load or store only longword-sized and quadword-sized memory data, the manipulation of byte-sized and word-sized data on such Alpha systems may require that the entire longword or quadword containing the byte- or word-sized item be manipulated. Thus, simply because of its proximity to an explicitly shared data item, neighboring data might become shared unintentionally.
Fetch the longword or quadword that contains the byte or word
Mask the nontargeted bytes
Manipulate the target byte or word
Store the entire longword or quadword
On such Alpha systems, because this sequence is interruptible, operations on byte and word data are not atomic. Also, this change in the granularity of memory access can affect the determination of which data is actually shared when a byte or word is accessed.
On such Alpha systems, the absence of byte and word granularity has important implications for access to shared data. In effect, any memory write of a data item other than an aligned longword or quadword must be done as a multiple-instruction read-modify-write sequence. Also, because the amount of data read and written is an entire longword or quadword, programmers must ensure that all accesses to fields within the longword or quadword are synchronized with each other.
Alpha systems with the byte-word extension provide instructions that can read or write byte-size and aligned word-sized memory data in a single noninterruptible operation.
6.2.2. Ordering of Read and Write Operations
On VAX uniprocessor and multiprocessor systems, write operations and read operations appear to occur in the same order in which you specify them from the viewpoint of all types of external threads of execution. Alpha uniprocessor systems also guarantee that read and write operations appear ordered for multiple threads of execution running within a single process or within multiple processes running on a uniprocessor.
On Alpha multiprocessor systems, you must order reads and writes explicitly to ensure that they occur in a specific order from the viewpoint of threads of execution on other processors. To provide the necessary operating system primitives and compatibility with VAX systems, Alpha systems provide instructions that impose an order on read and write operations.
6.2.3. Memory Reads and Memory Writes
On VAX systems, most instructions that read or write memory are noninterruptible. A memory write done with a noninterruptible instruction is atomic from the viewpoint of other threads on the same CPU.
On VAX systems, on a uniprocessor system, reads and writes of bytes, words, longwords, and quadwords are atomic with respect to any thread on the processor. On a multiprocessor, not all of those accesses are atomic with respect to any thread on any processor; only reads and writes of bytes, aligned words, and aligned longwords are atomic. Accessing unaligned data can require multiple operations. As a result, even though an unaligned longword is written with a noninterruptible instruction, if it requires multiple memory accesses, a thread on another CPU might see memory in an intermediate state. VAX systems do not guarantee multiprocessor atomic access to quadwords.
On Alpha systems, there is no instruction that performs multiple memory accesses. Each load or store instruction performs a maximum of one load from or one store to memory. On an Alpha processor without the byte-word extension, a load can occur only from an aligned longword or quadword; a store can occur only to an aligned longword or quadword. On an Alpha processor with the byte-word extension, a load can also occur from a byte or an aligned word; a store can also occur to a byte or an aligned word.
On Alpha systems, although reads and writes from one thread appear to occur ordered from the viewpoint of other threads on the same processor, there is no implicit ordering of reads and writes as seen by threads on other processors.
6.3. Memory Read and Memory Write Operations for I64 Systems
OpenVMS I64 systems provide memory access only through register load and store instructions and special semaphore instructions. This section describes how alignment and granularity affect the access of shared data on I64 systems. It also discusses the importance of the order of reads and writes completed on I64 systems, and how I64 systems perform memory reads and writes.
6.3.1. Atomic Semaphore Instructions on I64
On I64 systems, the semaphore instructions have implicit ordering. If there is a write, it always follows the read. In addition, the read and write are performed atomically with no intervening accesses to the same memory region.
6.3.2. Accessing Memory on I64
I64 integer store instructions can write either 1, 2, 4, or 8 bytes, and floating-point store instructions can write 4, 8, or 10 bytes. For example, a st4 instruction writes the low-order four bytes of an integer register to memory. In addition, semaphore instructions can read and write memory.
For highest performance, data should be aligned on natural boundaries; 10-byte floating-point data should be stored on 16-byte aligned boundaries.
If a load or store instruction accesses naturally aligned data, the reference is atomic with respect to the threads on the same CPU and on other SMP nodes. If the data is not naturally aligned, its access is not atomic with respect to threads on other SMP nodes.
I64 can load and store aligned bytes, words, longwords, quadwords, and 10-byte floating-point values that are aligned on 16-byte boundaries.
6.3.3. Ordering of Read and Write Operations for I64 Systems
Release semantics — all previous memory accesses are made visible before a reference that imposes release semantics (st.rel, fetchadd.rel instructions).
Acquire semantics — the reference imposing acquire semantics is visible before any subsequent ones (ld.acq, ld.c.clr.acq, xchg, fetchadd.acq, cmpxchg.acq instructions).
Fence semantics — combines release and acquire semantics (mf instruction).
6.4. Memory Read-Modify-Write Operations for VAX and Alpha
A fundamental synchronization primitive for accessing shared data is an atomic read-modify-write operation. This operation consists of reading the contents of a memory location and replacing them with new contents based on the old. Any intermediate memory state is not visible to other threads. Both VAX systems and Alpha systems provide this synchronization primitive, but they implement it in significantly different ways.
6.4.1. Uniprocessor Operations
On VAX systems, many instructions are capable of performing a read-modify-write operation in a single, noninterruptible (atomic) sequence from the viewpoint of multiple application threads executing on a single processor.
If you code in VAX MACRO, you can code to guarantee an atomic read-modify-write operation. If you code in a high-level language, however, you must tell the compiler to generate an atomic update. For further information, refer to the documentation for your high-level language.
On Alpha systems, there is no single instruction that performs an atomic read-modify-write operation. As a result, even uniprocessing applications in which processes access shared data must provide explicit synchronization of these accesses, usually through compiler semantics.
Privileged architecture library (PALcode) routines perform queue insertions and removals.
Load-locked and store-conditional instructions create a sequence of instructions that implement an atomic update.
6.4.2. Multiprocessor Operations
On multiprocessor systems, you must use special methods to ensure that a read-modify-write sequence is atomic. On VAX systems, interlocked instructions provide synchronization; on Alpha systems, load-locked and store-conditional instructions provide synchronization.
On VAX systems, a number of uninterruptible instructions are provided that both read and write memory with one instruction. When used with an operand type that is accessible in a single memory operation, each instruction provides an atomic read-modify-write sequence. The sequence is atomic with respect to threads of execution on the same VAX processor, but it is not atomic to threads on other processors. For instance, when a VAX CPU executes the instruction INCL x, it issues two separate commands to memory: a read, followed by a write of the incremented value. Another thread of execution running concurrently on another processor could issue a command to memory that reads or writes location x between the INCL's read and write. Section 6.6.4, “Interlocked Instructions (VAX Only)” describes read-modify-write sequences that are atomic with respect to threads on all VAX CPUs in an SMP system.
On a VAX multiprocessor system, an atomic update requires an interlock at the level of the memory subsystem. To perform that interlock, the VAX architecture provides a set of interlocked instructions that include Add Aligned Word Interlocked (ADAWI), Remove from Queue Head Interlocked (REMQHI), and Branch on Bit Set and Set Interlocked (BBSSI).
If you code in MACRO-32, you use the assembler to generate whatever instructions you tell it. If you code in a high-level language, you cannot assume that the compiler will compile a particular language statement into a specific code sequence. That is, you must tell the compiler explicitly to generate an atomic update. For further information, see the documentation for your high-level language.
On Alpha systems, there is no single instruction that performs an atomic read-modify-write operation. An atomic read-modify-write operation is only possible through a sequence that includes load-locked and store-conditional instructions, (see Section 6.6.2, “LD x_L and ST x_C Instructions (Alpha Only)”). Use of these instructions provides a read-modify-write operation on data within one aligned longword or quadword that is atomic with respect to threads on all Alpha CPUs in an SMP system.
6.5. Memory Read-Modify-Write Operations for I64 Systems
This section summarizes information described in the Intel® Itanium® Architecture Software Developer's Manual. Refer to that manual for complete information.
On I64 systems, the semaphore instructions perform read-modify-write operations that are atomic with respect to threads in the same system and other SMP nodes.
Three types of atomic semaphore instructions are defined: exchange (xchg), compare and exchange (cmpxchg), and fetch and add (fetchadd).
xchg1, xchg2, xchg4, xchg8 to atomically fetch and store (swap) a byte, word, longword or quadword.
cmpxchg1, cmpxchg2, cmpxchg4, cmpxchg8 to atomically compare and store a byte, word, longword or quadword. Atomic bit set and clear, as well as the bit-test-and-set/clear operations can be implemented using the cmpxchg instruction.
fetchadd4, fetchadd8 to atomically increment or decrement a longword or quadword by 1, 4, 8 or 16 bytes.
Note that memory operands of the semaphore instructions must be on aligned boundaries. Unaligned access by a semaphore instruction results in a nonrecoverable unaligned data fault.
6.5.1. Preserving Atomicity with MACRO-32
On an OpenVMS VAX or I64 single-processor system, an atomic memory modification instruction is sufficient to provide synchronized access to shared data. However, such an instruction is not available on OpenVMS Alpha systems.
In the case of code written in MACRO-32, the compiler provides the /PRESERVE=ATOMICITY option to guarantee the integrity of read-modify-write operations for VAX instructions that have a memory modify operand. Alternatively, you can insert the .PRESERVE ATOMICITY and .NOPRESERVE ATOMICITY directives in sections of MACRO-32 source code as required to enable and disable atomicity.
INCL (R1)
ld4 r22 = [r9] sxt4 r22 = r22 adds r22 = 1, r22 st4 [r9] = r22Note that MACRO-32 R1 corresponds to I64 R9.
The problem with the I64 code sequence is that an interrupt can occur between any of the instructions. For example, if the interrupt causes an AST routine to execute or causes another process to be scheduled between the ld4 and the st4, and the AST or other process updates the data pointed to by R1, the STL will store the result (R9) based on stale data.
$L3: ld4 r23 = [r9] mov.m apccv = r23 mov r22 = r23 sxt4 r23 = r23 adds r23 = 1, r23 cmpxchg4.acq r23, [r9] = r23 cmp.eq pr0, pr6 = r22, r23 (pr6) br.cond.dpnt.few $L3
This code uses the compare-exchange instruction (cmpxchg) to implement the locked access. If another thread of execution has modified the location being modified here, this code loops back and retries the operation.
6.6. Synchronization Primitives
Atomic memory references
Noninterruptible instructions
Interrupt priority level (IPL)
Interlocked memory accesses
On VAX systems, many read-modify-write instructions, including queue manipulation instructions, are noninterruptible. These instructions provide an atomic update capability on a uniprocessor. A kernel-mode code thread can block interrupt and process-based threads of execution by raising the IPL. Hence, it can execute a sequence of instructions atomically with respect to the blocked threads on a uniprocessor. Threads of execution that run on multiple processors of an SMP system synchronize access to shared data with read-modify-write instructions that interlock memory.
On Alpha systems, some of these mechanisms are provided by hardware, while others have been implemented in PALcode routines.
Alpha processors provide several features to assist with synchronization. Even though all instructions that access memory are noninterruptible, no single one performs an atomic read-modify-write. A kernel-mode thread of execution can raise the IPL in order to block other threads on that processor while it performs a read-modify-write sequence or while it executes any other group of instructions. Code that runs in any access mode can execute a sequence of instructions that contains load-locked (LD x_L) and store-conditional (ST x_C) instructions to perform a read-modify-write sequence that appears atomic to other threads of execution. Memory barrier instructions order a CPU's memory reads and writes from the viewpoint of other CPUs and I/O processors. Other synchronization mechanisms are provided by PALcode routines.
On I64 systems, some of these mechanisms are provided by hardware, while others have been implemented in the OpenVMS executive.
I64 systems provide atomic semaphore instructions, as described in Section 6.3.1, “Atomic Semaphore Instructions on I64”, acquire/release semantics on certain loads and stores, and the memory fence (MF) instruction, which is equivalent to the memory barrier (MB) on Alpha, to ensure correct memory ordering. Read-modify-write operations on an I64 system can be performed only by nonatomic, interruptible instruction sequences. I64 systems have hardware interrupt levels in maskable in groups of 16. On I634, most, but not all, Alpha PALcall builtins result in system service calls.
The sections that follow describe the features of interrupt priority level, load-locked (LD x_L), and store-conditional (ST x_C) instructions and their I64 equivalents, memory barriers and fences, interlocked instructions, and PALcode routines.
6.6.1. Interrupt Priority Level
The OpenVMS operating system in a uniprocessor system synchronizes access to systemwide data structures by requiring that all threads sharing data run at the IPL of the highest-priority interrupt that causes any of them to execute. Thus, a thread's accessing of data cannot be interrupted by any other thread that accesses the same data.
The IPL is a processor-specific mechanism. Raising the IPL on one processor has no effect on another processor. You must use a different synchronization technique on SMP systems where code threads run concurrently on different CPUs that must have synchronized access to shared system data.
On VAX systems, the code threads that run concurrently on different processors synchronize through instructions that interlock memory in addition to raising the IPL. Memory interlocks also synchronize access to data shared by an I/O processor and a code thread.
On Alpha systems, access to a data structure that is shared either by executive code running concurrently on different CPUs or by an I/O processor and a code thread must be synchronized through a load-locked/store-conditional sequence.
I64 systems have 256 hardware interrupt levels, which are maskable in groups of 16. On I64 systems, an OpenVMS executive component called software interrupt services (SWIS) handles I64 hardware interrupt masking and simulates IPL.
6.6.2. LD x_L and ST x_C Instructions (Alpha Only)
Because Alpha systems do not provide a single instruction that both reads and writes memory or mechanism to interlock memory against other interlocked accesses, you must use other synchronization techniques. Alpha systems provide the load-locked/store-conditional mechanism that allows a sequence of instructions to perform an atomic read-modify-write operation.
Load-locked (LD x_L) and store-conditional (ST x_C) instructions guarantee atomicity that is functionally equivalent to that of VAX systems. The LD x_L and ST x_C instructions can be used only on aligned longwords or aligned quadwords. The LD x_L and ST x_C instructions do not provide atomicity by blocking access to shared data by competing threads. Instead, when the LD x_L instruction executes, a CPU-specific lock bit is set. Before the data can be stored, the CPU uses the ST x_C instruction to check the lock bit. If another thread has accessed the data item in the time since the load operation began, the lock bit is cleared and the store is not performed. Clearing the lock bit signals the code thread to retry the load operation. That is, a load-locked/store-conditional sequence tests the lock bit to see whether the store succeeded. If it did not succeed, the sequence branches back to the beginning to start over. This loop repeats until the data is untouched by other threads during the operation.
By using the LD x_L and ST x_C instructions together, you can construct a code sequence that performs an atomic read-modify-write operation to an aligned longword or quadword. Rather than blocking other threads' modifications of the target memory, the code sequence determines whether the memory locked by the LD x_L instruction could have been written by another thread during the sequence. If it is written, the sequence is repeated. If it is not written, the store is performed. If the store succeeds, the sequence is atomic with respect to other threads on the same processor and on other processors. The LD x_L and ST x_C instructions can execute in any access mode.
Traditional VAX usage is for interlocked instructions to be used for multiprocessor synchronization. On Alpha systems, LD x_L and ST x_C instructions implement interlocks and can be used for uniprocessor synchronization. To achieve protection similar to the VAX interlock protection, you need to use memory barriers along with the load-locked and store-conditional instructions.
Some Alpha system compilers make the LD x_L and ST x_C instruction mechanism available as language built-in functions. For example, VSI C on Alpha systems includes a set of built-in functions that provides for atomic addition and for logical AND and OR operations. Also, Alpha system compilers make the mechanism available implicitly, because they use the LD x_L and ST x_C instructions to access declared data as requiring atomic accesses in a language-specific way.
6.6.3. Interlocking Memory References (Alpha Only)
The Alpha Architecture Reference Manual, Third Edition (AARM) describes strict rules for interlocking memory references. The Alpha 21264 (EV6) processor and all subsequent Alpha processors are more stringent than their predecessors in their requirement that these rules be followed. As a result, code that has worked in the past, despite noncompliance, could fail when executed on systems featuring the 21264 and subsequent processors. Occurrences of these noncompliant code sequences are believed to be rare. The Alpha 21264 processor was first supported by OpenVMS Alpha Version 7.1–2.
Noncompliant code can result in a loss of synchronization between processors when interprocessor locks are used, or can result in an infinite loop when an interlocked sequence always fails. Such behavior has occurred in some code sequences in programs compiled on old versions of the BLISS compiler, some versions of the MACRO–32 compiler and the MACRO–64 assembler, and in some VSI C and VSI C++ programs.
For recommended compiler versions, see Section 6.6.3.5, “Compiler Versions”.
The affected code sequences use LDx_L/STx_C instructions, either directly in assembly language sources or in code generated by a compiler. Applications most likely to use interlocked instructions are complex, multithreaded applications or device drivers using highly optimized, hand-crafted locking and synchronization techniques.
6.6.3.1. Required Code Checks
OpenVMS recommends that code that will run on the 21264 and later processors be checked for these sequences. Particular attention should be paid to any code that does interprocess locking, multithreading, or interprocessor communication.
The SRM_CHECK tool (named after the System Reference Manual, which defines the Alpha architecture) has been developed to analyze Alpha executables for noncompliant code sequences. The tool detects sequences that might fail, reports any errors, and displays the machine code of the failing sequence.
6.6.3.2. Using the Code Analysis Tool
SYS$SYSTEM:SRM_CHECK.EXE
$ define DCL$PATH []
$ srm_check myimage.exe
$ srm_check [*...]* -log
$ srm_check 'file' -output check.dat
You can use the output from the tool to find the module that generated the sequence by looking in the image's MAP file. The addresses shown correspond directly to the addresses that can be found in the MAP file.
** Potential Alpha Architecture Violation(s) found in file... ** Found an unexpected ldq at 00003618 0000360C AD970130 ldq_l R12, 0x130(R23) 00003610 4596000A and R12, R22, R10 00003614 F5400006 bne R10, 00003630 00003618 A54B0000 ldq R10, (R11) Image Name: SYSTEM_SYNCHRONIZATION Image Ident: X-3 Link Time: 5-NOV-1998 22:55:58.10 Build Ident: X6P7-SSB-0000 Header Size: 584 Image Section: 0, vbn: 3, va: 0x0, flags: RESIDENT EXE (0x880)
EXEC$NONPAGED_CODE 00000000 0000B317 0000B318 ( 45848.) 2 ** 5
SMPROUT 00000000 000047BB 000047BC ( 18364.) 2 ** 5
SMPINITIAL 000047C0 000061E7 00001A28 ( 6696.) 2 ** 5
The address 360C is in the SMPROUT module, which contains the addresses from 0-47BB. By looking at the machine code output from the module, you can locate the code and use the listing line number to identify the corresponding source code. If SMPROUT had a nonzero base, it would be necessary to subtract the base from the address (360C in this case) to find the relative address in the listing file.
Note that the tool reports potential violations in its output. Although SRM_CHECK can normally identify a code section in an image by the section's attributes, it is possible for OpenVMS images to contain data sections with those same attributes. As a result, SRM_CHECK may scan data as if it were code, and occasionally, a block of data may look like a noncompliant code sequence. This circumstance is rare and can be detected by examining the MAP and listing files.
6.6.3.3. Characteristics of Noncompliant Code
Some versions of OpenVMS compilers introduce noncompliant code sequences during an optimization called "loop rotation." This problem can only be triggered in C or C++ programs that use LDx_L/STx_C instructions in assembly language code that is embedded in the C/C++ source using the ASM function, or in assembly language written in MACRO–32 or MACRO–64. In some cases, a branch was introduced between the LDx_L and STx_C instructions.
This can be addressed by recompiling.
Some code compiled with very old BLISS, MACRO–32, or DEC Pascal compilers may contain noncompliant sequences. Early versions of these compilers contained a code scheduling bug where a load was incorrectly scheduled after a load_locked.
This can be addressed by recompiling.
In rare cases, the MACRO–32 compiler may generate a noncompliant code sequence for a BBSSI or BBCCI instruction where there are too few free registers.
This can be addressed by recompiling.
Errors may be generated by incorrectly coded MACRO–64 or MACRO–32 and incorrectly coded assembly language embedded in C or C++ source using the ASM function.
This requires source code changes. The new MACRO–32 compiler flags noncompliant code at compile time.
If the SRM_CHECK tool finds a violation in an image, the image should be modified if necessary and recompiled with the appropriate compiler (see Section 6.6.3.5, “Compiler Versions”). After recompiling, the image should be analyzed again. If violations remain after recompiling, the source code must be examined to determine why the code scheduling violation exists. Modifications should then be made to the source code.
6.6.3.4. Coding Requirements
The Alpha Architecture Reference Manual describes how an atomic update of data between processors must be formed. The Third Edition, in particular, has much more information on this topic.
There cannot be a memory operation (load or store) between the LDx_L (load locked) and STx_C (store conditional) instructions in an interlocked sequence.
There cannot be a branch taken between an LDx_L and an STx_C instruction. Rather, execution must "fall through" from the LDx_L to the STx_C without taking a branch.
Any branch whose target is between an LDx_L and matching STx_C creates a noncompliant sequence. For instance, any branch to "label" in the following example would result in noncompliant code, regardless of whether the branch instruction itself was within or outside of the sequence:LDx_L Rx, n(Ry) ... label: ... STx_C Rx, n(Ry)
Any memory operation (LDx/STx) between an LDx_L and an STx_C
Any branch that has a destination between an LDx_L and an STx_C
STx_C instructions that do not have a preceding LDx_L instruction
This typically indicates that a backward branch is taken from an LDx_L to the STx_C. Note that hardware device drivers that do device mailbox writes are an exception. These drivers use the STx_C to write the mailbox. This condition is found only on early Alpha systems and not on PCI based systems.
Excessive instructions between an LDx_L and an STxC
The AARM recommends that no more than 40 instructions appear between an LDx_l and an STx_c. In theory, more than 40 instructions can cause hardware interrupts to keep the sequence from completing. However, there are no known occurrences of this.
** Found an unexpected ldq at 0008291C 00082914 AC300000 ldq_l R1, (R16) 00082918 2284FFEC lda R20, 0xFFEC(R4) 0008291C A6A20038 ldq R21, 0x38(R2)
** Backward branch from 000405B0 to a STx_C sequence at 0004059C 00040598 C3E00003 br R31, 000405A8 0004059C 47F20400 bis R31, R18, R0 000405A0 B8100000 stl_c R0, (R16) 000405A4 F4000003 bne R0, 000405B4 000405A8 A8300000 ldl_l R1, (R16) 000405AC 40310DA0 cmple R1, R17, R0 000405B0 F41FFFFA bne R0, 0004059C
Note
This branch backward from the LDx_L to the STx_C is characteristic of the noncompliant code introduced by the "loop rotation" optimization.
getlck: evax_ldql r0, lockdata(r8) ; Get the lock data movl index, r2 ; and the current index. tstl r0 ; If the lock is zero, beql is_clear ; skip ahead to store. movl r3, r2 ; Else, set special index. is_clear: incl r0 ; Increment lock count evax_stqc r0, lockdata(r8) ; and store it. tstl r0 ; Did store succeed? beql getlck ; Retry if not.
movl index, r2 ; Get the current index getlck: evax_ldql r0, lockdata(r8) ; and then the lock data. evax_cmoveq r0, r3, r2 ; If zero, use special index. incl r0 ; Increment lock count evax_stqc r0, lockdata(r8) ; and store it. tstl r0 ; Did write succeed? beql getlck ; Retry if not.
6.6.3.5. Compiler Versions
This section contains information about versions of compilers that may generate noncompliant code sequences and the minimum recommended versions to use when recompiling.
Old Version |
Recommended Minimum Version |
---|---|
BLISS V1.1 |
BLISS V1.3 |
DEC C V5.x |
HP C V6.0 |
DEC C++ V5.x |
HP C++ V6.0 |
DEC Pascal V5.0-2 |
HP Pascal V5.1-11 |
MACRO–32 V3.0 |
|
MACRO–64 V1.2 |
See below. |
Current versions of the MACRO–64 assembler may still encounter the loop rotation issue. However, MACRO–64 does not perform code optimization by default, and this problem occurs only when optimization is enabled. If SRM_CHECK indicates a noncompliant sequence in the MACRO–64 code, it should first be recompiled without optimization. If the sequence is still flagged when retested, the source code itself contains a noncompliant sequence that must be corrected.
6.6.3.6. Interlocked Memory Sequence Checking for the MACRO–32 Compiler
The MACRO–32 Compiler for OpenVMS Alpha Version 4.1 and later performs additional code checking and displays warning messages for noncompliant code sequences. The following warning messages can display under the circumstances described:
BRNDIRLOC, branch directive ignored in locked memory sequence
Explanation: The compiler found a .BRANCH_LIKELY directive within an LDx_L/STx_C sequence.
User Action: None. The compiler ignores the .BRANCH_LIKELY directive and, unless other coding guidelines are violated, the code works as written.
BRNTRGLOC, branch target within locked memory sequence in routine ’routine_name’
Explanation: A branch instruction has a target that is within an LDx_L/STx_C sequence.
User Action: To avoid this warning, rewrite the source code to avoid branches within or into LDx_L/STx_C sequences. Branches out of interlocked sequences are valid and are not flagged.
MEMACCLOC, memory access within locked memory sequence in routine ’routine_name ’
Explanation: A memory read or write occurs within an LDx_L/STx_C sequence. This can be either an explicit reference in the source code, such as "MOVL data, R0", or an implicit reference to memory. For example, fetching the address of a data label (for example, "MOVAB label, R0") is accomplished by a read from the linkage section, the data area that is used to resolve external references.
User Action: To avoid this warning, move all memory accesses outside the LDx_L/STx_C sequence.
RETFOLLOC, RET/RSB follows LDx_L instruction
Explanation: The compiler found a RET or RSB instruction after an LDx_L instruction and before finding an STx_C instruction. This indicates an ill-formed lock sequence.
User Action: Change the code so that the RET or RSB instruction does not fall between the LDx_L instruction and the STx_C instruction.
RTNCALLOC, routine call within locked memory sequence in routine ’routine_name’
Explanation: A routine call occurs within an LDx_L/STx_C sequence. This can be either an