Previous | Contents | Index |
A mailbox is a virtual I/O device that is used for communication among
processes in the system. The routines CREATE_MAILBOX and DELETE_MAILBOX
in the following example illustrate the creation and deletion,
respectively, of a mailbox.
11.8.2.1 Creating the Mailbox
Example 11-3 illustrates a call to the Create Mailbox and Assign Channel (SYS$CREMBX) system service. This service returns the number of an I/O channel to the calling program. In PL/I, this number is not needed except for the deletion of the mailbox. You must, however, declare a FIXED BINARY(15) variable to receive the number returned by the system service. The following notes are keyed to Example 11-3:
Example 11-3 Creating a Mailbox |
---|
CREATE_MAILBOX: PROCEDURE OPTIONS(MAIN) RETURNS(FIXED BINARY(31)); %INCLUDE SYS$CREMBX; %INCLUDE $STSDEF; %REPLACE MESSAGE_SIZE BY 132; %REPLACE PERMANENT BY '1'B; DECLARE CHANNEL FIXED BINARY(15), MAILBOX_NAME CHARACTER(11) STATIC INITIAL('PLI_MAILBOX'); /* * Call SYS$CREMBX omitting optional arguments. * (Note that trailing optional arguments cannot * be omitted for system services unless specifically * indicated in the service description.) */ STS$VALUE = SYS$CREMBX( (1) PERMANENT, (2) CHANNEL, MESSAGE_SIZE, (3) 'FF00'B4,, (4) MAILBOX_NAME); /* * Return to command level with status. If SYS$CREMBX * completed with an error, the appropriate message is * displayed at the command level. */ RETURN(STS$VALUE); END CREATE_MAILBOX; |
Example 11-4 illustrates a call to the Delete Mailbox (SYS$DELMBX) system service. The procedure DELETE_MAILBOX deletes the mailbox PLI_MAILBOX. A mailbox is deleted when a channel number is specified; this program assigns a channel to the mailbox to obtain a number to be specified in deleting the mailbox. The following notes are keyed to Example 11-4:
Example 11-4 Deleting a Mailbox |
---|
DELETE_MAILBOX: PROCEDURE OPTIONS(MAIN) RETURNS(FIXED BINARY(31)); %INCLUDE SYS$ASSIGN; (1) %INCLUDE SYS$DELMBX; %INCLUDE $STSDEF; DECLARE MAILBOX_NAME CHARACTER(11) STATIC READONLY INITIAL('PLI_MAILBOX') CHANNEL FIXED BINARY(15); /* * Call SYS$ASSIGN and check return; if not successful exit */ STS$VALUE = SYS$ASSIGN(MAILBOX_NAME,CHANNEL,,,); (2) IF ^STS$SUCCESS THEN RETURN(STS$VALUE); /* * Call SYS$DELMBX and check return */ STS$VALUE = SYS$DELMBX(CHANNEL); (3) RETURN(STS$VALUE); END DELETE_MAILBOX; |
The system services that depend on time, either an absolute time or a
delta time, refer to a time value that is maintained in a 64-bit field.
There are system services that convert a character string that
specifies a time to its binary equivalent and vice versa.
11.8.3.1 Obtaining a Time Value in System Format
The PL/I procedure GETBINTIM, shown in Example 11-5, accepts a character-string time value as a parameter and returns the binary time value to the point of the procedure's invocation. The following notes are keyed to Example 11-5:
This procedure may be invoked as follows to supply a date and time value for a file in an ENVIRONMENT option:
DECLARE GETBINTIM ENTRY( CHAR(*) ) RETURNS BIT(64) ALIGNED, (CREATED_DATE,EXPIRE_DATE) BIT(64) ALIGNED; CREATED_DATE = GETBINTIM('17-JUN-1985 00:00:00.00'); EXPIRE_DATE = GETBINTIM('31-DEC-1991 00:00:00.00'); OPEN FILE(TAPEFILE) ENVIRONMENT( CREATION_DATE(CREATED_DATE), EXPIRATION_DATE(EXPIRE_DATE)); |
Example 11-5 Obtaining a System Time Value |
---|
/* * This procedure converts a time given in ASCII format to a * 64-bit time value that is used internally by OpenVMS. * Input strings must be of the form: * * dd-mmm-yyyy-hh:mm:ss.cc (for an absolute date or time) * dddd hh:mm:ss.cc (for a delta time) */ GETBINTIM: PROCEDURE(ASCII_STRING) RETURNS(BIT(64) ALIGNED); %INCLUDE SYS$BINTIM; (1) %INCLUDE $STSDEF; DECLARE ASCII_STRING CHARACTER(*), BINARY_TIME BIT(64) ALIGNED; /* * If successful, return binary time to point of * invocation. Otherwise, return 0 - this results * in absolute time 17-NOV-1858. */ STS$VALUE = SYS$BINTIM(ASCII_STRING,BINARY_TIME); (2) IF STS$SUCCESS THEN RETURN(BINARY_TIME); ELSE RETURN((64)'0'B); END GETBINTIM; |
The procedure in Example 11-6 uses the Set Timer (SYS$SETIMR) system service. It issues a time request for some activity to occur in 10 seconds and specifies the number of an event flag to be set when the 10 seconds have elapsed. The following notes are keyed to Example 11-6:
Example 11-6 Setting a Timer |
---|
SET_TIMER: PROCEDURE OPTIONS(MAIN) RETURNS(FIXED BINARY(31)); %INCLUDE LIB$GET_EF; %INCLUDE LIB$FREE_EF; %INCLUDE SYS$SETIMR; %INCLUDE SYS$WAITFR; %INCLUDE $STSDEF; DECLARE GETBINTIM ENTRY(CHAR(*)) /* character string time */ (1) RETURNS(BIT(64) ALIGNED); DECLARE EVENT_FLAG_NUM FIXED BIN(31); /* * Get an event flag to use. */ STS$VALUE = LIB$FREE_EF(EVENT_FLAG_NUM); (2) IF ^STS$SUCCESS THEN RETURN(STS$VALUE); /* * Set the timer for 10 seconds. */ STS$VALUE = SYS$SETIMR(EVENT_FLAG_NUM, GETBINTIM('0 00:00:10'),,); (3) IF ^STS$SUCCESS THEN RETURN(STS$VALUE); /* * Wait for the event flag, and display a * message when the timer completes. */ STS$VALUE = SYS$WAITFR(EVENT_FLAG_NUM); (4) IF ^STS$SUCCESS THEN RETURN(STS$VALUE); PUT SKIP LIST('Timer up!'); /* * Release the event flag. */ STS$VALUE = LIB$GET_EF(EVENT_FLAG_NUM); RETURN(STS$VALUE); END SET_TIMER; |
A Ctrl/c routine is a subroutine that is given control when the execution of the program is interrupted externally by the Ctrl/c function. To enable a Ctrl/c routine, you must code a call to the SYS$QIO (Queue I/O Request) system service, which performs I/O. In this call to SYS$QIO, you specify the name of an external procedure that will be executed when the interruption occurs. This type of procedure is called an asynchronous system trap (AST) routine because it may be executed at any time.
The sample programs in this section interact as follows:
The following notes are keyed to Example 11-7:
Example 11-7 Establishing a Ctrl/c Routine |
---|
SET_CTRLC: PROCEDURE RETURNS(FIXED BINARY(31)); %INCLUDE SYS$ASSIGN; (1) %INCLUDE SYS$QIO; %INCLUDE SYS$WAITFR; %INCLUDE $IODEF; (2) %INCLUDE $STSDEF; DECLARE TTCHAN FIXED BINARY(15); (3) DECLARE 1 IOSB, (4) 2 VALUE FIXED (15), /* Return status */ 2 NOT_USED(3) FIXED (15), C_AST ENTRY(POINTER); /* CTRL/C AST routine */ (5) DECLARE CNTRL_C_INTER STATIC BIT(1) ALIGNED GLOBALDEF, (6) IO_SUCCESS BIT(1) ALIGNED BASED(ADDR(IOSB.VALUE)); (7) DECLARE VALUE BUILTIN; /* * Call Assign I/O channel to get a terminal channel and then * call Queue I/O Request to enable the terminal for CTRL/C. */ STS$VALUE = SYS$ASSIGN ('TT',TTCHAN,,); (8) IF ^STS$SUCCESS THEN RETURN(STS$VALUE); STS$VALUE = SYS$QIO (1,TTCHAN, IO$_SETMODE|IO$M_CTRLCAST, /* function */ (9) IOSB, /* I/O status block */ ,, /* omit QIO AST argument */ VALUE(C_AST), /* AST routine for IO$_CTRLCAST */ ,,,,); /* unspecified p2 through p6 */ IF ^STS$SUCCESS THEN RETURN(STS$VALUE); STS$VALUE = SYS$WAITFR(1); IF ^IO_SUCCESS THEN RETURN(IOSB.VALUE); (10) CNTRL_C_INTER = '0'B; RETURN(1); END SET_CTRLC; |
The following description refers to Example 11-8.
Once a Ctrl/c handler has executed, it cannot be executed again unless the I/O request that establishes a handler is reexecuted. To keep a Ctrl/c handler active, it is common practice to reenable the Ctrl/c routine within the AST routine itself. The C_AST interrupt routine sets the CNTRL_C_INTER bit. When control is returned to the main routine, a Ctrl/c interrupt message is printed out. In addition, the Ctrl/c handler is reenabled by calling SET_CTRLC.
Example 11-8 Ctrl/c Handler |
---|
C_AST: PROCEDURE; DECLARE CNTRL_C_INTER STATIC BIT(1) ALIGNED GLOBALREF; CNTRL_C_INTER = '1'B; END C_AST; |
The procedure TESTC, in Example 11-9, tests the SET_CTRLC and C_AST routines. The techniques used here can be applied to any procedure in which you want to detect and respond to an external interrupt via Ctrl/c.
Example 11-9 Testing the Ctrl/c Routine |
---|
TESTC: PROCEDURE OPTIONS(MAIN) RETURNS(FIXED BIN(31)); /* * Field declarations for Return Status Values. */ %INCLUDE $STSDEF; DECLARE SET_CTRLC ENTRY RETURNS(FIXED BIN(31)); (1) DECLARE CNTRL_C_INTER BIT(1) GLOBALREF; %REPLACE TRUE BY '1'B; SIGNAL_INTER: PROCEDURE; (2) PUT SKIP LIST('Control/C interrupt'); STS$VALUE = SET_CTRLC(); /* reenable CTRL/C handler */ END; STS$VALUE = SET_CTRLC_(); (3) IF ^STS$SUCCESS THEN RETURN(STS$VALUE); DO WHILE (TRUE); (4) IF CNTRL_C_INTER THEN CALL SIGNAL_INTER; END; END TESTC; |
The following notes are keyed to Example 11-9:
Note that when this program is run, it can be interrupted at the
terminal and stopped only by the Ctrl/y function.
11.8.5 Obtaining Job/Process Information
The Get Job/Process Information (SYS$GETJPI) system service returns information about a specific aspect or attribute of a job that is currently being executed. A call to this service requires that you set up two buffers:
The procedure TIME, shown in Example 11-10, uses SYS$GETJPI to acquire performance statistics about the execution of a program. It has two entry points:
The statistics that are displayed represent the differences between the values acquired at the entry TIMRE and those acquired at the entry TIMRB.
The following notes are keyed to Example 11-10 and Example 11-11:
Example 11-10 Calling SYS$GETJPI (VAX) |
---|
TIME: PROCEDURE; %INCLUDE SYS$GETJPI; /* * INCLUDE definitions required by SYS$GETJPI */ %INCLUDE $JPIDEF; /* item codes */ (1) %INCLUDE $SSDEF; /* System (SS$_*) status values */ %INCLUDE $STSDEF; /* status value variable */ DECLARE 1 JPI_LIST STATIC EXTERNAL, (1) 2 JPI_BUFIO, /* Buffered I/O count */ 3 LENGTH FIXED BIN(15) INITIAL(4), 3 ITMCOD FIXED BIN(15) INITIAL(JPI$_BUFIO), (2) 3 BUFADR POINTER INITIAL(NULL()), 3 RETLEN POINTER INITIAL(NULL()), 2 JPI_CPUTIM, /* CPU time */ 3 LENGTH FIXED BIN(15) INITIAL(4), 3 ITMCOD FIXED BIN(15) INITIAL(JPI$_CPUTIM), (3) 3 BUFADR POINTER INITIAL(NULL()), 3 RETLEN POINTER INITIAL(NULL()), 2 JPI_DIRIO /* Direct I/O count */ 3 LENGTH FIXED BIN(15) INITIAL(4), 3 ITMCOD FIXED BIN(15) INITIAL(JPI$_DIRIO), (3) 3 BUFADR POINTER INITIAL(NULL()), 3 RETLEN POINTER INITIAL(NULL()), 2 JPI_PAGEFLTS /* Page faults */ 3 LENGTH FIXED BIN(15) INITIAL(4), 3 ITMCOD FIXED BIN(15) INITIAL(JPI$_PAGEFLTS), (3) 3 BUFADR POINTER INITIAL(NULL()), 3 RETLEN POINTER INITIAL(NULL()), 2 ENDLIST FIXED BIN(31) INITIAL(0); DECLARE (TO,CLOCK_TIME) FLOAT BIN(24) STATIC EXTERNAL, (4) (BUFIO,END_BUFIO,CPUTIM,END_CPUTIM,DIRIO, END_DIRIO,PAGEFLTS,END_PAGEFLTS) FIXED BIN(31) STATIC EXTERNAL, CPUSECONDS FLOAT BIN(24); DECLARE FOR$SECNDS ENTRY (FLOAT BIN(24)) RETURNS(FLOAT BIN(24)); TIMRE: ENTRY; JPI_BUFIO.BUFADR = ADDR(END_BUFIO); (5) JPI_CPUTIM.BUFADR = ADDR(END_CPUTIM); JPI_DIRIO.BUFADR = ADDR(END_DIRIO); JPI_PAGEFLTS.BUFADR = ADDR(END_PAGEFLTS); IF SYS$GETJPIW(,,,JPI_LIST,,,)^=SS$_NORMAL (6) THEN PUT SKIP LIST ('Error from SYS$GETJPI'); CLOCK_TIME = FOR$SECNDS(TO); CPUSECONDS = (END_CPUTIM-CPUTIM)/100E0; BUFIO = END_BUFIO-BUFIO; (7) DIRIO = END_DIRIO-DIRIO; PAGEFLTS = END_PAGEFLTS-PAGEFLTS; PUT SKIP EDIT ('Times in seconds','Page','Direct','Buffered') (A(20),A(10),A(10),A(10)); PUT SKIP EDIT ('CPU','Elapsed','Faults','I/O','I/O') (A(10),A(10),A(10),A(10),A(10)); PUT SKIP EDIT (CPUSECONDS,CLOCK_TIME,PAGEFLTS,DIRIO,BUFIO) (F(7,1),COLUMN(11),F(9,1),COLUMN(21),F(7,0),COLUMN(31), F(7,0),COLUMN(41),F(7,0)); /* * After calling TIMRE, fall through here to reinitialize. */ TIMRB: ENTRY; (8) TO = FOR$SECNDS(0E0); JPI_BUFIO.BUFADR = ADDR(BUFIO); (5) JPI_CPUTIM.BUFADR = ADDR(CPUTIM); JPI_DIRIO.BUFADR = ADDR(DIRIO); JPI_PAGEFLTS.BUFADR = ADDR(PAGEFLTS); IF SYS$GETJPIW(,,,JPI_LIST,,,)^=SS$_NORMAL THEN PUT SKIP LIST ('Error from SYS$GETJPI'); RETURN; END TIME; |
Previous | Next | Contents | Index |