# Compaq ACMS for OpenVMS
Systems Interface Programming

Previous | Contents | Index

## 2.1.5 ACMS$SIGNAL and ACMS$WAIT Support Services

Following are descriptions of the ACMS$SIGNAL and ACMS$WAIT synchronous support services, which you can use to obtain additional status information about an error.

### 2.1.5.1 ACMS$SIGNAL

When an agent program encounters an error during a call to an SI service, the service returns a status value to the agent program. In some cases, you need additional information about the error. To get additional error information, an agent program can call the ACMS$SIGNAL service. This service signals the secondary status, if any. The ACMS$SIGNAL service does not signal the primary error status, only secondary status information. The agent program must also call LIB$SIGNAL to signal the primary error status if all error logging is done using a condition handler.

By writing a condition handler, an agent program can collect error messages and write them to an error log. You can set up a condition handler in an agent program that receives the secondary status and any FAO parameters for the secondary status values in the signal array. See the OpenVMS Calling Standard for a discussion of signals in the OpenVMS calling standard.

Only the SI submitter services store secondary status information. The services store information on a per-submitter basis, and ACMS saves this secondary status information only until the next SI service for the same task submitter completes. For synchronous SI services, the agent program should call the ACMS$SIGNAL service immediately after any service that returns an error status. For asynchronous SI services, the agent program should call the ACMS$SIGNAL service in the AST completion routine.

Calling ACMS$SIGNAL from an AST routine is necessary to prevent another service from interrupting ACMS and possibly storing error information about other error conditions. When a service completes, any errors saved from the last service are deleted.

Note Do not use event flags if your agent program calls several asynchronous services at the same time for a single task submitter. ACMS cannot ensure that ACMS$SIGNAL will return information on the correct service completion because any of the services could have set the event flag.

## Format

> ACMS$SIGNAL (id.rq.r)

## Parameters

> ### id

> The submitter ID returned on the ACMS$SIGN_IN service.

> Because the ACMS$SIGNAL service requires a submitter ID as input, the agent program must explicitly sign in task submitters using the ACMS$SIGN_IN service, and pass the address of the submitter ID returned by the ACMS$SIGN_IN service to ACMS$SIGNAL. For example, the ACMS$SIGNAL service might return an error condition if the submitter ID is invalid.

Note Because the submitter ID is returned on successful completion of the ACMS$SIGN_IN service, ACMS$SIGNAL fails after an unsuccessful call to the ACMS$SIGN_IN service.

## Return Status

> The return status codes indicating success or failure of the call are:

> Status | Severity Level | Description
> --- | --- | ---
> ACMS$_NORMAL | Success | Normal successful completion
> ACMS$_NTSNIN | Error | Bad ID

See Chapter 7 for examples of agent programs that call the ACMS$SIGNAL service.

### 2.1.5.2 ACMS$WAIT

The SI asynchronous services sometimes invoke processing at mainline level instead of AST level. An agent program can call the ACMS$WAIT service to stall the mainline level process until an asynchronous service completes. The ACMS$WAIT service operates in a fashion similar to the $SYNCH system service. ACMS$WAIT checks that an event flag is set and a completion status block contains a nonzero status value; when these conditions are met, then the asynchronous SI service has completed and ACMS$WAIT returns to the calling agent program.

ACMS provides the ACMS$WAIT service for times when the SI asynchronous services need to perform processing at mainline level (instead of at AST level) to avoid hanging the process at AST level while performing a synchronous operation.

ACMS performs synchronous operations at mainline by having the ACMS$WAIT service process a queue of requests for these operations. This ensures that the SI services can continue processing at AST level. Because of this, one user cannot stop all processing in the agent program for all others while that user performs time-consuming operations.

Use the ACMS$WAIT service to invoke processing at mainline level when an agent program calls any of the following asynchronous submitter services:

- ACMS$CALL_A
- ACMS$START_CALL_A
- ACMS$WAIT_FOR_CALL_END_A

Note An agent program must use the ACMS$WAIT service at mainline level if it uses these asynchronous services. If an agent program does not use ACMS$WAIT with these services, it is possible for the service to hang indefinitely.

The ACMS$WAIT service uses a completion status block parameter. The ACMS$WAIT service puts the mainline code into a wait state. The code is resumed when the first longword of the completion status block is set to a nonzero value and the ACMS$EFN event flag is set.

Typical uses of the ACMS$WAIT service include:

