Trailing-Edge
-
PDP-10 Archives
-
SRI_NIC_PERM_SRC_3_19910112
-
monitor/enqsrv.mac
There are 13 other files named enqsrv.mac in the archive. Click here to see a list.
; Edit= 8904 to ENQSRV.MAC on 15-Aug-88 by LOMARTIRE
;Improve BUG. documentation
; Edit= 8848 to ENQSRV.MAC on 25-May-88 by LOMARTIRE (TCO 7.1292)
;More of edit 8847 - fix all places that quit after a "No" reply
; Edit= 8847 to ENQSRV.MAC on 24-May-88 by LOMARTIRE (TCO 7.1292)
;Prevent jobs hung in EVWAIT - make all nodes reply to vote
; UPD ID= 8513, RIP:<7.MONITOR>ENQSRV.MAC.14, 9-Feb-88 15:20:28 by GSCOTT
;TCO 7.1218 - Update copyright date.
; UPD ID= 8460, RIP:<7.MONITOR>ENQSRV.MAC.13, 5-Feb-88 09:34:31 by GSCOTT
;TCO 7.1210 - Set EQNOTF normally not dumpable.
; UPD ID= 8343, RIP:<7.MONITOR>ENQSRV.MAC.12, 15-Jan-88 15:43:39 by LOMARTIRE
;More of TCO 7.1179 - Do not check EN.CLL in EQRSTS. Always vote if the
; process has cluster-wide capabilities even if the block does not have
; EN.CLL set.
; UPD ID= 8341, RIP:<7.MONITOR>ENQSRV.MAC.11, 14-Jan-88 16:04:20 by LOMARTIRE
;TCO 7.1179 - Check EN.CLL before returning success in LOCLOK. Mixed mode
; non-file object locks should only be "found" if this system believes
; that it is a cluster-wide lock. This issue is of no concern for file
; locks since it is already handled via the ENQ Token which makes mixed
; mode file lock illegal. Also, add a check of EN.CLL in routines
; EQRSTS, EQPOOL, and EQLKSD.
; UPD ID= 8335, RIP:<7.MONITOR>ENQSRV.MAC.10, 6-Jan-88 13:59:53 by LOMARTIRE
;TCO 7.1172 - Prevent ILLUUO and ILFPTE BUGHLTs on CI-less systems; Move
; initialization of EQLBLT and EQLBCT from EQSINI into routine ENQINI.
; UPD ID= 308, RIP:<7.MONITOR>ENQSRV.MAC.9, 20-Nov-87 07:11:02 by LOMARTIRE
;TCO 7.1145 - Make the ENQ Answer fork and ENQ Resched fork more responsive
; UPD ID= 305, RIP:<7.MONITOR>ENQSRV.MAC.8, 18-Nov-87 13:16:54 by LOMARTIRE
;TCO 7.1142 - Prevent hung forks by removing race between the setting of
; VPRTY on the sending node and the clearing of the left half of EQFKFL
; on the receiving node. Make ANSWER retry a send only when it fails
; due to SCSNEC. Don't clear the left half of EQFKFL anymore after
; a cluster state change.
; UPD ID= 300, RIP:<7.MONITOR>ENQSRV.MAC.7, 16-Nov-87 15:13:14 by MCCOLLUM
;TCO 7.1138 - Add routine ENQCST and put the VRPA back here
; UPD ID= 269, RIP:<7.MONITOR>ENQSRV.MAC.6, 6-Nov-87 11:59:08 by LOMARTIRE
;More of TCO 7.1115 - Move VRPA to ENQPAR so CFSSRV can see bit VPRTY
; UPD ID= 262, RIP:<7.MONITOR>ENQSRV.MAC.5, 5-Nov-87 15:43:10 by LOMARTIRE
;TCO 7.1115 - Prevent races between EQAFRK and EQMSG in the updating of the
; VRQA by adding the VANA (Vote Answer Area). All the Vote Responder
; routines will use this area as a work area. The VANA will be copied
; from the VRQA by the EQAFRK. It is the same format as the VRQA.
; Move the setting of VPRTY from ENQRSV to CFSRSV so cluster state changes
; are handled correctly. The clearing of the left half of EQFKFL moves too.
; Also, add word EQLBCT to count the number of blocks on the EQLBLT.
; UPD ID= 234, RIP:<7.MONITOR>ENQSRV.MAC.4, 29-Oct-87 16:22:59 by LOMARTIRE
;TCO 7.1103 - Make HDRFIP put the user code into the VRQA correctly
; UPD ID= 228, RIP:<7.MONITOR>ENQSRV.MAC.3, 28-Oct-87 14:24:24 by LOMARTIRE
;TCO 7.1096 - Prevent SKDPF1s and PITRAPs by moving ENQRSV processing into
; process context. Also, update ACTION for EQNOTF BUGCHK.
; UPD ID= 161, RIP:<7.MONITOR>ENQSRV.MAC.2, 19-Oct-87 17:12:56 by LOMARTIRE
;TCO 7.1062 - Add support for cluster-wide ENQ
; COPYRIGHT (c) DIGITAL EQUIPMENT CORPORATION 1976, 1988.
; ALL RIGHTS RESERVED.
;
; THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND COPIED
; ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE AND WITH THE
; INCLUSION OF THE ABOVE COPYRIGHT NOTICE. THIS SOFTWARE OR ANY OTHER
; COPIES THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY
; OTHER PERSON. NO TITLE TO AND OWNERSHIP OF THE SOFTWARE IS HEREBY
; TRANSFERRED.
;
; THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE
; AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT
; CORPORATION.
;
; DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE OR RELIABILITY OF ITS
; SOFTWARE ON EQUIPMENT THAT IS NOT SUPPLIED BY DIGITAL.
SEARCH ENQPAR,SCAPAR,PROLOG
TTITLE (ENQSRV,,< - Cluster-wide ENQ/DEQ Protocol Server>)
; David M. Lomartire 20-Oct-87
EXTN <HSHTBL> ;Defined in STG.MAC
IFN CLEQIN,< ;Assemble only if cluster-wide code present
Subttl Table of Contents
; Table of Contents for ENQSRV
;
; Section Page
;
;
; 1. Data Definitions
; 1.1 The VRQA (Vote Request Area) . . . . . . . . . 4
; 1.2 The VRPA (Vote Reply Area) . . . . . . . . . . 6
; 1.3 The VANA (Vote Answer Area) . . . . . . . . . 7
; 1.4 Other Variables . . . . . . . . . . . . . . . 8
; 2. SYSAP Initialization
; 2.1 EQSINI . . . . . . . . . . . . . . . . . . . . 9
; 3. Support Routines
; 3.1 The ENQ Answer fork . . . . . . . . . . . . . 10
; 3.2 The ENQ Resched fork . . . . . . . . . . . . . 11
; 3.2.1 EQRFWT (Scheduler test) . . . . . . . . 12
; 3.3 ENQCST (Notify upon Configuration Change) . . 13
; 3.4 ENQRSV (React to Configuration Change) . . . . 14
; 3.5 EQMSG (Incoming Message) . . . . . . . . . . . 15
; 3.6 LOCLOK (Find the Lock-Block) . . . . . . . . . 17
; 3.7 HDRFIQ (Fill in header from Q-Block) . . . . . 19
; 3.8 HDRFIL (Fill in header from Lock-Block) . . . 21
; 3.9 HDRFIP (Fill in header from P registers) . . . 23
; 4. Vote Requester
; 4.1 ASK4IT (Send out votes) . . . . . . . . . . . 25
; 4.1.1 EVWAIT (Scheduler test) . . . . . . . . 30
; 4.1.2 BUFHDR (Fill in Buffer Header) . . . . . 31
; 4.2 Dispatch Table (EIDSPT) . . . . . . . . . . . 32
; 4.3 EIEOKR (Reply to .EOKR vote) . . . . . . . . . 33
; 4.4 EICNTS (Reply to .CNTS vote) . . . . . . . . . 34
; 4.5 EIRSTS (Reply to .RSTS vote) . . . . . . . . . 35
; 4.6 EIPOOL (Reply to .POOL vote) . . . . . . . . . 36
; 4.7 EIQSKD (Reply to .QSKD vote) . . . . . . . . . 37
; 4.8 EILKSD (Reply to .LKSD vote) . . . . . . . . . 38
; 5. Vote Responder
; 5.1 Dispatch Table (EVDSPT) . . . . . . . . . . . 39
; 5.2 ANSWER (Send the Reply) . . . . . . . . . . . 40
; 5.3 EVEOKR (Respond to .EOKR vote) . . . . . . . . 41
; 5.4 EVCNTS (Respond to .CNTS vote) . . . . . . . . 43
; 5.5 EVRSTS (Respond to .RSTS vote) . . . . . . . . 44
; 5.6 EVPOOL (Respond to .POOL vote) . . . . . . . . 45
; 5.7 EVQSKD (Respond to .QSKD vote) . . . . . . . . 46
; 5.8 EVLKSD (Respond to .LKSD vote) . . . . . . . . 47
; 6. Interface Routines for ENQ
; 6.1 EQEOKR (Check ENQ% request) . . . . . . . . . 48
; 6.2 EQCNTS (Get lock usage counts) . . . . . . . . 50
; 6.3 EQRSTS (Get remote lock status) . . . . . . . 51
; 6.4 EQPOOL (Get pool total) . . . . . . . . . . . 53
; 6.5 EQQSKD (QSKED remote) . . . . . . . . . . . . 54
; 6.6 EQLKSD (Notify for remote LOKSKD) . . . . . . 55
; 7. End of ENQSRV . . . . . . . . . . . . . . . . . . . . 56
SUBTTL Data Definitions -- The VRQA (Vote Request Area)
EHDRSZ==^D3 ;ENQSRV Header
LDCHDR==^D5 ;The constant part of the Lock Descriptor Header
LDMASK==^D15 ;The mask block in the Lock Descriptor Header
LDASCI==^D50 ;The string in the Lock Descriptor Header
LDTSIZ==LDCHDR+LDMASK+LDASCI ;The total length of the Lock Descriptor Header
ADDATA==^D3 ;The number of words of Additional Data
;Note that 2 more words could be used before
;another SCA message buffer (#3) would be
;required for a full Request Message Set
VQSIZE==.MHUDA+EHDRSZ+LDTSIZ+ADDATA ;[7.1115] Size of the VRQA and VANA
RS VRQA,VQSIZE ;The VRQA
;Word .MHUDA of the SCA message buffer is first word of ENQSRV Header
DEFSTR EBDOFF,.MHUDA,17,18 ;Offset from .MHUDA to .EBSOD
DEFSTR EBPKTN,.MHUDA,26,9 ;The total number of messages in Request Set
DEFSTR EBPNUM,.MHUDA,35,9 ;This message number
.EBFFW==.MHUDA+1 ;This must match word SCALEN in CFS vote buffer
DEFSTR EBFLAG,.EBFFW,11,12 ;Flags used by ENQSRV
DEFSTR EQNOV,.EBFFW,0,1 ;No vote required for this lock
DEFSTR EQNO,.EBFFW,1,1 ;Another node said "NO"
DEFSTR EQANS,.EBFFW,2,1 ;This is a reply to a vote request
DEFSTR EQBLN,.EBFFW,3,1 ;Ignore level numbers for this vote
DEFSTR EQTXT,.EBFFW,4,1 ;Lock is described by a text string
DEFSTR EBCFSC,.EBFFW,17,6 ;Function code - .CFENQ - Must match CFCOD
DEFSTR EBUNIQ,.EBFFW,35,18 ;Vote unique code
.EBEOH==.EBFFW+1
DEFSTR EBNODE,.EBEOH,11,12 ;CI node number
DEFSTR EBFTYP,.EBEOH,17,6 ;Function code for ENQSRV
.EOKR==1 ;Vote from EQEOKR Interface routine
.CNTS==2 ;Vote from EQCNTS Interface routine
.RSTS==3 ;Vote from EQRSTS Interface routine
.POOL==4 ;Vote from EQPOOL Interface routine
.QSKD==5 ;Vote from EQQSKD Interface routine
.LKSD==6 ;Vote from EQLKSD Interface routine
DEFSTR EBTOTT,.EBEOH,35,18 ;Total number of users words in this packet
.EBSOD==.EBEOH+1 ;The start of the Lock Descriptor Header
DEFSTR EBQFLG,.EBSOD,11,12 ;Flags from the Q or Lock Block
;Bits 12 to 17 are RESERVED
DEFSTR EBTYPE,.EBSOD,35,18 ;ENQOFN word from Lock-Block
.EBFL1==.EBSOD+1
DEFSTR EBSTRN,.EBFL1,35,36 ;The structure name in SIXBIT
.EBFL2==.EBFL1+1
DEFSTR EBADDR,.EBFL2,35,36 ;The index block address
.EBGHV==.EBFL2+1
DEFSTR EBGRP,.EBGHV,17,18 ;The group number
DEFSTR EBHASH,.EBGHV,35,18 ;The hash value for the Lock-Block
.EBWCT==.EBGHV+1
DEFSTR EBMBWS,.EBWCT,17,18 ;The number of words in the mask block
DEFSTR EBTSWS,.EBWCT,35,18 ;The number of words in the ASCIZ string
.EBSMB==.EBWCT+1 ;The start of the Mask Block
.EBAD1==.EBSMB ;Also, the start of Additional Data in reply
.EBAD2==.EBAD1+1 ;Second word of Additional Data in reply
.EBAD3==.EBAD2+1 ;Third word of Additional Data in reply
SUBTTL Data Definitions -- The VRPA (Vote Reply Area)
VPSIZE==ADDATA+1 ;Size = Additional data plus 1 flag word
RS VRPA,VPSIZE ;The VRPA
;The first word is in the same format as word .EBFFW of the VRQA.
.VPWD0==0 ;Word 0 of the VRPA (first word)
DEFSTR VPFLAG,.VPWD0,11,12 ;Flags used by ENQSRV
DEFSTR VPNOV,.VPWD0,0,1 ;No vote required for this lock
DEFSTR VPNO,.VPWD0,1,1 ;Another node said "NO"
DEFSTR VPRTY,.VPWD0,2,1 ;A cluster state change occurred
;Bits 12 to 17 are RESERVED
DEFSTR VPUNIQ,.VPWD0,35,18 ;Vote unique code
.VPAD1==.VPWD0+1 ;Start of Additional Data in reply
.VPAD2==.VPAD1+1 ;Second word of Additional Data in reply
.VPAD3==.VPAD2+1 ;Third word of Additional Data in reply
SUBTTL Data Definitions -- The VANA (Vote Answer Area)
RS VANA,VQSIZE ;[7.1115] The VANA - same format as VRQA
SUBTTL Data Definitions -- Other Variables
;The locations VOTUNI to EQCSTF are actually located in the first 8 words
;[7.1115] of the VRQA. There are no extra words remaining.
;[7.1115] Note that since the VANA is the same format as the VRQA, it has
;[7.1115] 8 spare words at the top. Of these, there are 8 remaining.
VOTUNI==VRQA ;The vote unique code
VOTVCT==VOTUNI+1 ;The number of outstanding replies
VRBADR==VOTVCT+1 ;The address of the vote reply buffer
ASMPTR==VRBADR+1 ;Offset into VRQA used by EQMSG
RPLYND==ASMPTR+1 ;CFS host index to send reply to
EQLBLT==:RPLYND+1 ;Lock-Block action list
EQLBCT==:EQLBLT+1 ;[7.1115] Count of blocks on action list
EQCSTF==EQLBCT+1 ;[7.1138] Cluster state change flag
SUBTTL SYSAP Initialization -- EQSINI
;EQSINI - ENQSRV SYSAP Initializaton
;
;The main thing required of this routine is to obtain the VRB. This
;routine is only called during SYSAP initialization by SCA via the
;CALL @INITAB in routine SCA::.
;
;Note that the first word of the invisible area in the message buffer is
;zeroed. This is checked by CFSWDN to determine if the buffer should be
;returned to SCA. The VRB is never returned after a message send but a
;message buffer obtained to send a Request Message set is.
;
;Returns +1: Always
XRESCD
EQSINI::MOVEI T1,1
CALL <XENT SC.ABF> ;(T1/T1,T2,T3)Get message buffer for VRB
BUG.(HLT,EQNVRB,ENQ,SOFT,<ENQ - Could not get buffer for VRB>,<<T1,ERR>>,<
Cause: SC.ABF was called to acquire a buffer for use as the VRB. However,
no buffers were available in the SCA message pool. We cannot
continue without a VRB.
Action: Examine the dump for signs of damage to the SCA message pool.
Data: ERR - Error code returned by SCA.
>)
MOVEM T1,VRBADR ;Save the buffer address
SETZM -C%BINV(T1) ;No return address (checked in CFSWDN)
RET
SUBTTL Support Routines -- The ENQ Answer fork
XSWAPCD
;This is the fork which sends the reply to the received vote request.
EQARUN::MOVX T1,USRCTX ;Start with user context set
MOVEM T1,FFL
MCENTR ;Start a new process
MOVEI T1,JP%SYS+1 ;[7.1145] Set higher priority and queue 1
MOVEM T1,JOBBIT ;[7.1145] Put in PSB
MOVE T1,FORKX ;Get our fork number
MOVEM T1,EQAFRK ;Save it away
MOVEI T1,.ENECL ;Enable this process for ...
ENQ% ;... cluster-wide ENQ/DEQ
NOP ;This call cannot fail
EQALOP: MOVEI T1,EQAFWT ;The wait test
MDISMS ;Wait now
EQATOP: CIOFF ;[7.1115] Prevent state changes
HLRZ T1,EQFKFL ;Get the unique code of the vote waiting
SKIPE T1 ;[7.1115] Is there one?
IFSKP. ;[7.1115] No
CION ;[7.1115] Turn CI back on
JRST EQALOP ;[7.1115] Go wait again
ENDIF. ;[7.1115]
;Note: A restriction here is that this fork cannot get the local ENQ lock
;because the ENQ resched fork can end up locking the local database and then
;waiting for the cluster-wide lock. So, in that case, the reply fork would
;not be able to get the local lock and so no reply would be able to be sent.
;This would cause hung forks to occur during cluster state changes.
; NOINT ;Must be NOINT for lock
; S1XCT <LOKK ENQLKK> ;Lock up the local ENQ data base
;[7.1115] Now transfer the VRQA into the VANA. All the Vote Responder
;[7.1115] routines will work with the VANA. Should a cluster state
;[7.1115] change force a revote, then the changing to the VRQA (by either
;[7.1115] EQMSG or the Vote Requester) will not disrupt the VANA or the
;[7.1115] reply in progress.
XMOVEI T1,VRQA ;Get the address of the VRQA
MOVEI T2,.MHUDA(T1) ;[7.1115] This is source of BLT
LOAD T3,EBMBWS,(T1) ;[7.1115] Get the number of mask block words
LOAD T1,EBTSWS,(T1) ;[7.1115] Get the number of string words
ADDI T1,EHDRSZ+LDCHDR+ADDATA(T3) ;[7.1115] Maximum size of transfer
XMOVEI T3,VANA ;[7.1115] Destination is start of ...
ADDI T3,.MHUDA ;[7.1115] ... ENQSRV Header in the VANA
CALLX (MSEC1,XBLTAT) ;[7.1115] (T1,T2,T3/T1,T2,T3)Transfer VRQA to VANA
CION ;[7.1115] Now state changes can occur
XMOVEI T1,VANA ;[7.1115] Get address of VANA
LOAD T1,EBFTYP,(T1) ;Get the type of ENQ function
CALL @EVDSPT-1(T1) ;() Reply to the Request Message Set
; S1XCT <UNLOKK ENQLKK> ;Free up the local data base
; OKINT
JRST EQATOP ;See if it was succesfully done
SUBTTL Support Routines -- The ENQ Answer fork -- EQAFWT (Scheduler test)
RESCD
EQAFWT: HLRZ T1,EQFKFL ;Get the unique code of vote to reply to
SKIPN T1 ;Is there one waiting?
JRST 0(T4) ;No so go back to sleep
JRST 1(T4) ;Yes, so send the reply
SUBTTL Support Routines -- The ENQ Resched fork
XSWAPCD
;This is the fork which handles a cluster state change.
EQRRUN::MOVX T1,USRCTX ;Start with user context set
MOVEM T1,FFL
MCENTR ;Start a new process
MOVEI T1,JP%SYS+1 ;[7.1145] Set higher priority and queue 1
MOVEM T1,JOBBIT ;[7.1145] Put in PSB
MOVE T1,FORKX ;Get our fork number
MOVEM T1,EQRFRK ;Save it away
MOVEI T1,.ENECL ;Enable this process for ...
ENQ% ;... cluster-wide ENQ/DEQ
NOP ;This call cannot fail
EQRLOP: MOVEI T1,EQRFWT ;The wait test
MDISMS ;Wait now
EQRTOP: HRRZ T1,EQFKFL ;Are there any locks to be rescheduled?
SKIPL EQCSTF ;[7.1096] Or a cluster state change occurred?
JUMPE T1,EQRLOP ;No, so just go to sleep again
NOINT ;Must be NOINT for lock
S1XCT <LOKK ENQLKK> ;Lock up the local ENQ data base
CALLX (MSEC1,CFEQLK) ;()Now lock database cluster-wide
SETZ T1, ;[7.1096]
EXCH T1,EQCSTF ;[7.1096] Get flag and reset to zero
SKIPE T1 ;[7.1096] Did cluster change state?
CALL ENQRSV ;[7.1096] ()Yes, so mark all locks for resched
MOVE T1,EQLBLT ;Get the first block on the action list
DO.
CAIN T1,-1 ;All done with the list?
EXIT. ;Yes, all done
LOAD T2,ENQFLG,(T1) ;Get the flags from the Lock-Block
TXZN T2,EN.SDO ;Is this one slated for resched?
IFSKP.
STOR T2,ENQFLG,(T1) ;Clear the resched bit
CALL REESKD ;(T1/T1)Resched this lock
SOS EQFKFL ;One less lock to reschedule
ENDIF.
LOAD T1,ENQAFP,(T1) ;Get the next block on the list
LOOP. ;Continue search
ENDDO.
CALLX (MSEC1,CFEQUL) ;()Unlock database cluster-wide
S1XCT <UNLOKK ENQLKK> ;Free up the local data base
OKINT
JRST EQRTOP ;Do all checks again
SUBTTL Support Routines -- The ENQ Resched fork -- EQRFWT (Scheduler test)
RESCD
EQRFWT: HRRZ T1,EQFKFL ;Get the number of Lock-Blocks to reschedule
SKIPE T1 ;[7.1096] Are there any?
JRST 1(T4) ;[7.1096] Yes, so reschedule them
SKIPN EQCSTF ;[7.1096] Did cluster change state?
JRST 0(T4) ;No so go back to sleep
JRST 1(T4) ;Yes, so reschedule all locks
SUBTTL Support Routines -- ENQCST (Notify upon Configuration Change)
;[7.1138] ENQCST - Notify upon Cluster State Change
;
;This routine is called by CFSRSV to notify ENQSRV of a cluster state change.
;Various bits and locations are set such that the ENQ Resched fork will
;awaken and restart all queued Lock-Blocks. Also, the VPRTY bit is set so
;that any vote which is waiting for replies will be restarted.
;
; CALL ENQCST
;
;Returns +1: Always and trashes no ACs
; RESCD
ENQCST::SAVEAC <T1> ;Do not trash T1
XMOVEI T1,VRPA ;Get the VRPA address
SETONE VPRTY,(T1) ;Vote in progress should be restarted
SETOM EQCSTF ;Notify ENQSRV of cluster state change
RET ;All done
SUBTTL Support Routines -- ENQRSV (React to Configuration Change)
;ENQRSV - React to Cluster Configuration Change
;
;This routine is responsible for handling cluster state transitions.
;Every blocked or queued request for a lock is marked for resched.
;
;This routine expects to be called from process context with both the
;local and cluster-wide ENQ Database locks
;
; CALL ENQRSV
;
;Returns +1: Always
;
;Upon return, every queued or blocked request (on list EQLBLT) will be
;marked for a vote retry by setting bit EN.SDO. The current vote in
;progress is marked for retry by setting VPRTY in the VRPA. Note that
;this was done prior to calling this routine by ENQCST.
XSWAPCD ;[7.1096]
ENQRSV: MOVE T1,EQLBLT ;[7.1115] Get the first block on action list
DO.
CAIN T1,-1 ;All done with the list?
EXIT. ;Yes, all done
LOAD T2,ENQFLG,(T1) ;Get the flags from the Lock-Block
TXON T2,EN.SDO ;Mark that it should be rescheduled
AOS EQFKFL ;Count this only if bit not already set
STOR T2,ENQFLG,(T1) ;Replace the flags
LOAD T1,ENQAFP,(T1) ;Get the next block on the list
LOOP. ;Continue search
ENDDO.
RET ;Done
SUBTTL Support Routines -- EQMSG (Incoming Message)
;EQMSG - Handle an incoming SCA message
;
;This routine is the general message handler. It is responsible for
;handling incoming vote requests and incoming replies to vote
;requests. It is called from SCMSG (in CFSSRV) when the .SSMGR
;callback occurs.
;
; Q1,T1/ Address of incoming message buffer
; T2/ CFCOD = EBCFSC = .CFENQ
;.MHSCI(Q1),T3/ SID index into CFS tables
;.MHDCI(Q1),T4/ Buffer return address
;
;This routine expects to be called at CI interrupt level independently
;of SCAILK. It assumes that all replies to vote requests will require
;only a single SCA message buffer.
;
;Returns +1: Always, to SCMSG; Preserves T1.
XRESCD ;[7.1096]
EQMSG:: SAVEQ ;Get some work registers
TMNN EQANS,(Q1) ;Is this a reply to a vote?
IFSKP. ;Yes
LOAD T3,EBUNIQ,(Q1) ;Get the unique code
CAME T3,VOTUNI ;Does it match the vote in progress?
JRST EQMDON ;No, so ignore this message
SOS VOTVCT ;One less node to wait for
LOAD T3,EBFTYP,(Q1) ;Get the type of ENQ function
CALL @EIDSPT-1(T3) ;(Q1/) Process the reply
JRST EQMDON ;Done with the reply
ENDIF.
;This is a Request Message Set packet - an incoming vote request.
;If it is the first of the Set, then the constant header portion is transferred
;into the VRQA. The rest of the packet from offset .EBSMB onward is then
;assembled into the VRQA for this and every subsequent packet for the Set.
XMOVEI Q2,VRQA ;Get the address of the VRQA
LOAD T2,EBPNUM,(Q1) ;Get message number
CAIE T2,1 ;Is this the first of the set?
IFSKP. ;Yes
MOVEI T1,EHDRSZ+LDCHDR ;Size of constant header portion of VRQA
MOVE T2,Q1 ;Get start of buffer
ADDI T2,.MHUDA ;Offset to ENQSRV Header portion
MOVEI T3,.MHUDA(Q2) ;Beginning of ENQSRV Header in VRQA
CALLX (MSEC1,XBLTAT) ;(T1,T2,T3/T1,T2,T3)Copy constant header to VRQA
HRRM T3,ASMPTR ;Initialize offset into VRQA for transfer
SETZRO EBTSWS,(Q2) ;Clear out count of string length
ENDIF.
LOAD T1,EBTOTT,(Q1) ;Get the total number of user words for buffer
SUBI T1,EHDRSZ+LDCHDR ;Constant header is included in EBTOTT - remove
MOVE T2,Q1 ;Get start of buffer
ADDI T2,.EBSMB ;Offset to non-constant portion in buffer
MOVE T3,ASMPTR ;Get destination offset into VRQA
CALLX (MSEC1,XBLTAT) ;(T1,T2,T3/T1,T2,T3)Non-constant part to VRQA
HRRM T3,ASMPTR ;Update the assembly offset
LOAD T2,EBTSWS,(Q1) ;Get string length in buffer
LOAD T3,EBTSWS,(Q2) ;Get current count in VRQA
ADD T3,T2 ;Update to reflect new amount
STOR T3,EBTSWS,(Q2) ;Restore in VRQA
LOAD T3,EBPKTN,(Q1) ;Get the total number of packets for vote
LOAD T2,EBPNUM,(Q1) ;Get this message number
CAME T3,T2 ;Is this the last buffer
JRST EQMDON ;No, so quit now
;This is the last packet for a Request Message Set. Set up various values in
;the VRQA in preparation for the reply and dispatch to the appropriate Vote
;Responder routine to respond to the vote request.
MOVE T1,MYPOR4 ;Get our node number
STOR T1,EBNODE,(Q2) ;Put in VRQA for reply
SETONE EQANS,(Q2) ;Indicate that this is a reply message
MOVEI T1,1
STOR T1,EBPKTN,(Q2) ;Replies are only a single packet
STOR T1,EBPNUM,(Q2)
MOVEI T1,EHDRSZ+LDCHDR ;Setup length as constant header only for now
STOR T1,EBTOTT,(Q2) ;It will be INCRed as Additional Data is added
MOVE T1,.MHSCI(Q1) ;Get host index
MOVEM T1,RPLYND ;Save this for later use by ANSWER
LOAD T1,EBUNIQ,(Q2) ;Get the unique code of this vote
HRLM T1,EQFKFL ;Save this in the ENQ fork flag ...
;... This will cause the ENQ fork to wake up
EQMDON: MOVE T1,Q1 ;Get buffer address to return
RETSKP ;Return to SCMSG - buffer is returned to port
SUBTTL Support Routines -- LOCLOK (Find the Lock-Block)
;LOCLOK - Routine used to find the Lock-Block described in the VANA.
;
; The VANA contains the reassembled Request Message Set.
;
;Returns +1: No Lock-Block found
; +2: Lock-Block found with address in T1
XSWAPCD
LOCLOK: SAVEQ ;Save some work registers
STKVAR <FNDLKI>
SETZM Q3 ;Assume no Lock-Block found
XMOVEI Q1,VANA ;[7.1115] Get address of VANA
LOAD Q2,EBHASH,(Q1) ;Get hash index for Lock-Block
ADD Q2,[HSHTBL] ;Index into the table
MOVEM Q2,FNDLKI ;Save as initial index
LOCLOP: LOAD T1,ENQNHC,(Q2) ;Get next entry in hash table
CAMN T1,FNDLKI ;Back to the hash table
RET ;Yes, so search is done
MOVEM T1,Q2 ;Save as next block to step from
LOAD T2,ENQOFN,(T1) ;Get the lock type from the Lock-Block
LOAD T3,EBTYPE,(Q1) ;Get the lock type from the VRQA
HRRES T2 ;Extend the sign of both
HRRES T3
SKIPGE T3 ;Is vote an OFN or a non-file lock?
IFSKP. ;An OFN
SKIPGE T2 ;Is this lock an OFN too?
JRST LOCLOP ;No so step to the next one
LOAD T3,STRX,(T2) ;Get the structure number
MOVE T3,STRTAB(T3) ;Get SDB address
SKIPE SDBALS(T3) ;Is there an alias for this one?
SKIPA T3,SDBALS(T3) ;Yes, so use it
MOVE T3,SDBNAM(T3) ;No, so use physical name
CAME T3,.EBFL1(Q1) ;Does it match what is in the VRQA?
JRST LOCLOP ;No so step to next one
LOAD T3,STGADR,SPTH(T2) ;Get index block address
LOAD T2,EBADDR,(Q1) ;Get it from the VRQA too
ENDIF.
CAME T2,T3 ;Are they the same?
JRST LOCLOP ;No, so step to next
LOAD T2,EBMBWS,(Q1) ;Get length of mask block
ADDI T2,.MHUDA+EHDRSZ+LDCHDR ;Add constant header amount
ADD T2,Q1 ;Point to start of string in VRQA
TMNE EQTXT,(Q1) ;Does VRQA have a text string?
IFSKP. ;No
MOVE T2,(T2) ;So actually get the user code
ELSE. ;Yes this is a text string
HRLI T2,(POINT 7,0) ;So make this a byte pointer to the string
ENDIF.
CALL STVCMP ;(T1,T2/)Compare the block to the VRQA
JRST LOCLOP ;Not found - keep looking
MOVE T1,Q2 ;Found it! Get address of block
LOAD T2,ENQFLG,(Q2) ;[7.1179] Get Lock-Block flags
TXZ T2,EN.NOV ;[7.1179] We must always vote on this lock
STOR T2,ENQFLG,(Q2) ;[7.1179] Put back the flags
TXNN T2,EN.CLL ;[7.1179] Is this marked as cluster-wide?
RET ;[7.1179] No! So return "not found"
RETSKP ;Return success
ENDSV.
SUBTTL Support Routines -- HDRFIQ (Fill in header from Q-Block)
;HDRFIQ - This routine is used to fill in the header portions of the VRQA
; given only a Q-Block address. It is called from EQEOKR and EQQSKD.
;
; T1/ Address of Q-Block
;
; CALL HDRFIQ
;
;Returns +1: Always with VRQA header areas updated and with:
; T2/ Start address in VRQA at which to add Additional Data
;
;Note that this routine preserves T1. The following is the register
;convention used:
;
; P1/ Address of Q-Block
; P2/ Address of VRQA
; P3/ Address of Lock-Block
; T3 and T4 are work registers
; XSWAPCD
HDRFIQ: SAVEAC <T1,P1,P2,P3> ;Preserve T1 and get work registers
MOVE P1,T1 ;Get address of Q-Block
XMOVEI P2,VRQA ;Get the address of the VRQA
LOAD P3,ENQLBP,(P1) ;Get Lock-Block address
MOVEI T4,EHDRSZ ;Get the size of the ENQSRV Header
STOR T4,EBDOFF,(P2) ;Save as offset to .EBSOD word
SETZRO EBFLAG,(P2) ;Clear the flags
LOAD T4,ENQFLG,(P3) ;Get flags from Lock-Block
TXNN T4,EN.TXT ;Is this lock described by a text string?
IFSKP.
SETONE EQTXT,(P2) ;Yes so indicate this in VRQA
ENDIF.
MOVEI T4,.CFENQ ;Get function code for CFS
STOR T4,EBCFSC,(P2) ;Put in VRQA
MOVE T4,MYPOR4 ;Get our node number
STOR T4,EBNODE,(P2) ;Put in VRQA
LOAD T4,ENQFLG,(P1) ;Get flags from Q-Block
STOR T4,EBQFLG,(P2) ;Put in VRQA
LOAD T4,ENQGRP,(P1) ;Get the group number from Q-Block
STOR T4,EBGRP,(P2) ;Put in VRQA
LOAD T3,ENQOFN,(P3) ;Get the OFN from the Lock-Block
STOR T3,EBTYPE,(P2) ;Put in VRQA
HRRES T3 ;Extend the sign
SKIPGE T3 ;Is this an OFN or a non-file lock?
IFSKP. ;An OFN
LOAD T4,STRX,(T3) ;Get the structure number
MOVE T4,STRTAB(T4) ;Get SDB address
SKIPE SDBALS(T4) ;Is there an alias for this one?
SKIPA T4,SDBALS(T4) ;Yes, so use it
MOVE T4,SDBNAM(T4) ;No, so use physical name
STOR T4,EBSTRN,(P2) ;Put in VRQA
LOAD T4,STGADR,SPTH(T3) ;Get index block address
STOR T4,EBADDR,(P2) ;Put in VRQA
ELSE. ;A non-file object
SETZRO EBSTRN,(P2) ;Clear both the structure name ...
SETZRO EBADDR,(P2) ;... and the index block address in VRQA
ENDIF.
LOAD T4,ENQHSH,(P3) ;Get hash value from Lock-Block
STOR T4,EBHASH,(P2) ;Put in VRQA
LOAD T4,ENQLEN,(P3) ;Get the length of the Lock-Block
SUBI T4,LBLEN ;Compute length of string or user code
STOR T4,EBTSWS,(P2) ;Put in VRQA
LOAD T3,ENQNMS,(P3) ;Get length of mask block from Lock-Block
STOR T3,EBMBWS,(P2) ;Put in VRQA
ADD T4,T3 ;Add it to the running total
ADDI T4,EHDRSZ+LDCHDR ;Add in the constant header portion
STOR T4,EBTOTT,(P2) ;Put in VRQA as total size less Additional Data
LOAD T2,ENQMSK,(P1) ;Get the pointer to the mask block
MOVEI T3,.EBSMB(P2) ;Setup destination in VRQA
LOAD T1,EBMBWS,(P2) ;Get length of mask block
CALLX (MSEC1,XBLTAT) ;(T1,T2,T3/T1,T2,T3)Move mask block into VRQA
MOVE T2,P3 ;Get address of Lock-Block
ADDI T2,.ENTXT ;Offset to beginning of string in Lock-Block
LOAD T1,EBTSWS,(P2) ;Get length of string
CALLX (MSEC1,XBLTAT) ;(T1,T2,T3/T1,T2,T3)Move string into the VRQA
MOVE T2,T3 ;Return pointer to where Additional Data goes
RET ;Done
SUBTTL Support Routines -- HDRFIL (Fill in header from Lock-Block)
;HDRFIL - This routine is used to fill in the header portions of the VRQA
; given only a Lock-Block address. It is called from EQCNTS, EQPOOL,
; and EQLKSD.
;
; T1/ Address of Lock-Block
;
; CALL HDRFIL
;
;Returns +1: Always with VRQA header areas updated and with:
; T2/ Start address in VRQA at which to add Additional Data
;
;Note that this routine preserves T1. The following is the register
;convention used:
;
; P1/ Address of Lock-Block
; P2/ Address of VRQA
; T3 and T4 are work registers
; XSWAPCD
HDRFIL: SAVEAC <T1,P1,P2> ;Preserve T1 and get work registers
MOVE P1,T1 ;Get address of Lock-Block
XMOVEI P2,VRQA ;Get the address of the VRQA
MOVEI T4,EHDRSZ ;Get the size of the ENQSRV Header
STOR T4,EBDOFF,(P2) ;Save as offset to .EBSOD word
SETZRO EBFLAG,(P2) ;Clear the flags
MOVEI T4,.CFENQ ;Get function code for CFS
STOR T4,EBCFSC,(P2) ;Put in VRQA
MOVE T4,MYPOR4 ;Get our node number
STOR T4,EBNODE,(P2) ;Put in VRQA
LOAD T4,ENQFLG,(P1) ;Get flags from Lock-Block
STOR T4,EBQFLG,(P2) ;Put in VRQA
TXNN T4,EN.TXT ;Is this lock described by a text string?
IFSKP.
SETONE EQTXT,(P2) ;Yes so indicate this in VRQA
ENDIF.
SETZRO EBGRP,(P2) ;No group number is sent - record in VRQA
LOAD T3,ENQOFN,(P1) ;Get the OFN from the Lock-Block
STOR T3,EBTYPE,(P2) ;Put in VRQA
HRRES T3 ;Extend the sign
SKIPGE T3 ;Is this an OFN or a non-file lock?
IFSKP. ;An OFN
LOAD T4,STRX,(T3) ;Get the structure number
MOVE T4,STRTAB(T4) ;Get SDB address
SKIPE SDBALS(T4) ;Is there an alias for this one?
SKIPA T4,SDBALS(T4) ;Yes, so use it
MOVE T4,SDBNAM(T4) ;No, so use physical name
STOR T4,EBSTRN,(P2) ;Put in VRQA
LOAD T4,STGADR,SPTH(T3) ;Get index block address
STOR T4,EBADDR,(P2) ;Put in VRQA
ELSE. ;A non-file object
SETZRO EBSTRN,(P2) ;Clear both the structure name ...
SETZRO EBADDR,(P2) ;... and the index block address in VRQA
ENDIF.
LOAD T4,ENQHSH,(P1) ;Get hash value from Lock-Block
STOR T4,EBHASH,(P2) ;Put in VRQA
LOAD T4,ENQLEN,(P1) ;Get the length of the Lock-Block
SUBI T4,LBLEN ;Compute length of string or user code
STOR T4,EBTSWS,(P2) ;Put in VRQA
SETZRO EBMBWS,(P2) ;No mask block is sent - record in VRQA
ADDI T4,EHDRSZ+LDCHDR ;Add in the constant header portion
STOR T4,EBTOTT,(P2) ;Put in VRQA as total size less Additional Data
MOVE T2,P1 ;Get address of Lock-Block
ADDI T2,.ENTXT ;Offset to beginning of string in Lock-Block
MOVEI T3,.EBSMB(P2) ;Setup destination in VRQA
LOAD T1,EBTSWS,(P2) ;Get length of string
CALLX (MSEC1,XBLTAT) ;(T1,T2,T3/T1,T2,T3)Move string into the VRQA
MOVE T2,T3 ;Return pointer to where Additional Data goes
RET ;Done
SUBTTL Support Routines -- HDRFIP (Fill in header from P registers)
;HDRFIP - This routine is used to fill in the header portions of the VRQA
; given only the P registers, Q1, and hash index. It is only called
; from EQRSTS.
;
; T1/ Hash value for Lock-Block
; P1-P5 set up by call to VALREQ and HASH
; Q1/ Address of lock request in user's space; set up by VALARG
;
; CALL HDRFIP
;
;Returns +1: Always with VRQA header areas updated and with:
; T2/ Start address in VRQA at which to add Additional Data
;
;Note that this routine preserves T1. The following is the register
;convention used:
;
; Q1/ Address of VRQA
; XSWAPCD
HDRFIP: SAVEAC <T1,Q1,Q2> ;Preserve T1 and get a work register
MOVE Q2,Q1 ;[7.1103] Save the user's address for a moment
XMOVEI Q1,VRQA ;Get the address of the VRQA
STOR T1,EBHASH,(Q1) ;Put hash value in VRQA
MOVEI T4,EHDRSZ ;Get the size of the ENQSRV Header
STOR T4,EBDOFF,(Q1) ;Save as offset to .EBSOD word
SETZRO EBFLAG,(Q1) ;Clear the flags
MOVEI T4,.CFENQ ;Get function code for CFS
STOR T4,EBCFSC,(Q1) ;Put in VRQA
MOVE T4,MYPOR4 ;Get our node number
STOR T4,EBNODE,(Q1) ;Put in VRQA
HLRZ T4,P1 ;Get flags from P1
STOR T4,EBQFLG,(Q1) ;Put in VRQA
MOVEI T1,1 ;Get length of user code word
MOVEI T2,.ENQUC-.ENQLV(Q2) ;[7.1103] Get location of user code
LOAD T4,NMFLG,P2 ;Get bits 0-2 to see if user specified code
CAIN T4,NUMVAL ;5B2 cannot be a string pointer
IFSKP. ;This is a text string
SETONE EQTXT,(Q1) ;Yes so indicate this in VRQA
MOVE T1,P4 ;Get string length instead of user code length
HRRZ T2,P2 ;Get location of string from pointer
ENDIF.
STOR T1,EBTSWS,(Q1) ;Put string/user-code length in VRQA
MOVEI T3,.EBSMB(Q1) ;Setup destination in VRQA
CALLX (MSEC1,BLTUM1) ;(T1,T2,T3/T1,T2,T3)Move string into the VRQA
MOVEM T3,Q2 ;Save pointer to where Additional Data goes
SETZRO EBMBWS,(Q1) ;No mask block is sent - record in VRQA
HRRZ T4,P5 ;Get the group from P5
STOR T4,EBGRP,(Q1) ;Put in VRQA
HRRZ T3,P1 ;Get the OFN from P1
STOR T3,EBTYPE,(Q1) ;Put in VRQA
HRRES T3 ;Extend the sign
SKIPGE T3 ;Is this an OFN or a non-file lock?
IFSKP. ;An OFN
LOAD T4,STRX,(T3) ;Get the structure number
MOVE T4,STRTAB(T4) ;Get SDB address
SKIPE SDBALS(T4) ;Is there an alias for this one?
SKIPA T4,SDBALS(T4) ;Yes, so use it
MOVE T4,SDBNAM(T4) ;No, so use physical name
STOR T4,EBSTRN,(Q1) ;Put in VRQA
LOAD T4,STGADR,SPTH(T3) ;Get index block address
STOR T4,EBADDR,(Q1) ;Put in VRQA
ELSE. ;A non-file object
SETZRO EBSTRN,(Q1) ;Clear both the structure name ...
SETZRO EBADDR,(Q1) ;... and the index block address in VRQA
ENDIF.
LOAD T4,EBTSWS,(Q1) ;Get string length in VRQA
ADDI T4,EHDRSZ+LDCHDR ;Add in the constant header portion
STOR T4,EBTOTT,(Q1) ;Put in VRQA as total size less Additional Data
MOVE T2,Q2 ;Return pointer to where Additional Data goes
RET ;Done
SUBTTL Vote Requester -- ASK4IT (Send out votes)
;ASK4IT - Routine called by Interface Routines to send out a Request
; Message Set to every TOPS-20 node running version 7.0 or
; greater.
;
;This routine expects the VRQA to have been completed with the Request
;to be sent. Also, it is to be called with the ENQ Database Lock Token
;obtained (thus, NOINT).
;
; CALL ASK4IT
;
;Returns +1: Failure, error code in T1
; +2: Success, results of the vote in the VRPA
;
;Upon successful return from this routine, the VRPA will have been
;updated with the results of the vote. This is done by various other
;Vote Requester routines.
; XSWAPCD
ASK4IT: TRVAR <BUFL,BUFN,RTN,REMTOT,REMSUC>
SAVEQ ;Get some work registers
ASKTOP: SETZM VRPA ;Clear the entire VRPA
MOVE T1,[VRPA,,VRPA+1]
BLT T1,VRPA+VPSIZE-1
XMOVEI Q3,VRPA
SETONE VPNOV,(Q3) ;Set bit EQ.NOV in the VRPA
AOS T1,VOTUNI ;Get a new unique code
STOR T1,VPUNIQ,(Q3)
SETZM VOTVCT ;Not waiting on any nodes
ASKLOP: CIOFF ;Lock out connection state changes
SKIPN CFSCMC ;Any connects outstanding?
IFSKP. ;If so
CION ;Release lock
MOVEI T1,DISET ;Wait for outstanding connects ...
HRLI T1,CFSCMC ;... to go to zero
MDISMS
JRST ASKLOP ;Check again
ENDIF.
SKIPN T1,DLYLOK ;A vote delay in effect?
IFSKP. ;If so
SUB T1,TODCLK ;Get relative time
IFG. T1 ;If we still need to wait...
CION ;Release lock
CALLX (MSEC1,SETBKT);(T1/T1)Compute wait time
HRRI T1,CFRCNW ;Wait for a while
MDISMS
JRST ASKLOP ;Do all checks again
ENDIF.
ENDIF.
SKIPE CFSHCT ;Are there any other nodes out there?
IFSKP. ;No, so quit now
CION ;Release lock
RETSKP ;Return success
ENDIF.
CION ;Allow connect state changes again
MOVSI Q1,-HSTSIZ ;Loop over the entire CFSHST table
;Now, scan the CFSHST table and send a Request Message Set to every
;TOPS-20 node running version 7.0 or greater in the cluster.
ASKVOT: TMNE VPNO,(Q3) ;Has the vote already been denied?
JRST ASKCHK ;[8848] Yes, stop and wait for all replies
SKIPLE T1,CFSHST(Q1) ;Get the CID
SKIPL CFHSTS(Q1) ;Is there a valid CID in this slot
JRST ASKNXT ;No, try next slot
CALL <XENT SC.NOD> ;(T1/T1,T2)Get the CI node number for CID
SKIPGE T2 ;Was this a valid CID?
JRST ASKNXT ;No skip it and do next slot
CALLX (MSEC1,IS7020) ;(T2/)Is this a version 7.0 or greater node?
JRST ASKNXT ;No, so skip it
;This node can be sent to. Format the VRQA into a Request Message Set
;and send it.
XMOVEI T1,VRQA ;Get the address of VRQA
LOAD T2,EBTOTT,(T1) ;Get the total number of user words in VRQA
SUBI T2,EHDRSZ+LDCHDR ;Remove header amounts
HRLI T2,.EBSMB-.MHUDA ;Starting location is mask block
ADDI T1,.EBSMB ;Offset to start of data to be transfered
CALL SC.BRK ;(T1,T2/T1,T2,T3)Break into SCA message buffers
RETBAD (ENQX24) ;Error - must have no more SCA space
MOVEM T1,BUFL ;Save the buffer list address
MOVEM T2,BUFN ;Save the number of buffers
MOVEM T3,RTN ;Save the return address
;The Mask Block and ASCIZ String have been placed in SCA message buffer(s).
;Update the header portions of the buffers and send them to the node.
MOVE T1,.PKFLI(T1) ;Get the next buffer in the list
EXCH T1,BUFL ;It is next buffer and BUFL is current buffer
MOVEM T3,-C%BINV(T1) ;Put return address in Invisible Area
CALL BUFHDR ;(T1/T1)Update various header values
XMOVEI T2,VRQA ;Get the address of the VRQA
MOVE T3,BUFN ;Get total number of buffers
STOR T3,EBPKTN,(T1) ;Put in message buffer
MOVEI T3,1 ;Say that this ...
STOR T3,EBPNUM,(T1) ;... is the first packet
MOVE T3,VOTUNI ;Get unique code
STOR T3,EBUNIQ,(T1) ;Put in message buffer
LOAD T3,EBTOTT,(T2) ;Get total number of user words from VRQA
CAILE T3,C%MUDA ;Is it greater than maximum possible?
MOVEI T3,C%MUDA ;Yes, so use maximum for 1st buffer
STOR T3,EBTOTT,(T1) ;Put in message buffer
LOAD T4,EBTOTT,(T2) ;Get total again from VRQA
SUB T4,T3 ;Reduce to reflect remaining String and Data
MOVEM T4,REMTOT ;Remember the remaining amount to send
SUBI T3,EHDRSZ+LDCHDR ;Take out constant header part
LOAD T4,EBMBWS,(T2) ;Get size of Mask Block
SUB T3,T4 ;Take away - this is max string size for buffer
LOAD T4,EBTSWS,(T2) ;Get the total size of the string
SUB T4,T3 ;Take max size away from total size
IFLE. T4 ;Does the string fit in the block?
SETZ T4, ;Yes, so left over amount is zero
LOAD T3,EBTSWS,(T2) ;And the size of the string is in VRQA
ENDIF.
MOVEM T4,REMSUC ;Store left over as remaining String to send
STOR T3,EBTSWS,(T1) ;Store the string size in the buffer
;Now the header portion of the first buffer is complete. The entire Mask
;Block, and as much of the String and Addtional Data as can fit is also
;present. Note that REMTOT now has the number of user words left
;to send (less the constant header amount). REMSUC has the number
;of words of String left to send. If this is zero, but REMTOT is not,
;then what is left to send is Additional Data.
;
;The buffer, which was obtained from SCA free space, is sent with F.RTB set
;so that it does not go on the port's message free queue. When the .SSMSC
;callback occurs, the return address stored in the packet (should be SC.RBF)
;will be called to return the buffer.
;
;Note: The value of C%OVHW+.PKLEN is subtracted from the total because SCA
;and PHYKLP add it on to account for the message buffer overhead. But, this
;value is already included in the .MHUDA symbol. So, the maximum value for
;a message length which can be specified to SCA is C%MUDA-C%OVHW-.PKLEN.
;Otherwise a KLPERR due to invalid packet length or a SCAPTL BUGHLT
;results. It appears that this behavior is incorrect and that it is sending
;C%OVHW+.PKLEN extra words for every message packet!
LOAD T3,EBTOTT,(T1) ;Get the number of user words
MOVE Q2,T1 ;Save buffer address in case of failure
BLCAL. (<XENT SC.SMG>,<CFSHST(Q1),[F.RTB+F.SPM],T3,T1,[CFSPRI],[0],[0]>)
IFNSK. ;Some kind of error
MOVE T1,Q2
CALL @-C%BINV(T1) ;(T1/)Return the buffer
SKIPE T1,BUFL ;Is there another buffer?
CALL @RTN ;(T1/)Yes, return it too
JRST ASKTOP ;Try again
ENDIF.
SKIPN T1,BUFL ;Is there another buffer?
JRST ASKSDN ;No, try another node
;The Request Message Set requires 2 SCA buffers. First, do some sanity
;checking.
SKIPG T2,REMTOT ;Any remaining user words to send
BUG.(HLT,EQSTOT,ENQSRV,SOFT,<ENQSRV - VRQA value of EBTOTT is too small>,,<
Cause: The value in variable BUFL indicates that SC.BRK thought that the
VRQA would require multiple buffers. But, the value of EBTOTT is
less than or equal to zero which means that there is nothing more
to send.
Action: Examine the dump for signs of a miscalculation in either SC.BRK
or the setting of EBTOTT.
>)
CAILE T2,C%MUDA ;Will they fit in just one more buffer?
BUG.(HLT,EQLTOT,ENQSRV,SOFT,<ENQSRV - VRQA value of EBTOTT is too big>,,<
Cause: The value in variable BUFL indicates that SC.BRK thought that the
VRQA would require multiple buffers. But, the value of EBTOTT
indicates that the rest to send will not fit in just 1 more buffer.
Action: Examine the dump for signs of a miscalculation in either SC.BRK
or the setting of EBTOTT.
>)
SKIPE .PKFLI(T1) ;Is there yet another buffer?
BUG.(HLT,EQBLNK,ENQSRV,SOFT,<ENQSRV - Bad list of SCA buffers>,,<
Cause: The .PKFLI pointer in the second buffer points to yet another
buffer. Presently, the code only expects to send 2 SCA messages
for any Request Message Set.
Action: Examine the dump for signs of a miscalculation in SC.BRK.
>)
MOVE T3,RTN ;Get the return address
MOVEM T3,-C%BINV(T1) ;Put return address in Invisible Area
CALL BUFHDR ;(T1/T1)Update various header values
XMOVEI T2,VRQA ;Get the address of the VRQA
MOVE T3,BUFN ;Get total number of buffers
STOR T3,EBPKTN,(T1) ;Put in message buffer
STOR T3,EBPNUM,(T1) ;Say this is the second and last packet
MOVE T3,VOTUNI ;Get unique code
STOR T3,EBUNIQ,(T1) ;Put in message buffer
MOVE T3,REMSUC ;Get the total size of the string remaining
STOR T3,EBTSWS,(T1) ;Store the string size in the buffer
SETZRO EBMBWS,(T1) ;No mask block is sent
MOVE T3,REMTOT ;Get total number of user words remaining
ADDI T3,EHDRSZ+LDCHDR ;Add on the constant header portion
STOR T3,EBTOTT,(T1) ;Put in message buffer
;Now send the second and last buffer.
MOVE Q2,T1 ;Save buffer address in case of failure
BLCAL. (<XENT SC.SMG>,<CFSHST(Q1),[F.RTB+F.SPM],T3,T1,[CFSPRI],[0],[0]>)
IFNSK. ;Some kind of error
MOVE T1,Q2
CALL @-C%BINV(T1) ;(T1/)Return the buffer
JRST ASKTOP ;Try again
ENDIF.
ASKSDN: AOS VOTVCT ;Yes, waiting for another reply
ASKNXT: AOBJN Q1,ASKVOT ;Try the next CFS host slot
;The votes have now been sent to all the nodes. Wait for replies.
ASKCHK: TMNE VPRTY,(Q3) ;Did a cluster-state change occur
JRST ASKTOP ;Yes, restart vote
SKIPN VOTVCT ;Are all the votes in?
RETSKP ;Yes, so return now
;Not all the replies are in yet. The fork will wait in EVWAIT until
;they all arrive, a cluster state change occurs, or a denied reply
;arrives.
MOVEI T1,EVWAIT ;Get address of wait routine
MDISMS ;Wait
JRST ASKCHK ;Check on response
ENDTV.
SUBTTL Vote Requester -- ASK4IT (Send out votes) -- EVWAIT (Scheduler test)
;EVWAIT - Scheduler test used by ASK4IT. Causes the fork to wake up when
; all the outstanding replies have arrived or a cluster state change
; occurs.
RESCD
EVWAIT: SKIPN VOTVCT ;Are all the votes in?
JRST 1(T4) ;Yes, so wake up
MOVEI T1,VRPA ;Get address of VRPA
TMNE VPRTY,(T1) ;Has a cluster state change occurred?
JRST 1(T4) ;Yes, so wake up
JRST 0(T4) ;No need to wake up yet
SUBTTL Vote Requester -- ASK4IT (Send out votes) -- BUFHDR (Fill in Buffer Header)
;BUFHDR - Routine used to transfer various header values from the VRQA
; into an SCA message buffer header portion
;
; T1/ Address of SCA message buffer
;
; CALL BUFHDR
;
;Returns +1: Always, with the following values updated in the SCA
; message buffer: EBDOFF, EBFLAG, EBCFSC, EBNODE, EBFTYP,
; EBQFLG, EBTYPE, EBSTRN, EBADDR, EBGRP, EBHASH, EBMBWS.
;
;Preserves T1.
XSWAPCD
BUFHDR: SAVEAC <T1> ;Preserve T1
XMOVEI T2,VRQA ;Get the address of the VRQA
LOAD T3,EBDOFF,(T2) ;Transfer ...
STOR T3,EBDOFF,(T1) ;... field EBDOFF from VRQA to buffer
LOAD T3,EBFLAG,(T2) ;Transfer ...
STOR T3,EBFLAG,(T1) ;... field EBFLAG from VRQA to buffer
LOAD T3,EBCFSC,(T2) ;Transfer ...
STOR T3,EBCFSC,(T1) ;... field EBCFSC from VRQA to buffer
LOAD T3,EBNODE,(T2) ;Transfer ...
STOR T3,EBNODE,(T1) ;... field EBNODE from VRQA to buffer
LOAD T3,EBFTYP,(T2) ;Transfer ...
STOR T3,EBFTYP,(T1) ;... field EBFTYP from VRQA to buffer
LOAD T3,EBQFLG,(T2) ;Transfer ...
STOR T3,EBQFLG,(T1) ;... field EBQFLG from VRQA to buffer
LOAD T3,EBTYPE,(T2) ;Transfer ...
STOR T3,EBTYPE,(T1) ;... field EBTYPE from VRQA to buffer
LOAD T3,EBSTRN,(T2) ;Transfer ...
STOR T3,EBSTRN,(T1) ;... field EBSTRN from VRQA to buffer
LOAD T3,EBADDR,(T2) ;Transfer ...
STOR T3,EBADDR,(T1) ;... field EBADDR from VRQA to buffer
LOAD T3,EBGRP,(T2) ;Transfer ...
STOR T3,EBGRP,(T1) ;... field EBGRP from VRQA to buffer
LOAD T3,EBHASH,(T2) ;Transfer ...
STOR T3,EBHASH,(T1) ;... field EBHASH from VRQA to buffer
LOAD T3,EBMBWS,(T2) ;Transfer ...
STOR T3,EBMBWS,(T1) ;... field EBMBWS from VRQA to buffer
RET ;All done
SUBTTL Vote Requester -- Dispatch Table (EIDSPT)
;This dispatch table is invoked from EQMSG when the reply to a vote
;request arrives
XRESCD
EIDSPT: XADDR. (EIEOKR) ;.EOKR
XADDR. (EICNTS) ;.CNTS
XADDR. (EIRSTS) ;.RSTS
XADDR. (EIPOOL) ;.POOL
XADDR. (EIQSKD) ;.QSKD
XADDR. (EILKSD) ;.LKSD
SUBTTL Vote Requester -- EIEOKR (Reply to .EOKR vote)
;EIEOKR - Routine which processes the replies to the vote request
; generated by the EVEOKR routine.
;
; Q1/ Address of incoming SCA message buffer (the reply)
;
;Returns +1: Always, with VRPA updated
; XRESCD
EIEOKR: XMOVEI T1,VRPA ;Get address of VRPA
TMNE VPNO,(T1) ;Has a no vote already arrived?
RET ;Yes, so just return
TMNN EQNO,(Q1) ;Was the reply a "NO"?
IFSKP. ;Yes
SETONE VPNO,(T1) ;Say it was denied in VRPA
MOVE T2,.EBAD1(Q1) ;Get error code returned
MOVEM T2,.VPAD1(T1) ;Put in VRPA
ENDIF.
TMNE EQNOV,(Q1) ;Did the other node know about this lock?
IFSKP. ;Yes
SETZRO VPNOV,(T1) ;Clear "no vote required" bit in VRPA
ENDIF.
RET ;Done
SUBTTL Vote Requester -- EICNTS (Reply to .CNTS vote)
;EIEOKR - Routine which processes the replies to the vote request
; generated by the EQCNTS routine.
;
; Q1/ Address of incoming SCA message buffer (the reply)
;
;Returns +1: Always, with VRPA updated
; XRESCD
EICNTS: XMOVEI T1,VRPA ;Get address of VRPA
MOVE T2,.EBAD1(Q1) ;Get the counts just returned
ADDM T2,.VPAD1(T1) ;Add to the running total
RET ;Done
SUBTTL Vote Requester -- EIRSTS (Reply to .RSTS vote)
;EIRSTS - Routine which processes the replies to the vote request
; generated by the EQRSTS routine.
;
; Q1/ Address of incoming SCA message buffer (the reply)
;
;Returns +1: Always, with VRPA updated
; XRESCD
EIRSTS: TMNE EQNO,(Q1) ;Was the reply a "NO"?
RET ;Yes so just return
XMOVEI T1,VRPA ;Get address of VRPA
HLRZ T2,.EBAD2(Q1) ;Get the job number
CAIN T2,-1 ;Was there one?
IFSKP. ;Yes
HRLM T2,.VPAD2(T1) ;Put in VRPA
HLRZ T2,.EBAD1(Q1) ;Get the lock access
HRLM T2,.VPAD1(T1) ;Put in VRPA
ENDIF.
HRRZ T2,.EBAD1(Q1) ;Get the level number
HRRZ T3,.VPAD1(T1) ;Get the number in the VRPA
CAMLE T2,T3 ;Is it greater than what is there now?
HRRM T2,.VPAD1(T1) ;Put in VRPA
HRRZ T2,.EBAD2(Q1) ;Get number of sharers
ADDM T2,.VPAD2(T1) ;Add to running total in VRPA
MOVE T2,.EBAD3(Q1) ;Get the time stamp
SKIPE .VPAD3(T1) ;Is there any value yet?
CAMGE T2,.VPAD3(T1) ;Is it less than what is there now?
MOVEM T2,.VPAD3(T1) ;Yes so put in VRPA
RET ;Done
SUBTTL Vote Requester -- EIPOOL (Reply to .POOL vote)
;EIPOOL - Routine which processes the replies to the vote request
; generated by the EQPOOL routine.
;
; Q1/ Address of incoming SCA message buffer (the reply)
;
;Returns +1: Always, with VRPA updated
; XRESCD
EIPOOL: XMOVEI T1,VRPA ;Get address of VRPA
MOVE T2,.EBAD1(Q1) ;Get the count just returned
ADDM T2,.VPAD1(T1) ;Add to the running total
RET ;Done
SUBTTL Vote Requester -- EIQSKD (Reply to .QSKD vote)
;EIQSKD - Routine which processes the replies to the vote request
; generated by the EVQSKD routine.
;
; Q1/ Address of incoming SCA message buffer (the reply)
;
;Returns +1: Always, with VRPA updated
; XRESCD
EIQSKD: XMOVEI T1,VRPA ;Get address of VRPA
TMNE VPNO,(T1) ;Has a no vote already arrived?
RET ;Yes, so just return
TMNN EQNO,(Q1) ;Was the reply a "NO"?
IFSKP. ;Yes
SETONE VPNO,(T1) ;Say it was denied in VRPA
RET ;Done
ENDIF.
MOVE T2,.EBAD1(Q1) ;Get the count just returned
ADDM T2,.VPAD1(T1) ;Add to the running total
RET ;Done
SUBTTL Vote Requester -- EILKSD (Reply to .LKSD vote)
;EILKSD - Routine which processes the replies to the vote request
; generated by the EQLKSD routine.
;
; Q1/ Address of incoming SCA message buffer (the reply)
;
;Returns +1: Always. No action needs to be taken for this reply.
; It is just needed so that it is assured that all the
; systems have received and processed the rescheduling
; notification.
; XRESCD
EILKSD: RET ;The reply is meaningless
SUBTTL Vote Responder -- Dispatch Table (EVDSPT)
XSWAPCD
EVDSPT: XADDR. (EVEOKR) ;.EOKR
XADDR. (EVCNTS) ;.CNTS
XADDR. (EVRSTS) ;.RSTS
XADDR. (EVPOOL) ;.POOL
XADDR. (EVQSKD) ;.QSKD
XADDR. (EVLKSD) ;.LKSD
SUBTTL Vote Responder -- ANSWER (Send the Reply)
;ANSWER - Send the Reply to a Request Message Set
;
;This routine is called from each of the dispatch routines in EVDSPT
;in order to send the reply to the vote just received. It expects that
;the VANA contains the reply to be sent. The VANA will be transferred
;into the VRB and sent back to the node which sent us the Request
;Message Set. Also, RPLYND is expected to contain the CFS host index
;from which to get the CID of the node to receive the reply. The left
;half of EQFKFL contains the unique code of the vote which we should
;be replying to.
;
; CALL ANSWER
;
;Returns +1: Always
;
;[7.1115] Note: The unique code in the VANA should match the unique code
;[7.1115] in the VRQA. The VRQA unique code is also contained in the left
;[7.1115] half of EQFKFL. If it does not, then a cluster state change must
;[7.1115] have occurred and another node is now revoting on one of its
;[7.1115] blocks on the EQLBLT. So, the VRQA contains a new vote request
;[7.1115] to reply to and the one in the VANA is not valid and can be
;[7.1115] ignored.
; XSWAPCD
ANSWER: XMOVEI T2,VANA ;[7.1115] Get the address of the VANA
CIOFF ;Protect against state changes for a moment
LOAD T1,EBUNIQ,(T2) ;[7.1115] Get unique code of vote in VANA
HLRZ T3,EQFKFL ;Get the unique code of the vote to respond to
CAMN T1,T3 ;Are they the same?
IFSKP. ;No, a state change happened previously
CION ;Unlock the CI
RET ;Return now without replying to old vote
ENDIF.
LOAD T1,EBTOTT,(T2) ;Get the total number of user words
MOVE T3,VRBADR ;Get address to use for reply buffer
ADDI T2,.MHUDA ;Beginning of ENQSRV Header in VRQA
ADDI T3,.MHUDA ;Beginning of ENQSRV Header in VRB
CALLX (MSEC1,XBLTAT) ;(T1,T2,T3/T1,T2,T3)Transfer VRQA into VRB
MOVE T2,VRBADR ;Get VRB address again
SETZRO EBMBWS,(T2) ;Replies never include a mask block ...
SETZRO EBTSWS,(T2) ;... or a text string/user code
LOAD T3,EBTOTT,(T2) ;Get the number of user words
MOVE T1,RPLYND ;Get host index
CION ;Unlock the CI for the reply
BLCAL. (<XENT SC.SMG>,<CFSHST(T1),[F.RTB+F.SPM],T3,T2,[CFSPRI],[0],[0]>)
IFNSK. ;[7.1142] Error - send failed!
CAIN T1,SCSNEC ;[7.1142] Did it fail due to lack of credit?
JRST ANSWER ;[7.1142] Yes, try again
ENDIF. ;[7.1142]
CIOFF ;[7.1142] Protect against state changes
XMOVEI T2,VANA ;[7.1142] Get the address of the VANA
LOAD T1,EBUNIQ,(T2) ;[7.1142] Get unique code of vote in VANA
HLRZ T3,EQFKFL ;[7.1142] Get unique code of vote to respond to
CAMN T1,T3 ;[7.1142] Are they the same?
HRRZS EQFKFL ;[7.1142] Reply completed - clear out unique code
CION ;[7.1142] Allow interrupts again
RET ;All done
SUBTTL Vote Responder -- EVEOKR (Respond to .EOKR vote)
;EVEOKR - This routine sends a reply to a vote request just received.
; The vote is of type .EOKR which is sent by the EQEOKR routine.
;
; The VANA contains the reassembled Request Message Set.
;
;Returns +1: Always once the reply message is sent
; XSWAPCD
EVEOKR: SAVEAC <Q2> ;Save a work register
XMOVEI Q2,VANA ;[7.1115] Get address of VANA
SETZRO <EQNO,EQNOV>,(Q2) ;Clear status flags in VRQA
CALL LOCLOK ;(/T1)Find the Lock-Block for this vote
IFNSK. ;There isn't one!
SETONE EQNOV,(Q2) ;No vote is required as far as we are concerned
JRST EVEOK7 ;Send the approval
ENDIF.
TXNN T2,EN.LTL ;Long term lock?
IFSKP. ;Yes
LOAD T2,ENQNLQ,(T1) ;Now see if the lock is free
CAME T2,T1 ;It is free if it points to itself
ANSKP. ;Yes, it is free
SETONE EQNOV,(Q2) ;No vote is required as far as we are concerned
JRST EVEOK7 ;Send the approval
ENDIF.
;At this point, the Lock-Block is active on this system. The same
;type of checks which occured in routine ENQ9 on the other node must
;now be performed here.
LOAD T2,ENQNMS,(T1) ;Get size of mask block
JUMPE T2,EVEOK5 ;Skip checks if zero
LOAD T3,EBMBWS,(Q2) ;Get mask block size of vote request
MOVEM T3,T4 ;Save this for later
JUMPE T3,EVEOK5 ;Skip checks if zero
CAMN T2,T3 ;They must be equal if non-zero
IFSKP. ;They aren't
SETONE EQNO,(Q2) ;Set the "NO" bit in VRQA
MOVEI T1,ENQX23 ;Get correct error code
MOVEM T1,.EBAD1(Q2) ;Put in as Additional Data
INCR EBTOTT,(Q2) ;Say one more word to send
JRST EVEOK7 ;Refuse the request
ENDIF.
EVEOK5: LOAD T2,EBTSWS,(Q2) ;Get size of string
ADDI T2,.MHUDA+EHDRSZ+LDCHDR ;Add in constant header amount
ADD T2,T4 ;Add mask block size - now at Additional Data
MOVE T2,VANA(T2) ;[7.1115] Get the first word of Additional Data
TMNE EQBLN,(Q2) ;Are levels being checked
JRST EVEOK6 ;No, so skip the check
HRRZM T2,T3 ;Move level number into T3
LOAD T4,ENQLVL,(T1) ;Get level number from Lock-Block
CAMN T4,T3 ;They should be the same
IFSKP. ;They aren't!
SETONE EQNO,(Q2) ;Set the "NO" bit in VRQA
MOVEI T1,ENQX3 ;Get correct error code
MOVEM T1,.EBAD1(Q2) ;Put in as Additional Data
INCR EBTOTT,(Q2) ;Say one more word to send
JRST EVEOK7 ;Refuse the request
ENDIF.
EVEOK6: HLRZS T2 ;Keep just pool total in T2
LOAD T4,ENQTR,(T1) ;Get pool total from Lock-Block
CAMN T4,T2 ;They should be the same
IFSKP. ;They aren't!
SETONE EQNO,(Q2) ;Set the "NO" bit in VRQA
MOVEI T1,ENQX4 ;Get correct error code
MOVEM T1,.EBAD1(Q2) ;Put in as Additional Data
INCR EBTOTT,(Q2) ;Say one more word to send
ENDIF.
EVEOK7: CALLRET ANSWER ;()Send the reply
SUBTTL Vote Responder -- EVCNTS (Respond to .CNTS vote)
;EVCNTS - This routine sends a reply to a vote request just received.
; The vote is of type .CNTS which is sent by the EQCNTS routine.
;
; The VANA contains the reassembled Request Message Set.
;
;Returns +1: Always once the reply message is sent
; XSWAPCD
EVCNTS: SAVEAC <Q2> ;Save a work register
XMOVEI Q2,VANA ;[7.1115] Get address of VANA
INCR EBTOTT,(Q2) ;Say one more word to send
CALL LOCLOK ;(/T1)Find the Lock-Block for this vote
IFNSK. ;There isn't one!
SETZM .EBAD1(Q2) ;Clear the first word of Additional Data
CALLRET ANSWER ;()Send the count of "0,,0"
ENDIF.
CALL CNTQLQ ;(T1/T1)Get count of "waiters,,lockers"
MOVEM T1,.EBAD1(Q2) ;Return in first word of Additional Data
CALLRET ANSWER ;()Send the reply
SUBTTL Vote Responder -- EVRSTS (Respond to .RSTS vote)
;EVRSTS - This routine sends a reply to a vote request just received.
; The vote is of type .RSTS which is sent by the EQRSTS routine.
;
; The VANA contains the reassembled Request Message Set.
;
;Returns +1: Always once the reply message is sent
; XSWAPCD
EVRSTS: SAVEAC <Q1,Q2> ;Save work registers
XMOVEI Q2,VANA ;[7.1115] Get address of VANA
CALL LOCLOK ;(/T1)Find the Lock-Block for this vote
IFNSK. ;There isn't one!
SETONE EQNO,(Q2) ;Set the "NO" bit in VRQA
CALLRET ANSWER ;()Send the reply
ENDIF.
MOVEM T1,Q1 ;Remember the Lock-Block address
CALL CNTQ ;(T1/T1)Get access!fork-number,,sharer-count
SETZM .EBAD1(Q2) ;Assume shared access
SKIPL T1 ;Is it?
HRROS .EBAD1(Q2) ;No, so set access as exclusive
HRRM T1,.EBAD2(Q2) ;Store the number of sharers
HLRZ T2,T1 ;Get just access!fork
TRZ T2,(1B0) ;Mask off access bit
HRRZ T3,T1 ;Get the number of sharers
SKIPN T3 ;Were there any sharers found?
IFSKP. ;Yes
LOAD T1,FKJO%,(T2) ;Get job number of this fork
CALLX (MSEC1,LCL2GL) ;(T1/T1)Get global job number
SETO T1, ;No job found - return no job number for sharer
ELSE. ;No sharers
SETO T1, ;So say owning job is -1
ENDIF.
HRLM T1,.EBAD2(Q2) ;Store job number in VRQA
LOAD T1,ENQLVL,(Q1) ;Get the level number of this lock
HRRM T1,.EBAD1(Q2) ;Put in VRQA
LOAD T1,ENQTS,(Q1) ;Get the time stamp
MOVEM T1,.EBAD3(Q2) ;Put in VRQA
LOAD T1,EBTOTT,(Q2) ;Get the total size of VRQA
ADDI T1,3 ;Increment to reflect data just stored
STOR T1,EBTOTT,(Q2) ;Put in VRQA
CALLRET ANSWER ;()Send the reply
SUBTTL Vote Responder -- EVPOOL (Respond to .POOL vote)
;EVPOOL - This routine sends a reply to a vote request just received.
; The vote is of type .POOL which is sent by the EQPOOL routine.
;
; The VANA contains the reassembled Request Message Set.
;
;Returns +1: Always once the reply message is sent
; XSWAPCD
EVPOOL: SAVEAC <Q2> ;Save a work register
XMOVEI Q2,VANA ;[7.1115] Get address of VANA
INCR EBTOTT,(Q2) ;Say one more word to send
CALL LOCLOK ;(/T1)Find the Lock-Block for this vote
IFNSK. ;There isn't one!
SETZM .EBAD1(Q2) ;Clear the first word of Additional Data
CALLRET ANSWER ;()Send the count of "0,,0"
ENDIF.
LOAD T3,ENQTR,(T1) ;Get total number of resources for lock
LOAD T2,ENQRR,(T1) ;Get the number remaining
SUB T3,T2 ;Compute number used
MOVEM T3,.EBAD1(Q2) ;Put in VRQA
CALLRET ANSWER ;()Send the reply
SUBTTL Vote Responder -- EVQSKD (Respond to .QSKD vote)
;EVQSKD - This routine sends a reply to a vote request just received.
; The vote is of type .QSKD which is sent by the EQQSKD routine.
;
; The VANA contains the reassembled Request Message Set.
;
;Returns +1: Always once the reply message is sent
; XSWAPCD
EVQSKD: SAVEAC <Q2> ;Save a work register
XMOVEI Q2,VANA ;[7.1115] Get address of VANA
SETZRO EQNO,(Q2) ;Clear "NO" flag in VRQA
CALL LOCLOK ;(/T1)Find the Lock-Block for this vote
IFNSK. ;There isn't one!
SETZM .EBAD1(Q2) ;Send "0" as the number of pool resources used
INCR EBTOTT,(Q2) ;One word of Additional Data is sent
CALLRET ANSWER ;()Send the reply
ENDIF.
;At this point, all the Q-Blocks which are visible and queued to the Lock-Block
;must be checked against the request currently specified in the VRQA. These
;checks are identical to the ones done on the node which sent the vote request.
LOAD T3,EBQFLG,(Q2) ;Get flags
LOAD T4,EBGRP,(Q2) ;Get the group number
HRL T4,T3 ;Put flags in correct position
XMOVEI T2,.EBSMB(Q2) ;Get address of Mask block
LOAD T3,EBMBWS,(Q2) ;Get size of Mask Block
SKIPN T3 ;Is there one?
SETZ T2, ;No, so do not send an address
CALL QSKDRC ;(T1,T2,T3,T4/T1)Check mask blocks and sharer groups
IFNSK. ;There was some incompatibility
SETONE EQNO,(Q2) ;Say "NO" to drugs!
CALLRET ANSWER ;()Send the reply
ENDIF.
LOAD T3,ENQTR,(T1) ;Get total number of resources for lock
LOAD T2,ENQRR,(T1) ;Get the number remaining
SUB T3,T2 ;Compute number used
MOVEM T3,.EBAD1(Q2) ;Put in VRQA
INCR EBTOTT,(Q2) ;One word of Additional Data is sent
CALLRET ANSWER ;()Send the reply
SUBTTL Vote Responder -- EVLKSD (Respond to .LKSD vote)
;EVLKSD - This routine sends a reply to a vote request just received.
; The vote is of type .LKSD which is sent by the EQLKSD routine.
;
; The VANA contains the reassembled Request Message Set.
;
;Returns +1: Always once the reply message is sent
; XSWAPCD
EVLKSD: CALL LOCLOK ;(/T1)Find the Lock-Block for this vote
CALLRET ANSWER ;There isn't one! Ignore notification.
LOAD T2,ENQFLG,(T1) ;Get the flags from the Lock-Block
TXON T2,EN.SDO ;Indicate that scheduling is needed
AOS EQFKFL ;Count this only if not already set
STOR T2,ENQFLG,(T1) ;Replace the flags
CALLRET ANSWER ;()Send back a null reply
SUBTTL Interface Routines for ENQ -- EQEOKR (Check ENQ% request)
;This routine is called from ENQREQ to remotely check the validity of
;the lock request (Q-Block) which is being specified in the ENQ% call.
;Specifically, the following is checked:
;
; 1. Mask Block size compatibility
; 2. Level Number agreement
; 3. Pool total agreement
;
; T1/ Q-Block address
;
; CALL EQEOKR
;
;Returns +1: Failure, with T1/ Error code
; +2: Success, Q-Block can now be scheduled, with:
; T1/ Q-Block address
;
;The error codes which can be returned by this routine are:
;
; ENQX3: Request and lock level numbers do not match
; ENQX4: Number of pool and lock resources do not match
; ENQX23: Mismatched mask block lengths
; XSWAPCD
EQEOKR::STKVAR <LBADDR,QBADDR>
MOVE T2,ENQWRD ;Get the ENQ word for this process
TXNN T2,EQ%ENA ;Is cluster-wide capability enabled?
RETSKP ;No, so just return
LOAD T2,ENQFLG,(T1) ;Get flags for Q-Block
TXNN T2,EN.CLL ;Is this a cluster-wide request?
RETSKP ;No, so just return
LOAD T2,ENQLBP,(T1) ;Get Lock-Block address
LOAD T2,ENQFLG,(T2) ;Get flags
TXNE T2,EN.NOV ;Do we need to vote on this lock?
RETSKP ;No, so just return
MOVEM T1,QBADDR ;Save Q-Block address
CALL HDRFIQ ;(T1/T1,T2)Fill in most of the VRQA header
LOAD T3,ENQLBP,(T1) ;Get Lock-Block address
MOVEM T3,LBADDR ;Save it for later
LOAD T4,ENQTR,(T3) ;Get the pool total
HRLM T4,(T2) ;Position in Additional Data
LOAD T4,ENQLVL,(T3) ;Get level number of lock
HRRM T4,(T2) ;Position in Additional Data
XMOVEI T2,VRQA ;Get address of VRQA
INCR EBTOTT,(T2) ;Add one to user total because of data
TXNN P1,EN%BLN ;Is the user bypassing level checking?
IFSKP. ;Yes
SETONE EQBLN,(T2) ;Indicate in flags
ENDIF.
MOVEI T3,.EOKR ;Get function code
STOR T3,EBFTYP,(T2) ;Store in VRQA
CALL ASK4IT ;()Send the VRQA to all systems
RETBAD () ;Failed due to lack of resources
XMOVEI T1,VRPA ;Get address of reply area
TMNN VPNOV,(T1) ;Are subsequent votes required for this lock?
IFSKP. ;No
MOVE T2,LBADDR ;Get Lock-Block address
LOAD T3,ENQFLG,(T2) ;Get flags
TXO T3,EN.NOV ;Set "no vote required" bit
STOR T3,ENQFLG,(T2) ;Restore flags
TMNE VPNO,(T1) ;Is the "NO" bit also set?
BUG.(HLT,EQNOVW,ENQSRV,SOFT,<ENQSRV - NO bit set no vote required>,,<
Cause: The VRPA contains the replies to a vote request and VPNO and VPNOV
are both set. This should never happen since VPNOV means that no
other node know about the lock but VPNO means that another node
rejected the vote request; so it must have known about the lock.
This is a problem in the Lock-Block caching algorithm.
Action: A cluster dump may be required here to solve the problem. Also,
check all the places where VPNOV and VPNO are set for a possible
problem. This logic resides mostly in routines EVEOKR and EIEOKR.
>) ;Yes - stop now!
ENDIF.
TMNE VPNO,(T1) ;Was this vote request denied by anyone?
IFSKP. ;No
MOVE T1,QBADDR ;Get Q-Block address back
RETSKP ;Return success
ENDIF.
MOVE T1,.VPAD1(T1) ;Get error code from Additional Data
RET ;Return failure
ENDSV.
SUBTTL Interface Routines for ENQ -- EQCNTS (Get lock usage counts)
;This routine is called from ENQFN3 (ENQ% function 3) in order to get
;the number of Q-Blocks on the queue for a particular Lock-Block. This
;must be known in order to determine if the .ENQMA function is
;allowable. All remote systems must be checked to see if there are any
;Q-Blocks queued for the lock which is about to have its access
;changed. If so, then the access change will not be permitted if we
;are attempting to change from SHARED to EXCLUSIVE.
;
; T1/ Q-Block address
;
; CALL EQCNTS ;(T1/T1)
;
;Returns +1: Always, with:
; T1/ Number of remote waiters,,Number of remote lockers
;
;Preserves T2.
; XSWAPCD
EQCNTS::SAVEAC <T2> ;Preserve T2
MOVE T3,T1 ;Save Q-Block address
SETZM T1 ;Assume no remote user now
MOVE T2,ENQWRD ;Get the ENQ word for this process
TXNN T2,EQ%ENA ;Is cluster-wide capability enabled?
RETSKP ;No, so just return
LOAD T2,ENQFLG,(T3) ;Get flags for Q-Block
TXNN T2,EN.CLL ;Is this a cluster-wide request?
RETSKP ;No, so just return
LOAD T4,ENQLBP,(T3) ;Get Lock-Block address
LOAD T2,ENQFLG,(T4) ;Get flags
TXNE T2,EN.NOV ;Do we need to vote on this lock?
RETSKP ;No, so just return
MOVE T1,T4 ;Reposition Lock-Block address
CALL HDRFIL ;(T1/T1,T2)Fill in most of the VRQA header
XMOVEI T2,VRQA ;Get address of VRQA
MOVEI T3,.CNTS ;Get function code
STOR T3,EBFTYP,(T2) ;Store in VRQA
CALL ASK4IT ;()Send the VRQA to all systems
RETBAD (,<SETO T1,>) ;Failed due to lack of resources
XMOVEI T1,VRPA ;Get VRPA address
MOVE T1,.VPAD1(T1) ;Get remote count word from Additional Data
RET ;Return success
SUBTTL Interface Routines for ENQ -- EQRSTS (Get remote lock status)
;This routine is called from ENQCF0 (ENQC% function 0) in order to get
;the remote status of the lock. This information is used to return the
;correct cluster-wide status of the lock. All remote nodes are queried
;about their own status on the lock.
;
; T1/ Hash value
; T2/ Lock-Block address or zero
; P1-P5 set up by call to VALREQ and HASH
; Q1/ Address of lock request in user's space; set up by VALARG
;
; CALL EQRSTS ;(T1,T2,Q1,P1-P5/T1,T2,T3)
;
;Returns +1: Always, with the following:
;
; T1/ Remote lock access (Shared=0, Exclusive=-1),,
; Greatest remote lock level
; T3/ Remote job number of lock owner (-1 if unowned),,
; Number of remote users (lockers) of lock
; T4/ Greatest remote time stamp (0 if lock was not known remotely)
; XSWAPCD
EQRSTS::STKVAR <TMPHSH,TMPLBA>
MOVEM T1,TMPHSH ;Save the hash value ...
MOVEM T2,TMPLBA ;... and the Lock-Block address
SETZB T1,T4 ;Init the returned values
HRLZI T3,-1
HRRE T2,P1 ;Get object type and extend sign
SKIPL T2 ;Is this a non-file lock?
IFSKP. ;Yes
TRNN P1,77000 ;Is this a 400000+job-number type of lock?
RET ;Yes, so return now
ENDIF.
MOVE T2,ENQWRD ;Get the ENQ word for this process
TXNN T2,EQ%ENA ;Is cluster-wide capability enabled?
RET ;No, so just return
SKIPN T2,TMPLBA ;Was a Lock-Block specified?
IFSKP. ;Yes
LOAD T2,ENQFLG,(T2) ;Get flags for Lock-Block
TXNE T2,EN.NOV ;Do we need to vote on this lock?
RET ;No, so just return
ENDIF.
MOVE T1,TMPHSH ;Get hash value back
CALL HDRFIP ;[7.1103] (T1,Q1,P1-P5/T1,T2) Fill in header of VRQA
XMOVEI T2,VRQA ;Get address of VRQA
MOVEI T3,.RSTS ;Get opcode for vote
STOR T3,EBFTYP,(T2) ;Put opcode into VRQA
CALL ASK4IT ;()Get the remote status
IFNSK. ;Failed due to lack of resources
SETZB T1,T4 ;So, return "unknown remotely" values
HRLZI T3,-1
RET
ENDIF.
XMOVEI T2,VRPA ;Get address of VRPA
SKIPE T4,.VPAD3(T2) ;Did we get any replies?
IFSKP. ;No, remote time was zero so lock is unknown
SETZ T1, ;So, return "unknown remotely" values
HRLZI T3,-1
ELSE. ;Yes, this was known remotely
HRRZ T3,.VPAD2(T2) ;Get the number of remote lockers
SETO T1, ;Assume no lock owner
SKIPE T3 ;Are there any?
HLRZ T1,.VPAD2(T2) ;Yes, get the lock owners's job number
HRL T3,T1 ;Put lock owner in correct position
MOVE T1,.VPAD1(T2) ;Get access,,level
ENDIF.
RET ;Done
ENDSV.
SUBTTL Interface Routines for ENQ -- EQPOOL (Get pool total)
;This routine is called from LOKSKD in order to get the remaining
;number of resources in the pool for a particular Lock-Block.
;
; T1/ Address of Lock-Block being rescheduled
;
; CALL EQPOOL ;(T1/T1,T2)
;
;Returns +1: Always, with:
; T2/ Total number of remaining resources in pool
;
;Preserves T1
; XSWAPCD
EQPOOL::SAVEAC <T1,Q1> ;Preserve T1 and get a work register
MOVEM T1,Q1 ;Save Lock-Block address
LOAD T2,ENQRR,(T1) ;Assume no need to vote
MOVE T3,ENQWRD ;Get the ENQ word for this process
TXNN T3,EQ%ENA ;Is cluster-wide capability enabled?
RET ;No, so just return
LOAD T3,ENQFLG,(T1) ;Get flags from Lock-Block
TXNE T3,EN.CLL ;[7.1179] Is this a cluster-wide lock?
TXNE T3,EN.NOV ;Do we need to vote on this lock?
RET ;No, so just return
CALL HDRFIL ;(T1/T1,T2)Fill in most of VRQA header
XMOVEI T2,VRQA ;Get address of VRQA
MOVEI T3,.POOL ;Get function code
STOR T3,EBFTYP,(T2) ;Store in VRQA
CALL ASK4IT ;()Send the VRQA to all systems
RETBAD (,<SETZ T2,>) ;Failed due to lack of resources
XMOVEI T1,VRPA ;Get address of VRPA
LOAD T3,ENQTR,(Q1) ;Get total number of resources for lock
LOAD T2,ENQRR,(Q1) ;Get the number remaining
SUB T3,T2 ;Compute number used locally
ADD T3,.VPAD1(T1) ;Add local amount to remote amount used
LOAD T2,ENQTR,(Q1) ;Get total number of resources for lock
SUB T2,T3 ;Compute number remaining in cluster
RET ;Done
SUBTTL Interface Routines for ENQ -- EQQSKD (QSKED remote)
;This routine is called from QSKED in order to perform a scheduling
;pass for a particular Q-Block on all remote nodes. This call is
;made after it has been determined that the scheduling pass succeeded
;locally (except for pool total checking). The following is checked
;remotely:
;
; 1. Mask Block compatibility
; 2. Sharer groups
;
; T1/ Address of Q-Block to be scheduled
;
; CALL EQQSKD ;(T1/T1,T4)
;
;Returns +1: Failure, Access disallowed by remote system(s)
; +2: Success (No conflicts exist in the cluster), with:
; T4/ Total number of remaining resources in pool for Lock-Block
;
;Preserves T1.
; XSWAPCD
EQQSKD::SAVEAC <T1,Q1> ;Preserve T1 and get a work register
LOAD Q1,ENQLBP,(T1) ;Get Lock-Block address
LOAD T4,ENQRR,(Q1) ;Get the number of resources remaining locally
MOVE T2,ENQWRD ;Get the ENQ word for this process
TXNN T2,EQ%ENA ;Is cluster-wide capability enabled?
RETSKP ;No, so just return
LOAD T2,ENQFLG,(T1) ;Get flags for Q-Block
TXNN T2,EN.CLL ;Is this a cluster-wide request?
RETSKP ;No, so just return
LOAD T2,ENQFLG,(Q1) ;Get flags from Lock-Block
TXNE T2,EN.NOV ;Do we need to vote on this lock?
RETSKP ;No, so just return
CALL HDRFIQ ;(T1/T1,T2)Fill in most of the VRQA header
XMOVEI T2,VRQA ;Get address of VRQA
MOVEI T3,.QSKD ;Get function code
STOR T3,EBFTYP,(T2) ;Store in VRQA
CALL ASK4IT ;()Send the VRQA to all systems
RETBAD () ;Failed due to lack of resources
XMOVEI T1,VRPA ;Get address of VRPA
TMNE VPNO,(T1) ;Was this vote request denied by anyone?
RET ;Yes, so return failure
LOAD T3,ENQTR,(Q1) ;Get total number of resources for lock
LOAD T2,ENQRR,(Q1) ;Get the number remaining
SUB T3,T2 ;Compute number used locally
ADD T3,.VPAD1(T1) ;Add local amount to remote amount used
LOAD T4,ENQTR,(Q1) ;Get total number of resources for lock
SUB T4,T3 ;Compute number remaining in cluster
RETSKP ;Done, return success
SUBTTL Interface Routines for ENQ -- EQLKSD (Notify for remote LOKSKD)
;This routine is called from LOKSKD in order to perform a remote
;scheduling pass for a particular Lock-Block. When the local node does
;a call to LOKSKD, this routine is called to notify the remote nodes
;of the event and cause a scheduling pass.
;
; T1/ Address of Lock-Block to reschedule
;
; CALL EQLKSD ;(T1/T1)
;
;Returns +1: Always, with T1 preserved
; XSWAPCD
EQLKSD::SAVEAC <T1> ;Preserve T1
MOVE T2,ENQWRD ;Get the ENQ word for this process
TXNN T2,EQ%ENA ;Is cluster-wide capability enabled?
RET ;No, so just return
LOAD T2,ENQFLG,(T1) ;Get flags from Lock-Block
TXNE T2,EN.CLL ;[7.1179] Is this a cluster-wide lock?
TXNE T2,EN.NOV ;Do we need to vote on this lock?
RET ;No, so just return
CALL HDRFIL ;(T1/T1,T2)Fill in most of the VRQA header
XMOVEI T2,VRQA ;Get address of VRQA
MOVEI T3,.LKSD ;Get function code
STOR T3,EBFTYP,(T2) ;Store in VRQA
CALL ASK4IT ;()Send the VRQA to all systems
BUG.(CHK,EQNOTF,ENQSRV,SOFT,<ENQSRV - Rescheduling notification failed>,,<
Cause: Routine EQLKSD was called to notify the other systems in the cluster
that a lock has been rescheduled. But, this did not occur because
of a lack of resources; SCA message buffers. So, it may be that
there is fork on another system which is hung waiting to get access
to this lock and it won't unhang until that system recieves a
rescheduling notification. This BUGCHK should not occur and is
evidence of a much more serious SCA problem.
Action: In order to unhang any forks which may be waiting for access to the
lock which was just rescheduled, the following can be done. On
every system, set bit EN.SDO in every Lock-Block which is on the
EQLBLT. Then increment the right half of EQFKFL by the number of
blocks just set. This can be done by setting EQCSTF to -1 on
each system. This will make the system think that a cluster
state change occurred and will force a rescheduling of all known
lock blocks.
>,,<DB%NND>) ;[7.1210][7.1096] Failed, lack of resources
RET ;All done - systems have been notified
SUBTTL End of ENQSRV
> ;End of IFN CLEQIN at top of module
TNXEND
END