hp.com home products and services support and drivers solutions how to buy
cd-rom home
End of Jump to page title
HP OpenVMS systems
documentation

Jump to content


HP OpenVMS Programming Concepts Manual

HP OpenVMS Programming Concepts Manual


Previous Contents Index

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:

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:

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:

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:

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.

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.

DELPRC_EXIT allows you to specify the least-privileged mode for which exit handling will be attempted, or that no exit handling will be attempted. The possible DELPRC_EXIT values are as follows:

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.

The $DELPRCSYMDEF macro defines a symbolic name for EXIT and NOEXIT. The EXIT flag should be or'd with the access mode defined by the $PSLDEF macro for the initial exit handler. Table 4-13 describes each flag:

Table 4-13 Contents of$DELPRC Flag Argument
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.

For example, to delete a process executing exec mode exit handlers from a macro program:


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

You should be aware of the following differences:

If you use the DCL STOP command without either the /IDENTIFICATION qualifier or the process-name parameter, then the currently excuting image is terminated; the process is not deleted.

In a mixed version or mixed architecture cluster, any explicit control specified to $DELPRC or a DCL STOP command is passed to the node on which the process is executing. The process deletion on the remote node executes as defined for the version of OpenVMS running on the target node. Therefore, consider the following configuration examples.
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

Deleting the current process: When $DELPRC is used to delete the current process, execution cannot continue in the mode from which $DELPRC was called. The first exit handlers that are called will be in the next more privileged mode relative to the mode from which $DELPRC was called (subject to options defined). For example:
  • $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 HP 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