|
HP OpenVMS systems documentation |
Previous | Contents | Index |
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 |
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 |
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:
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:
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:
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
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.
$DESCRIPTOR(prcnam,"CYGNUS"); . . . status = SYS$DELPRC(0, /* Process id */ &prcnam); /* Process name */ |
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:
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. |
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:
|
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 |