- When calling an asynchronous submitter service from mainline level, use the ACMS$WAIT service with the completion status parameter to wait for completion of the service.
- When you write an asynchronous multiuser agent program, you may want to suspend the mainline level and allow all activity to occur at AST level. Use ACMS$WAIT to suspend mainline level. Initialize the completion status buffer to zero before calling the service; do not use the status buffer in any other call.
  You can resume the mainline level by manually setting the ACMS$EFN flag and moving a nonzero completion status to the completion status buffer. Mainline level is generally resumed when running down the agent program.
- If an agent program selects a task that performs any exchange step using DECforms or TDMS request I/O, you must use the ACMS$WAIT service instead of SYS$HIBER or SYS$WAITFR. Set the completion status parameter to a nonzero value for the equivalent of a SYS$WAKE at mainline level.

  Note You must use ACMS$WAIT in such situations even if .RLB or .FORM files are manually cached, because ACMS checks the remote .RLB or .FORM file to make sure that the submitter node has the latest copy.

## Format

> ACMS$WAIT (comp_status.rq.r)

## Parameters

> ### comp_status

> The status block that waits for a nonzero value.

## Note

> ACMS$WAIT waits for only one event flag that is stored in a global location called ACMS$EFN. The ACMS$EFN symbol is not the value of the event flag. Rather it is the address of the location where the event flag number is stored. Therefore, declare ACMS$EFN as an external longword variable, not an external longword constant. Also, you must pass ACMS$EFN explicitly to all SI services when you use ACMS$WAIT, because ACMS does not set the event flag implicitly.

## Return Status

> The first longword of the IOSB is the return status. The return status is the completion status of the call that was waited for.

> ACMS$WAIT may also return the completion status of the relevant asynchronous service.

## 2.1.6 Single-Threaded and Multithreaded Agent Programs

You may want to have an agent program submit tasks for one user at a time. Single-threaded agent programs submit tasks to ACMS for only one user at a time. These agent programs are synchronous and are therefore easier to write and maintain. However, because single-threaded agent programs handle only one user, each user requires a separate OpenVMS process. This makes single-threaded agent programs expensive in terms of computing resources.

You may want to have an agent program handle several users simultaneously. Multithreaded agent programs submit tasks for several users at a time. For each user, the agent program calls the ACMS$SIGN_IN service to sign the user in to ACMS, returning a submitter ID.

Consider the following when programming a multithreaded agent program:

- Use a separate context, or thread, for each submitter. You can keep the information for each thread in heap storage. Because the agent program handles several threads, allocate an area of memory for each thread in the process to store information pertinent to that thread.
- Avoid operations that can stall the process. It is best to use the SI services and I/O operations asynchronously to avoid interrupting the execution of a process. Prompting a terminal user for information in a synchronous format, for example, can hold up all other threads in the process while they wait for that user to supply a response.
- Use separate I/O channels for each thread. You can establish a separate channel for each thread by using RMS or QIO statements in your agent program. For example, you can use the $OPEN and $CONNECT statements to open a channel for each thread. Then use the $GET and $PUT statements to read and write information for that thread.
- Provide for error isolation. Do not let an error in one thread interrupt or stop the processing of all other threads for that agent program. When an error occurs, provide an escape for that thread, such as signing the thread out of ACMS, rather than stopping the whole agent process.

## 2.1.7 Default Submitter Feature

Note The default submitter feature continues to be supported for existing applications of ACMS. This feature is in decline, however, and is not recommended for new development. You cannot use the Default Submitter Feature for agent programs that perform DECforms I/O, because they must call ACMS$INIT_EXCHANGE_IO, which requires the submitter ID returned from ACMS$SIGN_IN.

The ACMS$SIGN_IN service is optional for certain types of single-threaded agent programs. If you do not use ACMS$SIGN_IN, the default submitter feature is activated during the first call to an SI service.

If you write a single-threaded agent program that submits tasks under its own user name and does not use a terminal, you can omit calling the ACMS$SIGN_IN service and using the submitter ID parameter when calling subsequent SI services.

For single-threaded agent programs that do not call the ACMS$SIGN_IN service, the user is signed in automatically during the first call to an SI service, but a submitter ID is not returned to the user. Thus, the agent program cannot pass a submitter ID to any subsequent SI services.

The following restrictions apply to single-threaded agent programs that do not call the ACMS$SIGN_IN service; these agent programs:

- Cannot call tasks that perform DECforms I/O
- Must submit tasks under their own user name
- Must not use SYS$INPUT
- May receive ACMS$SIGN_IN errors from the first service called
- Cannot call the ACMS$SIGNAL service
- Must not call ACMS$SIGN_IN service at any time

If an agent program calls the ACMS$SIGN_IN service, it must use the ACMS$SIGN_IN service for each task submitter that it handles. The agent program must also pass a submitter ID to all subsequent SI services.

## 2.1.8 Running an Agent Program

Once you successfully compile and link an agent program, you invoke it with DCL commands as you do with any other program. It is important, however, to have the ACMS system running before you start the agent program. It is also important, if a Request Interface (RI) agent or a user-written agent uses DECforms in ACMS tasks, to define a logical name to prepare for using the agent.

Section 2.1.8.1 describes defining the logical name. Section 2.1.8.2 describes starting an agent program.

### 2.1.8.1 Preparing to Use RI or User-Written Agents that Use DECforms in Tasks

During the initialization of a Command Process (CP) or a user-written agent, ACMS determines the following two conditions:

- Whether CMA is in the process
- The version of DECforms being used

Depending on these two conditions, the ACMS agent with respect to DECforms operates in either single-user mode or multi-user mode.

Single-user mode is defined as one user at a time executing an ACMS task. A single-threaded user-written agent is an example of single-user mode.

Multi-user mode is defined as more than one user at a time executing an ACMS task. A CP is an example of multi-user mode. If you use a multi-user user-written agent with DECforms Version 2.2, the agent must be linked with CMA.

ACMS provides the logical name ACMS$DECFORMS_IN_AGENT. Define this logical name as a process logical name when a user-written agent uses DECforms in ACMS tasks. The following characters are valid for defining the logical name to a TRUE value: 1, T, t, Y, y. For example:

    $ DEFINE/PROCESS ACMS$DECFORMS_IN_AGENT "Y"

Compaq recommends that you use settings for the logical name based on the version of DECforms that the agent uses, as follows:

- DECforms Version 1.4 is used.
  Defining the logical name ACMS$DECFORMS_IN_AGENT is not required, but has no harmful effects. Defining the logical name causes ACMS to load the FORMS$MANAGER forms manager during initialization, rather than when the first DECforms call is made.
- DECforms Version 2.1B is used.
  Define the logical name ACMS$DECFORMS_IN_AGENT to a TRUE value. Doing so ensures that ACMS brings CMA into the process if CMA is not already there.
- DECforms Version 2.2 is used.
  If the agent is intended to run in single-user mode, defining the logical name ACMS$DECFORMS_IN_AGENT has no effect, because CMA is not in the process. Defining the logical name causes ACMS to load the FORMS$MANAGER forms manager during initialization, rather than when the first DECforms call is made.

Define the logical name ACMS$DECFORMS_IN_AGENT only when using DECforms Version 2.1B or when using DECforms Version 2.2 in multi-user mode.

### 2.1.8.2 Starting an Agent Program

If the agent program handles only one task submitter and receives its input from your terminal (SYS$INPUT), you can start it with the DCL RUN command. For example:

    $ RUN MYAGENT.EXE

For multithreaded agent programs that handle several task submitters or threads, or agent programs that receive input from a device other than a terminal, you can invoke the agent image as a detached process. For example:

    $ RUN/DETACHED/UIC=[1,4] -
    _$ /INPUT=MTAINPUT.DAT -
    _$ /OUTPUT=MTAOUTPUT.LOG -
    _$ /PROCESS=ACMS_MYAGENT MYAGENT.EXE

This example shows that the agent program receives its input from the file MTAINPUT.DAT and logs messages in the file MTAOUTPUT.LOG. The next section describes some additional considerations for writing a multithreaded agent program.

## 2.1.9 Debugging an Agent Program with ACMS$CHECK

When developing an agent program, you may make programming errors, such as omitting required parameters or incorrectly ordering parameters. To improve performance, ACMS does not check these parameters but instead returns access violations for errors. Access violations are generic and do not describe the error or the parameter that caused the problem. Therefore, to help debug agent programs, the SI allows you to set the ACMS$CHECK logical name, which tells the SI to probe parameters. If ACMS$CHECK cannot access a parameter, it returns relevant error messages rather than access violations.

To enable parameter checking, define the logical ACMS$CHECK name using an odd number or a string prefixed with an uppercase or lowercase T or Y. For example:

    $ DEFINE ACMS$CHECK TRUE
    $ RUN DISK$:[AGENT.OBJ]PROGRAM
               .
               .
               .
    $ DEASSIGN ACMS$CHECK

