; ; This software is COPYRIGHT © 1989-1994, Stephane Germain. ALL RIGHTS RESERVED. ; Permission is granted for not-for-profit redistribution, provided all source ; and object code remain unchanged from the original distribution, and that all ; copyright notices remain intact. ; ; This software is provided "AS IS". The author makes no representations or ; warranties with respect to the software and specifically disclaim any implied ; warranties of merchantability or fitness for any particular purpose. ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; This is SYS_PROBE:PROBE.MAR ; Creator S.Germain p.eng ; Using VAX/VMS 5.1-5.4/5.5 ; History V0.1 19 Sep 89 - concept prototype test : development start ; V1.0 24 Nov 89 - barebone control + monitoring + display ; V2.0 4 May 91 - new image functionality breakdown (3 processes) ; - completely rewritten for increased modularity ; - full set-up function, table/filter loading... diag ; V2.1 20 Feb 94 - updated /DISPLAY ; - added EZA0 to default device list ; V2.1B 16 Nov 94 - updated /STATISTICS & /RECORD for OUTPUT syntax ; V2.2 Dec 94 - removed LOAD_FILTER _notice flag set (DMS implicit) ; updated diagnostic section for logger.data size ; moved DISPLAY.interval processing to LOAD_DISPLAY ; modified keyboard AST routine for H,I,A-F inputs ; modified TABLE.protocol input for hexadecimal ; modified FILTER.node to keep count of active nodes ; ;; CONCEPT ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; This image sets-up, controls and terminates a set of processes performing ; Ethernet monitoring, logging, accounting and display functions. The images ; ACQ and DMS are invoked/spawned by this image. Handshaking is achieved via ; global sections and common event flags. Outputs are a function of ACQ (the ; acquisition/logging image) and DMS (the display manager/statistician image). ; All three images are designed to operate in real-time using asynchronous ; or timed/burst event awakening, thereby permitting timesharing operations ; inasmuch as actual network (load) processing will allow. This design uses ; interlocks to make the application suitable for multiprocessor systems. ; However, by the (promiscuous) nature of its network interface, only one ; "probe" can operate on a given adapter (system) at a time. Playback of ; previously recorded data is performed by the REPLAY image, a distinct ; entity which does not have specific privilege or concurrency limitations. ; ;; NOTES ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; 1. Conditions are signaled according to VAX/VMS standards. Image rundown is ; forced prior to signaling while at real-time level. Assembling and linking ; is done as follows: ; ; $ MACRO/NODEBUG PROBE ; $ MESSAGE/OBJECT=MSG PROBE ! message file PROBE.MSG ; $ SET COMMAND/OBJECT=TBL TABLE ! table command file TABLE.CLD ; $ LINK/NODEBUG/NOTRACEBACK PROBE,MSG,TBL ; ; 2. Invocation and run-time information parsing is performed by CLI routines. ; The command definition in file PROBE.CLD is included in the process command ; table as follows: ; ; $ SET COMMAND PROBE ! invocation via "PROBE" ; ; 3. User help information is contained in the library PROBE.HLB. ; ; 4. In order for this application to run, the process must have the PSWAPM, ; ALTPRI and PHY_IO privileges or the image must be installed (NON-SHAREABLE) ; with those privileges. ; ; 5. Because of the CPU involvement in processing every Ethernet packet, it is ; likely that performance will noticeably drop for timeshared processes while ; this program is recording/displaying data. Avoid using the network for either ; function (i.e. filing to a remote node or displaying to a LAT terminal) as ; this would skew statistics for the associated nodes. ; ;; CONSTANTS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; .TITLE PROBE ETHERNET TRAFFIC MONITORING .IDENT /2.2/ ; .LIBRARY "SYS$LIBRARY:LIB.MLB" ; alternate system macro library .LIBRARY "SYS_PROBE:PROBELIB" ; application macro library $IODEF ; $LNMDEF ; $PRCDEF ; $PRVDEF ; $PSLDEF ; $SECDEF ; $SMGDEF ; V22$GBLDEF ; global constants definitions V22$CTLDEF ; control section definitions V22$BUFDEF ; buffer entry & section definitions ; .PSECT FIXDATA,NOEXE,NOWRT,NOSHR,LONG ; ; command table label names (see CLD files) ; D_ADAPTER: .ASCID /PRB_ADAP/ D_DISPLAY: .ASCID /PRB_DISP/ D_FILTER: .ASCID /PRB_FILT/ D_RECORD: .ASCID /PRB_RECD/ D_SCHEDULE: .ASCID /PRB_SCHD/ D_STATISTICS: .ASCID /PRB_STAT/ D_TABLE: .ASCID /PRB_TABL/ D_CD: .ASCID /PRB_XCOL/ ; special : preset collision factor D_DMP: .ASCID /PRB_XDMP/ ; special : diagnostic dump D_050SCALE: .ASCID /SCAL_050/ D_100SCALE: .ASCID /SCAL_100/ D_LOGSCALE: .ASCID /SCAL_LOG/ D_PEAK: .ASCID /DISP_PEK/ D_REFRESH: .ASCID /DISP_INT/ D_SMOOTH: .ASCID /DISP_SMT/ D_THRESHOLD: .ASCID /DISP_THR/ D_802_3: .ASCID /FRMT_802/ D_ETHERNET: .ASCID /FRMT_ETH/ D_DESTINATION: .ASCID /FILT_DST/ D_FORMAT: .ASCID /FILT_FMT/ D_MULTICAST: .ASCID /FILT_MLT/ D_NODE: .ASCID /FILT_NOD/ D_PROTOCOL: .ASCID /FILT_PTL/ D_SOURCE: .ASCID /FILT_SRC/ D_SAMPLE: .ASCID /RECD_OUT/ D_DATA: .ASCID /RECD_DAT/ D_ACTIVE: .ASCID /SCHD_ACT/ D_CYCLE: .ASCID /SCHD_CYC/ D_STANDBY: .ASCID /SCHD_STB/ D_RESULT: .ASCID /STAT_OUT/ D_PTCL_IDN: .ASCID /PTCL_IDN/ D_PTCL_NAM: .ASCID /PTCL_NAM/ D_PTCL_VAL: .ASCID /PTCL_VAL/ D_NODE_ADR: .ASCID /NODE_ADR/ D_NODE_DST: .ASCID /NODE_DST/ D_NODE_NAM: .ASCID /NODE_NAM/ D_NODE_SRC: .ASCID /NODE_SRC/ D_NODE_DSTDIS: .ASCID /NODE_DST.NODE_DIS/ D_NODE_DSTPRI: .ASCID /NODE_DST.NODE_PRI/ D_NODE_DSTSMT: .ASCID /NODE_DST.NODE_BYP.NBYP_SMT/ D_NODE_DSTTHR: .ASCID /NODE_DST.NODE_BYP.NBYP_THR/ D_NODE_SRCDIS: .ASCID /NODE_SRC.NODE_DIS/ D_NODE_SRCPRI: .ASCID /NODE_SRC.NODE_PRI/ D_NODE_SRCSMT: .ASCID /NODE_SRC.NODE_BYP.NBYP_SMT/ D_NODE_SRCTHR: .ASCID /NODE_SRC.NODE_BYP.NBYP_THR/ ; ; Standard Ethernet adapter names (template devices) and search list ; .ALIGN LONG D_ETH0: .ASCID /ETHERNET/ ; user defined logical device precedence D_ETH1: .ASCID /ESA0/ ; inbedded adapter (Vaxstations...) D_ETH2: .ASCID /ETA0/ ; BI adapter (DEBNA,DEBNI) D_ETH3: .ASCID /EXA0/ ; XMI adapter (DEMNA) D_ETH4: .ASCID /EZA0/ ; SGEC adapter (DSSI, new VaxStations) D_ETH5: .ASCID /XQA0/ ; Qbus adapter (DEQNA,DELQA) D_ETH6: .ASCID /XEA0/ ; Unibus adapter (DELUA) ; AL_ETH: .ADDRESS D_ETH0 ; user default device pointer .ADDRESS D_ETH1 ; default device #1 pointer .ADDRESS D_ETH2 ; default device #2 pointer .ADDRESS D_ETH3 ; default device #3 pointer .ADDRESS D_ETH4 ; default device #4 pointer .ADDRESS D_ETH5 ; default device #5 pointer .ADDRESS D_ETH6 ; default device #6 pointer .LONG 0 ; end of default device list ; ; Multicast (generic) "node" name (default table loading - element 0) ; D_MLTCAST: .ASCID / / D_UNMATCHED: .ASCID / / ; ; VMS standard input/output logical devices ; D_LNMTAB: .ASCID /LNM$FILE_DEV/ D_INPUT: .ASCID /SYS$INPUT/ D_OUTPUT: .ASCID /SYS$OUTPUT/ ; ; Probe-specific logical names & descripted values ; D_PARTNER: .ASCID /PROBE_MIRROR/ ; network partner object name (V3.0) D_DMSIMAGE: .ASCID /SYS_PROBE:DMS/ ; image name D_DMSNAME: .ASCID /PROBE_DMS/ ; subprocess name D_ACQIMAGE: .ASCID /SYS_PROBE:ACQ/ ; image name D_ACQNAME: .ASCID /PROBE_ACQ/ ; subprocess name D_BASETIME: .ASCID /0 0:0:30/ ; 30 seconds base timeout (ASCII format) ; .ALIGN LONG S_HEXA: .ASCII /FEDCBA9876543210/ ; valid hexadecimal numerals W_EXITMASK: .WORD ^X201A ; ASCII for 'space' & 'CTRL/Z' W_FMTMASK: .WORD ^A/HI/ ; ASCII for 'H' & 'I' W_MLTMASK: .WORD ^A/M./ ; ASCII for 'M' & '.' S_PROMPT: .WORD ^X0D0A ; carriage control on RMS prompt .ASCII /Table> / ; RMS terminal table prompt promsiz = .-S_PROMPT ; size of RMS prompt string ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; .PSECT FILEDATA,NOEXE,WRT,NOSHR,LONG ; T_FILE: $FAB DNM=<.TBL>, - ; default file type FAC= ; read-only access T_REC: $RAB FAB=T_FILE, - ; input record PBF=S_PROMPT, - ; prompt string address for terminal PSZ=PROMSIZ, - ; prompt string size ROP=, - ; use prompt for terminal inputs USZ=GK_VALSIZE_MAX ; maximum record size T_DFILE: $FAB FNM=,- ; diagnostic file name FAC=,- ; write-only access RAT=,- ; carriage control is CR RFM= ; stream file (CRLF) T_DREC: $RAB FAB=T_DFILE ; pointer to file record access block ; D_DIA01: .ASCID \PROBE DIAGNOSTIC DUMP!_!_@ !%D!_(!XL)!/!/\ ; 2 D_DIA02: .ASCID \!_PID:!_!XL!_IPrio:!_!8!_Status: !XL!/\ - \!_ICSR:!_!XL!_ICtrl:!_!XL!/\ - \!_XCSR:!_!XL!_XEFS:!_!XL!/\ ; 7 D_DIA03: .ASCID \__ACQ__ PID:!_!XL!/\ - \!_Status: !XL!_VMS:!_!XL!_Ext:!_!XL!/\ - \!_Host:!_!8AD!_Device: !8AD!_IOs:!_!10!/\ - \!_CDmin:!_!10!_CDmax:!_!10\ - \!_CDRpt:!_!10!/\ - \!_Data:!_!4!/\ ; 13 D_DIA04: .ASCID \__DMS__ PID:!_!XL!/\ - \!_Status: !XL!_VMS:!_!XL!_Ext:!_!XL!/\ - \!_Lines:!_!8!_Dev1:!_!XL!_Dev2:!_!XL!/\ - \!_Refrsh: !8!_Smooth: !8\ - \!_Thresh: !8!/\ ; 10 D_DIA05: .ASCID \__BUF__ Flags:!_!XW!/\ - \Queue>!_Passes: !10!_Time:!_!10!/\ - \Depth>!_Min:!_!10!_Max:!_!10\ - \!_Ave:!_!10!/\ - \Orphan> Item:!_!10!_Free:!_!10\ - \!_Drop:!_!10!/\ ; 9 D_DIA06: .ASCID \__CTL__ Flags:!_!XL\ - \!_DefP:!_!XW!_!_ActP:!_!XW!/\ - \Cycle>!_Count:!_!UL/!7\ - \!_ActT:!_!10!_StbT:!_!10!/\ - \Frame>!_Count:!_!10\ - \!_Eth:!_!10!_IEEE:!_!10!/\ - \Mltcst>!_Count:!_!10\ - \!_Eth:!_!10!_IEEE:!_!10!/\ - \Byte>!_Count:!_!10\ - \!_Eth:!_!10!_IEEE:!_!10!/\ - \Filter>!_Byte:!_!10!_Eth:!_!10\ - \!_IEEE:!_!10!/!_Ptcl:!_!10\ - \!_Mltcst: !10!/\ ; 21 D_DIA07: .ASCID \Size>!_Min:!_!10!_Max:!_!10\ - \!_Ave:!_!10!/\ - \!_Eth:!_!10!_Eth:!_!10!/\ - \!_IEEE:!_!10!_IEEE:!_!10!/\ - \Rate>!_Min:!_!10!_Max:!_!10!/\ - \Load>!_Min:!_!10!_Max:!_!10\ ; 11 D_NULL: .ASCID \ \ D_PTAG: .ASCID \Ptcl>\ D_NTAG: .ASCID \Node>!_Flags:!_!XW\ - \!_!_Count:!_!UL/!7!_Fail:!_!10\ ; 4 D_HTAG: .ASCID \Hash>!_Flags:!_!XW\ ; 1 D_DIA_P: .ASCID \!AS!_!/\ - \!_Name:!_!12AD!_Value:!_!XW!/\ - \!_Count:!_!10!_Mltcst: !10\ - \!_Byte:!_!10!/\ - \!_MinSz:!_!10!_MaxSz:!_!10\ ; 10 D_DIA_N: .ASCID \!_!_!_!_Flags:!_!XW!_!_HitP:!_!XL!/\ - \!_Name:!_!12AD!_Addr:!_!XW!XL!/\ - \!_NextN:!_!10!_NextH:!_!UL!/\ - \!_SMinSz: !10!_DMinSz: !10!/\ - \!_SMaxSz: !10!_DMaxSz: !10!/\ - \!_SFrm:!_!10!_DFrm:!_!10!/\ - \!_SByte:!_!10!_Dbyte:!_!10!/\ - \!_SIFrm:!_!10!_DIFrm:!_!10!/\ - \!_SIByte: !10!_DIByte: !10\ ; 21 D_DIA_H: .ASCID \!_!_!UW!_!_!UW\ - \!_!_!UW!_!_!UW\ ; 8 ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; .PSECT WORKDATA,NOEXE,WRT,NOSHR,LONG ; AL_CTL: .LONG 0 ; control section start address .LONG 0 ; control section end address AL_BUF: .LONG 0 ; buffer section start address .LONG 0 ; buffer section end address AL_CODE: .ADDRESS PROBE ; program low address .ADDRESS QUIT ; program high address AL_EXIT: .LONG 0 ; (VMS reserved usage) forward link .ADDRESS SHUTDOWN ; exit handler address .LONG 1 ; number of arguments .ADDRESS L_VMSSTATUS ; argument # 1 (VMS filled status) AL_EXIT2: .LONG 0 ; (VMS reserved usage) forward link .ADDRESS RESET ; exit handler address .LONG 1 ; number of arguments .ADDRESS L_VMSSTATUS ; argument # 1 (VMS filled status) Q_NEWPRIV: .QUAD ; alter priority Q_KEYIOSB: .QUAD 0 ; keyboard input I/O status block Q_CRTIOSB: .QUAD 0 ; screen output I/O status block Q_BASETIME: .QUAD 0 ; initial & terminal timeout deltatime Q_SYNCTIME: .QUAD 0 ; subprocesses synchronization timeout Q_STANDBY: .QUAD 0 ; standby binary deltatime value Q_ACTIVE: .QUAD 0 ; activity binary deltatime value L_KEYBUFFER: .LONG 07 ; keyboard input storage (1 byte used) L_CRTBUFFER: .LONG 07 ; single ASCII bell character L_VMSSTATUS: .LONG 0 ; VMS-written exit status (exit handler) L_DEVICE_ID: .LONG 0 ; SMG returned pasteboard (inherent use) L_EFSTATE: .LONG 0 ; event flag cluster state L_ICSR: .LONG -1 ; initial control & status mask (diag) L_ICTRL: .LONG -1 ; initial control trapping mask L_IPRIO: .LONG -1 ; initial scheduling priority value L_XEFSTATE: .LONG 0 ; exit common event flag state (diag) L_XCSR: .LONG 0 ; exit control & status mask (diag) ; keyfunc = crtfunc = outfunc = ; AL_KEY: $QIO - ; untimed unterminated input arguments astadr=KEYBOARD,- ; >action routine address (no parameter) func= KEYFUNC,- ; >uppercase converted read with no echo iosb= Q_KEYIOSB,- ; >status block address chan= 0,- ; >program filled :input channel p1= L_KEYBUFFER,- ; >input buffer address p2= 1 ; >treat characters individually AL_CRT: $QIO - ; async single bell output arguments func= CRTFUNC,- ; >uninterpreted control write iosb= Q_CRTIOSB,- ; >status block address chan= 0,- ; >program filled :output channel p1= L_CRTBUFFER,- ; >output buffer address p2= 1 ; >single control (ASCII bell) character AL_OUT: $QIO - ; async message line output arguments func= OUTFUNC,- ; >standard control write iosb= Q_CRTIOSB,- ; >status block address chan= 0,- ; >program filled :output channel p1= 0,- ; >program filled :output buffer address p2= 0,- ; >program filled :output buffer size p4= 32 ; >single space fortran carriage control AL_TEXT: $FAO - ; parameter merging arguments ctrstr=D_WORK,- ; >control string address outlen=D_TEXT,- ; >resulting length address outbuf=D_TEXT,- ; >resulting string descriptor p1= 0 ; >program filled :parameter value AL_MSG: $GETMSG - ; message arguments msgid= 0,- ; >program filled :message code msglen=D_WORK,- ; >resulting length address bufadr=D_WORK ; >resulting string descriptor ; S_TEXT: .BLKB GK_VALSIZE_MAX ; string storage for FAO conversion S_WORK: .BLKB GK_VALSIZE_MAX ; string storage for MSG recovery S_TT: .BLKB GK_LOGICAL_MAX ; string storage for default terminal D_TEXT: .LONG GK_VALSIZE_MAX ; descriptor for FAO .ADDRESS S_TEXT ; D_WORK: .LONG GK_VALSIZE_MAX ; descriptor for MSG .ADDRESS S_WORK ; D_TT: .LONG GK_LOGICAL_MAX ; descriptor for TRNLNM .ADDRESS S_TT ; ; ;; MAIN PROGRAM ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; .PSECT CODE,EXE,NOWRT,NOSHR ; .ENTRY PROBE,^M<> ; entry point, no registers saved ; integer overflow trap is disabled callid = 0 ; initial call id (assembly variable) ; ; Boost & test privileges, ready interprocess flags, lockdown code in memory ; $setprv_s - ; update (temporary) process privileges prvadr=Q_NEWPRIV, - ; >address of new privileges mask enbflg=#1 ; >enable masked privileges blbs R0,PRV_OK ; check successful completion, else... stop message=#PRB_NOPRIV, - ; drop out with signal reason =R0 ; >second message parameter PRV_OK: $ascefc_s - ; associate common event flag cluster name= GS_CEFNAME, - ; >event flag cluster name efn= #GK_BASE, - ; >temporary event flag cluster id prot= #1 ; >access granted to creator UIC only blbs R0,IPC_OK ; upon incorrect status stop message=#PRB_NOIPC, - ; drop out with signal reason =R0 ; >second message parameter IPC_OK: $lckpag_s - ; code lockdown inadr= AL_CODE, - ; >code boundary array acmode=#PSL$C_USER ; >user access mode (3) blbs R0,C_MAP ; check status signal message=R0 ; ... inform user of problem C_MAP: ; ; Create & map CONTROL and BUFFER global sections, lock them down in memory. ; (Pages are initialized to zero, first-fit in virtual space, writable and ; allocated from pagefile) ; gsmask = ; $crmpsc_s - ; create and map Control global section inadr= AL_CTL,- ; >proposed virtual address array (P0) retadr=AL_CTL,- ; >actual virtual address array gsdnam=GS_CTL_NAME,- ; >global section name ident= GQ_CTL_IDENT,- ; >version identification acmode=#PSL$C_USER,- ; >user access mode (3) pagcnt=#GX_CTLPAGESIZE,-; >page count - predefined by macro prot= #<^XFFFFF888>,- ; >protection (S:RWE,O:RWE,G:RWE,W) flags= #GSMASK ; >creation attribute mask blbs R0,C_LOCK ; check status alert status=R0 ; drop out and signal internal problem C_LOCK: $lckpag_s - ; lock global pages in memory inadr= AL_CTL, - ; >actual virtual address array acmode=#PSL$C_USER ; >user access mode (3) blbs R0,B_MAP ; check status signal message=R0 ; ... inform user of problem B_MAP: $crmpsc_s - ; create and map Buffer global section inadr= AL_BUF,- ; >proposed virtual address array (P0) retadr=AL_BUF,- ; >actual virtual address array gsdnam=GS_BUF_NAME,- ; >global section name ident= GQ_BUF_IDENT,- ; >version identification acmode=#PSL$C_USER,- ; >user access mode (3) pagcnt=#GX_BUFPAGESIZE,-; >page count - predefined by macro prot= #<^XFFFFF888>,- ; >protection (S:RWE,O:RWE,G:RWE,W) flags= #GSMASK ; >creation attribute mask blbs R0,B_LOCK ; check status alert status=R0 ; drop out and signal internal problem B_LOCK: $lckpag_s - ; lock global pages in memory inadr= AL_BUF, - ; >actual virtual address array acmode=#PSL$C_USER ; >user access mode (3) blbs R0,I_QUE ; check status signal message=R0 ; ... inform user of problem I_QUE: movl AL_CTL,R11 ; load control section starting address movl AL_BUF,R10 ; load buffer section starting address movw #GK_ETH,GW_EQMIN(R10) ;*DIAG*reverse bias low Q size marker ; ; Initialize buffer free queue (allocate slots within global section) ; movab GAE_E_SLOT(R10),R9 ; load address of first ethernet item movl #GK_ETH,R8 ; load item count Q_FREE: insqti (R9),GAL_EQFREE(R10) ; update queue pointers bcc Q_OK ; if insertion error occured stop message=#PRB_QFRMINIT,- ; drop out and signal msg1 =R8,- ; >current counter value msg2 =#GK_ETH ; >item count (queue size) Q_OK: addl2 #GQNTRY_SIZE,R9 ; point to next item slot sobgtr R8,Q_FREE ; update count and loop until done ; ; Build heap (for system call arguments and workspace) below stack frame ; This area will be shared by succeeding procedures... ; scratch = 100 ; heap workspace offset (argument lists) heapsiz = scratch+GK_VALSIZE_MAX ; subl2 #HEAPSIZ,SP ; make space movl SP,R9 ; setup pointer to heap movab SCRATCH(R9),R8 ; setup pointer to (strings) workspace ; ; Initialize Control section from system environment & parameter ; Parse command line and load qualifier values into Control section ; jsb GET_ENVIRONMENT ; upon failure, flow will not return ; jsb LOAD_ALL ; upon failure, flow may not return ; ; Execute following routine only when interactive so that I/O device exists... ; Find terminal attributes & set-up manual/emergency rundown method ; bitl #M_BATCH,GL_CSR(R11) ; if execution mode is interactive bneq DOTIM ; then ; jsb SET_CONTROL ; upon failure, flow will not return DOTIM: ; ; Set-up subprocess creation and synchronization timeout representation. ; Declare main exit handler ; $bintim_s - ; convert time from ASCII to VMS binary timbuf=D_BASETIME, - ; >initial & terminal timeout interval timadr=Q_BASETIME ; >resulting binary delta time blbs R0,DOSYNC ; check success, else alert status=R0 ; drop out and signal internal problem DOSYNC: cmpw #1,GW_STANDBY(R11) ; if standby period is defined bgtr DOXIT ; & standby is at least 2 seconds beql DOHALF ; then movq Q_STANDBY,Q_SYNCTIME ; use standby time as basis addl2 #10000000,Q_SYNCTIME ; resync_timeout = standby_time - 1 adwc #0, ; brb DOXIT ; else DOHALF: ashq #-1,Q_STANDBY,Q_SYNCTIME; resync_timeout = standby_time / 2 DOXIT: $dclexh_s - ; establish main exit handler routine desblk=AL_EXIT ; >exit handler control block blbs R0,LETSGO ; check success, else alert status=R0 ; drop out and signal internal problem LETSGO: movl GL_CSR(R11),L_ICSR ;*DIAG* keep original control state ; ; Initiate network listener subprocess ; jsb START_ACQ ; upon failure, flow will not return ; ; At this point, the network is connected and standing by... ; Initiate network partner as required (V3.0) ; ; bitl #M_PARTNER,GL_CSR(R11) ; ; beql DODMS ; ; ; jsb START_COOP ; upon failure, executor traffic lost DODMS: ; ; Initiate data manager subprocess ; jsb START_DMS ; upon failure, will attempt to continue ; ; Elevate PROBE then ACQ/DMS priority level & wait for first active cycle ; movl FP,SP ; recover stack, discard heap $setpri_s - ; boost current process to real-time prvpri=L_IPRIO,- ; >fallback priority upon rundown pri= #GK_TOPPRIORITY ; >target priority (25) blbs R0,PRI2 ; if service unsuccesful abort status=#PRB_NOBOOST,- ; then force image rundown reason=R0 ; >pass error code to exit handler PRI2: $setpri_s - ; boost listener to real-time pidadr=GL_ACQPID(R11),- ; >target process pri= #GK_ACQPRIORITY ; >target priority (24) blbs R0,PRI3 ; if service unsuccesful abort status=#PRB_NOBOOST,- ; then force image rundown reason=R0 ; >pass error code to exit handler PRI3: tstl GL_DMSPID(R11) ; check that a data manager exists beql READY ; otherwise nothing to boost here $setpri_s - ; boost data manager to real-time pidadr=GL_DMSPID(R11),- ; >target process pri= #GK_DMSPRIORITY ; >target priority (23) blbs R0,READY ; if service unsuccesful cmpl #SS$_NONEXPR,R0 ; because was process was not there beql READY ; then disregard (it failed) abort status=#PRB_NOBOOST,- ; else force image rundown reason=R0 ; >pass error code to exit handler READY: ; ; Prepare to enter cycle loop... starting with a standby period (Top of Cycle), ; followed with an active period (Middle of Cycle) leading to a synchronization ; period (End of Cycle). ; tstw GW_STANDBY(R11) ; if standby period specified beql TOPCYC ; then $setimr_s - ; prepare standby wait timer daytim=Q_STANDBY,- ; >delta time reqidt=#1,- ; >specific identification efn= #GV_TIMEIN ; >synchronization event flag blbs R0,TOPCYC ; check success abort status=R0 ; and force rundown if abnormal TOPCYC: ; ; Check that it is possible to continue & for last cycle. Set running flags. ; Wait end of standby period. ; bitl #,GL_CSR(R11); is active bneq PURSUE ; if no work to do then inconsistent... abort status=#PRB_NOWORK ; rundown & report nothing to do... PURSUE: bisl2 #M_GO,GL_CSR(R11) ; set activity flag addw3 #1,GW_CURCYCLE(R11),R1 ; compute next cycle number cmpw R1,GW_MAXCYCLE(R11) ; if reached maximum specified cycle blss SYNC1 ; then bicl2 #M_STANDBY,GL_CSR(R11) ; drop continuation flag (last cycle) SYNC1: movw R1,GW_CURCYCLE(R11) ; entering next cycle... update number tstw GW_STANDBY(R11) ; if standby period exists beql MIDCYC ; then $waitfr_s - ; sleep until efn=#GV_TIMEIN ; >awaken by timer event blbs R0,MIDCYC ; validate success abort status=R0 ; else force rundown MIDCYC: ; ; Establish base cycle time (interval "0" reference). Set activity timer as ; required & trigger subprocesses. ; $gettim_s - ; get current/reference system time timadr=GQ_GOTIME(R11) ; >start time buffer address blbs R0,CLOCK ; validate success abort status=#PRB_NOTIME,- ; else force image rundown reason=R0 ; >pass error code to exit handler CLOCK: bitl #M_TIMER,GL_CSR(R11) ; if exit mode is timed (automatic) beql NOSTOP ; then $setimr_s - ; prepare active wait timer daytim=Q_ACTIVE,- ; >delta time reqidt=#1,- ; >specific identification efn= #GV_TIMEIN ; >synchronization event flag blbs R0,PULSE ; check success abort status=R0 ; and force rundown if abnormal PULSE: $setef_s - ; release subprocesses efn=#GV_TRIGGER ; >trigger flag blbs R0,SYNC2 ; validate success abort status=R0 ; else force rundown... can't start SYNC2: $waitfr_s - ; sleep until efn=#GV_TIMEIN ; >awaken by timer event blbs R0,ENDCYC ; validate success abort status=R0 ; else force rundown NOSTOP: $setef_s - ; else (manual)... release subprocesses efn=#GV_TRIGGER ; >trigger flag blbs R0,SLEEP ; validate success abort status=R0 ; else force rundown... can't start SLEEP: bisl2 #M_SLEEP,GL_CSR(R11) ; indicate hibernating state $hiber_s ; sleep "forever" (until user wakes up) brw FINISH ; all done... complete rundown ENDCYC: ; ; According to continuation (standby) indicator, reenter (next cycle) standby ; state or terminate the program. When continuing, drop activity flag & wait ; for subprocesses to catch up and resynchronize. Upon subprocess timeout, ; action rundown. ; bitl #M_STANDBY,GL_CSR(R11) ; if standby not indicated bneq MORCYC ; then movl #PRB_CYCLEND,- ; no more cycle message GL_STATUS(R11) ; (normal termination) brw FINISH ; quit MORCYC: ; else ; ; Outstanding cycles to perform... ; match3 = event3 = ; $gettim_s - ; get current system time timadr=GQ_STOPTIME(R11) ; >stop time buffer address blbs R0,EDGEOF ; validate success abort status=#PRB_NOTIME,- ; else force image rundown... no time reason=R0 ; >pass error code to exit handler EDGEOF: $clref_s - ; reset subprocess trigger efn=#GV_TRIGGER ; >event flag identifier blbs R0,STOP ; validate success abort status=R0 ; else force rundown... lost control STOP: bicl2 #M_GO,GL_CSR(R11) ; drop activity flag $setimr_s - ; entering next cycle... standby period daytim=Q_STANDBY,- ; >delta time reqidt=#1,- ; >specific identification efn= #GV_TIMEIN ; >synchronization event flag blbs R0,RESYNC ; check success abort status=R0 ; and force rundown if abnormal RESYNC: $setimr_s - ; set slave resync timeout daytim=Q_SYNCTIME,- ; >computed slave grace period reqidt=#2,- ; >specific identification efn= #GV_TIMEOUT ; >expiry event flag blbs R0,SYNC3 ; check success abort status=R0 ; force rundown if abnormal SYNC3: movl #EVENT3,R2 ; load original wait event mask LOOP3: $wflor_s - ; wait for either efn= #GK_BASE,- ; the timer expiry flag mask=R2 ; or the slave "thumbs up" flags blbs R0,WAKE3 ; validate success abort status=R0 ; otherwise force rundown WAKE3: $readef_s - ; check event flag state efn= #GV_TIMEOUT,- ; >timeout flag state=L_EFSTATE ; >complete EF cluster state cmpl #SS$_WASSET,R0 ; if event was timeout bneq VRFY3 ; then movl #PRB_SYNCSLOW,- ; subprocess too slow... GL_STATUS(R11) ; notify user brb FINISH ; quit VRFY3: bbc #,-; else if listener resynchronized L_EFSTATE,SKP3A ; then bicl2 #GM_ACQREADY,R2 ; remove corresponding wait bit SKP3A: bbc #,-; if data manager resynchronized L_EFSTATE,SKP3B ; then bicl2 #GM_DMSREADY,R2 ; remove corresponding wait bit SKP3B: bitl #MATCH3,R2 ; check for remaining subprocess syncs bneq LOOP3 ; if so repeat wait $cantim_s - ; else cancel timeout reqidt=#2,- ; >timer identifier acmode=#PSL$C_USER ; >normal user mode ; disregard potential problem brw TOPCYC ; resume cycle start (wait on standby) FINISH: movl #SS$_NORMAL,R0 ; final image status ret ; quit... invoke exit handler ; ;; SUBROUTINES ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; GET_ENVIRONMENT: ; ; This routine loads primal information (PID, mode, node name) into the control ; section. It also validates the ethernet adapter, if specified, or searches the ; system configuration for an appropriate device. If no ethernet exists on this ; system, then all processing stops. ; Called from: MAIN ; Subroutines: CLI$GET_VALUE , LIB$SIGNAL , LIB$STOP , ; SYS$GETDVIW , SYS$GETJPIW , SYS$GETSYIW , SYS$TRNLNM ; Register allocation: ; R0 - L - /W - system call status ; R1 - L - /W - (affected by system calls) ; R2 - L - /W - scratch (implicit thru MOVCx) ; R3 - L - /W - scratch (implicit thru MOVCx) ; R4 - L - /W - scratch (implicit thru MOVCx) ; R5 - L - /W - scratch (implicit thru MOVCx) ; R6 - L - /W - adapter descriptor pointer ; R7 - L - /W - default list scan pointer ; R8 - L - R/ - workspace pointer within heap ; R9 - L - R/ - heap argument lists pointer ; R10 - * - */* - not referenced ; R11 - L - R/ - control section pointer ; ; Structure heap fixed allocation [0..23] (for CLI$GET_VALUE) ; Values not initialized are call instance specific ; ; (R9) workspace/result descriptor (size) ; 4(R9) workspace/result descriptor (pointer) movl #3,8(R9) ; retrieval argument list : size ; 12(R9) >address of input descriptor movaq (R9),16(R9) ; >address of result string descriptor movaw (R9),20(R9) ; >address of string size ; ; Prepare argument lists & interrogate system ; movw #4,24(R9) ; >PID buffer size movw #JPI$_PID,26(R9) ; >item code moval GL_PID(R11),28(R9) ; >PID result address @ section offset movaw -12(R8),32(R9) ; >PID result length address (Xcare=4) movw #4,36(R9) ; >mode (& maxbuf) buffer size movw #JPI$_MODE,38(R9) ; >item code movl R8,40(R9) ; >mode result address movaw -12(R8),44(R9) ; >mode result length address (Xcare=4) clrl 48(R9) ; >item list end $getjpiw_s - ; get process identification itmlst=24(R9),- ; >item list iosb= -8(R8) ; >status block blbc R0,JPI_ER ; check call success blbs -8(R8),JPI_OK ; if IOSB reports service failure movzwl -8(R8),R0 ; then transfer error code from IOSB JPI_ER: alert status=R0 ; notify user & stop JPI_OK: cmpl #JPI$K_INTERACTIVE,(R8) ; check process mode for interactive beql DO_SYI ; otherwise consider as "batch" bisl2 #M_BATCH,GL_CSR(R11) ; mark CSR accordingly DO_SYI: movw #GK_NODESIZE_MAX,24(R9) ; >node name buffer length movw #SYI$_NODENAME,26(R9) ; >item code movab GS_NODENAME(R11),28(R9) ; >buffer address @ section offset movaw GW_NODESIZE(R11),32(R9) ; >return length address @ offset movw #SYI$_MAXBUF,38(R9) ; >item code (size preinitialized above) moval GL_MAXBUF(R11),40(R9) ; >maxbuf result address $getsyiw_s - ; get node name itmlst=24(R9),- ; >item list iosb= -8(R8) ; >status block blbc R0,SYI_ER ; check call success blbs -8(R8),SYI_OK ; if IOSB reports service failure movzwl -8(R8),R0 ; then transfer error code from IOSB SYI_ER: alert status=R0 ; notify user & stop SYI_OK: ; ; Parse command line for adapter name and validate its existence and type ; As required, scan system for existing ethernet device from default list ; (prepare device service call argument sublist from previous lists) ; movw #DVI$_NET,38(R9) ; >item code (network device?) movl R8,40(R9) ; >address of boolean result moval AL_ETH,R7 ; load default ethernet list head movaq (R9),R6 ; point to main descriptor for messaging clrl R5 ; mark message not issued logical movaq D_ADAPTER,12(R9) ; load address of parameter descriptor movab GS_ADAPTER(R11),4(R9) ; point to adapter string in control movzwl #GK_ADAPSIZE_MAX,(R9) ; initialize size to maximum permissible callg 8(R9),G^CLI$GET_VALUE ; get input adapter name blbs R0,CHK_DV ; if abnormal return then cmpl #CLI$_ABSENT,R0 ; check that parameter was specified bneq NGO_DV ; otherwise incl R5 ; cancel messaging... use defaults NGO_DV: bbss #0,R5,NXT_DV ; test and cancel messaging signal message=#PRB_ADAPTER ; notify user of unacceptable value NXT_DV: movl (R7)+,R6 ; else get ethernet default entry bneq CHK_DV ; if at end-of-list then stop message=#PRB_NOETDEV ; quit; no ethernet on this system CHK_DV: $getdviw_s - ; else get device characteristics itmlst=36(R9), - ; >item list devnam=(R6), - ; >user-specified device name iosb= -8(R8) ; >status block blbc R0,NGO_DV ; check call success blbc -8(R8),NGO_DV ; check service success blbc (R8),NGO_DV ; if device is network type then blbc R5,LOG_DV ; if adapter is not user-supplied then movc3 (R6),@4(R6), - ; transfer name string GS_ADAPTER(R11) ; to control section LOG_DV: ; ; Assume network device is a logical name... get physical equivalence ; movl #9,R7 ; initialize translation attempt depth movw #GK_LOGICAL_MAX,36(R9) ; >buffer length movw #LNM$_STRING,38(R9) ; >item code movaw -8(R8),44(R9) ; >address of result string size LOG_PS: $trnlnm_s - ; get equivalence name for SYS$OUTPUT tabnam=D_LNMTAB,- ; >logical name table lognam=(R6),- ; >logical name to translate itmlst=36(R9) ; >pointer to item list descriptor blbc R0,TELL ; if translation successful then movl R9,R6 ; use master heap descriptor movw -8(R8),(R6) ; update equivalence string size movc5 (R6),(R8),#^A/ /, - ; update adapter string in control #GK_ADAPSIZE_MAX,@4(R6) ; sobgtr R7,LOG_PS ; try translation again TELL: movw (R6),GW_ADAPSIZE(R11) ; update adapter size in control signal message=#PRB_DEFSPEC,- ; advise user of default match msg1 =R6 ; >address of device descriptor rsb ; all done ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; LOAD_ALL: ; ; This routine controls the loading, converting and checking of all specified ; and/or default qualifiers from the command line. Upon return, the utility's ; internal state and operating values are fully defined. ; Called from: MAIN ; Subroutines: CLI$PRESENT , CLI$GET_VALUE , LIB$SIGNAL , LIB$STOP , ; OTS$CVT_TU_L , ; LOAD_TIME , LOAD_DISPLAY , LOAD_TABLE , LOAD_FILTER ; Register allocation: ; R0 - L - /W - system call status ; R1 - L - /W - (affected by system calls) ; R2 - L - /W - scratch (implicit thru MOVCx) ; R3 - L - /W - scratch (implicit thru MOVCx) ; R4 - L - /W - scratch (implicit thru MOVCx) ; R5 - L - /W - scratch (implicit thru MOVCx) ; R6 - L - /W - scratch used by subroutines ; R7 - L - /W - scratch used by subroutines ; R8 - L - R/ - workspace pointer within heap ; R9 - L - R/ - heap argument lists pointer ; R10 - * - */* - not referenced ; R11 - L - R/ - control section pointer ; ; Structure heap fixed allocation [24..43] (for OTS$CVT_TU_L) ; Values not initialized are call instance specific ; movl #4,24(R9) ; conversion argument list : size movaq (R9),28(R9) ; >address of input descriptor ; 32(R9) >address of result value ; 36(R9) >result value type size (2,4) movl #^X11,40(R9) ; >ignore spacers ; ; Set-up global flags & retrieve extension qualifiers ; (errors in extension values are corrected without user notification) ; bisl2 #M_STANDBY,GL_CSR(R11) ; initial standby ; pushaq D_DMP ; >address of qualifier descriptor calls #1,G^CLI$PRESENT ; check presence in command line blbc R0,L_1N ; if so then bisl2 #M_DIAGNOSTIC,GL_CSR(R11); set corresponding flag in control L_1N: movaq D_CD,12(R9) ; load address of qualifier descriptor movzwl #GK_VALSIZE_MAX,(R9) ; load transient descr with max size movl R8,4(R9) ; initialize descr to heap workspace callg 8(R9),G^CLI$GET_VALUE ; retrieve command line value blbc R0,L_2N ; make sure qualifier value is correct movaw GW_COLLISION(R11),32(R9); load result address (in control) movl #2,36(R9) ; load result size (in bytes) callg 24(R9),G^OTS$CVT_TU_L ; convert from ASCII to binary blbc R0,L_2N ; if conversion valid then bisl2 #M_COLLRPT,GL_CSR(R11) ; mark qualifier presence in control cmpw #999,GW_COLLISION(R11) ; bound check bgequ L_2N ; if out-of-bounds movw #999,GW_COLLISION(R11) ; then limit accordingly L_2N: ; ; Load statistics file name (if specified) for subprocess usage ; pushaq D_STATISTICS ; >statistics label descriptor calls #1,G^CLI$PRESENT ; check qualifier presence blbc R0,L_SN ; if present then... bisl2 #M_STATISTICS,GL_CSR(R11); mark statistics presence in control movaq D_RESULT,12(R9) ; load output keyword label descriptor movzwl #GK_FILSIZE_MAX,(R9) ; initialize descriptor size movab GS_OUTFILE(R11),4(R9) ; point descriptor to control section callg 8(R9),G^CLI$GET_VALUE ; retrieve command line value (file) blbc R0,L_SN ; if success then movw (R9),GW_OUTSIZE(R11) ; set file string control size bisl2 #M_OUTPUT,GL_CSR(R11) ; mark output file presence in control L_SN: ; ; Load recording file name and data-size (if specified) for subprocess usage ; pushaq D_RECORD ; >record label descriptor calls #1,G^CLI$PRESENT ; check qualifier presence blbc R0,L_LN ; if present then... bisl2 #M_LOG,GL_CSR(R11) ; mark recording presence in control movaq D_DATA,12(R9) ; >data label descriptor movzwl #GK_VALSIZE_MAX,(R9) ; initialize transient descriptor size movl R8,4(R9) ; initialize descr to heap workspace callg 8(R9),G^CLI$GET_VALUE ; retrieve command line value blbc R0,L_DN ; if data present then... movaw GW_FDATA(R11),32(R9) ; load result address (in control) movl #2,36(R9) ; load result size (in bytes) callg 24(R9),G^OTS$CVT_TU_L ; convert from ASCII to binary blbc R0,L_DN ; if conversion valid then tstw GW_FDATA(R11) ; bound check bleq L_DN ; if positive then (valid) bisl2 #M_DATA,GL_CSR(R11) ; mark data logging in control cmpw #GK_MAXDATA,GW_FDATA(R11); if out-of-bounds [..1500] bytes bgequ L_DN ; then movw #GK_MAXDATA,GW_FDATA(R11); limit accordingly L_DN: movaq D_SAMPLE,12(R9) ; load output keyword label descriptor movzwl #GK_FILSIZE_MAX,(R9) ; initialize descriptor size movab GS_LOGFILE(R11),4(R9) ; point descriptor to control section callg 8(R9),G^CLI$GET_VALUE ; retrieve command line value (file) blbc R0,L_LN ; if success then movw (R9),GW_LOGSIZE(R11) ; set file string control size L_LN: ; (otherwise use ACQ default name) ; ; Load schedule attributes, non-interactive exit must be automatic ; pushaq D_SCHEDULE ; >schedule label descriptor calls #1,G^CLI$PRESENT ; check qualifier presence blbc R0,L_MODE ; if present then bisl2 #M_TIMER,GL_CSR(R11) ; set appropriate CSR bit ; jsb LOAD_TIME ; fetch & validate attributes ; L_MODE: bitl #M_BATCH,GL_CSR(R11) ; check for mode "batch" beql L_SANE ; if so then bitl #M_TIMER,GL_CSR(R11) ; check for automatic exit set bneq L_SANE ; if not then stop message=#PRB_NOTICK ; abort... program has no mean to stop L_SANE: cmpw #1,GW_MAXCYCLE(R11) ; check that at least 1 cycle to perform beql L_TIMN ; if exactly 1... no complications bgtr L_TDEF ; if more than 1... beware of stats bitl #M_OUTPUT,GL_CSR(R11) ; if output file inexistant bneq L_TIMN ; and bitl #M_STATISTICS,GL_CSR(R11); if statistics selected or defaulted beql L_TIMN ; then (multicycle terminal stats nogo) bicl2 #M_STATISTICS,GL_CSR(R11); cancel statistics signal message=#PRB_MCTTSTS ; advise user that file is missing brb L_TIMN ; endif L_TDEF: movw #1,GW_MAXCYCLE(R11) ; if zero... garantee default of 1 L_TIMN: ; ; Load display attributes, invalid when non-interactive ; pushaq D_DISPLAY ; >display label descriptor calls #1,G^CLI$PRESENT ; check qualifier presence blbc R0,L_DISN ; if present then bitl #M_BATCH,GL_CSR(R11) ; check for mode "batch" beql L_DIS ; if so then signal message=#PRB_DSPMODE ; advise user... no terminal device brb L_DISN ; forget display processing L_DIS: bisl2 #M_DISPLAY,GL_CSR(R11) ; else set appropriate control flag ; jsb LOAD_DISPLAY ; fetch attributes L_DISN: ; ; Prepare multicast entry name and default operating flags ; movab GAE_N_SLOT(R11),R7 ; point to node array base (slot 0) bisb2 #M_NDISABLE, - ; do not process (illogical) GB_NSRC_CTL(R7) ; multicast (entry 0) as a source bisb2 #M_NFRONT, - ; force to front of display queue GB_NDST_CTL(R7) ; multicast (entry 0) as a destination movw D_MLTCAST,GW_NSIZE(R7) ; load multicast string length movc3 D_MLTCAST, - ; use specific length to copy @, - ; from constant string GS_NNAME(R7) ; to node entry block ; ; Load additional table data if specified ; movaq D_TABLE,12(R9) ; load next qualifier descriptor movzwl #GK_FILSIZE_MAX,(R9) ; initialize descriptor size movl R8,4(R9) ; point descriptor to heap workspace callg 8(R9),G^CLI$GET_VALUE ; retrieve command line value blbc R0,L_TABN ; if success then movl R8,T_FILE+FAB$L_FNA ; set file access block name pointer movb (R9),T_FILE+FAB$B_FNS ; set file access block name size movl R8,T_REC+RAB$L_UBF ; set record access block buffer ptr ; jsb LOAD_TABLE ; process table information L_TABN: ; ; Load filters if specified ; bisl2 #,GL_CSR(R11) ; active by default pushaq D_FILTER ; >filter label descriptor calls #1,G^CLI$PRESENT ; check qualifier presence blbc R0,L_FLTN ; if successful then ; jsb LOAD_FILTER ; process filter information ; L_FLTN: rsb ; all done... parsing complete ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; LOAD_TIME: ; ; This routine obtains the schedule specific values from the command string and ; prepares control attributes accordingly. If the timer specifications are not ; usable then the timer flag is reset. ; Called from: LOAD_ALL ; Subroutines: CLI$GET_VALUE , LIB$CVT_FROM_INTERNAL_TIME , LIB$SIGNAL ; OTS$CVT_TU_L , SYS$BINTIM ; Register allocation: ; R0 - L - /W - system call status ; R1 - L - /W - (affected by system calls) ; R2 - * - */* - not referenced ; R3 - * - */* - not referenced ; R4 - * - */* - not referenced ; R5 - * - */* - not referenced ; R6 - * - */* - not referenced ; R7 - * - */* - not referenced ; R8 - L - R/ - heap workspace pointer ; R9 - L - R/ - heap structured lists pointer ; R10 - * - */* - not referenced ; R11 - L - R/ - control section pointer ; ; Load and validate cycle value (optional attribute) ; movaq D_CYCLE,12(R9) ; load address of attribute descriptor movzwl #GK_VALSIZE_MAX,(R9) ; load transient descr with max size movl R8,4(R9) ; point descriptor to heap workspace callg 8(R9),G^CLI$GET_VALUE ; retrieve command line value blbc R0,TM_CYC ; if specified then movaw GW_MAXCYCLE(R11),32(R9) ; load result address (in control) movl #2,36(R9) ; load result size (in bytes) callg 24(R9),G^OTS$CVT_TU_L ; convert from ASCII to binary blbc R0,TM_NOC ; if successful then tstw GW_MAXCYCLE(R11) ; bound check [1..32767] bgtr TM_STB ; if out-of-bounds then TM_NOC: signal message=#PRB_INVCYC ; notify user... TM_CYC: movw #1,GW_MAXCYCLE(R11) ; use default (1) TM_STB: ; ; Load and validate standby time value (required with multi-cycles) ; movaq D_STANDBY,12(R9) ; load address of attribute descriptor movzwl #GK_VALSIZE_MAX,(R9) ; load transient descr with max size movl R8,4(R9) ; point descriptor to heap workspace callg 8(R9),G^CLI$GET_VALUE ; retrieve command line value blbc R0,TM_ACT ; if specified then $bintim_s - ; convert time from ASCII to binary timbuf=(R9), - ; >input string descriptor in heap timadr=Q_STANDBY ; > resulting binary time blbc R0,TM_NOS ; if service successful then movl #LIB$K_DELTA_SECONDS,- ;