Google
 

Trailing-Edge - PDP-10 Archives - AP-D543V_SB - queser.mac
There are 11 other files named queser.mac in the archive. Click here to see a list.
TITLE	QUESER -- ENQUEUE/DEQUEUE SERVICE FACILITY - V2036
SUBTTL	S. BLOUNT  21 MAR 78
	SEARCH	F,S
	$RELOC
	$HIGH



;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED
;  OR COPIED IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
;COPYRIGHT (C) 1974,1975,1976,1977,1978 BY DIGITAL EQUIPMENT CORP., MAYNARD, MASS.
XP VQUESR,2036

ENTRY	QUESER		;LOAD THIS MODULE IF NEEDED

QUESER::


;ENQ/DEQ PROVIDES A QUEUEING FACILITY WHICH CAN BE USED
; TO INSURE MUTUAL EXCLUSION OF PROCESSES OPERATING ON
; A COMMON DATA BASE.

	SALL
	SUBTTL DATA BASE DEFINITIONS
REPEAT 0,<

;Q-BLOCK FORMAT

		+-------------------------+-------------------------+
		!.QBLJQ:                  !.QBNJQ:                  !
		!      BACK POINTER TO    !    FORWARD POINTER TO   !
		!   LAST Q-BLOCK FOR JOB  !   NEXT Q-BLOCK FOR JOB  !
		+-------------------------+----------+--------------+
		!.QBJOB:                  !.QBCHN:   !.QBFLG:       !
		!                         !  CHANNEL !              !
		!      JOB NUMBER         !  NUMBER  !   FLAGS      !
		+-------------------------+----------+--------------+
		!.QBLQ:                   !.QBNQ:                   !
		!     POINTER TO LAST     !     POINTER TO NEXT     !
		!     QUEUE ENTRY         !     QUEUE ENTRY         !
		+-------------------------+-------------------------+
		!.QBLQR:                  !.QBNQR:                  !
		!     POINTER TO LAST     !     POINTER TO NEXT     !
		!     MULTIPLE Q-BLOCK    !     MULTIPLE Q-BLOCK    !
		+-------------------------+-------------------------+
		!.QBRID:                  !.QBNRP:                  !  
                !                         !                         !
		!       REQUEST I.D.      !  # REQUESTED FROM POOL  !
		+-------------------------+-------------------------+
		!.QBGRP:                  !.QBLB:                   !
                !       GROUP             !     POINTER TO          !
                !       NUMBER            !     LOCK-BLOCK          !
		+-------------------------+-------------------------+


;LOCK-BLOCK FORMAT

		+-------------------------+-------------------------+
		!.LBLHS:                  !.LBNHS:                  !
		!   BACK POINTER TO LAST  !     POINTER TO NEXT     !
		! LOCK-BLOCK ON HASH CHAIN! LOCK-BLOCK ON HASH CHAIN!
		+-------------------------+-------------------------+
		!.LBLEN:                  !.LBFLG:                  !
		!    LENGTH OF LOCK-BLOCK !            FLAGS        !
		!                         !                         !
		+-------------------------+-------------------------+
 		!.LBLQ:                   !.LBNQ:                   !
                !     POINTER TO LAST     !     POINTER TO NEXT     !
                !     Q-BLOCK IN CHAIN    !     Q-BLOCK IN CHAIN    !
		+-------------------------+-------------------------+
		!.LBLVL:                  !.LBACC:                  !
                !     LEVEL NUMBER        !        ADDRESS OF       !
                !                         !        ACCESS BLOCK     !
		+-------------------------+-------------------------+
		!.LBPUL:                  !.LBAVL:                  !
                !                         !                         !
                !     # IN POOL           !    # AVAILABLE          !
		+-------------------------+-------------------------+
                !.LBTIM:                                            !
                !                  TIME-STAMP                       !
                !                                                   !
		+---------------------------------------------------+
		!.LBTXT:             ASCIZ STRING                   !
		!                        OR                         !
		!                 500000 + USER CODE                !
		+---------------------------------------------------+

>	;END OF REPEAT 0
	SUBTTL	STRUCTURE MACRO DEFINITIONS


;DEFINE DATA STRUCTURE
; NAM - NAME OF STRUCTURE AS USED IN CODE
; LOCN - ADDRESS OF DATA
; POS - POSITION OF DATA WITHIN WORD (RIGHTMOST BIT NUMBER)
; SIZ - SIZE OF DATA WITHIN WORD

DEFINE DEFSTR(NAM,LOCN,POS,SIZ)<
	RADIX	10
	.TSTSZ(POS,SIZ)
	DEFST1(\..TYP,NAM,LOCN,POS,SIZ)
	RADIX	8>

DEFINE DEFST1(TYP,NAM,LOCN,POS,SIZ)<
	DEFINE	NAM(OPS,AC,Y)<
	  ..C==0
	  IRP OPS,<
	    IFE TYP-..C,<
	      STOPI
	      IFN 3-..C,<
		OPS AC,LOCN''Y>
	      IFE 3-..C,<
		OPS AC,[POINT SIZ,LOCN''Y,POS]>>
	    ..C=..C+1>>>

DEFINE .TSTSZ(POS,SIZ)<
	..TYP==3
	IFE	SIZ-36,<..TYP=0>
	IFE	SIZ-18,<
	  IFE POS-35,<..TYP=1>
	  IFE POS-17,<..TYP=2>>>

;LOAD, STORE.
; AC - AC OPERAND
; STR - STRUCTURE NAME
; Y - (OPTIONAL) LOCATION OF DATA IF NOT AS ORIGINALLY SPECIFIED

DEFINE LOAD(AC,STR,Y)<
	STR(<MOVE,HRRZ,HLRZ,LDB>,AC,Y)>

DEFINE STOR(AC,STR,Y)<
	STR(<MOVEM,HRRM,HRLM,DPB>,AC,Y)>



	SUBTTL	DATA STRUCTURE DEFINITIONS

;DATA STRUCTURE DEFINITIONS


;Q-BLOCK STRUCTURES

DEFSTR(.QBLJQ,0,17,18)		;POINTER TO LAST ENTRY IN JOB-Q
DEFSTR(.QBNJQ,0,35,18)		;POINTER TO NEXT ENTRY IN JOB-Q
DEFSTR(.QBJOB,1,17,18)		;JOB NUMBER OF THIS USER
DEFSTR(.QBCHN,1,26,9)		;CHANNEL NUMBER
DEFSTR(.QBFLG,1,35,9)		;FLAGS FOR THIS Q-ENTRY
DEFSTR(.QBLQ,2,17,18)		;POINTER TO LAST ENTRY IN QUEUE
DEFSTR(.QBNQ,2,35,18)		;POINTER TO 1ST ENTRY IN QUEUE
DEFSTR(.QBLQR,3,17,18)		;POINTER TO PREVIOUS ENTRY IN THIS REQUEST
DEFSTR(.QBNQR,3,35,18)		;POINTER TO NEXT ENTRY IN THIS REQUEST
DEFSTR(.QBRID,4,17,18)		;REQUEST ID FOR THIS ENTRY
DEFSTR(.QBNRP,4,35,18)		;NUMBER OF RESOURCES REQUESTED FROM POOL
DEFSTR(.QBGRP,5,17,18)		;GROUP NUMBER FOR THIS USER
DEFSTR(.QBLB,5,35,18)		;POINTER TO LOCK BLOCK
QBSIZE==6			;SIZE OF Q-BLOCK



;LOCK-BLOCK STRUCTURES

DEFSTR(.LBLHS,0,17,18)		;POINTER TO LAST ENTRY IN HASH CHAIN
DEFSTR(.LBNHS,0,35,18)		;POINTER TO NEXT ENTRY IN HASH CHAIN
DEFSTR(.LBLEN,1,17,18)		;LENGTH IN WORDS OF THIS LOCK-BLOCK
DEFSTR(.LBFLG,1,35,12)		;FLAGS
DEFSTR(.LBLQ,2,17,18)		;POINTER TO LAST ENTRY IN QUEUE
DEFSTR(.LBNQ,2,35,18)		;POINTER TO 1ST ENTRY IN QUEUE
DEFSTR(.LBLVL,3,17,18)		;LEVEL NUMBER OF THIS RESOURCE
DEFSTR(.LBACC,3,35,18)		;ACCESS BLOCK ADDRESS/-1/-2/-3
DEFSTR(.LBPUL,4,17,18)		;NUMBER OF RESOURCES IN POOL
DEFSTR(.LBAVL,4,35,18)		;NUMBER OF RESOURCES AVAILABLE
DEFSTR(.LBPWD,4,35,36)		;ENTIRE POOLED RESOURCE WORD
DEFSTR(.LBTIM,5,35,36)		;TIME-STAMP WHEN LOCK WAS LAST LOCKED
DEFSTR(.LBTXT,6,35,36)		;USER CODE/TEXT STRING
LBSIZE==6			;SIZE OF LOCK-BLOCK (MINUS TEXT)
O.TEXT==6			;OFFSET OF START OF TEXT


	SUBTTL	PARAMETER DEFINITIONS


;ENQ FUNCTION CODES:
.ENQBL==0	;ENQ BLOCK OPTION
.ENQAA==1	;ENQ ALLOCATE ONLY IF AVAILABLE
.ENQSI==2	;ENQ SOFTWARE INTERRUPT OFTION
.ENQMA==3	;ENQ MODIFY ACCESS


;DEQ FUNCTION CODES
.DEQDR==0	;DEQ RESOURCE
.DEQDA==1	;DEQ ALL
.DEQID==2	;DEQ REQUEST I.D.


;ENQC FUNCTION CODES:
.ENQCS==0	;RETURN STATUS
.ENQCG==1	;GET USER'S ENQ QUOTA
.ENQCC==2	;CHANGE USER'S ENQ QUOTA
.ENQCD==3	;DUMP DATA BASE



;MAXIMUM FUNCTION CODES ALLOWED
EQMXFC==3	;HIGHEST ENQ FUNCTION CODE
DQMXFC==2	;HIGHEST DEQ CODE
QCMXFC==3	;ENQC MAX CODE



;FLAGS DEFINED IN LEFT HALF OF 1ST WORD OF USER LOCK SPEC
EN%SHR==(1B0)	;THIS LOCK IS SHARABLE
EN%BLN==(1B1)	;BYPASS LEVEL NUMBER SEQUENCING

;FLAGS RETURNED TO USER IN LEFT HALF OF STATUS WORD FOR ENQC. UUO:
EN%QCE==(1B0)	;ERROR OCCURED 
EN%QCO==(1B1)	;THIS USER IS THE OWNER
EN%QCQ==(1B2)	;THIS USER HAS ISSUED AN ENQ FOR THIS RESOURCE
EN%QCX==(1B3)	;OWNER HAS EXCLUSIVE ACCESS

;FLAGS RETURNED ON DATA-BASE DUMP OPTION OF ENQC.:
EN%QCL==(1B0)	;THIS IS A LOCK BLOCK DUMP
EN%QCT==(1B2)	;THIS LOCK HAS TEXT
EN%QCB==(1B4)	;THIS PROCESS IS BLOCKED


;SOME VARIOUS DEFINITIONS
LOKSIZ==3	;SIZE OF LOCK SPEC IN RESOURCE BLOCK
HDRSIZ==2	;SIZE OF HEADER IN RESOURCE BLOCK
EQMXCH==:^D30	;MAXIMUM STRING SIZE


;FLAGS IN Q-BLOCK
QBOWNR==1B35	;THIS IS THE LOCK OWNER
QBEXCL==1B34	;EXCLUSIVE REQUEST
QBPSI==1B33	;USER WANTS INTERRUPT (CODE WAS 2)
QBWAIT==1B32	;USER WANTS TO BLOCK (CODE WAS 0)
QBCOD1==1B31	;FUNCTION CODE WAS %ENQAA
QBINVS==1B30	;THIS ENTRY IS "INVISIBLE"
QBLKBK==1B29	;THIS IS A LOCK-BLOCK (ALWAYS ZERO)


;FLAGS IN LOCK-BLOCK
LBTEXT==1B35	;THIS BLOCK HAS TEXT INSTEAD OF USER CODE
LBLKBK==1B29	;THIS IS A LOCK-BLOCK (Q-BLOCKS MUST HAVE THIS BIT ZERO)

	SUBTTL	ERROR CODES RETURNED TO USER

