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