You usually enable ACMS$CHECK by making the ACMS$CHECK logical name accessible to your agent program as a process or job logical name. Defining the ACMS$CHECK logical name affects any agent program that has access to the logical name. For instance, defining the logical name as a system logical name affects every agent program on the system including the ACMS command process. The ACMS$CHECK logical name is translated when an agent program starts. Once enabled, ACMS$CHECK remains enabled for the life of the agent program. ACMS$CHECK cannot be enabled or disabled after an agent program starts.

Defining ACMS$CHECK as a logical name aids the debugging process. Although it is a valuable debugging aid, using ACMS$CHECK greatly reduces the performance of an agent program because it causes all arguments to be checked. Therefore, be sure to disable parameter checking by deassigning ACMS$CHECK at the end of the debugging session.

# 2.2 Features Common to Languages that Call the Systems Interface

You can call the SI services from any language that follows the OpenVMS Calling and Condition Handling Standards. All code that uses these services must execute in user mode. The following sections describe the libraries and files that languages can use to access the SI services. The libraries and files contain the following information:

- Structure layouts for the various service IDs. The SI services create and pass IDs, which are quadwords, to each other. The ID names are:
  - ACMS$CALL_ID
  - ACMS$CONNECT_ID
  - ACMS$EXCHANGE_IO_ID
  - ACMS$IO_ID
  - ACMS$PROCEDURE_ID
  - ACMS$STREAM_ID
  - ACMS$SUBMITTER_ID
- Length of the IDs. You can resolve these sizes at compile or link time. The size of the IDs is 8 bytes and is given by the following constants:
  - ACMS$S_CALL_ID
  - ACMS$S_CONNECT_ID
  - ACMS$S_EXCHANGE_IO_ID
  - ACMS$S_IO_ID
  - ACMS$S_PROCEDURE_ID
  - ACMS$S_STREAM_ID
  - ACMS$S_SUBMITTER_ID
- Constants other than return status values that are used in service calls for both input and output. Examples of this type of constant are the item codes in the item list in the ACMS$GET_PROCEDURE_INFO service. These constants are resolved at compile time.
- Status values declared as external literals. They are resolved at link time.

Some language interface files contain entry point information. The BLISS require file, for example, provides keyword macros for all the services.

The following sections discuss how BLISS, C, FORTRAN, MACRO, Pascal, and PL/I access the services. The last section describes how to use the services with other languages.

## 2.2.1 BLISS

The require file SYS$LIBRARY:ACMSBLI.R32 is supplied for BLISS programmers. The system manager can compile this file into a BLISS library file. See the BLISS-32 documentation for information on using require files, creating library files, and using library files.

The require file:

- Contains keyword macros for all the services. The macro name is the service name prefixed with a dollar sign ($). The keyword macro for ACMS$SIGN_IN, for example, is $ACMS$SIGN_IN.
- Contains structure definitions for all IDs. Use these IDs in declaration definitions. The name of the structure is the same as the name given in the structure layouts listed in Section 2.2.
- Defines constants other than return status values.

## 2.2.2 C

The text library SYS$LIBRARY:ACMSCC.TLB is supplied for C programmers. Refer to C documentation for information about using the text library files in programs.

The text library provides the following modules for agent programs:

- ACMS$SUBMITTER
- ACMS$STREAM

These modules:

- Contain routine definitions for all the SI services as functions returning long integers.
- Contain structure definitions for all IDs. Use these IDs in declarations. The name of the structure is the same as that given in the structure list above.
- Define constants other than return status values. These constants are defined by #DEFINE preprocessor definitions.

## 2.2.3 FORTRAN

The text library SYS$LIBRARY:ACMSFOR.TLB is supplied for FORTRAN programmers. See FORTRAN documentation for information on using the text library files in programs.

The text library provides the following modules for agent programs:

- ACMS$SUBMITTER
- ACMS$STREAM

These modules:

- Contain all the services defined as EXTERNAL INTEGER*4 functions.
- Contain byte arrays for all IDs. The name of the byte array is the same as the name given in the structure list in Section 2.2. The byte array gives the programmer one of each of the IDs.
- Define constants other than return status values. These constants are defined as parameters. For a method of referring to return status values, see the sample program in Chapter 7 for an example of a FORTRAN agent program using ACMS$_SENDER_DISCONN.

Previous | Next | Contents | Index