Trailing-Edge
-
PDP-10 Archives
-
bb-m780a-sm
-
monitor-sources/enq.mac
There are 50 other files named enq.mac in the archive. Click here to see a list.
; UPD ID= 204, SNARK:<5.MONITOR>ENQ.MAC.6, 22-Sep-81 16:57:52 by PAETZOLD
;More TCO 5.1481 - Fix the problem
; UPD ID= 165, SNARK:<5.MONITOR>ENQ.MAC.5, 10-Sep-81 14:45:03 by PAETZOLD
;TCO 5.1481 - Check for illegal OWGBP's
; UPD ID= 1763, SNARK:<5.MONITOR>ENQ.MAC.4, 24-Mar-81 14:07:53 by BLOUNT
;change STRCMP+5 from CAIN T2,NUMVAL to CAIN T3,NUMVAL
; UPD ID= 1003, SNARK:<5.MONITOR>ENQ.MAC.3, 11-Sep-80 18:00:47 by GRANT
;Change MONX01 to MONX06 in ASGENQ routine
; UPD ID= 935, SNARK:<5.MONITOR>ENQ.MAC.2, 20-Aug-80 15:15:43 by ENGEL
;TCO #5.1136 - CHANGE ALL LOCKS TO CONFORM TO THE NEW LOCK SCHEME
; UPD ID= 46, SNARK:<4.1.MONITOR>ENQ.MAC.16, 28-Nov-79 17:25:57 by HALL
;REMOVE CODE FOR INTERNAL ENQ AND DEQ OPERATIONS BECAUSE NO ONE CALLS IT
;<4.MONITOR>ENQ.MAC.14, 21-Oct-79 18:43:46, EDIT BY MAGRATH
;TCO 4.2540 - Routine FNDQ, add JFN check to search criteria
;<OSMAN.MON>ENQ.MAC.1, 10-Sep-79 15:28:06, EDIT BY OSMAN
;TCO 4.2412 - Move definition of BUGHLTs, BUGCHKs, and BUGINFs to BUGS.MAC
;<4.MONITOR>ENQ.MAC.12, 29-Aug-79 20:06:49, EDIT BY ZIMA
;USE THE PREFERRED MNEMONICS TO CHECK FOR NUMVAL
;<4.MONITOR>ENQ.MAC.11, 10-Jul-79 12:56:44, EDIT BY ZIMA
;TCO 4.2321 - FIX STRCMP TO RECOGNIZE MISMATCH OF USER CODE AND STRING.
;<4.MONITOR>ENQ.MAC.10, 1-May-79 23:31:04, Edit by MCLEAN
;MAKE JOB NUMBER OF 0,,-1 BE -1 FOR GTOKM .GOENQ..
;<4.MONITOR>ENQ.MAC.9, 18-Apr-79 16:46:41, Edit by MCLEAN
;REMOVE EXTRANEOUS NOINT ON CALL TO SETJSB IN ENQOK
;<4.MONITOR>ENQ.MAC.8, 18-Apr-79 15:10:00, Edit by MCLEAN
;ADD JOB NUMBER TO ENQ QUOTA CHANGE
;<4.MONITOR>ENQ.MAC.7, 5-Apr-79 11:44:12, Edit by MCLEAN
;<4.MONITOR>ENQ.MAC.6, 5-Apr-79 11:25:10, Edit by MCLEAN
;REMOVE 1ST ARG FROM GTOKM
;<4.MONITOR>ENQ.MAC.5, 9-Mar-79 14:05:32, Edit by MCLEAN
;FIX GTOKM TO RETERR NOT ITRAP
;<4.MONITOR>ENQ.MAC.4, 4-Mar-79 15:34:01, EDIT BY KONEN
;UPDATE COPYRIGHT FOR RELEASE 4
;<4.MONITOR>ENQ.MAC.3, 23-Jul-78 16:54:03, Edit by MCLEAN
;ADD GETOK TO SETTING QUOTAS FOR ENQ FOR NON PRIV USERS
;<4.MONITOR>ENQ.MAC.2, 23-Jul-78 16:52:40, Edit by MCLEAN
;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED
; OR COPIED IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
;COPYRIGHT (C) 1976,1977,1978,1979 BY DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASS.
SEARCH PROLOG
TTITLE ENQ
;THE ENQ AND DEQ JSYS'S
REPEAT 0,<
;Q-BLOCK FORMAT
+-------------------------+-------------------------+
!ENQLJQ: !ENQNJQ: !
! BACK POINTER TO ! FORWARD POINTER TO !
! LAST Q-BLOCK FOR JOB ! NEXT Q-BLOCK FOR JOB !
+-------------------------+-------------------------+
!ENQLLQ: !ENQNLQ: !
! BACK POINTER TO ! FORWARD POINTER TO !
! LAST Q-BLOCK ! NEXT Q-BLOCK !
+----------------+--------+-------------------------+
!ENQFLG: !ENQCHN: !ENQFRK: !
! FLAGS ! PSI ! FORK TO INTERRUPT !
! ! CHANNEL! WHEN REQUEST IS LOCKED !
+----------------+--------+-------------------------+
!ENQNR: !ENQID: !
! # OF RESOURCES ! REQUEST ID CODE !
! REQUESTED FROM POOL ! !
+-------------------------+-------------------------+
!ENQLRQ: !ENQFQ: !
! BACK POINTER TO ! FORWARD POINTER TO !
! LAST Q-BLOCK OF REQUEST ! NEXT Q-BLOCK OF REQUEST !
+-------------------------+-------------------------+
!ENQLBP: !ENQGRP: !
! POINTER TO ! GROUP # FOR !
! LOCK-BLOCK ! SHARABLE REQUESTS !
+-------------------------+-------------------------+
!ENQNST: !ENQJFN: !
! NEST COUNT ! JFN OF REQUEST !
! ! OR -1, -2, OR -3 !
+-------------------------+-------------------------+
! !ENQMSK: !
! ! POINTER TO THE !
! ! MASK BLOCK !
+-------------------------+-------------------------+
;LOCK-BLOCK FORMAT
+-------------------------+-------------------------+
!ENQLHC: !ENQNHC: !
! BACK POINTER TO LAST ! POINTER TO NEXT !
! LOCK-BLOCK ON HASH CHAIN! LOCK-BLOCK ON HASH CHAIN!
+-------------------------+-------------------------+
!ENQLLQ: !ENQNLQ: !
! BACK POINTER TO ! FORWARD POINTER TO !
! LAST Q-BLOCK ON QUEUE ! FIRST Q-BLOCK ON QUEUE !
+---------------+---------+-------------------------+
!ENQFLG: ! !ENQLVL: !
! FLAGS ! ! LEVEL NUMBER !
! ! ! OF THIS LOCK !
+---------------+---------+-------------------------+
!ENQTR: !ENQRR: !
! TOTAL # OF RESOURCES ! REMAINING NUMBER OF !
! IN THIS POOL ! RESOURCES IN THIS POOL !
+-------------------------+-------------------------+
!ENQTS: !
! TIME STAMP !
! TIME OF LAST REQUEST LOCKED !
+-------------------------+-------------------------+
!ENQFBP: !ENQLT: !
! FREE BLOCK POINTER ! LONG TERM LOCK LIST !
! TO FREE Q-BLOCK ! FOR THIS JOB !
+-------------------------+-------------------------+
!ENQOFN: !ENQLEN: !
! OFN, OR -2, OR -3, ! LENGTH OF THIS !
! OR 400000 + JOB NUMBER ! LOCK-BLOCK !
+-------------------------+-------------------------+
!ENQNMS: ! !
! NUMBER OF WORDS IN ! !
! THE MASK BLOCK ! !
+-------------------------+-------------------------+
!ENQTXT: ASCIZ STRING !
! OR !
! 500000 + USER CODE !
+---------------------------------------------------+
> ;END OF REPEAT 0
;LOCAL STORAGE DECLARED IN STG.MAC
EXTN <HSHTBL,HSHLEN,ENFKTB,ENFKTL>
;STRUCTURE DEFINITIONS FOR ENQ/DEQ
SWAPCD
DEFSTR(ENQLJQ,0,17,18) ;BACK POINTER TO LAST Q FOR JOB
DEFSTR(ENQNJQ,0,35,18) ;FORWARD POINTER TO NEXT Q FOR JOB
;ENQNJQ AND ENQLJQ MUST BE IN WORD 0
DEFSTR(ENQLLQ,1,17,18) ;BACK POINTER TO LAST Q IN LOCK QUEUE
DEFSTR(ENQNLQ,1,35,18) ;FORWARD POINTER TO NEXT Q OF LOCK
DEFSTR(ENQFLG,2,11,12) ;FLAGS OF BLOCK (EITHER LOCK OR Q)
DEFSTR(ENQCHN,2,17,6) ;PSI CHANNEL #, -1 MEANS JOB BLOCKED
DEFSTR(ENQFRK,2,35,18) ;FORK NUMBER OF CREATOR OF Q-BLOCK
DEFSTR(ENQNR,3,17,18) ;# OF RESOURCES REQUESTED
DEFSTR(ENQID,3,35,18) ;ID OF ENQ REQUEST
DEFSTR(ENQLRQ,4,17,18) ;BACK POINTER TO REST OF REQUEST
DEFSTR(ENQFQ,4,35,18) ;FORWARD POINTER TO REST OF REQUEST
DEFSTR(ENQLBP,5,17,18) ;POINTER TO LOCK-BLOCK OF THIS Q
DEFSTR(ENQGRP,5,35,18) ;GROUP NUMBER OF SHARABLE REQUEST
DEFSTR (ENQJFN,6,35,18) ;JFN OF ENQ REQUEST
DEFSTR (ENQNST,6,17,18) ;NEST COUNT
DEFSTR (ENQMSK,7,35,18) ;POINTER TO MASK BLOCK
DEFSTR(ENQLHC,0,17,18) ;BACK POINTER TO LAST LOCK IN HASH LIST
DEFSTR(ENQNHC,0,35,18) ;FORWARD PNTR TO NEXT LOCK ON HASH LIST
;ENQNHC AND ENQLHC MUST BE IN WORD 0
DEFSTR(ENQLVL,2,35,18) ;LEVEL NUMBER OF LOCK
DEFSTR(ENQTR,3,17,18) ;TOTAL # OF RESOURCES IN POOL
DEFSTR(ENQRR,3,35,18) ;# OF RESOURCES REMAINING IN POOL
DEFSTR(ENQTS,4,35,36) ;TIME STAMP OF LAST REQUEST TO BE LOCKED
DEFSTR(ENQFBP,5,17,18) ;POINTER TO FREE Q-BLOCK
DEFSTR(ENQLT,5,35,18) ;LONG TERM LOCK LIST FOR THIS JOB
.ENQLT==5 ;OFFSET OF LOCK LIST ELEMENT
DEFSTR(ENQOFN,6,17,18) ;OFN, -2, -3, OR 400000+JOB NUMBER
DEFSTR(ENQLEN,6,35,18) ;LENGTH OF LOCK-BLOCK
DEFSTR(ENQNMS,7,17,18) ;NUMBER OF WORDS IN THE MASK BLOCK
DEFSTR(ENQTXT,10,35,36) ;FIRST WORD OF TEXT OR USER CODE
.ENTXT==10 ;INDEX INTO LOCK-BLOCK FOR TEXT BLOCK
DEFSTR(ENQOTA,ENQLST,8,9) ;ENQ/DEQ QUOTA
DEFSTR(ENQCNT,ENQLST,17,9) ;COUNT OF REQUESTS QUEUED UP
QBLEN==10 ;LENGTH OF Q-BLOCK
LBLEN==10 ;LENGTH OF LOCK-BLK NOT COUNTING ENQTXT
ENQMXW==^D50 ;MAXIMUM # OF WORDS IN TEXT STRING
ENQMFN==3 ;MAX ENQ FUNCTION CODE
DEQMXF==1 ;MAX DEQ FUNCTION CODE
ENQCMF==2 ;MAX ENQC FUNCTION CODE
ENQSTQ==^D50 ;STANDARD ENQ/DEQ QUOTA
.ENQRL==3 ;LENGTH OF A LOCK REQUEST
.ENQHL==2 ;# OF HEADER WORDS IN ARGUMENT BLOCK
.ENWCH==77 ;FORK IS WAITING FOR CALL TO WAKFRK
LVLLEN==11 ;LENGTH OF LEVEL NUMBER FIELD
;ENQ/DEQ FLAGS IN "ENQFLG"
EN.LB==1 ;THIS IS THE LOCK-BLOCK
EN.EXC==2 ;REQUEST IS EXCLUSIVE
EN.TXT==4 ;THIS LOCK HAS A TEXT STRING IDENTIFIER
EN.LOK==10 ;THIS Q-BLOCK HAS THE LOCK LOCKED
EN.INV==20 ;THIS Q-BLOCK IS INVISIBLE
EN.LTL==40 ;LONG TERM LOCK
;THE ENQ JSYS
;ACCEPTS IN 1/ FUNCTION CODE
; 2/ LOCATION OF ARGUMENT BLOCK
; ENQ
;RETURNS +1: ERROR - ERROR CODE IN T1
; +2: SUCCESSFUL, SPECIFIED LOCKS ARE LOCKED
;THE ARGUMENT BLOCK HAS THE FOLLOWING FORMAT:
;LOC/ # OF LOCKS ,, LENGTH OF ARG BLOCK
;LOC+1/ PSI CHANNEL # ,, REQUEST ID
;LOC+2/ FLAGS & LEVEL NUMBER ,, JFN, -1, -2, OR -3
;LOC+3/ POINTER TO STRING OR 500000+USER CODE
;LOC+4/ # OF RESOURCES IN POOL ,, # OF RESOURCES REQUESTED
; .
; .
; .
;LOC+N/ FLAGS & LEVEL NUMBER ,, JFN, -1, -2, OR -3
;LOC+N+1/ POINTER TO STRING OR 500000 + USER CODE
;LOC+N+2/ # OF RESOURCES IN POOL ,, # OF RESOURCES REQUESTED
.ENQ:: MCENT ;ENTER JSYS
NOINT ;DONT ALLOW INTERRUPTS DURING CALL
LOKK ENQLKK ;LOCK UP THE ENQ DATA BASE
SETO T1, ;MARK THAT THIS IS A NORMAL TYPE ENQ
CALL ENQREQ ;GO SERVICE THIS REQUEST
JRST ENUNLE ;ERROR RETURN, GO UNLOCK
UMOVEM T2,1 ;RETURN ANSWER FOR USER
UNLOKK ENQLKK ;FREE UP THE DATA BASE
OKINT ;ALLOW INTERRUPTS
SKIPE T1 ;DO MDISMS?
MDISMS ;YES, WAIT FOR LOCK TO FREE UP
SMRETN ;GIVE SUCCESSFUL RETURN TO USER
ENUNLE: UNLOKK ENQLKK ;UNLOCK THE DATA BASE
OKINT ;ALLOW INTERRUPTS AGAIN
RETERR ;GIVE ERROR RETURN TO USER
REPEAT 0,<
;INTERNAL MONITOR ROUTINE TO ENQ ON A 33-BIT NUMBER
;ACCEPTS IN T1/ 33-BIT NUMBER
;ASSUMES A -3 LOCK, LEVEL # OF 0, ONE LOCK, ID = 0, AND ALWAYS WAIT
; CALL ENQUE
;RETURNS +1: ALWAYS, LOCK LOCKED
ENQUE: NOINT ;LOCK UP THE DATA BASE
LOKK ENQLKK ;...
SAVEPQ ;SAVE ALL PERMANENT ACS
CALL MONVAL ;GET ARGUMENTS SET UP
CALL ENQREQ ;DO THE ENQ
BUG(ENQMLF)
UNLOKK ENQLKK ;FREE UP DATA BASE
OKINT
SKIPE T1 ;NEED TO MDISMS?
MDISMS ;YES, WAIT TILL LOCK IS LOCKED
RET ;AND RETURN
>
;ROUTINE TO SET UP Q1-Q3, P1-P5 FOR INTERNAL ENQ AND DEQ CALLS
; CALL MONVAL
;RETURNS +1: ALWAYS
MONVAL: TLZ T1,700000 ;SET UP 500000,,0 + 33-BIT NUMBER
TLO T1,500000
MOVE P2,T1 ;P2 = USER CODE TO LOCK ON
MOVEI P1,-3 ;P1 = LEVEL 0, -3 LOCK TYPE
SETZB Q1,Q2 ;Q1 = 1 LOCK, Q2 = 0 ID VALUE
SETZB Q3,P3 ;MONITOR LEVEL = 0, EXCULSIVE LOCK
SETZB T1,P5 ;SHARABLE GROUP 0
RET
;ROUTINE TO SET UP GLOBAL VARIABLES USED BY CALLERS OF VALARG AND VALREQ
; JSP T1,SETVAR
;RETURNS +1: ALWAYS
SETVAR: TRVAR <EDNMS,EDMSK,EDSTP,EDSTB>
CALLRET 0(T1)
;EDNMS = NUMBER OF WORDS IN THE MASK BLOCK (MINUS COUNT WORD)
;EDMSK = ADDRESS OF THE FIRST MASK WORD OF MASK BLOCK
;EDSTP = -1 ,, LENGTH OF LOCK REQUEST BLOCK
;EDSTB = ADDRESS OF STATUS BLOCK FOR ENQC FUNCTION 0
;ROUTINE TO DO THE ENQ JSYS
;THIS ROUTINE MUST BE CALLED NOINT AND WITH ENQLKK LOCKED
;ACCEPTS IN T1/ 0 = INTERNAL MONITOR CALL
; -1 = NORMAL JSYS CALL
; CALL ENQREQ
;RETURNS +1: ERROR - CODE IN T1
; +2: OK
; T1 = 0, REQUEST IS LOCKED
; T1 NOT 0, DO MDISMS FIRST, THEN RETURN
; T2 = VALUE TO BE RETURNED IN USER AC 1
ENQREQ: JSP T1,SETVAR ;SET UP GLOBAL VARIABLES
STKVAR <ENQFC,ENQHI,ENQQ,ENQLB,ENQERC,ENQOKR>
SETZM ENQFC ;INITIALIZE FUNCTION CODE
JUMPE T1,ENQ5 ;IF 0, THIS IS A MONITOR CALL
SETZM ENQERC ;INITIALIZE ERROR CODE REGISTER
SETZM ENQOKR ;INITIALIZE OK RETURN ANSWER
SETZM ENQQ ;INITIALIZE THE Q-BLOCK ADDDRESS
SETZM ENQLB ;INITIALIZE LOCK BLOCK ADDRESS
CALL VALARG ;VALIDATE THE USER'S ARGUMENT BLOCK
RET ;SOMETHING ILLEGAL
XCTU [HRRZ T1,1] ;GET FUNCTION CODE
CAILE T1,ENQMFN ;MAKE SURE IT IS LEGAL
RETBAD (ENQX1) ;OUT OF BOUNDS, GIVE ERROR RETURN
MOVEM T1,ENQFC ;SAVE FUNCTION CODE FOR LATER
CAIN T1,0 ;IS THIS FUNCTION 0?
HRRI Q2,.ENWCH ;YES, MARK THE WAKFRK IS TO BE CALLED
ENQ0: CALL VALREQ ;VALIDATE THIS LOCK REQUEST
JRST ENQERR ;UNDO WHAT WAS JUST DONE
ENQ5: MOVE T1,ENQFC ;GET FUNCTION CODE
CAIN T1,.ENQMA ;IS IT MODIFY ACCESS FUNCTION?
JRST ENQFN3 ;YES, HANDLE THIS SEPERATELY
CALL HASH ;HASH THIS REQUEST
JRST ENQERR ;COULDNT HASH, GO UNDO REQUEST
MOVEM T1,ENQHI ;REMEMBER THE HASH INDEX VALUE
CALL FNDLOK ;FIND THE LOCK BLOCK
JRST [ MOVE T1,ENQHI ;NO LOCK BLOCK, GET HASH INDEX AGAIN
CALL CRELOK ;CREATE A LOCK BLOCK FOR THIS LOCK
JRST ENQERR ;FAILED! GO UNDO REQUEST
JRST .+1] ;LOCK BLOCK CREATED, ADR IN T1
MOVEM T1,ENQLB ;SAVE THE LOCK-BLOCK ADDRESS
LOAD T2,ENQNMS,(T1) ;GET SIZE OF MASK BLOCK FROM LOCK BLOCK
JUMPE T2,ENQ8 ;IF NONE SPECIFIED YET, THEN OK
CAME T2,EDNMS ;IF NOT 0, THEN BOTH BLOCKS MUST BE EQUAL
SKIPN EDNMS ;UNLESS THE CALLER IS NOT GIVING A BLOCK
SKIPA ;MASK BLOCKS ARE COMPATIBLE
RETBAD (ENQX23) ;MISMATCHED MASK BLOCK SIZE
ENQ8: LOAD T2,ENQLVL,(T1) ;GET LEVEL NUMBER OF THIS LOCK
HRRZ T4,P1 ;GET OFN
HRRE T3,Q3 ;GET USER MINIMUM LOCK LEVEL
CAIN T4,-3 ;IS THIS A MONITOR LOCK?
HLRE T3,Q3 ;YES, GET MONITOR MINIMUM LEVEL
CAMG T2,T3 ;IS THIS LEVEL NUMBER LEGAL?
JRST [ TLNE P1,(EN%BLN) ;USER BYPASSING LEVEL NUMBERS?
JRST [ MOVEI T3,ENQX2 ;YES, SET UP ANSWER FOR USER
MOVEM T3,ENQOKR
JRST ENQ4]
MOVEI T1,ENQX2 ;NO, GO UNDO THE REQUEST
JRST ENQERR]
;..
;..
ENQ4: LDB T3,[POINT 9,P1,17] ;GET LEVEL NUMBER SPECIFIED IN REQ
CAME T2,T3 ;LEVEL NUMBERS MATCH?
JRST [ TLNE P1,(EN%BLN) ;BYPASSING LEVEL #'S?
JRST [ MOVEI T3,ENQX3 ;YES, SET UP ERROR CODE
MOVEM T3,ENQOKR ;FOR SKIP RETURN
JRST ENQ6]
MOVEI T1,ENQX3 ;NO, THIS IS ILLEGAL
JRST ENQERR] ;GO UNDO EVERYTHING
ENQ6: LOAD T2,ENQTR,(T1) ;GET TOTAL NUMBER OF RESOURCES IN POOL
HLRZ T3,P3 ;GET USER'S VALUE
CAME T2,T3 ;ARE THEY IDENTICAL?
JRST [ MOVEI T1,ENQX4 ;NO, THIS IS NOT ALLOWED
JRST ENQERR] ;GO UNDO
CALL FNDQ ;SEE IF THERE IS ALREADY A REQUEST IN
SKIPA T1,ENQLB ;NO, GET LOCK BLOCK BACK
JRST [ TXNE P1,EN%NST ;NESTED LOCK?
JRST ENQ7 ;YES
MOVEI T1,ENQX5 ;YES, THIS IS NOT ALLOWED
JRST ENQERR] ;GO UNDO THE REQUEST
MOVE T2,ENQQ ;GET LAST Q-BLOCK IN THIS REQUEST
SETZ T3, ;INITIALIZE FLAGS
JUMPN P3,ENQ1 ;IF POOLED REQUEST, DONT SET ANY FLAGS
TLNN P1,(EN%SHR) ;IS THIS A SHARED REQUEST
TRO T3,EN.EXC ;NO, SET EXCLUSIVE FLAG
ENQ1: CALL CREQ ;CREATE THE Q-BLOCK FOR THE REQUEST
JRST ENQERR ;FAILED, GO UNDO THE REQUEST
ENQ1A: MOVEM T1,ENQQ ;SAVE THE Q-BLOCK ADR FOR OTHER ENTRIES
ENQ2: ADD Q1,EDSTP ;ADVANCE THE POINTER TO THE NEXT REQ
JUMPG Q1,ENQ0 ;LOOP BACK FOR ALL REQUESTS
SKIPE T1,ENQERC ;ANY ERRORS SEEN?
RET ;YES, TAKE ERROR RETURN NOW
SKIPN T1,ENQQ ;GET A Q-BLOCK ADDRESS IF ANY
JRST ENQ3 ;NONE, MUST BE CHANGE ACCESS CALL
CALL QSKD ;DO A SCHEDULING PASS OVER QUEUE
JRST ENQNL ;LOCK NOT LOCKED
ENQ3: SETZ T1, ;FLAG THAT MDISMS IS NOT NEEDED
MOVE T2,ENQOKR ;SET UP USER'S AC
RETSKP ;REQUEST IS FULLY LOCKED
ENQ7: INCR ENQNST,(T1) ;COUNT UP THE NEST COUNT
JRST ENQ1A ;AND ALLOW THIS ENQ TO CONTINUE
ENQNL: MOVE T1,ENQFC ;GET THE FUNCTION CODE
JRST @ENQNLT(T1) ;GO PERFORM THE PROPER EXITING
ENQNLT: IFIW!ENQWAT ;0 - WAIT UNTIL LOCKED
IFIW!ENQDEQ ;1 - DEQ THIS REQUEST
IFIW!ENQRET ;2 - JUST EXIT AND WAIT FOR INTERRUPT
ENQWAT: MOVE T1,FORKX ;WAIT UNTIL THE REQUEST IS SATISFIED
CALL GETMSK ;CLEAR OUT WAITING CONDITION
ANDCAM T2,ENFKTB(T1) ;...
HRRI T1,ENQTST ;SET UP FOR MDISMS
HRL T1,FORKX
RETSKP ;RETURN AND DO AN MDISMS UNTIL LOCKED
ENQDEQ: MOVE T1,ENQQ ;GET Q-BLOCK ADDRESS
CALL REQDEQ ;DEQUEUE THIS REQUSET
ENQRET: MOVEI T1,ENQX6 ;GET "LOCK NOT SET" ERROR CODE
RET ;GIVE ERROR RETURN
ENQERR: MOVEM T1,ENQERC ;SAVE ERROR CODE
SKIPN T1,ENQLB ;WAS A LOCK-BLOCK FOUND?
JRST ENQER1 ;NO, JUST EXIT
LOAD T2,ENQNLQ,(T1) ;IS IT AN EMPTY LOCK-BLOCK?
CAIN T2,0(T1) ;...
CALL LOKREL ;YES, DELETE IT
SKIPE T1,ENQQ ;WAS A Q-BLOCK CREATED?
CALL REQDEQ ;YES, DELETE THE REQUEST
ENQER1: MOVE T1,ENQERC ;GET ERROR CODE BACK
RET ;AND GIVE NON-SKIP RETURN
;FUNCTION CODE 3 (.ENQMA)
ENQFN3: CALL HASH ;HASH THIS REQUEST
JRST ENQF3F ;ERROR
CALL FNDLOK ;FIND THE LOCK BLOCK
JRST ENQF3F ;NOT ENQ'D ON THIS LOCK
MOVEM T1,ENQLB ;SAVE LOCK-BLOCK ADDRESS
CALL FNDQ ;FIND THE Q-BLOCK FOR THIS REQUEST
JRST ENQF3F ;NOT ENQ'D ON THIS LOCK
LOAD T2,ENQTR,(T1) ;GET TOTAL # REQUESTED
JUMPN T2,ENQF3E ;CANT CHANGE POOLED REQUESTS
LOAD T2,ENQFLG,(T1) ;GET FLAGS OF REQUEST
TLNE P1,(EN%SHR) ;WANT IT TO BE SHARABLE
JRST [ TRZN T2,EN.EXC ;YES, SET IT SHARABLE
JRST ENQ2 ;ALREADY WAS SHARABLE
STOR T2,ENQFLG,(T1) ;STORE UPDATED FLAGS
MOVE T1,ENQLB ;GET LOCK BLOCK ADDRESS AGAIN
CALL LOKSKD ;SCHEDULE THIS LOCK
JRST ENQ2] ;LOOP BACK FOR ALL REQUESTS
TROE T2,EN.EXC ;SEE IF ALREADY EXCLUSIVE
JRST ENQ2 ;YES, THIS IS OK SINCE NOT CHANGING IT
LOAD T3,ENQLLQ,(T1) ;SEE IF THIS IS THE ONLY SHARER
LOAD T4,ENQNLQ,(T1) ;GET POINTER TO LAST AND NEXT Q-BLOCK
CAME T3,T4 ;IF EQUAL, THEN THIS IS THE ONLY SHARER
JRST ENQF3E ;NOT EQUAL, GIVE ERROR RETURN
STOR T2,ENQFLG,(T1) ;MAKE THIS BE AN EXCLUSIVE LOCK
JRST ENQ2 ;AND LOOP BACK FOR THE OTHERS
ENQF3E: MOVEI T1,ENQX8 ;FUNCTION 3 ERROR
ENQF3F: MOVEM T1,ENQERC ;REMEMBER THAT AN ERROR OCCURED
JRST ENQ2 ;GO DO AS MUCH AS POSSIBLE
;THE DEQ JSYS - DEQUEUE REQUESTS
;ACCEPTS IN 1/ FUNCTION
; 2/ LOCATION OF ARGUMENT BLOCK (FUNCTION 0 ONLY)
; DEQ
;RETURNS +1: UNSUCCESSFUL - ERROR CODE IN T1
; (AS MUCH AS POSSIBLE DEQUEUED)
; +2: SUCCESSFUL - REQUEST DEQUEUED
;THE ARGUMENT BLOCK IS IDENTICAL TO THAT OF ENQ
.DEQ:: MCENT ;ENTER JSYS
NOINT ;LOCK UP
LOKK ENQLKK ;...
CALL DEQREQ ;GO DO THE DEQUEUEING
JRST ENUNLE ;ERROR DURING DEQ, RETURN ERROR CODE
DEQOKR: CALL LGTAD ;GET TIME OF DAY
CAMLE T1,ENQLTS ;IS IT TIME TO DO A GARBAGE COLLECT?
JRST [ ADDI T1,^D<10*60*3> ;YES, SAVE TIME OF NEXT GC
EXCH T1,ENQLTS ;DO A GARBAGE COLLECT EVERY 10 MINUTES
CALL ENQGC
JRST .+1]
UNLOKK ENQLKK ;UNLOCK THE DATA BASE
OKINT
SMRETN ;GIVE SUCCESSFUL RETURN TO USER
;ROUTINE TO DO THE ACTUAL DEQUEUEING
DEQREQ: XCTU [HRRZ T2,1] ;GET THE FUNCTION CODE
CAIL T2,DQTABL ;IS THIS A LEGAL FUNCTION CODE?
RETBAD (ENQX1) ;NO, TELL USER
SETO T1, ;THIS IS A JSYS CALL
JRST @DEQTAB(T2) ;DISPATCH TO FUNCTION CODE
DEQTAB: IFIW!DEQFN0 ;NORMAL DEQ
IFIW!DEQFN1 ;DEQ ALL RESOURCES
IFIW!DEQFN2 ;DEQ THIS ID
DQTABL==.-DEQTAB
REPEAT 0,<
;INTERNAL MONITOR ROUTINE TO DO A DEQ (FUNCTION 0 ONLY)
;ACCEPTS IN T1/ 33-BIT NUMBER
;ASSUMES A -3 LOCK, LEVEL # OF 0, ONE LOCK, ID = 0, AND ALWAYS WAIT
; CALL DEQUE
;RETURNS +1: ALWAYS
DEQUE: NOINT ;LOCK UP THE DATA BASE
LOKK ENQLKK ;...
SAVEPQ ;SAVE THE PERMANENT ACS
CALL MONVAL ;SET UP THE ARGUMENTS IN Q1-Q3, P1-P4
CALL DEQFN0 ;DO THE DEQ
BUG(DEQMDF)
UNLOKK ENQLKK ;UNLOCK THE LOCKS
OKINT
RET ;AND RETURN TO CALLER
>
;DEQ FUNCTION 0
;ACCEPTS IN T1/ 0 = INTERNAL MONITOR CALL
; -1 = JSYS CALL (READ ARGUMENTS FROM USER SPACE)
DEQFN0: JSP T1,SETVAR ;SET UP GLOBAL VARIABLES
STKVAR <DQFN0T,DQFN0Q>
SETZM DQFN0T ;INITIALIZE ERROR COUNTER
JUMPE T1,DQFN0D ;IF MONITOR CALL, ARGS ARE SET UP
CALL VALARG ;VALIDATE THE ARGUMENT BLOCK
RET ;ILLEGAL ARGUMENT BLOCK
DQFN0A: CALL VALREQ ;VALIDATE THIS LOCK SPECIFICATION
JRST DQFN0B ;ERROR
DQFN0D: CALL HASH ;HASH THIS REQUEST
JRST DQFN0B ;ERROR DURING HASH
CALL FNDLOK ;FIND THE LOCK-BLOCK
JRST DQFN0B ;NO SUCH LOCK-BLOCK
LOAD T2,ENQFLG,(T1) ;GET FLAGS OF THE LOCK BLOCK
TXNE P1,EN%LTL ;IS THIS A LONG TERM LOCK
TXO T2,EN.LTL ;YES, REMEMBER THIS IN THE LOCK BLOCK
STOR T2,ENQFLG,(T1)
CALL FNDQ ;FIND THE Q-BLOCK FOR THIS FORK
JRST DQFN0B ;COULD NOT FIND THE Q-BLOCK
MOVEM T1,DQFN0Q ;SAVE THE Q-BLOCK ADDRESS
LOAD T2,ENQNST,(T1) ;GET NEST COUNT
JUMPG T2,[DECR ENQNST,(T1)
JRST DQFN0C] ;THIS WAS A NESTED ENQ, DONT DEQ IT
LOAD T2,ENQNR,(T1) ;GET NUMBER LOCKED IN ORIGINAL ENQ
JUMPE T2,[CALL DEQMSK ;IF 0, SEE IF DEQ'ING A MASK
JRST DQFN0E ;NOT COMPLETELY DEQUEUED
MOVE T1,DQFN0Q ;OK TO DELETE THIS Q-BLOCK
CALL SQDEQ ;GO DELETE THIS Q-BLOCK
JRST DQFN0C] ;STEP TO NEXT REQUEST
SUBI T2,0(P3) ;SEE IF DEQ'ING ALL RESOURCES
JUMPL T2,[MOVEI T1,ENQX12
JRST DQFN0B] ;DEQ'ING TOO MANY RESOURCES
JUMPE T2,[CALL SQDEQ ;DEQ'ING ALL OF THEM, DELETE Q-BLOCK
JRST DQFN0C]
STOR T2,ENQNR,(T1) ;PUT BACK NEW # OF RESOURCES LOCKED
LOAD T1,ENQLBP,(T1) ;GET ADDRESS OF LOCK BLOCK
LOAD T2,ENQRR,(T1) ;GET # OF REMAINING RESOURCES
ADDI T2,0(P3) ;UPDATE THE COUNT
STOR T2,ENQRR,(T1) ;STORE NEW COUNT OF REMAINING RESOURCES
DQFN0E: MOVE T1,DQFN0Q ;GET Q-BLOCK ADDRESS
LOAD T1,ENQLBP,(T1) ;GET ADDRESS OF THE LOCK BLOCK
CALL LOKSKD ;GO SCHEDULE THIS LOCK
JRST DQFN0C ;DONT COUNT UP ERROR COUNTER
DQFN0B: MOVEM T1,DQFN0T ;SAVE THIS ERROR CODE
DQFN0C: ADD Q1,EDSTP ;STEP TO THE NEXT LOCK REQUEST
JUMPG Q1,DQFN0A ;LOOP BACK FOR ALL LOCKS
SKIPG T1,DQFN0T ;ANY ERRORS SEEN?
RETSKP ;NO, DEQUEUING COMPLETED
RET ;YES, RETURN ERROR CODE IN T1
;ROUTINE TO SEE IF A REQUEST IS COMPLETELY DEQ'ED
;ACCEPTS IN T1/ Q-BLOCK ADDRESS
; CALL DEQMSK
;RETURNS +1: NOT COMPLETELY DEQUEUED
; +2: OK TO DELETE THIS Q-BLOCK
DEQMSK: STKVAR <DEQMSF>
SETZM DEQMSF ;INITIALIZE THE FLAG WORD
SKIPN T4,EDMSK ;IS THERE A MASK SPECIFIED?
RETSKP ;NO, THEN DEQ THE WHOLE THING
LOAD T3,ENQMSK,(T1) ;GET THE POINTER TO THE MASK BLOCK
JUMPE T3,RSKP ;IF NONE, THEN DEQ THE WHOLE THING
LOAD T2,ENQLBP,(T1) ;GET LOCK BLOCK ADDRESS
LOAD T2,ENQNMS,(T2) ;GET LENGTH OF MASK BLOCK
CAMLE T2,EDNMS ;DO THE LENGTHS MATCH?
SETOM DEQMSF ;NO, MARK THIS AS NOT COMPLETELY DEQ'D
CAMLE T2,EDNMS ;GET THE LESSER OF THE TWO LENGTHS
MOVE T2,EDNMS ;...
DEQMS1: MOVE T1,0(T3) ;GET FIRST WORD OF MASK BLOCK
XCTU [ANDCM T1,0(T4)] ;TURN OFF THE BITS BEING DEQUEUED
MOVEM T1,0(T3) ;UPDATE THE MASK IN THE Q-BLOCK
SKIPE T1 ;ANY RESOURCES LEFT ON?
SETOM DEQMSF ;YES, MARK THAT THE LOCK IS STILL LOCKED
AOS T3 ;STEP THE MASK POINTER
AOS T4 ;STEP THE USER MASK POINTER
SOJG T2,DEQMS1 ;LOOP BACK THROUGH THE WHOLE MASK BLOCK
SKIPE DEQMSF ;ANY PART OF THE LOCK STILL LOCKED?
RET ;YES
RETSKP ;NO, GO DELETE IT
;DEQ FUNCTION 1
DEQFN1: HRRZ T1,FORKX ;GET SYSTEM FORK HANDLE
SETO T2, ;DEQ ALL
CALL DEQFRK ;DELETE ALL REQUESTS FOR THIS FORK
JUMPG T1,RSKP ;WERE ANY RELEASED?
RETBAD (ENQX7) ;NO, THIS IS AN ERROR
;DEQ FUNCTION 2 - DEQ AN ID
DEQFN2: HRRZ T1,FORKX ;FOR THIS FORK ONLY
XCTU [HRRZ T2,2] ;GET THE ID
CALL DEQFRK ;DEQ THIS ID ONLY
JUMPG T1,RSKP ;WERE ANY RELEASED?
RETBAD (ENQX7) ;NO, THIS IS AN ERROR
;THE ENQC JSYS - ENQ CONTROL
;USED TO GET STATUS OF LOCKS AND GET AND SET QUOTA
;ACCEPTS IN T1/ FUNCTION CODE - 0, 1, OR 2
; T2/ LOCATION OF ARGUMENT BLOCK
; T3/ ADDRESS OF STATUS BLOCK (FUNCTION 0 ONLY)
; ENQC
;RETURNS +1: ERROR - CODE IN T1
; +2: SUCCESSFUL
;ARGUMENT BLOCK FOR FUNCTION 0 IS SAME AS FOR ENQ
; FUNCTION 1 AND 2 ARGUMENT BLOCK IS: QUOTA ,, JOB NUMBER
.ENQC:: MCENT ;ENTER JSYS
XCTU [HRRZ T1,1] ;GET FUNCTION CODE
CAIN T1,.ENQCD ;DOING A DUMP?
JRST ENQCD ;YES, GO DUMP
JUMPN T1,ENQC1 ;ALL EXCEPT FUNCTION 0 GO TO ENQC1
NOINT ;LOCK UP
LOKK ENQLKK ;...
CALL ENQCF0 ;DO FUNCTION 0
JRST ENUNLE ;ERROR, GO UNLOCK AND RETURN THE CODE
JRST DEQOKR ;SUCCESSFUL
;ENQC FUNCTION 0
ENQCF0: JSP T1,SETVAR ;SET UP THE GLOBAL VARIABLES
STKVAR <ENCF0L,ENCF0T,ENCF0S,ENCF0I>
SETZM ENCF0L ;INITIALIZE LOCK BLOCK ADR
SETZM ENCF0T ;INITIALIZE ERROR CODE REGISTER
UMOVE T1,3 ;GET ADDRESS OF STATUS BLOCK
MOVEM T1,EDSTB ;SAVE THE ADR OF THE STATUS BLOCK
CALL VALARG ;VALIDATE THE ARGUMENT BLOCK
RET ;ERROR IN FORMAT
ENCF0A: SETZM ENCF0S ;INITIALIZE TIME STAMP REGISTER
SETZM ENCF0I ;..AND REQUEST ID REGISTER
CALL VALREQ ;GET INFO ABOUT THE NEXT LOCK REQUEST
JRST ENCF0E ;ERROR ON THIS SPECIFICATION
CALL HASH ;HASH IT
JRST ENCF0E ;ERROR
CALL FNDLOK ;FIND THE LOCK
JRST ENCF0F ;NOT DEFINED, IT MUST BE AVAILABLE
MOVEM T1,ENCF0L ;REMEMBER THE LOCK ADDRESS
CALL FNDQ ;FIND OUR REQUEST IF THERE IS ONE
TDZA T2,T2 ;NOT IN Q, ZERO FLAG REGISTER
MOVX T2,EN%QCQ ;WE ARE IN THE QUEUE
JUMPE T2,ENCF0B ;IN THE QUEUE?
LOAD T3,ENQID,(T1) ;YES, GET REQUEST ID OF US
MOVEM T3,ENCF0I ;SAVE IT FOR LATER
ENCF0B: HRRI T2,-1 ;ASSUME NOBODY HAS IT LOCKED
MOVE T1,ENCF0L ;GET ADDRESS OF LOCK AGAIN
LOAD T3,ENQTS,(T1) ;GET TIME STAMP OF LOCK
MOVEM T3,ENCF0S ;SAVE IT
LOAD T3,ENQLVL,(T1) ;GET LEVEL NUMBER
DPB T3,[POINT LVLLEN,T2,17]
ENCF0G: LOAD T1,ENQNLQ,(T1) ;SCAN THE LIST LOOKING FOR US
LOAD T3,ENQFLG,(T1) ;GET FLAGS
TRNE T3,EN.LB ;BACK TO THE LOCK BLOCK?
JRST ENCF0D ;YES, NOT FOUND
LOAD T4,ENQFRK,(T1) ;GET FORK NUMBER OF OWNER
CAME T4,FORKX ;US?
JRST ENCF0G ;NO, LOOP BACK THRU LIST
JRST ENCF0H ;YES
ENCF0D: MOVE T1,ENCF0L ;GET LOCK BLOCK ADR AGAIN
LOAD T1,ENQNLQ,(T1) ;GET FIRST Q ON LIST
LOAD T3,ENQFLG,(T1) ;GET FLAGS OF Q ENTRY
TRNN T3,EN.LB ;IS THIS THE LOCK BLOCK?
TRNE T3,EN.INV ;NO, IS THIS INVISIBLE?
JRST ENCF0C ;YES, NOBODY OWNS LOCK
LOAD T4,ENQFRK,(T1) ;GET FORK NUMBER OF THIS Q-BLOCK
TRNE T3,EN.LOK ;IS IT LOCKED?
CAME T4,FORKX ;AND DOES THIS BELONG TO OUR FORK?
SKIPA ;NO, DONT SET LOCKED BIT
ENCF0H: TLO T2,(EN%QCO) ;YES, MARK THAT WE OWN IT
TRNE T3,EN.EXC ;IS THIS AN EXCLUSIVE REQUEST?
TLO T2,(EN%QCX) ;YES, SET THE EXCLUSIVE BIT
LOAD T3,ENQFRK,(T1) ;GET THE OWNER OF THIS Q-BLOCK
HLR T2,FKJOB(T3) ;PUT JOB NUMBER IN RIGHT HALF WORD
LOAD T3,ENQID,(T1) ;GET REQUEST ID
SKIPN ENCF0I ;IF IT'S NOT ALREADY SET...
MOVEM T3,ENCF0I ;..DO SO
ENCF0C: MOVE T3,EDSTB ;GET ADR OF TEH STATUS BLOCK
UMOVEM T2,0(T3) ;STORE ANSWER IN STATUS BLOCK
MOVE T2,ENCF0S ;GET TIME STAMP OF LOCK
UMOVEM T2,1(T3) ;GIVE IT TO THE USER
SKIPE T1,ENCF0L ;GET ADR OF LOCK BLOCK
CALL CNTQ ;COUNT THE NUMBER OF SHARERS
MOVE T3,EDSTB ;GET BACK THE ADR OF THE STATUS BLOCK
MOVE T2,ENCF0I ;GET REQUEST ID
HRL T2,T1 ;PUT THE COUNT OF SHARERS IN LH
UMOVEM T2,2(T3) ;STORE IN STATUS BLOCK
HRRI T3,3(T3) ;INCREMENT POINTER TO STATUS BLOCK
MOVEM T3,EDSTB ;SAVE THE UPDATED ADR OF THE STATUS BLOCK
ADD Q1,EDSTP ;STEP TO NEXT LOCK REQUEST
JUMPG Q1,ENCF0A ;LOOP BACK IF ANY MORE LOCKS TO CHECK
SKIPN T1,ENCF0T ;DID ANY ERRORS OCCUR DURING TESTING?
RETSKP ;NO, GIVE OK RETURN
RET ;YES, GIVE ERROR RETURN
ENCF0E: HRLI T1,(EN%QCE) ;SET ERROR BIT IN LH OF WORD
MOVE T2,T1 ;SET UP TO STORE ERROR CODE IN LIST
HRRZM T1,ENCF0T ;STORE ERROR CODE FOR ERROR RETURN
JRST ENCF0C ;GO STORE CODE IN STATUS BLOCK
ENCF0F: MOVEI T2,-1 ;MARK THAT THE LOCK IS FREE
JRST ENCF0C ;GO STORE ANSWER IN STATUS BLOCK
;ENQC FUNCTIONS 1 AND 2
ENQC1: UMOVE P1,2 ;GET POINTER TO ARG BLOCK
MOVE P2,T1 ;SAVE FUNCTION CODE
CAILE P2,ENQCMF ;LEGAL FUNCTION CODE?
RETERR (ENQX1) ;NO, GIVE ERROR RETURN
CAIN P2,.ENQCC ;SETTING QUOTA?
JRST [ CALL CHKWHL ;YES, MUST BE A WHEEL
JRST ENQGOK ;NOT PRIVILEGED ASK PERMISSION
JRST .+1]
ENQOK: XCTU [HRRZ T1,0(P1)] ;GET JOB NUMBER
CAIN T1,-1 ;USER WANT SELF?
HRRZ T1,JOBNO ;YES, GET OUR JOB NUMBER
CAIGE T1,NJOBS ;WITHIN BOUNDS?
SKIPGE JOBRT(T1) ;IS JOB LOGGED IN?
RETERR (ENQX21) ;NO, ILLEGAL JOB#
;DONT ALLOW INTERRUPTS WITH JSB MAPPED
CALL SETJSB ;MAP IN THIS JSB
XCTU [HLRZ T2,0(P1)] ;GET NEW QUOTA
CAIN P2,.ENQCC ;SETTING QUOTA?
STOR T2,ENQOTA,(T1) ;YES, SET IT
LOAD T3,ENQOTA,(T1) ;GET CURRENT QUOTA
CAIN P2,.ENQCG ;USER WANTS QUOTA?
UMOVEM T3,1 ;YES, GIVE IT TO HIM
CALL CLRJSB ;UNMAP JSB AND ENABLE INTERRUPTS
SMRETN ;GIVE OK RETURN
ENQGOK: XCTU [HLRZ T2,0(P1)] ;GET QUOTA
XCTU [HRRE T1,0(P1)] ;GET JOB NUMBER
GTOKM (.GOENQ,<T2,T1>,[RETERR ()])
JRST ENQOK
;ENQC FUNCTION 3 - DUMP THE LOCKS AND QUEUES
ENQCD: CALL CHKWHL ;MUST BE A WHEEL TO DO THIS FUNCTION
RETERR ;NOT PRIVILEGED!
NOINT ;LOCK THE LOCKS
LOKK ENQLKK ;...
MOVSI Q1,-HSHLEN ;SET UP COUNTER FOR MAIN LOOP
HRRI Q1,HSHTBL
UMOVE P1,2 ;GET POINTER TO DATA BLOCK
XCTU [MOVN T1,0(P1)] ;GET NEGATIVE LENGTH
HRL P1,T1 ;SET UP AOBJP WORD
ENQCD1: HRRZ Q2,0(Q1) ;GET POINTER TO LOCK BLOCK IF ANY
ENQCD2: CAIN Q2,0(Q1) ;BACK TO HASH TABLE?
JRST ENQCD3 ;YES, GO STEP TO NEXT HASH ENTRY
MOVE T1,Q2 ;GET ADDRESS OF LOCK BLOCK
CALL ENQDMP ;GO DUMP LOCK AND QUEUE BLOCKS
JRST ENQCD4 ;ALL DONE
LOAD Q2,ENQNHC,(Q2) ;STEP TO NEXT LOCK BLOCK ON HASH CHAIN
JRST ENQCD2 ;LOOP BACK FOR ALL LOCKS
ENQCD3: AOBJN Q1,ENQCD1 ;LOOP BACK FOR ALL HASH ENTRIES
AOBJP P1,ENQCD4 ;STEP THE USER'S DATA POINTER
XCTU [SETOM 0(P1)] ;MARK THE END OF THE DUMP
ENQCD4: UNLOKK ENQLKK ;UNLOCK THE ENQ DATA BASE
OKINT
SMRETN ;AND GIVE OK RETURN
;ROUTINE TO DUMP THE ENQ DATA BASE
;ACCEPTS IN T1/ ADDRESS OF A LOCK BLOCK
; P1/ ADDRESS IN USER SPACE OF BLOCK TO RECEIVE DATA
; CALL ENQDMP
;RETURNS +1: RAN OUT OF SPACE IN USER BUFFER
; +2: OK RETURN
ENQDMP: LOAD T2,ENQOFN,(T1) ;GET OFN OR -2, -3, OR 400000+JOB
LOAD T3,ENQFLG,(T1) ;GET LOCK BLOCK FLAGS
LOAD T4,ENQLVL,(T1) ;GET LEVEL NUMBER OF THIS LOCK
HRL T2,T4 ;SET UP ANSWER IN T2
TLO T2,(EN%QCL) ;MARK THAT THIS IS A LOCK BLOCK
TRNE T3,EN.TXT ;STRING POINTER?
TLO T2,(EN%QCT) ;YES, MARK THAT IN ANSWER
AOBJP P1,R ;ENOUGH ROOM LEFT?
UMOVEM T2,0(P1) ;YES, STORE ANSWER IN DATA BLOCK
LOAD T2,ENQTR,(T1) ;GET # IN POOL
LOAD T4,ENQRR,(T1) ;GET # REMAINING
HRL T4,T2 ;SET UP ANSWER
AOBJP P1,R ;IS THERE MORE ROOM?
UMOVEM T4,0(P1) ;YES, STORE DATA IN BUFFER
LOAD T2,ENQTS,(T1) ;GET TIME STAMP OF LOCK
AOBJP P1,R ;UPDATE POINTER TO USER AREA
UMOVEM T2,0(P1) ;GIVE TIME STAMP TO USER
LOAD T2,ENQLEN,(T1) ;GET LENGTH OF BLOCK
SUBI T2,LBLEN ;GET LENGTH OF DATA OR TEXT AREA
MOVE T3,T1 ;GET COPY OF LOCK BLOCK ADDRESS
ENQDM1: LOAD T4,ENQTXT,(T3) ;GET NEXT WORD OF STRING
AOBJP P1,R ;STEP TO NEXT WORD
UMOVEM T4,0(P1) ;GIVE TEXT WORD TO USER
AOS T3 ;STEP TO NEXT WORD OF TEXT
SOJG T2,ENQDM1 ;ANY MORE TO GET?
MOVE T2,T1 ;NO, NOW GET Q-BLOCK INFO
ENQDM2: LOAD T2,ENQNLQ,(T2) ;GET ADDRESS OF NEXT Q-BLOCK
CAMN T2,T1 ;BACK TO LOCK BLOCK?
RETSKP ;YES, ALL FINISHED
LOAD T3,ENQFRK,(T2) ;GET FORK NUMBER OF OWNER
HLRZ T3,FKJOB(T3) ;GET JOB NUMBER OF CREATOR OF ENTRY
LOAD T4,ENQCHN,(T2) ;GET PSI CHANNEL #
HRL T3,T4 ;SET UP ANSWER
CAIN T4,.ENWCH ;THIS FORK WAITING?
TLC T3,.ENWCH+<EN%QCB>_-^D18 ;YES, SET BLOCKED BIT
LOAD T4,ENQFLG,(T2) ;GET FLAGS OF ENTRY
TRNE T4,EN.LOK ;IS THIS LOCKED?
TLO T3,(EN%QCO) ;YES, SET THE OWNER BIT
TRNE T4,EN.LOK ;LOCKED?
TLZ T3,(EN%QCB) ;YES, MAKE SURE BLOCKED BIT IS OFF
TRNE T4,EN.EXC ;EXCLUSIVE LOCK
TLO T3,(EN%QCX) ;YES
AOBJP P1,R ;ENOUGH ROOM?
UMOVEM T3,0(P1) ;YES, GIVE IT TO USER
LOAD T3,ENQID,(T2) ;GET ID NUMBER
LOAD T4,ENQNR,(T2) ;GET NUMBER REQUESTED IF POOLED
SKIPN T4 ;IS THIS A NON-POOLED LOCK?
LOAD T4,ENQGRP,(T2) ;YES, GET GROUP NUMBER INSTEAD
HRL T3,T4 ;CONSTRUCT ANSWER
AOBJP P1,R ;STEP POINTER TO DATA BLOCK
UMOVEM T3,0(P1) ;STORE IN USER BLOCK
JRST ENQDM2 ;LOOP BACK FOR OTHER Q ENTRIES
;ROUTINE TO VALIDATE THE ARGUMENT BLOCK FROM THE USER
;THIS ROUTINE LOADS Q1 - Q3 WITH THE FOLLOWING VALUES:
; Q1/ # OF LOCKS-1 ,, ADDRESS OF FIRST LOCK REQUEST
; Q2/ ID ,, PSI CHANNEL #
; Q3/ MINIMUM MONITOR LEVEL ,, MINIMUM USER LOCK LEVEL
; EDSTP/ -1 ,, LENGTH OF LOCK REQUEST BLOCK
VALARG: UMOVE Q1,2 ;GET LOCATION OF ARGUMENT BLOCK
HRRZS Q1 ;MUST CONTAIN USER SECTION WHEN SEC NON ZERO***
UMOVE T1,0(Q1) ;GET THE HEADER WORD
HRRZ T4,T1 ;GET LENGTH OF ARG BLOCK INTO T4
LOAD T3,.ENNLK,T1 ;GET NUMBER OF LOCKS INTO T3
JUMPE T3,[RETBAD (ENQX9)] ;0 LOCKS IS NOT ALLOWED
HRLI Q1,-1(T3) ;SAVE NUMBER OF LOCKS-1
LOAD T2,.ENHLN,T1 ;GET THE LENGTH OF HEADER AREA
HRRZ T1,Q1 ;GET ADDRESS OF ARG BLOCK
CAIGE T2,.ENQHL ;IS IT AN OLD STYLE HEADER?
MOVEI T2,.ENQHL ;YES, SET UP THE LENGTH MANUALLY
ADD Q1,T2 ;MAKE Q1 POINT TO START OF LOCK BLOCK
SUBM T4,T2 ;GET LENGTH OF LOCK AREA INTO T2
IDIV T2,T3 ;GET SIZE OF EACH LOCK BLOCK
SKIPE T3 ;MUST BE NO REMAINDER TO BE VALID
RETBAD (ENQX10) ;ILLEGALLY FORMATTED ARGUMENT BLOCK
HRROM T2,EDSTP ;SET UP THE STEP VARIABLE
XCTU [MOVS Q2,1(T1)] ;GET ID ,, CHANNEL #
HRRZ T1,Q2 ;VALIDATE PSI CHANNEL NUMBER
CAILE T1,^D35 ;IS IT A LEGAL CHANNEL #
RETBAD (ENQX11) ;NO, GIVE ERROR RETURN
CALL GETLVL ;GET THE MINIMUM ALLOWABLE LEVEL
MOVE Q3,T1 ;SAVE IN Q3
RETSKP ;GIVE OK RETURN
;ROUTINE TO VALIDATE A LOCK REQUEST
;THIS ROUTINE ASSUMES Q1 - Q3 SET UP BY VALARG
;THIS ROUTINE SETS UP P1 - P3 WITH THE FOLLOWING INFORMATION:
; P1/ FLAGS & LEVEL NUMBER ,, OFN
; P2/ STRING POINTER OR 500000,,0 + USER CODE
; P3/ # OF RESOURCES ,, # REQUESTED
; P4 GETS SET UP WITH WORD LENGTH OF STRING BY HASH
; P5/ JFN OF REQUEST ,, GROUP #
; EDNMS/ NUMBER OF WORDS IN MASK BLOCK MINUS THE COUNT WORD
; EDMSK/ ADR OF FIRST MASK WORD IN USERS MASK BLOCK
VALREQ: HRRZ P3,Q1 ;REMOVE HIGH BITS
SETZM EDMSK ;INITIALIZE GLOBAL VARIABLES
SETZM EDNMS
HRRZ T1,EDSTP ;GET SIZE OF LOCK REQUEST BLOCK
CAIGE T1,4 ;LONG ENOUGH TO CONTAIN A MASK BLOCK?
JRST VALRQ2 ;NO
UMOVE T1,3(P3) ;YES, GET ADR OF MASK BLOCK
JUMPE T1,VALRQ2 ;IS THERE ONE?
UMOVE T2,0(T1) ;YES, GET ITS LENGTH
SUBI T2,1 ;DONT COUNT THE COUNT WORD
SKIPLE T2 ;IS IT A LEGAL LENGTH
CAILE T2,<^D512+^D35>/^D36
RETBAD (ENQX22) ;ILLEGAL MASK BLOCK LENGTH
MOVEM T1,EDMSK ;SAVE THE MASK BLOCK ADDRESS
MOVEM T2,EDNMS ;NUMBER OF WORDS IN MASK BLOCK
AOS EDMSK ;STEP MASK BLOCK ADR OVER COUNT WORD
VALRQ2: UMOVE P3,2(P3) ;GET # OF RESOURCES
HRR P5,P3 ;GET GROUP NUMBER IN P5
TLNN P3,-1 ;IS THIS A POOLED REQUEST
JRST [ SETZ P3, ;NO, ZERO P3
JRST VALRQ0]
HLLZS P5 ;YES, MAKE GROUP # BE 0
TRNN P3,-1 ;YES, MUST REQUEST AT LEAST 1
RETBAD (ENQX12) ;ERROR IF 0
HLRZ T1,P3 ;GET TOTAL # IN POOL
CAIGE T1,0(P3) ;CAN THIS REQUEST BE MET?
RETBAD (ENQX12) ;NO, GIVE ERROR RETURN
VALRQ0: HRRZ P2,Q1 ;GET ADDRESS ONLY
UMOVE P2,1(P2) ;GET STRING POINTER
TLC P2,-1 ;SEE IF -1 IN LH
TLCN P2,-1 ;...
HRLI P2,(POINT 7,0) ;YES, SET UP ASCII POINTER
LDB T2,[POINT 3,P2,2] ;GET HIGH ORDER 3 BITS
CAIN T2,5 ;IS THIS A USER CODE?
JRST VALRQ1 ;YES
TLZE P2,37 ;NO, INDIRECT OR INDEXED POINTER?
RETBAD (ENQX13) ;YES, THIS IS NOT ALLOWED
MOVE T1,P2 ;GET THE POINTER FOR A CALL
CALL PTRCHK ;SEE IF THIS IS AN ILLEGAL OWGBP
RETBAD(ENQX14) ;YES...INVALID BYTE SIZE ERROR
VALRQ1: HRRZ P1,Q1 ;GET ADDRESS ONLY
UMOVE P1,0(P1) ;GET FLAGS, LEVEL #, AND JFN
HRL P5,P1 ;SAVE JFN OF REQUEST
HRRZ T1,P1 ;GET JFN AGAIN
CAIN T1,-1 ;JOB WIDE LOCK?
JRST [ HRR P1,JOBNO ;YES, GET JOB NUMBER
TRO P1,400000 ;MAKE IT 400000 + JOB NUMBER
RETSKP] ;ALL THROUGH
CAIN T1,-2 ;GLOBAL LOCK?
JRST [ CALLRET CHKENP] ;YES, CHECK IF PRIVILEGED
CAIN T1,-3 ;SYSTEM LOCK?
JRST [ CALLRET CHKWHL] ;YES, CHECK WHEEL PRIVILEGE
CALL CHKENJ ;CHECK IF THIS IS A LEGAL JFN
RET ;NO, GIVE ERROR RETURN
HRR P1,T1 ;SAVE OFN
RETSKP ;GIVE OK RETURN
;ROUTINE TO CHECK IF ENQ PRIVILEGE IS SET
; CALL CHKENP
;RETURNS +1: PRIVILEGE NOT SET - ERROR CODE IN T1
; +2: PRIVELEGE SET
CHKENP: MOVE T1,CAPENB ;GET ENABLED PRIVILEGES
TRNN T1,SC%WHL!SC%OPR!SC%ENQ
RETBAD (ENQX15) ;NOT PRIVILEGED
RETSKP ;HAS ENOUGH PRIVILEGES
;ROUTINE TO CHECK IF THE USER IS A WHEEL OR OPERATOR
CHKWHL: MOVE T1,CAPENB ;GET CAPABILITIES
TRNN T1,SC%WHL!SC%OPR ;WHEEL OR OPERATOR
RETBAD (ENQX16) ;NO
RETSKP ;YES
;ROUTINE TO CHECK A JFN FOR LEGALITY AND GET THE OFN
;ACCEPTS IN T1/ JFN
; CALL CHKENJ
;RETURNS +1: NOT A LEGAL JFN FOR LOCKING ON
; +2: JFN LEGAL - OFN IN T1
CHKENJ: HRLZS T1 ;LH = JFN ,, RH = PAGE # 0
CALL JFNOFN ;GET OFN,,PAGE # FOR PAGE 0 OF THIS JFN
JRST [ SKIPGE T1 ;SEE IF THERE IS AN ERROR CODE IN T1
MOVEI T1,ENQX17 ;NO, ILLEGAL JFN
RET] ;GIVE ERROR RETURN
HLRZS T1 ;GET OFN IN RH
RETSKP ;GIVE OK RETURN
;ROUTINE TO FIND A LOCK-BLOCK
;ACCEPTS IN T1/ HASH INDEX
; P1-P4/ AS SET UP BY VALREQ
; CALL FNDLOK
;RETURNS +1: NOT FOUND
; +2: LOCK-BLOCK FOUND, ADDRESS IN T1
FNDLOK: STKVAR <FNDLKI,FNDLKO,FNDLKP,FNDLKL>
MOVEI T1,HSHTBL(T1) ;GET ADDRESS OF HASH CHAIN
MOVEM T1,FNDLKI ;SAVE THE HASH CHAIN ADDRESS
FNDLK1: LOAD T1,ENQNHC,(T1) ;GET NEXT LOCK-BLOCK ON CHAIN
CAMN T1,FNDLKI ;HAVE WE EXHAUSTED LIST?
RETBAD (ENQX7) ;YES, LOCK BLOCK WAS NOT FOUND
MOVEM T1,FNDLKL ;REMEMBER THIS LOCK-BLOCK ADDRESS
LOAD T2,ENQOFN,(T1) ;GET OFN NUMBER
CAIE T2,(P1) ;IS THIS A MATCH
JRST FNDLK2 ;NO, TRY NEXT ENTRY
MOVE T2,P2 ;GET STRING POINTER
CALL STRCMP ;COMPARE STRINGS
JRST FNDLK2 ;NO MATCH
MOVE T1,FNDLKL ;GET BACK LOCK-BLOCK ADDRESS
RETSKP ;LOCK-BLOCK WAS FOUND
FNDLK2: MOVE T1,FNDLKL ;GET LOCK-BLOCK ADDRESS
JRST FNDLK1 ;LOOP BACK TILL LIST SCANNED
;ROUTINE TO FIND A Q-BLOCK
;ACCEPTS IN T1/ LOCK-BLOCK ADDRESS
; CALL FNDQ
;RETURNS +1: NO Q-BLOCK UNDER THIS LOCK
; +2: Q-BLOCK FOUND, Q-BLOCK ADDRESS IN T1
FNDQ: LOAD T2,ENQNLQ,(T1) ;GET ADDRESS OF FIRST Q-BLOCK
EXCH T1,T2 ;GET Q-BLOCK ADR INTO T1 FOR RETURN
FNDQ1: CAIN T2,0(T1) ;HAVE WE ARRIVED BACK AT LOCK-BLOCK?
RETBAD (ENQX7) ;YES, GIVE UNSUCCESSFUL RETURN
LOAD T3,ENQGRP,(T1) ;GET GROUP # OF BLOCK
CAIE T3,0(P5) ;MATCH?
JRST FNDQ2 ;NO, KEEP LOOKING
LOAD T3,ENQFRK,(T1) ;GET OWNER OF BLOCK
CAME T3,FORKX ;IS THIS OUR Q-BLOCK?
JRST FNDQ2 ;NO, KEEP LOOKING
LOAD T3,ENQJFN,(T1) ;GET JFN FROM Q-BLOCK
HLRZ T4,P5 ;AND JFN FOR NEW REQUEST
CAMN T4,T3 ;DO THE JFNS MATCH?
RETSKP ;YES, RETURN WITH ADR IN T1
FNDQ2: LOAD T1,ENQNLQ,(T1) ;STEP TO NEXT Q-BLOCK
JRST FNDQ1 ;LOOP BACK FOR ALL Q-BLOCKS
;ROUTINE TO GET THE HIGHEST LOCKED LEVEL #
; CALL GETLVL
;RETURNS +1: ALWAYS
; T1/ LH = MONITOR LEVEL #, RH = USER LEVEL #
GETLVL: STKVAR <GETLVU,GETLVM>
SETOM GETLVU ;INITIALIZE USER LEVEL TO -1
SETOM GETLVM ;SAME FOR MONITOR LEVEL #
HRRZ T1,ENQLST ;GET FIRST Q-BLOCK OF JOB
GETLV1: JUMPE T1,GETLV3 ;IF 0, END OF JOB LIST
LOAD T2,ENQFRK,(T1) ;GET FORK # OF OWNER
CAME T2,FORKX ;IS THIS OUR FORK?
JRST GETLV2 ;NO, IGNORE IT
LOAD T2,ENQLBP,(T1) ;GET ADDRESS OF LOCK BLOCK
LOAD T3,ENQLVL,(T2) ;GET LEVEL NUMBER OF THIS LOCK
LOAD T4,ENQOFN,(T2) ;GET OFN OF LOCK
CAIN T4,-3 ;IS THIS A MONITOR LOCK?
JRST [ CAMLE T3,GETLVM ;YES, IS THIS A NEW HIGH MONITOR LEVEL?
MOVEM T3,GETLVM ;YES, STORE THIS NEW LEVEL NUMBER
JRST GETLV2] ;GO CHECK OTHER LEVELS
CAMLE T3,GETLVU ;NO, IS THIS A NEW HIGH USER LEVEL?
MOVEM T3,GETLVU ;YES, REMEMBER IT
GETLV2: LOAD T1,ENQNJQ,(T1) ;STEP TO NEXT ENTRY IN JOB LIST
JRST GETLV1 ;LOOP BACK FOR ALL Q-BLOCKS
GETLV3: HRL T1,GETLVM ;SET UP ANSWER
HRR T1,GETLVU ;...
RET ;AND RETURN
;ROUTINE TO COUNT UP THE NUMBER OF SHARERS OF A LOCK
;ACCEPTS IN T1/ LOCK BLOCK ADDRESS
; CALL CNTQ
;RETRUNS +1: ALWAYS - COUNT OF SHARERS IN T1
CNTQ: SETZ T4, ;INITIALIZE THE COUNT
MOVE T2,T1 ;SAVE ADR OF LOCK BLOCK
CNTQL: LOAD T2,ENQNLQ,(T2) ;STEP TO THE NEXT QUEUE BLOCK
CAIN T2,0(T1) ;BACK TO THE LOCK BLOCK YET?
JRST [ MOVE T1,T4 ;YES, GET THE COUNT INTO T1
RET] ;AND RETURN
LOAD T3,ENQFLG,(T2) ;GET THE FLAGS OF THIS BLOCK
TXNE T3,EN.LOK ;IS THE LOCK LOCKED?
AOS T4 ;YES, COUNT UP THE COUNT
JRST CNTQL ;LOOP BACK TILL BACK TO LOCK BLOCK
;ROUTINE TO COMPARE STRINGS OR USER CODES
;ACCEPTS IN T1/ LOCK BLOCK ADDRESS
; T2/ STRING POINTER OR USER CODE
; CALL STRCMP
;RETURNS +1: NO MATCH
; +2: MATCH
STRCMP: STKVAR <STRCPP>
LOAD T3,ENQFLG,(T1) ;GET FLAGS OF LOCK-BLOCK
TRNN T3,EN.TXT ;TEXT OR USER CODE?
JRST STRCMC ;USER CODE
LOAD T3,NMFLG,T2 ;GET BITS 0-2 TO SEE IF USER SPECIFIED CODE
CAIN T3,NUMVAL ; 5B2 CANNOT BE A STRING POINTER
RET ; SO RETURN NO MATCH ON TYPE MISMATCH
MOVE T3,T2 ;BUILD THE STRING POINTER
AND T3,[007700,,0] ;GET THE BYTE SIZE OF THE OTHER STRING
TDO T3,[POINT 0,.ENTXT(T1)] ;SET UP THE REST OF THE BYTE POINTER
MOVEM T3,STRCPP ;SAVE BYTE POINTER INTO LOCK-BLOCK
STRCM0: XCTBU [ILDB T3,T2] ;GET USER'S BYTE
ILDB T4,STRCPP ;GET LOCK'S BYTE
CAME T3,T4 ;A MATCH?
RET ;NO, RETURN
JUMPN T3,STRCM0 ;IF NOT 0, LOOP BACK
RETSKP ;STRING MATCHED
STRCMC: LOAD T3,ENQTXT,(T1) ;GET USER CODE
CAME T2,T3 ;IS THIS A MATCH?
RET ;NO
RETSKP ;YES
;ROUTINE TO CREATE A LOCK-BLOCK
;ACCEPTS IN T1/ HASH INDEX
; P1-P4/ AS SET UP BY VALREQ
; CALL CRELOK
;RETURNS +1: COULD NOT CREATE LOCK-BLOCK
; +2: SUCCESSFUL - LOCK-BLOCK ADDRESS IN T1
CRELOK: STKVAR <CRELKH,CRELKL>
MOVEM T1,CRELKH ;SAVE THE HASH INDEX
SKIPN T1,P4 ;STRING OR CODE?
MOVEI T1,1 ;USER CODE NEEDS ONLY ONE WORD
ADDI T1,LBLEN ;ADD IN LOCK-BLOCK LENGTH
MOVEM T1,CRELKL ;REMEMBER THE LOCK-BLOCK LENGTH
CALL ASGENQ ;GET FREE BLOCK FOR LOCK
RET ;NO SPACE LEFT
MOVE T2,CRELKH ;PUT BLOCK ON HASH LIST
MOVEI T2,HSHTBL(T2) ;GET ACTUAL ADR OF ENTRY
STOR T2,ENQLHC,(T1) ;POINT BACK TO HASH TABLE ENTRY
HRRZ T3,0(T2) ;GET HASH TABLE FORWARD POINTER
HRRM T1,0(T2) ;MAKE US BE FIRST ON LIST
STOR T3,ENQNHC,(T1) ;MAKE NEW LOCK POINT TO NEXT LOCK
STOR T1,ENQLHC,(T3) ;MAKE SECOND ENTRY POINT BACK TO US
STOR T1,ENQLLQ,(T1) ;THIS IS AN EMPTY LOCK
STOR T1,ENQNLQ,(T1) ;IT POINTS TO ITSELF
LDB T2,[POINT 9,P1,17] ;GET THE LEVEL NUMBER
STOR T2,ENQLVL,(T1) ;REMEMBER THE LEVEL # OF THIS LOCK
HLRZ T2,P3 ;GET # OF RESOURCES
STOR T2,ENQRR,(T1) ;SET UP REMAINING RESOURCES
STOR T2,ENQTR,(T1) ;AND TOTAL RESOURCES
STOR P1,ENQOFN,(T1) ;SAVE OFN CODE
MOVE T2,CRELKL ;GET LOCK-BLOCK LENGTH
STOR T2,ENQLEN,(T1) ;SAVE LENGTH FOR RETURNING LOCK-BLOCK
MOVEI T3,-1 ;MARK THAT THIS LOCK IS NOT ON LTL LIST
STOR T3,ENQLT,(T1) ;THIS CAUSES IT TO BE PUT ON LIST LATER
MOVEI T2,EN.LB ;GET FLAGS
LDB T3,[POINT 3,P2,2] ;GET HIGH ORDER 3 BITS
CAIE T3,5 ;A USER CODE?
TRO T2,EN.TXT ;NO, SET TEXT FLAG
TXNE P1,EN%LTL ;LONG TERM LOCK?
TXO T2,EN.LTL ;YES, REMEMBER THIS IN THE LOCK BLOCK
STOR T2,ENQFLG,(T1) ;STORE FLAGS OF LOCK-BLOCK
TRNN T2,EN.TXT ;TEXT?
JRST [ STOR P2,ENQTXT,(T1) ;NO, STORE USER CODE
RETSKP] ;ALL DONE
MOVE T2,P2 ;BUILD THE BYTE POINTER
AND T2,[007700,,0] ;GET BYTE SIZE FROM OTHE BYTE POINTER
TDO T2,[POINT 0,.ENTXT(T1)]
CRELK1: XCTBU [ILDB T3,P2] ;COPY STRING INTO BLOCK
IDPB T3,T2 ;...
JUMPN T3,CRELK1 ;IF NOT 0, LOOP BACK FOR ALL CHARS
RETSKP ;LOCK-BLOCK CREATED
;ROUTINE TO CREATE A Q-BLOCK AND PUT IT ON A LOCK-BLOCK CHAIN
;ACCEPTS IN T1/ LOCK-BLOCK ADR
; T2/ Q-BLOCK ADR OF MEMBER OF MULTIPLE REQUEST
; T3/ FLAGS FOR NEW Q-BLOCK
; Q1-Q3, P1-P4 AS SET UP BY VALARG AND VALREQ
; CALL CREQ
;RETURNS +1: CANNOT CREATE Q-BLOCK
; +2: Q-BLOCK ADDRESS IN T1
CREQ: STKVAR <CREQL,CREQQ,CREQF,CREQA>
MOVEM T1,CREQL ;SAVE LOCK-BLOCK ADDRESS
MOVEM T2,CREQQ ;SAVE MULTIPLE REQUEST Q-BLOCK
MOVEM T3,CREQF ;SAVE FLAGS
LOAD T1,ENQOTA ;GET QUOTA FOR THIS JOB
LOAD T2,ENQCNT ;GET CURRENT COUNT
HRRZ T3,P1 ;GET OFN
CAIN T3,-3 ;SYSTEM LOCK?
JRST CREQ1 ;YES, DONT COUNT UP QUOTA
CAMG T1,T2 ;ROOM LEFT FOR MORE ENTRIES?
RETBAD (ENQX18) ;NO, DONT CREATE QUEUE
AOS T2 ;COUNT UP COUNT
STOR T2,ENQCNT ;STORE UPDATED COUNT
CREQ1: MOVE T2,CREQL ;GET ADR OF THE LOCK BLOCK
LOAD T1,ENQFBP,(T2) ;SEE IF THERE IS A FREE Q-BLOCK
SETZRO ENQFBP,(T2) ;CLEAR OUT POINTER TO THE BLOCK
JUMPN T1,CREQ2 ;IF THERE IS A FREE BLOCK, GO USE IT
MOVEI T1,QBLEN ;GET LENGTH OF Q-BLOCK
CALL ASGENQ ;GET FREE BLOCK FOR Q
RET ;NO SPACE LEFT
CREQ2: MOVEM T1,CREQA ;SAVE THE ADDRESS OF THE Q-BLOCK
MOVEI T2,ENQLST ;GET ADDRESS OF ENTRY
STOR T2,ENQLJQ,(T1) ;POINT BACK TO JOB TABLE ENTRY
HRRZ T3,0(T2) ;GET FORWARD POINTER
HRRM T1,0(T2) ;MAKE JOB LIST POINT TO US
STOR T3,ENQNJQ,(T1) ;MAKE US POINT FORWARD
SKIPE T3 ;IS THIS THE END OF THE LIST
STOR T1,ENQLJQ,(T3) ;NO, MAKE SECOND ITEM POINT BACK TO US
MOVE T2,CREQL ;GET LOCK BLOCK ADDRESS AGAIN
STOR T2,ENQNLQ,(T1) ;MAKE US POINT FORWARD TO LOCK-BLOCK
LOAD T3,ENQLLQ,(T2) ;GET BACK OF QUEUE FROM LOCK-BLOCK
STOR T3,ENQLLQ,(T1) ;MAKE US POINT BACK TO IT
STOR T1,ENQNLQ,(T3) ;MAKE IT POINT TO US
STOR T1,ENQLLQ,(T2) ;MAKE LOCK-BLOCK POINT BACK TO US
STOR T2,ENQLBP,(T1) ;SET UP A POINTER TO THE LOCK-BLOCK
STOR Q2,ENQCHN,(T1) ;SAVE PSI CHANNEL NUMBER
HLRZ T2,Q2 ;GET ID
STOR T2,ENQID,(T1) ;SAVE THE ID NUMBER
MOVE T2,CREQF ;GET FLAGS
STOR T2,ENQFLG,(T1) ;SAVE THEM
MOVE T2,FORKX ;GET FORK NUMBER OF THIS FORK
STOR T2,ENQFRK,(T1) ;SAVE IT FOR INTERRUPTING
STOR P3,ENQNR,(T1) ;STORE # OF RESOURCES REQUESTED
HLRZ T2,P5 ;GET JFN OF REQUEST
STOR T2,ENQJFN,(T1) ;STORE JFN
HRRZ T2,P5 ;GET GROUP #
STOR T2,ENQGRP,(T1) ;STORE GROUP NUMBER
LOAD T1,ENQMSK,(T1) ;DO WE HAVE A MASK BLOCK YET?
JUMPE T1,CREQ3 ;...
MOVE T2,CREQL ;YES, GET ITS SIZE
LOAD T2,ENQNMS,(T2) ; FROM THE LOCK BLOCK
CAMN T2,EDNMS ;IS THIS THE SAME SIZE AS REQUESTED
JRST CREQ3A ;YES, GO USE IT
CALL RELENQ ;NO, RELEASE IT
MOVE T1,CREQA ;GET THE ADR OF THE Q-BLOCK AGAIN
SETZRO ENQMSK,(T1) ;CLEAR THE MASK BLOCK ADDRESS
CREQ3: SKIPN T1,EDNMS ;IS THERE A MASK BLOCK SPECIFIED?
JRST CREQ5 ;NO
CALL ASGENQ ;YES, GET SPACE FOR IT
RETBAD (,<MOVE T1,CREQA ;FAILED, RETURN Q-BLOCK
MOVEI T2,QBLEN
CALL RELENQ
MOVE T1,LSTERR>) ;GET BACK ERROR CODE
CREQ3A: MOVE T2,CREQA ;GET ADR OF Q-BLOCK
STOR T1,ENQMSK,(T2) ;SAVE ADR OF MASK BLOCK IN Q-BLOCK
MOVE T4,EDNMS ;GET THE LENGTH OF THE BLOCK
MOVE T3,CREQL ;GET ADR OF LOCK BLOCK
STOR T4,ENQNMS,(T3) ;STORE THE LENGTH OF THE MASK BLOCK
MOVE T3,EDMSK ;GET THE ADR OF THE USER'S MASK BLOCK
CREQ4: UMOVE T2,0(T3) ;GET THE NEXT USER MASK WORD
MOVEM T2,0(T1) ;COPY IT TO THE MASK BLOCK
AOS T1 ;STEP THE USER'S ADR
AOS T3 ;STEP THE MONITOR'S ADR
SOJG T4,CREQ4 ;LOOP BACK TILL THE BLOCK IS COPIED
CREQ5: MOVE T1,CREQA ;GET BACK THE ADR OF THE Q-BLOCK
;..
;..
SKIPN T2,CREQQ ;IS THIS A MULTIPLE REQUEST?
JRST [ STOR T1,ENQFQ,(T1) ;NO, MAKE AN EMPTY LIST
STOR T1,ENQLRQ,(T1)
RETSKP] ;ALL DONE
LOAD T3,ENQFQ,(T2) ;ADD THIS Q-BLOCK ONTO LIST OF REQUESTS
STOR T1,ENQFQ,(T2) ; POINT FORWARD TO US
STOR T1,ENQLRQ,(T3) ; POINT BACK TO US
STOR T3,ENQFQ,(T1) ; WE POINT FORWARD
STOR T2,ENQLRQ,(T1) ; AND WE POINT BACKWARD
RETSKP ;ALL THROUGH
;ROUTINE TO DEQ AN ENTIRE REQUEST
;ACCEPTS IN T1/ Q-BLOCK ADDRESS
; CALL REQDEQ
;RETURNS +1: ALWAYS, REQUEST DEQUEUED
REQDEQ: CALL QDEQ ;DEQUEUE THIS Q-BLOCK
JUMPN T1,REQDEQ ;IF ANY MORE Q-BLOCKS, DEQ THEM TOO
RET ;EXIT SUCCESSFULLY
;ROUTINE TO DEQ A SINGLE Q-BLOCK
;ACCEPTS IN T1/ Q-BLOCK ADDRESS TO BE DEQUEUED
; CALL SQDEQ
;RETURNS +1: ALWAYS - Q-BLOCK DEQUEUED AND SCHEDULING PERFORMED
SQDEQ: STKVAR <SQDEQQ,SQDEQF>
LOAD T2,ENQFLG,(T1) ;GET FLAGS OF THIS Q-BLOCK
MOVEM T2,SQDEQF ;SAVE FOR LATER USE
CALL QDEQ ;DEQ THIS Q-BLOCK
JUMPE T1,R ;IF NOT A MULTIPLE REQUEST, RETURN
MOVEM T1,SQDEQQ ;SAVE Q-BLOCK ADDRESS
CALL QSKD ;SCHEDULE THIS Q ENTRY
RET ;LOCK NOT LOCKED YET
JUMPN T1,SQDEQ1 ;LOCKING WAS COMPLETED ON THIS CALL?
MOVE T1,SQDEQF ;NO, SEE IF USER NEEDS WAKING UP
TRNE T1,EN.LOK ;WAS THE ORGINAL Q ALREADY LOCKED?
RET ;YES, THEN USER HAD BEEN INFORMED
SQDEQ1: MOVE T1,SQDEQQ ;USER NEEDS AWAKENING, GET Q ADDRESS
CALLRET INTQ ;GO WAKE UP THE FORK
;ROUTINE TO DEQ A Q-BLOCK
;ACCEPTS IN T1/ Q-BLOCK ADDRESS
; CALL QDEQ
;RETURNS +1: ALWAYS - T1 CONTAINS 0 OR Q-BLOCK ADR OF NEXT Q IN THE
; MULTIPLE REQUEST CHAIN
QDEQ: STKVAR <QDEQRQ,QDEQLB,QDEQQA>
MOVEM T1,QDEQQA ;SAVE THE ADR OF THE Q-BLOCK
LOAD T2,ENQLJQ,(T1) ;REMOVE Q-BLOCK FROM JOB CHAIN
LOAD T3,ENQNJQ,(T1) ;GET POINTERS BACKWARD AND FORWARD
SKIPE T3 ;IF END OF LIST, DONT STORE BACK POINTER
STOR T2,ENQLJQ,(T3) ;FIX UP BACK POINTER
STOR T3,ENQNJQ,(T2) ;AND FORWARD POINTER
LOAD T2,ENQLLQ,(T1) ;NOW REMOVE IT FROM LOCK CHAIN
LOAD T3,ENQNLQ,(T1)
STOR T2,ENQLLQ,(T3)
STOR T3,ENQNLQ,(T2)
LOAD T2,ENQLRQ,(T1) ;NOW REMOVE IT FROM THE MULTIPLE LIST
LOAD T3,ENQFQ,(T1)
STOR T2,ENQLRQ,(T3)
STOR T3,ENQFQ,(T2)
MOVEM T2,QDEQRQ ;SAVE ADDRESS OF NEXT Q-BLOCK
CAIN T2,0(T1) ;IS THE MULTIPLE LIST EMPTY?
SETZM QDEQRQ ;YES, RETURN 0 IN T1 ON RETURN
LOAD T2,ENQLBP,(T1) ;GET ADDRESS OF LOCK BLOCK
LOAD T3,ENQNR,(T1) ;GET NUMBER OF RESOURCES REQUESTED
LOAD T4,ENQRR,(T2) ;GET REMAINING RESOURCES COUNT
ADD T4,T3 ;GIVE BACK OUR RESOURCES
LOAD T3,ENQFLG,(T1) ;GET FLAGS OF REQUEST
TRNE T3,EN.LOK ;WAS LOCK LOCKED?
STOR T4,ENQRR,(T2) ;YES, GIVE BACK RESOURCES
MOVEM T2,QDEQLB ;REMEMBER THE LOCK-BLOCK FOR LATER
LOAD T3,ENQCNT ;DECREMENT THE QUOTA COUNT
SOS T3
LOAD T4,ENQOFN,(T2) ;GET THE OFN VALUE
CAIE T4,-3 ;IF -3 LOCK, DONT DECREMENT QUOTA
STOR T3,ENQCNT ;STORE UPDATED COUNT
MOVE T3,QDEQLB ;GET ADR OF LOCK BLOCK
LOAD T4,ENQFBP,(T3) ;GET POINTER TO FREE Q-BLOCK IF ANY
JUMPE T4,[STOR T1,ENQFBP,(T3)
JRST QDEQ0] ;IF NO FREE Q-BLOCK, SAVE THIS ONE
LOAD T2,ENQNMS,(T3) ;GET THE SIZE OF THE MASK BLOCK
LOAD T1,ENQMSK,(T1) ;GET THE ADDRESS OF THE MASK BLOCK
SKIPE T1 ;IS THERE A MASK BLOCK?
CALL RELENQ ;YES, RELEASE ITS SPACE
MOVE T1,QDEQQA ;GET BACK THE ADR OF THE Q-BLOCK
MOVEI T2,QBLEN ;NOW GIVE BACK THE Q-BLOCK SPACE
CALL RELENQ ;...
QDEQ0: MOVE T1,QDEQLB ;GET ADR OF LOCK-BLOCK
LOAD T2,ENQNLQ,(T1) ;SEE IF LOCK IS EMPTY
CAIE T2,0(T1) ;...
JRST [ CALL LOKSKD ;NO, DO A SCHEDULING PASS ON IT
JRST QDEQ1] ;AND RETURN
CALL LOKREL ;RELEASE THE LOCK-BLOCK
QDEQ1: MOVE T1,QDEQRQ ;GET Q-BLOCK ADR OF MULTIPLE REQUEST
RET ;AND RETURN
;ROUTINE TO RELEASE A LOCK-BLOCK
;ACCETPS IN T1/ LOCK BLOCK ADDRESS
; CALL LOKREL
;RETURNS +1: ALWAYS - LOCK BLOCK GIVEN BACK TO FREE POOL
LOKREL: STKVAR <LOKRLQ,LOKRLM,LOKRLN>
LOAD T2,ENQFBP,(T1) ;GET POINTER TO FREE Q-BLOCK IF ANY
MOVEM T2,LOKRLQ ;REMEMBER IT IF IT NEEDS RELEASING
SKIPE T3,T2 ;ANY FREE Q-BLOCK?
LOAD T3,ENQMSK,(T2) ;YES, GET THE POINTER TO THE MASK BLOCK
MOVEM T3,LOKRLM ;SAVE THE ADR TO THE MASK BLOCK
LOAD T3,ENQNMS,(T1) ;GET THE SIZE OF THE MASK BLOCK
MOVEM T3,LOKRLN ;SAVE IT FOR LATER
LOAD T2,ENQFLG,(T1) ;GET THE FLAGS
TXNE T2,EN.LTL ;IS THIS A LONG TERM LOCK?
JRST LOKRL1 ;YES, DO NOT RELEASE IT YET
LOAD T2,ENQLHC,(T1) ;REMOVE LOCK-BLOCK FROM HASH CHAIN
LOAD T3,ENQNHC,(T1)
STOR T2,ENQLHC,(T3)
STOR T3,ENQNHC,(T2)
LOAD T2,ENQLEN,(T1) ;GET THE LENGTH OF THE LOCK-BLOCK
CALL RELENQ ;RELEASE THE SPACE
MOVEI T2,QBLEN ;NOW RELEASE THE Q-BLOCK
SKIPE T1,LOKRLQ ;IF THERE WAS ONE
CALL RELENQ ;RELEASE IT
MOVE T2,LOKRLN ;GET THE LENGTH OF THE MASK BLOCK
SKIPE T1,LOKRLM ;IS THERE A MASK BLOCK TO RELEASE
CALL RELENQ ;YES, RELEASE IT
RET ;ALL DONE
LOKRL1: LOAD T2,ENQLT,(T1) ;GET POINTER TO LONG TERM LOCK LIST
CAIE T2,-1 ;IS THIS ALREADY ON A LIST?
RET ;YES, NO NEED TO PUT IT ON AGAIN
HRRZ T2,ENQLTL ;GET POINTER TO JOB LONG TERM LOCK LIST
STOR T2,ENQLT,(T1) ;LINK THIS LOCK ONTO HEAD OF THAT LIST
HRRM T1,ENQLTL ;THIS LOCK IS NOW FIRST ON THE LIST
RET ;AND EXIT, LOCK GETS RELEASED LATER
;ROUTINE TO DO A SCHEDULING PASS GIVEN A Q-BLOCK ADDRESS
;ACCEPTS IN T1/ Q-BLOCK ADDRESS
; CALL QSKD
;RETURNS +1: THIS REQUEST IS NOT FULLY LOCKED YET
; +2: THIS REQUEST IS FULLY LOCKED
; T1 = 0 IF ALREADY LOCKED BEFORE THIS CALL
; T1 = -1 IF THE LOCKING WAS COMPLETED ON THIS CALL
QSKD: SAVEQ
STKVAR <QSKDQ,QSKDT,CKLOKQ,QSKDF,QSKDG,QSKDM,QSKDN>
SETZM QSKDF ;ASSUME LOCK ALREADY LOCKED ON CALL
MOVEM T1,QSKDQ ;SAVE THE ADDRESS OF THIS Q-BLOCK
CALL SETINV ;MAKE SURE INVISIBLE BITS SET OK
JRST QSKD0 ;GO MAKE SCHEDULING PASS
JRST QSKD3 ;LOCK IS ALREADY LOCKED
QSKD0: MOVE T1,QSKDQ ;GET ADDRESS OF THIS Q-BLOCK AGAIN
QSKD1: MOVEM T1,QSKDT ;SAVE IT IN A TEMPORARY REGISTER
LOAD T2,ENQMSK,(T1) ;GET THE ADR TO THE MASK BLOCK
MOVEM T2,QSKDM ;SAVE THE ADR OF THE MASK BLOCK
LOAD T2,ENQLBP,(T1) ;GET THE POINTER TO THE LOCK BLOCK
LOAD T2,ENQNMS,(T2) ;GET THE LENGTH OF THE MASK BLOCK
MOVEM T2,QSKDN ;SAVE IT FOR LATER
LOAD T2,ENQGRP,(T1) ;GET GROUP # OF THIS Q ENTRY
MOVEM T2,QSKDG ;SAVE FOR COMPARISON LATER
LOAD T2,ENQFLG,(T1) ;GET THE FLAGS OF THIS Q-BLOCK
TRNE T2,EN.LOK!EN.INV ;IS THE LOCK LOCKED BY THIS Q-BLOCK
; OR AN INVISIBLE Q-BLOCK?
JRST QSKD2 ;YES, GO CONTINUE SCANNING SIDEWAYS
CHKLK1: LOAD T1,ENQLLQ,(T1) ;GET PREVIOUS BLOCK ON QUEUE
MOVE T2,QSKDT ;GET ORIGINAL Q-BLOCK ADR
LOAD T3,ENQFLG,(T2) ;RESTORE ITS FLAGS INTO T2
LOAD T4,ENQFLG,(T1) ;GET THE FLAGS OF THIS BLOCK
TRNE T4,EN.LB ;IS THIS THE LOCK-BLOCK?
JRST CHKLK2 ;YES, WE ARE AT TOP OF QUEUE
TRNE T4,EN.INV ;NO, IS THIS Q-BLOCK INVISIBLE?
JRST CHKLK1 ;YES, IGNORE THIS BLOCK ENTIRELY
TRNN T4,EN.EXC ;IS THIS AN EXCLUSIVE REQUEST?
TRNE T3,EN.EXC ;OR IS ORIGINAL REQUEST EXCLUSIVE?
JRST CHKLK3 ;YES, GO CHECK MASK BLOCKS
LOAD T2,ENQGRP,(T1) ;GET GROUP NUMBER OF THIS Q
CAME T2,QSKDG ;IS THIS THE SAME GROUP
RET ;NO, CANNOT SCHEDULE THIS REQUEST
JRST CHKLK1 ;LOOP BACK UNTIL AT LOCK-BLOCK
CHKLK2: MOVE T3,QSKDT ;GET THE NUMBER OF RESOURCES NEEDED
LOAD T3,ENQNR,(T3) ;...
LOAD T4,ENQRR,(T1) ;GET THE # OF REMAINING RESOURCES
SUB T4,T3 ;SEE IF ENOUGH LEFT FOR THIS REQUEST
JUMPL T4,R ;IF NOT, LOCK CANNOT BE LOCKED
STOR T4,ENQRR,(T1) ;THERE ARE ENOUGH, LOCK THE LOCK
MOVE T3,QSKDT ;GET BACK ADR OF Q-BLOCK
LOAD T2,ENQFLG,(T3) ;GET FLAGS AGAIN
TRO T2,EN.LOK ;LOCK THE LOCK BIT
STOR T2,ENQFLG,(T3) ;STORE THE UPDATED FLAGS
LOAD T2,ENQNLQ,(T3) ;NOW MOVE THIS Q-BLOCK TO THE HEAD
LOAD T4,ENQLLQ,(T3) ; OF THE QUEUE FOR THIS LOCK
STOR T2,ENQNLQ,(T4) ;FIRST REMOVE IT FROM THE QUEUE
STOR T4,ENQLLQ,(T2) ;...
LOAD T2,ENQNLQ,(T1) ;NOW ADD IT TO THE START OF THE QUEUE
STOR T3,ENQLLQ,(T2) ; POINTER BACK TO Q-BLOCK FROM Q-2
STOR T3,ENQNLQ,(T1) ; POINTER TO Q-BLOCK FROM LOCK-BLOCK
STOR T2,ENQNLQ,(T3) ; POINTER TO SECOND Q-BLOCK
STOR T1,ENQLLQ,(T3) ; POINTER BACK TO LOCK-BLOCK
CALL LGTAD ;GET TIME AND DATE
MOVE T3,QSKDT ;GET Q-BLOCK ADDRESS
LOAD T3,ENQLBP,(T3) ;GET LOCK BLOCK ADDRESS
STOR T1,ENQTS,(T3) ;STORE NEW TIME STAMP IN LOCK BLOCK
MOVE T1,QSKDQ ;GET ORIGINAL Q-BLOCK ADDRESS
SETOM QSKDF ;MARK THAT A LOCK WAS LOCKED
CALL SETINV ;GO CLEAR ANY INVISIBLE BITS
JRST QSKD0 ;LOCK NOT FULLY LOCKED YET, TRY AGAIN
JRST QSKD3 ;LOCK IS LOCKED, GO GIVE OK RETURN
QSKD2: MOVE T2,QSKDT ;GET Q-BLOCK ADR OF PRESENT Q-BLOCK
LOAD T1,ENQFQ,(T2) ;STEP TO NEXT Q-BLOCK IN THIS REQUEST
CAME T1,QSKDQ ;ARE WE BACK TO THE Q-BLOCK STARTED AT?
JRST QSKD1 ;NO, GO CHECK IF THIS Q LOCKED
QSKD3: MOVE T1,QSKDF ;GET BACK ANSWER TO BE RETURNED
RETSKP ;AND SKIP RETURN
CHKLK3: LOAD T3,ENQMSK,(T1) ;YES, CHECK FOR MASKS
SKIPE T4,QSKDM ;IS THERE A MASK FOR THIS Q-BLOCK
JUMPN T3,CHKLK4 ;YES, DO BOTH BLOCKS HAVE A MASK?
JUMPN T4,CHKLK5 ;NO, ONLY ONE HAVE A MASK?
JUMPE T3,R ;IF NEITHER HAVE A MASK, THEN CANNOT LOCK
MOVE T4,T3 ;GET ADR OF MASK BLOCK TO USE
CHKLK5: MOVE T3,QSKDN ;GET LENGTH OF MASK BLOCK
CHKLK6: SKIPE 0(T4) ;ARE THERE ANY BITS ON IN MASK?
RET ;YES, THEN CANNOT LOCK IT NOW
AOS T4 ;STEP TO NEXT WORD IN MASK
SOJG T3,CHKLK6 ;LOOP BACK TIL SCANNED WHOLE MASK
JRST CHKLK1 ;THESE Q-BLOCKS CAN CO-EXIST
CHKLK4: MOVE Q1,QSKDN ;GET LENGTH OF MASK BLOCK
CHKLK7: MOVE Q2,0(T3) ;GET NEXT WORD IN MASK BLOCK
AND Q2,0(T4) ;AND IN THE NEXT MASK BLOCK IN OTHER BLOCK
JUMPN Q2,R ;IF OVERLAPPED, THEN CANNOT LOCK YET
AOS T3 ;STEP TO NEXT MASK WORD
AOS T4 ;IN BOTH BLOCKS
SOJG Q1,CHKLK7 ;LOOP BACK
JRST CHKLK1 ;THESE Q-BLOCKS CAN CO-EXIST
;ROUTINE TO CLEAR INVISIBLE BITS AS Q-BLOCKS GET LOCKED
;ACCEPTS IN T1/ Q-BLOCK ADDRESS OF ONE ELEMENT OF A REQUEST
; CALL SETINV
;RETURNS +1: REQUEST NOT FULLY LOCKED YET
; +2: REQUEST IS NOW FULLY LOCKED
SETINV: STKVAR <SETINQ,SETINU>
MOVSI T2,1 ;INITIALIZE LEVEL NUMBER SCANNER
MOVEM T2,SETINU ;...
MOVEM T1,SETINQ ;REMEMBER Q-BLOCK ADDRESS
SETIN1: LOAD T2,ENQLBP,(T1) ;GET ADDRESS OF LOCK-BLOCK FOR Q
LOAD T4,ENQLVL,(T2) ;GET LEVEL NUMBER OF THIS LOCK
LOAD T3,ENQFLG,(T1) ;GET Q FLAGS
TRNE T3,EN.LOK ;IS THIS Q ALREADY LOCKED?
JRST SETIN2 ;YES
CAMG T4,SETINU ;NO, IS THIS A NEW LOW VALUE?
MOVEM T4,SETINU ;YES, REMEMBER LOWEST NON-LOCKED LEVEL
SETIN2: LOAD T1,ENQFQ,(T1) ;GET NEXT Q-BLOCK IN THIS REQUEST
CAME T1,SETINQ ;ARE WE BACK TO STARTING POINT?
JRST SETIN1 ;NO, LOOP BACK FOR OTHER Q-BLOCKS
MOVE T2,SETINU ;GET LEVEL NUMBER
TLNE T2,-1 ;SEE IF AN UNLOCKED LOCK WAS SEEN
RETSKP ;NONE SEEN, THE LOCK IS FULLY LOCKED
SETIN3: LOAD T2,ENQLBP,(T1) ;GET ADR OF LOCK-BLOCK FOR THIS Q
LOAD T4,ENQLVL,(T2) ;GET LEVEL NUMBER OF LOCK
LOAD T3,ENQFLG,(T1) ;GET FLAGS OF THIS Q-BLOCK
CAMG T4,SETINU ;IS LEVEL ABOVE LOWEST UNLOCKED LEVEL?
TRZA T3,EN.INV ;NO, MAKE THIS Q-BLOCK VISIBLE
TRO T3,EN.INV ;YES, THE Q-BLOCK MUST REMAIN INVISIBLE
STOR T3,ENQFLG,(T1) ;STORE UPDATED FLAGS
LOAD T1,ENQFQ,(T1) ;GET ADR OF NEXT Q-BLOCK IN REQUEST
CAME T1,SETINQ ;HAVE WE SEEN ALL Q-BLOCKS?
JRST SETIN3 ;NO, LOOP BACK UNTIL ALL SEEN
RET ;YES, ALL THROUGH (REQ NOT TOTALLY
; LOCKED)
;ROUTINE TO MAKE A SCHEDULING PASS GIVEN A LOCK-BLOCK ADDRESS
;ACCEPTS IN T1/ LOCK-BLOCK ADDRESS
; CALL LOKSKD
;RETURNS +1: ALWAYS - ALL NEWLY LOCKED REQUESTS INTERRUPTED
LOKSKD: STKVAR <LOKSKL,LOKSKQ,LOKSKC>
MOVEM T1,LOKSKL ;SAVE ADDRESS OF LOCK FOR LATER
MOVEM T1,LOKSKQ ;INITIALIZE Q-BLOCK ADDRESS REGISTER
LOAD T2,ENQRR,(T1) ;GET REMAINING RESOURCES IN POOL
MOVEM T2,LOKSKC ;SAVE COUNT OF RESOURCES
LOKSK1: LOAD T1,ENQNLQ,(T1) ;STEP TO NEXT Q-BLOCK ON QUEUE
CAMN T1,LOKSKL ;BACK TO THE LOCK-BLOCK YET?
RET ;YES, SCHEDULING PASS IS DONE
MOVEM T1,LOKSKQ ;UPDATE POINTER TO CURRENT Q-BLOCK
LOAD T2,ENQFLG,(T1) ;GET FLAGS OF THE Q-BLOCK
TRNE T2,EN.INV ;INVISIBLE?
JRST LOKSK1 ;YES, IGNORE IT
TRNE T2,EN.LOK ;THIS Q ALREADY LOCKED?
JRST LOKSK3 ;YES, DONT DECREMENT RESOURCE COUNT
LOAD T2,ENQNR,(T1) ;GET NUMBER OF RESOURCES REQUESTED
MOVE T3,LOKSKC ;GET REMAINING RESOURCES
SUB T3,T2 ;DECREMENT COUNT
JUMPL T3,R ;IF NOT ENOUGH LEFT, EXIT
MOVEM T3,LOKSKC ;STORE NEW COUNT
LOKSK3: CALL QSKD ;GO SEE IF THIS REQUEST IS LOCKED
JRST LOKSK2 ;NO
JUMPE T1,LOKSK2 ;IF NOT JUST LOCKED, DONT INTERRUPT
MOVE T1,LOKSKQ ;GET Q-BLOCK ADDRESS
CALL INTQ ;INTERRUPT THE PROCESS
LOKSK2: MOVE T1,LOKSKQ ;GET Q-BLOCK ADDRESS AGAIN
JRST LOKSK1 ;LOOP BACK FOR REST OF QUEUE
;ROUTINES TO WAKE UP OR INTERRUPT WAITING FORKS WHEN LOCK IS LOCKED
;ROUTINE TO WAKE UP A FORK GIVEN THE Q-BLOCK JUST LOCKED
;ACCEPTS IN T1/ Q-BLOCK ADDRESS
; CALL INTQ
;RETURNS +1: ALWAYS - FORK AWAKENED OR INTERRUPTED AS APPROPRIATE
INTQ: LOAD T2,ENQFRK,(T1) ;GET FORK TO BE AWAKENED
LOAD T1,ENQCHN,(T1) ;GET CHANNEL #
CAIE T1,.ENWCH ;IS FORK BLOCKED OR NOT
CALLRET PSIRQ ;NOT BLOCKED, GIVE IT AN INTERRUPT
MOVE T1,T2 ;GET FORK # IN T1
PUSH P,T1 ;SAVE FORK #
CALL GETMSK ;GET THE BIT POSITION AND WORD INDEX
IORM T2,ENFKTB(T1) ;SET BIT IN ENQ FORK TABLE
POP P,T1 ;GET BACK FORK NUMBER
CALLRET UNBLKF ;UNBLOCK THE FORK
;ROUTINE TO TEST IF A FORK IS READY TO CONTINUE (CALLED BY SCHEDULER)
;ACCEPTS IN T1/ FORK #
; JSP T4,ENQTST
;RETURNS +1: FORK NOT READY TO CONTINUE
; +2: FORK IS READY TO BE CONTINUED, LOCK IS LOCKED
RESCD
ENQTST: PUSH P,T4 ;SAVE RETURN ADDRESS
CALL GETMSK ;GET BIT POSITION AND WORD INDEX
TDNN T2,ENFKTB(T1) ;IS FORK READY TO CONTINUE?
RET ;NO
RETSKP ;YES
SWAPCD
;ROUTINE TO GET SPACE FOR AN ENQ BLOCK
;ACCEPTS IN 1/ LENGTH OF BLOCK DESIRED
; CALL ASGENQ
;RETURNS +1: NO ROOM
; +2 T1/ ADR OF BLOCK
ASGENQ: STKVAR <ASGENC,ASGENO>
MOVEM T1,ASGENC ;SAVE COUNT OF WORDS NEEDED
MOVE T2,ENQSPC ;GET SPACE LEFT
SUB T2,ASGENC ;CALCULATE THE NEW AMOUNT
JUMPL T2,ASGEN2 ;NONE LEFT, GO TRY TO FREE UP SOME
EXCH T2,ENQSPC ;SAVE NEW COUNT
MOVEM T2,ASGENO ;SAVE OLD COUNT
CALL ASGSWP ;GET SPACE
JRST ASGEN1 ;FAILED, GO TRY TO FREE UP SOME
RETSKP
ASGEN1: MOVE T1,ASGENO ;RESTORE OLD COUNTER
MOVEM T1,ENQSPC
ASGEN2: HRLOI T1,377777 ;RELEASE ALL LONG TERM LOCKS
CALL ENQGC ;BRUTE FORCE TECHNIQUE TO GET SPACE
MOVE T2,ENQSPC ;GET SPACE LEFT
SUB T2,ASGENC ;CALCULATE THE NEW AMOUNT
JUMPL T2,[RETBAD(MONX06)] ;NO SWAPPABLE FREE SPACE
EXCH T2,ENQSPC ;SAVE NEW COUNT
MOVEM T2,ASGENO ;SAVE OLD COUNT
MOVE T1,ASGENC ;GET NUMBER OF WORDS NEEDED
CALL ASGSWP ;GET SPACE
RETBAD (,<MOVE T2,ASGENO ;GET THE OLD COUNT AGAIN
MOVEM T2,ENQSPC>) ;RESTORE THE OLD COUNT
RETSKP
;ROUTINE TO RELEASE ENQ SPACE
;ACCEPTS IN T1/ ADR OF BLOCK
; T2/ LENGTH OF BLOCK
; CALL RELENQ
;RETURNS +1: ALWAYS
RELENQ: ADDM T2,ENQSPC ;PUT BACK THE SPACE USED
CALLRET RELSWP ;AND RELEASE THE BLOCK
;ROUTINE TO GARBAGE COLLECT LONG TERM LOCKS
;ACCEPTS IN T1/ TIME STAMP FOR DELETING LOCK BLOCKS
; CALL ENQGC
;RETURNS +1: ALWAYS
ENQGC: HRRZ T2,ENQLTL ;ANY LOCKS ON THE LIST?
JUMPE T2,R ;NO
SAVEQ ;GET SOME ACS TO USE
MOVEI Q1,ENQLTL-.ENQLT ;GET POINTER TO HEAD OF LIST
MOVE Q3,T1 ;SAVE TIME STAMP
ENQGC1: LOAD T1,ENQLT,(Q1) ;GET NEXT LOCK ON LIST
JUMPE T1,R ;0 MEANS NO MORE
LOAD T2,ENQTS,(T1) ;WHEN WAS THE LAST TIME IT WAS USED
CAMGE T2,Q3 ;IS IT TOO OLD?
JRST ENQGC2 ;YES, GO DELETE IT
MOVE Q1,T1 ;GET POINTER TO THIS LOCK INTO Q1
JRST ENQGC1 ;LOOP BACK FOR ALL LOCKS ON LIST
ENQGC2: LOAD T2,ENQLT,(T1) ;NOW REMOVE THIS LOCK FROM THE LIST
STOR T2,ENQLT,(Q1) ;MAKE LIST SKIP OVER THIS ONE
MOVEI T2,-1 ;MARK THAT THIS ONE IS NOT ON LIST
STOR T2,ENQLT,(T1)
LOAD T2,ENQFLG,(T1) ;TURN OFF THE LONG TERM LOCK FLAG
TXZ T2,EN.LTL ;SO IT WILL BE RELEASED
STOR T2,ENQFLG,(T1)
LOAD T2,ENQNLQ,(T1) ;NOW SEE IF THE LOCK IS FREE
CAIN T2,0(T1) ;IT IS FREE IF IT POINTS TO ITSELF
CALL LOKREL ;IT IS FREE, GO RELEASE IT
JRST ENQGC1 ;LOOP BACK FOR REST OF LIST
;ROUTINE TO CALCULATE AN INDEX INTO THE HASH TABLE
;REQUIRES THAT P1 - P4 BE SET UP BY VALREQ
; CALL HASH
;RETURNS +1: ILLEGAL ARGUMENT - ERROR CODE IN T1
; +2: HASH INDEX IN T1
; P4 CONTAINS WORD LENGTH OF STRING
HASH: SETZ P4, ;INITIALIZE CHARACTER COUNT
MOVE T1,P2 ;GET STRING POINTER
LDB T2,[POINT 3,T1,2] ;SEE IF A CODE OR STRING POINTER
CAIN T2,5 ;...
JRST HASH1 ;USER CODE (500000,,0 + 33-BIT NUMBER)
CALL STHASH ;HASH THE STRING
RET ;ILLEGAL STRING POINTER
MOVEM T2,P4 ;SAVE CHARACTER COUNT
HASH1: HRRZ T2,P1 ;GET OFN CODE
CALL MHASH ;HASH THE TWO NUMBERS TOGETHER
MOVMS T1 ;MAKE SURE IT IS POSITIVE
IDIVI T1,HSHLEN ;GET FINAL HASH INDEX
MOVE T1,T2 ;USE REMAINDER
RETSKP ;AND GIVE OK RETURN
;ROUTINE TO HASH TWO NUMBERS TOGETHER
;ACCEPTS IN T1/ NUMBER
; T2/ NUMBER
; CALL MHASH
;RETURNS +1: ALWAYS - T1/ HASH
MHASH: XOR T1,RANDOM ;GUARD AGAINST A ZERO IN T1
XOR T2,RANDOM ;OR IN T2
MUL T2,RANDOM ;GET A RANDOM NUMBER
MUL T1,T2 ;...
RET
RANDOM: 5*5*5*5*5*5*5*5*5*5*5*5*5*5*5
;ROUTINE TO HASH A STRING
;ACCEPTS IN T1/ STRING POINTER IN USER SPACE
; CALL STHASH
;RETURNS +1: ILLEGAL STRING POINTER - ERROR CODE IN T1
; +2: HASH IN T1
; # OF WORDS IN STRING IN T2
STHASH: STKVAR <STHSHP,STHSHX,STHSHC,STHSHB,STHSHN,STHSHM>
MOVEM T1,STHSHP ;SAVE POINTER
LDB T2,[POINT 6,T1,11] ;GET THE BYTE SIZE
MOVEI T3,^D36 ;GET NUMBER OF BYTES PER WORD
IDIVI T3,(T2) ;...
MOVEM T3,STHSHN ;SAVE NUMBER OF BYTES PER WORD
IMULI T3,ENQMXW ;GET MAX NUMBER OF CHARACTERS ALLOWED
MOVEM T3,STHSHM ;SAVE FOR LATER
AND T1,[007700,,0] ;BUILD A BYTE POINTER
TDO T1,[POINT 0,T2] ;POINTING TO AC T2
MOVEM T1,STHSHB ;SAVE IT FOR LATER
SETZM STHSHC ;INITIALIZE THE COUNT OF CHARACTERS
SETZM STHSHX ;INITIALIZE ANSWER REGISTER
STHSH1: MOVE T4,STHSHN ;INITIALIZE COUNTER
MOVE T3,STHSHB ;AND BYTE POINTER
SETZ T2, ;INITIALIZE RECEIVER AC
STHSH2: AOS T1,STHSHC ;COUNT UP CHARACTER COUNTER
CAMLE T1,STHSHM ;STRING TOO LONG?
RETBAD (ENQX19) ;YES, GIVE ERROR RETURN
XCTBU [ILDB T1,STHSHP] ;GET A BYTE FROM THE USER'S STRING
JUMPE T1,STHSH3 ;END OF STRING?
IDPB T1,T3 ;NO, STORE CHARACTER IN T2
SOJG T4,STHSH2 ;LOOP BACK FOR 5 CHARACTERS
XORM T2,STHSHX ;XOR THIS INTO ANSWER WORD
JRST STHSH1 ;LOOP BACK UNTIL END OF STRING
STHSH3: XORM T2,STHSHX ;STORE PARTIAL WORD TOO
MOVE T1,STHSHX ;GET ANSWER
MOVE T2,STHSHC ;GET CHARACTER COUNT
IDIV T2,STHSHN ;GET NUMBER OF WORDS
SKIPE T3 ;AND PARTIAL WORDS IN THE STRING
AOS T2
RETSKP ;AND RETURN
;ROUTINE TO DEQ ALL REQUESTS FOR A FORK
;ACCEPTS IN T1/ FORK NUMBER
; CALL ENQFKR OR CALL DEQFRK (IF DATA BASE ALREADY LOCKED)
;RETURNS +1: ALWAYS
ENQFKR::HRRZ T2,ENQLST ;ANY LOCKS LOCKED FOR THIS JOB?
JUMPE T2,R ;IF NOT, THEN EXIT NOW
NOINT ;LOCK UP THE DATA BASE FIRST
LOKK ENQLKK
SETO T2, ;DEQ ALL
CALL DEQFRK ;DEQUEUE ALL ENTRIES FOR THIS FORK
UNLOKK ENQLKK ;UNLOCK THE DATA BASE
OKINT
RET ;AND RETURN
;ROUTINE TO DEQ FOR A FORK
;ACCEPTS IN T1/ FORK #
; T2/ -1 FOR ALL, OR AN ID TO BE MATCHED
; CALL DEQFRK
;RETURNS +1 ALWAYS - T1/ COUNT OF LOCKS DEQUEUED
DEQFRK: STKVAR <DEQFKF,DEQFKQ,DEQFKI,DEQFCT>
SETZM DEQFCT ;INIT COUNT OF DEQUEUED LOCKS TO 0
MOVEM T1,DEQFKF ;SAVE FORK NUMBER ON STACK
MOVEM T2,DEQFKI ;SAVE ID
DEQFK0: HRRZ T1,ENQLST ;GET FIRST Q ON JOB LIST
DEQFK1: JUMPE T1,DEQFK2 ;IF NO MORE, GO EXIT
LOAD T2,ENQFRK,(T1) ;GET FORK NUMBER OF CREATOR OF Q
LOAD T3,ENQID,(T1) ;GET ID OF Q-ENTRY
SKIPL DEQFKI ;IS THIS A DELETE ALL REQUEST?
CAMN T3,DEQFKI ;NO, IS THIS A MATCH?
CAME T2,DEQFKF ;YES, IS THIS TO BE DELETED?
JRST [ LOAD T1,ENQNJQ,(T1) ;NO, STEP TO NEXT Q-BLOCK IN CHAIN
JRST DEQFK1] ;LOOP BACK TILL END OF LIST
CALL REQDEQ ;YES, DELETE IT
AOS DEQFCT ;COUNT UP NUMBER OF LOCKS DEQUEUED
JRST DEQFK0 ;START OVER AGAIN AT START OF LIST
DEQFK2: MOVE T1,DEQFCT ;GET THE COUNT OF LOCKS RELEASED
RET ;AND RETURN
;ROUTINE TO INITIALIZE THE JSB ON JOB CREATION
ENQJBI::SETZB T1,ENQLST ;INITIALIZE POINTER TO Q-BLOCKS
STOR T1,ENQCNT ;ZERO COUNT OF REQUESTS
MOVEI T1,ENQSTQ ;GET STANDARD ENQ/DEQ QUOTA
STOR T1,ENQOTA ;STORE IN JSB
RET ;AND RETURN
;ROUTINE TO CHECK IF AN OFN HAS A LOCK SET ON IT
;ACCEPTS IN T1/ OFN
; T2/ JFN
; CALL ENQCLS
;RETURNS +1: OFN IS LOCKED, FILE CANNOT BE CLOSED OR MADE LONG
; +2: OFN IS NOT LOCKED BY THIS JOB
ENQCLS::MOVEM T2,T4 ;SAVE JFN BEING CLOSED
NOINT ;LOCK UP THE DATA BASE DURING SCAN
LOKK ENQLKK ;...
HRRZ T2,ENQLST ;GET POINTER TO LOCKS FOR THIS JOB
ENQCL1: JUMPE T2,ENQCL2 ;IF 0, END OF LIST AND OFN IS OK
LOAD T3,ENQLBP,(T2) ;GET ADDRESS OF LOCK BLOCK
LOAD T3,ENQOFN,(T3) ;GET OFN OF LOCK
CAMN T1,T3 ;THE SAME OFN?
JRST [ LOAD T3,ENQJFN,(T2) ;YES, GET JFN OF REQUEST
CAME T3,T4 ;IS JFN OF REQUEST BEING CLOSED ?
JRST .+1 ;NO, GO SCAN REST OF THE LIST
UNLOKK ENQLKK ;YES, FILE CANNOT BE CLOSED
OKINT
MOVEI T1,ENQX20 ;GET ERROR CODE
RET] ;GIVE ERROR RETURN
LOAD T2,ENQNJQ,(T2) ;GET ADDRESS OF NEXT Q IN LIST
JRST ENQCL1 ;LOOP TIL END OF LIST
ENQCL2: UNLOKK ENQLKK ;UNLOCK THE LOCKS
OKINT
RETSKP ;GIVE OK RETURN
;ROUTINE TO INITIALIZE THE DATA BASE ON SYSTEM START UP
; CALL ENQINI
;RETURNS +1: ALWAYS
ENQINI::SETZM ENFKTB ;ZERO THE WAKEUP TABLE
MOVE T1,[ENFKTB,,ENFKTB+1]
MOVEI T2,ENFKTL
CAILE T2,1 ;DO BLT ONLY IF TABLE MORE THAN 1 WORD
BLT T1,ENFKTB-1+ENFKTL
MOVEI T1,HSHTBL ;INITIALIZE HASH TABLE
HRLS T1 ; WITH EACH ENTRY POINTING TO ITSELF
MOVEI T2,HSHLEN ;GET NUMBER OF ELEMENTS IN TABLE
ENQIN1: HRRZ T3,T1 ;SET UP ADDRESS ONLY
MOVEM T1,0(T3) ;STORE POINTERS TO SELF
ADD T1,BHC+1 ;INCREMENT BOTH HALVES BY 1
SOJG T2,ENQIN1 ;LOOP BACK FOR ALL ENTRIES
MOVEI T1,ENQMXF ;GET MAX ALLOWABLE USE OF FREE POOL
MOVEM T1,ENQSPC ;INITIALIZE THE ENQ SPACE POOL
SETZM ENQLTL ;INIT LONG TERM LOCK LIST
SETZM ENQLTS ;AND TIME STAMP
LCKINI ENQLKK ;INIT THE ENQ LOCK BLOCK
RET ;RETURN
TNXEND
END