1
0
mirror of https://github.com/PDP-10/stacken.git synced 2026-02-16 12:42:51 +00:00
Files
PDP-10.stacken/files/stacken-tape-backup/dskb:10_7/mon/queser.mac
Lars Brinkhoff 6e18f5ebef Extract files from tape images.
Some tapes could not be extracted.
2021-01-29 10:47:33 +01:00

2823 lines
92 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
TITLE QUESER -- ENQUEUE/DEQUEUE SERVICE FACILITY - V145
SUBTTL S. BLOUNT /WRS/PMV 22-DEC-87
SEARCH F,S
$RELOC
$HIGH
;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED
; OR COPIED ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
;COPYRIGHT (c) DIGITAL EQUIPMENT CORPORATION
; 1974,1975,1976,1977,1978,1979,1980,1982,1984,1986,1988.
;ALL RIGHTS RESERVED.
.CPYRT<1974,1988>
XP VQUESR,145
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
;
;
;
UENQ:: 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
UDEQ:: 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
UENQC:: 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,FLMCOM ;FOR PRVBIT
MOVSI T1,JP.POK
PUSHJ P,PRVBIT## ;AM I [1,2] OR JACCT?
TLOA M,FLMCOM ;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:
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
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
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
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
;
;
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
;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,FLMCOM ;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
$INIT
;ENQINI -- INITIALIZE THE QUEUEING SYSTEM (CALLED FROM SYSINI)
;
;CALL:
; PUSHJ P,ENQINI
; RETURN HERE ALWAYS
ENQINI::SKIPE [HSHTAB##] ;SKIP IF NO INITIALIZATION TO BE DONE
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
$HIGH
;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
SUBTTL GETTAB TABLE
.EQTAB::
%ENQML: EXP EQMXCH ;MAXIMUM WORD SIZE OF STRING
%ENQNQ: Z ;NUMBER OF ACTIVE QUEUES
%ENQTE: Z ;TOTAL NUMBER OF ENQ'S SINCE RELOAD
%ENQTD: Z ;TOTAL NUMBER OF DEQ'S SINCE RELOAD
%ENQNP: Z ;NUMBER OF ACTIVE POOLED RESOURCES
%ENQDF: EXP M.ENQD## ;DEFAULT ENQ QUOTA
%ENQMM: EXP EQMXMW ;PIE-SLICE-LOCK MAX BLOCK SIZE
%ENQMT: EXP EQMXTB ;LOCK-ASSOCIATED TABLE MAX SIZE
%ENQLT: EXP EQMLTL ;MINUTES LONG TERM LOCKS STAY AROUND
%ENQDD: Z ;NUMBER OF DEADLOCKS DETECTED
%ENQTO: Z ;NUMBER OF TIMEOUTS
%ENQMQ: EXP M.ENQM## ;MAXIMUM NUMBER OF ACTIVE QUEUES
ENQMXL==:<.-.EQTAB-1>B26 ;FOR GETTAB
$LIT
QUEEND::END