Document revision date: 15 July 2002 | |
Previous | Contents | Index |
This example shows the use of $GETDTI on recovery to determine the final state of a transaction. $SETDTI is used to remove the resource manager from the transaction.
/* Recover the state of a prepared resource after a failure */ RecoverString(...) { int status; IOSB iosb; uint context = 0; /* context from $GETDTI */ int retlen; Int state; /* transaction state */ DTIRECDEF dti; ITMLST3_DECL (search, 1); ITMLST3_ITEM (search, 0, DTI$_SEARCH_RESOLVED_STATE, DTI$S_TRANSACTION_INFORMATION, &dti, 0); DTI$S_TRANSACTION_INFORMATION, &dti, 0); ITMLST3_END (search); ITMLST3_DECL (result, 1); ITMLST3_ITEM (result, 0, DTI$_TRANSACTION_INFORMATION, DTI$S_TRANSACTION_INFORMATION, &dti, &retlen); ITMLST3_END (result); /* get final state of transaction */ dti.dti$b_part_name_len = 0; /* no RM name specified */ CopyUid((uint *) dti.dti$t_tid, pTaos->stringBuf.tid); status = sys$getdtiw(pTaos->efn, DDTM$M_FULL_STATE, &iosb, NULL, 0, pTaos->tmLogId, &context, &search, &result); if (SUCCESS(status)) status = iosb.iosb$w_status; if (SUCCESS(status)) state = dti.dti$b_state; /* treat forgotten TID as presumed abort */ if (status == SS$_NOSUCHTID) { state = DTI$K_ABORTED; status = SS$_NORMAL; } if (SUCCESS(status)) { switch (state) { case DTI$K_COMMITTED: /* Make update permanent and visible here. * Set status on error. */ break; case DTI$K_ABORTED: /* Undo the update here. Set status on error. */ break; } } if (SUCCESS(status)) { /* allow DECdtm to remove this RM from the transaction */ status = sys$setdtiw(pTaos->efn, 0, &iosb, NULL, 0, &context DTI$K_DELETE_RM_NAME, &result); } } |
The following BLISS program demonstrates how a simple resource manager may perform recovery following a system failure. In the example, a $GETDTI is executed on behalf of a remote node (MYNODE) specifying a transaction identifier, named resource manager, participant log identifier and transaction manager log identifier.
When the $GETDTI finishes processing, the recovery logic in the resource manager performs its own recovery and issues a $SETDTI to remove the resource manager name from the transaction.
MODULE RECOVER_TRANSACTION (MAIN=MAIN)= BEGIN LIBRARY'SYS$LIBRARY:STARLET'; FORWARD ROUTINE MAIN, AST_COMPLETION_ROUTINE : NOVALUE; ROUTINE MAIN = BEGIN OWN STATUS : LONG UNSIGNED, IOSB : VECTOR [4,WORD], SEARCH_CONTEXT : LONG UNSIGNED INITIAL (0), PART_LOG_ID : $BBLOCK [DTI$S_PART_LOG_ID] INITIAL (REP DTI$S_PART_LOG_ID OF BYTE (0)), TM_LOG_ID : $BBLOCK [DTI$S_PART_LOG_ID] INITIAL (REP DTI$S_PART_LOG_ID OF BYTE (0)), TID : $BBLOCK [DTI$S_TID] INITIAL (REP DTI$S_TID OF BYTE (0)), SEARCH_LIST : $ITMLST_DECL (ITEMS=2), ITEM_LIST : $ITMLST_DECL (ITEMS=1), TRANS_INFO : $BBLOCK [DTI$S_TRANSACTION_INFORMATION]; BIND SEARCH_NODE_NAME = UPLIT (%ASCII'MYNODE'), RESOURCE_MANAGER = UPLIT (%ASCII'FRED'); LITERAL SEARCH_NODE_NAME_LENGTH = %CHARCOUNT ('MYNODE'), RESOURCE_MANAGER_LENGTH = %CHARCOUNT ('FRED'); ! Resource manager opens recovery log and reads first resolved ! recovery record. The information in the recovery record ! should contain the transaction identifier, resource manager ! log identifier and transaction manager log identifier. This ! information is written into the transaction information ! record. CH$MOVE (DTI$S_TID, TID, TRANS_INFO [DTI$T_TID]); CH$MOVE (DTI$S_PART_LOG_ID, PART_LOG_ID, TRANS_INFO [DTI$T_PART_LOG_ID]); CH$MOVE (RESOURCE_MANAGER_LENGTH, .RESOURCE_MANAGER, TRANS_INFO [DTI$T_PART_NAME]); TRANS_INFO [DTI$B_PART_NAME_LEN] = RESOURCE_MANAGER_LENGTH; ! The search item list is initialized with a node ! name and transaction information record. $ITMLST_INIT (ITMLST=SEARCH_LIST, (ITMCOD=DTI$_SEARCH_AS_NODE, BUFADR=.SEARCH_NODE_NAME, BUFSIZ=SEARCH_NODE_NAME_LENGTH), (ITMCOD=DTI$_SEARCH_RESOLVED_STATE, BUFADR=TRANS_INFO, BUFSIZ=DTI$S_TRANSACTION_INFORMATION)); ! The item list is initialized to return a transaction ! information record containing the resolved state of the ! transaction. ! transaction. $ITMLST_INIT (ITMLST=ITEM_LIST, (ITMCOD=DTI$_TRANSACTION_INFORMATION, BUFADR=TRANS_INFO, BUFSIZ=DTI$S_TRANSACTION_INFORMATION)); ! A $GETDTI is now performed to return the state of the ! transaction and the node name. STATUS = $GETDTIW (EFN=10, FLAGS=DDTM$M_FULL_STATE, IOSB=IOSB, ASTADR=AST_COMPLETION_ROUTINE, ASTPRM=0, CONTXT=SEARCH_CONTEXT, LOG_ID=TM_LOG_ID, SEARCH=SEARCH_LIST, ITMLST=ITEM_LIST); ! If the transaction was committed then perform resource manager ! recovery and then delete the resource manager from the ! transaction. IF .TRANS_INFO [DTI$B_STATE] EQLU DTI$K_COMMITTED THEN STATUS = $SETDTIW (EFN=10, FLAGS=0, IOSB=IOSB, ASTADR=AST_COMPLETION_ROUTINE, ASTPRM=0, CONTXT=SEARCH_CONTEXT, FUNC=DTI$K_DELETE_RM_NAME, ITMLST=ITEM_LIST); RETURN .STATUS END; ROUTINE AST_COMPLETION_ROUTINE (ASTPRM : LONG UNSIGNED) : NOVALUE = BEGIN RETURN; END; END ELUDOM |
This chapter describes how to create user-written system services. It contains the following sections:
Section 31.1 describes privileged routines and privileged shareable images.
Section 31.2 describes how to write a privileged routine.
Section 31.3 describes how to create a privileged shareable image on VAX systems.
Section 31.4 describes how to create a privileged shareable image on
Alpha systems.
31.1 Overview
Your application may contain certain routines that perform privileged functions, called user-written system services. To create these routines, put them in a privileged shareable image. User-mode routines in other modules can call the routines in the privileged shareable image to perform functions in a more privileged mode.
You create a privileged shareable image as you would any other shareable image, using the /SHAREABLE qualifier with the linker. (For more information about how to create a shareable image, see the OpenVMS Linker Utility Manual.) However, because a call to a routine in a more privileged mode must be vectored through the system service dispatch routine, you must perform some additional steps. The following steps outline the basic procedure. Section 31.3 provides more detail about requirements specific to VAX systems. Section 31.4 describes the necessary steps for Alpha systems.
$ INSTALL INSTALL> ADD SYS$SHARE:MY_PRIV_SHARE/PROTECT/OPEN/SHARED/HEADER_RES |
To use a privileged shareable image, you include it in a link operation
as you would any other shareable image: specifying the shareable image
in a linker options file with the /SHAREABLE qualifier appended to the
file specification to identify it as a shareable image.
31.2 Writing a Privileged Routine (User-Written System Service)
On both VAX systems and Alpha systems, the routines that implement user-written system services must enable any privileges they need that the nonprivileged user of the user-written system service lacks. The user-written system service must also disable any such privileges before the nonprivileged user receives control again. To enable or disable a set of privileges, use the Set Privileges ($SETPRV) system service. The following example shows the operator (OPER) and physical I/O (PHY_IO) privileges being enabled. (Any code executing in executive or kernel mode is granted an implicit SETPRV privilege so it can enable any privileges it needs.)
PRVMSK: .LONG <1@PRV$V_OPER>!<1@PRV$V_PHY_IO> ;OPER and PHY_IO .LONG 0 ;quadword mask required. No bits set in ;high-order longword for these privileges. . . . $SETPRV_S ENBFLG=#1,- ;1=enable, 0=disable PRVADR=PRVMSK ;Identifies the privileges |
When you design your system service, you must carefully define the boundaries between the protected subsystem and the user who calls the service. A protected image has privileges to perform tasks on its own behalf. When your image performs tasks on behalf of users, you must ensure that your image performs only those tasks the users could not have done on their own. Always keep the following coding principles in mind:
On VAX systems, refer to SYS$EXAMPLES:USSDISP.MAR and USSTEST.MAR for listings of modules in a user-written system service and of a module that calls the user-written system service.
On Alpha systems, for C examples refer to SYS$EXAMPLES:UWSS.C and
SYS$EXAMPLES:UWSS_TEST.C.
31.3 Creating a Privileged Shareable Image (VAX Only)
On VAX systems, you must create dispatch routines that transfer control
to the privileged routines in your shareable image. You then put the
addresses of these dispatch routines in a privileged library vector
(PLV). Section 31.3.1 describes how to create a dispatch routine.
Section 31.3.2 describes how to create a PLV.
31.3.1 Creating User-Written Dispatch Routines on VAX Systems
On VAX systems, you must create kernel-mode and executive-mode dispatching routines that transfer control to the routine entry points. You must supply one dispatch routine for all your kernel mode routines and a separate routine for all the executive mode routines. The dispatcher is usually written using the CASE construct, with each routine identified by a code number. Make sure that the identification code you use in the dispatch routine and the code specified in the transfer vector identify the same routine.
The image activator, when it activates a privileged shareable image, obtains the addresses of the dispatch routines from the PLV and stores these addresses at a location known to the system service dispatcher. When a call to a privileged routine is initiated by a CHME or CHMK instruction, the system service dispatcher attempts to match the code number with a system service code. If there is no match, it transfers control to the location where the image activator has stored the address of your dispatch routines.
A dispatch routine must validate the CHMK or CHME operand identification code number, handling any invalid operands. In addition, the dispatching routine must transfer control to the appropriate routine for each identification code if the user-written system service contains functionally separate coding segments. The CASE instruction in VAX MACRO or a computed GOTO-type statement in a high-level language provides a convenient mechanism for determining where to transfer control.
Users of your privileged shareable image must specify the same code number to identify a privileged routine as you used to identify it in the dispatch routine. Users specify the code number in their CHMK or CHME instruction. See Section 31.3.3 for information about transfer vectors. |
In your source file, a dispatch routine must precede the routines that implement the user-written system service.
Example 31-1 illustrates a sample dispatching routine, taken from the sample privileged shareable image in SYS$EXAMPLES named USSDISP.MAR.
Example 31-1 Sample Dispatching Routine |
---|
KERNEL_DISPATCH:: ; Entry to dispatcher MOVAB W^-KCODE_BASE(R0),R1 ; Normalize dispatch code value BLSS KNOTME ; Branch if code value too low CMPW R1,#KERNEL_COUNTER ; Check high limit BGEQU KNOTME ; Branch if out of range ; ; The dispatch code has now been verified as being handled by this dispatcher, ; now the argument list will be probed and the required number of arguments ; verified. ; MOVZBL W^KERNEL_NARG[R1],R1 ; Get required argument count MOVAL @#4[R1],R1 ; Compute byte count including argcount IFNORD R1,(AP),KACCVIO ; Branch if arglist not readable CMPB (AP),W^<KERNEL_NARG-KCODE_BASE>[R0] ; Check for required number BLSSU KINSFARG ; of arguments MOVL FP,SP ; Reset stack for service routine CASEW R0,- ; Case on change mode . . . |
On VAX systems, a call to a privileged routine goes to the transfer vector that executes a change mode instruction (CHMx) specifying the identification code of the privileged routine as the operand to the instruction. The operating system routes the change mode instruction to the system service dispatch routine, which attempts to locate the system service with the code specified. Because the code is a negative number, the system service dispatcher drops through its list of known services and transfers control to a user-written dispatch routine, if any have been specified.
The image activator has already placed at this location the address of whatever user-written dispatch routines it found in the privileged shareable image's PLV when it activated the PLV. The dispatch routine transfers control to the routine in the shareable image identified by the code. (You must ensure that the code used in the transfer vector and the code specified in the dispatch routine both identify the same routine.) Figure 31-1 illustrates this flow of control.
Figure 31-1 Flow of Control Accessing a Privileged Routine on VAX Systems
Figure 31-2 shows the components of the PLV in VAX shareable images.
Figure 31-2 Components of the Privileged Library Vector on VAX Systems
Table 31-1 describes each field in the PLV on a VAX processor, including the symbolic names the operating system defines to access each field. These names are defined by the $PLVDEF macro in SYS$LIBRARY:STARLET.MLB.
Component | Symbol | Description |
---|---|---|
Vector type code | PLV$L_TYPE | Identifies the type of vector. For PLVs, you must specify the symbolic constant defined by the operating system, PLV$C_TYP_CMOD, which identifies a privileged library vector. |
Kernel-mode dispatcher | PLV$L_KERNEL | Contains the address of the user-supplied kernel-mode dispatching routine if your privileged library contains routines that run in kernel mode. The address is expressed as an offset relative to the start of the data structure (self-relative pointer). A value of 0 indicates that a kernel-mode dispatcher does not exist. |
Executive-mode dispatcher | PLV$L_EXEC | Contains the address of the user-supplied executive-mode dispatching routine if your privileged library contains routines that run in executive mode. The address is expressed as an offset relative to the start of the data structure (self-relative pointer). A value of 0 indicates that a kernel-mode dispatcher does not exist. |
User-supplied rundown routine | PLV$L_USRUNDWN | Contains the address of a user-supplied rundown routine that performs image-specific cleanup and resource deallocation if your privileged library contains such a routine. When the image linked against the user-written system service is run down by the system, this run-time routine is invoked. Unlike exit handlers, the routine is always called when a process or image exits. (The image rundown code calls this routine with a JSB instruction; it returns with an RSB instruction called in kernel mode at IPL 0.) |
RMS dispatcher | PLV$L_RMS | Contains the address of a user-supplied dispatcher for OpenVMS RMS services. A value of 0 indicates that a user-supplied OpenVMS RMS dispatcher does not exist. Only one user-written system service should specify the OpenVMS RMS vector, because only the last value is used. This field is intended for use only by Compaq. |
Address check | PLV$L_CHECK | Contains a value to verify that a user-written system service that is not position independent is located at the proper virtual address. If the image is position independent, this field should contain a zero. If the image is not position independent, this field should contain its own address. |
Example 31-2 illustrates how the sample privileged shareable image in SYS$EXAMPLES assigns values to the PLV.
Example 31-2 Assigning Values to a PLV on a VAX System |
---|
.PAGE $PLVDEF ; Define PLV fields .SBTTL Change Mode Dispatcher Vector Block (1) .PSECT USER_SERVICES,PAGE,VEC,PIC,NOWRT,EXE (2) .LONG PLV$C_TYP_CMOD ; Set type of vector to change mode .LONG 0 ; Reserved .LONG KERNEL_DISPATCH-. ; Offset to kernel mode dispatcher .LONG EXEC_DISPATCH-. ; Offset to executive mode dispatcher .LONG USER_RUNDOWN-. ; Offset to user rundown service .LONG 0 ; Reserved. .LONG 0 ; No RMS dispatcher .LONG 0 ; Address check - PIC image |
Previous | Next | Contents | Index |
privacy and legal statement | ||
5841PRO_082.HTML |