From:	CRDGW2::CRDGW2::MRGATE::"SMTP::CRVAX.SRI.COM::RELAY-INFO-VAX" 27-JUN-1989 14:13
To:	MRGATE::"ARISIA::EVERHART"
Subj:	Re: Obviously, I'm doing something wrong:  Help w/ AST's please.

From: RELAY-INFO-VAX@CRVAX.SRI.COM
Message-Id:  <8906271757.AA21149@crdgw1.ge.com>
Received: From KL.SRI.COM by CRVAX.SRI.COM with TCP; Tue, 27 JUN 89 09:46:34 PDT
Received: from nscvax.princeton.edu ([128.112.6.9]) by KL.SRI.COM with TCP; Tue, 27 Jun 89 09:32:09 PDT
Date: 27 Jun 1989 09:35:45 EST
Sender: dragon@nscvax.princeton.edu
Reply-To: dragon@NSCVAX.PRINCETON.EDU
To: info-vax@KL.SRI.COM
Subject: Re: Obviously, I'm doing something wrong:  Help w/ AST's please.

Kevin Cole <CADS_COLE%GALLUA.BITNET@CORNELLC.cit.cornell.edu> writes:
>
>A while back, I asked some questions about passing information between two
>processes.  Since then, I've learned just enough about MACRO and Systems
>Services to be dangerous.  However, I still ended up writing my toy in FORTRAN.
>The thing is supposed to update a status line at the bottom of my screen every
>30 seconds.  The information therein consists of the current directory of the
>parent process (as revealed through a job logical called CURDIR), the date and
>the time.  It's also supposed receive messages via a mailbox and jump to a
>handler which displays the message passed to it.
>
>Unfortunately, when I added the mailbox and AST stuff, I managed to break the
>part that handles the display of the current directory.  So I can get either/or
>but not both.  I suspect that the answer to my troubles is fairly obvious to
>someone well-versed in this stuff.
>
>The programs CLOCK.FOR and SET.FOR follow.  The "D" lines (QIO) in CLOCK seem
>to be where I'm going wrong.  I think I need a simpler explaination of how to
>set up QIO's.
>------------------------------------------------------------------------------
>
>!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
>!                                                                       !
>!               *** CLOCK ***   Written by Kevin Cole   20-Jun-89       !
>!                                                                       !
>!     This program is meant to be spawned in a subprocess.  The cursor  !
>!  position and attributes are saved, the video is set to reverse-dim,  !
>!  and the cursor is moved by direct address command to the appropriate !
>!  screen location to print the date and time.  Then the video is set   !
>!  back to normal and the cursor position and attributes are restored.  !
>!                                                                       !
>!     Work is currently being done to implement a mailbox for receipt   !
>! of alarm/appointment messages and system/user messages...             !
>!                                                                       !
>!  The magic command is:  $ SPAWN/NOWAIT/INPUT=NL: RUN CLOCK   (KJC)    !
>!                                                                       !
>!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
>
>        PROGRAM CLOCK
>        INCLUDE '($IODEF)'              ! I/O masks, etc.
>        INCLUDE '($SSDEF)'              ! System Service Status Codes
>        INCLUDE '($SYSSRVNAM)'          ! Actual System Service names
>
>        EXTERNAL  MBXAST
>
>        CHARACTER BUFF*80,CURDIR*60
>        CHARACTER ESC*1,RECALL*2,HILITE*10,ALARM*10,MESSAG*10
>        CHARACTER NORMAL*4,BOTTOM*7,SAVE*2,BEL*1,MONTH(12)*3
>        INTEGER*4 ITIME(2),INITIAL(2),CDLEN,STATUS,IOSB
The first problem is here ------------------------> ^^^^

The IOSB is a eight byte control block.  For convenience in addressing the
various fields, many of which are sixteen bits, it is customary to declare
this as INTEGER*2 IOSB(4)

