Google
 

Trailing-Edge - PDP-10 Archives - AP-4178E-RM - swskit-sources/enq.mac
There are 50 other files named enq.mac in the archive. Click here to see a list.
;<3-MONITOR>ENQ.MAC.77, 16-Nov-77 14:58:32, EDIT BY KIRSCHEN
;MORE COPYRIGHT UPDATING...
;<3-MONITOR>ENQ.MAC.74, 19-Oct-77 17:31:59, EDIT BY HURLEY
;MAKE FREE SPACE MAXIMUM USE PART OF IPCF FREE SPACE
;<3-MONITOR>ENQ.MAC.73, 17-Oct-77 16:23:56, EDIT BY HURLEY
;<3-MONITOR>ENQ.MAC.72, 12-Oct-77 13:44:21, EDIT BY KIRSCHEN
;UPDATE COPYRIGHT FOR RELEASE 3
;<3-MONITOR>ENQ.MAC.71, 30-Sep-77 17:39:47, EDIT BY HURLEY
;FIX ENQC TO NOT LOOP IN CNTL
;<3-MONITOR>ENQ.MAC.70, 19-Aug-77 14:41:03, EDIT BY HURLEY
;<3-MONITOR>ENQ.MAC.69, 15-Aug-77 18:44:23, EDIT BY HURLEY
;MAKE SHARER REQUESTS WITH MASK BLOCKS CO-EXIST WITH EXCLUSIVE LOCKS
;<3-MONITOR>ENQ.MAC.68, 18-Jul-77 14:42:57, EDIT BY HURLEY
;MAKE PARTIAL MASK DEQ'S WORK
;<3-MONITOR>ENQ.MAC.67,  6-Jul-77 18:53:39, EDIT BY HURLEY
;<3-MONITOR>ENQ.MAC.66,  6-Jul-77 16:11:45, EDIT BY HURLEY
;<3-MONITOR>ENQ.MAC.65,  6-Jul-77 14:36:02, EDIT BY HURLEY
;<3-MONITOR>ENQ.MAC.64,  6-Jul-77 13:09:25, EDIT BY HURLEY
;<3-MONITOR>ENQ.MAC.63,  6-Jul-77 12:20:19, EDIT BY HURLEY
;<3-MONITOR>ENQ.MAC.62,  6-Jul-77 11:38:12, EDIT BY HURLEY
;<3-MONITOR>ENQ.MAC.61,  6-Jul-77 11:28:02, EDIT BY HURLEY
;<3-MONITOR>ENQ.MAC.60,  6-Jul-77 11:10:03, EDIT BY HURLEY
;<3-MONITOR>ENQ.MAC.59,  6-Jul-77 10:43:56, EDIT BY HURLEY
;<3-MONITOR>ENQ.MAC.58,  6-Jul-77 09:20:11, EDIT BY HURLEY
;<3-MONITOR>ENQ.MAC.57,  6-May-77 12:00:15, EDIT BY HURLEY
;ADD CHECK FOR GROUP MATCH IN FNDQ
;<3-MONITOR>ENQ.MAC.56,  2-May-77 19:59:43, EDIT BY BOSACK
;<3-MONITOR>ENQ.MAC.55,  2-May-77 19:58:33, EDIT BY BOSACK
;<3-MONITOR>ENQ.MAC.54, 17-Jan-77 14:21:09, Edit by MCLEAN
;<3-MONITOR>ENQ.MAC.53, 13-Jan-77 14:18:33, Edit by MCLEAN
;TCO 1669 EXTENDED ADDRESSING
;<3-MONITOR>ENQ.MAC.52, 30-Dec-76 12:31:07, EDIT BY HURLEY
;SCAN ENTIRE ENQLST TO VERIFY THAT A JFN DOES NOT HAVE A LOCK LOCKED
;<3-MONITOR>ENQ.MAC.51, 27-Dec-76 17:32:00, EDIT BY HURLEY
;<2-MONITOR>ENQ.MAC.50, 11-Nov-76 16:55:02, EDIT BY HURLEY
;<2-MONITOR>ENQ.MAC.49,  5-Nov-76 16:57:16, EDIT BY HURLEY
;<2-MONITOR>ENQ.MAC.48,  4-Nov-76 10:16:06, EDIT BY HURLEY
;<2-MONITOR>ENQ.MAC.47,  4-Nov-76 09:02:34, EDIT BY HURLEY
;MORE OF LONG TERM LOCK STUFF
;<2-MONITOR>ENQ.MAC.46,  1-Nov-76 12:03:05, EDIT BY HURLEY
;<2-MONITOR>ENQ.MAC.45,  1-Nov-76 09:20:43, EDIT BY HURLEY
;<2-MONITOR>ENQ.MAC.44, 20-Oct-76 18:02:21, EDIT BY HURLEY
;TCO 1609 - ADD NESTED LOCKS
;<2-MONITOR>ENQ.MAC.43, 14-Oct-76 23:23:49, EDIT BY HURLEY
;<2-MONITOR>ENQ.MAC.42, 14-Oct-76 19:15:52, EDIT BY HURLEY
;TCO 1597 - FIX ENQ QUOTAS TO ALLOW THEM TO BE VERY HIGH
;<1B-MONITOR>ENQ.MAC.2,  8-APR-76 09:22:27, EDIT BY KIRSCHEN
;<1B-MONITOR>ENQ.MAC.1,  6-APR-76 11:32:20, EDIT BY KIRSCHEN
;TCO # 1241 - FIX BUG WHICH PREVENTED CLOSF ON ENQ'ED FILE USING ANOTHER JFN
;<1MONITOR>ENQ.MAC.40, 29-MAR-76 17:01:02, EDIT BY HURLEY
;TCO # 1137 - RAISE ENQ QUOTA TO ^D20
;<1MONITOR>ENQ.MAC.39,  2-MAR-76 13:24:51, EDIT BY HURLEY
;TCO #1053 - IF NO LOCKS ARE LOCKED ON A DEQ, GIVE AN ERROR RETURN
;TCO #1137 - INCREASE ENQ QUOTA FROM 5 TO ^D10
;<2MONITOR>ENQ.MAC.38, 16-JAN-76 17:46:47, EDIT BY MURPHY
;<2MONITOR>ENQ.MAC.37,  8-JAN-76 13:28:42, EDIT BY HURLEY

