; ; 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:ACQ.MAR ; Creator S.Germain p.eng ; Using VAX/VMS 5.2/5.4/5.5 ; History V1.0 Dec 89 : imbedded with PROBE ; V2.0 Jun 91 : full-function (logging) except collision detection ; V2.1 Feb 94 : improved IEEE format determination/handling ; size now reflects significant data portion ; V2.2 Dec 94 : adjusted log_it.type3 for protocol 0 skip ; updated log_it.type0 for new flags & data logging ; (size no longer bounded, IEEE overhead now valid) ; added log_it.type2 and log_it.type6 ; changed intro.block layout: not backward compatible ; ;; CONCEPT ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; This image is run as a subprocess spawned from PROBE when in "record" mode. ; The image initialization data is through the "control" global section created ; and set-up by PROBE. Operational input is obtained from the Ethernet port ; driver. Packet decomposition (envelop striping) is channeled to either (or ; both) the "buffer" global section for the DMS process or to a log file. ; Internal and external synchronizations are performed using event flags. ; Collision computing is done independantly through timer AST's although file ; logging is synchronous with recorded traffic. ; ;; NOTES ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; 1. Messages vectored by ACQ are contained in PROBE.MSG for PROBE's handling. ; Initialisation and runtime errors are signaled via the CTL global section. ; Assembling and linking is done as follows: ; ; $ MACRO/NODEBUG ACQ ; $ MESSAGE/OBJECT=MSG PROBE ; $ LINK/NODEBUG/NOTRACEBACK ACQ,MSG ; ; 2. This image, by the (promiscuous) nature of its interface to the network ; driver is NOT shareable. This implies that at most one PROBE session can be ; active per node/adapter at a given time. ; ; 3. The Ethernet device driver does not echo back frames emitted from the ; node on which this image runs. Therefore, some network traffic cannot be ; seen by this program. To minimize the impact of this, it is advisable to ; use PROBE on a quiet node (for example a standalone workstation). This ; problem will be corrected in a future dual-listener release of PROBE. ; ;; CONSTANTS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; .TITLE ACQ NETWORK LISTENER .IDENT /2.2/ ; .LIBRARY "SYS$LIBRARY:LIB.MLB" ; alternate system macro library .LIBRARY "SYS_PROBE:PROBELIB" ; application macro library $IODEF ; $NMADEF ; $PSLDEF ; $SECDEF ; V22$GBLDEF ; global constants definitions V22$CTLDEF ; control section definitions V22$BUFDEF ; buffer entry & section definitions V22$LOGDEF ; logfile section definitions ; .PSECT FIXDATA,NOEXE,NOWRT,NOSHR,LONG ; K_ALLOCBUF = 16 ; driver/port packet queue length ~BYTLM K_NETBUFSIZ = 1500 ; driver default buffer size K_LINBUFSIZ = 128 ; DECnet line counters (~) buffer size ; ; The following values are used to compute the logger data storage requirements. ; (With a log entry size of 48 bytes, a segment of 60 blocks can store 640 log ; entries. Given a 100 msec logger IO turnaround time, 2 segments can sustain ; a nominal arrival rate of 6400 ethernet frame/sec). ; K_MINBIO = 3 ; minimum aligned IO fragments (blocks) K_MULTIPLE = 20 ; number of fragments per segment K_SEGMBLCK = K_MULTIPLE*K_MINBIO ; logger segment size (blocks) K_SEGMBYTE = 512*K_SEGMBLCK ; logger segment size (bytes) K_SEGMENTS = 2 ; number of logger segments (*K_SEGMBLCK ; file extent quantities (blocks) K_INTRO = <<<1+GK_PTCLS+GK_NODES>*GLNTRY_SIZE>+511>/512 K_IFILE = </K_MINBIO>*K_MINBIO ; ; Named values & descripted values ; D_LINE: .LONG K_LINBUFSIZ ; CD report line buffer size .ADDRESS AB_LINE_COUNTS ; CD report line buffer location D_CDTIME: .ASCID /0 0:0:01/ ; 1 second base CD report (ASCII format) D_LOGNAME: .ASCID /ACQ_LOG/ ; log global section name ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; .PSECT FILEDATA,NOEXE,WRT,NOSHR,QUAD ; T_FILE: $FAB ALQ=K_IFILE,- ; file creation allocated space DEQ=K_XFILE,- ; automatic extension size DNM=,- ; default file name FAC=,- ; block output only FOP=,- ; seq trunc try-contig *.*;+1 MRS=GLNTRY_SIZE,- ; record is single log entry ORG=,- ; sequential organisation RFM=,- ; fixed record format SHR= ; unlocked multistream sharing T_STR0: ; ; Define one record access block per segments ; (cannot use automatic RMS next-block-pointer... asynchronous set later) ; .REPEAT K_SEGMENTS $RAB FAB=T_FILE ; pointer to output file access block .ENDR ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; .PSECT SCRATCH,NOEXE,WRT,NOSHR,PAGE ; AB_NETBUF: .BLKB K_NETBUFSIZ ; network frame data (block aligned) AB_NETENV: .BLKB 20 ; network frame envelop (QIO P5 buffer) AB_LINE_COUNTS: .BLKB K_LINBUFSIZ ; line counters buffer AB_L4_BLOCK: .BLKB GLNTRY_SIZE ; collision report logging block ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; .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_LOG: .LONG 0 ; log section start address .LONG 0 ; log section end address AL_CODE: .ADDRESS ACQ ; program low address .ADDRESS BYE ; 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_DATA: .BLKL K_SEGMENTS ; pointers to stream control [0..segm-1] Q_NETIOSB: .QUAD 0 ; network I/O status block Q_LINIOSB: .QUAD 0 ; collision (line) I/O status block Q_AWAKE: .QUAD 0 ; collision reporter short wait interval Q_SLEEP: .QUAD 0 ; collision reporter long wait interval Q_TIME: .QUAD 0 ; frame reception binary interval F_DELTA: .FLOAT 0.0 ; frame arrival interval fractional time L_VMSSTATUS: .LONG 0 ; VMS-written exit status (exit handler) L_ALLFRAMES: .LONG 0 ; network frame counter (absolute total) L_STREAM: .LONG 0 ; currently loading stream RAB address L_NEXTBLK: .LONG 1 ; overall next block pointer (IO VBN) L_TIME_OP: .LONG ; binary to floating time factor L_DATALEFT: .LONG 1 ; network data (size) outstanding (log) L_DATAPTR: .LONG 1 ; network data (pointer) (log) B_SEQUENCE: .BYTE 1 ; network data block sequence number ; setfunc = getfunc = linfunc = ; .ALIGN LONG AL_NET: $QIO - ; network driver I/O arguments iosb= Q_NETIOSB,- ; >status block address func= 0,- ; >program filled :requested operation chan= 0,- ; >program filled :input network channel efn= GV_ACQCATCH,- ; >IO completion event p1= 0,- ; >program filled :input buffer address p2= 0,- ; >program filled :frame/buffer size p5= 0 ; >program filled :frame header info ; AL_LIN: $QIO - ; network driver I/O line arguments astadr=COUNTERS,- ; >line counter scanning routine iosb= Q_LINIOSB,- ; >status block address func= LINFUNC,- ; >requested counter retrieval operation chan= 0,- ; >program filled :input network channel p2= D_LINE ; >line buffer descriptor ; AL_SYNC: $WAITFR - ; network frame arrival wait argument efn= GV_ACQCATCH ; >IO completion event synch ; AL_TIM: $SETIMR - ; collision reporter sleep arguments astadr=COLLISION,- ; >executing procedure daytim=Q_SLEEP,- ; >program filled :interval (default) efn= GV_ACQCDPASS ; >timer expiry indicator ; AL_CVT: .LONG 3 ; time conversion argument list (size) .ADDRESS L_TIME_OP ; >operation to perform (scaling factor) .ADDRESS F_DELTA ; >target (converted) time .ADDRESS Q_TIME ; >source binary interval time ; AB_NET_SETUP: .WORD NMA$C_PCLI_BFN .LONG K_ALLOCBUF ; preallocated driver buffer .WORD NMA$C_PCLI_BUS .LONG K_NETBUFSIZ ; 1500 byte is driver default .WORD NMA$C_PCLI_PRM .LONG NMA$C_STATE_ON ; promiscuous mode .WORD NMA$C_PCLI_RES .LONG NMA$C_LINRES_ENA; automatic adapter restart ; D_NET_SETUP: .LONG D_NET_SETUP-AB_NET_SETUP .ADDRESS AB_NET_SETUP ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; .PSECT CODE,EXE,NOWRT,NOSHR ; .ENTRY ACQ,^M<> ; entry point, no registers saved ; integer overflow trap is disabled ; ; Associate with common event cluster - communication with PROBE parent ; $ascefc_s - ; associate common event flag cluster efn= #GK_BASE,- ; >temporary event flag cluster id name=GS_CEFNAME,- ; >event flag cluster name prot=#1 ; >access granted to creator UIC only blbc R0,NOWAY ; validate success $setef_s - ; notify parent process of progress efn=#GV_ACQCONTACT ; >contact established flag blbs R0,DO_MAP ; upon incorrect status NOWAY: ret ; drop out... parent will time out DO_MAP: ; ; Map CONTROL and BUFFER global sections - data was locked down by parent ; (Pages are writable, first fit into virtual space) ; Lock down code & define master reference pointers to sections ; gsmask = ; $mgblsc_s - ; map the existing group 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) flags= #GSMASK ; >attribute mask blbc R0,NOMAP ; validate success $mgblsc_s - ; map the existing group 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) flags= #GSMASK ; >attribute mask blbs R0,MAPPED ; validate success NOMAP: $setef_s - ; notify parent process of problem efn=#GV_ACQFINISH ; >failure flag ret ; quit MAPPED: $lckpag_s - ; code lockdown inadr= AL_CODE,- ; >code boundary array acmode=#PSL$C_USER ; >user access mode (3) ; signal abnormal status movl AL_CTL,R11 ; load control section starting address movl AL_BUF,R10 ; load buffer section starting address ; ; Perform logging selection & validation followed by network adapter setup ; bbc #V_LOG,GL_CSR(R11),CONX ; if traffic recording is selected then ; jsb LOG_ON ; prepare logging file & log streams ; CONX: jsb CONNECT ; prepare network interface ; ; Complete data structure & automatic collision factor computation timer setup ; Declare exit handler (disregard failure) ; bbc #V_COLLRPT, - ; if user specified collision factor GL_CSR(R11),DYNCD ; then movw GW_COLLISION(R11),- ; fix invariant minimum GW_MINCOLL(R11) ; movw GW_COLLISION(R11),- ; fix invariant maximum GW_MAXCOLL(R11) ; brw PURSUE ; else (automatic collision) DYNCD: movw #999,GW_MINCOLL(R11) ; reverse bias minimum collision factor clrw GW_MAXCOLL(R11) ; reverse bias maximum collision factor $bintim_s - ; convert time from ASCII to VMS binary timbuf=D_CDTIME, - ; >base collision (short) interval timadr=Q_AWAKE ; >resulting binary delta time blbs R0,SPAN ; if conversion unsuccessful then movl R0,GL_ACQ_VMS(R11) ; save error condition code moval PRB_ACQOTOCD, - ; mark no collision detection warning GL_ACQSTATUS(R11) ; brb PURSUE ; skip remainder of collision set-up SPAN: movq Q_AWAKE,Q_SLEEP ; quiescent (long) interval baseline subw3 #2,GW_STANDBY(R11),R1 ; if cycle standby is more than 2 sec bleq AUTOCD ; then incw R1 ; adjust wait to approx 1 sec before movl SP,R5 ; preserve stack state subl2 #20,SP ; open heap storage area (5 longwords) movl SP,R4 ; point to heap movl #3,(R4) ; >argument list size moval L_TIME_OP,4(R4) ; >operation (scaling is seconds) moval 16(R4),8(R4) ; >input time address in heap movaq Q_SLEEP,12(R4) ; >output time is long interval cvtwf R1,16(R4) ; place wait period in heap callg (R4), - ; convert wait period to binary time G^LIB$CVTF_TO_INTERNAL_TIME movl R5,SP ; discard heap... recover stack blbs R0,QUIET ; if conversion unsuccessful then movl R0,GL_ACQ_VMS(R11) ; save error condition code moval PRB_ACQOTOCD, - ; mark no collision detection warning GL_ACQSTATUS(R11) ; brb PURSUE ; skip remainder of collision set-up QUIET: bitw #M_QUIET,GW_EFLAGS(R10) ; initial collision reporter sleep AUTOCD: $setimr_g - ; set standby AST timer AL_TIM ; >for default quiescent interval blbs R0,PURSUE ; if collision reporter submit failed movl R0,GL_ACQ_VMS(R11) ; save error condition code moval PRB_ACQOTOCD, - ; mark no collision detection warning GL_ACQSTATUS(R11) ; PURSUE: $dclexh_s - ; establish exit handler routine desblk=AL_EXIT ; >exit handler control block READY: ; ; Main control loop origin & PROBE handshaking ; Process indefinitely while parent is holding standby active. ; bbs #V_STANDBY, - ; if parent continuation flag absent GL_CSR(R11),RESET ; then ret ; rundown the program... (normal END) RESET: ; else ; ; Reset cyclic data structures before every new iteration ; ;; (none required in this release) ; ; Indicate readiness and wait for parent's synchronization signal ; Once triggered, log start of activity & collision status as required ; $setef_s - ; notify parent process back efn=#GV_ACQREADY ; >setup complete... in gear $waitfr_s - ; synchronize with parent command efn=#GV_TRIGGER ; >slave wait... release clutch $clref_s - ; drop ready synch efn=#GV_ACQREADY ; >processing... drive ; bbc #V_LOG,GL_CSR(R11),INCYC; if recording to file then movzbl #GK_GO_ID,R8 ; set Start_Cycle type block ; jsb LOG_IT ; transfer start block to log stream ; clrl R8 ;*DSD* set default data block type bbc #V_COLLRPT, - ; if collision report outstanding GL_CSR(R11),INCYC ; then movzbl #GK_CD_ID,R8 ; collision report block type ; jsb LOG_IT ; put collision report in log stream INCYC: ; endif ; ; Listen for network traffic & wait for a catch... ; Process frames as long as within cycle and no errors are reported ; $qio_g AL_NET ; capture next frame blbs R0,WAIT ; if service submission failed then movl R0,GL_ACQ_VMS(R11) ; save error condition code moval PRB_NET_IO, - ; user message vector GL_ACQSTATUS(R11) ; ret ; quit WAIT: $waitfr_g - ; wait until arrival detected AL_SYNC ; >synchronisation flag list bbs #V_GO,GL_CSR(R11),GREEN ; if activity is prevented then ; ; Process stopping state indicated by parent or failure ; As required, indicate end of cycle in log stream... cleanup ; bbc #V_LOG,GL_CSR(R11),CLOSE; if logging is active then ; COOP frame check & processing bbc #V_COLLRPT, - ; if collision report outstanding GL_CSR(R11),NOOCD ; then movzbl #GK_CD_ID,R8 ; collision report block type ; jsb LOG_IT ; put collision report in log stream ; NOOCD: movzbl #GK_STOP_ID,R8 ; set Stop_Cycle type block insv #1,#8,#8,R8 ;*DSD* don't flush stream (normal) ; jsb LOG_IT ; transfer stop block to log stream CLOSE: ; endif ; cancel outstanding network IO's ; wake parent as required brw READY ; back to top of synchronization loop GREEN: ; ; Process running state... validate consistency & time ; Construct a frame entry from the packet envelop and store into DMS buffer ; queue and/or recording (log file) stream ; blbs Q_NETIOSB,OK1 ; if network IO resulted in problem then movzwl Q_NETIOSB,GL_ACQ_VMS(R11); save error condition code cmpzv #1,#2,Q_NETIOSB,#0 ; check extended severity beql OK0 ; disregard warning (overrun...) moval PRB_NET_IO, - ; user message vector GL_ACQSTATUS(R11) ; ret ; quit OK0: moval PRB_NET_FLG, - ; user message vector GL_ACQSTATUS(R11) ; OK1: bitl #,GL_CSR(R11) ; (for DMS or logger) bneq OK2 ; otherwise moval PRB_NOWORK, - ; declare abnormal end GL_ACQSTATUS(R11) ; ret ; and leave OK2: incl L_ALLFRAMES ; update frame acquisition count bcc OK3 ; if beyond maximum permitted (4G) then moval PRB_MAXPACIN, - ; prevent overflow GL_ACQSTATUS(R11) ; ret ; must terminate here OK3: $gettim_s - ; get current system time timadr=Q_TIME ; >resulting binary VMS reference blbs R0,DELTA ; if unsuccessful then movl R0,GL_ACQ_VMS(R11) ; save error condition code moval PRB_NOTIME, - ; declare abnormal end GL_ACQSTATUS(R11) ; ret ; and leave DELTA: movq GQ_GOTIME(R11),R4 ; load cycle reference time subl2 Q_TIME,R4 ; compute (low) delta time sbwc ,R5 ; update (high) delta time movq R4,Q_TIME ; store binary interval bneq TIME ; make sure interval time is not zero movl #<-10>,Q_TIME ; otherwise, set at 1 micro-sec minimum movl #<-1>, ; negative required for deltatime TIME: callg AL_CVT,- ; convert interval to floating format G^LIB$CVTF_FROM_INTERNAL_TIME ; blbs R0,FRAME ; validate service success else movl R0,GL_ACQ_VMS(R11) ; save error condition code moval PRB_NOTIME, - ; declare abnormal end GL_ACQSTATUS(R11) ; ret ; and leave FRAME: bbs #V_LOG,GL_CSR(R11),FILE ; if logger inactive then remqhi GAL_EQFREE(R10),R9 ; grab free slot bvs NOSLOT ; if successful then clrw GB_QFLAGS(R9) ;*DSD* initialize flags (& tag) movw , - ; transfer frame size GW_QSIZE(R9) ; movl F_DELTA,GF_QTIME(R9) ; mark frame interval time movc5 #6,AB_NETENV,#0,#8,- ; GQ_QDESTIN(R9) ; transfer destination information movc5 #6,,#0,#8,-; GQ_QSOURCE(R9) ; transfer source information movw , - ; GW_QPTCL(R9) ; transfer protocol information tstl ; if frame is 802.3 beql INSERT ; then bisb2 #GM_LE_FRAMETYPE, - ; mark block appropriately GB_QTAG(R9) ; clrl ; dismiss IEEE potential for next frm brb INSERT ; else NOSLOT: bisw2 #M_ACQRAF,GW_EFLAGS(R10); mark remove failure for diagnostics brb FAILS ; or LOST: bisw2 #M_ACQIAF,GW_EFLAGS(R10); mark insert failure for diagnostics FAILS: incl GL_EACQDROP(R10) ; & update failure count brw INCYC ; else FILE: bbc #V_COLLRPT, - ; if collision report outstanding GL_CSR(R11),RECORD ; then movzbl #GK_CD_ID,R8 ; collision report block type ; jsb LOG_IT ; put collision report in log stream ; RECORD: jsb LOG_IT ; put frame/data block in log stream ; tstl R8 ; repeat log for multi-block data bneq RECORD ; (may result in single stream switch) ; bitl #,GL_CSR(R11) ; then beql DONE ; remqhi GAL_EQFREE(R10),R9 ; grab free slot bvs NOSLOT ; if successful then movc3 #,-; transfer frame block information (R7),GB_QFLAGS(R9) ; from stream into free item INSERT: insqti (R9),GAL_EQITEM(R10) ; replace item into common queue bcs LOST ; if successful then adawi #1,GW_ECOUNT(R10) ; update item queue size DONE: brw INCYC ; all done... next packet ; ;; SUBROUTINES ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; LOG_ON: ; ; This routine is activated when logging is specified by the user. It creates ; and initializes a new traffic data file and associated buffers & controls. ; Called from: MAIN ; Subroutines: SYS$CONNECT , SYS$CREATE , SYS$CRMPSC , SYS$GETTIM , SYS$LCKPAG ; LOG_IT ; Register allocation: ; R0 - L - /W - system calls status ; R1 - L - /W - (affected by system calls) ; R2 - L - /W - subroutine scratch ; R3 - L - /W - subroutine scratch ; R4 - L - /W - scratch (segment ID) ; R5 - L - /W - scratch (segment pointer) ; R6 - L - /W - stream control (RAB) pointer ; R7 - L - /W - log parameter ; R8 - L - /W - log entry type (& subtype as applicable) ; R9 - L - /W - protocol definition/extraction mask ; R10 - L - R/ - buffer section pointer ; R11 - L - R/ - control section pointer ; ; Create, map & lock LOG global section (used as buffer for file I/O) ; (Pages are initialized to zero, first-fit in virtual space, writable and ; allocated from pagefile) ; gsmask = gssize = ; $crmpsc_s - ; create and map Control global section inadr= AL_LOG,- ; >proposed virtual address array (P0) retadr=AL_LOG,- ; >actual virtual address array gsdnam=D_LOGNAME,- ; >global section name - hardcoded acmode=#PSL$C_USER,- ; >user access mode (3) pagcnt=#GSSIZE,- ; >size to fit all segments (blocks) flags= #GSMASK,- ; >creation attribute mask prot= #<^XFFFFF888> ; >protection (S:RWE,O:RWE,G:RWE,W) blbs R0,LOCK ; validate section creation movl R0,GL_ACQ_VMS(R11) ; save error code for diagnostics moval PRB_ACQFILE, - ; set unrecoverable logging vector code GL_ACQSTATUS(R11) ; bicl2 #M_LOG,GL_CSR(R11) ; cancel logging operations rsb ; return to caller LOCK: $lckpag_s - ; lock global pages in memory inadr= AL_LOG, - ; >actual virtual address array acmode=#PSL$C_USER ; >user access mode (3) ; disregard potential error processing ; ; Initialize stream array RAB pointers and corresponding streams ; movb GW_LOGSIZE(R11),- ; set log file string size T_FILE+FAB$B_FNS ; into control block movab GS_LOGFILE(R11),- ; set log file string address T_FILE+FAB$L_FNA ; into control block $create fab=T_FILE ; attempt to create a new empty file blbs R0,STREAM ; if unsuccessful then moval PRB_ACQFILE, - ; identify error GL_ACQSTATUS(R11) ; movl T_FILE+FAB$L_STS, - ; store RMS/R0 status for diagnostics GL_ACQ_VMS(R11) ; movl T_FILE+FAB$L_STV, - ; store extended information GL_ACQ_EXT(R11) ; bicl2 #M_LOG,GL_CSR(R11) ; cancel logging operations rsb ; return to caller STREAM: moval T_STR0,R6 ; point to stream 0 control movl R6,L_STREAM ; stream 0 is default initial stream movl AL_LOG,R5 ; point to log buffer clrl R4 ; initialize stream ID IN_STR: movl R4,RAB$L_CTX(R6) ; place ID into stream user context movl R6,AL_DATA[R4] ; point stream directory item to control movl R5,RAB$L_RBF(R6) ; point stream control to log buffer $connect - ; establish this stream rab=(R6) ; blbs R0,NX_STR ; if unsuccessful then moval PRB_ACQFILE, - ; identify error GL_ACQSTATUS(R11) ; movl RAB$L_STS(R6), - ; store RMS/R0 status for diagnostics GL_ACQ_VMS(R11) ; movl RAB$L_STV(R6), - ; store extended information GL_ACQ_EXT(R11) ; bicl2 #M_LOG,GL_CSR(R11) ; cancel logging operations rsb ; return to caller NX_STR: bisl2 #RAB$M_ASY,RAB$L_ROP(R6); stream operations async from now on addl2 #RAB$C_BLN,R6 ; advance stream control to next RAB addl2 #K_SEGMBYTE,R5 ; advance log buffer to next stream acbl #, - ; repeat #1,R4,IN_STR ; until all streams are ready ; ; Prepare Preamble (introduction) block ; movl L_STREAM,R6 ; point to stream control bicl2 #RAB$M_ASY,RAB$L_ROP(R6); make stream 0 synchronous for preamble movzbl #GK_INTRO_ID,R8 ; set Introduction type (raw) ; jsb LOG_IT ; transfer intro block to logger buffer ; ; Prepare Filler blocks... can contain protocol and/or node definitions ; movzbl #GK_FILL_ID,R8 ; set generic filler block type movzwl GW_DEFPTCL(R11),R9 ; if protocols are defined beql NODE ; then insv #GK_PTCL_ID,#8,#8,R8 ; set protocol filler subtype clrl R7 ; initialize protocol ID below range PTCL: incl R7 ; first/next protocol ID ashl #-1,R9,R9 ; scan for defined protocol beql NODE ; if some left then blbc R9,PTCL ; if current is defined then ; jsb LOG_IT ; transfer protocol block to logger ; brb PTCL ; repeat until no more protocols NODE: movzwl GW_NODECOUNT(R11),R7 ; if nodes are defined beql FILL ; then insv #GK_NODE_ID,#8,#8,R8 ; set node filler subtype SCAN: jsb LOG_IT ; transfer node block to logger ; sobgtr R7,SCAN ; repeat until no more nodes FILL: insv #GK_ALIGN_ID,#8,#8,R8 ; set generic filler block type ; ; Force the stream to be block aligned (multiple of logging unit to prevent ; data gaps) and output synchronously to guarantee preamble presence at the ; beginning of file. ; jsb LOG_IT ; add one filling block to stream ; bisl2 #RAB$M_ASY,RAB$L_ROP(R6); resume async stream 0 operations ; ; Prepare fixed collision report block as required (logging performed later) ; (zero sequence for differentiation) ; bbc #V_COLLRPT, - ; if user specified collision factor GL_CSR(R11),LOGGED ; then $gettim_s - ; (fill-in only meaningful attributes) timadr=AB_L4_BLOCK+GQ_L4_ABSTIME; obtain system time reference movl #1000,AB_L4_BLOCK+GL_L4_FXMITTED; hardcode factor scale movzwl GW_COLLISION(R11), - ; hardcode scaled user value AB_L4_BLOCK+GL_L4_SINGLE ; (precomputed ratio) LOGGED: rsb ; all done... back to caller ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; LOG_IT: ; ; This routine creates a log entry into a log stream. ; The stream is automatically written out to the recording file when full and ; a stream switch is carried out while operations are asynchronous. ; Called from: LOG_ON , MAIN , SHUTDOWN ; Subroutines: SYS$WRITE ; Register allocation: ; R0 - L - /W - system calls status ; R1 - L - /W - (affected by system calls) ; R2 - L - /W - scratch (implicit thru MOVCx) ; R3 - L - /W - stream pointer (implicit thru MOVCx) ; R4 - L - /W - filler scratch (implicit thru MOVCx) ; R5 - L - /W - filler scratch (implicit thru MOVCx) ; R6 - L - R/W - stream control (RAB) pointer (modified only on async IO) ; R7 - L - R/W - optional logger parameter (type 0 returns pointer) ; R8 - W - R/W - block type & subtype -> unmodified except: ; (type 4 returns 0; type 0 may return 2; type 2 returns 0) ; R9 - * - */* - not referenced ; R10 - L - R/ - buffer section pointer ; R11 - L - R/ - control section pointer ; movzwl RAB$W_RSZ(R6),R2 ; load current segment size movab @RAB$L_RBF(R6)[R2],R3 ; load stream current pointer caseb R8,#0,#7 ; execute one of following types [0..7] SELECT: .WORD TYPE0-SELECT ; 0 : frame block .WORD TYPE1-SELECT ; 1 : introduction block .WORD TYPE2-SELECT ; 2 : payload termination block .WORD TYPE3-SELECT ; 3 : filler block .WORD TYPE4-SELECT ; 4 : collision report block .WORD TYPE5-SELECT ; 5 : start cycle block .WORD OTHER-SELECT ; 6 : RESERVED (payload spanning block) .WORD TYPE7-SELECT ; 7 : stop cycle block OTHER: rsb ; reserved or out-of-bound... do nothing TYPE0: ; ; Type 0 - data block ; (uses implicitely adjusted pointer... filled in non-symbolic order) ; movl R3,R7 ; save block stream position clrw (R3)+ ;*DSD* mark default data block & tag blbs Q_NETIOSB,T0_A ; if warning was reported by QIO bisb2 #GM_LE_FRAMESTATUS, - ; then GB_LE_TAG(R7) ; mark block[tag] appropriately T0_A: movw ,(R3)+ ;*DSD* transfer frame data size movl F_DELTA,(R3)+ ;*DSD* transfer frame interval time movc5 #6,,#0, - ;*DSD* transfer source information #8,(R3) ; movc5 #6,AB_NETENV,#0,#8,(R3) ;*DSD* transfer target info movl #2,R2 ; assume Ethernet -- protocol size=2 movl ,R0 ; if packet is 802.3 type (CTL defined) beql T0_D ; then bisb2 #GM_LE_FRAMETYPE, - ; mark block[tag] appropriately GB_LE_TAG(R7) ; movl #8,R2 ; assume extended IEEE -- overhead=8 cmpw #^XAAAA, ; if not extended IEEE (non-dual SNAP) beql T0_C ; then T0_B: movl #3,R2 ; assume single-CTL -- overhead=3 cmpb R0,R2 ; check 00000011 (UI) beql T0_C ; if not matched then bicb2 #^B00010000,R0 ; disregard bit 5 cmpb #^B10101111,R0 ; check 101x1111 (XID) beql T0_C ; if not matched then cmpb #^B11100011,R0 ; check 111x0011 (TEST) beql T0_C ; if not matched then (dual-CTL) incl R2 ; adjust overhead=4 T0_C: insv R2,#GV_LE_802OVERHEAD,- ; transfer IEEE headers size #4,GB_LE_TAG(R7) ; (3, 4 or 8) T0_D: movc5 R2,,#0, - ;*DSD* transfer (Ethernet) protocol #8,(R3) ; or (IEEE) sap/headers + fill (& R2=0) clrl ; dismiss IEEE potential for next frame bbc #V_DATA,GL_CSR(R11),T0_E; if data from frame requested then bisb2 #GM_LE_FRAMEDATA, - ; mark block[tag] appropriately GB_LE_TAG(R7) ; movzwl ,R2 ; load actual frame data length cmpw R2,GW_FDATA(R11) ; limit data transfer quantity bleq T0_E ; as required movzwl GW_FDATA(R11),R2 ; to the user-requested size T0_E: movc5 R2,AB_NETBUF,#0, - ;*DSD* transfer frame data as required #GK_LOGDATA,(R3) ; (or initialize that space) movl R0,L_DATALEFT ; if data transfer is not complete beql T0_F ; then bisb2 #GM_LE_MOREDATA, - ; mark block[tag] appropriately GB_LE_TAG(R7) ; movl R1,L_DATAPTR ; remind input buffer location clrb B_SEQUENCE ; initialize follow-on block sequencing movl #2,R8 ;*DSD* set follow-on data block type T0_F: brw ADJUST ; block complete... go check stream TYPE1: ; ; Type 1 - intro block ; (end filling not required... stream already ok from demand-0 section) ; movb R8,GB_LTYPE(R3) ; mark introduction block movb #GLNTRY_SIZE, - ; register fixed record size (<256) GB_L1_RECORD(R3) ; movw GW_FDATA(R11), - ; register maximum significant payload GW_L1_PAYLOAD(R3) ; bisb2 #GM_L1_VAX, - ; mark data as VAX type (raw by default) GB_L1_FLAGS(R3) ; movl #GK_VERSION, - ; load section structure level GL_L1_VERSION(R3) ; $gettim_s - ; obtain system time reference timadr=GQ_L1_ABSTIME(R3); >use as initial creation time movl GL_CSR(R11), - ; load startup control state GL_L1_CSR(R3) ; movl GL_PID(R11), - ; load parent process ID GL_L1_PID(R3) ; movw GW_CHRONO(R11), - ; load activity schedule GW_L1_ACTIVE(R3) ; movw GW_STANDBY(R11), - ; load standby schedule GW_L1_STANDBY(R3) ; movw GW_MAXCYCLE(R11), - ; load cycle repetitions GW_L1_CYCLE(R3) ; movb GW_ADAPSIZE(R11), - ;*DSD* load adapter name string size GB_L1_ASIZE(R3) ; movb GW_NODESIZE(R11), - ;*DSD* load node name string size GB_L1_NSIZE(R3) ; movc5 GW_ADAPSIZE(R11), - ; load adapter name GS_ADAPTER(R11), - ; #^A/ /, - ; & blank fill #GK_ADAPSIZE_MAX, - ; GS_L1_ADAPTER(R3) ; movc5 GW_NODESIZE(R11), - ;*DSD* load node name GS_NODENAME(R11), - ; #^A/ /, - ; & blank fill #GK_NODESIZE_MAX, - ; (R3) ; (non symbolic because previous MOVC5) brw ADJUST ; block complete... go check stream TYPE2: ; ; Type 2 - data continuation block ; movb R8,GB_LTYPE(R3) ; mark data block (assume last) addb3 #1,B_SEQUENCE, - ; mark updated sequence number GB_L2_SEQ(R3) ; movl L_DATALEFT,R0 ; reload transfer size context cmpl #GX_L2_SIZE,R0 ; if payload exceed block capacity bgeq T2_A ; then bisb2 #GM_LE_MOREDATA, - ;*DSD* convert to block 6 (data span) GB_LTYPE(R3) ; movc5 R0,@L_DATAPTR,#0, - ;*DSD* transfer continuation data #GX_L2_SIZE,GS_L2_DATA(R3); and blank fill as required movl R0,L_DATALEFT ; remind transfer size context movl R1,L_DATAPTR ; remind input buffer location incb B_SEQUENCE ; remind block sequence brw ADJUST ; else (last pass) T2_A: movc5 R0,@L_DATAPTR,#0, - ;*DSD* transfer remaining data #GX_L2_SIZE,GS_L2_DATA(R3); and blank fill as required clrl R8 ;*DSD* reset default data block type brw ADJUST ; block complete... go check stream TYPE3: ; ; Type 3 - filler block ; cmpzv #8,#8,R8,#1 ; examine subtype beql T3_1 ; if subtype not protocol specific bgtr T3_2 ; and not node specific then T3_0: cmpzv #0,#9,RAB$W_RSZ(R6),#0 ; while logger buffer not block aligned beql T3_Z ; do movb R8,(R3)+ ;*DSD* mark generic filler block movc5 #0,(R3),#0, - ; #GX_L30_FILL,(R3) ; erase the block addl2 #GLNTRY_SIZE, - ; compute new stream size RAB$W_RSZ(R6) ; brb T3_0 ; enddo T3_Z: brw IO ; force output T3_1: ; ; Type 3 / Subtype 1 - protocol definition filler block ; movab GAE_P_SLOT(R11),R4 ; load protocol table base emul #GPNTRY_SIZE,R7,R4,R4 ; compute protocol entry base address movw R8,GB_LTYPE(R3) ; mark protocol type movw R7,GW_L3$1_ID(R3) ; load protocol ID movw GW_ACTPTCL(R11), - ; GW_L3$1_ACTPTCL(R3) ; load protocol activity mask movw GW_PROTOCOL(R4), - ; GW_L3$1_VALUE(R3) ; load protocol value movw GW_PSIZE(R4), - ; GW_L3$1_SIZE(R3) ; load protocol name string size movc5 GW_PSIZE(R4), - ; GS_PNAME(R4),#^A/ /, - ; load protocol name string #GK_PSIZE_MAX, - ; & blank fill GS_L3$1_NAME(R3) ; movc5 #0,(R3),#0, - ;*DSD* erase remainder of log block #GX_L3$1_FILL,2(R3) ; brw ADJUST ; block complete... go check stream T3_2: ; ; Type 3 / Subtype 2 - node definition filler block ; movab GAE_N_SLOT(R11),R4 ; load protocol table base emul #GNNTRY_SIZE,R7,R4,R4 ; compute protocol entry base address movw R8,GB_LTYPE(R3) ; mark node type movw R7,GW_L3$2_INDEX(R3) ; load last/previous node index movq GQ_NADDRESS(R4), - ; GQ_L3$2_ADDRESS(R3) ; load node ethernet address movw GW_NCONTROL(R4), - ; GW_L3$2_CONTROL(R3) ; load node control flags movw GW_NSIZE(R4), - ; GW_L3$2_SIZE(R3) ; load node name string size movc5 GW_NSIZE(R4), - ; GS_NNAME(R4),#^A/ /, - ; load node name string #GK_NSIZE_MAX, - ; & blank fill GS_L3$2_NAME(R3) ; movc5 #0,(R3),#0, - ;*DSD* erase remainder of log block #GX_L3$2_FILL,8(R3) ; brw ADJUST ; block complete... go check stream TYPE4: ; ; Type 4 - collision report block ; clrl R8 ;*DSD* reset default data block type bbssi #V_L4MTX, - ;*DSD* reserve block access mutex AB_L4_BLOCK,T4_Z ; (& mark block type) movc3 #GLNTRY_SIZE, - ; transfer static storage block AB_L4_BLOCK,(R3) ; to log stream bicl2 #M_COLLRPT,GL_CSR(R11) ; dismiss report-required flag bicw2 #M_L4MTX,AB_L4_BLOCK ; release block access mutex brw ADJUST ; block complete... go check stream T4_Z: rsb ; interlock failed... reporter busy TYPE5: ; ; Type 5 - cycle start block ; movzwl R8,GB_LTYPE(R3) ; mark begin cycle type movzwl GW_CURCYCLE(R11), - ; GL_L5_SEQUENCE(R3) ; load cycle number movq GQ_GOTIME(R11), - ; GQ_L5_GOTIME(R3) ; load cycle termination time movl GL_CSR(R11), - ; GL_L5_CSR(R3) ; load master control state movc5 #0,(R3),#0, - ; #GX_L5_FILL, - ; erase remainder of log block space GX_L5_SIZE(R3) ; brw ADJUST ; block complete... go check stream TYPE7: ; ; Type 7 - cycle stop block ; movzwl R8,GB_LTYPE(R3) ; mark end cycle type movzwl GW_CURCYCLE(R11), - ; GL_L7_SEQUENCE(R3) ; load cycle number movq GQ_STOPTIME(R11), - ; GQ_L7_STOPTIME(R3) ; load cycle termination time movl GL_CSR(R11), - ; GL_L7_CSR(R3) ; load master control state movw GW_EFLAGS(R10), - ; GW_L7_STATE(R3) ; load secondary control state movw GW_NODECOUNT(R11), - ; GW_L7_NODES(R3) ; load node list size movl L_ALLFRAMES, - ; GL_L7_FRAMES(R3) ; load total processed frames movl GL_EACQDROP(R10), - ; GL_L7_DROPS(R3) ; load total dropped frames movl GL_LOGIOS(R11), - ; GL_L7_IOS(R3) ; load total logger IO's movc5 #0,(R3),#0, - ; #GX_L7_FILL, - ; erase remainder of log block space GX_L7_SIZE(R3) ; bbs #8,R8,ADJUST ;*DSD* if forced termination then addw2 #GLNTRY_SIZE, - ; (last file entry) RAB$W_RSZ(R6) ; compute new stream size brb IO ; force output ADJUST: ; ; Output stream if full or forced.... ; addw2 #GLNTRY_SIZE, - ; compute new stream size RAB$W_RSZ(R6) ; cmpw #K_SEGMBYTE,RAB$W_RSZ(R6);if stream not yet full then bleq IO ; all done... back to caller rsb ; else (stream full) IO: extzv #9,#7,RAB$W_RSZ(R6),R2 ; extract stream size in blocks addl2 R2,L_NEXTBLK ; compute file next VBN slot bbc #RAB$V_ASY, - ; if stream operations are asynchronous RAB$L_ROP(R6),SYNCH ; then insv #1,RAB$L_CTX(R6),#1, - ;*DSD* GW_EFLAGS(R10) ; mark current stream busy $write rab=(R6), - ; initiate IO to log file suc=STREAM_OK, - ; >success AST routine err=STREAM_ERROR ; >failure AST routine blbc R0,IOBUG ; if launch successful then ffc #V_LOGSEGM,#K_SEGMENTS,-;*DSD* GW_EFLAGS(R10),R2 ; search for next available stream beql IOFULL ; if one found then movl AL_DATA[R2],R6 ; load stream control block (RAB) IOOK: clrw RAB$W_RSZ(R6) ; initialize stream size movl L_NEXTBLK,RAB$L_BKT(R6) ; corresponding file VBN slot movl R6,L_STREAM ; make this stream current rsb ; all done... back to caller SYNCH: $write rab=(R6) ; else initiate IO to log file blbs R0,IOOK ; if operation failed then movl RAB$L_STV(R6), - ; load failure status GL_ACQ_EXT(R11) ; IOBUG: movl R0,GL_ACQ_VMS(R11) ; load completion code moval PRB_LOG_IO, - ; mark user notification message GL_ACQSTATUS(R11) ; bicl2 #M_LOG,GL_CSR(R11) ; drop logging rsb ; nothing else to do... return IOFULL: moval PRB_ACQOVFL, - ; when no empty stream exist GL_ACQSTATUS(R11) ; advise user of problem bicl2 #M_LOG,GL_CSR(R11) ; drop logging bisw2 #M_LOGFULL,GW_EFLAGS(R10);*DIAG* mark condition rsb ; nothing else to do... return ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; CONNECT: ; ; This routine opens a port on the ethernet adapter described in the control ; section and attempts to start promiscuous mode. ; Called from: MAIN ; Subroutines: SYS$ASSIGN , SYS$QIOW ; Register allocation: ; R0 - L - /W - system calls status ; R1 - L - /W - (affected by system calls) ; R2 - * - */* - not referenced ; R3 - * - */* - not referenced ; R4 - L - /W - heap pointer ; R5 - L - /W - original (saved) stack pointer ; R6 - * - */* - not referenced ; R7 - * - */* - not referenced ; R8 - * - */* - not referenced ; R9 - * - */* - not referenced ; R10 - L - R/ - buffer section pointer ; R11 - L - R/ - control section pointer ; movl SP,R5 ; preserve stack state subl2 #8,SP ; open heap storage area (1 quadword) movl SP,R4 ; point to heap movzwl GW_ADAPSIZE(R11),(R4) ; construct descriptor movab GS_ADAPTER(R11),4(R4) ; for adapter name string in control $assign_s - ; open a channel to the ethernet devnam=(R4),- ; >input device name acmode=#PSL$C_USER,- ; >input access mode chan= AL_NET+QIO$_CHAN ; >returned channel into QIO arglist movl R5,SP ; discard heap... recover stack blbs R0,PORT ; if service unsuccessful then movl R0,GL_ACQ_VMS(R11) ; save error condition code moval PRB_NOIO, - ; declare abnormal end GL_ACQSTATUS(R11) ; ret ; and leave PORT: movl AL_NET+QIO$_CHAN, - ; else AL_LIN+QIO$_CHAN ; share channel with CD report routine ; ; Network port open... start universal read mode ; movl #SETFUNC, - ; command controller startup AL_NET+QIO$_FUNC ; into QIO arglist movaq D_NET_SETUP, - ; extended characteristics descriptor AL_NET+QIO$_P2 ; into QIO arglist callg AL_NET,G^SYS$QIOW ; start the ethernet port blbc R0,FERME ; if either submission or blbs Q_NETIOSB,SET ; service unsuccessful then movzwl Q_NETIOSB,R0 ; FERME: movl R0,GL_ACQ_VMS(R11) ; save error condition code moval PRB_ACQPORT, - ; declare abnormal end GL_ACQSTATUS(R11) ; ret ; and leave SET: ; ; Prepare network read QIO argument list ; movl #GETFUNC, - ; read virtual block AL_NET+QIO$_FUNC ; is new IO function movab AB_NETBUF, - ; network buffer AL_NET+QIO$_P1 ; is IO storage location movl #K_NETBUFSIZ, - ; network buffer size AL_NET+QIO$_P2 ; is IO maximum transfer movab AB_NETENV,AL_NET+QIO$_P5; frame parameters buffer location rsb ; all done... return to caller ; ;; MODULES ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; .PSECT HANDLE,EXE,NOWRT,NOSHR ; ; Asynchronous system trap code - invoked automatically by RMS (executive mode) ; .ENTRY STREAM_OK,^M ; ; ; This module is for logging success post-processing. It frees the returning ; stream buffer for further storage by the logger code. ; movl AL_CTL,R11 ; point to control section movl AL_BUF,R10 ; point to buffer section incl GL_LOGIOS(R11) ;*DIAG* count all IO's movl 4(AP),R1 ; point to RAB (for stream ID) insv #0,RAB$L_CTX(R1),#1, - ; free stream from usage bit map GW_EFLAGS(R10) ; ret ; continue interrupted processing ; .ENTRY STREAM_ERROR,^M ; ; ; This module is for logging failure post-processing. It puts an error message ; in the control section and cancels further logging. ; movl AL_CTL,R11 ; point to control section bicl2 #M_LOG,GL_CSR(R11) ; drop logging movl 4(AP),R1 ; point to RAB (for status codes) moval PRB_ACQFILE, - ; user error message GL_ACQSTATUS(R11) ; movl RAB$L_STS(R1), - ; RMS status code GL_ACQ_VMS(R11) ; movl RAB$L_STV(R1), - ; RMS status value GL_ACQ_EXT(R11) ; ret ; continue interrupted processing ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; .ENTRY COLLISION,^M<> ; ; ; Asynchronous system trap code - invoked automatically by VMS timer rundown ; ; readef ; if low (standby period) ; then if ; then clear ; set awake interval ; else set ; set sleep interval ; endif ; else if ; then clear ; set awake interval ; endif ; endif ; issue async line counter retrieval ; wait interval... reissue itself AST ret ; .ENTRY COUNTERS,^M<> ; ; if mutex_sync ; then ; if then prepare CDreport block ; update min-max ; set ; endif ; update collision report count ret ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; .ENTRY SHUTDOWN,^M<> ; ; This module is called automatically by VMS upon image rundown after being ; declared as an exit handler. ; This module performs necessary steps to... ; movl AL_CTL,R11 ; recover pointer to control section movl AL_BUF,R10 ; recover pointer to buffer section ; ; cancel collision processing timer as required ; bbc #V_LOG,GL_CSR(R11),BYE ; if logging is active then ; ; check the stream... reissue uncertain last stream IO ; switch to new stream as required... make sure no outstanding IO's ; movl L_STREAM,R6 ; point to stream control bicl2 #RAB$M_ASY,RAB$L_ROP(R6); make stream synchronous for fade-out movzbl #GK_STOP_ID,R8 ; set (forced) Stop_Cycle type block ; jsb LOG_IT ; flush stream ; $truncate - ; truncate the file rab=(R6) ; to prevent excessive over-allocation ; BYE: $setef_s - ; notify parent process of termination efn=#GV_ACQFINISH ; >signing off event flag bbcci #V_SLEEP,GL_CSR(R11),- ; if parent currently sleeping ADIOS ; then $wake_s pidadr=GL_PID(R11) ; wake it up ADIOS: ret ; complete rundown (normal END) ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; .END ACQ