ENQRU%==1	;SOME RESOURCE(S) REQUEST WERE  UNAVAILABLE
ENQBP%==2	;ILLEGAL # OF RESOURCES REQUESTED (POOLED RESOURCES)
ENQBJ%==3	;BAD JOB NUMBER
ENQBB%==4	;BAD BYTE SIZE IN TEXT STRING
ENQST%==5	;STRING TOO LONG
ENQBF%==6	;BAD FUNCTION CODE
ENQBL%==7	;ILLEGAL ARGUMENT BLOCK LENGTH
ENQIC%==10	;ILLEGAL NUMBER OF LOCKS SPECIFIED
ENQBC%==11	;BAD CHANNEL NUMBER
ENQPI%==12	;OPERATOR/JACCT PRIVILEGE REQUIRED
ENQNC%==13	;NO CORE AVAILABLE
ENQFN%==14	;FILE NOT OPEN ON SPECIFIED CHANNEL, OR DEVICE NOT A DISK
ENQIN%==15	;INDIRECT OR INDEXED BYTE POINTER NOT ALLOWED
ENQNO%==16	;NO RESOURCES WERE OWNED
ENQLS%==17	;LEVEL SEQUENCING ERROR (LEVEL # TOO LOW)
ENQCC%==20	;CAN'T CHANGE ACCESS
ENQQE%==21	;QUOTA EXCEEDED
ENQPD%==22	;# OF RESOURCES IN POOL NOT SAME AS IN LOCK
ENQDR%==23	;DUPLICATE REQUEST FOR RESOURCE (LOCK ALREADY REQUESTED)
ENQNE%==24	;NOT ENQ'ED ON THIS LOCK
ENQLD%==25	;LEVEL # IN REQUEST DOES NOT MATCH LOCK
ENQED%==26	;ENQ/DEQ PRIVILEGES REQUIRED
	SUBTTL	ENQ--ENQ A RESOURCE REQUEST
;
;
;
	ENTRY	ENQ, DEQ, ENQC

ENQ:	PUSHJ	P,SAVE4##	;SAVE P1-P4
	AOS	%ENQTE##	;BUMP TOTAL NUMBER OF ENQ'S
	MOVEI	T2,EQMXFC	;SET UP MAX FUNCTION CODE
	PUSHJ	P,SETUP		;DO PRELIMINARY THINGS
	  POPJ	P,		;ERROR, GIVE ERROR CODE
	PUSHJ	P,CHKBLK	;CHECK OUT THE PARAMETER BLOCK
	  JRST	STOTAC##	;  ERROR RETURN
	HRRZ	T1,FCODE	;GET SAVED FUNCTION CODE
	CAIE	T1,.ENQMA	;IS THIS A "MODIFY ACCESS"?
	PUSHJ	P,PRVJC##	;OR, IS THIS GUY PRIVILEGED?
  	  JRST	ENQ1		;YES, DON'T CHECK QUOTAS FOR HIM
	HLRZ	T1,LOCKCT	;GET # OF LOCKS IN THIS REQUEST
	MOVE	T2,.PDEQQ##(W)	;AND QUOTA OF SAME
	TLON	T2,EQ.HBS##	;QUOTA ALREADY BEEN SET?
	HRR	T2,%ENQDF##	;NO, SET DEFAULT QUOTA
	MOVEM	T2,.PDEQQ(W)	;STORE QUOTA BACK AGAIN
	ADD	T1,REQCNT	;ADD # OF OUTSTANDING LOCKS
	CAILE	T1,(T2)		;TOO MANY REQUESTS?
	JRST	ENQER3		;YES, ABORT UUO

ENQ1:	PUSHJ	P,GETLOK	;GET A LOCK SPEC
	PUSHJ	P,DOIT		;PERFORM APPROPRIATE FUNCTION
	  JRST	BACKUP		;ERROR--UNWIND PREVIOUS STUFF
	PUSHJ	P,CHKCNT	;MORE LOCKS TO GO?
	  JRST	ENQ1		;YES, CYCLE BACK FOR MORE
	HRRZ	T2,FCODE	;GET STORED FUNCTION CODE
	CAIE	T2,.ENQMA	;IS IT "MODIFY ACCESS"?
	JRST	ENQ2		;NO, FINISH UP
	SKIPN	T1,NQERRF	;YES, WAS THERE AN ERROR?
	JRST	CPOPJ1##	;NO, GIVE SKIP RETURN
	JRST	STOTAC##	;RETURN ERROR CODE TO USER

;COME HERE WHEN ALL ENQ REQUESTS HAVE BEEN PERFORMED

ENQ2:	HLRZ	T1,P4		;GET SAVED ADDRESS OF LAST Q
	PUSHJ	P,QSKD		;SCHEDULE IT
	  SKIPA			;NOT ALL WERE FREE
	JRST	GUDXIT		;EVERYTHING WAS OK

;COME HERE IF ONE OR MORE OF THE RESOURCES WERE BUSY
	HLRZ	T1,P4		;GET ADDRESS OF LAST ENQ'ED BLOCK
	LOAD	T2,.QBFLG,(T1)	; AND IT'S FLAGS
	TRNE	T2,QBWAIT	;SHOULD HE BE BLOCKED?
	JRST	BLKHIM		;YES, GO BLOCK HIM
	MOVEI	T1,ENQRU%	;SET UP ERROR CODE
	TRNN	T2,QBPSI	;IS HE USING SOFT. INTERRUPT SYS?
	JRST	BACKUP		;NO, WE MUST RELEASE HIS REQUEST
	JRST	STOTAC##	;YES, JUST RETURN AN ERROR CODE TO HIM

;HERE TO BLOCK USER ON A FUNCTION CODE OF "0"
BLKHIM:	PUSH	P,P4		;SAVE POINTER TO LAST Q-BLOCK
	PUSH	P,NQERRF	;SAVE ERROR FLAG
	MOVEI	T1,0		;TELL HIBER WHAT TO DO
	PUSHJ	P,HIBER##	;HIBERNATE HIM
	  JFCL
	POP	P,NQERRF	;GET ERROR FLAG BACK
	POP	P,P4		;GET BACK P4
	JRST	ENQ2		;GO TRY AGAIN	




;COME HERE IF AN ENQ REQUEST FAILED FOR SOME REASON
; THE ENTIRE CHAIN OF REQUESTS (IF ANY) MUST
; BE REMOVED FROM THE QUEUES. THE POINTER TO THE
; LAST MEMBER OF THE CHAIN IS KEPT IN THE
; LEFT HALF OF P4.
;
;ON ENTRY, THE ERROR CODE IS IN T1
BACKUP:	HLRZ	T3,P4		;GET ADDRESS OF LAST Q'ED ENTRY
	JUMPE	T3,STOTAC##	;THERE WAS NONE--EXIT
	MOVEM	T1,NQERRF	;SAVE ERROR CODE
	SKIPA	T1,T3		;MOVE THIS ADDRESS TO USE AS PTR
BACK2:	MOVE	T1,T2		;GET ADDRESS OF LAST BLOCK
	LOAD	T2,.QBLQR,(T1)	;GET PREVIOUS Q-BLOCK'S LOCATION
	PUSHJ	P,DEQIT		;REMOVE THE CURRENT BLOCK
	  JFCL			;DON'T CARE IF Q IS FLUSHED
	CAIE	T2,(T1)		;HAVE WE GONE IN CIRCLE?
	JRST	BACK2		;NO
	MOVE	T1,NQERRF	;YES, GET ERROR CODE
	JRST	STOTAC##	;GIVE HIM ERROR CODE
	SUBTTL	SUBROUTINE TO PERFORM AN ENQ FUNCTION

;SUBROUTINE TO PERFORM ONE ENQ FUNCTION FOR A GIVEN RESOURCE.
;THIS ROUTINE (EXCEPT IN THE CASE OF A "MODIFY ACCESS")
; CHECKS THE LEVEL #, POOL COUNT, AND WHETHER THIS
; USER ALREADY HAS AN ENTRY QUEUED. IF ALL THESE CHECKS
; ARE OK, THE USER IS QUEUED FOR THE RESOURCE.
;
;ENTER:
;	P1-P4 SET UP BY GETLOK
;	PUSHJ	P,DOIT
;
;RETURNS:
;	+1	ERROR RETURN
;	+2	NORMAL RETURN
;
;CLOBBERS ALL T'S

DOIT:	HRRZ	T2,FCODE	;GET SAVED FUNCTION CODE
	CAIN	T2,.ENQMA	;IS IT A MODIFY ACCESS?
	JRST	DOFC3		;YES, DO SPECIAL STUFF
	LDB	T2,[POINT 9,P1,17]	;GET LEVEL #
	HRRE	T3,HILEVL	; AND THE STORED HIGHEST LEVEL #
	HRRZ	T4,P1		;GET TYPE OF REQUEST
	CAIN	T4,-3		;IS THIS A MONITOR REQUEST?
	HLRE	T3,HILEVL	;YES, USE HIGHEST MONITOR LEVEL #
	CAMLE	T2,T3		;IS THE LEVEL NUMBER OK?
	JRST	DOIT1		;YES
	TLNN	P1,EN%BLN	;NO, DOES HE WANT TO BYPASS IT?
	JRST	ENQER1		;NO, FLUSH HIM
	MOVEI	T2,ENQLS%	;YES, REMEMBER THAT THIS HAPPENED
	MOVEM	T2,NQERRF	;  IN THE ERROR FLAG
DOIT1:	PUSHJ	P,LOCKOK	;CHECK OTHER THINGS ABOUT THE LOCK
	  POPJ	P,		; ERROR FOUND
	HRRE	T2,P1		;GET CHANNEL #
	JUMPL	T2,DOIT2	;NOT A CHANNEL NUMBER
	MOVE	T2,USRJDA##(P1)	;GET DDB ADDRESS
	MOVE	T3,DEVMOD(T2)	;AND DEVICE BITS
	TLNE	T3,DVDSK	;IS THIS A DISK?
	TLNN	T2,LOOKB+ENTRB	; AND HAS THE FILE BEEN 'LOOKED-UP'...
	JRST	HDRER9		;NO, ERROR
DOIT2:	PUSHJ	P,CHPRIV	;DOES THIS GUY HAVE THE PRIVILEGES?
	  POPJ	P,		;NO, ERROR
	PUSHJ	P,CHLOCK	;DOES LOCK EXIST?
	  JRST	DOIT3		;NO, WE MUST CREATE IT
	LOAD	T2,.LBLVL,(T1)	;GET LEVEL #
	LDB	T3,[POINT 9,P1,17]	;AND NUMBER FOR NEW REQUEST
	TLNE	P1,EN%BLN	;DON'T CHECK IF HE DOESN'T CARE
	JRST	DOIT2A		;SKIP OVER CHECK
	CAIE	T2,(T3)		; SAME?
	JRST DOERR0		;NO, ERROR RETURN
DOIT2A:	HLRZ	T3,P3		;GET # IN POOL
	LOAD	T2,.LBPUL,(T1)	; AND CORRECT # IN POOL
	CAIE	T2,(T3)		;AND THEY THE SAME?
	JRST	DOERR2		;NO, POOL REQUEST ERROR
	PUSHJ	P,CHECKQ	;IS THIS GUY IN THE Q?
	  JRST	DOERR3		;YES, ERROR
	JRST	DOIT4		;NO, GO PUT HIM IN IT


;COME HERE IF THIS IS A NEW LOCK, TO SET UP THE APPROPRIATE
; BLOCKS AND LINKAGES
DOIT3:	MOVE	T1,EQTMP4	;GET HASH BACK AGAIN
	MOVEI	T2,LBLKBK	;FLAGS="LOCK-BLOCK"
	LDB	T3,[POINT 3,P2,2]
	CAIE	T3,5		;IS THIS A USER CODE?
	TRO	T2,LBTEXT	;NO, SET "TEXT" FLAG IN LOCK BLOCK
	PUSHJ	P,BLDLOK	;BUILD A LOCK BLOCK
	  POPJ	P,		;ERROR (NO CORE,BAD STRING,ETC.)
IFN FTTRACKS,<
	MOVEM	T1,LSTLOK	;REMEMBER LAST LOCK ADDRESS
>;END IFN FTTRACKS
	AOS	%ENQNQ##	;BUMP THE NUMBER OF QUEUES
	TLNE	P3,-1		;IF THIS IS A POOLED RESOURCE..
	AOS	%ENQNP##	;  BUMP THE TOTAL OF THEM TOO
DOIT4:	HLRZ	T2,P4		;GET MULTIPLE REQUEST ADDRESS
	SETZ	T3,
	SKIPL	P1		;IS THE "SHARED" BIT ON?
	MOVEI	T3,QBEXCL	;NO, SET EXCLUSIVE BIT IN BLOCK
	MOVE	T4,FCODE	;GET STORED FUNCTION CODE
	XCT	[TRO	T3,QBWAIT
		 TRO	T3,QBCOD1
		 TRO	T3,QBPSI](T4)	;SET BIT IN FLAG WORD
	PUSHJ	P,QHIM		;PUT HIM ON Q
	  JRST	DOERR6		;NO MORE CORE LEFT
IFN FTTRACKS,<
	MOVEM	T1,LASTQ	;REMEMBER LAST Q-BLOCK ADDRESS
>;END IFN FTTRACKS
	HRL	P4,T1		;SAVE ADDRESS OF THIS ENTRY
	PJRST	CPOPJ1##	;SKIP RETURN




;COME HERE IF USER WANTS TO MODIFY ACCESS
DOFC3:	PUSHJ	P,LOCKOK	;IS THE LOCK SPEC OK?
	  JRST	MARETN		;NO, ERROR FOUND
	PUSHJ	P,CHLOCK	;DOES THE LOCK EXIST?
	  JRST	DOERR4		;NO, GIVE USER ERROR
	PUSHJ	P,CHECKQ	;IS HE ALREADY IN Q?
	  SKIPA			;YES
	JRST	DOERR4		;NO, FLAG IT AS ERROR
	LOAD	T2,.QBFLG,(T1)	;FETCH FLAGS
	TRNN	T2,QBEXCL	;EXCLUSIVE?
	JRST	[TLNN	P1,EN%SHR	;NO, BUT IS HE ASKING FOR A CHANGE?
		 JRST	DOERR5		;YES--CAN'T CHANGE ACCESS TO EXCL
		 JRST	CPOPJ1]		;NO, IGNORE THIS LOCK
	TLNN	P1,EN%SHR	;DOES HE WANT TO MAKE IT SHARABLE?
	JRST	CPOPJ1##	;NO, IGNORE THIS LOCK
	TRZ	T2,QBEXCL	;YES, MAKE IT SHARABLE
	STOR	T2,.QBFLG,(T1)	;RESTORE FLAGS
	LOAD	T1,.QBLB,(T1)	;GET LOCK BLOCK ADDRESS
	PUSHJ	P,LOKSKD	;SCHEDULE THIS LOCK
	PJRST	CPOPJ1##	;RETURN FROM "DOIT"






	SUBTTL	DEQ--DEQ A RESOURCE REQUEST

DEQ:	PUSHJ	P,SAVE4##	;SAVE P1-P4
	AOS	%ENQTD##	;BUMP TOTAL OF DEQ'S SINCE RELOAD
	MOVEI	T2,DQMXFC	;SET MAX FUNCTION CODE
	PUSHJ	P,SETUP		;DO PRELIMINARY THINGS
	  POPJ	P,		;ERROR RETURN
	XCT	[JRST	DEQFC0	;DISPATCH TABLE FOR DEQ FUNCTION CODE
		 JRST	DEQFC1
		 JRST	DEQFC1](T3)
DEQFC1:	PUSHJ	P,FNDPDS##	;GET THIS GUY'S PDB
	HRRZ	T1,.PDEQJ##(W)	;GET START OF JOB Q
	JUMPE	T1,DERNJQ	;EXIT IF NO JOB Q
	HRRZ	T3,FCODE	;GET FUNCTION
	SETZM	DQFLAG		;ASSUME NO LOCKS
DEQ0:	LOAD	T2,.QBNJQ,(T1)	;GET NEXT JOB IN Q POINTER
	LOAD	T4,.QBRID,(T1)	;GET REQUEST ID
	CAME	T4,RBLOCK	;IF SAME AND CODE=2, DEQ
	CAIN	T3,.DEQDA	; OR IF CODE=1, THEN DEQ
	PUSHJ	P,DEQIT		;REMOVE CURRENT ONE FROM Q
	MOVE	T1,T2		;GET NEXT Q-ENTRY
	JUMPN	T2,DEQ0		;KEEP GOING IF THERE IS ONE..
	SKIPE	DQFLAG		;DID U DEQ ANYTHING?
	JRST	CPOPJ1##	;SKIP RETURN
	JRST	DERNJQ		;NO, ERROR



;COME HERE FOR A STANDARD DEQ (FUNCTION CODE=0)
; ENTIRE RESOURCE BLOCK MUST BE SCANNED
; AND CHECKED AND EACH LOCK MUST BE DEQ'ED.

DEQFC0:	PUSHJ	P,CHKBLK	;CHECK OUT THE USER'S PARAMETER BLOCK
	  JRST STOTAC##		;  ERROR

FC0.2:	PUSHJ	P,GETLOK	;GET A NEW LOCK
	PUSHJ	P,LOCKOK	;IS THE LOCK SPEC OK?
	  JRST	FC0ERR		;NO
	PUSHJ	P,CHPRIV	;ARE THE PRIVILEGES OK?
	  JRST	FC0ERR		;NO
	PUSHJ	P,CHLOCK	;FIND THIS LOCK IN DATA BASE
	  JRST	FCERR1		;DOESN'T EXIST
	PUSHJ	P,CHECKQ	;IS HE IN THE Q?
	  SKIPA			;YES
	JRST	FCERR1		;NO, ITS AN ERROR
	TLNN	P3,-1		;IS THIS A POOLED RESOURCE?
	JRST	FC0.3		;NO
	LOAD	T2,.QBNRP,(T1)	;GET NUMBER THIS GUY HAS OUT
	CAIN	T2,(P3)		;IS HE RETURNING ALL OF THEM?
	JRST	FC0.3		;YES, HE'S GIVING THEM ALL BACK
	CAIG	T2,(P3)		;IS HE RETURNING TOO MUCH?
	JRST	FCERR0		;YES, DON'T LET HIM DO IT
	SUBI	T2,(P3)		;COMPUTE NUMBER HE STILL HAS
	STOR	T2,.QBNRP,(T1)	;UPDATE HIS TOTAL
	LOAD	T1,.QBLB,(T1)	;GET LOCK-BLOCK
	LOAD	T2,.LBAVL,(T1)	;GET # OF FREE RESOURCES
	ADDI	T2,(P3)		;ADD THOSE HE IS RETURNING
	STOR	T2,.LBAVL,(T1)	;UPDATE # AVAILABLE
	PUSHJ	P,LOKSKD	;..AND SCHEDULE LOCK-BLOCK
	JRST	FC0.4		;DON'T DEQ THIS Q-BLOCK

FC0.3:	PUSHJ	P,DEQIT		;DEQ THIS ENTRY
	JRST	FC0.4		;DON'T SET ERROR FLAG
FCERR0:	SKIPA	T1,[ENQBP%]	;TRYING TO GIVE BACK TOO MUCH
FCERR1:	MOVEI	T1,ENQNE%	;NOT ENQ'ED ON THIS LOCK
FC0ERR:	HRRM	T1,NQERRF	;REMEMBER THAT THERE WAS AN ERROR
FC0.4:	PUSHJ	P,CHKCNT	;ARE THERE MORE LOCKS?
	  JRST	FC0.2		;YES, GO BACK
	SKIPN	T1,NQERRF	;WAS THERE AN ERROR?
	JRST	CPOPJ1##	;NO, SKIP RETURN
	JRST	STOTAC##	;GIVE ERROR RETURN
	SUBTTL	DEQ A PARTICULAR Q-ENTRY

;SUBROUTINE TO DEQ ONE Q-ENTRY
;
;CALL:
;	MOVE	T1,Q-ENTRY-ADDRESS
;	PUSHJ	P,DEQIT
;	RETURN HERE ALWAYS
;
;ON RETURN, ALL SCHEDULING FOR THE Q-ENTRY AND THE LOCK-BLOCK
; HAS BEEN DONE
;
;CLOBBERS:	NONE			;DQFLAG IS BUMPED ON EXIT


DEQIT:	AOS	DQFLAG		;REMEMBER THIS
	PUSHJ	P,SAVT##	;JUST FOR SAFETY
	LOAD	T3,.QBNJQ,(T1)	;GET NEXT JOB PTR
	LOAD	T2,.QBLJQ,(T1)	;AND LAST JOB PTR
	STOR	T3,.QBNJQ,(T2)	;RELINK JOB Q
	SKIPE	T3		;THIS MAY BE THE END OF THE JOB Q
	STOR	T2,.QBLJQ,(T3)	;MAKE NEXT ENTRY POINT TO LAST ONE
	LOAD	T2,.QBLQ,(T1)	;GET LAST Q-PTR
	LOAD	T3,.QBNQ,(T1)	; AND NEXT Q-ENTRY
	STOR	T2,.QBLQ,(T3)	;RELINK THESE Q'S
	STOR	T3,.QBNQ,(T2)	; SAME
	LOAD	T2,.QBLQR,(T1)	;GET NEXT LINKED REQUEST
	LOAD	T3,.QBNQR,(T1)	; POINTERS
	STOR	T2,.QBLQR,(T3)	;RELINK REQUEST Q
	STOR	T3,.QBNQR,(T2)
	MOVE	T2,T1		;PUT Q-BLOCK ADDRESS IN T2

	LOAD	T1,.QBLB,(T2)	;GET LOCK BLOCK ADDR
	LOAD	T3,.LBNQ,(T1)	;GET ADDR OF NEXT Q
	CAIN	T3,(T1)		;IS Q EMPTY?
	JRST	FLUSH		;YES, GO FLUSH IT

	LOAD	T3,.QBFLG,(T2)	;GET FLAGS AGAIN
	TRNN	T3,QBOWNR	;OWNER?
	JRST	FLSHQ		;NO, GO FLUSH IT
	LOAD	T3,.QBNRP,(T2)	;YES, GET ALLOCATION
	LOAD	T4,.LBAVL,(T1)	;AND # AVAILABLE
	ADD	T3,T4		;COMBINE THEM
	STOR	T3,.LBAVL,(T1)	;PUT BACK IN POOL
	JRST	FLSHQ		;NOW, GO AND FLUSH Q
;COME HERE TO FLUSH A LOCK BLOCK AND A Q BLOCK FROM THE DATA BASE

FLUSH:	LOAD	T3,.LBNHS,(T1)	;GET NEXT HASH PTR
	LOAD	T4,.LBLHS,(T1)	; AND LAST HASH PTR
	STOR	T3,.LBNHS,(T4)	;RELINK THEM
	STOR	T4,.LBLHS,(T3)	; SO THIS BLOCK DISAPPEARS
	PUSH	P,T2		;SAVE ADDRESS OF Q-BLOCK
	MOVE	T2,T1		;GET LOCK BLOCK ADDR
	LOAD	T3,.LBPUL,(T1)	;GET NUMBER IN RESOURCE POOL
	SKIPE	T3		;IS IT POOLED?
	SOS	%ENQNP##	;YES, DECREMENT THAT TOTAL
	LOAD	T1,.LBLEN,(T2)	;GET LENGTH
	PUSHJ	P,GIVWDS##	;GIVE IT BACK
	POP	P,T2		;GET Q-BLOCK LOCATION BACK
	SOSA	%ENQNQ##	;REDUCE NUMBER OF QUEUES AND DON'T RE-SCHED

FLSHQ:	PUSHJ	P,RSKED		;DO RE-SCHEDULING FOR THIS Q-BLOCK
	MOVEI	T1,QBSIZE	;SET UP SIZE
	PJRST	GIVWDS##	;FREE UP THIS SPACE NO RETURN
	SUBTTL	ENQC QUEUE CONTROLLER UUO

;THIS UUO HAS FOUR FUNCTIONS:
;	0. RETURN STATUS OF LIST OF RESOURCES
;	1. RETURN USER'S LOCK QUOTA
;	2. SET USER'S LOCK QUOTA (PRIVILEGED)
;	3. DUMP OUT QUEUE STRUCTURE INTO USER BUFFER
;FOR OPTION 0, THREE WORDS ARE RETURNED FOR EACH LOCK SPECIFIED BY THE
; USER. THE 1ST WORD HAS THE FOLLOWING FORMAT:
;
;	B0	ERROR BIT 
;	B1	THIS USER IS THE OWNER OF THE LOCK
;	B2	THIS USER HAS ISSUED AN ENQ FOR THE LOCK
;	B3	THE OWNER OF THE LOCK HAS EXCLUSIVE ACCESS
;	B9-17	LEVEL NUMBER OF RESOURCE
;	B18-35	JOB NUMBER OF OWNER/ERROR CODE 
;			THE JOB NUMBER OF THE OWNER MAY BE
;			ONLY ONE OF MANY OWNERS IF THE
;			LOCK IS SHARED.
;
;THE SECOND WORD IS A 36-BIT TIME-STAMP WHICH REPRESENTS
;	THE TIME AT WHICH THE RESOURCE WAS LAST
;	"ALLOCATED". THIS PROVIDES A METHOD OF DETERMINING
;	IF A USER HAS HELD THE RESOURCE FOR AN EXCESSIVE
;	AMOUNT OF TIME.
;
;THE THIRD WORD HAS THE REQUEST-ID IN THE RIGHT HALF.
;IF BIT 2 IN WORD 1 IS ON, THIS IS THE CALLER'S ID
;OTHERWISE, IT'S THE OWNER'S ID.
;
;IF THE LOCK HAS NO CURRENT OWNER, THE STATUS WORD WILL HAVE
; -1 IN THE RIGHT HALF

ENQC::	PUSHJ	P,SAVE4		;SAVE P1-P4
	MOVEM	M,QSKDT		;SAVE ADDRESS OF AC FOR LATER
	MOVEI	T2,QCMXFC	;SET UP MAX FUNCTION CODE
	PUSHJ	P,SETUP		;DO STANDARD STUFF
	  POPJ	P,		;ERROR IN FUNCTION CODE
	XCT	[JRST QC0	; DISPATCH TABLE FOR ENQC
		 JRST QC1
		 JRST QC2
		 JRST QC3](T3)

QC0:	PUSHJ	P,CHKBLK	;CHECK LEGALITY OF RESOURCE BLOCK
	  JRST	STOTAC##	;  ERROR FOUND--ABORT
	AOS	QSKDT		;GET ADDRESS OF AC BACK
	HRR	M,QSKDT		;GET AC+1
	PUSHJ	P,GETWDU##	;GET CONTENTS OF AC+1
	SOS	T1		;PUTWD1 BUMPS IT
	HRRZM	T1,QSKDT	;SAVE IT
QC0.0:	PUSHJ	P,GETLOK	;GET A LOCK
	PUSHJ	P,LOCKOK	;IS THE LOCK SPEC OK?
	  JRST	QCERR		;NO, RETURN ERROR CODE
	PUSHJ	P,CHLOCK	;DOES THIS QUEUE EXIST?
	  JRST	[MOVEI P3,-1	;SET STATUS=-1
		 SETZB P4,P2	;CLEAR TIME-STAMP
		 JRST TELHIM]
	PUSHJ	P,CHECKQ	;YES, BUT AM I IN IT?
	  JRST	GOTHIM		; YES
	SETZB	P3,P4		;CLEAR AC
	LOAD	T1,.LBNQ,(T3)	;GET FIRST Q-BLOCK IN QUEUE (T3=LOCK)
	LOAD	P2,.QBRID,(T1)	;REQUEST ID
	LOAD	T2,.QBFLG,(T1)	;AND FLAGS FOR THIS ENTRY
	TRNE	T2,QBOWNR	;IS HE THE OWNER?
	JRST	GOTHM2		;YES
	MOVEI	P3,-1		;SET RH OF STATUS TO -1
	JRST	TELLVL		;AND GO GET LEVEL #
QCERR:	HRLI	T1,EN%QCE	;SET ERROR BIT IN STATUS WORD
	MOVE	P3,T1		;MOVE ENTIRE WORD TO P3
	HRRM	P3,NQERRF	;REMEMBER THAT AN ERROR OCCURED
	SETZB	P2,P4		;CLEAR OTHER STUFF
	JRST	TELHIM		;AND GIVE IT BACK TO USER
;COME HERE WHEN THE CURRENT JOB IS IN THE QUEUE
GOTHIM:	MOVSI	P3,EN%QCQ	;TELL HIM HE'S IN THE QUEUE
	LOAD	T2,.QBFLG,(T1)	;GET HIS FLAG'S
	LOAD	P2,.QBRID,(T1)	;GET REQUEST ID.
	TRNE	T2,QBOWNR	;IS HE THE OWNER?
	JRST	GOTHM1		;YES, GO AND SET THE BIT
	LOAD	T1,.QBLB,(T1)	;NO, GO AND FIND THE OWNER
	LOAD	T1,.LBNQ,(T1)	;GET FIRST ENTRY IN QUEUE
	LOAD	T2,.QBFLG,(T1)	;GET Q-BLOCK FLAGS
	TRNN	T2,QBINVS	;IS IT INVISIBLE?
	JRST	GOTHM2		;NO
	HRRI	P3,-1		;YES, TELL USER THAT THERE IS NO OWNER
	JRST	TELLVL
GOTHM1:	TLO	P3,EN%QCO	;TELL HIM HE'S THE OWNER
GOTHM2:	TRNE	T2,QBEXCL	;EXCLUSIVE ACCESS?
	TLO	P3,EN%QCX	;YES, SET THE BIT
	LOAD	T2,.QBJOB,(T1)	;GET JOB NUMBER
	HRR	P3,T2		;MOVE INTO STATUS WORD
TELLVL:	LOAD	T1,.QBLB,(T1)	;GET LOCK-BLOCK ADDRESS
	LOAD	T2,.LBLVL,(T1)	; AND LEVEL #
	DPB	T2,[POINT 9,P3,17]	;STICK IT IN
	LOAD	P4,.LBTIM,(T1)	;GET TIME-STAMP
TELHIM:	MOVE	T1,P3		;MOVE STATUS WORD
	HRR	M,QSKDT		;GET STATUS BLOCK
	PUSHJ	P,PUTWD1##	;GIVE WORD TO USER
	MOVE	T1,P4		;GET TIME-STAMP
	PUSHJ	P,PUTWD1##	;PUT IT OUT
	MOVE	T1,P2		;GET ID
	PUSHJ	P,PUTWD1##	;PUT IT OUT
	HRRM	M,QSKDT		;PUT IT BACK
	PUSHJ	P,CHKCNT	;MORE LOCKS TO GO?
	  JRST	QC0.0		;YES
	SKIPN	T1,NQERRF	;WAS THERE AN ERROR?
	JRST	CPOPJ1##	;NO, EXIT
	JRST	STOTAC##	;YES, RETURN ERROR CODE
;COME HERE TO PROCESS ENQC FUNCTION CODE 1 (RETURN USER'S QUOTA)
;
QC1:	PUSHJ	P,GETQUO	;GET CURRENT QUOTA
	  JRST	STOTAC##	; ERROR
	TLZ	T1,-1		;CLEAR PDB FLAGS
	JRST	GUDXT2		;SKIP RETURN WITH QUOTA IN AC


;COME HERE TO SET USER'S QUOTA
;
QC2:	TLZ	M,400000	;FOR PRVBIT
	MOVSI	T1,JP.POK
	PUSHJ	P,PRVBIT##	;AM I [1,2] OR JACCT?
	  TLOA	M,400000	;YES, IT'S OK
	JRST	HDRERC		;NO, EXIT
	PUSHJ	P,GETQUO	;GET CURRENT QUOTA
	  JRST	STOTAC##	; ERROR
	TLO	T1,EQ.HBS##	;REMEMBER THAT IT'S BEEN SET
	HLR	T1,P1		;GET NEW QUOTA
	MOVEM	T1,.PDEQQ##(W)	;STORE IT AWAY
	JRST	CPOPJ1##	;.AND EXIT



;SUBROUTINE TO RETURN USER'S QUOTA
;
;CALL:
;	PUSHJ	P,GETQUO
;	 ERROR RETURN
;	NORMAL RETURN
;
;ON RETURN, T1 = QUOTA
;	    P1 = HEADER WORD OF EFFECTIVE ADDRESS OF UUO (NEW QUOTA,,JOB #)
;
GETQUO:	PUSHJ	P,GETWDU##	;GET FIRST WORD
	MOVE	P2,J		;SAVE CURRENT JOB NUMBER
	MOVE	P1,T1		; AND HEADER WORD
	HRR	J,P1		;GET NEW JOB NUMBER
	PUSHJ	P,FNDPDB##	;FIND USER'S PDB
	  JRST	QCERR1		;BAD JOB NUMBER
	MOVE	T1,.PDEQQ##(W)	 ;FETCH USER'S QUOTA
	MOVE	J,P2		;RESTORE CURRENT JOB NUMBER
	JRST	CPOPJ1##	;SKIP RETURN
	SUBTTL	DATA-STRUCTURE DUMP UTILITY

;THIS OPTION OF THE ENQC. UUO DUMPS THE ENTIRE QUEUE STRUCTURE
; INTO A USER-SPECIFIED PARAMETER BLOCK. THIS FUNCTION IS
; RESTRICTED TO PEEK/SPY PRIVILEGE  AND SHOULD BE USEFUL ONLY IN
; EXCEPTION CIRCUMSTANCES.
;
QC3:	MOVSI	T1,PVSPYM	;GET SPY BIT
	PUSHJ	P,PRVBIT##	;CAN HE SPY?
	  SKIPA			;YES, LET HIM THRU
	JRST	HDRERC		;NO, FLUSH THIS REQUEST
	HRRZ	T1,RBLOCK	;GET ADDRESS OF HIS BLOCK
	PUSHJ	P,GETWDU##	;GET LENGTH OF BLOCK
	SOJL	T1,QCERR2	;LENGTH MUST BE POSITIVE
	MOVEM	T1,EQTMP1	;SAVE IT FOR LATER
	MOVEI	P1,HSHLEN##-1	;INIT POINTER TO HASH TABLE

;GET THE NEXT ENTRY IN THE HASH TABLE
QC3.1:	HRRZ	P2,HSHTAB##(P1)	;GET THIS ENTRY
	CAIE	P2,HSHTAB##(P1)	;IS IT EMPTY?
	JRST	QC3.2		;NO, GO GET LOCK
QC3.1A:	SOJGE	P1,QC3.1	;MORE?
PUTEND:	SETO	T1,		;YES, SET UP INSERT -1 AT END
	SOSL	EQTMP1		;IS THERE ROOM?
	PUSHJ	P,PUTWD1##	;YES, DO IT
	JRST	CPOPJ1##	;EXIT FROM UUO
;COME HERE TO SEARCH A PARTICULAR CHAIN IN THE HASH TABLE
;
;P1- ENTRY IN HASH TABLE
;P2- LOCK BLOCK ON CHAIN

QC3.1B:	LOAD	P2,.LBNHS,(P2)	;GET NEXT LOCK-BLOCK ON CHAIN
	CAIN	P2,HSHTAB##(P1)	;BACK TO HASH TABLE?
	JRST	QC3.1A		;YES
QC3.2:	LOAD	T1,.LBLEN,(P2)	;GET LENGTH OF LOCK BLOCK
	SUBI	T1,LBSIZE-2	;FIND LENGTH OF STATUS ENTRY
	CAMLE	T1,EQTMP1	;IS THERE ROOM IN BLOCK?
	JRST	PUTEND		;NO, PUT END MARKER IN IT
	EXCH	T1,EQTMP1	;YES, UPDATE LENGTH LEFT
	SUBM	T1,EQTMP1	;...
	LOAD	T1,.LBACC,(P2)	;GET ACCESS BLOCK ADDR
	LOAD	T2,.LBFLG,(P2)	;..AND FLAGS
	LOAD	T3,.LBLVL,(P2)	;..AND LEVEL
	HRL	T1,T3		;PUT LEVEL NUMBER IN WORD
	TLO	T1,EN%QCL	;THIS IS A LOCK BLOCK
	TRNE	T2,LBTEXT	;DOES IT HAVE TEXT?
	TLO	T1,EN%QCT	;YES, SET THE BIT
	PUSHJ	P,PUTWD1##	;STORE IT AWAY
	LOAD	T1,.LBPWD,(P2)	;GET POOLED LOCK WORD
	PUSHJ	P,PUTWD1##	;STORE IT
	LOAD	T1,.LBTIM,(P2)	;GET TIME-STAMP
	PUSHJ	P,PUTWD1##	;GIVE IT TO USER
	LOAD	P3,.LBLEN,(P2)	;GET LENGTH BACK AGAIN
	SUBI	P3,LBSIZE	;FIND SIZE OF TEXT/CODE
	MOVEI	P4,O.TEXT(P2)	;SET UP POINTER TO TEXT
QC3.4:	MOVE	T1,(P4)		;GET WORD OF TEXT
	PUSHJ	P,PUTWD1##	;STORE IT
	AOS	P4		;BUMP POINTER
	SOJN	P3,QC3.4	;MORE?
	LOAD	P3,.LBNQ,(P2)	;GET 1ST Q-BLOCK

;FALL THRU TO NEXT PAGE...
;COME HERE TO DUMP OUT A Q-BLOCK ENTRY
QC3.4A:	CAMN	P3,P2		;ARE WE BACK AT LOCK-BLOCK?
	JRST	QC3.1B		;YES, GET NEXT LOCK IN CHAIN
	MOVE	T1,EQTMP1	;GET LENGTH LEFT
	SUBI	T1,QBSIZE	;UPDATE IT
	JUMPL	T1,PUTEND	;JUMP IF NO ROOM
	MOVEM	T1,EQTMP1	;YES
	LOAD	T1,.QBJOB,(P3)	;GET JOB NUMBER
	LOAD	T2,.QBFLG,(P3)	;AND FLAGS
	TRNN	T2,QBOWNR	;IS HE THE OWNER?
	JRST	QC3.5		;NO
	TLO	T1,EN%QCO	;YES, SET BIT
	JRST	QC3.6		;KEEP GOING
QC3.5:	TRNE	T2,QBWAIT	;NOT OWNER--IS HE WAITING?
	TLO	T1,EN%QCB	;YES, SET BLOCKED BIT
QC3.6:	TRNE	T2,QBEXCL	;EXCLUSIVE?
	TLO	T1,EN%QCX	;YES, SET IT
	PUSHJ	P,PUTWD1##	;STORE WORD
	LOAD	T1,.QBRID,(P3)	;GET REQUEST ID
	LOAD	T2,.LBPUL,(P2)	;GET LOCK-BLOCK POOL COUNT
	LOAD	T3,.QBGRP,(P3)	;GET GROUP #
	SKIPE	T2		;IS IT'S A POOLED RESOURCE,
	LOAD	T3,.QBNRP,(P3)	;GET # HE WANTS
	HRL	T1,T3		;FORM WORD
	PUSHJ	P,PUTWD1##	;GIVE IT TO USER
	LOAD	P3,.QBNQ,(P3)	;GET NEXT Q-BLOCK
	JRST	QC3.4A		;GO CHECK IF WE ARE BACK AT LOCK
;SUBROUTINE TO VALIDATE THE HEADER WORD AND CHECK ALL
; ENTRIES IN THE RESOURCE BLOCK FOR ADDRESS CHECK, ETC.
;
;CALL:
;	PUSHJ	P,CHKBLK
;	 HERE IF ERROR DISCOVERED (ERROR CODE IN T1)
;	NORMAL RETURN
;
;
;CLOBBERS:	T1-T4,P1-P3
;

CHKBLK:	HRRZ	T1,RBLOCK	;GET PARAMETER BLOCK ADDRESS
	PUSHJ	P,GETWDU##	;GET THE HEADER WORD
	MOVE	T3,T1		;SAVE # OF LOCKS..
	HRRI	T3,1		;..AS A COUNTER
	MOVEM	T3,LOCKCT	;..FOR USE LATER
	HLRE	T3,T1		;GET # OF LOCKS
	JUMPLE	T3,HDRERB	;BAD LOCK COUNT
	IMULI	T3,LOKSIZ	;COMPUTE WHAT LENGTH SHOULD
	ADDI	T3,HDRSIZ	; BE
	CAIE	T3,(T1)		;IS IT RIGHT?
	JRST	BFERR		;NO, FLAG IT

	PUSHJ	P,FNDPDS##	;FIND HIS PDB
	PUSHJ	P,GETLVL	;GET LEVEL # OF HIGHEST LOCK
	MOVEM	T1,HILEVL	;SAVE IT FOR USE LATER
	PUSHJ	P,GETWD1##	;GET THE REQUEST ID
	MOVEM	T1,REQID	;SAVE IT FOR LATER
HDRLUP:	PUSHJ	P,GETLOK	;GET A LOCK SPEC
HDR3:	LDB	T2,[POINT 3,P2,2]	;GET ID CODE FROM PTR/CODE
	CAIN	T2,5		;IS THIS A USER CODE?
	JRST	BYTCK6		;YES, IGNORE THIS ONE
	MOVE	T1,P2		;ARGUMENT TO CKSTR
	PUSHJ	P,CKSTR##	;MAKE SURE STRING IS IN CORE AND LEGAL
	  JRST	HDRER2		;ADDRESS CHECK
	MOVE	P2,T1		;BYTE POINTER TO STRING TO P2
IFN FTKA10,<
	TLO	P2,U		;SET RELOCATION IN POINTER FOR KA-10
>
BYTCK6:	PUSHJ	P,CHKCNT	;UPDATE LOCK COUNT AND CHECK IT
	JRST	HDRLUP		;THERE'S MORE LOCKS TO GO
	HRRI	T1,1		;INITIALIZE COUNTER OF USED LOCKS FOR LATER
	HRRM	T1,LOCKCT	;STORE IT IN LOCK-COUNT WORD
	PJRST	CPOPJ1##	;SKIP RETURN

	SUBTTL	QUEUE SCHEDULING SUBROUTINES


;SUBROUTINE TO INITIATE SCHEDULING AFTER ONE DEQ CALL
;
;CALL:
;	MOVE	T1,LOCK-BLOCK-ADDR
;	MOVE	T2,Q-BLOCK-ADDR
;	PUSHJ	P,RSKED
;	RETURN HERE ALWAYS
;
;

RSKED:	PUSH	P,T2		;SAVE Q-BLOCK ADDRESS
	PUSH	P,T1		;SAVE LOCK-BLOCK ADDRESS
	LOAD	T1,.QBNQR,(T2)	;GET NEXT REQUEST
	CAIN	T1,(T2)		;IS IT A MULTIPLE REQUEST?
	JRST	RSKED3		;NO, DON'T RESCHEDULE THE Q-ENTRY
	MOVEM	T2,EQTMP4	;SAVE Q-BLOCK ADDRESS
	PUSHJ	P,QSKD		;SCHEDULE THIS Q-BLOCK
	  JRST	RSKED3		;GO ON AND SCHEDULE LOCK
	MOVE	T2,EQTMP4	;GET Q-BLOCK ADDRESS BACK
	LOAD	T4,.QBFLG,(T2)	;GET FLAGS OF OLD REQUEST
	JUMPN	T1,RSKED1	;JUMP IF SCHEDULER DID SOMETHING
	TRNE	T4,QBOWNR	;WAS HE AN OWNER?
	JRST	RSKED3		;YES, DON'T GIVE AN INTERRUPT

RSKED1:
IFN FTPI,<
	LOAD	T1,.QBNQR,(T2)	;GET NEXT REQUEST 
	TRNN	T4,QBPSI	;DOES THIS USER EXPECT AN INTERRUPT?
	JRST	RSKED2		;NO, HE IS BLOCKED
	PUSH	P,J		;SAVE J
	LOAD	J,.QBJOB,(T2)
	PUSHJ	P,GENPSI	;YES, GIVE HIM ONE
	POP	P,J		;RESTORE J
	JRST	RSKED3		; AND GO ON TO SCHEDULE LOCK
>;END OF IFN FTPI
RSKED2:	LOAD	T1,.QBJOB,(T2)	;GET HIS JOB NUMBER
	PUSHJ	P,WAKJOB##	;GO AND WAKE HIM UP
RSKED3:	POP	P,T1		;GET LOCK-BLOCK BACK AGAIN
	PUSHJ	P,LOKSKD	;SCHEDULE LOCK BLOCK
	POP	P,T2		;GET Q-BLOCK ADDRESS BACK
	POPJ	P,



;SUBROUTINE TO SCHEDULE ONE Q REQUEST CHAIN
;
;CALL:
;	MOVE	T1,Q-BLOCK-ADDR
;	PUSHJ	P,QSKD
;	  RETURN HERE IF REQUEST NOT LOCKED
;	HERE IF FULLY LOCKED AND
;		T1 = 0  IF ALREADY LOCKED BEFORE THIS CALL
;		T1 =-1  IF THIS CALL DID THE LOCKING
;
;

QSKD:	SETZM	QSKDF		;ASSUME LOCK ALREADY LOCKED
	MOVEM	T1,QSKDQ	;SAVE THE ADDRESS OF THIS Q-BLOCK
	PUSHJ	P,SETINV	;SET INVISIBLE BITS
	  JRST	QSKD0		;GO MAKE SCHEDULING PASS
	JRST	QSKD3		;LOCK IS ALREADY LOCKED

QSKD0:	MOVE	T1,QSKDQ	;GET ADDR OF THIS BLOCK AGAIN
QSKD1:	MOVEM	T1,QSKDT	;SAVE IT TEMPORARILY
	LOAD	T2,.QBGRP,(T1)	;GET GROUP NUMBER
	MOVEM	T2,QSKDG	;SAVE IT
	LOAD	T2,.QBFLG,(T1)	;GET FLAGS
	TRNE	T2,QBOWNR+QBINVS  ;IS THIS THE OWNER OR IS IT INVISIBLE?
	JRST	QSKD2		;YES, CONTINUE SCANNING SIDEWAYS
	LOAD	T3,.QBNRP,(T1)	;GET # OF RESOURCES WANTED

CHKLK1:	LOAD	T1,.QBLQ,(T1)	;GET LAST BLOCK ON Q
	MOVE	T2,QSKDT	;GET Q-BLOCK ADDR
	LOAD	T2,.QBFLG,(T2)	;GET FLAGS
	LOAD	T4,.QBFLG,(T1)	;AND FLAGS
	TRNE	T4,LBLKBK	;IS THIS A LOCK BLOCK?
	JRST	CHKLK2		;YES, WE ARE AT TOP OF QUEUE
	TRNE	T4,QBINVS	;IS IT INVISIBLE?
	JRST	CHKLK1		;YES, IGNORE IT ENTIRELY
	TRNN	T4,QBEXCL	;IS THIS AN EXCLUSIVE REQUEST?
	TRNE	T2,QBEXCL	;OR IS ORIGINAL REQUEST EXCLUSIVE?
	JRST	QSKD4		;YES TO EITHER MEANS NOT LOCKABLE
	LOAD	T2,.QBGRP,(T1)	;GET GROUP NUMBER
	CAME	T2,QSKDG	;SAME GROUP AS OWNER?
	JRST	QSKD4		;NO, STOP HERE
	JRST	CHKLK1		;LOOP BACK UNTIL AT LOCK BLOCK

;QSKD CONTINUES ON NEXT PAGE...
CHKLK2:	LOAD	T4,.LBAVL,(T1)	;GET # OF RESOURCES AVAILBLE
	SUB	T4,T3		;SUBTRACT REQUEST
	JUMPL	T4,CPOPJ##	;NOT ENOUGH AVAILABLE
	STOR	T4,.LBAVL,(T1)	;STORE BACK UPDATED TOTAL
	MOVE	T3,QSKDT	;GET BACK ADDR OF Q-BLOCK
	TRO	T2,QBOWNR	;SET THE OWNER FLAG
	STOR	T2,.QBFLG,(T3)	;STORE THE UPDATED FLAGS
	LOAD	T2,.QBNQ,(T3)	;NOW MOVE THIS Q-BLOCK TO THE HEAD
	LOAD	T4,.QBLQ,(T3)	;  OF THE Q FOR THIS LOCK
	STOR	T2,.QBNQ,(T4)	;FIRST, REMOVE IT FROM THE Q
	STOR	T4,.QBLQ,(T2)	;...
	LOAD	T2,.LBNQ,(T1)	;NOW ADD IT TO THE START OF THE Q
	STOR	T3,.QBLQ,(T2)	; PTR BACK TO Q-BLOCK FROM Q-2
	STOR	T3,.LBNQ,(T1)	; PTR TO Q-BLOCK FROM LOCK-BLOCK
	STOR	T2,.QBNQ,(T3)	; PTR TO SECOND Q-BLOCK
	STOR	T1,.LBLQ,(T3)	; PTR BACK TO LOCK-BLOCK
	MOVE	T2,DATE##	;GET DATE-TIME
	STOR	T2,.LBTIM,(T1)	;PUT IN LOCK-BLOCK
	MOVE	T1,QSKDQ	;GET BACK ORIGINAL Q-BLOCK ADDR
	SETOM	QSKDF		;MARK THAT A LOCK WAS LOCKED
	PUSHJ	P,SETINV	;SET INVISIBILITY
	  JRST	QSKD0		;NOT FULLY LOCKED YES, TRY AGAIN
	JRST	QSKD3		;LOCK IS FULLY LOCKED, GIVE O RETURN

QSKD2:	MOVE	T2,QSKDT	;GET Q-BLOCK ADR OF PRESENT Q-BLOCK
	LOAD	T1,.QBNQR,(T2)	;GET NEXT Q-BLOCK IN THIS REQUEST
	CAME	T1,QSKDQ	;ARE WE BACK AT THE Q-BLOCK YET?
	JRST	QSKD1		;NO, GO CHECK IF THIS Q LOCKED
QSKD3:	MOVE	T1,QSKDF	;GET FLAG
	PJRST	CPOPJ1##	;SKIP RETURN
QSKD4:	MOVE	T1,QSKDQ	;RESTORE T1
	POPJ	P,		;FAIL RETURN
;SUBROUTINE TO SET INVISIBLE BITS FOR A Q-BLOCK ENTRY
;
;CALL:	
;	MOVE	T1,Q-BLOCK-ADDR
;	PUSHJ	P,SETINV
;	  HERE IF NOT FULLY LOCKED YET
;	HERE IF REQUEST IS NOW FULLY LOCKED
;
;CLOBBERS:	T1-T4
;
SETINV:	MOVSI	T2,1		;INIT LEVEL NUMBER SCANNER
	MOVEM	T2,EQTMP2	;SAVE LEVEL NUMBER FOR LATER
	MOVEM	T1,EQTMP1	;SAVE Q-BLOCK ADDR TOO
SETIN1:	LOAD	T2,.QBLB,(T1)	;GET ADDR OF LOCK BLOCK
	LOAD	T4,.LBLVL,(T2)	;AND ITS LEVEL
	LOAD	T3,.QBFLG,(T1)	;  AND FLAGS FOR Q-BLOCK
	TRNE	T3,QBOWNR	;IS THIS THE OWNER OF THE LOCK?
	JRST	SETIN2		;YES
	CAMG	T4,EQTMP2	;NO, IS THIS A NEW LOW VALUE?
	MOVEM	T4,EQTMP2	;YES, REMEMBER LOWEST NON-LOCKED VALUE
SETIN2:	LOAD	T1,.QBNQR,(T1)	;GET NEXT Q-BLOCK IN THIS REQUEST
	CAME	T1,EQTMP1	;ARE WE BACK AT STARTING POINT?
	JRST	SETIN1		;NO, LOOP BACK FOR MORE Q-BLOCKS
	MOVE	T2,EQTMP2	;GET LEVEL NUMBER
	TLNE	T2,-1		;SEE IF AN UNLOCKED WAS SEEN
	JRST	CPOPJ1##	;NONE SEEN, LOCK IS FULLY LOCKED

SETIN3:	LOAD	T2,.QBLB,(T1)	;GET LOCK ADDR
	LOAD	T4,.LBLVL,(T2)	;AND ITS LEVEL
	LOAD	T3,.QBFLG,(T1)	;GET Q-BLOCK'S FLAGS
	CAMG	T4,EQTMP2	;IS LEVEL ABOVE LOWEST UNLOCKED LEVEL?
	TRZA	T3,QBINVS	;NO, MAKE THIS Q-BLOCK VISIBLE
	TRO	T3,QBINVS	;YES, MAKE IT INVISIBLE
	STOR	T3,.QBFLG,(T1)	;STORE FLAGS BACK
	LOAD	T1,.QBNQR,(T1)	;GET ADDR OF Q-BLOCK IN REQUEST
	CAME	T1,EQTMP1	;HAVE WE SEEN ALL Q-BLOCKS?
	JRST	SETIN3		;NO, LOOP BACK FOR MORE
	POPJ	P,		;NON-SKIP RETURN
	SUBTTL	LOCK SCHEDULING SUBROUTINE

;SUBROUTINE TO SCHEDULE ONE ENTIRE QUEUE FOR A GIVEN LOCK
;
;CALL:
;	MOVE	T1,LOCK-BLOCK-ADDR
;	PUSHJ	P,LOKSKD
;	RETURN HERE ALWAYS
;
;ON RETURN, ALL PROCESSES HAVE BEEN INTERRUPTED, OR WOKEN UP
;WHICH HAD RESOURCES THAT HAD BECOME AVAILABLE
;

LOKSKD:	MOVEM	T1,LKTMP1	;SAVE ADDRESS OF LOCK
	MOVEM	T1,LKTMP2	;INIT Q-BLOCK ADDRESS REGISTER
	LOAD	T2,.LBAVL,(T1)	;GET NUMBER AVAILABLE
	MOVEM	T2,LKTMP3	;SAVE IT
LOKSK1:	LOAD	T1,.LBNQ,(T1)	;GET ADDR OF NEXT Q-BLOCK FOR LOCK
	CAMN	T1,LKTMP1	;BACK TO THE LOCK-BLOCK YET?
	POPJ	P,		;YES, THRU
	MOVEM	T1,LKTMP2	;SAVE THIS ADDRESS
	LOAD	T2,.QBFLG,(T1)	;GET FLAGS FOR THIS ENTRY
	TRNE	T2,QBINVS	;IS IT INVISIBLE?
	JRST	LOKSK1		;YES, IGNORE IT
	TRNE	T2,QBOWNR	;IS HE THE OWNER?
	JRST	LOKSK0		;YES
	LOAD	T2,.QBNRP,(T1)	;GET NUMBER REQUESTED
	MOVE	T3,LKTMP3	;GET NUMBER AVAILABLE
	SUB	T3,T2		;GET DIFFERENCE
	MOVEM	T3,LKTMP3	;UPDATE # AVAILABLE
	JUMPL	T3,CPOPJ##	;LEAVE IF SUPPLY EXAUSTED
LOKSK0:	PUSHJ	P,QSKD		;SCHEDULE THIS Q-BLOCK
	  JRST	LOKSK2		;IT WASN'T LOCKED
	JUMPE	T1,LOKSK2	;IF NOT JUST LOCKED, DON'T INTERRUPT
	MOVE	T1,LKTMP2	;GET ADDR OF THIS Q-BLOCK
IFN FTPI,<
	LOAD	T2,.QBFLG,(T1)	;GET FLAGS
	TRNN	T2,QBPSI	;IS HE EXPECTING AN INTERRUPT?
	JRST	LOKSK3		;NO, HE IS WAITING
	PUSH	P,J		;SAVE J
	LOAD	J,.QBJOB,(T1)
	PUSHJ	P,GENPSI	;GENERATE AN INTERRUPT FOR HIM
	POP	P,J		;RESTORE J
	JRST	LOKSK2		;AND CONTINUE
>;END FTPI
LOKSK3:	LOAD	T1,.QBJOB,(T1)	;GET THIS GUY'S JOB NUMBER
	PUSH	P,W		;JUST IN CASE W GETS LOST
	PUSHJ	P,WAKJOB##	;WAKE HIM UP
	POP	P,W		;GET IT BACK

LOKSK2:	MOVE	T1,LKTMP2	;GET Q-BLOCK ADDR AGAIN
	LOAD	T2,.QBFLG,(T1)	;GET FLAGS
	TRNN	T2,QBEXCL	;EXCLUSIVE REQUEST?
	JRST	LOKSK1		;NO, LOOP BACK FOR REST OF Q
	POPJ	P,		;YES, NO NEED TO SCAN FURTHER
	SUBTTL	SUBROUTINE TO GET A LOCK SPECIFICATION FROM USER SPACE

;SUBROUTINE TO GET ONE 3-WORD LOCK SPEC FROM THE USER'S
; RESOURCE BLOCK
;
;ON ENTRY, THE WORD "LOCKCT" IS SET UP AS FOLLOWS:
;	XWD	TOTAL # OF LOCKS, # OF LOCK TO GET
;
;CALL:
;	PUSHJ	P,GETLOK
;	NORMAL RETURN ALWAYS
;
;ON EXIT, P1-P3 WILL HAVE A PRECISE COPY OF THE LOCK
; SPECIFICATION AS GIVEN BY THE USER WITH THE FOLLOWING
; CHANGES:
;	1.  IF LH OF P2 WAS -1, IT IS CHANGED TO "POINT 7,0"
;	2.  THE RH OF P4 HAS THE ACCESS BLOCK ADDRESS IN IT
;		(OR -1/-2/-3)
;
;
GETLOK:	HRR	M,RBLOCK	;GET ADDRESS OF PARAMETERS
	HRRZ	T1,LOCKCT	;GET THE NUMBER OF THIS LOCK
	IMULI	T1,LOKSIZ	;MULTIPLY BY SIZE
	ADDI	M,-2(T1)	;BUMP POINTER 
	PUSHJ	P,GETWD1	;GET THE 1ST WORD OF THE LOCK SPEC
	MOVEM	T1,P1		;SAVE IT IN P1
	PUSHJ	P,GETWD1	;GET THE USER CODE/POINTER WORD
	MOVEM	T1,P2		;SAVE IT TOO
	PUSHJ	P,GETWD1	;GET THE POOL VALUES
	MOVEM	T1,P3		;SAVE IT IN P3
	HLRE	T1,P2		;GET LEFT HALF OF PTR
	AOSN	T1		;IS IT A -1?
	HRLI	P2,440700	;YES, MAKE IT INTO A BYTE PTR
	HRRE	T1,P1		;GET CHANNEL #/-1/-2/-3
	HRRM	T1,P4		;SAVE THIS IN RH OF P4 FOR USE LATER
	JUMPL	T1,CPOPJ##	;LEAVE NOW IF NOT A FILE LOCK
	CAMLE	T1,USRHCU##	;INVALID CHANNEL NUMBER
	JRST	CPOPJ##		;YES. LEAVE NOW
	MOVE	T1,USRJDA##(T1)	;GET DDB ADDRESS
	HRR	P4,DEVACC##(T1)	;GET ACCESS BLOCK ADDRESS
	POPJ	P,		;RETURN
	SUBTTL	SUBROUTINES TO CHECK PRIVILEGES AND LOCK SPECS

;SUBROUTINE TO CHECK USER PRIVILEGES
;
;ON ENTRY, P1-P4 MUST BE SET UP BY GETLOK
;
;CALL:
;	PUSHJ	P,CHPRIV
;	 RETURN HERE IF PRIV. INSUFFICIENT
;	USER IS OK
;
CHPRIV:	HRRE	T1,P1		;GET CHANNEL #/-1/-2/-3
	CAMN	T1,[-2]		;IS IT A LOGICAL LOCK?
	  JRST	[MOVSI T1,JP.ENQ ;YES, DOES HE HAVE ENQ PRIV?
		 PUSHJ	P,PRVBIT## ;CHECK PRIVILEGES
		 JRST	CPOPJ1## ;IT'S OK
 		 JRST	PRVERR]	;NO, HE'S AN IMPOSTER
	CAMN	T1,[-3]		;OR, IS IT A [1,2]/JACCT LOCK?
	  JRST	[PUSHJ	P,PRVJC## ;YES, IS HE PRIVILEGED?
		 JRST	CPOPJ1## ;YES, ITS OK
		  JRST	HDRER7]	; NO
	PJRST	CPOPJ1##	;SKIP RETURN
;SUBROUTINE TO CHECK THE BYTE POINTER SIZE, POOL VALUES,
; AND CHANNEL #
;
;ON ENTRY, P1-P4 SET UP BY GETLOK
;
;CALL:
;	PUSHJ	P,LOCKOK
;	 ERROR RETURN
;	NORMAL RETURN
;
LOCKOK:	LDB	T2,[POINT 3,P2,2]	;GET STRING IDENTIFIER
	CAIN	T2,5		;IS IT A USER CODE?
	JRST	LKOK2		;YES, DON'T CHECK BYTE SIZE
	LDB	T2,[POINT 6,P2,11]	;GET BYTE SIZE
	CAIE	T2,7		;ERROR IF NOT ASCII
	JRST	HDRER1
	TLZE	P2,37		;INDEXED OR INDIRECT POINTER?
	JRST	HDRERA		;YES, ERROR
LKOK2:	HRRE	T1,P1		;GET CHANNEL #
	CAMG	T1,USRHCU##	;IS IT MORE THAN HIGHEST INIT'D CHANNEL?
	CAMGE	T1,[-3]		;OR LESS THAN -3?
	JRST	HDRER6		;YES TO EITHER IS AN ERROR
	JUMPL	P3,HDRER8	;NEGATIVE POOL NUMBER IS ILLEGAL
	HLRE	T2,P3		;GET POOL VALUES
	JUMPE	T2,CPOPJ1##	;DON'T CHECK IF NOT A POOLED RESOURCE
	TRNE	P3,-1		;DOES HE WANT NONE OF THEM?
	CAIGE	T2,(P3)		;REQUEST MORE THAN IN POOL?
	JRST	HDRER8		;YES, ERROR
	PJRST	CPOPJ1##	;SKIP RETURN
;SUBROUTINE TO CHECK IF A USER HAS BEEN QUEUE'D FOR A LOCK
;
;CALL:
;	MOVE	T1,LOCK-BLOCK-ADDR
;	PUSHJ	P,CHECKQ
;	 HERE IF HE IS Q'ED
;	HERE IF USER NOT Q'D
;
;ON ENTRY, P1-P3 MUST BE SET UP WITH THE LOCK SPEC
;
;ON NON-SKIP RETURN, T1 WILL HAVE THE Q-BLOCK ADDRESS IN IT
;
;
CHECKQ:	MOVE	T3,T1		;SAVE LOCK BLOCK ADDR FOR A SEC
CHECK2:	LOAD	T1,.LBNQ,(T1)	;GET ADDRESS OF NEXT Q-BLOCK
	CAIN	T1,(T3)		;ARE WE BACK AT START?
	JRST	CPOPJ1##	;YES, SKIP RETURN
	LOAD	T2,.QBJOB,(T1)	;GET THIS Q-BLOCK'S JOB NUMBER
	CAIN	T2,(J)		;IS IT THIS GUY?
	POPJ	P,		;YES, RETURN WITH ADDR IN T1
	JRST	CHECK2		;KEEP GOING
	SUBTTL	MISCELLANEOUS SUBROUTINES



;SUBROUTINE TO CREATE A LOCK-BLOCK
;
;CALL:
;	MOVE	T1,HASH-INDEX
;	MOVE	T2,FLAGS
;	PUSHJ	P,BLDLOK
;	  HERE IF ERROR
;	NORMAL RETURN
;
;ON RETURN, T1 = ADDRESS OF LOCK-BLOCK
;
BLDLOK:	MOVEM	T1,EQTMP1	;SAVE HASH INDEX
	MOVEM	T2,EQTMP2	;SAME FOR FLAGS
	MOVEI	T2,1		;ASSUME LENGTH OF CODE/TEXT IS ONE
	LDB	T3,[POINT 3,P2,2]	;GET THE STRING IDENTIFIER
	CAIN	T3,5		;IS IT A USER CODE?
	JRST	GOTLNG		;YES, SO WE ALREADY HAVE THE LENGTH
IFN FTKA10,<
	PUSH	P,P2		;SAVE PNTR AS ARGUMENT
	PUSHJ	P,RELPTR	;SET RELOCATION IN U
	POP	P,(P)		;REMOVE ARGUMENT
>
	MOVE	T3,P2		;GET THE STRING POINTER
	MOVEI	T2,0		;INITIALIZE COUNTER
BUILD2:	EXCTUX	<ILDB T4,T3>
	AOS	T2		;BUMP CHARACTER COUNT
	JUMPN	T4,BUILD2	;LEAVE LOOP ONLY IF NULL
	CAMLE	T2,%ENQML##	;TOO MANY CHARACTERS?
	JRST	HDRER2		;YES
	IDIVI	T2,5		;FIND # OF WORDS NEEDED
	SKIPE	T3		;WAS THERE A REMAINDER?
	AOS	T2		;YES, WE NEED ANOTHER WORD
GOTLNG:	ADDI	T2,LBSIZE	;ADD LENGTH OF LOCK BLOCK
	MOVEM	T2,EQTMP4	;SAVE IT FOR NOW
	PUSHJ	P,GETWDS##	;GET SOME FREE CORE FOR IT
	  JRST	DOERR6		;NONE AVAILABLE
	MOVE	T2,EQTMP1	;GET HASH INDEX BACK
	MOVEI	T2,HSHTAB##(T2)	; AND ACTUAL ADDRESS OF ENTRY
	STOR	T2,.LBLHS,(T1)	;STORE IT IN HASH CHAIN
	HRRZ	T3,(T2)		;GET FORWARD POINTER FOR HASH CHAIN
	HRRM	T1,0(T2)
	STOR	T3,.LBNHS,(T1)	;NEXT HASH POINTER
	STOR	T1,.LBLHS,(T3)	;MAKE NEXT ENTRY POINT TO US
	STOR	T1,.LBNQ,(T1)	;MAKE THIS A NULL-QUEUE
	STOR	T1,.LBLQ,(T1)	;...SAME
	LDB	T2,[POINT 9,P1,17]	;GET LEVEL #
	STOR	T2,.LBLVL,(T1)	;PUT IT INTO LOCK BLOCK
	HLRZ	T2,P3		;GET # OF RESOURCES IN REQUEST
	STOR	T2,.LBPUL,(T1)	;PUT IT IN BLOCK
	STOR	T2,.LBAVL,(T1)	;WITH SAME AMOUNT AS "AVAILABLE"
	STOR	P4,.LBACC,(T1)	;STORE ACCESS BLOCK ADDRESS
	MOVE	T3,EQTMP4	;GET LENGTH BACK AGAIN
	STOR	T3,.LBLEN,(T1)	;LENGTH OF LOCK BLOCK
	SETZ	T2,		;CLEAR TIME STAMP
	STOR	T2,.LBTIM,(T1)	;STORE IT
	MOVE	T2,EQTMP2	;GET FLAGS AGAIN
	STOR	T2,.LBFLG,(T1)	;PUT THEM AWAY
	TRNN	T2,LBTEXT	;IS THERE TEXT?
	JRST	[STOR	P2,.LBTXT,(T1)	;NO, STORE USER CODE
		 JRST	CPOPJ1]
	MOVE	T2,[POINT 7,O.TEXT(T1)]	;SET UP POINTER TO TEXT
BLD1:	EXCTUX	<ILDB T3,P2>	;START MOVING TEXT INTO BLOCK
	IDPB	T3,T2		;KEEP GOING
	JUMPN	T3,BLD1		;LOOP UNTIL NULL BYTE
	JRST	CPOPJ1##	;GIVE SKIP RETURN
;SUBROUTINE TO CREATE A QUEUE-BLOCK AND LINK IT
; INTO THE CHAIN OF QUEUED REQUESTS
;
;CALL:
;	MOVE	T1,LOCK-BLOCK-ADDR
;	MOVE	T2,ADDR-OF-Q-BLOCK-IN-MULTIPLE-REQUEST
;	MOVE	T3,FLAGS
;	PUSHJ	P,QHIM
;	  ERROR RETURN
;	NORMAL RETURN
;
;ON RETURN, T1 = ADDRESS OF NEW Q-BLOCK ENTRY
;
QHIM:	MOVEM	T1,EQTMP1	;SAVE LOCK-BLOCK ADDRESS
	MOVEM	T2,EQTMP2	;SAME FOR MULTIPLE REQUEST ADDR
	MOVEM	T3,EQTMP3	; AND FOR FLAGS
	MOVEI	T2,QBSIZE	;GET LENGTH OF Q-BLOCK
	PUSHJ	P,GETWDS##	;GET SOME FREE SPACE FOR IT
	  POPJ	P,		; NO MORE LEFT!
	MOVEM	T1,T2		;SAVE ADDRESS OF BLOCK
	HRRZI	T2,.PDEQJ##(W)	;ADDRESS OF JOB-Q BEGINNING
	STOR	T2,.QBLJQ,(T1)	;LINK INTO JOB CHAIN
	HRRZ	T3,(T2)		;GET FORWARD POINTER
	HRRM	T1,(T2)		;MAKE JOB Q POINT TO US
	STOR	T3,.QBNJQ,(T1)	;MAKE US POINT TO START
	SKIPE	T3		;CHECK FOR END OF CHAIN
	STOR	T1,.QBLJQ,(T3)	;ELSE, RELINK BACKWARD POINTERS
	MOVE	T2,EQTMP1	;GET LOCK BLOCK ADDR
	STOR	T2,.QBNQ,(T1)	;PUT US INTO REGULAR CHAIN OF Q-BLOCKS
	LOAD	T3,.LBLQ,(T2)	;GET POINTER TO LAST Q ENTRY
	STOR	T3,.QBLQ,(T1)	;PUT US AFTER IT
	STOR	T1,.QBNQ,(T3)	;MAKE LOCK BLOCK POINT TO US
	STOR	T1,.LBLQ,(T2)	;WE ARE THE LAST ENTRY IN QUEUE
	STOR	T2,.QBLB,(T1)	;MAKE POINTER TO LOCK BLOCK
	MOVE	T4,REQID	;GET THE REQUEST ID
	STOR	T4,.QBRID,(T1)	;STORE ID IN Q-BLOCK
	MOVE	T3,EQTMP3	;FETCH FLAGS
	TLNE	P3,-1		;IS THIS A MULTIPLE RESOURCE?
	TRZ	T3,QBEXCL	;YES, CLEAR THE EXCLUSIVE BIT
	STOR	T3,.QBFLG,(T1)	;PUT THEM AWAY
	STOR	P1,.QBCHN,(T1)	;PUT IN Q-BLOCK
	SKIPN	T2,EQTMP2	;IS THIS A MULTIPLE REQUEST?
	JRST	[STOR	T1,.QBNQR,(T1)	;YES, SET UP LINKS FOR CHAIN
		 STOR	T1,.QBLQR,(T1)	;MAKE US POINT TO OURSELVES
		 JRST QHIM2]		;AND FILL IN REST OF BLOCK
	LOAD	T3,.QBNQR,(T2)	;GET ADDR OF NEXT ENTRY IN CHAIN
	STOR	T1,.QBNQR,(T2)	;MAKE HIM POINT TO US
	STOR	T1,.QBLQR,(T3)	;...
	STOR	T3,.QBNQR,(T1)	;MAKE US POINT TO HIM
	STOR	T2,.QBLQR,(T1)	;...
QHIM2:	STOR	J,.QBJOB,(T1)	;STORE JOB NUMBER
	SETZ	T2,		;SET UP TO CLEAR SOME STRUCTURES
	TLNN	P3,-1		;POOLED?
	EXCH	T2,P3		;NO
	STOR	P3,.QBNRP,(T1)	;YES, STORE REQUESTED NUMBER
	STOR	T2,.QBGRP,(T1)	;CLEAR GROUP NUMBER
	JRST	CPOPJ1##	; AND EXIT
;SUBROUTINE TO GENERATE AN INTERRUPT FOR A USER
;
;CALL:
;	MOVE	T1,Q-BLOCK ADDRESS
;	PUSHJ	P,GENPSI
;	RETURN HERE ALWAYS
;
;
IFN FTPI,<
GENPSI:

	LOAD	T2,.QBRID,(T1)	;GET REQUEST ID FROM Q-BLOCK
	SIGNAL	C$QUE		;SIGNAL INTERRUPT
	EXCTUU	<IORM T2,IBKISW##(M)>	;STORE ID IN INTERRUPT BLOCK
	POPJ	P,		;RETURN
>;END IFN FTPI





;SUBROUTINE TO UPDATE THE CURRENT LOCK COUNTER AND
; DETERMINE IF THERE ARE MORE LOCKS TO BE PROCESSED
;
;CALL:	
;	PUSHJ	P,CHKCNT
;	 HERE IF THERE ARE MORE LOCKS
;	HERE IF ALL THRU
;
;ON ENTRY, THE WORD "LOCKCT" MUST BE SET UP AS FOLLOWS:
;	XWD	# OF LOCKS,,# OF THE CURRENT LOCK
;
CHKCNT:	AOS	T3,LOCKCT	;BUMP COUNTER
	TLZ	T3,-1		;CLEAR # LOCKS
	HLRZ	T2,LOCKCT	;GET NUMBER OF TOTAL LOCKS
	CAIL	T2,(T3)		;MORE TO GO?
	POPJ	P,		;YES
	JRST	CPOPJ1##	;NO, GIVE SKIP RETURN
;SUBROUTINE TO HASH TWO NUMBERS TOGETHER
;
;CALL:	
;	MOVE	T1,NUMBER
;	MOVE	T2,NUMBER
;	PUSHJ	P,MHASH
;	RETURN HERE ALWAYS WITH HASH IN T1
;
MHASH:	XOR	T1,RANDOM	;GUARD AGAINST 0 IN T1
	XOR	T2,RANDOM	;SAME
	MUL	T2,RANDOM	;SCRAMBLE THINGS UP A LITTLE
	MUL	T1,T2		;MAKE IT REALLY RANDOM
	POPJ	P,

RANDOM:	EXP	5*5*5*5*5*5*5*5*5*5*5*5*5*5*5	;THIS IS 5^15



;SUBROUTINE TO HASH A STRING
;
;CALL:
;	MOVE	T2,STRING-POINTER
;	PUSHJ	P,STHASH
;	RETURN HERE WITH HASH IN T1
;
;
STHASH:	MOVEM	T2,EQTMP1	;SAVE POINTER
IFN FTKA10,<
	PUSH	P,T2		;SAVE ARGUMENT
	PUSHJ	P,RELPTR	;SET U TO RELOC FOR HI OR LOW SEG
	POP	P,(P)
>
	SETZM	EQTMP2		;CLEAR ANSWER REGISTER
STHSH1:	MOVEI	T4,5		;SET UP COUNTER
	MOVE	T3,[POINT 7,T2]	; AND BYTE POINTER
	SETZ	T2,		;CLEAR RECEIVER AC
STHSH2:	EXCTUX	<ILDB	T1,EQTMP1>  ;GET A BYTE FROM USER'S STRING
	JUMPE	T1,STHSH3	;END OF STRING?
	IDPB	T1,T3		;NO, STORE CHARACTER IN T2
	SOJG	T4,STHSH2	;LOOP BACK FOR 5 CHARACTERS
	LSH	T2,-1		;LOW ORDER BIT IS ALWAYS 0
	XORM	T2,EQTMP2	;XOR THIS INTO ANSWER WORD
	JRST	STHSH1		;LOOP BACK UNTIL END OF STRING
STHSH3:	XORM	T2,EQTMP2	;STORE PARTIAL WORD TOO
	MOVE	T1,EQTMP2	;GET ANSWER
	POPJ	P,		;RETURN
;SUBROUTINE TO CALCULATE AN INDEX INTO THE HASH TABLE
;
;CALL:
;	MOVE	P1,ACCESS-BLOCK-ADDR/-1/-2/-3
;	MOVE	P2,USER CODE OR STRING POINTER
;	PUSHJ	P,HASH
;	NORMAL RETURN
;
;
HASH:	HRRE	T1,P4		;GET CHANNEL #/-1/-2/-3
	CAMN	T1,[-1]		;IF ITS' -1...
	HRRZ	T1,J		; ..MAKE IT INTO JOB # (BETTER HASH)
	MOVE	T2,P2		; AND STRING POINTER
	LDB	T3,[POINT 3,T2,2]	;GET THE IDENTIFIER
	CAIN	T3,5		;IS IT A USER CODE?
	JRST	HASH2		;YES, DON'T HASH IT
	PUSH	P,T1		;SAVE CHANNEL #
	PUSHJ	P,STHASH	;HASH THE STRING
	POP	P,T2		;GET IT BACK AGAIN
HASH2:	PUSHJ	P,MHASH		;HASH THE ACCESS BLOCK AND CODE/STRING
	MOVMS	T1		;MAKE IT POSITIVE
	IDIVI	T1,HSHLEN##	;DIVIDE BY SIZE OF HASH TABLE
	MOVE	T1,T2		;USE THE REMAINDER
	POPJ	P,		;RETURN
;SUBROUTINE TO FIND A LOCK-BLOCK
;
;CALL:
;	SET UP P1-P4 BY GETLOK
;	PUSHJ	P,CHLOCK
;
;	  RETURN HERE IF NOT FOUND
;	HERE IF FOUND, ADDRESS OF LOCK-BLOCK IN T1
;
;
CHLOCK:	LDB	T2,[POINT 3,P2,2]	;GET USER CODE IDENTIFIER
	CAIN	T2,5		;IS THIS A USER CODE?
	JRST	FNDLK0		;YES, DON'T WORRY ABOUT RELOCATION
IFN FTKA10,<
	TLO	P2,U		;..THEN SET RELOCATION
>
FNDLK0:	PUSHJ	P,HASH		;HASH LOCK NAME
	MOVEM	T1,EQTMP4	;SAVE IT FOR LATER
	MOVEI	T1,HSHTAB##(T1)	;GET ADDRESS OF ENTRY
	MOVEM	T1,EQTMP5	;SAVE T1
FNDLK1:	LOAD	T1,.LBNHS,(T1)	;ADVANCE TO NEXT LOCK-BLOCK
	CAMN	T1,EQTMP5	;HAVE WE EXHAUSTED LIST?
	POPJ	P,		;YES, BLOCK WAS NOT FOUND
	MOVEM	T1,EQTMP1	;REMEMBER THIS ADDRESS
	LOAD	T2,.LBACC,(T1)	;GET ACCESS BLOCK ADDRESS
	CAIE	T2,(P4)		;IS THIS A MATCH?
	JRST	FNDLK2		;NO, TRY NEXT ENTRY
	MOVE	T2,P2		;GET STRING POINTER
	PUSHJ	P,STRCMP	;COMPARE THE STRINGS
	  JRST	FNDLK2		;NO MATCH
	HRRE	T1,P4		;GET ACCESS BLOCK ADDRESS
	AOJN	T1,FNDLK3	;NOT -1, SO IT'S A MATCH
	MOVE	T1,EQTMP1	;YES, SO WE HAVE TO CHECK JOB NUMBERS
	LOAD	T2,.LBNQ,(T1)	;GET 1ST ENTRY IN QUEUE
	LOAD	T2,.QBJOB,(T2)	; AND IT'S JOB NUMBER
	CAIE	T2,(J)		;IS IT THIS JOB?
	JRST	FNDLK2		;NO, CONSIDER IT A NON-MATCH
FNDLK3:	MOVE	T1,EQTMP1	;GET BACK LOCK-BLOCK ADDRESS
	  PJRST	CPOPJ1##	;SKIP RETURN

FNDLK2:	MOVE	T1,EQTMP1	;GET LOCK-BLOCK ADDRESS
	JRST	FNDLK1		;GO ON
;SUBROUTINE TO COMPARE STRINGS OR USER CODES
;
;CALL:
;	MOVE	T1,LOCK-BLOCK-ADDRESS
;	MOVE	T2,STRING-PTR
;	PUSHJ	P,STRCMP
;	  HERE IF NO MATCH
;	RETURN HERE IF MATCH
;
;

STRCMP:	PUSHJ	P,SAVE1##	;SAVE P1
	LDB	T3,[POINT 3,T2,2]
	CAIN	T3,5		;IS THIS A USER CODE?
	JRST	STRCMC		;YES
	LOAD	T3,.LBFLG,(T1)	;GET THE FLAGS
	TRNN	T3,LBTEXT	;TEXT?
	POPJ	P,0		;NO
IFN FTKA10,<
	PUSH	P,T2		;SAVE ARGUMENT
	PUSHJ	P,RELPTR	;SET U FOR RELOCATION
	POP	P,(P)		;REMOVE ARG FROM LIST
>
	MOVE	P1,[POINT 7,O.TEXT(T1)]	;SET UP PTR TO TEXT
STRCM0:	EXCTUX	<ILDB T3,T2>	;GET A BYTE FROM USER
	ILDB	T4,P1		;AND ONE FROM LOCK BLOCK
	CAME	T3,T4		;A MATCH?
	POPJ	P,		;NO, RETURN
	JUMPN	T3,STRCM0	;YES, KEEP GOING IF NOT NULL
	PJRST	CPOPJ1##	;SKIP RETURN

STRCMC:	LOAD	T3,.LBFLG,(T1)	;GET THE FLAGS FOR THE LOCK BLOCK
	TRNE	T3,LBTEXT	;IS THIS USER CODE?
	POPJ	P,		;NO
	LOAD	T3,.LBTXT,(T1)	;GET USER CODE
	CAME	T2,T3		;MATCH?
	POPJ	P,		;NO
	PJRST	CPOPJ1##	;YES, SKIP RETURN
;SUBROUTINE TO FIND THE HIGHEST LEVEL # FOR A GIVEN USER
;
;CALL:
;	MOVE	W,PDB-ADDRESS
;	PUSHJ	P,GETLVL
;	RETURN HERE ALWAYS
;
;
;ON RETURN, T1 = HIGHEST MONITOR LEVEL,,HIGHEST USER LEVEL
;	REQCNT = # OF OUTSTANDING REQUESTS FOR THIS USER
;
;
GETLVL:	SETO	T1,		;ASSUME THE QUEUE IS EMPTY
	SETZM	REQCNT		;CLEAR REQUEST COUNT
	HRRZ	T2,.PDEQJ##(W)	;GET START OF JOB Q
LVL2:	JUMPE	T2,CPOPJ##	;EXIT IF NO Q
	LOAD	T3,.QBLB,(T2)	;GET LOCK BLOCK
	LOAD	T4,.LBLVL,(T3)	; AND ITS LEVEL #
	AOS	REQCNT		;BUMP COUNT OF REQUESTS
	LOAD	P2,.LBACC,(T3)	;YES, GET FILE ID/-1/-2/-3
	CAIE	P2,-3		;IS THIS A PRIVILEGED LOCK?
	JRST	LVL3		;NO, CHECK IT AGAINST HIGH USER LEVEL
	HLRE	T3,T1		;GET HIGHEST MONITOR LEVEL #
	CAMLE	T4,T3		;A NEW HIGH?
	HRL	T1,T4		;YES, UPDATE MONITOR LEVEL #
	JRST	LVL4		; AND KEEP GOING
LVL3:	HRRE	T3,T1		;GET HIGHEST USER'S LEVEL
	CAMLE	T4,T3		;A NEW HIGH?
	HRR	T1,T4		;YES
LVL4:	LOAD	T2,.QBNJQ,(T2)	;RETURN ADDRESS OF Q-BLOCK
	JRST	LVL2		;NO, MORE TO GO





;SUBROUTINE TO PERFORM COMMON SETUP FUNCTIONS
;
;CALL:
;	MOVE	T2,MAX-FUNCTION-CODE
;
;	PUSHJ	P,SETUP
;	  ERROR RETURN (ERROR CODE IN T1)
;	NORMAL RETURN (FUNCTION CODE IN T3)
;
;P4 IS RETURNED CLEAR
; AND THE FUNCTION CODE IS STORED IN THE RIGHT HALF OF "FCODE"
;
SETUP:	SETZB	P4,NQERRF	;INITIALIZE FLAGS
	HRR	M,T1		;GET PARAMETER BLOCK ADDR
	HRRM	M,RBLOCK	;SAVE THIS ADDRESS FOR LATER
	HLRZ	T3,T1		;GET FUNCTION FROM CALL
	MOVEM	T3,FCODE	;SAVE IT FOR USE LATER
	CAILE	T3,(T2)		;IS IT WITHIN RANGE?
	JRST	NDUERR		;NO, ERROR RETURN
	TLO	M,400000	;SO ERRORS RETURN RATHER THAN GOING TO STOTAC
	JRST	CPOPJ1##	;GIVE GOOD RETURN

IFN FTKA10,<
;ROUTINE TO SET UP U FOR RELOCATION OF A USER BYTE-POINTER
;ENTER WITH POINTER ON STACK
RELPTR:	PUSHJ	P,SAVT##	;SAVE ACS
	PUSH	P,J
	MOVE	J,.C0JOB##
	HRRZ	U,R		;ASSUME ADDR IS IN LOW SEG
	PUSHJ	P,HSVAD##
	HRRZ	T4,-7(P)
	CAMGE	T4,T2		;IS IT?
	JRST	JPOPJ##		;YES, RETURN
	MOVE	T1,JBTSGN##(J)	;NO, GET HI-SEG RELOCATION
	HRRZ	U,JBTADR##(T1)	;SET U SUCH THAT UVA+C(U)
	SUBI	U,(T2)		; POINTS TO RIGHT PHYSICAL ADR
	JRST	JPOPJ##		; AND RETURN
>


;SUBROUTINE TO PERFORM CLEAN-UP ON A RESET
;
;CALL:
;	PUSHJ	P,ENQRST
;	RETURN HERE ALWAYS
;
ENQRST::PUSHJ	P,FNDPDS##	;FIND HIS PDB
	SKIPA	T1,.PDEQJ(W)	;GET START OF JOB Q
RESET2:	MOVE	T1,T2		;FETCH ADDRESS OF CURRENT BLOCK
	JUMPE	T1,CPOPJ	;EXIT IF NO JOB QUEUE
	LOAD	T2,.QBNJQ,(T1)	;GET NEXT ENTRY IN JOB Q
	PUSHJ	P,DEQIT		;YES, DEQ THIS Q-BLOCK
	JRST	RESET2		;GO BACK TO START OF LOOP




;SUBROUTINE TO PERFORM "CLOSE" ON FILE-LOCKS
; THIS ROUTINE IS CALLED ON EVERY CLOSE, OPEN, INIT,
; LOOKUP, AND ENTER  WHICH OCCURS.
;IT CHECKS TO SEE IF THERE ARE
; ANY OUTSTANDING LOCKS FOR A GIVEN CHANNEL.
; HOWEVER, IT PERFORMS NO ACTION IF IT FINDS ANY.
;
;CALL:
;	MOVEI	P1,CHANNEL #
;	PUSHJ	P,ENQCLS##
;	 HERE IF THERE WERE LOCKS STILL OUT
;	HERE IF USER HAD NO LOCKS OUTSTANDING
;
ENQCLS::PUSHJ	P,SAVT##	;SAVE SOME AC'S
	MOVE	J,.C0JOB##	;GET USER'S JOB #
	PUSHJ	P,FNDPDS##	;GET HIS PDB
	HRRZ	T2,.PDEQJ(W)	;GET START OF JOB Q
CLOSE2:	JUMPE	T2,CPOPJ1##	;LEAVE NOW IF HE HAS NO LOCKS
	MOVE	T1,T2		;UPDATE CURRENT BLOCK POINTER
	LOAD	T3,.QBCHN,(T1)	;GET CHANNEL # FOR THIS LOCK
	LOAD	T2,.QBNJQ,(T1)	;GET NEXT BLOCK IN JOB Q
	CAIN	T3,(P1)		;MATCHES THE CLOSED CHANNEL?
	POPJ	P,		;YES, GIVE ERROR RETURN
	JRST	CLOSE2		;NO, GET NEXT Q-BLOCK IN JOB QUEUE
	SUBTTL	ERROR MESSAGES AND RETURNS



;ERROR RETURNS
; SOME OF THESE RETURN TO THE USER (JRST STOTAC), AND SOME
; OF THEM MERELY RETURN FROM THE CURRENTLY ACTIVE SUBROUTINE

;	ERCODE	ERRTAB,ENQRU%	;(1) SOME RESOURCES UNAVAILABLE
	ERCODE	HDRER8,ENQBP%	;(2) ILLEGAL # OF RESOURCES REQUESTED.
	ERCODE	QCERR1,ENQBJ%	;(3) BAD JOB NUMBER
	ERCODE	HDRER1,ENQBB%	;(4) BAD BYTE SIZE
	ERCODE	HDRER2,ENQST%	;(5) STRING TOO LONG
	ERCODE	NDUERR,ENQBF%	;(6) BAD FUNCTION CODE
	ERCODE	BFERR,ENQBL%	;(7) ILLEGAL ARGUMENT BLOCK LENGTH
	ERCODE	HDRERB,ENQIC%	;(10) ILLEGAL # OF LOCKS SPECIFIED
	ERCODE	HDRER6,ENQBC%	;(11) BAD CHANNEL NUMBER
	ERCODE	HDRER7,ENQPI%	;(12) OPERATOR/JACCT PRIVELEGE REQUIRED
	ERCODE	DOERR6,ENQNC%	;(13) NO CORE AVAILABLE
	ERCODE	HDRER9,ENQFN%	;(14) FILE NOT OPEN, OR DEVICE NOT A DISK
	ERCODE	HDRERA,ENQIN%	;(15) INDIRECT BYTE POINTER
;	ERCODE	DERNJQ,ENQNO%	;(16) NO RESOURCES WERE OWNED
	ERCODE	ENQER1,ENQLS%	;(17) LEVEL # TOO LOW
;	ERCODE	DOERR5,ENQCC%	;(20) CAN'T CHANGE ACCESS
;	ERCODE	ENQER3,ENQQE%	;(21) QUOTA EXCEEDED
	ERCODE	DOERR2,ENQPD%	;(22) POOL COUNT DESCREPANCY
	ERCODE	DOERR3,ENQDR%	;(23) LOCK ALREADY REQUESTED
;	ERCODE	DOERR4,ENQNE%	;(24) NOT ENQ'D ON THIS LOCK
	ERCODE	DOERR0,ENQLD%	;(25) LEVEL # DESCREPANCY
	ERCODE	PRVERR,ENQED%	;(26) ENQ/DEQ PRIVILEGES REQUIRED
;PRIVILEGES INSUFFICIENT (AND EXIT TO USER)
HDRERC:	MOVEI	T1,ENQPI%
	JRST	STOTAC##


;QUOTA EXCEEDED
ENQER3:	MOVEI	T1,ENQQE%	;QUOTA EXCEEDED
	JRST	STOTAC##


;BAD LENGTH GIVEN IN ARGUMENT BLOCK (FOR DUMP)
QCERR2:	MOVEI	T1,ENQBL%	;BAD DUMP BLOCK LENGTH
	JRST	STOTAC##

;NO REQUEST FOUND FOR LOCK
DOERR4:	MOVEI	T1,ENQNE%	;NO PENDING REQUEST FOUND
	JRST	MARETN		;GO STORE CODE

;CAN'T CHANGE ACCESS
DOERR5:	MOVEI	T1,ENQCC%	;CAN'T CHANGE ACCESS
MARETN:	HRRM	T1,NQERRF	;SAVE CODE
	JRST	CPOPJ1##	;RETURN FROM "DOIT"


;RESOURCE NOT FOUND (DEQ ALL OR DEQ REQ:ID)
DERNJQ:	MOVEI	T1,ENQNO%	;NO RESOURCES FOUND
	JRST	STOTAC##	;GIVE USER THE ERROR CODE



;COME HERE TO MAKE A GOOD EXIT BACK TO THE USER 
;THE CONTENTS OF T1 ARE RETURNED IN THE UUO AC.
GUDXIT:	HRRZ	T1,NQERRF	;RETRIEVE ERROR CODE(FROM ENQ)
GUDXT2:	AOS	(P)		;BUMP RETURN ADDRESS
	JRST	STOTAC##	;AND GIVE IT BACK TO HIM
	SUBTTL	TEMPORARY STORAGE LOCATIONS FOR ENQ/DEQ
	$LOW

;
;NOTE THAT THESE LOCATIONS ARE NOT SAVED IF A JOB BECOMES
; BLOCKED. THEREFORE, THEY SHOULD BE USED ONLY FOR
; TEMPORARY STORAGE FOR THE DURATION OF THE PROCESSING OF
; THE UUO, EXCLUDING ANY SCHEDULING WHICH MAY OCCUR.


FCODE:	Z	;KEEP THE USER'S FUNCTION CODE HERE
HILEVL:	Z	;HIGHEST LEVEL # ISSUED BY USER
DQFLAG:	Z	;NON:ZERO IF A LOCK WAS DEQ'D
EQTMP1:	Z	;RANDOM TEMPORARIES
EQTMP2:	Z	;..SAME
EQTMP3:	Z	;..SAME
EQTMP4:	Z	;..SAME
EQTMP5:	Z
LKTMP1: Z	;STORAGE FOR LOCK-SCHEDULER
LKTMP2: Z	;..SAME
LKTMP3: Z	;..SAME
QSKDF:	Z	;STORAGE FOR Q-SCHEDULER
QSKDG:	Z	;..SAME
QSKDT:	Z	;..SAME
QSKDQ:	Z	;..SAME
RBLOCK:	Z	;ADDRESS OF USER'S PARAMETER BLOCK
LOCKCT:	Z	;# OF LOCKS IN REQUEST,,# OF CURRENT LOCK
REQID:	Z	;STORAGE FOR REQUEST ID
NQERRF:	Z	;NON-ZERO IF ERROR OCCURED
REQCNT: Z	;COUNT OF OUTSTANDING RESOURCE REQUESTS FOR THIS USER
IFN FTTRACKS,<
LSTLOK::Z	;LAST LOCK-BLOCK CREATED
LASTQ::	Z	;LAST Q-BLOCK CREATED
>;END IFN FTTRACKS

	$LIT

	END
############################################################