;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED
;  OR COPIED IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
;COPYRIGHT (C) 1977 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,ENQLOK,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
	LOCK ENQLOK		;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
	UNLOCK ENQLOK		;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:	UNLOCK ENQLOK		;UNLOCK THE DATA BASE
	OKINT			;ALLOW INTERRUPTS AGAIN
	RETERR			;GIVE ERROR RETURN TO USER
;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
	LOCK ENQLOK		;...
	SAVEPQ			;SAVE ALL PERMANENT ACS
	CALL MONVAL		;GET ARGUMENTS SET UP
	CALL ENQREQ		;DO THE ENQ
	 BUG(CHK,ENQMLF,<ENQUE: INTERNAL ENQ OF A MONITOR LOCK FAILED>)
	UNLOCK ENQLOK		;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 ENQLOK 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
	LOCK ENQLOK		;...
	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]
	UNLOCK ENQLOK		;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


;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
	LOCK ENQLOK		;...
	SAVEPQ			;SAVE THE PERMANENT ACS
	CALL MONVAL		;SET UP THE ARGUMENTS IN Q1-Q3, P1-P4
	CALL DEQFN0		;DO THE DEQ
	 BUG(CHK,DEQMDF,<DEQUE: INTERNAL MONITOR DEQ FAILED>)
	UNLOCK ENQLOK		;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
	LOCK ENQLOK		;...
	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
		RETERR		;NOT PRIVILEGED
		JRST .+1]
	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#
	NOINT			;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
	OKINT
	SMRETN			;GIVE OK RETURN
;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
	LOCK ENQLOK		;...
	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:	UNLOCK ENQLOK		;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
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
	CAMN T3,FORKX		;IS THIS OUR Q-BLOCK?
	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
	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
	LO