PROGRAM MAILBOX_A IMPLICIT NONE C****************************************************************************** C*** C*** This program is an example of using mailboxes to comunicate between C*** two process. This program MAILBOX_A, creates two mailboxs. One for C*** read and one for write then spawns a subprocess MAILBOX_B, which opens C*** the two mailboxs. MAILBOX_A then writes two unformatted integers describing C*** the two dimensions of a real array to transfer. If either of the two integers C*** is zero, then MAILBOX_B closes the two mailboxes and exits. Then MAILBOX_B C*** closes and deletes the mailboxes and exits itself. However if the two C*** integers are non-zero, then the two-dimensional real array is transferred to C*** MAILBOX_B which then negates all elements and sends it back to MAILBOX_A. C*** C*** Author : Jeff Cameron C*** jcam90502@jcameron.com C*** http://www.jcameron.com/vms/ C*** C*** Modification history : C*** C*** Programmer Date Description C*** ---------------------------------------------------------------------- C*** Jeff Cameron 25-JAN-1989 Initially written C*** ---------------------------------------------------------------------- C*** C****************************************************************************** C C*** Constants INCLUDE '($SSDEF)' INCLUDE '($LIBDEF)' INTEGER*1 TEMPORARY PARAMETER (TEMPORARY = 0) INTEGER*4 NOWAIT PARAMETER (NOWAIT = 1) C C*** Common blocks C C*** Local declarations REAL*4 IN_ARRAY (100,100) REAL*4 OUT_ARRAY (100,100) INTEGER*4 ROWS,COLS INTEGER*4 I,J INTEGER*4 ERRORS C INTEGER*4 STATUS INTEGER*4 ATOB_CHAN, BTOA_CHAN INTEGER*4 A2B /11/, B2A /12/ ! Fortran LUNS for mailboxes INTEGER*4 PID, COMPLETION_STATUS, COUNT C C*** Externals INCLUDE '($SYSSRVNAM)' INTEGER*4 LIB$SPAWN EXTERNAL LIB$SPAWN C C*** Formats 1 FORMAT (A) C------------------------------------------------------------------------------ C C*** Begining of executable code. C*** First create the mailbox for transfer from A to B WRITE (6,1) ' >> Creating A to B mailbox.' STATUS = SYS$CREMBX (%VAL(TEMPORARY),ATOB_CHAN,,,,,'A_TO_B',) IF (.NOT. STATUS) CALL LIB$STOP (%VAL(STATUS)) C C*** Open the file for unformatted writes WRITE (6,1) ' >> Opening A to B mailbox.' OPEN (UNIT=A2B,FILE='A_TO_B',STATUS='NEW',FORM='UNFORMATTED',IOSTAT=STATUS) IF (STATUS .NE. 0) STOP 'OPEN ATOB' C C*** NOW CREATE the mailbox for transfer back from B to A WRITE (6,1) ' >> Creating B to A mailbox.' STATUS = SYS$CREMBX (%VAL(TEMPORARY),BTOA_CHAN,,,,,'B_TO_A',) IF (.NOT. STATUS) CALL LIB$STOP (%VAL(STATUS)) C C*** Now open file for unformatted reads WRITE (6,1) ' >> Opening B to A mailbox.' OPEN (UNIT=B2A,FILE='B_TO_A',STATUS='NEW',FORM='UNFORMATTED',IOSTAT=STATUS) IF (STATUS .NE. 0) STOP 'OPEN BTOA' C C*** Create the subprocess WRITE (6,1) ' >> Creating MAILBOX_B subprocess.' STATUS = LIB$SPAWN ('RUN MAILBOX_B.EXE',,,NOWAIT,'MBX B',PID,%VAL(%LOC(COMPLETION_STATUS)),,,,,,) IF (.NOT. STATUS) CALL LIB$STOP (%VAL(STATUS)) COMPLETION_STATUS = -1 C C*** GENERATE AND WRITE THE FIRST ARRAY ROWS = 50 COLS = 80 ERRORS = 0 C WRITE (6,1) ' >> Writing ROWS,COLS for pass 1.' WRITE (A2B) ROWS,COLS C WRITE (6,1) ' >> Sending pass 1 array.' DO J = 1,ROWS DO I = 1,COLS IN_ARRAY (I,J) = FLOAT (I - J) END DO WRITE (A2B) (IN_ARRAY(I,J),I=1,COLS) END DO C ERRORS = 0 C C*** READ and check THE RESPONSE WRITE (6,1) ' >> reading back pass 1 array.' DO J = 1,ROWS READ (B2A) (OUT_ARRAY(I,J),I=1,COLS) DO I = 1,COLS IF (OUT_ARRAY(I,J) .NE. (-1.0*IN_ARRAY(I,J))) ERRORS = ERRORS + 1 END DO END DO C WRITE (6,*) ' >> TOTAL ERRORS PASS 1 = ',ERRORS C CALL SUSPEND (0,0,5,0) C*** DO IT AGAIN ROWS = 100 COLS = 100 ERRORS = 0 C WRITE (6,1) ' >> Writing ROWS,COLS for pass 2.' WRITE (A2B) ROWS,COLS C WRITE (6,1) ' >> Sending pass 2 array.' DO J = 1,ROWS DO I = 1,COLS IN_ARRAY (I,J) = FLOAT (2*I - 2*J) END DO WRITE (A2B) (IN_ARRAY(I,J),I=1,COLS) END DO C ERRORS = 0 C C*** READ and check THE RESPONSE WRITE (6,1) ' >> reading back pass 2 array.' DO J = 1,ROWS READ (B2A) (OUT_ARRAY(I,J),I=1,COLS) DO I = 1,COLS IF (OUT_ARRAY(I,J) .NE. (-1.0*IN_ARRAY(I,J))) ERRORS = ERRORS + 1 END DO END DO C WRITE (6,*) ' TOTAL ERRORS PASS 2 = ',ERRORS C CALL SUSPEND (0,0,5,0) C*** TELL THE SUBPROCESS TO QUIT ROWS = 0 COLS = 0 WRITE (6,1) ' >> Telling MAILBOX_B subprocess to quit.' WRITE (A2B) ROWS,COLS C C*** WAIT UNTIL COMPLETION STATUS IS WRITTEN COUNT = 0 WRITE (6,1) ' >> Waiting for MAILBOX_B subprocess to quit.' DO WHILE (COMPLETION_STATUS .EQ. -1) CALL SUSPEND (0,0,1,0) COUNT = COUNT + 1 WRITE (6,1) ' >> Still Waiting.' IF (COUNT .GT. 10) STOP 'SUBPSTOP' END DO C C*** CLOSE THE FORTRAN MAILBOX FILES WRITE (6,1) ' >> Closing FORTRAN Mailbox files.' CLOSE (UNIT=A2B) CLOSE (UNIT=B2A) C C*** DELETE THE MAILBOXES WRITE (6,1) ' >> Deleting Mailboxs.' STATUS = SYS$DELMBX (ATOB_CHAN) STATUS = SYS$DELMBX (BTOA_CHAN) C C*** All done WRITE (6,1) ' >> ALL DONE!' CALL EXIT END SUBROUTINE SUSPEND (HOURS,MINUTES,SECONDS,TENTHS) INTEGER*4 HOURS, MINUTES, SECONDS, TENTHS C********************************************************************* C*** C*** THIS ROUTINE WILL SUSPEND THE PROGRAM FOR THE SPECIFIED TIME C*** C*** HOURS IS LIMITED FROM 0 TO 23 C*** MINUTES IS LIMITED FROM 0 TO 59 C*** SECONDS IS LIMITED FROM 0 TO 59 C*** TENTHS IS LIMITED FROM 0 TO 9 C*** C*** IF ALL PARAMETERS ARE 0, THEN THE ROUTINE WILL RETURN C*** IMMEDIATELY C*** C*** PARAMETERS : C*** C*** HOURS (I*4) NUMBER OF HOURS TO WAIT C*** C*** MINUTES (I*4) NUMBER OF MINUTES TO WAIT C*** C*** SECONDS (I*4) NUMBER OF SECONDS TO WAIT C*** C*** TENTHS (I*4) NUMBER OF TENTHS OF SECONDS TO WAIT C*** C******************************************************************** C*MCT INTEGER*4 H, M, S, T CHARACTER*16 ASCII_TIME INTEGER*4 BINARY_TIME(2) C INTEGER*4 SYS$BINTIM, SYS$SETIMR, SYS$WAITFR INTEGER*4 LIB$GET_EF INTEGER*4 FLAG C C*** LIMIT VALUES H = LIMIT (HOURS,0,23) M = LIMIT (MINUTES,0,59) S = LIMIT (SECONDS,0,59) T = LIMIT (TENTHS,0,9) C I = H + M + S + T IF (I .EQ. 0) RETURN C C*** ENCODE THE ASCII TIME ENCODE (16,10,ASCII_TIME) H, M, S, T 10 FORMAT ('0000 ',I2.2,':',I2.2,':',I2.2,'.',I1,'0') C C*** CONVERT TO SYSTEM BINARY TIME ISTAT = SYS$BINTIM (ASCII_TIME,BINARY_TIME) IF (.NOT. ISTAT) CALL SYS_SIGNAL (ISTAT) C C*** FIND OURSELF AN EVENT FLAG WE CAN USE CALL LIB$GET_EF (FLAG) IF (FLAG .EQ. -1) THEN C C*** NO EVENT FLAGS AVAILABLE, RETURN WITH NO DELAY RETURN ELSE ENDIF C C*** NOW SET THE TIMER ISTAT = SYS$SETIMR (%VAL(FLAG),BINARY_TIME,,) IF (.NOT. ISTAT) CALL SYS_SIGNAL (ISTAT) C C*** NOW SUSPEND OURSELF, AND WAIT FOR EVENT FLAG TO RAISE ISTAT = SYS$WAITFR (%VAL(FLAG)) IF (.NOT. ISTAT) CALL SYS_SIGNAL (ISTAT) C C*** FREE THE EVENT FLAG CALL LIB$FREE_EF (FLAG) C RETURN END SUBROUTINE SYS_SIGNAL (STATUS) INTEGER*4 STATUS C********************************************************************* C*** C*** This routine will take the status longword returned by a VMS C*** system service, or runtime library routine and report to the C*** SYS$OUTPUT device the error status. Since LIB$SIGNAL will C*** stop the image if the severity is fatal, this routine will C*** mask off the severity bit (bit 2) changing the error to a C*** warning. C*** C*** PARAMETER : C*** STATUS (I*4) VMS STATUS LONGWORD C*** C********************************************************************* C*MCT INTEGER*4 LOCAL_STATUS C C*** ONLY PROCESS IF THERE IS AN ERROR IF (.NOT. STATUS) THEN LOCAL_STATUS = STATUS IF (BJTEST(LOCAL_STATUS,2)) LOCAL_STATUS = LOCAL_STATUS - 4 CALL LIB$SIGNAL (%VAL(LOCAL_STATUS)) ELSE ENDIF C RETURN END INTEGER*4 FUNCTION LIMIT (VALUE,MINIMUM,MAXIMUM) ! SUBROUTINE LIMIT C SUBROUTINE LIMIT INTEGER*4 VALUE ! INPUT VALUE TO BE LIMITED INTEGER*4 MINIMUM ! LOWER LIMIT VALUE INTEGER*4 MAXIMUM ! UPPER LIMIT VALUE C************************************************************************ C*** C*** THIS FUNCTION WILL CLIP VALUE BETWEEN THE MINIMUM LIMIT AND C*** THE MAXIMUM LIMIT. C*** C*** PARAMETERS : C*** C*** VALUE (I*4) INPUT VALUE TO BE LIMITED C*** C*** MINIMUM (I*4) LOWWER LIMIT VALUE C*** C*** MAXIMUM (I*4) UPPER LIMIT VALUE C*** C************************************************************************ C*MCT IF (VALUE .GT. MAXIMUM) THEN LIMIT = MAXIMUM C ELSE IF (VALUE .LT. MINIMUM) THEN LIMIT = MINIMUM C ELSE LIMIT = VALUE ENDIF RETURN END