Document revision date: 30 March 2001

## OpenVMS Programming Concepts Manual

Previous | Contents | Index

1. Process TAURUS creates the process ORION, specifying the descriptor for the image named COMPUTE.
2. 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.
3. 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 Chapter 27.

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.

#### 4.9.1.2 Using Alternative Methods of Hibernation

You can use two additional methods to cause a process to hibernate:

- 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 and in Section 4.9.4. The RUN and STOP commands are described in the 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

The following DCL command executes the command image associated with the DCL command COPY:

    $ COPY DATA.TMP APRIL.DAT

To pass control from the current image to a command image, use the run-time library (RTL) routine LIB$DO_COMMAND. If LIB$DO_COMMAND executes successfully, control is not returned to the invoking image, and statements following the LIB$DO_COMMAND statement are not executed. The following statement causes the current image to exit and executes the DCL command in the preceding example:

       .
       .
       .
    STATUS = LIB$DO_COMMAND ('COPY DATA.TMP APRIL.DAT')
    IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS))

    END

To execute a number of DCL commands, specify a DCL command procedure. The following statement causes the current image to exit and executes the DCL command procedure [STATS.TEMP]CLEANUP.COM:

       .
       .
       .
    STATUS = LIB$DO_COMMAND ('@[STATS.TEMP]CLEANUP')
    IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS))

    END

#### 4.9.2.2 Invoking a Noncommand Image

You invoke a noncommand image at DCL command level with the DCL command RUN. The following command executes the noncommand image [STATISTICS.TEMP]TEST.EXE:

    $ RUN [STATISTICS.TEMP]TEST

To pass control from the current image to a noncommand image, use the run-time library routine LIB$RUN_PROGRAM. If LIB$RUN_PROGRAM executes successfully, control is not returned to the invoking image, and statements following the LIB$RUN_PROGRAM statement are not executed. The following program segment causes the current image to exit and passes control to the noncommand image [STATISTICS.TEMP]TEST.EXE on the default disk:

       .
       .
       .
    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.

These exit activities are also initiated when an image completes abnormally as a result of any of the following conditions:

- 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.
- A Force Exit (SYS$FORCEX) system service issued on behalf of the process by another process.

#### 4.9.3.1 Performing Image Rundown

The operating system performs image rundown functions that release system resources obtained by a process while it is executing in user mode. These activities occur in the following order:

1. Any outstanding I/O requests on the I/O channels are canceled, and I/O channels are deassigned.
2. 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.
3. All devices allocated to the process at user mode are deallocated (devices allocated from the command stream in supervisor mode are not deallocated).
4. Timer-scheduled requests, including wakeup requests, are canceled.
5. Common event flag clusters are disassociated.
6. Locks are dequeued as a part of rundown.
7. User mode ASTs that are queued but have not been delivered are deleted, and ASTs are enabled for user mode.
8. Exception vectors declared in user mode, compatibility mode handlers, and change mode to user handlers are reset.
9. System service failure exception mode is disabled.
10. 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, 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.

This status code is used as follows:

- 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.

#### 4.9.3.4 Initiating Image Rundown for Another Process

The Force Exit (SYS$FORCEX) system service provides a way for a process to initiate image rundown for another process. For example, the following call to SYS$FORCEX causes the image executing in the process CYGNUS to exit:

            $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.

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 and Section 9.15.4.

### 4.9.4 Deleting a Process

Process deletion completely removes a process from the system. A process can be deleted by any of the following events:

- 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 system performs each of the following procedures, beginning with the lowest process in the hierarchy and ending with the topmost process:

- 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. 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 illustrates the flow of events from image exit through process deletion.

Figure 4-1 Image Exit and Process Deletion

#### 4.9.4.1 Deleting a Process By Using System Services

A process can delete itself or another process at any time, depending on the restrictions outlined in Section 4.1.1. Any one of the following system services can be used to delete a subprocess or a detached process. Some services terminate execution of the image in the process; others terminate the process itself.

- 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 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$EDLPRC(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 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 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.

The following example illustrates a complete sequence of process creation, with a termination mailbox:

    #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 {                                        (1)
            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) */ (2)
                          &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 */      (3)
                          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 */           (4)
                            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)                       (5)
         {
             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;
    }

Previous | Next | Contents | Index

| privacy and legal statement |
5841PRO_016.HTML