The effect of this error will be that the first four bytes of the IOSB will
be stored at IOSB, and the next four bytes will be stored at the address of
IOSB, +4 which is the address of some other variable.

>        INTEGER*2 NTIM(7),CHANL
>
>        COMMON  BUFF,RECALL,HILITE,ALARM,MESSAG,NORMAL,BOTTOM
>        COMMON  SAVE,NTIM,MONTH
>
>        PARAMETER (ESC = CHAR(27))
>        PARAMETER (BEL = CHAR(07))
>
>        DATA MONTH /'Jan','Feb','Mar','Apr','May','Jun',
>     *              'Jul','Aug','Sep','Oct','Nov','Dec'/
>
>        ITIME(1) = -1E7 * 30            ! 30 seconds
>        ITIME(2) =  -1
>
>        SAVE   = ESC//'7'               ! Save current cursor attributes
>        HILITE = ESC//'[0;30;41m'       ! Turn on  reverse video (black on red)
>        ALARM  = ESC//'[1;33;44m'       ! Alarm colors (Bright yellow on blue)
>        MESSAG = ESC//'[1;31;44m'       ! Message colors (Bright red on blue)
>        BOTTOM = ESC//'[25;1H'          ! Move cursor to lower left  corner
>        NORMAL = ESC//'[0m'             ! Turn off reverse video
>        RECALL = ESC//'8'               ! Restore former cursor attributes
>
>        STATUS = SYS$CREMBX (,CHANL,,,,,'CLOKBOX')
>        IF (.NOT. STATUS) CALL LIB$STOP (%VAL(STATUS))  ! Give error
>D       STATUS = SYS$QIO (%VAL(1),
>D    *                    %VAL(CHANL),
>D    *                    %VAL(IO$_READVBLK),
>D    *                    IOSB,
>D    *                    MBXAST,,
>D    *                    %REF(BUFF),

The %REF is correct but not required.  Fortran uses pass by reference as
the default.

>D    *                    %VAL(60),,,,)
>D       IF (.NOT. STATUS) CALL LIB$STOP (%VAL(STATUS))  ! Give error
>
>        CALL SYS$NUMTIM (NTIM,)
>        INITIAL(1) = (MOD (ZEXT (NTIM(6)*100 + NTIM(7)), 3000) - 3000) * 1E5
>        INITIAL(2) = -1
>        CALL SYS$SCHDWK (,,INITIAL,ITIME)
>        DO WHILE (.TRUE.)
>          CALL SYS$HIBER                ! Sleep for ITIME seconds
>          CALL SYS$NUMTIM (NTIM,)       ! Get current time as a number
>          NTIM(1) = MOD(NTIM(1),100)    ! Convert to two digit year
>!         STATUS = SYS$TRNLOG ('CURDIR',CDLEN,CURDIR,,,)        ! Doesn't pad
>!         IF (.NOT. STATUS) CALL LIB$STOP (%VAL(STATUS))        ! Give error
>          CALL LIB$SYS_TRNLOG ('CURDIR',CDLEN,CURDIR)           ! Pads w/ spaces
>          TYPE 30,SAVE,HILITE,BOTTOM,CURDIR,
>     *            NTIM(3),MONTH(NTIM(2)),NTIM(1),NTIM(4),NTIM(5),NTIM(6),
>     *            NORMAL,RECALL
>30        FORMAT ('+',A2,A10,A7,1X,A60,
>     *            I2.2,'-',A3,'-',I2.2,1X,I2.2,':',I2.2,':',I2.2,1X,A4,A2,$)
>        END DO
>
>        STOP
>        END
>!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
>!                                                                       !
>!       *** MBXAST ***          Written by Kevin Cole   21-Jun-89       !
>!                                                                       !
>!   This is supposed to be the Asynchronous Systems Trap (AST) handler  !
>! for any Queued I/O (QIO's) that occur for the mailbox opened above.   !
>! Currently, if it receives a message from the SET program, it's        !
>! supposed to ring the bell twice, change the colors to yellow on blue  !
>! and display the message, date and time instead of current directory,  !
>! date and time.                                                        !
>!                                                                       !
>!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
>
>        SUBROUTINE MBXAST
>        IMPLICIT INTEGER (A-Z)
>
>        CHARACTER BUFF*80,RING*1
>        CHARACTER RECALL*2,HILITE*10,ALARM*10,MESSAG*10
>        CHARACTER NORMAL*4,BOTTOM*7,SAVE*2,MONTH(12)*3
>        INTEGER*2 NTIM(7)
>
>        COMMON  BUFF,RECALL,HILITE,ALARM,MESSAG,NORMAL,BOTTOM
>        COMMON  SAVE,NTIM,MONTH
>
>        RING = CHAR(07)
>
>        TYPE 30,RING,RING,
>     *          SAVE,ALARM,BOTTOM,BUFF,
>     *          NTIM(3),MONTH(NTIM(2)),NTIM(1),NTIM(4),NTIM(5),NTIM(6),
>     *          NORMAL,RECALL
>30      FORMAT ('+',2A1,A2,A10,A7,1X,A60,
>     *          I2.2,'-',A3,'-',I2.2,1X,I2.2,':',I2.2,':',I2.2,1X,A4,A2,$)
>
>        RETURN
>        END
>------------------------------------------------------------------------------
>!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
>!                                                                       !
>!              *** SET ***      Written by Kevin Cole   21-Jun-89       !
>!                                                                       !
>!     This program is meant to talk to a subprocess named CLOCK.  The   !
>! idea is that this will send an alarm message to the other guy's       !
>! mailbox...  We'll see what happens.                                   !
>!                                                                       !
>!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
>
>        PROGRAM SET
>        INCLUDE '($IODEF)'              ! I/O masks, etc.
>        INCLUDE '($SSDEF)'              ! System Service Status Codes
>        INCLUDE '($SYSSRVNAM)'          ! Actual System Service names
>
>        CHARACTER BUFF*60
>        CHARACTER ESC*1,RECALL*2,HILITE*10,ALARM*10,MESSAG*10
>        CHARACTER NORMAL*4,BOTTOM*7,SAVE*2,BEL*1
>        INTEGER*4 ITIME(2),INITIAL(2),BLEN,STATUS
>        INTEGER*2 NTIM(7),CHANL
>
>        STATUS = SYS$ASSIGN ('CLOKBOX',CHANL,,)
>        IF (.NOT. STATUS) CALL LIB$STOP (%VAL(STATUS))  ! Give error
>        TYPE 10
>10      FORMAT (' Enter message to be displayed (60 chars max):')
>        ACCEPT 20,BLEN,BUFF
>20      FORMAT (Q,A)
>        STATUS = SYS$QIO (%VAL(1),
>     *                    %VAL(CHANL),
>     *                    %VAL(IO$_WRITEVBLK.OR.IO$M_NOW),
>     *                    IOSB,,,
IOSB is not declared at all here.  See my previous comments.
>     *                    %REF(BUFF),
>     *                    %VAL(60),,,,)
>        IF (.NOT. STATUS) CALL LIB$STOP (%VAL(STATUS))  ! Give error
>
>        STOP
>        END

     Another, potential, problem is that the IOSB is not checked for
successful completion of the I/O requests.  The return status only tells you
whether or not the I/O request was successfully queued.  The request could
fail for a number of reasons and your program would never know it.  I would
suggest inserting the following line at a point where you know the request
has completed:
	IF(.NOT. IOSB(1)) CALL LIB$SIGNAL(%VAL(IOSB(1))
If you, then, find that you occasionally get a certain specific error, you
can add code to recover, if recovery is possible.

   There may be still more errors but the IOSB problem is enough to do
you in.

************************************************************************
*                                                                      *
*                      Here, there be dragons!                         *
*                                                                      *
************************************************************************


