Trailing-Edge
-
PDP-10 Archives
-
BB-X140B-BB_1986
-
10,7/703mon/queser.mac
There are 11 other files named queser.mac in the archive. Click here to see a list.
TITLE QUESER -- ENQUEUE/DEQUEUE SERVICE FACILITY - V140
SUBTTL S. BLOUNT /WRS/PMV 10 SEP 85
SEARCH F,S
$RELOC
$HIGH
;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED
; OR COPIED IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
.CPYRT<1974,1986>
;COPYRIGHT (C) 1974,1975,1976,1977,1978,1979,1980,1982,1984,1986
;BY DIGITAL EQUIPMENT CORP., MAYNARD, MASS.
;ALL RIGHTS RESERVED.
;
;
XP VQUESR,140
ENTRY QUESER ;LOAD THIS MODULE IF NEEDED
QUESER::
;ENQ/DEQ PROVIDES A QUEUEING FACILITY WHICH CAN BE USED
; TO INSURE MUTUAL EXCLUSION OF PROCESSES OPERATING ON
; A COMMON DATA BASE.
SALL
SUBTTL DATA BASE DEFINITIONS
REPEAT 0,<
;Q-BLOCK FORMAT
+-------------------------+-------------------------+
!.QBLJQ: !.QBNJQ: !
! BACK POINTER TO ! FORWARD POINTER TO !
! LAST Q-BLOCK FOR JOB ! NEXT Q-BLOCK FOR JOB !
+-------------------------+----------+--------------+
!.QBJCH: !.QBCHN: !.QBFLG: !
! ! CHANNEL ! !
! JOB CONTEXT HANDLE ! NUMBER ! FLAGS !
+-------------------------+----------+--------------+
!.QBLQ: !.QBNQ: !
! POINTER TO LAST QUEUE ! POINTER TO NEXT QUEUE !
! BLOCK FOR THIS LOCK ! BLOCK FOR THIS LOCK !
+-------------------------+-------------------------+
!.QBLQR: !.QBNQR: !
! POINTER TO LAST ! POINTER TO NEXT !
! MULTIPLE Q-BLOCK ! MULTIPLE Q-BLOCK !
+-------------------------+-------------------------+
!.QBRID: !.QBNRP: !
! ! !
! REQUEST I.D. ! # REQUESTED FROM POOL !
+-------------------------+-------------------------+
!.QBGRP: !.QBLB: !
! GROUP ! POINTER TO !
! NUMBER ! LOCK-BLOCK !
+-------------------------+-------------------------+
! .QBCHK: ! .QBMSK: !
! POINTER TO NEXT Q-BLOCK ! MASK BLOCK !
! TO BE DEADLOCK CHECKED ! !
+-------------------------+-------------------------+
;LOCK-BLOCK FORMAT
+-------------------------+-------------------------+
!.LBLHS: !.LBNHS: !
! BACK POINTER TO LAST ! POINTER TO NEXT !
! LOCK-BLOCK ON HASH CHAIN! LOCK-BLOCK ON HASH CHAIN!
+-------------------------+-------------------------+
!.LBLEN: !.LBFLG: !
! LENGTH OF LOCK-BLOCK ! FLAGS !
! ! !
+-------------------------+-------------------------+
!.LBLQ: !.LBNQ: !
! POINTER TO LAST ! POINTER TO NEXT !
! Q-BLOCK IN CHAIN ! Q-BLOCK IN CHAIN !
+-------------------------+-------------------------+
!.LBLVL: !.LBACC: !
! LEVEL NUMBER ! ADDRESS OF ACCESS TABLE !
! ! -2, -3, OR 400000+JOB # !
+-------------------------+-------------------------+
!.LBPUL: !.LBAVL: !
! ! !
! # IN POOL ! # AVAILABLE !
+-------------------------+-------------------------+
!.LBTIM: !
! TIME-STAMP !
! !
+---------------------------------------------------+
!.LBTLN: !.LBTBL: !
! LENGTH OF TABLE BLOCK ! LOCK ASSOCIATED TABLE !
! ! !
+-------------------------+-------------------------+
!.LBNMS !.LBPLT! !
! NUMBER OF WORDS IN THE !TIMER ! !
! MASK BLOCK ! !
+-------------------------+-------------------------+
!.LBTXT: ASCIZ STRING !
! OR 500000,,0 + USER CODE !
! OR 36-BIT USER CODE !
+---------------------------------------------------+
> ;END OF REPEAT 0
SUBTTL STRUCTURE MACRO DEFINITIONS
;DEFINE DATA STRUCTURE
; NAM - NAME OF STRUCTURE AS USED IN CODE
; LOCN - ADDRESS OF DATA
; POS - POSITION OF DATA WITHIN WORD (RIGHTMOST BIT NUMBER)
; SIZ - SIZE OF DATA WITHIN WORD
DEFINE DEFSTR(NAM,LOCN,POS,SIZ)<
RADIX 10
.TSTSZ(POS,SIZ)
DEFST1(\..TYP,NAM,LOCN,POS,SIZ)
RADIX 8>
DEFINE DEFST1(TYP,NAM,LOCN,POS,SIZ)<
DEFINE NAM(OPS,AC,Y)<
..C==0
IRP OPS,<
IFE TYP-..C,<
STOPI
IFN 3-..C,<
OPS AC,LOCN''Y>
IFE 3-..C,<
OPS AC,[POINT SIZ,LOCN''Y,POS]>>
..C=..C+1>>>
DEFINE .TSTSZ(POS,SIZ)<
..TYP==3
IFE SIZ-36,<..TYP=0>
IFE SIZ-18,<
IFE POS-35,<..TYP=1>
IFE POS-17,<..TYP=2>>>
;LOAD, STORE.
; AC - AC OPERAND
; STR - STRUCTURE NAME
; Y - (OPTIONAL) LOCATION OF DATA IF NOT AS ORIGINALLY SPECIFIED
DEFINE LOAD.(AC,STR,Y)<
STR(<MOVE,HRRZ,HLRZ,LDB>,AC,Y)>
DEFINE STOR.(AC,STR,Y)<
STR(<MOVEM,HRRM,HRLM,DPB>,AC,Y)>
SUBTTL DATA STRUCTURE DEFINITIONS
;DATA STRUCTURE DEFINITIONS
;Q-BLOCK STRUCTURES
DEFSTR(.QBLJQ,0,17,18) ;POINTER TO LAST ENTRY IN JOB-Q
DEFSTR(.QBNJQ,0,35,18) ;POINTER TO NEXT ENTRY IN JOB-Q
DEFSTR(.QBJCH,1,17,18) ;JOB/CONTEXT HANDLE OF THIS USER
DEFSTR(.QBCHN,1,26,9) ;CHANNEL NUMBER
DEFSTR(.QBFLG,1,35,9) ;FLAGS FOR THIS Q-ENTRY
DEFSTR(.QBLQ,2,17,18) ;POINTER TO LAST ENTRY IN QUEUE
DEFSTR(.QBNQ,2,35,18) ;POINTER TO 1ST ENTRY IN QUEUE
DEFSTR(.QBLQR,3,17,18) ;POINTER TO PREVIOUS ENTRY IN THIS REQUEST
DEFSTR(.QBNQR,3,35,18) ;POINTER TO NEXT ENTRY IN THIS REQUEST
DEFSTR(.QBRID,4,17,18) ;REQUEST ID FOR THIS ENTRY
DEFSTR(.QBNRP,4,35,18) ;NUMBER OF RESOURCES REQUESTED FROM POOL
DEFSTR(.QBGRP,5,17,18) ;GROUP NUMBER FOR THIS USER
DEFSTR(.QBLB,5,35,18) ;POINTER TO LOCK BLOCK
DEFSTR(.QBCHK,6,17,18) ;NEXT BLOCK TO BE DEADLOCK CHECKED
DEFSTR(.QBMSK,6,35,18) ;POINTER TO MASK BLOCK
QBSIZE==7 ;SIZE OF Q-BLOCK
;LOCK-BLOCK STRUCTURES
DEFSTR(.LBLHS,0,17,18) ;POINTER TO LAST ENTRY IN HASH CHAIN
DEFSTR(.LBNHS,0,35,18) ;POINTER TO NEXT ENTRY IN HASH CHAIN
DEFSTR(.LBLEN,1,17,18) ;LENGTH IN WORDS OF THIS LOCK-BLOCK
DEFSTR(.LBFLG,1,35,12) ;FLAGS
DEFSTR(.LBLQ,2,17,18) ;POINTER TO LAST ENTRY IN QUEUE
DEFSTR(.LBNQ,2,35,18) ;POINTER TO 1ST ENTRY IN QUEUE
DEFSTR(.LBLVL,3,17,18) ;LEVEL NUMBER OF THIS RESOURCE
DEFSTR(.LBACC,3,35,18) ;ACCESS TABLE ADDRESS/-2/-3/400000+JOB #
DEFSTR(.LBPUL,4,17,18) ;NUMBER OF RESOURCES IN POOL
DEFSTR(.LBAVL,4,35,18) ;NUMBER OF RESOURCES AVAILABLE
DEFSTR(.LBPWD,4,35,36) ;ENTIRE POOLED RESOURCE WORD
DEFSTR(.LBTIM,5,35,36) ;TIME-STAMP WHEN LOCK WAS LAST LOCKED
DEFSTR(.LBTLN,6,17,18) ;LENGTH OF LOCK-ASSOCIATED TABLE
DEFSTR(.LBTBL,6,35,18) ;ADDRESS OF LOCK-ASSOCIATED TABLE
DEFSTR(.LBNMS,7,17,18) ;LENGTH OF MASK BLOCK FOR THIS LOCK
DEFSTR(.LBPLT,7,22,5) ;PERMANENT LOCK TIMER
DEFSTR(.LBTXT,10,35,36) ;USER CODE/TEXT STRING
LBSIZE==10 ;SIZE OF LOCK-BLOCK (MINUS TEXT)
;IDLE
O.TEXT==10 ;OFFSET OF START OF TEXT (SEE LB.TXT)
SUBTTL PARAMETER DEFINITIONS
;ENQ FUNCTION CODES:
.ENQBL==0 ;ENQ BLOCK OPTION
.ENQAA==1 ;ENQ ALLOCATE ONLY IF AVAILABLE
.ENQSI==2 ;ENQ SOFTWARE INTERRUPT OFTION
.ENQMA==3 ;ENQ MODIFY ACCESS
;DEQ FUNCTION CODES
.DEQDR==0 ;DEQ RESOURCE
.DEQDA==1 ;DEQ ALL
.DEQID==2 ;DEQ REQUEST I.D.
;ENQC FUNCTION CODES:
.ENQCS==0 ;RETURN STATUS
.ENQCG==1 ;GET USER'S ENQ QUOTA
.ENQCC==2 ;CHANGE USER'S ENQ QUOTA
.ENQCD==3 ;DUMP DATA BASE
;MAXIMUM FUNCTION CODES ALLOWED
EQMXFC==3 ;HIGHEST ENQ FUNCTION CODE
DQMXFC==2 ;HIGHEST DEQ CODE
QCMXFC==3 ;ENQC MAX CODE
;FLAGS DEFINED IN LEFT HALF OF 1ST WORD OF USER LOCK SPEC
EN%SHR==(1B0) ;THIS LOCK IS SHARABLE
EN%BLN==(1B1) ;BYPASS LEVEL NUMBER SEQUENCING
EN%LTL==(1B2) ;LONG TERM LOCK
EN%NDR==(1B3) ;NOT DEQUEUED ON RESET
EN%ABT==(1B4) ;PROGRAM SAID THIS LOCK HAS BEEN ABORTED
EN%DED==(1B5) ;DEADLOCK DETECTION
EN%UCW==(1B6) ;USER CODE WORD INSTEAD OF STRING POINTER
;FLAGS RETURNED TO USER IN LEFT HALF OF STATUS WORD FOR ENQC. UUO:
EN%QCE==(1B0) ;ERROR OCCURED
EN%QCO==(1B1) ;THIS USER IS THE OWNER
EN%QCQ==(1B2) ;THIS USER HAS ISSUED AN ENQ FOR THIS RESOURCE
EN%QCX==(1B3) ;OWNER HAS EXCLUSIVE ACCESS
;FLAGS RETURNED ON DATA-BASE DUMP OPTION OF ENQC.:
EN%QCL==(1B0) ;THIS IS A LOCK BLOCK DUMP
EN%QCT==(1B2) ;THIS LOCK HAS TEXT
EN%QCB==(1B4) ;THIS PROCESS IS BLOCKED
EN%QCN==(1B5) ;THIS LOCK IS NOT DEQUEUED ON RESET
EN%QCA==(1B6) ;THIS LOCK IS ABORTED (NO FURTHER REQUESTS GRANTED)
EN%QCI==(1B7) ;THIS QUEUE BLOCK IS INVISIBLE
EN%QCD==(1B8) ;THIS QUEUE BLOCK WILL BE CHECKED FOR DEADLOCK
;SOME VARIOUS DEFINITIONS
HDRMAX==3 ;MAXIMUM SIZE OF HEADER
LKMIN==2 ;MINIMUM SIZE OF LOCK
LKMAX==5 ;MAXIMUM SIZE OF LOCK
EQMXCH==:^D30 ;MAXIMUM STRING SIZE IN WORDS
EQDFEQ==:^D100 ;DEFAULT ENQ QUOTA
EQMXMW==:17 ;MAXIMUM PIE SLICE MASK WORD BLOCK LENGTH
EQMXTB==:^D512 ;MAXIMUM LOCK-ASSOCIATED TABLE LENGTH
EQMLTL==:^D5 ;MINUTES LONG TERM LOCKS STAY AROUND
EQMXAQ==:^D500 ;MAXIMUM NUMBER OF ACTIVE QUEUES
CODMIN==400000 ;MINIMUM VALUE OF A SPECIAL CODE
;FLAGS IN Q-BLOCK
QBOWNR==1B35 ;THIS IS THE LOCK OWNER
QBEXCL==1B34 ;EXCLUSIVE REQUEST
QBPSI==1B33 ;USER WANTS INTERRUPT (CODE WAS 2)
QBWAIT==1B32 ;USER WANTS TO BLOCK (CODE WAS 0)
QBINVS==1B31 ;THIS ENTRY IS "INVISIBLE"
QBLKBK==1B30 ;THIS IS A LOCK-BLOCK (ALWAYS ZERO)
QBDEAD==1B29 ;CHECK FOR DEADLOCK
QBLNDR==1B28 ;NOT DEQ'D ON RESET
QBLABT==1B27 ;ABORTED RESOURCE
;FLAGS IN LOCK-BLOCK
LBLKBK==1B30 ;THIS IS A LOCK-BLOCK (Q-BLOCKS MUST HAVE THIS BIT ZERO)
LBLAUC==1B26 ;READ COUNT INCREMENTED IN THE ACCESS TABLE
LBLLTL==1B25 ;LONG TERM LOCK
LBTEXT==1B24 ;THIS BLOCK HAS TEXT INSTEAD OF USER CODE
SUBTTL ERROR CODES RETURNED TO USER
ENQRU%==1 ;SOME RESOURCE(S) REQUESTED WERE UNAVAILABLE
ENQBP%==2 ;ILLEGAL # OF RESOURCES REQUESTED (POOLED RESOURCES)
ENQBJ%==3 ;BAD JOB NUMBER
ENQBB%==4 ;BAD BYTE SIZE IN TEXT STRING
ENQST%==5 ;STRING TOO LONG
ENQBF%==6 ;BAD FUNCTION CODE
ENQBL%==7 ;ILLEGAL ARGUMENT BLOCK LENGTH
ENQIC%==10 ;ILLEGAL NUMBER OF LOCKS SPECIFIED
ENQBC%==11 ;BAD CHANNEL NUMBER
ENQPI%==12 ;OPERATOR/JACCT PRIVILEGE REQUIRED
ENQNC%==13 ;NO CORE AVAILABLE
ENQFN%==14 ;FILE NOT OPEN ON SPECIFIED CHANNEL, OR DEVICE NOT A DISK
ENQIN%==15 ;INDIRECT OR INDEXED BYTE POINTER NOT ALLOWED
ENQNO%==16 ;NO RESOURCES WERE OWNED
ENQLS%==17 ;LEVEL SEQUENCING ERROR (LEVEL # TOO LOW)
ENQCC%==20 ;CAN'T CHANGE ACCESS
ENQQE%==21 ;QUOTA EXCEEDED
ENQPD%==22 ;# OF RESOURCES IN POOL NOT SAME AS IN LOCK
ENQDR%==23 ;DUPLICATE REQUEST FOR RESOURCE (LOCK ALREADY REQUESTED)
ENQNE%==24 ;NOT ENQ'ED ON THIS LOCK
ENQLD%==25 ;LEVEL # IN REQUEST DOES NOT MATCH LOCK
ENQED%==26 ;ENQ/DEQ PRIVILEGES REQUIRED
ENQME%==27 ;MASK IS TOO LONG, OR LENGTHS DO NOT MATCH.
ENQTE%==30 ;ENQ. TABLE IS TOO LONG
ENQAB%==31 ;ATTEMPT TO ENQ. AN ABORTED LOCK
ENQGF%==32 ;ATTEMPT TO LOCK WITH NDR ON A 'GHOST FILE'
ENQDD%==33 ;DEADLOCK DETECTED
ENQTL%==34 ;TIME LIMIT EXCEEDED
SUBTTL ENQ--ENQ A RESOURCE REQUEST
;
;
;
ENQ:: PUSHJ P,SAVE4## ;SAVE P1-P4
SETZ P4, ;CLEAR LIST OF REQUESTS
AOS %ENQTE## ;BUMP TOTAL NUMBER OF ENQ'S
SETOM ENQFLG ;FLAG THAT THIS IS AN ENQ
MOVEI T2,EQMXFC ;SET UP MAX FUNCTION CODE
PUSHJ P,SETUP ;DO PRELIMINARY THINGS
POPJ P, ;ERROR, GIVE ERROR CODE
PUSHJ P,CHKBLK ;CHECK OUT THE PARAMETER BLOCK
JRST STOTAC## ; ERROR RETURN
IFN FTMP,<
PUSHJ P,EQLOCK ;GET THE EQ RESOURCE
>
HRRZ T1,FCODE ;GET SAVED FUNCTION CODE
CAIE T1,.ENQMA ;IS THIS A "MODIFY ACCESS"?
PUSHJ P,PRVJC## ;OR, IS THIS GUY PRIVILEGED?
JRST ENQ1 ;YES, DON'T CHECK QUOTAS FOR HIM
HLRZ T1,LOCKCT ;GET # OF LOCKS IN THIS REQUEST
MOVE T2,.PDEQQ##(W) ;AND QUOTA OF SAME
TLON T2,EQ.HBS## ;QUOTA ALREADY BEEN SET?
HRR T2,%ENQDF## ;NO, SET DEFAULT QUOTA
MOVEM T2,.PDEQQ##(W) ;STORE QUOTA BACK AGAIN
ADD T1,REQCNT ;ADD # OF OUTSTANDING LOCKS
CAILE T1,(T2) ;TOO MANY REQUESTS?
JRST ENQER3 ;YES, ABORT UUO
ENQ1: PUSHJ P,GETLOK ;GET A LOCK SPEC
PUSHJ P,ENQIT ;PERFORM APPROPRIATE FUNCTION
JRST BACKUP ;ERROR--UNWIND PREVIOUS STUFF
PUSHJ P,CHKCNT ;MORE LOCKS TO GO?
JRST ENQ1 ;YES, CYCLE BACK FOR MORE
HRRZ T2,FCODE ;GET STORED FUNCTION CODE
CAIE T2,.ENQMA ;IS IT "MODIFY ACCESS"?
JRST ENQ2 ;NO, FINISH UP
SKIPN T1,NQERRF ;YES, WAS THERE AN ERROR?
JRST CPOPJ1## ;NO, GIVE SKIP RETURN
JRST STOTAC## ;RETURN ERROR CODE TO USER
;COME HERE WHEN ALL ENQ REQUESTS HAVE BEEN PERFORMED
ENQ2: HLRZ T1,P4 ;GET SAVED ADDRESS OF LAST Q
PUSHJ P,QSKD ;SCHEDULE IT
JRST ENQFAI ;NOT ALL WERE FREE
ENQ3: HLLZS LOCKCT ;RESET LOCK ARGUMENT COUNTER
FILTBL: PUSHJ P,GETLOK ;GET A LOCK ARGUMENT
SKIPE EQLTBL ;IS THERE A TABLE TO FILL?
PUSHJ P,REDTBL ;YES, GO FILL IT FOR HIM
PUSHJ P,CHKCNT ;ANY OTHER LOCKS TO CHECK?
JRST FILTBL ;YES, GET NEXT
JRST GUDXIT ;EVERYTHING WAS OK
;COME HERE IF ONE OR MORE OF THE RESOURCES WERE BUSY
ENQFAI: HLRZ T1,P4 ;GET ADDRESS OF LAST ENQ'ED BLOCK
LOAD. T2,.QBFLG,(T1) ; AND IT'S FLAGS
TRNN T2,QBPSI ;IF USING PSI, IGNORE TIME LIMIT (TEMP)
SKIPN TIMLIM ;IF TIME LIMIT, POSTPONE DEADLOCK CHECK
TRNN T2,QBDEAD ;SHOULD DEADLOCKS BE DETECTED?
JRST ENQFA2 ;NO, USER DOESN'T CARE
PUSHJ P,DEADLK ;CHECK TO SEE IF DEADLOCK
JRST ENQDED ;YES, GO CLEAN UP
HLRZ T1,P4 ;GET ADDRESS OF LAST ENQ'ED BLOCK
LOAD. T2,.QBFLG,(T1) ; AND IT'S FLAGS
ENQFA2: TRNE T2,QBWAIT ;SHOULD HE BE BLOCKED?
JRST BLKHIM ;YES, GO BLOCK HIM
MOVEI T1,ENQRU% ;SET UP ERROR CODE
TRNN T2,QBPSI ;IS HE USING SOFT. INTERRUPT SYS?
JRST BACKUP ;NO, WE MUST RELEASE HIS REQUEST
JRST STOTAC## ;NO, JUST RETURN AN ERROR CODE TO HIM
;HERE TO BLOCK USER ON A FUNCTION CODE OF "0"
BLKHIM:
PUSH P,P4 ;SAVE POINTER TO LAST Q-BLOCK
PUSH P,NQERRF ;SAVE ERROR FLAG
PUSH P,REQCNT
PUSH P,LOKSIZ
PUSH P,HDRSIZ
PUSH P,RBLOCK
PUSH P,FCODE
PUSH P,LOCKCT
PUSH P,REQID
PUSH P,TIMLIM
PUSH P,HILEVL
IFN FTMP,<
PUSHJ P,DWNEQ ;FREE EQ RESOURCE OVER HIBER CALL
>
MOVSI T1,HBRSEC## ;TIME LIMIT IS IN SECONDS
HRR T1,TIMLIM ;TELL HIBER HOW LONG TO WAIT
PUSHJ P,HIBER## ;HIBERNATE HIM
JFCL
IFN FTMP,<
PUSHJ P,UPEQ ;GET THE EQ RESOURCE BACK
>
POP P,HILEVL
POP P,TIMLIM
POP P,REQID
POP P,LOCKCT
POP P,FCODE
POP P,RBLOCK
POP P,HDRSIZ
POP P,LOKSIZ
POP P,REQCNT
POP P,NQERRF ;GET ERROR FLAG BACK
POP P,P4 ;GET BACK P4
HLRZ T1,P4 ;GET SAVED ADDRESS OF LAST Q
LOAD. T1,.QBLB,(T1) ;GET ADDRESS OF LOCK BLOCK
PUSHJ P,CHKABT ;WAS THIS LOCK ABORTED?
JRST [MOVEI T1,ENQAB% ;YES, SET UP ERROR CODE
JRST BACKUP] ;AND RELEASE THE REQUEST
HLRZ T1,P4 ;GET SAVED ADDRESS OF LAST Q
PUSHJ P,QSKD ;SCHEDULE IT
CAIA ;NOT ALL REQUESTS WERE GRANTED
JRST ENQ3 ;ALL LOCKED
JUMPN T1,ENQFAI ;WAIT SOME MORE IF ANYTHING GRANTED
SKIPN TIMLIM ;WAS A TIME LIMIT SPECIFIED?
JRST ENQFAI ;NO, SO WE CAN'T TIMEOUT
PUSHJ P,DEADLK ;SEE IF TIMEOUT DUE TO DEADLOCK
JRST ENQDED ;YES, COUNT AND RELEASE REQUEST
AOS %ENQTO## ;COUNT TIMEOUTS
MOVEI T1,ENQTL% ;SET UP ERROR CODE
JRST BACKUP ;AND RELEASE THE REQUEST
ENQDED: AOS %ENQDD## ;COUNT DEADLOCKS DETECTED
MOVEI T1,ENQDD% ;SET UP ERROR CODE
JRST BACKUP ;AND RELEASE THE REQUEST
;ROUTINE TO FILL A USER TABLE WITH DATA FROM THE LOCK-ASSOCIATED TABLE
REDTBL: PUSHJ P,FNDLOK ;FIND THE LOCK BLOCK
STOPCD CPOPJ##,DEBUG,ENQLNF ;++LOCK NOT FOUND
HLRZ T2,EQLTBL ;LENGTH OF USER'S DATA BLOCK
LOAD. T3,.LBTLN,(T1) ;LENGTH OF STORED DATA
CAMG T2,T3 ;IS THE USERS TABLE LONGER?
JRST REDTB1 ;NO, JUST COPY THE DATA
HRRZ T4,EQLTBL ;POINTER TO USER'S ARGUMENT BLOCK
EXCTXU <SETZM (T4)> ;CLEAR FIRST WORD FOR HIM
ADDI T2,-1(T4) ;LAST WORD OF BLOCK
HRL T4,T4 ;SETUP SOURCE AT START OF BLOCK
ADDI T4,1 ;MAKE PROPAGATING POINTER
CAIL T2,(T4) ;ONE WORD BLOCK?
EXCTUU <BLT T4,(T2)> ;ZERO BLOCK TO ENSURE ZERO FILL
MOVEI T2,(T3) ;COPY ONLY REAL DATA
REDTB1: JUMPE T2,CPOPJ## ;IF ZERO LENGTH, JUST RETURN
LOAD. T3,.LBTBL,(T1) ;GET ADDRESS OF LOCK-ASSOCIATED TABLE
HRLZ T3,T3 ;MAKE THIS THE SOURCE ADDRESS FOR BLT
HRR T3,EQLTBL ;AND USERS TABLE IS THE DESTINATION
ADDI T2,-1(T3) ;LAST WORD TO TRANSFER
EXCTXU <BLT T3,(T2)> ;COPY THE DATA FOR HIM
POPJ P, ;AND RETURN
;COME HERE IF AN ENQ REQUEST FAILED FOR SOME REASON
; THE ENTIRE CHAIN OF REQUESTS (IF ANY) MUST
; BE REMOVED FROM THE QUEUES. THE POINTER TO THE
; LAST MEMBER OF THE CHAIN IS KEPT IN THE
; LEFT HALF OF P4.
;
;ON ENTRY, THE ERROR CODE IS IN T1
BACKUP: HLRZ T3,P4 ;GET ADDRESS OF LAST Q'ED ENTRY
JUMPE T3,STOTAC## ;THERE WAS NONE--EXIT
MOVEM T1,NQERRF ;SAVE ERROR CODE
SKIPA T1,T3 ;MOVE THIS ADDRESS TO USE AS PTR
BACK2: MOVE T1,T2 ;GET ADDRESS OF LAST BLOCK
LOAD. T2,.QBLQR,(T1) ;GET PREVIOUS Q-BLOCK'S LOCATION
PUSHJ P,DEQIT ;REMOVE THE CURRENT BLOCK
JFCL ;DON'T CARE IF Q IS FLUSHED
CAIE T2,(T1) ;HAVE WE GONE IN CIRCLE?
JRST BACK2 ;NO
MOVE T1,NQERRF ;YES, GET ERROR CODE
JRST STOTAC## ;GIVE HIM ERROR CODE
SUBTTL SUBROUTINE TO PERFORM AN ENQ FUNCTION
;SUBROUTINE TO PERFORM ONE ENQ FUNCTION FOR A GIVEN RESOURCE.
;THIS ROUTINE (EXCEPT IN THE CASE OF A "MODIFY ACCESS")
; CHECKS THE LEVEL #, POOL COUNT, AND WHETHER THIS
; USER ALREADY HAS AN ENTRY QUEUED. IF ALL THESE CHECKS
; ARE OK, THE USER IS QUEUED FOR THE RESOURCE.
;
;ENTER:
; P1-P4 SET UP BY GETLOK
; PUSHJ P,ENQIT
;RETURNS:
; +1 ERROR RETURN
; +2 NORMAL RETURN
;USES T1-T4
ENQIT: HRRZ T2,FCODE ;GET SAVED FUNCTION CODE
CAIN T2,.ENQMA ;IS IT A MODIFY ACCESS?
JRST DOFC3 ;YES, DO SPECIAL STUFF
LDB T2,[POINT 9,P1,17] ;GET LEVEL #
HRRE T3,HILEVL ; AND THE STORED HIGHEST LEVEL #
HRRZ T4,P1 ;GET TYPE OF REQUEST
CAIN T4,-3 ;IS THIS A MONITOR REQUEST?
HLRE T3,HILEVL ;YES, USE HIGHEST MONITOR LEVEL #
CAMLE T2,T3 ;IS THE LEVEL NUMBER OK?
JRST ENQIT1 ;YES
TLNN P1,EN%BLN ;NO, DOES HE WANT TO BYPASS IT?
JRST ENQER1 ;NO, FLUSH HIM
MOVEI T2,ENQLS% ;YES, REMEMBER THAT THIS HAPPENED
MOVEM T2,NQERRF ; IN THE ERROR FLAG
ENQIT1: PUSHJ P,LOCKOK ;CHECK OTHER THINGS ABOUT THE LOCK
POPJ P, ; ERROR FOUND
HRRE T2,P1 ;GET CHANNEL #
JUMPL T2,ENQIT2 ;NOT A CHANNEL NUMBER
MOVE T3,DEVMOD(F) ;AND DEVICE BITS
TLNE T3,DVDSK ;IS THIS A DISK?
TLNN F,LOOKB+ENTRB ; AND HAS THE FILE BEEN 'LOOKED-UP'...
JRST HDRER9 ;NO, ERROR
ENQIT2: PUSHJ P,CHPRIV ;DOES THIS GUY HAVE THE PRIVILEGES?
POPJ P, ;NO, ERROR
PUSHJ P,FNDLOK ;DOES LOCK EXIST?
JRST ENQIT4 ;NO, WE MUST CREATE IT
;CONTINUED ON THE NEXT PAGE
;CONTINUED FROM THE PREVIOUS PAGE
PUSHJ P,CHKABT ;HAS THIS LOCK BEEN ABORTED
JRST ABTERR ;YES, INFORM THE NEW REQUESTER
LOAD. T2,.LBLVL,(T1) ;GET LEVEL #
LDB T3,[POINT 9,P1,17] ;AND NUMBER FOR NEW REQUEST
TLNE P1,EN%BLN ;DON'T CHECK IF HE DOESN'T CARE
JRST ENQIT3 ;SKIP OVER CHECK
CAIE T2,(T3) ; SAME?
JRST DOERR0 ;NO, ERROR RETURN
ENQIT3: HLRZ T3,P3 ;GET # IN POOL
LOAD. T2,.LBPUL,(T1) ; AND CORRECT # IN POOL
CAIE T2,(T3) ;AND THEY THE SAME?
JRST DOERR2 ;NO, POOL REQUEST ERROR
PUSH P,T1
MOVE T2,.CPJCH##
PUSHJ P,CHECKQ ;IS THIS GUY IN THE Q?
JRST [POP P,T1
JRST DOERR3]
POP P,T1
JRST ENQIT5 ;NO, GO PUT HIM IN IT
; HERE IF NEW LOCK
ENQIT4: MOVE T1,EQTMP4 ;GET HASH BACK AGAIN
MOVEI T2,LBLKBK ;FLAGS="LOCK-BLOCK"
TLNE P1,EN%UCW ;CODE WORD?
JRST ENQIT7 ;YES, DON'T SET TEXT FLAG
LDB T3,[POINT 3,P2,2]
CAIE T3,5 ;IS THIS A USER CODE?
TRO T2,LBTEXT ;NO, SET "TEXT" FLAG IN LOCK BLOCK
ENQIT7: TLNE P1,EN%LTL ;USER WANTS THIS ONE TO STAY AROUND?
TRO T2,LBLLTL ;YES, SET 'LONG TERM LOCK' BIT
PUSHJ P,BLDLOK ;BUILD A LOCK BLOCK
POPJ P, ;ERROR (NO CORE,BAD STRING,ETC.)
MOVEM T1,LSTLOK ;REMEMBER LAST LOCK ADDRESS
AOS %ENQNQ## ;BUMP THE NUMBER OF QUEUES
TLNE P3,-1 ;IF THIS IS A POOLED RESOURCE..
AOS %ENQNP## ; BUMP THE TOTAL OF THEM TOO
ENQIT5: SETZ T3,
SKIPL P1 ;IS THE "SHARED" BIT ON?
MOVEI T3,QBEXCL ;NO, SET EXCLUSIVE BIT IN BLOCK
TLNN P1,EN%NDR
JRST ENQIT6
TRO T3,QBLNDR
PUSHJ P,OKNDR ;OK TO NDR LOCK?
JRST STOTAC ;GIVE ERROR RETURN
PUSH P,T1 ;SAVE LOCK BLOCK ADDRESS
LOAD. T1,.LBACC,(T1) ;GET THE ACCESS-TABLE ADDRESS
CAIGE T1,CODMIN ;IS IT REALLY A SPECIAL CODE?
PUSHJ P,FILNDR## ;NO, MARK FILE AS NDR
POP P,T1 ;GET BACK LOCK BLOCK ADDRESS
ENQIT6: MOVE T4,FCODE ;GET STORED FUNCTION CODE
TDO T3,[EXP QBWAIT,0,QBPSI](T4) ;SET BIT IN FLAG WORD
TLNE P1,EN%ABT ;ABORT REQUESTED?
TRO T3,QBLABT ;YES, REMEMBER IT
TLNE P1,EN%DED ;DEADLOCK DETECTION REQUESTED?
TRO T3,QBDEAD ;YES, REMEMBER IN QUEUE BLOCK
HLRZ T2,P4 ;GET MULTIPLE REQUEST ADDRESS
PUSHJ P,QHIM ;PUT HIM ON Q
JRST DOERR6 ;NO MORE CORE LEFT
MOVEM T1,LASTQ ;REMEMBER LAST Q-BLOCK ADDRESS
PUSHJ P,BLDMSK ;BUILD THE MASK BLOCK FOR HIM
POPJ P, ;NO CORE OR MISMATCHED LENGTHS
HRL P4,T1 ;SAVE ADDRESS OF THIS ENTRY
PJRST CPOPJ1## ;SKIP RETURN
;COME HERE IF USER WANTS TO MODIFY ACCESS
DOFC3: PUSHJ P,LOCKOK ;IS THE LOCK SPEC OK?
JRST MARETN ;NO, ERROR FOUND
PUSHJ P,FNDLOK ;DOES THE LOCK EXIST?
JRST DOERR4 ;NO, GIVE USER ERROR
MOVE T2,.CPJCH##
PUSHJ P,CHECKQ ;IS HE ALREADY IN Q?
SKIPA ;YES
JRST DOERR4 ;NO, FLAG IT AS ERROR
LOAD. T2,.QBFLG,(T1) ;FETCH FLAGS
TRNN T2,QBOWNR ;IS HE THE OWNER
JRST DOFC3B ;NO
TRNN T2,QBEXCL ;EXCLUSIVE?
JRST DOFC3A ;NO
;OWNER/EXCLUSIVE
TLNN P1,EN%SHR ;HE WANTS IT SHARABLE NOW?
JRST DOFC3E ;NO, NO CHANGE
TRZ T2,QBEXCL ;CLEAR EXCLUSIVE
JRST DOFC3D ;AND STORE FLAGS
;OWNER/SHARED
DOFC3A: TLNE P1,EN%SHR ;HE WANTS IT EXCLUSIVE NOW?
JRST DOFC3E ;NO, NO CHANGE
PUSHJ P,CKONLY ;ONLY IF HE'S THE ONLY ONE
JRST DOERR5 ;SOMEONE ELSE IS SHARING ALSO
TRO T2,QBEXCL ;OKAY, SET EXCLUSIVE
JRST DOFC3D ;AND STORE UPDATED FLAGS
;HERE IF A NON-OWNER
DOFC3B: TRNN T2,QBEXCL ;EXCLUSIVE
JRST DOFC3C ;NO
;NON-OWNER/EXCLUSIVE
TLNN P1,EN%SHR ;WANTS IT SHARABLE NOW?
JRST DOFC3E ;NO, NO CHANGE
TRZ T2,QBEXCL ;CLEAR EXCLUSIVE
JRST DOFC3D ;AND STORE FLAGS
;NON-OWNER/SHARED
DOFC3C: TLNE P1,EN%SHR ;WANTS IT EXCLUSIVE NOW?
JRST DOFC3E ;NO, NO CHANGE
TRO T2,QBEXCL ;SET EXCLUSIVE
DOFC3D: STOR. T2,.QBFLG,(T1) ;STORE UPDATED FLAGS
DOFC3E:
;CONTINUED ON THE NEXT PAGE
;CONTINUED FROM THE PREVIOUS PAGE
;CHECK HERE FOR SETTING/CLEARING THE ABORT STATUS IN THE QUEUE
; BLOCK
TLNN P1,EN%ABT ;CHANGE TO ABORT STATUS?
JRST [TRNE T2,QBOWNR ;NO, OWNING QUEUE BLOCK?
TRZ T2,QBLABT ;YES, CLEAR ABORT STATUS
JRST DOFC3F]
TRNN T2,QBOWNR ;OWNING QUEUE BLOCK?
JRST DERNJQ ;NO, ERROR
TRO T2,QBLABT ;SET ABORT FLAG
DOFC3F: STOR. T2,.QBFLG,(T1) ;RESTORE FLAGS IN Q-BLOCK
;CHECK HERE FOR SETTING/CLEARING THE NO DEQUEUE ON RESET BIT
;T1-T4 ALREADY SET UP ABOVE
TLNN P1,EN%NDR ;CLEAR NO DEQUEUE ON RESET?
JRST [TRNE T2,QBOWNR ;OWNING QUEUE BLOCK?
TRZ T2,QBLNDR ;YES, CLEAR NO DEQUEUE ON RESET
JRST DOFC3G]
TRNN T2,QBOWNR ;OWNING QUEUE BLOCK?
JRST DERNJQ ;NO, ERROR
MOVE T3,T1 ;SAVE Q-BLOCK ADDRESS
LOAD. T1,.QBLB,(T1) ;LOCK BLOCK ADDRESS
PUSHJ P,OKNDR
JRST STOTAC ;GIVE ERROR RETURN
LOAD. T1,.LBACC,(T1) ;GET ACCESS TABLE ADDRESS
CAIGE T1,CODMIN ;IS IT REALLY A SPECIAL CODE?
PUSHJ P,FILNDR## ;NO, MARK THE FILE AS NDR
MOVE T1,T3 ;GET BACK Q-BLOCK ADDRESS
TRO T2,QBLNDR ;SET NO DEQUEUE ON RESET
DOFC3G: STOR. T2,.QBFLG,(T1) ;RESETORE FLAGS IN Q-BLOCK
LOAD. T1,.QBLB,(T1) ;GET LOCK BLOCK ADDRESS
PUSHJ P,LOKSKD ;SCHEDULE THIS LOCK
PJRST CPOPJ1## ;RETURN FROM "ENQIT"
;ROUTINE TO CHECK FOR SOLE OWNERSHIP OF A SHARABLE LOCK
;CALL WITH T1 CONTAINING THE ADDRESS OF A QUEUE-BLOCK
; PUSHJ P,CKONLY
; <IF OTHER OWNERS ALSO>
; <IF SOLE OWNER>
CKONLY: PUSHJ P,SAVT## ;PRESERVES ALL AC'S
MOVEI T3,(T1) ;INITIALIZE CURRENT BLOCK POINTER
CKONL1: LOAD. T3,.QBNQ,(T3) ;NEXT REQUEST
CAIN T3,(T1) ;BACK TO SELF?
JRST CPOPJ1## ;YES, GOOD RETURN
LOAD. T2,.QBFLG,(T3) ;FLAG BITS
TRNN T2,QBLKBK ;IF THIS IS THE LOCK BLOCK, IGNORE IT
TRNN T2,QBOWNR ;IS THIS ONE AN OWNER?
JRST CKONL1 ;NO, LOOP OVER WHOLE LIST
PUSHJ P,CKOMSK ;CHECK FOR NON-CONFLICTING MASKS
POPJ P, ;MATCH ON MASKS
JRST CKONL1 ;NO MATCH
;CKOMSK -- ROUTINE FOR CKONLY TO CHECK FOR MULTI-RESOURCE
; MASKS.
CKOMSK: PUSHJ P,SAVE3## ;SAVE P1-P3
LOAD. P1,.QBMSK,(T1) ;MASK ADDRESS
JUMPE P1,CPOPJ ;NO MASK IMPLIES ALL. MUST CONFLICT
LOAD. P2,.QBMSK,(T3) ;MASK ADDRESS
JUMPE P2,CPOPJ ;NO MASK IMPLIES ALL. MUST CONFLICT
TLO P1,(<POINT 36,>) ;MAKE A BYTE POINTER TO THE MASK
CKOMS1: LDB T2,P1 ;WORD FROM MASK 1
AND T2,(P2) ;AND WITH WORD OF MASK 2
JUMPN T2,CPOPJ ;FAIL IF ANY MATCHES
SOJLE P3,CPOPJ1 ;IF END OF BLOCK. NO CONFLICT
AOJA P2,CKOMS1 ;NOT END. LOOP OVER WHOLE MASK STRING
SUBTTL DEQ--DEQ A RESOURCE REQUEST
DEQ:: PUSHJ P,SAVE4## ;SAVE P1-P4
AOS %ENQTD## ;BUMP TOTAL OF DEQ'S SINCE RELOAD
SETZM ENQFLG ;THIS IS NOT AN ENQ.
MOVEI T2,DQMXFC ;SET MAX FUNCTION CODE
PUSHJ P,SETUP ;DO PRELIMINARY THINGS
POPJ P, ;ERROR RETURN
JRST @[EXP DEQFC0,DEQFC1,DEQFC1](T3)
DEQFC1: PUSHJ P,FNDPDS## ;GET THIS GUY'S PDB
IFN FTMP,<
PUSHJ P,EQLOCK ;KEEPS OTHERS OUT OF THE DATABASE
>
HRRZ T1,.PDEQJ##(W) ;GET START OF JOB Q
JUMPE T1,DERNJQ ;EXIT IF NO JOB Q
HRRZ T3,FCODE ;GET FUNCTION
SETZM DQFLAG ;ASSUME NO LOCKS
DEQ0: LOAD. T2,.QBNJQ,(T1) ;GET NEXT JOB IN Q POINTER
LOAD. T4,.QBRID,(T1) ;GET REQUEST ID
CAME T4,RBLOCK ;IF SAME AND CODE=2, DEQ
CAIN T3,.DEQDA ; OR IF CODE=1, THEN DEQ
PUSHJ P,DEQIT ;REMOVE CURRENT ONE FROM Q
MOVE T1,T2 ;GET NEXT Q-ENTRY
JUMPN T2,DEQ0 ;KEEP GOING IF THERE IS ONE..
SKIPE DQFLAG ;DID U DEQ ANYTHING?
JRST CPOPJ1## ;SKIP RETURN
JRST DERNJQ ;NO, ERROR
;COME HERE FOR A STANDARD DEQ (FUNCTION CODE=0)
; ENTIRE RESOURCE BLOCK MUST BE SCANNED
; AND CHECKED AND EACH LOCK MUST BE DEQ'ED.
DEQFC0: PUSHJ P,CHKBLK ;CHECK OUT THE USER'S PARAMETER BLOCK
JRST STOTAC## ; ERROR
IFN FTMP,<
PUSHJ P,EQLOCK ;INTERLOCK ON EQ
>
FC0.2: PUSHJ P,GETLOK ;GET A NEW LOCK
PUSHJ P,LOCKOK ;IS THE LOCK SPEC OK?
JRST FC0ERR ;NO
PUSHJ P,CHPRIV ;ARE THE PRIVILEGES OK?
JRST FC0ERR ;NO
PUSHJ P,FNDLOK ;FIND THIS LOCK IN DATA BASE
JRST FCERR1 ;DOESN'T EXIST
MOVE T2,.CPJCH##
PUSHJ P,CHECKQ ;IS HE IN THE Q?
SKIPA ;YES
JRST FCERR1 ;NO, ITS AN ERROR
TLNN P3,-1 ;IS THIS A POOLED RESOURCE?
JRST FC0.3 ;NO
LOAD. T2,.QBNRP,(T1) ;GET NUMBER THIS GUY HAS OUT
CAIN T2,(P3) ;IS HE RETURNING ALL OF THEM?
JRST FC0.3 ;YES, HE'S GIVING THEM ALL BACK
CAIG T2,(P3) ;IS HE RETURNING TOO MUCH?
JRST FCERR0 ;YES, DON'T LET HIM DO IT
SUBI T2,(P3) ;COMPUTE NUMBER HE STILL HAS
STOR. T2,.QBNRP,(T1) ;UPDATE HIS TOTAL
LOAD. T1,.QBLB,(T1) ;GET LOCK-BLOCK
LOAD. T2,.LBAVL,(T1) ;GET # OF FREE RESOURCES
ADDI T2,(P3) ;ADD THOSE HE IS RETURNING
STOR. T2,.LBAVL,(T1) ;UPDATE # AVAILABLE
PUSHJ P,LOKSKD ;..AND SCHEDULE LOCK-BLOCK
JRST FC0.4 ;DON'T DEQ THIS Q-BLOCK
FC0.3: PUSHJ P,STOTBL ;STORE USER SUPPLIED TABLE INFORMATION
PUSHJ P,DEQIT ;DEQ THIS ENTRY
JRST FC0.4 ;DON'T SET ERROR FLAG
FCERR0: SKIPA T1,[ENQBP%] ;TRYING TO GIVE BACK TOO MUCH
FCERR1: MOVEI T1,ENQNE% ;NOT ENQ'ED ON THIS LOCK
FC0ERR: HRRM T1,NQERRF ;REMEMBER THAT THERE WAS AN ERROR
FC0.4: PUSHJ P,CHKCNT ;ARE THERE MORE LOCKS?
JRST FC0.2 ;YES, GO BACK
SKIPN T1,NQERRF ;WAS THERE AN ERROR?
JRST CPOPJ1## ;NO, SKIP RETURN
JRST STOTAC## ;GIVE ERROR RETURN
SUBTTL DEQ A PARTICULAR Q-ENTRY
;SUBROUTINE TO DEQ ONE Q-ENTRY
;
;CALL:
; MOVE T1,Q-ENTRY-ADDRESS
; PUSHJ P,DEQIT
; RETURN HERE ALWAYS
;
;ON RETURN, ALL SCHEDULING FOR THE Q-ENTRY AND THE LOCK-BLOCK
; HAS BEEN DONE
;
;CLOBBERS: NONE ;DQFLAG IS BUMPED ON EXIT
DEQIT: AOS DQFLAG ;FLAG DOING A DEQ. FUNCTION
PUSHJ P,SAVT## ;SAVE T-REGISTERS (RESET NEEDS THEM)
IFN FTMP,<
PUSHJ P,HAVEQ
STOPCD .+1,DEBUG,ENQDNL ;++DEQ NOT INTERLOCKED
>
LOAD. T3,.QBNJQ,(T1) ;GET NEXT JOB PTR
LOAD. T2,.QBLJQ,(T1) ;AND LAST JOB PTR
STOR. T3,.QBNJQ,(T2) ;RELINK JOB Q
SKIPE T3 ;THIS MAY BE THE END OF THE JOB Q
STOR. T2,.QBLJQ,(T3) ;MAKE NEXT ENTRY POINT TO LAST ONE
LOAD. T2,.QBLQ,(T1) ;GET LAST Q-PTR
LOAD. T3,.QBNQ,(T1) ; AND NEXT Q-ENTRY
STOR. T2,.QBLQ,(T3) ;RELINK THESE Q'S
STOR. T3,.QBNQ,(T2) ; SAME
LOAD. T2,.QBLQR,(T1) ;GET NEXT LINKED REQUEST
LOAD. T3,.QBNQR,(T1) ; POINTERS
STOR. T2,.QBLQR,(T3) ;RELINK REQUEST Q
STOR. T3,.QBNQR,(T2)
MOVE T2,T1 ;PUT Q-BLOCK ADDRESS IN T2
LOAD. T1,.QBLB,(T2) ;GET LOCK BLOCK ADDR
LOAD. T3,.LBNQ,(T1) ;GET ADDR OF NEXT Q
CAIN T3,(T1) ;IS Q EMPTY?
JRST FLUSH ;YES, GO FLUSH IT
LOAD. T3,.QBFLG,(T2) ;GET FLAGS AGAIN
TRNN T3,QBOWNR ;OWNER?
JRST FLSHQ ;NO, GO FLUSH IT
LOAD. T3,.QBNRP,(T2) ;YES, GET ALLOCATION
LOAD. T4,.LBAVL,(T1) ;AND # AVAILABLE
ADD T3,T4 ;COMBINE THEM
STOR. T3,.LBAVL,(T1) ;PUT BACK IN POOL
JRST FLSHQ ;NOW, GO AND FLUSH Q
;COME HERE TO FLUSH A LOCK BLOCK AND A Q BLOCK FROM THE DATA BASE
FLUSH: LOAD. T3,.LBPUL,(T1) ;GET NUMBER IN RESOURCE POOL
SKIPE T3 ;IS IT POOLED?
SOS %ENQNP## ;YES, DECREMENT THAT TOTAL
LOAD. T3,.LBFLG,(T1) ;GET FLAGS
TRNE T3,LBLLTL ;IS THIS A PERMANENT LOCK?
PJRST FLUSH1 ;YES DON'T DELETE NOW. GO START TIMER
PUSH P,T1 ;SAVE LOCK BLOCK ADDRESS
PUSHJ P,FLSHQ1 ;DELETE Q-BLOCK WITHOUT RESCHEDULING
POP P,T1 ;RESTORE LOCK BLOCK ADDRESS
PJRST DLTLOK ;DELETE THE LOCK BLOCK
;HERE IF THE LOCK BLOCK HAS THE LONG-TERM-LOCK BIT SET. START
;THE TIMER, THEN GO DELETE THE QUEUE BLOCK.
FLUSH1: MOVE T3,%ENQLT## ;GET NUMBER OF MINUTES TO WAIT
STOR. T3,.LBPLT,(T1) ;PERMANENT LOCK TIMER VALUE
PJRST FLSHQ1 ;DELETE Q-BLOCK WITHOUT RESCHEDULING
;HERE TO DELETE THE QUEUE BLOCK. ENTER AT FLSHQ1 TO SKIP RESCHEDULING
;IF THE ASSOCIATED LOCK BLOCK HAS EITHER BEEN DELETED OR NOW HAS
;A NULL QUEUE.
FLSHQ: PUSHJ P,RSKED ;DO RE-SCHEDULING FOR THIS Q-BLOCK
FLSHQ1: PUSHJ P,DLTMSK ;DELETE MASK BLOCK, IF ANY
MOVEI T1,QBSIZE ;SET UP SIZE
PJRST GIVWDS## ;FREE UP THIS SPACE NO RETURN
;SUBROUTINE TO DELETE A LOCK BLOCK.
;CALL:
; MOVE T1, LOCK-BLOCK ADDRESS
; PUSHJ P,DLTLOK
; ALWAYS RETURNS HERE
;PRESERVES ALL AC'S
DLTLOK: PUSHJ P,SAVT## ;SAVE T1-T4
PUSHJ P,DLTTBL ;DELETE LOCK ASSOCIATED TABLE, IF ANY
MOVE T2,T1 ;COPY LOCK BLOCK ADDRESS
LOAD. T3,.LBFLG,(T2) ;GET FLAGS
TRNN T3,LBLAUC ;INCREMENTED A.T. READ COUNT?
JRST DLTLK1 ;NO, DON'T NEED TO DECREMENT
LOAD. T1,.LBACC,(T2) ;GET ACCESS TABLE ADDRESS
CAIGE T1,CODMIN ;IS IT REALLY A SPECIAL CODE?
PUSHJ P,FILDRC## ;NO, DECREMENT READER COUNT
DLTLK1: LOAD. T3,.LBNHS,(T2) ;GET NEXT HASH PTR
LOAD. T4,.LBLHS,(T2) ; AND LAST HASH PTR
STOR. T3,.LBNHS,(T4) ;RELINK THEM
STOR. T4,.LBLHS,(T3) ; SO THIS BLOCK DISAPPEARS
LOAD. T1,.LBLEN,(T2) ;GET LENGTH
SOS %ENQNQ## ;REDUCE NUMBER OF QUEUES
PJRST GIVWDS## ;GIVE BACK THE SPACE TO MONITOR
SUBTTL ENQC QUEUE CONTROLLER UUO
;THIS UUO HAS FOUR FUNCTIONS:
; 0. RETURN STATUS OF LIST OF RESOURCES
; 1. RETURN USER'S LOCK QUOTA
; 2. SET USER'S LOCK QUOTA (PRIVILEGED)
; 3. DUMP OUT QUEUE STRUCTURE INTO USER BUFFER
;FOR OPTION 0, THREE WORDS ARE RETURNED FOR EACH LOCK SPECIFIED BY THE
; USER. THE 1ST WORD HAS THE FOLLOWING FORMAT:
;
; B0 ERROR BIT
; B1 THIS USER IS THE OWNER OF THE LOCK
; B2 THIS USER HAS ISSUED AN ENQ FOR THE LOCK
; B3 THE OWNER OF THE LOCK HAS EXCLUSIVE ACCESS
; B9-17 LEVEL NUMBER OF RESOURCE
; B18-26 CONTEXT NUMBER OF OWNER
; B27-35 JOB NUMBER OF OWNER/ERROR CODE
; THE JOB NUMBER OF THE OWNER MAY BE
; ONLY ONE OF MANY OWNERS IF THE
; LOCK IS SHARED.
;
;THE SECOND WORD IS A 36-BIT TIME-STAMP WHICH REPRESENTS
; THE TIME AT WHICH THE RESOURCE WAS LAST
; "ALLOCATED". THIS PROVIDES A METHOD OF DETERMINING
; IF A USER HAS HELD THE RESOURCE FOR AN EXCESSIVE
; AMOUNT OF TIME.
;
;THE THIRD WORD HAS THE REQUEST-ID IN THE RIGHT HALF.
;IF BIT 2 IN WORD 1 IS ON, THIS IS THE CALLER'S ID
;OTHERWISE, IT'S THE OWNER'S ID.
;
;IF THE LOCK HAS NO CURRENT OWNER, THE STATUS WORD WILL HAVE
; -1 IN THE RIGHT HALF
ENQC:: PUSHJ P,SAVE4## ;PRESERVE P1-P4
SETZM ENQFLG ;THIS IS NOT AN ENQ.
MOVEM M,SBLOCK ;SAVE ADDRESS OF AC FOR LATER
MOVEI T2,QCMXFC ;SET UP MAX FUNCTION CODE
PUSHJ P,SETUP ;DO STANDARD STUFF
POPJ P, ;ERROR IN FUNCTION CODE
JRST @[EXP QC0,QC1,QC2,QC3](T3)
;ENQC. FUNCTION 0 (.ENQCS), RETURN STATUS
QC0: PUSHJ P,CHKBLK ;CHECK LEGALITY OF RESOURCE BLOCK
JRST STOTAC## ; ERROR FOUND--ABORT
IFN FTMP,<
PUSHJ P,EQLOCK ;
>
AOS SBLOCK ;GET ADDRESS OF AC BACK
HRR M,SBLOCK ;GET AC+1
PUSHJ P,GETWDU## ;GET CONTENTS OF AC+1
SOS T1 ;PUTWD1 BUMPS IT
HRRZM T1,SBLOCK ;SAVE IT
QC0.0: PUSHJ P,GETLOK ;GET A LOCK
PUSHJ P,LOCKOK ;IS THE LOCK SPEC OK?
JRST QCERR ;NO, RETURN ERROR CODE
PUSHJ P,FNDLOK ;DOES THIS QUEUE EXIST?
JRST [MOVEI P3,-1 ;SET STATUS=-1
SETZB P4,P2 ;CLEAR TIME-STAMP
JRST TELHIM]
PUSHJ P,COUNTQ ;COUNT THE QUEUE LENGTH
JUMPE T2,[MOVEI P3,-1 ;NO ONE IN QUEUE, SET STATUS=-1
SETZB P4,P2 ;CLEAR TIME-STAMP
JRST TELHIM]
HRLZ P2,T2 ;PUT IT IN LEFT HALF
MOVE T2,.CPJCH##
PUSHJ P,CHECKQ ;YES, BUT AM I IN IT?
JRST GOTHIM ; YES
SETZB P3,P4 ;CLEAR AC
LOAD. T1,.LBNQ,(T1) ;GET FIRST Q-BLOCK IN QUEUE (T1=LOCK)
LOAD. T2,.QBRID,(T1) ;REQUEST ID
HRR P2,T2 ;PUT IT IN RIGHT HALF
LOAD. T2,.QBFLG,(T1) ;AND FLAGS FOR THIS ENTRY
TRNE T2,QBOWNR ;IS HE THE OWNER?
JRST GOTHM2 ;YES
MOVEI P3,-1 ;SET RH OF STATUS TO -1
JRST TELLVL ;AND GO GET LEVEL #
QCERR: HRLI T1,EN%QCE ;SET ERROR BIT IN STATUS WORD
MOVE P3,T1 ;MOVE ENTIRE WORD TO P3
HRRM P3,NQERRF ;REMEMBER THAT AN ERROR OCCURED
SETZB P2,P4 ;CLEAR OTHER STUFF
JRST TELHIM ;AND GIVE IT BACK TO USER
;COME HERE WHEN THE CURRENT JOB IS IN THE QUEUE
GOTHIM: MOVSI P3,EN%QCQ ;TELL HIM HE'S IN THE QUEUE
LOAD. T2,.QBRID,(T1) ;GET REQUEST ID.
HRR P2,T2 ;PUT IT IN RIGHT HALF
LOAD. T2,.QBFLG,(T1) ;GET HIS FLAG'S
TRNE T2,QBOWNR ;IS HE THE OWNER?
JRST GOTHM1 ;YES, GO AND SET THE BIT
LOAD. T1,.QBLB,(T1) ;NO, GO AND FIND THE OWNER
LOAD. T1,.LBNQ,(T1) ;GET FIRST ENTRY IN QUEUE
LOAD. T2,.QBFLG,(T1) ;GET Q-BLOCK FLAGS
TRNN T2,QBINVS ;IS IT INVISIBLE?
JRST GOTHM2 ;NO
HRRI P3,-1 ;YES, TELL USER THAT THERE IS NO OWNER
JRST TELLVL
GOTHM1: TLO P3,EN%QCO ;TELL HIM HE'S THE OWNER
GOTHM2: TRNE T2,QBEXCL ;EXCLUSIVE ACCESS?
TLO P3,EN%QCX ;YES, SET THE BIT
LOAD. T2,.QBJCH,(T1) ;GET JOB/CONTEXT HANDLE
HRR P3,T2 ;MOVE INTO STATUS WORD
TELLVL: LOAD. T1,.QBLB,(T1) ;GET LOCK-BLOCK ADDRESS
LOAD. T2,.LBLVL,(T1) ; AND LEVEL #
DPB T2,[POINT 9,P3,17] ;STICK IT IN
LOAD. P4,.LBTIM,(T1) ;GET TIME-STAMP
TELHIM: MOVE T1,P3 ;MOVE STATUS WORD
HRR M,SBLOCK ;GET STATUS BLOCK
PUSHJ P,PUTWD1## ;GIVE WORD TO USER
MOVE T1,P4 ;GET TIME-STAMP
PUSHJ P,PUTWD1## ;PUT IT OUT
MOVE T1,P2 ;GET ID
PUSHJ P,PUTWD1## ;PUT IT OUT
HRRM M,SBLOCK ;PUT IT BACK
PUSHJ P,CHKCNT ;MORE LOCKS TO GO?
JRST QC0.0 ;YES
SKIPN T1,NQERRF ;WAS THERE AN ERROR?
JRST CPOPJ1## ;NO, EXIT
JRST STOTAC## ;YES, RETURN ERROR CODE
;ENQC. FUNCTION 1 (.ENQCG), RETURN USER'S QUOTA
;
QC1: PUSHJ P,GETQUO ;GET CURRENT QUOTA
JRST STOTAC## ; ERROR
TLZ T1,-1 ;CLEAR PDB FLAGS
JRST GUDXT2 ;SKIP RETURN WITH QUOTA IN AC
;ENQC. FUNCTION 2 (.ENQCC), SET USER'S QUOTA
;
QC2: TLZ M,400000 ;FOR PRVBIT
MOVSI T1,JP.POK
PUSHJ P,PRVBIT## ;AM I [1,2] OR JACCT?
TLOA M,400000 ;YES, IT'S OK
JRST HDRERC ;NO, EXIT
PUSHJ P,GETQUO ;GET CURRENT QUOTA
JRST STOTAC## ; ERROR
TLO T1,EQ.HBS## ;REMEMBER THAT IT'S BEEN SET
HLR T1,P1 ;GET NEW QUOTA
MOVEM T1,.PDEQQ##(W) ;STORE IT AWAY
JRST CPOPJ1## ;.AND EXIT
;SUBROUTINE TO RETURN USER'S QUOTA
;
;CALL:
; PUSHJ P,GETQUO
; ERROR RETURN
; NORMAL RETURN
;
;ON RETURN, T1 = QUOTA
; P1 = HEADER WORD OF EFFECTIVE ADDRESS OF UUO (NEW QUOTA,,JOB #)
;
GETQUO: PUSHJ P,GETWDU## ;GET FIRST WORD
MOVE P2,J ;SAVE CURRENT JOB NUMBER
MOVE P1,T1 ; AND HEADER WORD
HRRE J,P1 ;JOB NUMBER
CAMN J,[-1] ;IF -1
MOVE J,.CPJOB## ;USE CURRENT
PUSHJ P,FNDPDB## ;FIND USER'S PDB
JRST QCERR1 ;BAD JOB NUMBER
MOVE T1,.PDEQQ##(W) ;FETCH USER'S QUOTA
TLZN T1,EQ.HBS##
HRRZ T1,%ENQDF
MOVE J,P2 ;RESTORE CURRENT JOB NUMBER
JRST CPOPJ1## ;SKIP RETURN
SUBTTL DATA-STRUCTURE DUMP UTILITY
;ENQC. FUNCTION 3 (.ENQCD), DUMP ENQ/DEQ DATABASE.
;THIS OPTION OF THE ENQC. UUO DUMPS THE ENTIRE QUEUE STRUCTURE
; INTO A USER-SPECIFIED PARAMETER BLOCK. THIS FUNCTION IS
; RESTRICTED TO PEEK/SPY PRIVILEGE AND SHOULD BE USEFUL ONLY IN
; EXCEPTION CIRCUMSTANCES.
;
QC3: MOVSI T1,PVSPYM!PVSPYA ;GET SPY BITS
PUSHJ P,PRVBIT## ;CAN HE SPY?
SKIPA ;YES, LET HIM THRU
JRST HDRERC ;NO, FLUSH THIS REQUEST
IFN FTMP,<
PUSHJ P,EQLOCK ;INTERLOCK ON EQ RESOURCE
>
HRRZ T1,RBLOCK ;GET ADDRESS OF HIS BLOCK
PUSHJ P,GETWDU## ;GET LENGTH OF BLOCK
SOJL T1,QCERR2 ;LENGTH MUST BE POSITIVE
MOVEM T1,EQTMP1 ;SAVE IT FOR LATER
MOVEI P1,HSHLEN##-1 ;INIT POINTER TO HASH TABLE
;GET THE NEXT ENTRY IN THE HASH TABLE
QC3.1: HRRZ P2,HSHTAB##(P1) ;GET THIS ENTRY
CAIE P2,HSHTAB##(P1) ;IS IT EMPTY?
JRST QC3.2 ;NO, GO GET LOCK
QC3.1A: SOJGE P1,QC3.1 ;MORE?
PUTEND: SETO T1, ;YES, SET UP INSERT -1 AT END
SOSL EQTMP1 ;IS THERE ROOM?
PUSHJ P,PUTWD1## ;YES, DO IT
JRST CPOPJ1## ;EXIT FROM UUO
;COME HERE TO SEARCH A PARTICULAR CHAIN IN THE HASH TABLE
;
;P1- ENTRY IN HASH TABLE
;P2- LOCK BLOCK ON CHAIN
QC3.1B: LOAD. P2,.LBNHS,(P2) ;GET NEXT LOCK-BLOCK ON CHAIN
CAIN P2,HSHTAB##(P1) ;BACK TO HASH TABLE?
JRST QC3.1A ;YES
QC3.2: LOAD. T1,.LBLEN,(P2) ;GET LENGTH OF LOCK BLOCK
SUBI T1,LBSIZE-2 ;FIND LENGTH OF STATUS ENTRY
CAMLE T1,EQTMP1 ;IS THERE ROOM IN BLOCK?
JRST PUTEND ;NO, PUT END MARKER IN IT
EXCH T1,EQTMP1 ;YES, UPDATE LENGTH LEFT
SUBM T1,EQTMP1 ;...
LOAD. T1,.LBACC,(P2) ;GET ACCESS TABLE ADDR
LOAD. T2,.LBFLG,(P2) ;..AND FLAGS
LOAD. T3,.LBLVL,(P2) ;..AND LEVEL
HRL T1,T3 ;PUT LEVEL NUMBER IN WORD
TLO T1,EN%QCL ;THIS IS A LOCK BLOCK
TRNE T2,LBTEXT ;DOES IT HAVE TEXT?
TLO T1,EN%QCT ;YES, SET THE BIT
PUSHJ P,PUTWD1## ;STORE IT AWAY
LOAD. T1,.LBPWD,(P2) ;GET POOLED LOCK WORD
PUSHJ P,PUTWD1## ;STORE IT
LOAD. T1,.LBTIM,(P2) ;GET TIME-STAMP
PUSHJ P,PUTWD1## ;GIVE IT TO USER
LOAD. P3,.LBLEN,(P2) ;GET LENGTH BACK AGAIN
SUBI P3,LBSIZE ;FIND SIZE OF TEXT/CODE
MOVEI P4,O.TEXT(P2) ;SET UP POINTER TO TEXT
QC3.4: MOVE T1,(P4) ;GET WORD OF TEXT
PUSHJ P,PUTWD1## ;STORE IT
AOS P4 ;BUMP POINTER
SOJN P3,QC3.4 ;MORE?
LOAD. P3,.LBNQ,(P2) ;GET 1ST Q-BLOCK
;FALL THRU TO NEXT PAGE...
;COME HERE TO DUMP OUT A Q-BLOCK ENTRY
QC3.4A: CAMN P3,P2 ;ARE WE BACK AT LOCK-BLOCK?
JRST QC3.1B ;YES, GET NEXT LOCK IN CHAIN
MOVE T1,EQTMP1 ;GET LENGTH LEFT
SUBI T1,QBSIZE ;UPDATE IT
JUMPL T1,PUTEND ;JUMP IF NO ROOM
MOVEM T1,EQTMP1 ;YES
LOAD. T1,.QBJCH,(P3) ;GET JOB/CONTEXT HANDLE
LOAD. T2,.QBFLG,(P3) ;AND FLAGS
TRNN T2,QBOWNR ;IS HE THE OWNER?
JRST QC3.5 ;NO
TLO T1,EN%QCO ;YES, SET BIT
JRST QC3.6 ;KEEP GOING
QC3.5: TRNE T2,QBWAIT ;NOT OWNER--IS HE WAITING?
TLO T1,EN%QCB ;YES, SET BLOCKED BIT
QC3.6: TRNE T2,QBEXCL ;EXCLUSIVE?
TLO T1,EN%QCX ;YES, SET IT
TRNE T2,QBLNDR ;NOT DEQ'ED ON RESET?
TLO T1,EN%QCN ;YES, SET IT
TRNE T2,QBLABT ;ABORT?
TLO T1,EN%QCA ;YES, SET IT
TRNE T2,QBINVS ;INVISIBLE?
TLO T1,EN%QCI ;YES, SET IT
TRNE T2,QBDEAD ;CHECK FOR DEADLOCK?
TLO T1,EN%QCD ;YES, SET IT
PUSHJ P,PUTWD1## ;STORE WORD
LOAD. T1,.QBRID,(P3) ;GET REQUEST ID
LOAD. T2,.LBPUL,(P2) ;GET LOCK-BLOCK POOL COUNT
LOAD. T3,.QBGRP,(P3) ;GET GROUP #
SKIPE T2 ;IS IT A POOLED RESOURCE
LOAD. T3,.QBNRP,(P3) ;GET # HE WANTS
HRL T1,T3 ;FORM WORD
PUSHJ P,PUTWD1## ;GIVE IT TO USER
LOAD. P3,.QBNQ,(P3) ;GET NEXT Q-BLOCK
JRST QC3.4A ;GO CHECK IF WE ARE BACK AT LOCK
;SUBROUTINE TO VALIDATE THE HEADER WORD AND CHECK ALL
; ENTRIES IN THE RESOURCE BLOCK FOR ADDRESS CHECK, ETC.
;
;CALL:
; PUSHJ P,CHKBLK
; HERE IF ERROR DISCOVERED (ERROR CODE IN T1)
; NORMAL RETURN
;
;
;CLOBBERS: T1-T4,P1-P3,M
;
CHKBLK:
IFN FTMP,<
PUSHJ P,HAVEQ ;DOES HE HAVE EQ RESOURCE
CAIA ;NO, OKAY
STOPCD .+1,DEBUG,ENQAVE ;++ALREADY HAVE EQ
>
HRR M,RBLOCK ;GET PARAMETER BLOCK ADDRESS
PUSHJ P,GETWDU## ;GET THE HEADER WORD
LDB T2,[POINT 6,T1,5] ;LENGTH OF BLOCK HEADER
CAIN T2,0 ;ANY HEADER SIZE SPECIFIED?
MOVEI T2,2 ;NO, MAKE IT 2 (HISTORICAL)
CAILE T2,HDRMAX ;WITHIN DEFINED RANGE?
JRST BFERR ;NO, TOO MANY ARGUMENTS
MOVEM T2,HDRSIZ ;NOTE HEADER LENGTH
HRRZ T2,T1 ;TOTAL LENGTH OF THE BLOCK
SUB T2,HDRSIZ ;NUMBER OF WORDS FOR LOCK BLOCKS
LDB T4,[POINT 12,T1,17] ;NUMBER OF LOCKS
IDIVI T2,(T4) ;COMPUTE OF WORDS PER LOCK
JUMPN T3,BFERR ;IF NON-ZERO REMAINDER
CAIL T2,LKMIN ;IF LOCK TOO SMALL
CAILE T2,LKMAX ;OR TOO LARGE
JRST BFERR
MOVEM T2,LOKSIZ ;REMEMBER PER-LOCK BLOCK LENGTH
HRLZM T4,LOCKCT ;SAVE LOCK-COUNT,,0
HRRE T4,T4 ;GET # OF LOCKS
JUMPLE T4,HDRERB ;BAD LOCK COUNT
IMUL T4,LOKSIZ ;COMPUTE WHAT LENGTH SHOULD
PUSHJ P,FNDPDS## ;FIND PDB OR DIE
PUSHJ P,GETLVL ;GET LEVEL # OF HIGHEST LOCK
MOVEM T1,HILEVL ;SAVE IT FOR USE LATER
SETZ T1, ;DEFAULT REQUEST ID IS 0
MOVE T2,HDRSIZ ;GET THE SIZE OF THE HEADER
CAIL T2,2 ;DID HEADER INCLUDE REQUEST ID?
PUSHJ P,GETWD1## ;GET THE REQUEST ID
MOVEM T1,REQID ;SAVE IT FOR LATER
SETZ T1, ;DEFAULT TIME LIMIT IS FOREVER
MOVE T2,HDRSIZ ;GET THE SIZE OF THE HEADER
CAIL T2,3 ;DID HEADER INCLUDE TIME LIMIT?
PUSHJ P,GETWD1## ;YES, GET IT
MOVEM T1,TIMLIM ;SAVE IN CASE WE BLOCK
CHKBK2: PUSHJ P,GETLOK ;GET A LOCK SPEC
TLNE P1,EN%UCW ;CODE WORD?
JRST CHKBK3 ;YES, DON'T ADDRESS CHECK
MOVE T1,P2 ;ARGUMENT TO CHKSTR
PUSHJ P,CHKSTR ;MAKE SURE STRING IS IN CORE AND LEGAL
POPJ P, ;PROPAGATE ERROR
CHKBK3: SKIPN EQLMSK ;CHECK FOR MASK ARGUMENT
JRST CHKBK4 ;IF NONE
HRRZ T1,EQLMSK ;MASK WORD ADDRESS
HLRZ T2,EQLMSK ;AND LENGTH
CAMLE T2,%ENQMM## ;IS IT OF LEGAL LENGTH?
JRST MWLERR ;IF NO
PUSHJ P,ARNGE## ;RANGE CHECK
JRST UADERR## ;ADDRESS IS ILLEGAL
JRST UADERR## ;ADDRESS IS ILLEGAL FOR I/O
CHKBK4: SKIPN EQLTBL ;DID USER SPECIFY A LOCK TABLE?
JRST CHKBK5 ;NO, SKIP ADDRESS CHECKS
HRRZ T1,EQLTBL ;GET START ADDRESS
HLRZ T2,EQLTBL ;AND LENGTH
CAMLE T2,%ENQMT## ;MAXIMUM TABLE LENGTH
JRST TBLERR ;TABLE SIZE TOO LARGE
PUSHJ P,ARNGE## ;RANGE CHECK
JRST UADERR## ;ADDRESS IS ILLEGAL
JRST UADERR## ;ADDRESS IS ILLEGAL FOR I/O
CHKBK5: PUSHJ P,CHKCNT ;UPDATE LOCK COUNT AND CHECK IT
JRST CHKBK2 ;THERE'S MORE LOCKS TO GO
HLLZS LOCKCT ;RESET LOCK-COUNT WORD
PJRST CPOPJ1## ;SKIP RETURN
SUBTTL QUEUE SCHEDULING SUBROUTINES
;SUBROUTINE TO INITIATE SCHEDULING AFTER ONE DEQ CALL
;
;CALL:
; MOVE T1,LOCK-BLOCK-ADDR
; MOVE T2,Q-BLOCK-ADDR
; PUSHJ P,RSKED
; RETURN HERE ALWAYS
;
;
RSKED: PUSH P,T2 ;SAVE Q-BLOCK ADDRESS
PUSH P,T1 ;SAVE LOCK-BLOCK ADDRESS
LOAD. T1,.QBNQR,(T2) ;GET NEXT REQUEST
CAIN T1,(T2) ;IS IT A MULTIPLE REQUEST?
JRST RSKED3 ;NO, DON'T RESCHEDULE THE Q-ENTRY
MOVEM T2,EQTMP4 ;SAVE Q-BLOCK ADDRESS
PUSHJ P,QSKD ;SCHEDULE THIS Q-BLOCK
JRST RSKED3 ;GO ON AND SCHEDULE LOCK
MOVE T2,EQTMP4 ;GET Q-BLOCK ADDRESS BACK
LOAD. T4,.QBFLG,(T2) ;GET FLAGS OF OLD REQUEST
JUMPN T1,RSKED1 ;JUMP IF SCHEDULER DID SOMETHING
TRNE T4,QBOWNR ;WAS HE AN OWNER?
JRST RSKED3 ;YES, DON'T GIVE AN INTERRUPT
RSKED1:
IFN FTPI,<
TRNN T4,QBPSI ;DOES THIS USER EXPECT AN INTERRUPT?
JRST RSKED2 ;NO, HE IS BLOCKED
PUSH P,J ;SAVE J
LOAD. J,.QBJCH,(T2) ;GET JOB/CONTEXT HANDLE OF USER
MOVE T1,T2 ;COPY LOCK BLOCK ADDRESS
SETZ T2, ;INDICATE NORMAL REQUEST
PUSHJ P,GENPSI ;YES, GIVE HIM ONE
POP P,J ;RESTORE J
JRST RSKED3 ; AND GO ON TO SCHEDULE LOCK
>;END OF IFN FTPI
RSKED2: LOAD. T1,.QBJCH,(T2) ;GET HIS JOB NUMBER
PUSHJ P,CTXWAK## ;GO AND WAKE HIM UP
STOPCD .+1,JOB,ENQCWD ;++CAN'T WAKE JOB/CONTEXT AFTER DEQ.
RSKED3: POP P,T1 ;GET LOCK-BLOCK BACK AGAIN
PUSHJ P,LOKSKD ;SCHEDULE LOCK BLOCK
JRST T2POPJ## ;GET Q-BLOCK ADDRESS BACK AND RETURN
;SUBROUTINE TO SCHEDULE ONE Q REQUEST CHAIN
;
;CALL:
; MOVE T1,Q-BLOCK-ADDR
; PUSHJ P,QSKD
; RETURN HERE IF REQUEST NOT LOCKED
; HERE IF FULLY LOCKED
; T1 = 0 IF ALREADY LOCKED BEFORE THIS CALL
; T1 =-1 IF THIS CALL DID ANY LOCKING
;
;
QSKD: PUSHJ P,SAVE2## ;SAVE P1-P2
SETZM QSKDF ;ASSUME LOCK ALREADY LOCKED
MOVEM T1,QSKDQ ;SAVE THE ADDRESS OF THIS Q-BLOCK
QSKD0: PUSHJ P,SETINV ;SET INVISIBLE BITS
JRST QSKD1 ;GO MAKE SCHEDULING PASS
JRST QSKD6 ;LOCK IS ALREADY LOCKED
QSKD1: MOVE T1,QSKDQ ;GET ADDR OF THIS BLOCK AGAIN
QSKD2: MOVEM T1,QSKDT ;SAVE IT TEMPORARILY
LOAD. T2,.QBMSK,(T1) ;GET THE MASK WORD
MOVEM T2,QSKDM ;SAVE FOR FUTURE REFERENCE
LOAD. T2,.QBLB,(T1) ;GET POINTER TO LOCK BLOCK
LOAD. T2,.LBNMS,(T2) ;GET LENGTH OF MASK BLOCK
MOVEM T2,QSKDN ;SAVE
LOAD. T2,.QBGRP,(T1) ;GET GROUP NUMBER
MOVEM T2,QSKDG ;SAVE IT
LOAD. T2,.QBFLG,(T1) ;GET FLAGS
TRNE T2,QBOWNR+QBINVS ;IS THIS THE OWNER OR IS IT INVISIBLE?
JRST QSKD5 ;YES, CONTINUE SCANNING SIDEWAYS
QSKD3: LOAD. T1,.QBLQ,(T1) ;GET PREVIOUS BLOCK IN QUEUE
MOVE T2,QSKDT ;GET THIS QUEUE BLOCK ADDRESS AGAIN
LOAD. T3,.QBFLG,(T2) ;AND FLAGS FROM SAME
LOAD. T4,.QBFLG,(T1) ;AND FLAGS FROM PREVIOUS
TRNE T4,LBLKBK ;IS THIS A LOCK BLOCK?
JRST QSKD4 ;YES, WE ARE AT TOP OF QUEUE
TRNE T4,QBINVS ;IS IT INVISIBLE?
JRST QSKD3 ;YES, IGNORE IT ENTIRELY
TRNN T4,QBEXCL ;IS THIS AN EXCLUSIVE REQUEST?
TRNE T3,QBEXCL ;OR IS ORIGINAL REQUEST EXCLUSIVE?
JRST QSKD7 ;YES TO EITHER. MUST LOOK AT MASKS
LOAD. T2,.QBGRP,(T1) ;GET GROUP NUMBER
CAME T2,QSKDG ;SAME GROUP AS OWNER?
JRST QSKD13 ;NO, STOP HERE
JRST QSKD3 ;LOOP BACK UNTIL AT LOCK BLOCK
;QSKD CONTINUES ON NEXT PAGE...
QSKD4: MOVE T3,QSKDT
LOAD. T3,.QBNRP,(T3) ;GET # OF RESOURCES WANTED
LOAD. T4,.LBAVL,(T1) ;GET # OF RESOURCES AVAILABLE
SUB T4,T3 ;SUBTRACT REQUEST
JUMPL T4,QSKD13 ;NOT ENOUGH AVAILABLE
STOR. T4,.LBAVL,(T1) ;STORE BACK UPDATED TOTAL
MOVE T3,QSKDT ;GET BACK ADDR OF Q-BLOCK
LOAD. T2,.QBFLG,(T3) ;GET FLAGS FROM SAME
TRO T2,QBOWNR ;SET THE OWNER FLAG
STOR. T2,.QBFLG,(T3) ;STORE THE UPDATED FLAGS
LOAD. T2,.QBNQ,(T3) ;NOW MOVE THIS Q-BLOCK TO THE HEAD
LOAD. T4,.QBLQ,(T3) ; OF THE Q FOR THIS LOCK
STOR. T2,.QBNQ,(T4) ;FIRST, REMOVE IT FROM THE Q
STOR. T4,.QBLQ,(T2) ;...
LOAD. T2,.LBNQ,(T1) ;NOW ADD IT TO THE START OF THE Q
STOR. T3,.QBLQ,(T2) ; PTR BACK TO Q-BLOCK FROM Q-2
STOR. T3,.LBNQ,(T1) ; PTR TO Q-BLOCK FROM LOCK-BLOCK
STOR. T2,.QBNQ,(T3) ; PTR TO SECOND Q-BLOCK
STOR. T1,.LBLQ,(T3) ; PTR BACK TO LOCK-BLOCK
MOVE T2,DATE## ;GET DATE-TIME
STOR. T2,.LBTIM,(T1) ;PUT IN LOCK-BLOCK
MOVE T1,QSKDQ ;GET BACK ORIGINAL Q-BLOCK ADDR
SETOM QSKDF ;MARK THAT A LOCK WAS LOCKED
JRST QSKD0 ;AND SCAN AGAIN
QSKD5: MOVE T2,QSKDT ;GET Q-BLOCK ADR OF PRESENT Q-BLOCK
LOAD. T1,.QBNQR,(T2) ;GET NEXT Q-BLOCK IN THIS REQUEST
CAME T1,QSKDQ ;ARE WE BACK AT THE Q-BLOCK YET?
JRST QSKD2 ;NO, GO CHECK IF THIS Q LOCKED
QSKD6: MOVE T1,QSKDF ;GET FLAG
PJRST CPOPJ1## ;SKIP RETURN
QSKD7: LOAD. T3,.QBMSK,(T1) ;CHECK FOR MASKS
SKIPE T4,QSKDM ;IS THERE A MASK FOR THE QUEUE BLOCK
JUMPN T3,QSKD10 ;YES, DO BOTH HAVE A MASK
JUMPN T4,QSKD8 ;NO, ONLY ONE?
JUMPE T3,QSKD13 ;YES, CAN'T GET THE LOCK NOW
MOVE T4,T3 ;GET ADDRESS OF BLOCK TO USE
QSKD8: MOVE T3,QSKDN ;GET LENGTH OF MASK BLOCK
QSKD9: SKIPE (T4) ;ANY BIT ON IN MASK
JRST QSKD13 ;YES, QUIT
ADDI T4,1 ;ADVANCE TO NEXT WORD IN MASK
SOJG T3,QSKD9 ;LOOP OVER WHOLE MASK BLOCK
JRST QSKD3 ;ENTIRE MASK BLOCK IS ZERO
QSKD10: MOVE P1,QSKDN ;LENGTH OF MASK BLOCK
QSKD11: MOVE P2,0(T3) ;NEXT WORD IN MASK BLOCK
AND P2,0(T4) ;CLEAR NON-CONFLICTING BITS
JUMPN P2,QSKD13 ;RETURN IF ANY CONFLICTS
ADDI T3,1 ;STEP
ADDI T4,1 ; TO NEXT MASK WORD
SOJG P1,QSKD11 ;LOOP OVER WHOLE BLOCK
JRST QSKD3 ;THESE BLOCKS CAN CO-EXIST
QSKD13: MOVE T1,QSKDF ;GET FLAG
POPJ P, ;GIVE ERROR RETURN
;SUBROUTINE TO SET INVISIBLE BITS FOR A Q-BLOCK ENTRY
;
;CALL:
; MOVE T1,Q-BLOCK-ADDR
; PUSHJ P,SETINV
; HERE IF NOT FULLY LOCKED YET
; HERE IF REQUEST IS NOW FULLY LOCKED
;
;CLOBBERS: T1-T4
;
SETINV: MOVSI T2,1 ;INIT LEVEL NUMBER SCANNER
MOVEM T2,EQTMP2 ;SAVE LEVEL NUMBER FOR LATER
MOVEM T1,EQTMP1 ;SAVE Q-BLOCK ADDR TOO
SETIN1: LOAD. T2,.QBLB,(T1) ;GET ADDR OF LOCK BLOCK
LOAD. T4,.LBLVL,(T2) ;AND ITS LEVEL
LOAD. T3,.QBFLG,(T1) ; AND FLAGS FOR Q-BLOCK
TRNE T3,QBOWNR ;IS THIS THE OWNER OF THE LOCK?
JRST SETIN2 ;YES
CAMG T4,EQTMP2 ;NO, IS THIS A NEW LOW VALUE?
MOVEM T4,EQTMP2 ;YES, REMEMBER LOWEST NON-LOCKED VALUE
SETIN2: LOAD. T1,.QBNQR,(T1) ;GET NEXT Q-BLOCK IN THIS REQUEST
CAME T1,EQTMP1 ;ARE WE BACK AT STARTING POINT?
JRST SETIN1 ;NO, LOOP BACK FOR MORE Q-BLOCKS
MOVE T2,EQTMP2 ;GET LEVEL NUMBER
TLNE T2,-1 ;SEE IF AN UNLOCKED WAS SEEN
JRST CPOPJ1## ;NONE SEEN, LOCK IS FULLY LOCKED
SETIN3: LOAD. T2,.QBLB,(T1) ;GET LOCK ADDR
LOAD. T4,.LBLVL,(T2) ;AND ITS LEVEL
LOAD. T3,.QBFLG,(T1) ;GET Q-BLOCK'S FLAGS
CAMG T4,EQTMP2 ;IS LEVEL ABOVE LOWEST UNLOCKED LEVEL?
TRZA T3,QBINVS ;NO, MAKE THIS Q-BLOCK VISIBLE
TRO T3,QBINVS ;YES, MAKE IT INVISIBLE
STOR. T3,.QBFLG,(T1) ;STORE FLAGS BACK
LOAD. T1,.QBNQR,(T1) ;GET ADDR OF Q-BLOCK IN REQUEST
CAME T1,EQTMP1 ;HAVE WE SEEN ALL Q-BLOCKS?
JRST SETIN3 ;NO, LOOP BACK FOR MORE
POPJ P, ;NON-SKIP RETURN
SUBTTL LOCK SCHEDULING SUBROUTINE
;SUBROUTINE TO SCHEDULE ONE ENTIRE QUEUE FOR A GIVEN LOCK
;
;CALL:
; MOVE T1,LOCK-BLOCK-ADDR
; PUSHJ P,LOKSKD
; RETURN HERE ALWAYS
;
;ON RETURN, ALL PROCESSES HAVE BEEN INTERRUPTED, OR WOKEN UP
;WHICH HAD RESOURCES THAT HAD BECOME AVAILABLE OR ABORTED
;
LOKSKD: MOVEM T1,LKTMP1 ;SAVE ADDRESS OF LOCK
MOVEM T1,LKTMP2 ;INIT Q-BLOCK ADDRESS REGISTER
LOAD. T2,.LBAVL,(T1) ;GET NUMBER AVAILABLE
MOVEM T2,LKTMP3 ;SAVE IT
SETZM LKTMP4 ;FLAG THAT LOCK IS NOT ABORTED
PUSHJ P,CHKABT ;CHECK TO SEE IF LOCK IS ABORTED
SETOM LKTMP4 ;YES IT IS ABORTED
LOKSK1: LOAD. T1,.LBNQ,(T1) ;GET ADDR OF NEXT Q-BLOCK FOR LOCK
CAMN T1,LKTMP1 ;BACK TO THE LOCK-BLOCK YET?
POPJ P, ;YES, THRU
MOVEM T1,LKTMP2 ;SAVE THIS ADDRESS
LOAD. T2,.QBFLG,(T1) ;GET FLAGS FOR THIS ENTRY
TRNE T2,QBINVS ;IS IT INVISIBLE?
JRST LOKSK1 ;YES, IGNORE IT
SKIPE LKTMP4 ;WAS LOCK JUST ABORTED?
JRST LOKSK4 ;YES, GO WAKEUP OR SIGNAL
TRNE T2,QBOWNR ;IS HE THE OWNER?
JRST LOKSK0 ;YES
LOAD. T2,.QBNRP,(T1) ;GET NUMBER REQUESTED
MOVE T3,LKTMP3 ;GET NUMBER AVAILABLE
SUB T3,T2 ;GET DIFFERENCE
MOVEM T3,LKTMP3 ;UPDATE # AVAILABLE
JUMPL T3,CPOPJ## ;LEAVE IF SUPPLY EXHAUSTED
LOKSK0: PUSHJ P,QSKD ;SCHEDULE THIS Q-BLOCK
JRST LOKSK2 ;IT WASN'T LOCKED
JUMPE T1,LOKSK2 ;IF NOT JUST LOCKED, DON'T INTERRUPT
LOKSK4: MOVE T1,LKTMP2 ;GET ADDR OF THIS Q-BLOCK
IFN FTPI,<
LOAD. T2,.QBFLG,(T1) ;GET FLAGS
TRNN T2,QBPSI ;IS HE EXPECTING AN INTERRUPT?
JRST LOKSK3 ;NO, HE IS WAITING
PUSH P,J ;SAVE J
LOAD. J,.QBJCH,(T1) ;GET JOB/CONTEXT HANDLE OF USER
MOVE T2,LKTMP4 ;INDICATE NORMAL OR ABORTED REQUEST
PUSHJ P,GENPSI ;GENERATE AN INTERRUPT FOR HIM
POP P,J ;RESTORE J
JRST LOKSK2 ;AND CONTINUE
>;END FTPI
LOKSK3: LOAD. T1,.QBJCH,(T1) ;GET THIS GUY'S JOB NUMBER
PUSH P,W ;JUST IN CASE W GETS LOST
PUSHJ P,CTXWAK## ;WAKE HIM UP
STOPCD .+1,JOB,ENQCWJ ;++CAN'T WAKE JOB/CONTEXT
POP P,W ;GET IT BACK
LOKSK2: MOVE T1,LKTMP2 ;GET Q-BLOCK ADDR AGAIN
JRST LOKSK1 ;LOOP BACK FOR REST OF Q
SUBTTL DEADLK -- CHECK QUEUE STRUCTURE FOR DEADLOCK
;CALL:
; PUSHJ P,DEADLK
; <IF DEADLOCK>
; <IF NO DEADLOCK>
DEADLK: PUSHJ P,SAVE4## ;PRESERVE P1-P4
PUSHJ P,SAVJW## ;PRESERVE J AND W TOO
SETZM ENQTBC ;NULL LIST OF REQUESTS TO BE CHECKED
SETZM ENQHBC ;NULL LIST OF ALREADY CHECKED REQUESTS
MOVE P3,.CPJCH## ;GET REQUESTER'S JOB/CONTEXT HANDLE
DEADJQ: MOVE T1,P3 ;GET THE NEXT JOB/CONTEXT HANDLE
PUSHJ P,CTXENQ## ;GET START OF JOB/CONTEXT'S QUEUE CHAIN
STOPCD .+1,JOB,ENQIJC ;++ILLEGAL JOB/CONTEXT HANDLE
SKIPA P1,T2 ;SAVE IN P1
DEADR: LOAD. P1,.QBNJQ,(P1) ;GET THE NEXT QUEUE ENTRY
JUMPE P1,DEADJ ;NO QUEUE CHAIN, CHECK NEXT JOB
LOAD. T1,.QBFLG,(P1) ;GET QUEUE BLOCK FLAGS
TRNE T1,QBOWNR ;IS THIS A REQUEST?
JRST DEADR ;NO, TRY NEXT QUEUE ENTRY
LOAD. P2,.QBLB,(P1) ;GET THE LOCK-BLOCK FOR THIS QUEUE ENTRY
DEADQ: LOAD. P2,.QBNQ,(P2) ;GET THE NEXT QUEUE ENTRY
CAMN P1,P2 ;HAVE WE LOOPED BACK TO THE REQUEST?
JRST DEADR ;YES, CHECK JOB'S NEXT REQUEST
LOAD. T1,.QBJCH,(P2) ;GET OWNER OF THIS QUEUE ENTRY
CAMN T1,.CPJCH## ;ARE WE THE OWNER?
POPJ P, ;YES, DEADLOCK
SKIPN T2,ENQHBC ;HAS THIS JOB ALREADY BEEN CHECKED?
MOVEM P2,ENQHBC ;NULL LIST, MAKE NON-EMPTY
JUMPE T2,DEADQ2 ;AND GO STORE ON CHECK LIST
DEADQ1: MOVE T4,T2 ;SAVE ORIGINAL POINTER
LOAD. T3,.QBJCH,(T2) ;GET OWNER OF THIS QUEUE ENTRY
CAMN T3,T1 ;ALREADY ON CHECK LIST?
JRST DEADQ ;YES, GET ANOTHER QUEUE ENTRY
LOAD. T2,.QBCHK,(T2) ;GET NEXT ENTRY IN CHECK LIST
JUMPN T2,DEADQ1 ;ANY MORE ENTRIES IN CHECK LIST?
STOR. P2,.QBCHK,(T4) ;NO, PUT REQUEST ON TAIL OF CHECK LIST
DEADQ2: STOR. T2,.QBCHK,(P2) ;PUT NULL AT END OF CHECK LIST
SKIPN ENQTBC ;LIST EMPTY?
MOVEM P2,ENQTBC ;YES, MAKE NOT EMPTY
JRST DEADQ ;GET ANOTHER QUEUE ENTRY
DEADJ: SKIPN P4,ENQTBC ;GET NEXT REQUEST TO BE CHECKED
JRST CPOPJ1## ;NO JOBS FOUND, NO DEADLOCK!
LOAD. P3,.QBJCH,(P4) ;GET JOB/CONTEXT HANDLE OF REQUEST
LOAD. T1,.QBCHK,(P4) ;GET NEXT REQUEST TO BE CHECKED
MOVEM T1,ENQTBC ;SAVE FOR LATER
JRST DEADJQ ;GO CHECK OUT THIS JOB
SUBTTL SUBROUTINE TO GET A LOCK SPECIFICATION FROM USER SPACE
;SUBROUTINE TO GET ONE LOCK SPEC (2 TO 5 WORDS) FROM THE USER'S
; RESOURCE BLOCK
;
;ON ENTRY, THE WORD "LOCKCT" IS SET UP AS FOLLOWS:
; XWD TOTAL # OF LOCKS, # OF LOCK TO GET
;
;CALL:
; PUSHJ P,GETLOK
; NORMAL RETURN ALWAYS
;
;ON EXIT, P1-P3 WILL CONTAIN THE FIRST 3 WORDS OF THE LOCK
; SPECIFICATION AS GIVEN BY THE USER WITH THE FOLLOWING
; CHANGES:
; 1. IF LH OF P2 WAS -1, IT IS CHANGED TO "POINT 7,0"
; 2. THE RH OF P4 HAS THE ACCESS TABLE ADDRESS IN IT
; (OR -2/-3/400000+JOB #)
; IN ADDITION, THE WORD EQLTBL WILL CONTAIN A WORD OF THE
; FORM XWD LENGTH,ADDRESS FOR THE USERS LOCK-ASSOCIATED TABLE,
; AND THE WORD EQLMSK WILL CONTAIN A WORD OF THE FORM
; XWD LENGTH,ADDRESS FOR THE USERS PIE-SLICE LOCK MASK WORD.
GETLOK: HRR M,RBLOCK ;GET ADDRESS OF PARAMETERS
HRRZ T1,LOCKCT ;GET THE NUMBER OF THIS LOCK
IMUL T1,LOKSIZ ;MULTIPLY BY SIZE
ADD T1,HDRSIZ ;ADD IN HEADER SIZE
ADDI M,-1(T1) ;BUMP POINTER, ALLOW FOR PREINCREMENT
SETZM USRLOK ;CLEAR MONITOR COPY TO ZERO
MOVE T1,[USRLOK,,USRLOK+1]
BLT T1,USRLOK+LKMAX-1
MOVN P1,LOKSIZ ;LENGTH OF PER-LOCK BLOCK
MOVSI P1,(P1) ;MAKE INTO AN AOBJN POINTER
GETLK1: PUSHJ P,GETWD1## ;FETCH A WORD
MOVEM T1,USRLOK(P1) ;SAVE IT
AOBJN P1,GETLK1 ;LOOP OVER WHOLE BLOCK
MOVE P3,[USRLOK,,P1] ;SET TO COPY TO AC'S
BLT P3,P3 ;ZAP!
TLNE P1,EN%UCW ;CODE WORD?
JRST GETLK2 ;YES, CAN'T BE BYTE POINTER
HLRZ T1,P2 ;GET LEFT HALF OF PTR
CAIN T1,-1 ;IS IT -1?
HRLI P2,(POINT 7,0) ;YES, MAKE IT INTO A BYTE PTR
GETLK2: HRRE T1,P1 ;GET CHANNEL #/-1/-2/-3
CAMN T1,[-1] ;IS THIS A JOB WIDE LOCK?
HRRI T1,CODMIN(J) ;YES, MAKE 400000+JOB NUMBER
JUMPL T1,GETLK3 ;LEAVE NOW IF NOT A FILE LOCK
HRRZS P1 ;ISOLATE CHANNEL NUMBER
PUSHJ P,SETUF## ;POINT F AT THE DDB
TDZA T1,T1 ;CHANNEL ILLEGAL OR NOT YET OPEN
HRRZ T1,DEVACC##(F) ;GET ACCESS TABLE ADDRESS
CAIL T1,CODMIN ;DOES IT LOOK LIKE A SPECIAL CODE?
STOPCD .+1,DEBUG,ENQATA ;++BAD ACCESS TABLE ADDRESS
MOVE P1,USRLOK ;RESTORE P1
GETLK3: HRRM T1,P4 ;SAVE THIS IN RH OF P4 FOR USE LATER
POPJ P, ;RETURN
SUBTTL SUBROUTINES TO CHECK PRIVILEGES AND LOCK SPECS
;SUBROUTINE TO CHECK USER PRIVILEGES
;
;ON ENTRY, P1-P4 MUST BE SET UP BY GETLOK
;
;CALL:
; PUSHJ P,CHPRIV
; RETURN HERE IF PRIV. INSUFFICIENT
; USER IS OK
;
CHPRIV: HRRE T1,P1 ;GET CHANNEL #/-1/-2/-3
CAMN T1,[-2] ;IS IT A LOGICAL LOCK?
JRST [MOVSI T1,JP.ENQ ;YES, DOES HE HAVE ENQ PRIV?
PUSHJ P,PRVBIT## ;CHECK PRIVILEGES
JRST CPOPJ1## ;IT'S OK
JRST PRVERR] ;NO, HE'S AN IMPOSTER
CAMN T1,[-3] ;OR, IS IT A [1,2]/JACCT LOCK?
JRST [PUSHJ P,PRVJC## ;YES, IS HE PRIVILEGED?
JRST CPOPJ1## ;YES, ITS OK
JRST HDRER7] ; NO
PJRST CPOPJ1## ;SKIP RETURN
;SUBROUTINE TO CHECK ASCII STRING
;CALL:
; MOVE T1,USERS BYTE STRING
; PUSHJ P,CHKSTR
; BAD POINTER RETURN
; STRING OKAY RETURN
;USES T1-T2. NEVER RETURNS IF BAD ADDRESS IN THE STRING.
CHKSTR: LDB T2,[POINT 3,T1,2] ;FIRST 3 BITS
CAIN T2,5 ;IS IT A 5 (SPECIAL CODE FOR NUMBER)
JRST CPOPJ1## ;YES, GIVE GOOD RETURN NOW
TLNE T1,37 ;ANY INDEX OR INDIRECT BITS
JRST HDRERA ;YES, THE POINTER IS BAD
PUSHJ P,SAVE4## ;PRESERVE P1-P4
MOVEI P1,^D36 ;BITS PER WORD
LDB P2,[POINT 6,T1,11] ;BITS PER USER BYTE
JUMPE P2,HDRER1 ;IF ZERO
CAILE P2,^D36 ;OR MORE THAN A WORD
JRST HDRER1 ;BAD BYTE SIZE ERROR
IDIVI P1,(P2) ;COMPUTE BYTES PER WORD
IMUL P1,%ENQML## ;COMPUTE MAXIMUM ALLOWABLE NR. OF BYTES
MOVE P2,T1 ;SAVE BYTE POINTER
SETO P3, ;LAST PAGE CHECKED
CHKST1: IBP P2 ;POINT TO ADDRESS ACTUALLY REFERENCED
LDB P4,[POINT 9,P2,26] ;PAGE ADDRESS OF THE POINTER
CAME P4,P3 ;CHECKED LAST TIME?
PUSHJ P,ADRCHK ;CHECK ADDRESS
EXCTUX <LDB T2,P2> ;GET A BYTE
JUMPE T2,CPOPJ1## ;IF END OF STRING
SOJG P1,CHKST1 ;LOOP OVER MAXIMUM LENGTH
JRST HDRER2 ;ELSE RETURN ERROR
;ROUTINE TO CHECK AN ADDRESS, CALLED ONLY BY CKST1.
;CALL WITH BYTE POINTER IN P2, PAGE ADDRESS IN P4.
;RETURNS WITH LAST PAGE CHECKED IN P3. CLOBBERS T1.
ADRCHK: PUSH P,M ;SAVE M
HRRZ M,P2 ;ADDRESS TO BE CHECKED
PUSHJ P,GETWDU## ;LOOK AT THE WORD
MOVE P3,P4 ;UPDATE PAGE LAST CHECKED
PJRST MPOPJ## ;RESTORE M AND RETURN
;SUBROUTINE TO CHECK THE BYTE POINTER SIZE, POOL VALUES,
; AND CHANNEL #
;
;ON ENTRY, P1-P4 SET UP BY GETLOK
;
;CALL:
; PUSHJ P,LOCKOK
; ERROR RETURN
; NORMAL RETURN
;
LOCKOK: TLNE P1,EN%UCW ;CODE WORD?
JRST LKOK2 ;YES, CODE IS OK
LDB T2,[POINT 3,P2,2] ;GET STRING IDENTIFIER
CAIN T2,5 ;IS IT A USER CODE?
JRST LKOK2 ;YES, DON'T CHECK BYTE SIZE
LDB T2,[POINT 6,P2,11] ;GET BYTE SIZE
JUMPE T2,HDRER1 ;ZERO BYTE SIZE?
CAILE T2,^D36 ;TOO LARGE?
JRST HDRER1 ;YES, BAD BYTE SIZE ERROR
TLNE P2,37 ;INDEXED OR INDIRECT POINTER?
JRST HDRERA ;YES, ERROR
LKOK2: HRRE T1,P1 ;GET CHANNEL #
CAMGE T1,[-3] ;OR LESS THAN -3?
JRST HDRER6
JUMPL T1,LKOK3 ;NO DDB IF NEGATIVE
CAIGE T1,775 ;CAN'T USE CHANNELS 775,776,777
PUSHJ P,QSTUF ;LEGAL CHANNEL?
JRST HDRER6 ;YES TO EITHER IS AN ERROR
LKOK3: JUMPL P3,HDRER8 ;NEGATIVE POOL NUMBER IS ILLEGAL
HLRE T2,P3 ;GET POOL VALUES
JUMPE T2,CPOPJ1## ;DON'T CHECK IF NOT A POOLED RESOURCE
TRNE P3,-1 ;DOES HE WANT NONE OF THEM?
CAIGE T2,(P3) ;REQUEST MORE THAN IN POOL?
JRST HDRER8 ;YES, ERROR
PJRST CPOPJ1## ;SKIP RETURN
;
QSTUF: PUSHJ P,SAVE1## ;SAVE P1
HRRZ P1,P1 ;CLEAR LEFT HALF
PJRST SETUF## ;CHECK FOR LEGAL CHANNEL
;SUBROUTINE TO CHECK IF A USER HAS BEEN QUEUE'D FOR A LOCK
;
;CALL:
; MOVE T1,LOCK-BLOCK-ADDR
; MOVE T2,JOB-CONTEXT-HANDLE
; PUSHJ P,CHECKQ
; HERE IF HE IS Q'ED
; HERE IF USER NOT Q'D
;
;ON NON-SKIP RETURN, T1 WILL HAVE THE Q-BLOCK ADDRESS IN IT
;ON SKIP RETURN, T1 WILL STILL HAVE THE LOCK-BLOCK ADDRESS IN IT
;
;
CHECKQ: PUSHJ P,SAVE3## ;SAVE P1-P3
MOVE P1,T1 ;SAVE LOCK BLOCK ADDR
LOAD. P2,.LBNMS,(T1) ;LENGTH OF RESOURCE MASK
MOVE P3,T2 ;SAVE JOB/CONTEXT HANDLE
LOAD. T1,.LBNQ,(T1) ;GET ADDRESS OF NEXT Q-BLOCK
CHECK2: CAIN T1,(P1) ;ARE WE BACK AT START?
JRST CPOPJ1## ;YES, SKIP RETURN
LOAD. T2,.QBJCH,(T1) ;GET THIS Q-BLOCK'S JOB/CONTEXT HANDLE
CAME T2,P3 ;FOR THIS JOB/CONTEXT?
JRST CHECK3 ;NO, KEEP LOOKING
JUMPE P2,CPOPJ ;IF NO MASKS SPECIFIED
PUSH P,T1 ;SAVE ADDRESS OF THIS QUEUE ENTRY
LOAD. T1,.QBMSK,(T1) ;ADDRESS OF MASK
HRRZ T2,EQLMSK ;ADDRESS OF TARGET MASK
MOVEI T3,(P2) ;LENGTH OF MASK BLOCK
PUSHJ P,TSTMSK ;SEE IF IDENTICAL
CAIA ;NO
JRST TPOPJ## ;RETURN SKIP. HE'S QUEUED
POP P,T1 ;RESTORE Q-BLOCK ADDRESS
CHECK3: LOAD. T1,.QBNQ,(T1) ;TO NEXT Q-BLOCK
JRST CHECK2 ;KEEP GOING
;SUBROUTINE TO CHECK IF A LOCK HAS BEEN ABORTED
;
;CALL:
; MOVE T1,LOCK-BLOCK-ADDR
; PUSHJ P,CHKABT
; HERE IF LOCK IS ABORTED
; HERE IF LOCK IS NOT ABORTED
;
;ON RETURN, T1 WILL STILL HAVE THE LOCK-BLOCK ADDRESS IN IT
;
CHKABT: MOVE T3,T1 ;SAVE LOCK BLOCK ADDR
CHKAB2: LOAD. T3,.LBNQ,(T3) ;GET ADDRESS OF NEXT Q-BLOCK
CAIN T3,(T1) ;ARE WE BACK AT START?
JRST CPOPJ1## ;YES, SKIP RETURN
LOAD. T4,.QBFLG,(T3) ;GET THIS Q-BLOCK'S FLAGS
TRNE T4,QBOWNR ;IS THIS THE OWNER OF THE LOCK?
TRNN T4,QBLABT ;AND IS IT AN ABORTED LOCK?
JRST CHKAB2 ;NO, SO KEEP GOING
POPJ P, ;YES, RETURN
;TSTMSK -- ROUTINE TO COMPARE TWO MASK BLOCKS FOR EQUALITY
;CALL:
; MOVEI T1,ADDR-OF-MASK BLOCK
; MOVEI T2,ADDR-OF MASK BLOCK
; MOVEI T3,LENGTH
; PUSHJ P,TSTMSK
; <IF DIFFERENT>
; <IF EQUAL>
TSTMSK: JUMPE T1,TSTMS1 ;IF ZERO ADDRESS (ASSUMES -1,...,-1)
MOVE T4,(T1) ;FIRST WORD OF MASK 1
AOJA T1,TSTMS2 ;INCREMENT POINTER, JOIN PROCESSING
TSTMS1: SETO T4, ;ASSUME -1 FOR MISSING BLOCK
TSTMS2: JUMPN T2,TSTMS3 ;IF NON-ZERO ADDRESS FOR MASK 2
SETCA T4, ;MASK-2 = -1,...,-1. SEE IF MASK 1 = -1
JUMPN T4,CPOPJ ;NO, NOT SAME
SOJG T3,TSTMSK ;THIS WORD MATCHES, CHECK NEXT
JRST CPOPJ1 ;NO MORE. WHOLE MATCH
TSTMS3: EXCTUX <CAME T4,(T2)> ;CHECK THIS WORD
POPJ P, ;NO MATCH. RETURN FAILURE
AOS T2 ;MATCH. INCREMENT POINTER FOR BLOCK 2
SOJG T3,TSTMSK ;CHECK NEXT WORD
JRST CPOPJ1
;SUBROUTINE TO COUNT USERS SHARING A LOCK
;
;CALL:
; MOVE T1,LOCK-BLOCK-ADDR
; PUSHJ P,COUNTQ
; HERE WITH COUNT IN T2, LOCK-BLOCK-ADDR STILL IN T1
;
COUNTQ: MOVE T3,T1 ;SAVE LOCK BLOCK ADDR
SETZ T2, ;INITIALIZE COUNTER
COUNT2: LOAD. T3,.LBNQ,(T3) ;GET ADDR OF NEXT Q-BLOCK
CAIN T3,(T1) ;BACK AT START?
POPJ P, ;YES, RETURN
LOAD. T4,.QBFLG,(T3) ;GET Q-BLOCK FLAGS
TRNN T4,QBOWNR ;IS HE THE OWNER?
JRST COUNT2 ;NO, DON'T COUNT THIS ENTRY
AOJA T2,COUNT2 ;TRY NEXT BLOCK
SUBTTL BLDLOK -- SUBROUTINE TO BUILD A LOCK BLOCK
;SUBROUTINE TO CREATE A LOCK-BLOCK
;
;CALL:
; MOVE T1,HASH-INDEX
; MOVE T2,FLAGS
; P1-P4 SETUP BY GETLOK
; PUSHJ P,BLDLOK
; HERE IF ERROR
; NORMAL RETURN
;
;ON RETURN, T1 = ADDRESS OF LOCK-BLOCK
;
BLDLOK: MOVEM T1,EQTMP1 ;SAVE HASH INDEX
MOVEM T2,EQTMP2 ;SAME FOR FLAGS
MOVE T1,%ENQNQ## ;GET THE NUMBER OF LOCK BLOCKS
CAML T1,%ENQMQ## ;ARE WE ALREADY AT MAXIMUM?
JRST DOERR6 ;YES, DON'T EAT UP ALL OF FREE CORE
MOVEI T2,1 ;ASSUME LENGTH OF CODE/TEXT IS ONE
TLNE P1,EN%UCW ;CODE WORD?
JRST GOTLNG ;YES, LENGTH IS 1
LDB T3,[POINT 3,P2,2] ;GET THE STRING IDENTIFIER
CAIN T3,5 ;IS IT A USER CODE?
JRST GOTLNG ;YES, SO WE ALREADY HAVE THE LENGTH
MOVE T3,P2 ;GET THE STRING POINTER
MOVEI T2,0 ;INITIALIZE COUNTER
BUILD2: EXCTUX <ILDB T4,T3>
AOS T2 ;BUMP CHARACTER COUNT
JUMPN T4,BUILD2 ;LEAVE LOOP ONLY IF NULL
LDB T4,[POINT 6,P2,11] ;GET BYTE SIZE TO
MOVEI T3,^D36 ;BITS PER WORD
IDIV T3,T4 ;BYTES PER WORD
IDIV T2,T3 ;FIND # OF WORDS NEEDED
SKIPE T3 ;WAS THERE A REMAINDER?
AOS T2 ;YES, WE NEED ANOTHER WORD
GOTLNG: ADDI T2,LBSIZE ;ADD LENGTH OF LOCK BLOCK
MOVEM T2,EQTMP4 ;SAVE IT FOR NOW
PUSHJ P,GETZWD ;GET SOME FREE CORE FOR IT
JRST DOERR6 ;NONE AVAILABLE
MOVE T2,EQTMP1 ;GET HASH INDEX BACK
MOVEI T2,HSHTAB##(T2) ; AND ACTUAL ADDRESS OF ENTRY
STOR. T2,.LBLHS,(T1) ;STORE IT IN HASH CHAIN
HRRZ T3,(T2) ;GET FORWARD POINTER FOR HASH CHAIN
HRRM T1,0(T2)
STOR. T3,.LBNHS,(T1) ;NEXT HASH POINTER
STOR. T1,.LBLHS,(T3) ;MAKE NEXT ENTRY POINT TO US
STOR. T1,.LBNQ,(T1) ;MAKE THIS A NULL-QUEUE
STOR. T1,.LBLQ,(T1) ;...SAME
;CONTINUED ON THE NEXT PAGE...
;CONTINUED FROM THE PREVIOUS PAGE
LDB T2,[POINT 9,P1,17] ;GET LEVEL #
STOR. T2,.LBLVL,(T1) ;PUT IT INTO LOCK BLOCK
HLRZ T2,P3 ;GET # OF RESOURCES IN REQUEST
STOR. T2,.LBPUL,(T1) ;PUT IT IN BLOCK
STOR. T2,.LBAVL,(T1) ;WITH SAME AMOUNT AS "AVAILABLE"
STOR. P4,.LBACC,(T1) ;STORE ACCESS TABLE ADDRESS
MOVE T3,EQTMP4 ;GET LENGTH BACK AGAIN
STOR. T3,.LBLEN,(T1) ;LENGTH OF LOCK BLOCK
SETZ T2, ;CLEAR TIME STAMP
STOR. T2,.LBTIM,(T1) ;STORE IT
PUSHJ P,BLDTBL ;BUILD LOCK-ASSOCIATED TABLE, IF NEEDED
JRST DOERR6 ;INSUFFICIENT FREE CORE
MOVE T2,EQTMP2 ;GET FLAGS AGAIN
STOR. T2,.LBFLG,(T1) ;PUT THEM AWAY
TRNN T2,LBTEXT ;IS THERE TEXT?
JRST [STOR. P2,.LBTXT,(T1) ;NO, STORE USER CODE
JRST CPOPJ1##]
MOVE T2,[POINT 7,O.TEXT(T1)]
LDB T3,[POINT 6,P2,11]
DPB T3,[POINT 6,T2,11]
BLD1: EXCTUX <ILDB T3,P2> ;START MOVING TEXT INTO BLOCK
IDPB T3,T2 ;KEEP GOING
JUMPN T3,BLD1 ;LOOP UNTIL NULL BYTE
JRST CPOPJ1## ;GIVE SKIP RETURN
SUBTTL ROUTINES TO BUILD AND DELETE A LOCK-ASSOCIATED TABLE.
;BLDTBL -- ROUTINE TO BUILD A LOCK-ASSOCIATED TABLE
;CALL:
; MOVE T1,LOCK BLOCK ADDRESS
; PUSHJ P,BLDTBL
; NO CORE RETURN
; TABLE POINTER SETUP IN THE LOCK BLOCK
BLDTBL: HLRZ T2,EQLTBL ;LENGTH OF TABLE TO GET SPACE FOR
JUMPE T2,CPOPJ1## ;IF ZERO LENGTH, JUST RETURN
PUSHJ P,SAVE1## ;SAVE A REGISTER
MOVE P1,T1 ;COPY POINTER TO LOCK BLOCK
STOR. T2,.LBTLN,(P1) ;SAVE LENGTH OF THE TABLE TOO
PUSHJ P,GETZWD ;GET THE SPACE
POPJ P, ;NO SPACE
STOR. T1,.LBTBL,(P1) ;SAVE ADDRESS OF THE TABLE
MOVE T1,P1 ;RESTORE T1
JRST CPOPJ1## ;AND GIVE GOOD RETURN
;ROUTINE TO DELETE A TABLE (IF ANY) ASSOCIATED WITH A LOCK BLOCK.
;CALL WITH
; MOVE T1,LOCK BLOCK ADDRESS
; PUSHJ P,DLTTBL
; ALWAYS RETURNS HERE WITH TABLE DELETED
;USES T2-T4
DLTTBL: LOAD. T2,.LBTBL,(T1) ;ADDRESS OF THE TABLE
JUMPE T2,CPOPJ## ;DONE IF NONE
PUSH P,T1 ;SAVE ADDRESS OF LOCK BLOCK
LOAD. T1,.LBTLN,(T1) ;LENGTH OF LOCK-ASSOCIATED TABLE
PUSHJ P,GIVWDS## ;RETURN THE SPACE TO THE MONITOR
POP P,T1 ;RESTORE LOCK BLOCK ADDRESS
SETZ T2, ;ZERO
STOR. T2,.LBTBL,(T1) ;CLEAR TABLE ADDRESS
STOR. T2,.LBTLN,(T1) ;AND THE LENGTH
POPJ P, ;RETURN
SUBTTL ROUTINES TO MANAGE THE USER TABLE
;ROUTINE TO COPY INFORMATION FROM THE USER TO THE LOCK-TABLE
STOTBL: SKIPN EQLTBL ;ANY DATA GIVEN
POPJ P, ;NO, JUST RETURN
LOAD. T2,.QBFLG,(T1) ;GET FLAGS
TRNE T2,QBOWNR ;IS THE QUEUE ENTRY THE OWNER
TRNN T2,QBEXCL ;AND EXCLUSIVELY SO?
POPJ P, ;EITHER NOT OWNER OR NOT EXCLUSIVE
PUSH P,T1 ;SAVE ADDRESS OF Q-BLOCK
LOAD. T1,.QBLB,(T1) ;ADDRESS OF LOCK BLOCK
LOAD. T2,.LBTBL,(T1) ;ADDRESS OF LOCK-ASSOCIATED TABLE
JUMPE T2,TPOPJ##
HRL T2,EQLTBL ;ADDRESS OF USERS DATA
LOAD. T3,.LBTLN,(T1) ;LENGTH OF MONITORS TABLE
HLRZ T4,EQLTBL ;LENGTH OF USERS DATA
CAML T4,T3 ;USERS SHORTER?
JRST STOTB1 ;NO, COPY AS MUCH AS MONITOR CAN HOLD
PUSHJ P,CLRTBL ;CLEAR MONITORS TABLE (SO ZERO FILL)
HLRZ T3,EQLTBL ;AND USE USERS LENGTH (WHICH IS SHORTER)
STOTB1: ADDI T3,-1(T2) ;LAST WORD ADDRESS
EXCTUX <BLT T2,(T3)> ;COPY USERS DATA
JRST TPOPJ## ;RESTORE T1 AND RETURN
;ROUTINE TO CLEAR THE CONTENTS OF THE TABLE IN MONITOR FREE SPACE
;TO ZEROS
;CALL WITH T1 POINTING TO LOCK BLOCK.
CLRTBL: PUSHJ P,SAVE2## ;PRESERVE P1-P2
LOAD. P1,.LBTBL,(T1) ;LOAD ADDRESS OF TABLE
JUMPE P1,CPOPJ## ;IF ZERO, TABLE IS ALREADY ZEROS
HRL P1,P1 ;COPY ADDRESS TO LEFT HALF
SETZM (P1) ;CLEAR FIRST WORD
LOAD. P2,.LBTLN,(T1) ;LENGTH OF THE TABLE
ADDI P2,-1(P1) ;COMPUTE LAST WORD OF TABLE
ADDI P1,1 ;MAKE PROPAGATING BLT POINTER
CAIL P2,(P1) ;LENGTH GREATER THAN ONE?
BLT P1,(P2) ;YES, CLEAR REST OF TABLE
POPJ P, ;AND RETURN
SUBTTL ROUTINES TO BUILD AND DELETE THE MASK BLOCK
BLDMSK: SKIPN EQLMSK ;DOES HE NEED THIS?
JRST CPOPJ1## ;NO, GIVE GOOD RETURN
PUSHJ P,SAVE1## ;SAVE P1
MOVE P1,T1 ;ADDRESS OF QUEUE BLOCK
HLRZ T2,EQLMSK ;LENGTH OF USERS MASK
LOAD. T3,.QBLB,(P1) ;ADDRESS OF LOCK BLOCK
LOAD. T4,.LBNMS,(T3) ;LENGTH OF EXISTING MASKS
JUMPN T4,BLDMS1 ;ALREADY HAVE SOME, CHECK FOR MATCH
STOR. T2,.LBNMS,(T3) ;STORE LENGTH IN LOCK BLOCK
JRST BLDMS2 ;JOIN PROCESSING
BLDMS1: CAME T4,T2 ;ARE THEY BOTH THE SAME?
JRST MWLERR ;NO, THIS IS AN ERROR
BLDMS2: PUSHJ P,GETZWD ;GET THE SPACE
JRST DOERR6 ;NO MORE FREE CORE
STOR. T1,.QBMSK,(P1) ;IN THE QUEUE BLOCK
ADDI T2,-1(T1) ;COMPUTE LAST WORD TO BE COPIED
HRL T1,EQLMSK ;SOURCE ADDRESS FOR COPY
EXCTUX <BLT T1,(T2)> ;COPY THE MASK
MOVE T1,P1 ;RESTORE T1
JRST CPOPJ1## ;AND RETURN
;DLTMSK -- ROUTINE TO RETURN A MULTI-RESOURCE LOCK MASK BLOCK
;CALL:
; MOVEI T2,Q-BLOCK ADDRESS
; PUSHJ P,DLTMSK
; <ALWAYS RETURNS HERE WITH MASK BLOCK DELETED>
;PRESERVES ALL AC'S
DLTMSK: PUSHJ P,SAVT## ;PRESERVE T1-T4
LOAD. T3,.QBLB,(T2) ;LOCATION OF THE LOCK BLOCK
LOAD. T2,.QBMSK,(T2) ;GET ADDRESS
JUMPE T2,CPOPJ## ;IF NONE
LOAD. T1,.LBNMS,(T3) ;THEN LENGTH OF MASK BLOCK
PJRST GIVWDS## ;RETURN SPACE TO MONITOR
SUBTTL QHIM -- SUBROUTINE TO BUILD A Q-BLOCK
;SUBROUTINE TO CREATE A QUEUE-BLOCK AND LINK IT
; INTO THE CHAIN OF QUEUED REQUESTS
;
;CALL:
; MOVE T1,LOCK-BLOCK-ADDR
; MOVE T2,ADDR-OF-Q-BLOCK-IN-MULTIPLE-REQUEST
; MOVE T3,FLAGS
; PUSHJ P,QHIM
; ERROR RETURN
; NORMAL RETURN
;
;ON RETURN, T1 = ADDRESS OF NEW Q-BLOCK ENTRY
;
QHIM: MOVEM T1,EQTMP1 ;SAVE LOCK-BLOCK ADDRESS
MOVEM T2,EQTMP2 ;SAME FOR MULTIPLE REQUEST ADDR
MOVEM T3,EQTMP3 ; AND FOR FLAGS
MOVEI T2,QBSIZE ;GET LENGTH OF Q-BLOCK
PUSHJ P,GETZWD ;GET SOME FREE SPACE FOR IT
POPJ P, ; NO MORE LEFT!
HRRZI T2,.PDEQJ##(W) ;ADDRESS OF JOB-Q BEGINNING
STOR. T2,.QBLJQ,(T1) ;LINK INTO JOB CHAIN
HRRZ T3,(T2) ;GET FORWARD POINTER
HRRM T1,(T2) ;MAKE JOB Q POINT TO US
STOR. T3,.QBNJQ,(T1) ;MAKE US POINT TO START
SKIPE T3 ;CHECK FOR END OF CHAIN
STOR. T1,.QBLJQ,(T3) ;ELSE, RELINK BACKWARD POINTERS
MOVE T2,EQTMP1 ;GET LOCK BLOCK ADDR
STOR. T2,.QBNQ,(T1) ;PUT US INTO REGULAR CHAIN OF Q-BLOCKS
LOAD. T3,.LBLQ,(T2) ;GET POINTER TO LAST Q ENTRY
STOR. T3,.QBLQ,(T1) ;PUT US AFTER IT
STOR. T1,.QBNQ,(T3) ;MAKE LOCK BLOCK POINT TO US
STOR. T1,.LBLQ,(T2) ;WE ARE THE LAST ENTRY IN QUEUE
STOR. T2,.QBLB,(T1) ;MAKE POINTER TO LOCK BLOCK
MOVE T4,REQID ;GET THE REQUEST ID
STOR. T4,.QBRID,(T1) ;STORE ID IN Q-BLOCK
MOVE T3,EQTMP3 ;FETCH FLAGS
TLNE P3,-1 ;IS THIS A POOLED RESOURCE?
TRZ T3,QBEXCL ;YES, CLEAR THE EXCLUSIVE BIT
STOR. T3,.QBFLG,(T1) ;PUT THEM AWAY
STOR. P1,.QBCHN,(T1) ;PUT IN Q-BLOCK
SKIPN T2,EQTMP2 ;IS THIS A MULTIPLE REQUEST?
JRST [STOR. T1,.QBNQR,(T1) ;YES, SET UP LINKS FOR CHAIN
STOR. T1,.QBLQR,(T1) ;MAKE US POINT TO OURSELVES
JRST QHIM2] ;AND FILL IN REST OF BLOCK
LOAD. T3,.QBNQR,(T2) ;GET ADDR OF NEXT ENTRY IN CHAIN
STOR. T1,.QBNQR,(T2) ;MAKE HIM POINT TO US
STOR. T1,.QBLQR,(T3) ;...
STOR. T3,.QBNQR,(T1) ;MAKE US POINT TO HIM
STOR. T2,.QBLQR,(T1) ;...
QHIM2: MOVE T2,.CPJCH## ;GET OUR JOB/CONTEXT HANDLE
STOR. T2,.QBJCH,(T1) ;STORE JOB/CONTEXT HANDLE
;CONTINUED ON THE NEXT PAGE
;CONTINUED FROM THE PREVIOUS PAGE
SETZ T2, ;SET UP TO CLEAR SOME STRUCTURES
TLNN P3,-1 ;POOLED?
EXCH T2,P3 ;NO
STOR. P3,.QBNRP,(T1) ;YES, STORE REQUESTED NUMBER
STOR. T2,.QBGRP,(T1) ;SET GROUP NUMBER
JRST CPOPJ1## ; AND EXIT
SUBTTL GENPSI AND CHKCNT
;SUBROUTINE TO GENERATE AN INTERRUPT FOR A USER
;
;CALL:
; MOVE T1,Q-BLOCK ADDRESS
; MOVE T2,FLAG ;0 FOR NORMAL, -1 FOR ABORTED REQUEST
; PUSHJ P,GENPSI
; RETURN HERE ALWAYS
;
;
IFN FTPI,<
GENPSI:
MOVE T3,T2 ;SAVE THE FLAG
LOAD. T2,.QBRID,(T1) ;GET REQUEST ID FROM Q-BLOCK
SKIPE T3 ;WAS THIS AN ABORTED REQUEST?
TLO T2,(1B0) ;YES, LIGHT BIT IN STATUS WORD
SIGNAL C$QUE ;SIGNAL INTERRUPT
JFCL
POPJ P, ;RETURN
>;END IFN FTPI
;SUBROUTINE TO UPDATE THE CURRENT LOCK COUNTER AND
; DETERMINE IF THERE ARE MORE LOCKS TO BE PROCESSED
;
;CALL:
; PUSHJ P,CHKCNT
; HERE IF THERE ARE MORE LOCKS
; HERE IF ALL THRU
;
;ON ENTRY, THE WORD "LOCKCT" MUST BE SET UP AS FOLLOWS:
; XWD # OF LOCKS,,# OF THE CURRENT LOCK
;
CHKCNT: AOS T3,LOCKCT ;BUMP COUNTER
TLZ T3,-1 ;CLEAR # LOCKS
HLRZ T2,LOCKCT ;GET NUMBER OF TOTAL LOCKS
CAILE T2,(T3) ;MORE TO GO?
POPJ P, ;YES
JRST CPOPJ1## ;NO, GIVE SKIP RETURN
SUBTTL ENQMIN -- ONCE A MINUTE CODE FOR QUESER
ENQMIN::PUSHJ P,SAVE4## ;PRESERVE P1-P4
MOVEI P1,HSHLEN##-1 ;START AT TOP OF HASH HEADER TABLE
ENQMN1: MOVEI P2,HSHTAB##(P1) ;START POINTER
ENQMN2: LOAD. P2,.LBNHS,(P2) ;POINT TO NEXT LOCK BLOCK ON CHAIN
CAIN P2,HSHTAB##(P1) ;REACHED END?
JRST ENQMN4 ;YES, CHECK NEXT CHAIN
LOAD. T2,.LBFLG,(P2) ;GET FLAGS
TRNN T2,LBLLTL ;IS THIS A LONG-TERM-LOCK?
JRST ENQMN2 ;NO, GET NEXT LOCK BLOCK
LOAD. T3,.LBNQ,(P2) ;YES, LOAD THE Q-BLOCK CHAIN POINTER
CAIE T3,(P2) ;IS THIS CHAIN EMPTY?
JRST ENQMN2 ;NO, CHECK NEXT BLOCK
LOAD. T3,.LBPLT,(P2) ;FETCH TIMER VALUE
SOJL T3,ENQMN3 ;COUNT DOWN, JUMP IF EXPIRED
STOR. T3,.LBPLT,(P2) ;RESTORE COUNT
JRST ENQMN2 ;CHECK NEXT BLOCK
ENQMN3: MOVEI T1,(P2) ;ADDRESS OF THIS LOCK BLOCK
LOAD. P2,.LBLHS,(P2) ;BACKUP POINTER NOW, SINCE DELETING
PUSHJ P,DLTLOK ;DELETE THE LOCK BLOCK
JRST ENQMN2 ;SEARCH REST OF CHAIN
;HERE TO ADVANCE TO THE NEXT HASH CHAIN
ENQMN4: SOJGE P1,ENQMN1 ;DECREMENT POINTER, LOOP OVER ALL
POPJ P, ;RETURN AFTER CHECKING ALL LOCK BLOCKS
SUBTTL ENQSDT -- SET DAYTIME CODE FOR QUESER
;SUBROUTINE TO FIX UP DATE-TIME STAMPS IN ALL LOCK BLOCKS
;
;CALL:
; MOVE T1,DATE-TIME-OFFSET
; PUSHJ P,ENQSDT
; RETURN HERE ALWAYS
;
;PRESERVES ALL
ENQSDT::PUSHJ P,SAVE4## ;PRESERVE P1-P4
MOVEI P1,HSHLEN##-1 ;START AT TOP OF HASH HEADER TABLE
ENQSD1: MOVEI P2,HSHTAB##(P1) ;START POINTER
ENQSD2: LOAD. P2,.LBNHS,(P2) ;POINT TO NEXT LOCK BLOCK ON CHAIN
CAIN P2,HSHTAB##(P1) ;REACHED END?
JRST ENQSD3 ;YES, CHECK NEXT CHAIN
LOAD. P3,.LBTIM,(P2) ;GET TIME-STAMP OF LOCK
JUMPE P3,ENQSD2 ;IF 0, NO TIME-STAMP WAS SET
ADD P3,T1 ;FUDGE UP TIME-STAMP
STOR. P3,.LBTIM,(P2) ;STORE CORRECTED VALUE
JRST ENQSD2 ;CHECK NEXT BLOCK
;HERE TO ADVANCE TO THE NEXT HASH CHAIN
ENQSD3: SOJGE P1,ENQSD1 ;DECREMENT POINTER, LOOP OVER ALL
POPJ P, ;RETURN AFTER CHECKING ALL LOCK BLOCKS
SUBTTL MHASH -- SUBROUTINE TO HASH TWO NUMBERS TOGETHER
;SUBROUTINE TO HASH TWO NUMBERS TOGETHER
;
;CALL:
; MOVE T1,NUMBER
; MOVE T2,NUMBER
; PUSHJ P,MHASH
; RETURN HERE ALWAYS WITH HASH IN T1
;
MHASH: XOR T1,RANDOM ;GUARD AGAINST 0 IN T1
XOR T2,RANDOM ;SAME
MUL T2,RANDOM ;SCRAMBLE THINGS UP A LITTLE
MUL T1,T2 ;MAKE IT REALLY RANDOM
POPJ P,
RANDOM: EXP 5*5*5*5*5*5*5*5*5*5*5*5*5*5*5 ;THIS IS 5^15
SUBTTL HASH -- SUBROUTINE TO HASH A STRING
;SUBROUTINE TO HASH A STRING
;
;CALL:
; MOVE T2,STRING-POINTER
; PUSHJ P,STHASH
; RETURN HERE WITH HASH IN T1
;
STHASH: PUSHJ P,SAVE1## ;PRESERVE P1
MOVEM T2,EQTMP1 ;SAVE POINTER
SETZM EQTMP2 ;CLEAR ANSWER REGISTER
LDB T4,[POINT 6,T2,11] ;GET BYTE SIZE
MOVEI T3,44 ;COMPUTE BYTES/WORD
IDIV T3,T4 ;BYTE/WORD IN T3
MOVE P1,T3 ; INTO P1
STHSH1: MOVE T4,P1 ;GET BYTES/WORD FOR COUNT
MOVE T3,[POINT 7,T2]
LDB T2,[POINT 6,EQTMP1,11]
DPB T2,[POINT 6,T3,11]
SETZ T2, ;CLEAR RECEIVER AC
STHSH2: EXCTUX <ILDB T1,EQTMP1>;GET A BYTE FROM USER'S STRING
JUMPE T1,STHSH3 ;END OF STRING?
IDPB T1,T3 ;NO, STORE CHARACTER IN T2
SOJG T4,STHSH2 ;LOOP BACK FOR CHARACTERS
XOR T2,EQTMP2 ;XOR THIS INTO ANSWER WORD
ROT T2,1 ;ROTATE TO MUSH BITS A LITTLE MORE
MOVEM T2,EQTMP2 ;AND RE-STORE THE WORD
JRST STHSH1 ;LOOP BACK UNTIL END OF STRING
STHSH3: XORM T2,EQTMP2 ;STORE PARTIAL WORD TOO
MOVE T1,EQTMP2 ;GET ANSWER
POPJ P, ;RETURN
SUBTTL HASH -- SUBROUTINE TO HASH A LOCK NAME
;SUBROUTINE TO CALCULATE AN INDEX INTO THE HASH TABLE
;
;CALL:
; MOVE P1,FLAGS,,ACCESS-TABLE-ADDR/-2/-3/400000+JOB #
; MOVE P2,USER CODE OR STRING POINTER
; PUSHJ P,HASH
; NORMAL RETURN
;
HASH: HRRE T1,P4 ;GET ACCESS-TABLE-ADDR/-2/-3/400000+JOB #
MOVE T2,P2 ; AND STRING POINTER
TLNE P1,EN%UCW ;CODE WORD?
JRST HASH2 ;YES, DON'T HASH IT
LDB T3,[POINT 3,T2,2] ;GET THE IDENTIFIER
CAIN T3,5 ;IS IT A USER CODE?
JRST HASH2 ;YES, DON'T HASH IT
PUSH P,T1 ;SAVE CHANNEL #
PUSHJ P,STHASH ;HASH THE STRING
POP P,T2 ;GET IT BACK AGAIN
HASH2: PUSHJ P,MHASH ;HASH THE ACCESS TABLE AND CODE/STRING
MOVMS T1 ;MAKE IT POSITIVE
IDIVI T1,HSHLEN## ;DIVIDE BY SIZE OF HASH TABLE
MOVE T1,T2 ;USE THE REMAINDER
POPJ P, ;RETURN
SUBTTL FNDLOK -- SUBROUTINE TO FIND A LOCK BLOCK
;SUBROUTINE TO FIND A LOCK-BLOCK
;
;CALL:
; SET UP P1-P4 BY GETLOK
; PUSHJ P,FNDLOK
;
; RETURN HERE IF NOT FOUND
; HERE IF FOUND, ADDRESS OF LOCK-BLOCK IN T1
;
;
FNDLOK: PUSHJ P,HASH ;HASH LOCK NAME
MOVEM T1,EQTMP4 ;SAVE IT FOR LATER
MOVEI T1,HSHTAB##(T1) ;GET ADDRESS OF ENTRY
MOVEM T1,EQTMP5 ;SAVE T1
FNDLK1: LOAD. T1,.LBNHS,(T1) ;ADVANCE TO NEXT LOCK-BLOCK
CAMN T1,EQTMP5 ;HAVE WE EXHAUSTED LIST?
POPJ P, ;YES, BLOCK WAS NOT FOUND
MOVEM T1,EQTMP1 ;REMEMBER THIS ADDRESS
LOAD. T2,.LBACC,(T1) ;GET ACCESS TABLE ADDRESS
CAIE T2,(P4) ;IS THIS A MATCH?
JRST FNDLK2 ;NO, TRY NEXT ENTRY
PUSHJ P,STRCMP ;COMPARE THE STRINGS
JRST FNDLK2 ;NO MATCH
MOVE T1,EQTMP1 ;GET BACK LOCK-BLOCK ADDRESS
PJRST CPOPJ1## ;SKIP RETURN
FNDLK2: MOVE T1,EQTMP1 ;GET LOCK-BLOCK ADDRESS
JRST FNDLK1 ;GO ON
SUBTTL STRCMP -- SUBROUTINE TO COMPARE TWO STRINGS
;SUBROUTINE TO COMPARE STRINGS OR USER CODES
;
;CALL:
; MOVE T1,LOCK-BLOCK-ADDRESS
; P1-P4 SET UP BY GETLOK
; PUSHJ P,STRCMP
; HERE IF NO MATCH
; RETURN HERE IF MATCH
;
;
STRCMP: TLNE P1,EN%UCW ;CODE WORD?
JRST STRCMC ;YES
LDB T3,[POINT 3,P2,2]
CAIN T3,5 ;IS THIS A USER CODE?
JRST STRCMC ;YES
LOAD. T3,.LBFLG,(T1) ;GET THE FLAGS
TRNN T3,LBTEXT ;TEXT?
POPJ P, ;NO
PUSHJ P,SAVE1## ;SAVE P1
MOVE P1,[POINT 7,O.TEXT(T1)] ;SET UP PTR TO TEXT
LDB T3,[POINT 6,P2,11] ;BYTE SIZE
DPB T3,[POINT 6,P1,11]
MOVE T2,P2 ;COPY STRING POINTER
STRCM0: EXCTUX <ILDB T3,T2> ;GET A BYTE FROM USER
ILDB T4,P1 ;AND ONE FROM LOCK BLOCK
CAME T3,T4 ;A MATCH?
POPJ P, ;NO, RETURN
JUMPN T3,STRCM0 ;YES, KEEP GOING IF NOT NULL
PJRST CPOPJ1## ;SKIP RETURN
STRCMC: LOAD. T3,.LBFLG,(T1) ;GET THE FLAGS FOR THE LOCK BLOCK
TRNE T3,LBTEXT ;IS THIS USER CODE?
POPJ P, ;NO
LOAD. T3,.LBTXT,(T1) ;GET USER CODE
CAME T3,P2 ;MATCH?
POPJ P, ;NO
PJRST CPOPJ1## ;YES, SKIP RETURN
SUBTTL GETLVL -- SUBROUTINE TO FIND THE HIGHEST LEVEL # FOR A GIVEN USER
;SUBROUTINE TO FIND THE HIGHEST LEVEL # FOR A GIVEN USER
;
;CALL:
; MOVE W,PDB-ADDRESS
; PUSHJ P,GETLVL
; RETURN HERE ALWAYS
;
;
;ON RETURN, T1 = HIGHEST MONITOR LEVEL,,HIGHEST USER LEVEL
; REQCNT = # OF OUTSTANDING REQUESTS FOR THIS USER
;
;
GETLVL:
IFN FTMP,<
PUSHJ P,EQLOCK
>
SETO T1, ;ASSUME THE QUEUE IS EMPTY
SETZM REQCNT ;CLEAR REQUEST COUNT
HRRZ T2,.PDEQJ##(W) ;GET START OF JOB Q
GTLVL2: JUMPE T2,CPOPJ## ;EXIT IF NO Q
LOAD. T3,.QBLB,(T2) ;GET LOCK BLOCK
LOAD. T4,.LBLVL,(T3) ; AND ITS LEVEL #
AOS REQCNT ;BUMP COUNT OF REQUESTS
LOAD. P2,.LBACC,(T3) ;YES, GET FILE ID/-2/-3/400000+JOB #
CAIE P2,-3 ;IS THIS A PRIVILEGED LOCK?
JRST GTLVL3 ;NO, CHECK IT AGAINST HIGH USER LEVEL
HLRE T3,T1 ;GET HIGHEST MONITOR LEVEL #
CAMLE T4,T3 ;A NEW HIGH?
HRL T1,T4 ;YES, UPDATE MONITOR LEVEL #
JRST GTLVL4 ; AND KEEP GOING
GTLVL3: HRRE T3,T1 ;GET HIGHEST USER'S LEVEL
CAMLE T4,T3 ;A NEW HIGH?
HRR T1,T4 ;YES
GTLVL4: LOAD. T2,.QBNJQ,(T2) ;RETURN ADDRESS OF Q-BLOCK
JRST GTLVL2 ;NO, MORE TO GO
SUBTTL -- MISCELLANEOUS SUBROUTINES
;SUBROUTINE TO PERFORM COMMON SETUP FUNCTIONS
;
;CALL:
; MOVE T2,MAX-FUNCTION-CODE
;
; PUSHJ P,SETUP
; ERROR RETURN (ERROR CODE IN T1)
; NORMAL RETURN (FUNCTION CODE IN T3)
;
;P4 IS RETURNED CLEAR
; AND THE FUNCTION CODE IS STORED IN THE RIGHT HALF OF "FCODE"
;
SETUP: SETZB P4,NQERRF ;INITIALIZE FLAGS
HRR M,T1 ;GET PARAMETER BLOCK ADDR
HRRZM M,RBLOCK ;SAVE THIS ADDRESS FOR LATER
HLRZ T3,T1 ;GET FUNCTION FROM CALL
MOVEM T3,FCODE ; AND SAVE IT FOR USE LATER
CAILE T3,(T2) ;IS IT WITHIN RANGE?
JRST NDUERR ;NO, ERROR RETURN
TLO M,400000 ;SO ERRORS RETURN INSTEAD OF EXIT
JRST CPOPJ1## ; TO STOTAC. THEN GIVE GOOD RETURN
;ROUTINE TO ALLOCATE FREE CORE
;
;CALL:
; MOVEI T2,NUMBER OF WORDS
; PUSHJ P,GETZWD
; ERROR RETURN
; NORMAL RETURN
;USES T1,T3,T4
GETZWD: PUSH P,T2 ;
PUSHJ P,GETWDS## ;GET BLOCK
PJRST T2POPJ##
MOVE T2,(P) ;LENGTH
ADDI T2,-1(T1) ;LAST WORD
SETZM (T1) ;CLEAR FIRST
MOVEI T3,1(T1) ;DESTINATION
HRL T3,T1 ;SOURCE
BLT T3,(T2) ;CLEAR BLOCK
JRST T2POJ1## ;
;SUBROUTINE TO GET THE EQ RESOURCE TO INTERLOCK SMP SYSTEMS
;
;CALL:
; PUSHJ P,EQLOCK
; <RETURN HERE WITH INTERLOCK>
;
;AUTOMATICALLY FREES LOCK WHEN CALLER OF EQLOCK RETURNS
IFN FTMP,<
EQLOCK: PUSH P,NQERRF
PUSH P,LOKSIZ
PUSH P,HDRSIZ
PUSH P,RBLOCK
PUSH P,FCODE
PUSH P,LOCKCT
PUSH P,REQID
PUSH P,TIMLIM
PUSH P,HILEVL
PUSH P,SBLOCK
PUSHJ P,UPEQ ;WAIT FOR RESOURCE
POP P,SBLOCK
POP P,HILEVL
POP P,TIMLIM
POP P,REQID
POP P,LOCKCT
POP P,FCODE
POP P,RBLOCK
POP P,HDRSIZ
POP P,LOKSIZ
POP P,NQERRF
PUSHJ P,@0(P) ;RETURN TO CALLER OF EQLOCK
CAIA ;IF NON-SKIP RETURN
AOS -1(P) ;ADVANCE RETURN
POP P,(P) ;CLEAR EQLOCK CALLER'S ADDRESS
PJRST DWNEQ ;FREE RESOURCE AND RETURN
;SUBROUTINE TO CHECK TO SEE IF THE CURRENT JOB OWNS THE EQ
;RESOURCE
;CALL:
; PUSHJ P,HAVEQ
; <NO>
; <YES>
;PRESERVES ALL
HAVEQ:: PUSH P,T1
HRRZ T1,EQUSER##
CAIE T1,(J)
JRST TPOPJ##
JRST TPOPJ1##
UPEQ: PUSH P,F ;SAVE F
SETZ F, ;DON'T TOUCH EVM
PUSHJ P,EQWAIT## ;GET THE EQ
JRST FPOPJ## ;AND RESTORE F
DWNEQ: PUSH P,F ;SAVE F
SETZ F, ;DON'T TOUCH EVM
PUSHJ P,EQFREE## ;GIVE UP THE EQ
JRST FPOPJ## ;AND RESTORE F
>
;SUBROUTINE TO PERFORM CLEAN-UP ON A RESET (OR LOGOUT, OR POP)
;
;CALL: HRRZ T1,NEWJCH
; XMOVEI T2,NEWJQ
; PUSHJ P,ENQRST -OR- PUSHJ P,ENQLGO -OR- PUSHJ P,ENQPOP
; RETURN HERE ALWAYS
;
ENQRST::TDZA T4,T4 ;INDICATE RESET (DEQ ALL BUT NDR)
ENQLGO::MOVEI T4,1 ;INDICATE LOGOUT (DEQ ALL)
CAIA
ENQPOP::MOVEI T4,2 ;INDICATE POP (RENAME TO NEW JCH)
PUSHJ P,FNDPDS## ;FIND HIS PDB
SKIPN .PDEQJ##(W) ;DOES HE HAVE A QUEUE
POPJ P, ;IF NULL QUEUE
PUSHJ P,SAVE3## ;SAVE SOME ACS
MOVE P1,T4 ;SAVE THE ENTRY CODE
MOVE P2,T1 ;SAVE NEW JCH (FOR POPIT)
MOVE P3,T2 ;SAVE NEW JOB QUEUE ADDRESS (FOR POPIT)
IFN FTMP,<
PUSHJ P,EQLOCK ;INTERLOCK THE ENQ/DEQ DATABASE
>
MOVE T2,.PDEQJ##(W) ;GET START OF JOB QUEUE
RESET2: MOVE T1,T2 ;FETCH ADDRESS OF CURRENT BLOCK
JUMPE T1,CPOPJ## ;EXIT IF NO JOB QUEUE
LOAD. T2,.QBNJQ,(T1) ;GET NEXT ENTRY IN JOB Q
PUSHJ P,@[RSTIT ;RESET
DEQIT ;LOGOUT ALWAYS DEQUEUES
POPIT](P1) ;POP
JRST RESET2 ;GO BACK TO START OF LOOP
RSTIT: LOAD. T4,.QBFLG,(T1) ;GET FLAGS FOR THIS Q-BLOCK
TRNN T4,QBOWNR ;IS THIS THE OWNER OF THE LOCK?
PJRST DEQIT ;NO, DON'T CHECK ETERNAL FLAG
TRNN T4,QBLNDR ;NOT TO BE DELETED ON RESET?
PJRST DEQIT ;IF NDR OPTION NOT SELECTED.
SETO T4, ;CHANNEL OF 777
STOR. T4,.QBCHN,(T1) ;WON'T MATCH ON NEXT FILE OPERATION
PUSHJ P,TSTAAC ;DO WE NEED TO INCRMENT THE A.T. COUNT?
POPJ P, ;NO. GO LOOK AT NEXT REQUEST
LOAD. T3,.QBLB,(T1) ;LOCK BLOCK ADDRESS
LOAD. T4,.LBFLG,(T3) ;YES, GET FLAGS FOR THIS LOCK BLOCK
TRO T4,LBLAUC ;NOTE THAT USE COUNT IS INCREMENTED
STOR. T4,.LBFLG,(T3) ;RESET FLAGS IN LOCK BLOCK
LOAD. T1,.LBACC,(T3) ;GET ACCESS TABLE ADDRESS
CAIGE T1,CODMIN ;IS IT REALLY A SPECIAL CODE?
PUSHJ P,FILIRC## ;NO, INCREMENT READER COUNT
POPJ P, ;LOOK FOR NEXT Q-BLOCK
POPIT: PUSHJ P,[PUSHJ P,SAVT## ;SAVE ALL TEMP ACS
LOAD. T1,.QBLB,(T1) ;GET LOCK BLOCK ADDRESS
MOVE T2,P2
PJRST CHECKQ] ;SEE IF USER IS ALREADY QUEUED
PJRST DEQIT ;YES, DEQUEUE THIS LOCK
LOAD. T4,.QBLJQ,(T1) ;GET ADDRESS OF JOB QUEUE HEADER
STOR. T2,.QBNJQ,(T4) ;POINT JOB QUEUE TO NEXT Q-BLOCK
SKIPE T2 ;IS THERE REALLY A NEXT Q-BLOCK?
STOR. T4,.QBLJQ,(T2) ;YES, POINT IT BACK TO JOB QUEUE HEADER
STOR. P2,.QBJCH,(T1) ;STORE NEW JCH IN Q-BLOCK
SE1XCT< LOAD. T3,.QBNJQ,(P3) ;GET FIRST Q-BLOCK IN NEW JOB QUEUE
STOR. T1,.QBNJQ,(P3)> ;POINT NEW JOB QUEUE HEADER TO Q-BLOCK
STOR. T3,.QBNJQ,(T1) ;POINT NEW FIRST Q-BLOCK TO OLD Q-BLOCK
SKIPE T3 ;IS THERE REALLY AN OLD FIRST Q-BLOCK?
STOR. T1,.QBLJQ,(T3) ;YES, POINT IT BACK TO THE NEW Q-BLOCK
POPJ P, ;LOOK FOR NEXT Q-BLOCK
;TSTAAC -- ROUTINE TO DETERMINE IF WE NEED TO INCREMENT THE
; READ COUNT IN THE ACCESS TABLE TO MAKE IT STAY
; AROUND.
;CALL:
; MOVE T1,Q-BLOCK ADDRESS
; LOAD. T3,.QBLB,(T1) ;LOCK BLOCK ADDRESS
; PUSHJ P,TSTAAC
; <NO NEED TO INCREMENT>
; <MUST INCREMENT>
TSTAAC: PUSHJ P,SAVE4## ;SAVE P1-P4
HRRZ P1,.PDEQJ##(W) ;START OF JOBS QUEUE LIST
LOAD. P4,.LBACC,(T3) ;ACCESS TABLE TO BE CHECKED
TSTAA1: LOAD. P2,.QBLB,(P1) ;LOCK BLOCK ADDRESS OF THIS ENTRY
LOAD. P3,.LBACC,(P2) ;ACCESS TABLE FOR THIS LOCK
CAIE P3,(P4) ;SAME?
JRST TSTAA2 ;NO, LOOK AT NEXT
LOAD. P3,.LBFLG,(P2) ;YES, SEE IF INCREMENTED
TRNE P3,LBLAUC ; BY CHECKING FLAG
POPJ P, ;YES. NO NEED TO INCREMENT AGAIN
TSTAA2: CAIN P1,(T1) ;SEARCHED TO CURRENT Q-BLOCK
JRST CPOPJ1## ;YES. NOT YET INCREMENTED
LOAD. P1,.QBNJQ,(P1) ;ADVANCE TO NEXT Q-BLOCK
JUMPN P1,TSTAA1 ;AND CHECK IT TOO
STOPCD .+1,JOB,ENQQFU ;++Q-BLOCKS FOULED UP
JRST CPOPJ1## ;INCRMENT AND HOPE
;SUBROUTINE TO PERFORM "CLOSE" ON FILE-LOCKS
; THIS ROUTINE IS CALLED ON EVERY CLOSE, OPEN, INIT,
; LOOKUP, AND ENTER WHICH OCCURS.
;IT CHECKS TO SEE IF THERE ARE
; ANY OUTSTANDING LOCKS FOR A GIVEN CHANNEL.
; HOWEVER, IT PERFORMS NO ACTION IF IT FINDS ANY.
;
;CALL:
; HRRI P1,CHANNEL #
; PUSHJ P,ENQCLS##
; HERE IF THERE WERE LOCKS STILL OUT
; HERE IF USER HAD NO LOCKS OUTSTANDING
;PRESERVES ALL
;
ENQCLS::PUSHJ P,SAVJW## ;SAVE JOB/CONTEXT HANDLE
MOVE J,.CPJOB## ;GET USER'S JOB #
PUSHJ P,FNDPDS## ;GET HIS PDB
SKIPN .PDEQJ##(W) ;ANY LOCKS FOR THIS JOB?
JRST CPOPJ1## ;NO, LEAVE QUICKLY
PUSHJ P,SAVT## ;PRESERVE SOME AC'S
HRRZ T2,.PDEQJ##(W) ;GET START OF JOB Q
ENQCL2: JUMPE T2,CPOPJ1## ;LEAVE NOW IF HE HAS NO LOCKS
MOVE T1,T2 ;UPDATE CURRENT BLOCK POINTER
LOAD. T3,.QBCHN,(T1) ;GET CHANNEL # FOR THIS LOCK
LOAD. T2,.QBNJQ,(T1) ;GET NEXT BLOCK IN JOB Q
CAIN T3,(P1) ;MATCHES THE CLOSED CHANNEL?
POPJ P, ;YES, GIVE ERROR RETURN
JRST ENQCL2 ;NO, GET NEXT Q-BLOCK IN JOB QUEUE
;ROUTINE TO VERIFY THAT AN NDR LOCK IS PERMISSIBLE ON A SPECIFIED FILE.
;CALL:
; MOVE T1,LOCK-BLOCK ADDRESS
; PUSHJ P,OKNDR
; ERROR
; OK
;PRESERVES ALL IF NO ERROR. ELSE ERROR CODE IN T1
OKNDR: PUSH P,T1 ;SAVE T1
LOAD. T1,.LBACC,(T1) ;GET ACCESS TABLE ADDRESS
CAIL T1,CODMIN ;IS IT REALLY A SPECIAL CODE?
JRST OKNDR1 ;YES, OK
PUSHJ P,FILGFC## ;GHOST FILE? (BEING CREATED OR SUPERSEDED)
JRST OKNDR2 ;YES, ERROR
OKNDR1: MOVSI T1,JP.ENQ ;ENQ PRIVILEGE BIT
PUSHJ P,[PUSHJ P,SAVT## ;PRESERVE THE TEMP ACS
PJRST PRVBIT##] ;CHECK PRIVILEGE
JRST TPOPJ1## ;OK, GIVE GOOD RETURN
POP P,T1 ;RESTORE T1
MOVEI T1,ENQED% ;GIVE INSUFFICIENT PRIVILEGES ERROR
POPJ P, ;GIVE ERROR RETURN
OKNDR2: POP P,T1 ;RESTORE T1
MOVEI T1,ENQGF% ;CANNOT USE EQ.FEL ON A GHOST FILE
POPJ P, ;ERROR RETURN
;ENQNDR -- CHECK FOR OUTSTANDING LOCKS WITH 'NO
; DELETE ON RESET' SET.
;
;CALL:
; MOVE T1,ACCESS TABLE ADDRESS
; PUSHJ P,ENQNDR
; <IF ANY SET>
; <IF NONE SET>
;PRESERVES ALL
ENQNDR::PUSHJ P,SAVE4## ;SAVE P1-P4
MOVEI P1,HSHLEN##-1 ;TABLE LENGTH
ENQND1: MOVEI P2,HSHTAB##(P1) ;
ENQND2: LOAD. P2,.LBNHS,(P2) ;GET NEXT
CAIN P2,HSHTAB##(P1) ;END OF CHAIN?
JRST ENQND4 ;YES, CHECK NEXT HEADER
LOAD. P3,.LBACC,(P2) ;GET A.T. ADDRESS
CAIE P3,(T1) ;TARGET?
JRST ENQND2 ;NO, LOOK AT NEXT LOCK BLOCK
LOAD. P3,.LBNQ,(P2) ;GET Q-BLOCK LIST
ENQND3: CAIN P3,(P2) ;END OF Q-BLOCK CHAIN?
JRST ENQND2 ;YES, CHECK NEXT LOCK BLOCK
LOAD. P4,.QBFLG,(P3) ;Q-BLOCK FLAGS
TRNE P4,QBLNDR ;NDR REQUEST
POPJ P, ;YES, FAIL NOW
LOAD. P3,.QBNQ,(P3) ;NO. GET NEXT Q-BLOCK
JRST ENQND3 ;LOOP OVER Q-BLOCK CHAIN
ENQND4: SOJGE P1,ENQND1 ;ADVANCE TO NEXT BIN HEADER
JRST CPOPJ1## ;IF DONE
;ENQINI -- INITIALIZE THE QUEUEING SYSTEM (CALLED FROM SYSINI)
;
;CALL:
; PUSHJ P,ENQINI
; RETURN HERE ALWAYS
ENQINI::SKIPL T1,[-HSHLEN##,,HSHTAB##] ;AOBJN POINTER TO HASH TABLE
POPJ P, ;DONE IF NO ENQ/DEQ
ENQIN1: HRRM T1,(T1) ;MAKE RIGHT HALF POINT TO ITSELF
HRLM T1,(T1) ;AND LEFT HALF TOO
AOBJN T1,ENQIN1 ;BUMP POINTER AND COUNTER
POPJ P, ;TABLE ALL DONE
;ENQJBI -- INITIALIZE THE PROCESS DATA BLOCK (FOR LOGIN OR PUSH)
;
;CALL:
; PUSHJ P,ENQJBI
; RETURN HERE ALWAYS
ENQJBI::SETZM .PDEQJ##(W) ;ZERO THE JOB QUEUE
POPJ P, ;DONE
SUBTTL ERROR MESSAGES AND RETURNS
;ERROR RETURNS
; SOME OF THESE RETURN TO THE USER (JRST STOTAC), AND SOME
; OF THEM MERELY RETURN FROM THE CURRENTLY ACTIVE SUBROUTINE
; ERCODE ERRTAB,ENQRU% ;(1) SOME RESOURCES UNAVAILABLE
ERCODE HDRER8,ENQBP% ;(2) ILLEGAL # OF RESOURCES REQUESTED.
ERCODE QCERR1,ENQBJ% ;(3) BAD JOB NUMBER
ERCODE HDRER1,ENQBB% ;(4) BAD BYTE SIZE
ERCODE HDRER2,ENQST% ;(5) STRING TOO LONG
ERCODE NDUERR,ENQBF% ;(6) BAD FUNCTION CODE
ERCODE BFERR,ENQBL% ;(7) ILLEGAL ARGUMENT BLOCK LENGTH
ERCODE HDRERB,ENQIC% ;(10) ILLEGAL # OF LOCKS SPECIFIED
ERCODE HDRER6,ENQBC% ;(11) BAD CHANNEL NUMBER
ERCODE HDRER7,ENQPI% ;(12) OPERATOR/JACCT PRIVILEGE REQUIRED
ERCODE DOERR6,ENQNC% ;(13) NO CORE AVAILABLE
ERCODE HDRER9,ENQFN% ;(14) FILE NOT OPEN, OR DEVICE NOT A DISK
ERCODE HDRERA,ENQIN% ;(15) INDIRECT BYTE POINTER
; ERCODE DERNJQ,ENQNO% ;(16) NO RESOURCES WERE OWNED
ERCODE ENQER1,ENQLS% ;(17) LEVEL # TOO LOW
; ERCODE DOERR5,ENQCC% ;(20) CAN'T CHANGE ACCESS
; ERCODE ENQER3,ENQQE% ;(21) QUOTA EXCEEDED
ERCODE DOERR2,ENQPD% ;(22) POOL COUNT DISCREPANCY
ERCODE DOERR3,ENQDR% ;(23) LOCK ALREADY REQUESTED
; ERCODE DOERR4,ENQNE% ;(24) NOT ENQ'D ON THIS LOCK
ERCODE DOERR0,ENQLD% ;(25) LEVEL # DESCREPANCY
ERCODE PRVERR,ENQED% ;(26) ENQ/DEQ PRIVILEGES REQUIRED
ERCODE MWLERR,ENQME% ;(27) MASK WORD LENGTH ERROR
ERCODE TBLERR,ENQTE% ;(30) TABLE ERROR
ERCODE ABTERR,ENQAB% ;(31) ATTEMPT TO ENQ. AN ABORTED LOCK
; ERCODE NDRERC,ENQGF% ;(32) ATTEMPT TO LOCK WITH NDR ON A 'GHOST FILE'
; ERCODE DEDERR,ENQDD% ;(33) DEADLOCK DETECTED
; ERCODE TLEERR,ENQTL% ;(34) TIME LIMIT EXCEEDED
;PRIVILEGES INSUFFICIENT (AND EXIT TO USER)
HDRERC: MOVEI T1,ENQPI%
JRST STOTAC##
;QUOTA EXCEEDED
ENQER3: MOVEI T1,ENQQE% ;QUOTA EXCEEDED
JRST STOTAC##
;BAD LENGTH GIVEN IN ARGUMENT BLOCK (FOR DUMP)
QCERR2: MOVEI T1,ENQBL% ;BAD DUMP BLOCK LENGTH
JRST STOTAC##
;NO REQUEST FOUND FOR LOCK
DOERR4: MOVEI T1,ENQNE% ;NO PENDING REQUEST FOUND
JRST MARETN ;GO STORE CODE
;CAN'T CHANGE ACCESS
DOERR5: MOVEI T1,ENQCC% ;CAN'T CHANGE ACCESS
MARETN: HRRM T1,NQERRF ;SAVE CODE
JRST CPOPJ1## ;RETURN FROM "ENQIT"
;RESOURCE NOT FOUND (DEQ ALL OR DEQ REQ:ID)
DERNJQ: MOVEI T1,ENQNO% ;NO RESOURCES FOUND
JRST STOTAC## ;GIVE USER THE ERROR CODE
;COME HERE TO MAKE A GOOD EXIT BACK TO THE USER
;THE CONTENTS OF T1 ARE RETURNED IN THE UUO AC.
GUDXIT: HRRZ T1,NQERRF ;RETRIEVE ERROR CODE(FROM ENQ)
GUDXT2: AOS (P) ;BUMP RETURN ADDRESS
JRST STOTAC## ;AND GIVE IT BACK TO HIM
SUBTTL TEMPORARY STORAGE LOCATIONS FOR ENQ/DEQ
$LOW
;
;NOTE THAT THESE LOCATIONS ARE NOT SAVED IF A JOB BECOMES
; BLOCKED. THEREFORE, THEY SHOULD BE USED ONLY FOR
; TEMPORARY STORAGE FOR THE DURATION OF THE PROCESSING OF
; THE UUO, EXCLUDING ANY SCHEDULING WHICH MAY OCCUR.
;
;WHEN ADDING OR DELETING VARIABLES
;FROM THIS AREA, BE SURE TO
;UPDATE THE VALUE OF QDBLEN IN
;COMMON SO IT IS THE SAME AS
;THE VALUE COMPUTED HERE
;
ENQ...==0 ;VARIABLE FOR WORD MACRO
DEFINE WORD(SYM),<
SYM==.CPQTS##+ENQ...
ENQ...==ENQ...+1
>
DEFINE BLOK(SYM,N),<
SYM==.CPQTS##+ENQ...
ENQ...==ENQ...+N
>
BLOK(ENQFLG,1) ;-1 IF ENQ., ELSE 0
;***DO NOT SEPARATE OR REORDER THE FOLLOWING WORDS***
BLOK(USRLOK,3) ;COPY OF USERS LOCK BLOCK ARGUMENT
BLOK(EQLMSK,1) ;COPY OF MASK WORD FROM USER
BLOK(EQLTBL,1) ;COPY OF TABLE POINTER FROM USER
;***THE PREVIOUS GROUP MUST BE LKMAX WORDS LONG***
WORD(LOKSIZ) ;SIZE OF LOCK ENTRY FOR THIS CALL
WORD(HDRSIZ) ;SIZE OF HEADER FOR THIS CALL
WORD(FCODE) ;KEEP THE USER'S FUNCTION CODE HERE
WORD(HILEVL) ;HIGHEST LEVEL # ISSUED BY USER
WORD(RBLOCK) ;ADDRESS OF USER'S PARAMETER BLOCK
WORD(SBLOCK) ;ADDRESS OF USER'S STATUS BLOCK
WORD(LOCKCT) ;# OF LOCKS IN REQUEST,,# OF CURRENT LOCK
WORD(REQID) ;STORAGE FOR REQUEST ID
WORD(TIMLIM) ;TIME LIMIT TO OBTAIN LOCKS
WORD(NQERRF) ;NON-ZERO IF ERROR OCCURED
WORD(REQCNT) ;COUNT OF OUTSTANDING RESOURCE REQUESTS FOR THIS USER
WORD(LSTLOK) ;LAST LOCK-BLOCK CREATED (FOR DEBUGGING)
WORD(LASTQ) ;LAST Q-BLOCK CREATED (FOR DEBUGGING)
QDBLEN==:ENQ... ;DEFINE LENGTH OF DATABASE
;
; THESE ARE ALL SUPER-TEMPORARY VARIABLES ONLY USED WITH EQ RESOURCE
;
DQFLAG: BLOCK 1 ;NON:ZERO IF A LOCK WAS DEQ'D
EQTMP1: BLOCK 1 ;RANDOM TEMPORARIES
EQTMP2: BLOCK 1 ;..SAME
EQTMP3: BLOCK 1 ;..SAME
EQTMP4: BLOCK 1 ;..SAME
EQTMP5: BLOCK 1
LKTMP1: BLOCK 1 ;STORAGE FOR LOCK-SCHEDULER
LKTMP2: BLOCK 1 ;..SAME
LKTMP3: BLOCK 1 ;..SAME
LKTMP4: BLOCK 1 ;..SAME
QSKDF: BLOCK 1 ;STORAGE FOR Q-SCHEDULER
QSKDG: BLOCK 1 ;..SAME
QSKDT: BLOCK 1 ;..SAME
QSKDQ: BLOCK 1 ;..SAME
QSKDM: BLOCK 1 ;..SAME
QSKDN: BLOCK 1 ;..SAME
ENQTBC: BLOCK 1 ;POINTER TO NEXT Q-BLOCK TO BE DEADLOCK CHECKED
ENQHBC: BLOCK 1 ;POINTER TO NEXT Q-BLOCK ALREADY CHECKED
$LIT
END
############################################################