Google
 

Trailing-Edge - PDP-10 Archives - dec-10-omona-u-mc9 - clock1.mac
There are 14 other files named clock1.mac in the archive. Click here to see a list.
TITLE	CLOCK1 - CLOCK, CONTEXT SWITCHING, AND JOB STARTUP AND STOP ROUTINES - V1047
SUBTTL APRINT TH/CHW/RCC/PFC/JE/DAL/EVS  22 FEB 77
	SEARCH	F,S
	$RELOC
	$HIGH
;***COPYRIGHT 1973,1974,1975,1976,1977 DIGITAL EQUIPMENT CORP., MAYNARD, MASS.***
XP VCLOCK1,1047
		; PUT VERSION NUMBER IN GLOB LISTING AND LOADER STORAGE MAP

	ENTRY	CLOCK1		;ALWAYS LOAD CLOCK1 IF LIBRARY SEARCH
CLOCK1:

;THIS SERVICE ROUTINE RUNS ON A HIGH PRIORITY CHANNEL
;AND REQUESTS INTERRUPTS ON LOWER CLK CHANNEL
;FOR SCHEDULING JOBS AND ERROR HANDLING THAT THE USER
;IS NOT ENABLED TO HANDLE HIMSELF


EXTERNAL .C0NJD,.C0ADR,.C0AEF,.C0APC,.C0JOB,.C0PC,.C0SCF,.C0UPT
EXTERNAL .C0S17,.C0CDB,.C0NPD
EXTERNAL .CPDUI
EXTERNAL .CPABC,.CPABA,.CPADR,.CPAEF,.CPAPC,.CPCHL,.CPCKF
EXTERNAL .CPCN1,.CPCON,.CPDTO,.CPJOB,.CPLJR
EXTERNAL .CPLST,.CPLUC,.CPNAP,.CPNJD,.CPNJE
EXTERNAL .CPNXJ,.CPPLT,.CPREL,.CPRUA,.CPSCF,.CPTMF,.CPTOS,.CPUPT
EXTERNAL .CPEEB,.CPEME,.CPIEF,.CPILM
EXTERNAL .CPUEH

EXTERNAL TIME,XI.RQC
EXTERNAL JOBTPC,JOBCNI,JOBAPR,JOBD15
EXTERNAL JBTNAM,JOBINT,CPOPJ1

EXTERNAL APRILM,COMMAN,CONMES,DEVCHK,DEVSRC
EXTERNAL CRSHWD,CRASHX


INTERNAL FTCHECK,FTMONP,FTMEMPAR,FTLOGIN

IFN FTCHECK+FTMONP,<
EXTERNAL DATA,DAMESS,UUO0,CLOCK
INTERNAL UUO1
>
IFE FTCHECK+FTMONP,<
	INTERN	CLOCK,DAMESS
	EXTERN	CIPWTM
	$LOW
DAMESS:	ASCIZ	/-Jan-/
CLOCK:	POINT	36,CIPWTM,35	;BYTE POINTER TO CLOCK REQ QUEUE
	$HIGH
>
;SUBROUTINE TO SERVICE APR INTERRUPTS (AND MEM PARITY)
;THIS IS CPU INDEPENDENT -  CALLED FROM COMMON
;FOR SPEED, NO ACS SAVED EXCEPT P,P4
;CALL:	MOVEI	P4,ADR OF CPU DATA BLCK
;	PUSJP,APRSU
;	ALWAYS RETURN HERE

;THE CODE IS ORGANIZED SO THAT:
; 1. CLOCK INTERRUPTS ARE FASTEST
; 2. TRAPS TO USERS ARE NEXT FASTEST
; 3. MORE SERIOUS ERRORS ARE LAST

;THE ORDER OF RECOGNIZING INTERRUPTS IS MUCH DIFFERENT:
; 1. FIRST MEM PARITY IS CHECKED FOR - SINCE POTENTIALLY CATASTROPHIC
;    AND ANY OTHER ERRORS COULD ERRONEOUSLY COME UP AT THE SAME TIME.
; 2. THEN CLOCK
; 3. FINALLY ALL OTHER INTERRUPTS

;FATAL AND CPU DEPENDENT ERRORS ARE FILTERED OUT BEFORE CALLING APRSUB
; THESE INCLUDE POWER FAIL AND (IO PAGE FAIL - KI10) AND ADDRESS BREAK

	INTERN	FTMEMPAR,FTRTTRP
	INTERN	APRSUB,APRER9,APRCK0

APRSUB:
IFN FTMEMPAR,<			;MEM PARITY (HALT IN COMMON IF NOT FEATURE)
IFN FTMEMNXM,<
	CONSO	@.CPNXM##(P4)	;NON-EXISTENT MEMORY? (AP.NXM OR IP.NXP)
>
	XCT	.CPMPE##(P4)	;MEMORY PARITY? (CONSZ PI, ON KA-10)
				; (CONSZ APR, ON KI-10)
	JRST	APRPAR		;YES, GO HANDLE
>
IFN FTRTTRP,<			;REAL TIME RTTRP UUO?
	SKIPE	.CPRTT##(P4)	;ANY REAL TIME INTERRUPTS IN PROGRESS?
	PJRST	APRCHK##	;YES, GO SERVICE IT PROPERLY
>
;HERE TO CHECK FOR AND SERVICE CLOCK
APRCK0:	XCT	.CPHCT##(P4)	;NO, HAVE CLOCK INTERRUPT
	JRST	APRER		;NO, GO CHECK ERROR FLAGS
IFN FTMS,<			;DUAL CPUS
	SKPCPU	(0);		;YES, IS THIS CPU1?
	JRST	APRCK1		;YES, DO NOT DO TIME ACCOUNTING FOR SYSTEM AS WHOLE
>
	AOS	TIME		;NO, INCREMENT TIME OF DAY FOR SYSTEM
	SOS	HNGTIM##	;DECREMENT HNGTIM FOR SYSTEM
IFN FTKL10,<
	SETOM	.CPPTF##(P4)	;INITIALIZE PAGE TABLE PARITY FLAG ONCE/CLOCK TICK
>
APRCK1:	AOS	.CPUPT(P4)	;UPTIME IS LOADED AS ZERO,AND IS NEVER CLEARED
	SETOM	.CPTMF(P4)	;FLAG THAT APR CLOCK HAS TICKED
	SETOM	.CPCKF(P4)	;SET FLAG FOR CLK FORCED INTERRUPT
IFN FTMS,<	EXTERNAL .CPOK,.CPOK1
	SETOM	.CPOK(P4)	;TELL OTHER PROCESSOR THAT ALL IS OK
	SOS	.CPOK(P4)	;MAKE COUNT -2 IN CASE OF LOST TIME FROM PI'S ABOVE APR
	AOS	@.CPOK1(P4)	;CHECK IF OTHER PROCESSOR IS ALIVE
>				;END OF FTMS CONDITIONAL
	CONO	PI,XI.RQC	;REQUEST INTERRUPT ON CLK CHANNEL
	XCT	.CPIUE##(P4)	;IS USER ENABLED FOR ANY FLAGS(INCLUDING CLOCK)
	CAIA
				; RH .CPCN1 ALSO MODIFIED EACH TIME A USER RUNS
	JRST	APRERC		;YES, GO PROCESS TRAP
	XCT	.CPCCF##(P4)	;NO, CLEAR ONLY THE CLOCK FLAG
				; (IN CASE OTHERS ALSO ON)
	POPJ	P,		;DISMISS INTERRUPT - IF OTHERS ON TOO (RARE)
				; THEY WILL INTERRUPT IMMEDIATELY AGAIN
;HERE ON CLOCK FLAG AND IT OR SOME OTHER FLAG IS ON WHICH USERS WANTS

APRERC:	EXCH	T1,@.CPCHL(P4)	;SAVE T1, GET PC
	TLNE	T1,(XC.USR)	;IS PC FROM USER MODE ?
	JRST	APRE1A		;YES, GO GET STATUS
	XCT	.CPCCF##(P4)	;NO, NOW CLEAR CLOCK FLAG
	JRST	APRER0		;GO CHECK IN CASE ALSO A SERIOUS ERROR

;HERE ON USER ENABLED TRAP AND PC IS IN USER MODE
APRE1A:	EXCH	R,.CPADR##(P4)	;GET STATUS--PICK UP EXEC VIRT. ADR OF JOB DATA AREA
	XCT	.CPUEH(P4)	;STORE STATUS IN JOB DATA AREA (JOBCNI)
	XCT	.CPCCF##(P4)	;CLEAR CLOCK FLAG
	JRST	APRER4		;GO TRAP TO HIM
COMMENT	$
HERE FOR MEMORY PARITY ERROR ANALYSIS
THE FIRST RULE OF THE MEMORY PARITY CHECKER IS NEVER
 PROCEED IF THERE IS ANY CHANCE OF THE MONITOR MAKING AN
 ERROR USING INFORMATION WHICH IS IN ERROR.
THE SECOND RULE IS TO KEEP THE SYSTEM RUNNING IF ONLY ONE
 OR MORE USER JOBS ARE AFFECTED.
FINALLY THE OPERATOR AND THE AFFECTED USERS ARE ALWAYS
 INFORMED OF PARITY ERRORS. THE OPERATOR IS GIVEN ENOUGH
 INFO ON CTY OR OPR TO RECONFIGURE THE MEMORIES. FIELD SERVICE
 CAN OBTAIN ENOUGH INFORMATION BY CONSULTING ERROR LOG
 FILE WRITTEN BY DAEMON. IF SYSTEM HALTS DURING
 PARITY CHECK, CTY PRINTS MESSAGE INSTEAD OF OPR. DAEMON WILL
 FIND PARITY INFO IN CRASHED MONITOR (CRASH.SAV) WHEN SYSTEM IS
 RELOADED, PROVIDED OPERATOR FOLLOWS CRASH PROCEDURE.

THE ANALYSIS IS AS FOLLOWS:
IF PAR ERROR PC FROM USER MODE
    IF USER ENABLED FOR PAR TRAP AND PRIVILEGED, DISMISS TO HIM
    IF PC SAME AS LAST PARITY PC, SET PC TO 0 ( SO PI 7 CAN GET IN)
    REQUEST INTERRUPT ON PI 7 TO SWEEP ALL OF CORE
ELSE (ERROR PC FROM EXEC MODE)
    IF ADR OF INSTR. IS MONITOR SWEEP LOOP (.CPMPI IN CPU DEPENDENT SUBS)
	DISMISS INTERRUPT WITH PC+1 TO MAKE IT SKIP
    IF ADR OF INST. IS IN CHANNEL MEM PARITY STATISTICS ROUTINE
        DISMISS INTERRUPT - NOT SERIOUS
    IF ADR OF INST. IS MONITOR USER-AREA BLT (BLTINS IN CORE1)
	SET FLAG FOR ERROR IN JOB (JS.PEF)
	IF BAD WORD IS IN JOB DATA AREA, SET BIT (JS.JDP) TO CLEAR JOBDAT AT PI 7
    IF ANY PIS IN PROGRESS OR PC SAME AS LAST PARITY PC
	SWEEP CORE AT APR PI LEVEL
	IF ERRORS IN MONITOR, PRINT CTY+HALT
    ELSE REMEMBER THIS PC AS LAST PC
END
DISMISS INTERRUPT
$
;HERE TO DO MEMORY PARITY ANALYSIS
IFN FTMEMPAR,<			;MEMORY PARITY ANALYSIS?
APRPAR::
IFN FTMEMNXM,<
	PUSHJ	P,SAVE1##	;SAVE P1
	MOVEI	P1,UE.PEF	;ASSUME PARITY ERROR
	XCT	.CPMPE##(P4)	;IS IT A PARITY ERROR?
	JRST	APRPA1		;YES
IFN FTKA10!FTKI10,<
	CONO	APR,@.CPNXM##(P4) ;NO, NXM CLEAR NXM FLAG

	TRCA	P1,UE.PEF+UE.NXM;INDICATE NXM

>;END IFN FTKA10!FTKI10
IFN FTKL10,<
	TRC	P1,UE.PEF!UE.NXM
>
>
APRPA1:
IFN FTKA10!FTKI10,<
	CONO	PI,XI.CPE	;CLEAR PARITY ERROR (KA10 + KI10)
>
	EXCH	T1,@.CPCHL##(P4);SAVE T1, GET INTERRUPT PC
	PUSH	P,T1		;SAVE INTERRUPT PC
	PUSH	P,T2		;SAVE T2
	PUSHJ	P,APRPTS	;GET REAL PC (IN CASE LOWER PRIORITY INT JSR SNUCK IN KI10)
	EXCH	R,.CPADR##(P4)	;SAVE R, SETUP ADR OF JOB DATA AREA
	TLNE	T1,(XC.USR)	;IS REAL PC IN USER MODE?
	JRST	APPUSR		;YES, NOT A SERIOUS ERROR

;HERE IF REAL PC IS IN EXEC MODE (THIS MAYBE A SERIOUS ERROR)
	TLZ	T1,-1		;CLEAR LH PC FLAGS
	CAME	T1,.CPMPI##(P4)	;IS INT. FROM PI 7 PARITY SWEEP LOOP?
	JRST	APPCPE		;NO, GO CHECK OTHER SPECIAL MONITOR ADRS

;HERE WHEN PC IS FROM PI 7 MEM PARITY SWEEP LOOP
	AOS	@T2		;ADD 1 TO REAL PC SO INSTR. IN MEM SWEEP
				; LOOP WILL SKIP
	AOS	@T2		;ADD ANOTHER (SO GET OVER SOJG - ONKJ)
	JRST	APREX1		;POP T2 T1, R AND DISMISS INT.
				; LOOP WILL SKIP, DISMISS INTERRUPT


;HERE TO CHECK IF PARITY ERROR IN CHANNEL ERROR RECORDING ROUTINE (CHNMPE)
APPCPE:
IFN FTKL10,<
	SKIPN	.CPTSD##(P4)	;DID THE TRAP ROUTINE SAVE THE DATA?
	 JRST	APPCP1		;NO-CAPTURE IT NOW
	MOVE	T1,.CPAPI##(P4)	;GET THE APR PIA
	TRO	T1,LP.CSF!LP.PAR!LP.SBE	;SAY CLEAR THE FLAGS
	CONO	APR,(T1)
	MOVE	T1,.CPPPC##(P4)	;YES-THIS INTERRUPT IS FROM A "HARD"
		;TRAP FAILURE,DATA HAS BEEN SAVED AT TIME OF THE TRAP
		;WE ARE HERE TO GET PC AT TIME OF TRAP AND HANDLE INTERRUPT
		;AS IF TRAP NEVER HAPPENED, IE. CHECK FOR USER TRAP ENABLED,
		;SWEEP CORE AND KILL THE USER, ETC.
	JRST	APPUSR		;AND HANDLE AS A USER ERROR
APPCP1:	RDERA	.CPAER##(P4)	;SAVE ERA FOR ERROR REPORT
	CONI	APR,.CPPEF##(P4)	;SAVE APR FLAGS
	PUSH	P,T3		;SAVE T3
	PUSH	P,T4		;SAVE T4
	MOVE	T3,[100000,,0]	;GET FUNCTION FOR SBDIAG IN T3
	SBDIAG	T3		;DO IT
	DMOVEM	T3,.CPPSB##(P4)	;SAVE SBDIAG FUNCTION 1
	MOVE	T3,[100000,,1]	;GET FUNCTION
	SBDIAG	T3		;READ SBUS
	DMOVEM	T3,.CPPSB##+2(P4)	;SAVE SBDIAG FUNCTION 2
	MOVSI	T3,110000	;SETUP TO CLEAR THE ERRORS IN THE DMA-20
	SWPUA			;SINCE WE KNOW WE HAVE AN ERROR EITHER IN
				;CACHE OR CORE, WE SWEEP THE CACHE NOW,
				;WITH THE APR,ERA,AND DMA STILL FROZEN, TO
				;AVOID RECURSIVE FAILURES AS MUCH AS POSSIBLE
	CONSZ	APR,LP.CSB	;WAIT FOR THE SWEEP TO FINISH
	 JRST	.-1		;FAILURES WHICH MIGHT OCCUR HERE WILL
				;ALL BE DETECTED DURING THE CORE MEMORY SWEEP
				;WHICH WILL FOLLOW.
	TRNN	P1,UE.PEF	;PARITY?
	JRST	APPCP2		;YES
	PUSH	P,T1		;SAVE T1 FOR  A MINUTE
	MOVE	T1,.CPAPI##(P4)	;GET THE APR PIA
	TRO	T1,LP.CSF!LP.PAR!LP.SBE	;SAY CLEAR THE FLAGS
	CONO	APR,(T1)
	POP	P,T1		;GET T1 BACK
	SKIPA			;GO ON
APPCP2::	CONO	APR,@.CPNXM##(P4)	;CLEAR NXM FLAG
	SBDIAG	T3		;NOW CLEAR THE DMA WITH THE FUNCTION WE SET UP ABOVE
	POP	P,T4		;RESTORE T4
	POP	P,T3		;RESTORE T3
>;END FTKL10
	CAIL	T1,CHNIN1##	;BELOW FIRST BLT IN CHNMPE ROUTINE
	CAILE	T1,CHNIN2##	;NO, ABOVE LAST BLT IN CHNMPE ROUTINE
	SKIPA			;YES, NOT IN CHNMPE ROUTINE - CHECK OTHER ADRS
	JRST	APREX1		;NO, JUST DISMISS INT.  THIS IS NOT SERIOUS
				; CHANNEL ROUTINE CAN REQUEST SWEEP

;HERE TO CHECK IF EXEC MODE PC IS FROM BLT OF USER CORE
IFN FTLOCK,<			;LOCK UUO FEATURE
	CAIN	T1,LOKINS##	;EXEC PC = ADR OF BLT OF USER CORE ON LOCK UUO?
	JRST	APPBLT		;YES, SEE IF IN JOB DATA AREA
>
	CAIE	T1,BLTINS##	;NO, EXEC PC = ADR OF BLT OF USER CORE?
	JRST	APPSAM		;NO, SEE IF SAME PC OR PI'S IN PROGRESS

;HERE ON PARITY ERROR DURING BLT OF USER CORE
	XP	BLTAC,P1	;AC USED IN BLT INSTR. - GET MUL DEF
				; GLOBAL IF DO NOT AGREE WITH CORE1 MODULE
APPBLT:	MOVE	T2,.CPLSB##(P4)	;JOB OR HIGH SEG NO BEING BLTED
	HLRZ	T1,BLTAC	;GET SOURCE MOVE SO FAR FROM BLT AC POINTER
	SUB	T1,JBTADR(T2)	;SUBTRACT ORIGIN OF SOURCE
	TLZ	T1,-1		;CLEAR OUT GARBAGE (-PROTECTION)
	MOVEI	T2,JS.MPE!JS.APE	;JOB HAS A MEM PARITY STATUS BIT AND APR ERROR
				;USED ON PI 7 TO PRINT MESSAGE FOR JOB
IFN FTMEMNXM,<
	TRNE	P1,UE.NXM	;WAS IT REALLY NXM?
	TRC	T2,JS.MPE+JS.NXM;YES, INDICATE NXM INSTEAD
>
	CAIG	T1,JOBPFI##+3	;IS BAD WORD IN PROTECTED PART OF JOB DATA AREA?
				; (BLT POINTER STOPS 1(KA10)3(KI10) BEYOND ERROR)
	TRO	T2,JS.JDP	;YES, FLAG JOB DATA AREA PARITY ERROR
				; SO JOB DATA AREA WILL BE CLEARED AT PI 7
				; SINCE MONITOR ADDRESSES ARE NO LONGER VALID
IFN FTMEMNXM,<
	TRNN	P1,UE.PEF	;PARITY ERROR?
	TRZ	T2,JS.JDP	;NO, DON'T ATTEMPT TO CLEAR JOBDAT SINCE IT
				; MAY BE IN NON-EXISTENT MEMORY
>
	HRRZ	T1,.CPLSB##(P4)	;JOB OR HIGH SEG NO. OF SEG BEING BLTED
IFN FT2REL,<
	CAIG	T1,JOBMAX##	;IS THIS A HIGH SEG BEING BLTED?
>
	IORM	T2,JBTSTS##(T1)	;NO, SET JOB ERROR BITS
	JRST	APPRSC		;GO REQUEST PI 7 SWEEP OF CORE (OK FOR
				; PI 7 TO BE IN PROGRESS - CORE COMMAND)
				; (NO INTERVENING PIS BETTER BE IN PROGRESS
				;  ELSE CAN NEVER DISMISS TO PI 7)
				;DO NOT FLAG CURRENT JOB, SINCE MAY NOT
				; BE THE JOB BEING SHUFFLED
;HERE ON EXEC PARITY IN NO SPECIAL PLACE - CHECK FOR SAME AS LAST INTERRUPT
APPSAM:	MOVE	T1,-1(P)	;GET ALL OF STORED PC INCLUDING FLAGS
	CAMN	T1,.CPLPP##(P4)	;SAME PC AS LAST ON REQUEST TO PI 7?
	JRST	APPSWP		;YES, HAVE TO SWEEP AT APR PI THEN
				; (PARITY ERROR AT UUO LEVEL IN MONITOR ON INSTR. FETCH
				; OR INSTR OR INDIRECT AT PI LEVEL)

;HERE IF EXEC MODE PC IS NOT IN ANY OF THE SPECIAL PLACES IN MONITOR OR SAME PC
	CONSO	PI,@.CPNAP##(P4)	;ARE ANY PI'S (BELOW APR) IN PROGRESS?
	JRST	APPRS1		;NO, GO REQUEST PI 7 SWEEP OF CORE
				; FLAG CURRENT USER TO BE STOPPED SINCE DOING HIS UUO

;HERE IF IT IS NECESSARY TO SWEEP CORE AT APR LEVEL TO FIND BAD ADRS.
; FOR FEAR OF DISMISSING AND THE MONITOR PROCEDING WITH DATA
; THAT IS POSSIBLY IN ERROR DUE TO THE BAD PARITY
APPSWP:	MOVE	T1,-1(P)	;GET STORED PC
	PUSHJ	P,APRPTS	;GET REAL PC
	MOVEM	T1,.CPAPC##(P4)	;STORE SO SWEEP ROUTINE WILL KNOW
				; WHERE PC IS IN CASE NO PARITY FOUND
				; ON SWEEP - SERIOUS IF EXEC MODE
	MOVEI	T1,.CPA00##(P4)	;FIRST ADR. OF PARITY SWEEP SAVE AC AREA
	BLT	T1,.CPA17##(P4)	;SAVE ALL ACS IN CDB BLOCK
	HLLZ	S,.CPMPS##(P4)	;REQUEST CPU SWEEP, SO JOBS WILL BE FLAGGED
				; TO STOP
IFN FTMEMNXM,<
	TRO	S,(P1)		;FLAG WHETHER NXM OR PARITY SWEEP
>
	PUSHJ	P,PARSW1##	;CALL USUAL PI 7 ROUTINE TO SWEEP CORE
				;(DO NOT PRINT ANY INFO)
	TLZ	S,(CP.PSX)	;CLEAR REQUEST TO SWEEP - SINCE ALREADY
				; SWEPT AT APR PI
	IORM	S,.CPAEF##(P4)	;STORE PRINT REQUEST FOR PRINT ROUTINE
				; SO IT WILL NOT THINK CHAN FOUND ERROR
	PUSHJ	P,PARCTY##	;IF ANY SERIOUS ERRORS OR NONE, PRINT ON CTY+HALT
				; RETURN IF NOT SERIOUS OR OPER PUSHES CONTINUE
				; NOT RECOMMENDED SINCE MONITOR WILL
				; PROBABLY HAVE BAD DATA
	MOVSI	17,.CPA00##(P4)	;RESTORE ALL ACS FROM CDB BLOCK
	BLT	17,17		;
	HLLZ	T1,.CPAEF##(P4)	;SWEEP AND PRINT REQUEST BITS FOR THIS CPU
	JRST	APPRS2		;GO REQEUST PI 7 TO PRINT (NO SWEEP)
				; DO NOT FLAG CURRENT USER WITH ERROR
;HERE ON PARITY ERROR WHEN PC REALLY IN USER MODE - T1 HAS REAL PC, R=JOBDAT
APPUSR:	EXCH	J,.CPJOB##(P4)	;SAVE AC J - GET CURRENT JOB NO.
	MOVE	T2,.CPCN1##(P4)	;USER ENABLED APR AND PI TRAPS
IFE FTMEMNXM,<
	TRNN	T2,UE.PEF	;IS HE ENABLED TO TRAP ON THESE?
>
IFN FTMEMNXM,<
	TRNN	T2,(P1)		;ENABLED FOR NXM OR PARITY ERROR?
>
	JRST	APPRS0		;NO, REQUEST PI 7 SWEEP OF CORE
	MOVE	T2,JBTSTS##(J)	;YES, JOB STATUS WORD
	TLNE	T2,JACCT	;IS JOB PRIVILEGED?
	JRST	APPPET		;YES, ALLOW PARITY ERROR TRAP
	MOVE	T2,JBTPPN##(J)	;JOB PROJECT-PROGRAMMER NO.
	CAME	T2,FSFPPN##	;IS IT THE OPERATOR PROJ-PROG?
	JRST	APPRS0		;NO, DON'T ALLOW TRAP, GO REQUEST SWEEP

;HERE TO TRAP TO PRIVILEGED, ENABLED USER - (J SET TO JOB NO, T1 TO REAL PC, R=JOBDAT)
APPPET:	EXCH	J,.CPJOB##(P4)	;RESTORE J, JOB NUMBER
IFE FTMEMNXM,<
	MOVEI	T2,UE.PEF	;JOBENB UUO PARITY DONE FLAG
	MOVEM	T2,JOBCNI##(R)	;STORE PSEUDO PROCESSOR FLAGS FOR USER OR ERRCON
>
IFN FTMEMNXM,<
	MOVEM	P1,JOBCNI##(R)	;STORE PSEUDO-PROCESSOR FLAG FOR USER OR ERRCON
	TRNN	P1,UE.PEF	;A PARITY ERROR?
	AOSA	.CPUEN##(P4)	;NO, NXM BUMP COUNT OF USER ENABLED NXM'S
>
	AOS	.CPUEP##(P4)	;INCREMENT COUNT OF USER ENABLED PAR ERRORS
				; ON THIS CPU
				; TO LOOK AT IN HIS INTERRUPT ROUTINE
	MOVE	T1,-1(P)	;GET STORED PC (SO CAN COMPUTE POINTER WHERE
				; REAL PC IS STORED (T2 IN APRPTS)
	JRST	APRE4A		;HANDLE TRAPS TO USER (T1 HAS STOPPED PC FOR APRPTS)
>				;END FTMEMPAR
;HERE IF APR INTERRUPT, BUT NOT CLOCK

APRER:	EXCH	T1,@.CPCHL(P4)	;SAVE T1, GET TRAP PC
	TLNN	T1,(XC.USR)	;INTERRUPT PC IN USER MODE?
APRER0:	CONSZ	APR,@.CPILM(P4)	;WAS ERROR ILM, IF SO MUST BE FROM USER
				; EVEN IF PC IN EXEC MODE - SEE APRPTS
	JRST	APRER3		;ERROR WAS USER GENERATED
	CONSZ	APR,@.CPEME(P4)	;DOES EXEC CARE ABOUT ERROR?
	JRST	APRER9		;YES, GO HANDLE IT
	AOS	.CPEDI##(P4)	;COUNT NO OF EXEC DON'T-CARE INTERRUPTS (AOV,FOV)
				; HAPPENS ONLY IF USER IS ENABLED WHEN MONITOR
				; CAUSES CONDITION
	HRLM	T1,.CPEDI##(P4)	;STORE OFFENDING PC SO WE CAN FIX CODE -
				; SINCE THIS SLOWS DOWN SYSTEM
	JRST	APRER1		;NO, CLEAR PC FLAGS, RESTORE T1, CLEAR APR AND DISMISS

;HERE IF ERROR GENERATED BY USER

APRER3:	XCT	.CPIUE##(P4)	;USER ENABLED FOR THIS ERROR?
	JRST	APRER6		;NO, STOP USER AND PRINT ERROR MESSAGE

;HERE TO TRAP TO USER - NOT CLOCK OR MEM PARITY
	EXCH	R,.CPADR(P4)	;SAVE AC R, GET CURRENT JOB ADDR. ON THIS CPU
	XCT	.CPUEH(P4)	;CONI APR TO JOB DATA AREA (JOBCNI)
				; INCLUDE THE CLOCK FLAG

;HERE TO TRAP TO USER ON CLOCK - R SET TO EVA OF USER JOB DATA AREA
APRER4:	PUSH	P,T1		;SAVE T1 AND T2
	PUSH	P,T2
;HERE TO TRAP TO USER ON MEM PARITY, R SET TO EXEC VIRT ADR OF JOB DATA AREA,
; T1 TO STORED PC
APRE4A:	PUSHJ	P,APRPTS	;GET POINTER TO REAL USER MODE PC

	MOVEM	T1,JOBTPC(R)	;STORE ERROR PC
	HRR	T1,JOBAPR##(R)	;GET USER TRAP ADDRESS
	CAMN	T1,JOBTPC##(R)	;IS INT FROM FIRST INSTR IN HIS TRAP
				; ROUTINE?
	JRST	APRRS3		;YES, GO STOP USER IF SAME INT PC
				; AS LAST, SET PC = 0 SO PI 7 CAN INT.
	HRRI	T1,1(T1)	;INCREMENT TRAP ADR BY 1
	CAMN	T1,JOBTPC##(R)	;SAME AS PC STORED BY INT?
	JRST	APRRS3		;YES, STOP JOB-INT FROM USER INT
				; ROUTINE-MEM PAR ALWAYS INCREMENTS PC
				; SO COULD BE IN A LOOP
;HERE IF NO POSSIBILITY OF A SYSTEM LOOP CAUSED BY FIRST INSTR.
; IN USER TRAP ROUTINE GIVING AN INT. ON INSTR. FETCH (BEFORE PI7 CAN INT.)
APRE4C:	HRR	T1,JOBENB(R)	;GET SAVED SOFTWARE ENABLE FLAGS
	TRNE	T1,XP.DDU	;DOES USER WANT TRAPS DISABLED WHENEVER ONE OCCURS?
	JRST	APRE4B		;NO, GO DISABLE CLOCK ONLY
;HERE TO DISABLE ALL USER ENABLED INTERRUPTS
	HLLZS	JOBENB(R)	;CLEAR SOFTWARE FLAGS SO THAT USER MUST DO
				; ANOTHER APRENB UUO IN ORDER TO ENABLE TRAPS
	SETZM	.CPCN1(P4)	;ALSO CLEAR USER APR CONSO FLAGS
	HRRI	T1,@.CPEEB(P4)	;AND SET MONITOR TO CHECK ONLY
	HRRM	T1,.CPCON(P4)	;PD OVF,ILM,NXM, AND CLOCK AND ADDRESS BREAK
	HRR	T1,.CPDUI(P4)	;GET APR CONO MASK
	HRRZM	T1,.CPLUC(P4)	;STORE FOR INTERRUPT LEVEL USE
	CONO	APR,(T1)	;DISABLE FOV, AROVF IN CASE ON
				; SO USER MUST REENABLE WITH APRENB UUO
APRE4B:	TRZN	T1,XP.CCF	;ALWAYS DISABLE CLOCK INTERRUPT
	JRST	APRER5		;BECAUSE USER CANNOT CONTROL ITS
	HRRM	T1,JOBENB(R)	;COMING AND COULD INTERRUPT HIS OWN
	ANDM	T1,.CPCN1(P4)	;INTERRUPT PROCESSOR WITHOUT MEANING TO.
APRER5:	HRR	T1,JOBAPR(R)	;GET USER TRAP ADDRESS
	MOVEM	T1,@T2		;SET UP USER TRAP FROM DISMISS
				; (IF ILM - COULD POINT TO LOWER PI JSR PC)
APREX1:	EXCH	R,.CPADR(P4)	;RESTORE JOB ADDRESS AND AC R
	POP	P,T2		;RESTORE T1
	POP	P,T1		;RESTORE T2
	JRST	APRER1		;GO CLEAR PC FLAGS AND DISMISS APR INTERRUPT
;HERE WHEN USER TRAP ROUTINE HAS LOOP (PC=FIRST OR SECOND ADR)
; MEM PARITY OR OTHER USER ENABLED TRAP.
APRRS3:
	MOVE	T1,JOBCNI##(R)	;APR CONI BITS ALREADY STORED FOR USER
	TRNN	T1,UE.PEF+IFN FTMEMNXM,<UE.NXM>	;IS THIS A MEM PARITY ERROR?
	JRST	APRE6A		;NO, JUST STOP JOB

IFN FTMEMPAR,<			;MEMORY PARITY ANALYSIS?
;HERE ON USER PARITY ERROR - T1 = REAL PC
;FLAG CURRENT USER THIS CPU AS HAVING ERROR AND HAVE TO BE STOPPED
APPRS1:	EXCH	J,.CPJOB##(P4)	;GET CURRENT JOB NO, SAVE J
APPRS0:	MOVEI	T2,JS.MPE!JS.APE	;JOB MEM PAR ERROR AND APR ERROR
IFN FTMEMNXM,<
	TRNN	P1,UE.PEF	;A PARITY ERROR?
	TRC	T2,JS.MPE+JS.NXM;NO, INDICATE NXM
>
	IORM	T2,JBTSTS(J)	;FLAG JOB TO GET PARITY MESSAGE
	EXCH	J,.CPJOB##(P4)	;RESTORE J, SAVE JOB NO.
	MOVE	T1,-1(P)	;STORED PC
	PUSHJ	P,APRPTS	;GET REAL PC = T1, ADR OF PC = T2
	CAMN	T1,.CPLPP##(P4)	;IS REAL PC SAME AS LAST PC?
	JRST	APRE6A		;YES, CLEAR PC TO 0, SO CAN DISMISS TO PI7
				; MUST BE MEM PAR ON INSTR. FETCH

;HERE TO REQUEST SWEEP OF CORE AT PI 7 TO FIND ALL BAD PARITY WORDS
; R=JOB DATA AREA PROPER JOB ERROR BIT ALREADY SET (IN CASE PAR NOT IN CURRENT JOB)
APPRSC:	HLLZ	T1,.CPMPS##(P4)	;GET SWEEP REQUESTED BY CPU N (THIS CPU) BITS
				; (CP.PXX+CP.RSX)
IFE FTMEMNXM,<
	TRO	T1,UE.PEF	;PSEUDO PARITY ERROR FLAG FOR APR CONI
>
IFN FTMEMNXM,<
	TRO	T1,(P1)		;SET PUEUDO PARITY OR NXM FLAG
>
APPRS2:	IORM	T1,.CPAEF##(P4)	;SET FLAG FOR PI 7 TO SEE PAR ERROR
				; AND CALL PARITY SWEEP ROUTINE
	MOVEM	T1,.JBCNI##(R)	;STORE ERROR FLAGS IN JOB DATA AREA
				; (IN CASE THIS IS CPU1 - CAN'T PRINT UNTIL ON CPU0)
	MOVE	T1,-1(P)	;GET STORED PC
	PUSHJ	P,APRPTS	;GET REAL PC AGAIN (MAYBE DIFF ON KI10)
	SKIPE	.CPTSD##(P4)	;WAS THIS INTERRUPT CAUSED BY A HARD TRAP
				;FAILURE ON A KL10?
	MOVE	T1,.CPPPC##(P4)	;YES, GET THE REAL INTERRUPT PC

	SETZM	.CPTSD##(P4)	;CLEAR THE INTERLOCK FLAG

	MOVEM	T1,.CPMPP##(P4)	;STORE MEM PAR PC FOR PI7
	MOVEM	T1,.CPLPP##(P4)	;REMEMBER THIS PC AS LAST PC
				; CLEARED WHEN PI7 SWEEP FINISHED
				; USED TO DETECT WHEN PI7 IS NOT GETTING INTERRUPT
				; WHEN APR DISMISSES (PAR ON INSTR. FETCH)
	JRST	APRE6B		;STORE ERROR PC AND REQUEST PI 7
				; DO NOT CLEAR PC SINCE CHECK WILL BE
				; MADE ON NEXT INTERRUPT FOR EXEC OR USER
				; DISMISS LOOP - SEE .CPLPP
>				;END FTMEMPAR
;HERE IF CURRENT JOB IS TO BE STOPPED

APRER6:	EXCH	R,.CPADR(P4)	;GET JOB ADDRESS SAVE R
	PUSH	P,T1		;SAVE T1 (CONTAINS PC WORD)
	PUSH	P,T2		;SAVE T2
	PUSHJ	P,APRPTS	;GET POINTER TO USER MODE PC
	XCT	.CPUEH##(P4)	;SET UP FLAG TO CLOCK LEVEL (CONI APR,JOBCNI)
				; NOTE:  DO NOT STORE IN .CPAEF, SINCE MAYBE CPU1.
				; SINCE JS.APE IS SET, ERROR WILL BE CAUGHT JUST
				; BEFORE RUNNING THE USER
;HERE TO STOP USER ELSE HE IS IN A SYSTEM LOOP (FIRST INSTR. IN HIS
; INTERRUPT ROUTINE CAUSES INTERRUPT BEFORE PI7 CAN GET IN)
APRE6A:	MOVSI	T1,(XC.USR)	;DISMISS TO USER 0
	EXCH	T1,@T2		;WHENEVER PC REACHES CLOCK LEVEL (MAYBE -1(P))
APRE6B:	MOVEM	T1,.CPAPC(P4)	;STORE PC FOR ERROR REPORTING
	MOVEM	T1,JOBTPC(R)	;STORE ERROR PC FOR USER TO LOOK AT
	MOVEI	T2,JS.APE	;GET ERROR BIT
	EXCH	J,.CPJOB(P4)	;GET JOB NO. OF JOB ON THIS CPU
	IORM	T2,JBTSTS(J)	;SET ERROR BIT IN STATUS WORD
IFN FTMS,<			;DUAL PROCESSOR?
	PUSHJ	P,CP1APE##	;MAKE SURE JOB CAN RUN ON CPU0 SO
				; ERROR MESSAGE WILL PRINT
>
	EXCH	J,.CPJOB(P4)	;RESTORE J
	EXCH	R,.CPADR(P4)	;RESTORE R
APREX3:	POP	P,T2		;RESTORE T2
	POP	P,T1		;RESTORE T1 (PC WORD - MAY HAVE CHANGED)
	JRST	APRER8		;REQUEST CLK INT, CLEAR FLAGS AND DISMISS
;EXIT - APR ERROR IN EXEC MODE - MAY BE SERIOUS
APRER9:	XCT	.CPEEH##(P4)	;STORE APR STATUS FOR PI 7 PROCESSING
				; BY CPU0 OR CPU1
	MOVEM	T1,.CPAPC##(P4)	;STORE ERROR PC FOR PI 7 TO FIND
IFN FTHALT,<
	CONSZ	PI,@.CPNAP##(P4) ;ANY PIS IN PROGRESS (NOT APR)
	STOPCD	.+1,STOP,POP,	;++PI ON PROGRESS
>				;CONTINUE WILL TRY THOUGH
				;DO NOT CLEAR PC TO IMPROVE CHANCES
	 			; OF GETTING TO PI 7 LEVEL.  ONLY CASE
				; CLEARING PC WOULD HELP IS NXM ON INSTR.  FETCH
				;(EXEC MODE MEMORY OFF-LINE OR WILD TRANSFER)
				; IN THIS CASE SYSTEM WILL LOOP ON CONTINUE

;EXIT - REQUEST PI 7 INTERRUPT AND RESCHEDULE (STOP) CURRENT USER
APRER8:	SETOM	.CPCKF##(P4)	;SET FLAG FOR CLK (PI 7) INTERRUPT
	SETOM	.CPSCF##(P4)	;FORCE RESCHEDULING EVEN IF ERROR
				; IS IN MONITOR
	CONO	PI,XI.RQC	;REQUEST CLK (PI 7) INTERRUPT

;EXIT - CLEAR PC FLAGS SO INTERRUPT CAN BE DISMISSED
APRER1:	TLZ	T1,(XC.OVF+XC.FOV+XC.FUF+XC.NDV) ;CLEAR PC FLAGS
				; OVF, FOV, FLOAT UNDERFLOW, NO DIVIDE
APRER2:	EXCH	T1,@.CPCHL##(P4)	;RESTORE T1, SAVE (NEW) DISMISS PC
	CONO	APR,@.CPIEF##(P4) ;CLEAR ALL FLAGS EXCEPT CLOCK, PAR
				;(PAR ALREADY CLEARED, MIGHT GET ONE IN
				; THIS ROUTINE, CLOCK MIGHT LOSE TIME).
	POPJ	P,		;RETURN AND DISMISS

;SUBROUTINE TO SET UP POINTERS TO REAL PC FOR APR ON THIS CPU
; REAL PC CAN DIFFER FROM STORED PC BY APR JSR IF AN INTERMEDIATE
; LEVEL PI SNEAKS IN ITS JSR
; KA10 - ONLY ILM - THEREFORE REAL PC BETTER BE USER MODE
; KI10 - NXM AND PARITY ERROR - REAL PC EXEC OR USER MODE
; CALLED ON EVERY MEMORY PARITY INTERRUPT
;CALL:	PUSH	P,T1		;PC WORD
;	PUSH	P,T2		;
;	PUSHJ	P,APRPTS
;	RETURN HERE, C(T1)=REAL ERROR PC
;		     C(T2)=POINTER TO LOCATION OF SAVED USER MODE PC
;	WARNING T2 MAY BE POINTER TO THIS STACK -1(P) AFTER POPJ.

	INTERN	APRPTS

APRPTS:	TLNE	T1,(XC.USR)	;INTERRUPT PC IN USER MODE?
	JRST	APRPT1		;YES, EASY TO SET UP
	CONI	PI,T1		;GET PI'S CURRENTLY IN PROGRESS
	ANDI	T1,@.CPNAP(P4)	;EXCEPT APRCHANNEL
	JFFO	T1,.+2		;DETERMINE CHANNEL NUMBER
	JRST	APRPT0		;IF NO PIS IN PROGRESS, THEN STORED PC
				; IS REAL PC - RETURN IT
	LSH	T2,1		;COMPUTE ADDRESS OF JSR
	SUBI	T2,2*^D20-40	;FOR THIS CHANNEL
	ADD	T2,.CPTOS(P4)	;0 OR 100 FOR TRAP OFF SET
	HLRZ	T1,(T2)		;GET INSTRUCTION FROM PI LOCATION
	ANDI	T1,777000	;JUST GET OPCODE
	CAIE	T1,(JSR)	;IS THIS A JSR?
	AOS	T2		;MUST BE BLKI(O), GO TO 41+ZN
	MOVE	T2,(T2)		;GET "JSR CH'N"
	PUSH	P,(T2)		;SAVE POSSIBLE REAL PC FOR RET IN T1
	HRRZ	T1,-3(P)	;GET STORED APR PC
	CAIN	T1,1(T2)	;IS APR STORED PC ONE AFTER CH'N?
	JRST	TPOPJ##		;YES, THEN JSR HAD JUST SNUCK IN - RET REAL PC IN T2
	POP	P,T2		;NO, LIKELY ON MEMPAR (ALWAYS WHEN FROM SWEEP AT PI7

;HERE IF PC STORED BY APR JSR IS REAL PC WHICH CAUSED APR INTERRUPT
APRPT0:	MOVE	T1,-2(P)	;RETURN STORED PC AS REAL PC
APRPT1:	HRLOI	T2,P		;POINT TO SAVED APRCHL PC ON PUSH DOWN STACK
	POPJ	P,		;RETURN (NOW REAL PC IS AT -1(P)).

;HERE FROM KASER OR KISER WITH THE ACS SAVED IF APPROPRIATE
; I.E., ALWAYS ON A KA10, ONLY IF THE PC IS IN EXEC MODE ON THE KI10
CHKAPE::
IFN FTPI,<
	SETZM	CK0CHL##	;SO PSISER WON'T FIND THE NULL JOBS PC
>
IFN FTVM,<
	SETOM	.C0ISF##	;FLAG IN THE SCHEDULAR
>
IFN FTMS,<	EXTERNAL SVMES,SVTYPE
	SKIPE	SVMES		;DOES THE SLAVE NEED A MESSAGE TYPED OUT
	PUSHJ	P,SVTYPE	;YES, GO TYPE IT OUT
>
	MOVEI	P4,.C0CDB	;GET CDB OFFSET FOR THIS PROCESSOR
	MOVE	S,.CPAEF(P4)	;COMMUNICATION FLAG BETWEEN HIGHER PI LEVELS AND CLK
	JUMPE	S,RSCHED	;ANY APR OR PARITY ERRORS?
	PUSHJ	P,APRILM	;YES, GO PROCESS ERROR,APRILM WILL CLEAR .CPAEF
				; FLAG IMMEDIATELY 
	  JRST	RSCHED		;NOT PDL OV - RESCHEDULE
	PUSHJ	P,CPUTIM	;CHARGE THE CURRENT USER FOR HIS ACCUMULATED
				; CPU TIME INCLUDING THE PDL OVERFLOW
				; PROCESSING TIME
	  JRST	CIP6A		;IGNORE 0 CHARGES;CONTINUE SAME JOB
	LDB	T3,JBYLTM##	;ELSE, GET JOB'S TIME LIMIT
	JUMPE	T3,CIP6A	;NO LIMIT, CONTINUE SAME JOB
	SUB	T3,P1		;REDUCE REMAINING TIME
	SKIPG	T3		;IS THERE ANY TIME LEFT?
	MOVEI	T3,1		;NO, AMKE NEXT JOB ACC'T'NG FAIL
	DPB	T3,JBYLTM##	;REPLACE TIME LIMIT WITH NEW
	JRST	CIP6A		;GO CONTINUE WITH SAME JOB
TSTRS:	AOS	(P)		;TEST R AND SKIP
TESTR:	SKIPE	R		;R NON-ZERO? (20-37 WIPED IF NOT)
	POPJ	P,		;YES, RETURN
	STOPCD	.+1,DEBUG,NCJ,	;++NO CORE FOR JOB
	MOVE	R,.C0ADR##	;ATTEMPT RECOVERY
	POPJ	P,

;HERE AT UUO LEVEL WHEN CURRENT JOB RETURNS TO USER MODE
;FROM A UUO CALL AND EITHER:
;	1. CURRENT JOB TYPED CONTROL C WHILE IN EXEC MODE
;	2. CLOCK FLAG WENT OFF WHILE CURRENT JOB WAS
;		IN EXEC MODE

;CALL:	MOVE J,CURRENT JOB NUMBER
;	PUSHJ P,USCHD1	;FROM UUOCON(UUO HANDLER RETURN TO USER)
;	RETURN HERE WHEN RUNABLE
	INTERN	USCHD1

USCHD1:
IFN FTMEMPAR,<
	TRNN	T1,JS.MPE	;MEM PAR AT UUO LEVEL ?
	JRST	USCHD2		;NO, GO CHECK FOR ^C.
	PUSHJ	P,STOP1C	;YES, STOPJOB
	JRST	USCHED		;STOPPED
USCHD2:
>
	TLNE	T1,CNTRLC	;^C TYPED WHILE IN MONITOR ?
	PUSHJ	P,STOP1		;YES, STOPJOB.

;HERE AT UUO LEVEL FROM MONRET UUO
;SAME CALL AS USCHD1, EXCEPT T1 NOT SETUP


INTERNAL USCHED
EXTERNAL JOBDPG,JOBDPD

USCHED:	POP	P,.C0PC##	;SAVE PC IN PROTECTED PART OF SYSTEM DATA
	PUSHJ	P,TESTR		;MAKE SURE R IS SETUP
	MOVEM	J,JOBDAC##+J(R)	;SAVE CURRENT JOB NUMBER
				; NEEDED ON CALL FROM USER UUO EXIT
				; SINCE CAN START UP ON EITHER CPU
	MOVEM	R,JOBDPG(R)	;SAVE R IN DUMP AC AREA
	MOVEM	P,JOBDPD(R)	;SAVE P
	JRST	WSCHD2		;GO SETUP LONGER PDL AND RESCHEDULE
;HERE AT UUO LEVEL WHEN JOB GOES INTO IO WAIT OR SHARABLE DEVICE WAIT
;CALL:	PUSHJ P,WSCHED
;	RETURN HERE WHEN RUNABLE AGAIN

EXTERNAL JOBDAC,JOBD16

WSCHED::
	MOVEM	17,JOBD17##(R)	;SAVE AC17 IN DUMP ACS (P4 IN NEW ACS)
	PUSHJ	P,TSTRS		;MAKE SURE R IS SETUP
WSCHD1::PUSHJ	P,TESTR		;MAKE SURE R IS SETUP
	POP	P,.C0PC##	;SAVE PC IN PROTECTED PART OF SYSTEM DATA
	MOVEI	17,JOBDAC(R)	;SAVE ACS 0-16 IN DUMP ACS
	BLT	17,JOBD16(R)	;IN CURRENT JOB DATA AREA
WSCHD2:	MOVE	P,.C0NPD##	;NULL JOB PD LIST
				;USED TO CALL SCHEDULER AND COMMAND DECODER
				; OTHERWISE GET PD OUF
				;FALL INTO RSCHED AND RESCHEDULE
	MOVEI	P4,.C0CDB	; WITH P4 SET UP WITH CDB FOR CPU 0
;SLAVE PROCESSOR ENTERS HERE WITH P4 SET UP TO CPU DATA BLOCK
	INTERN	FTKCT,RSCHED
EXTERNAL COMCNT,HNGTIM
EXTERNAL PMONTB

RSCHED:
IFN FTVM!FTMS,<
	SETOM	.CPISF##(P4)	;FLAG IN THE SCHEDULAR
>
IFN FTPI,<
	MOVE	J,.CPJOB(P4)	;GET CURRENT JOB #
	SKIPN	.CPTMF(P4)	;DID CLOCK TICK?
	JRST	NTAPRC		;NOT APR CLOCK
	MOVE	T2,DATE##	;UNIVERSAL DATE/TIME
	SIGNAL	C$APRC		;SIGNAL APR CLOCK
	EXCTXU	<MOVEM T2,IBKISW##(M)>	;STORE FOR USER
>;END FTPI
NTAPRC:	PUSHJ	P,CPUTIM	;CHARGE USER WITH CPU TIME USED
	  JRST	CIP1		;DID NOT USE FULL JIFFY
	JRST	CIP0		;USED OVER A JIFFY
;TIME ACCOUNTING
;THE VARIOUS TIME TOTALS ACCUMULATED FOR JOBS ARE BASED ON
;UNITS OF JIFFIES (1/60 OR 1/50 SECOND ACCORDING TO LOCAL
;POWER LINE FREQUENCY.)  IN ORDER TO USE THE GREATER PRECISION
;OF THE DK10 REAL TIME CLOCK IN A MANNER COMPATABLE WITH
;EXISTING PROGRAMS THAT USE THESE TOTALS, SEPARATE TOTALS OF 10^-5 JIFFIES
;PAST LAST WHOLE JIFFY ARE MAINTAINED.  WHEN ONE OF THESE
;TOTALS EXCEEDS A JIFFY WE DECREMENT IT AND INCREMENT
;THE CORRESPONDING JIFFY COUNT.

EXTERN	TIME,MIDNIT,THSDAT,TSETBI

CPUTIM:	PUSHJ	P,TIMEX		;GET TIME IN T1
IFE FTEMRT,<
	SKIPN	P1,T1		;TEST FOR 0 (& SAVE TIME IN P1)
	POPJ	P,
>;END IFE FTEMRT

IFN FTEMRT,<
	MOVSI	T2,(ST.EMO)	;EXCLUDE MONITOR OVERHEAD?
	TDNE	T2,STATES##	;SKIP IF NO
	PUSHJ	P,ACCMOF##	;ITS TO BE EXCLUDED, TURN ACCOUNTING METER OFF
	SKIPN	P1,T1		;SKIP IF ANY REAL TIME TO CHARGE
	JRST	INCTIM		;YES, MUST INCREMENT USER TIME EVEN
				; THOUGH REAL TIME WAS NOT A TICK
>;END IFN FTEMRT
CPUTM1:

IFN FTTIME,<
;P1 IS NOW SET UP WITH THE LENGTH OF TIME FOR WHICH THE
;LAST USER RAN, IN JIFFIES *10^-5.  ABOVE CODE SHOULD NOT
;BE MADE CONDITIONAL BECAUSE THIS NUMBER MAY BE
;USED FOR SEVERAL DIFFERENT PURPOSES.

IFN FTRSP,<
	SKIPN	SWPNUF##	;SWAPPER NULL FLAG UP?
	JRST	INCLST		;NO, CONTINUE
	MOVE	T1,P1		;YES, COMPUTE NULL TIME VALUE
	ADD	T1,SWPNU2##
	IDIVI	T1,RTUPS##
	ADDM	T1,SWPNUL##
	MOVEM	T2,SWPNU2##
	SETZM	SWPNUF##	;CLEAR FLAG
	SKIPN	SWPPLT##	;LOST TIME UP THIS TICK?
	JRST	INCLST		;NO, CONTINUE
	MOVE	T1,P1		;YES, GET TIME IN T1
	ADD	T1,SWPLS2##	;ADD LAST REMAINDER
	IDIVI	T1,RTUPS##	;CONVERT TO JIFFIES PLUS REMAINDER
	ADDM	T1,SWPLOS##	;ADD TO SWAPPER LOST TIME
	MOVEM	T2,SWPLS2##	;REMEMBER NEW REMAINDER
	SETZM	SWPPLT##	;CLEAR LOST TIME FLAG
>;END IFN FTRSP
INCLST:	SKIPE	J,.CPJOB(P4)	;LAST JOB..WAS IT NULL JOB?
	JRST	INCTIM		; NO, CONTINUE
	SKIPN	.CPPLT##(P4)	; YES..WAS IT LOST TIME?
	JRST	INCNUL		; NOT LOST, JUST IDLE.
	MOVE	T1,P1		; LOST, INCREMENT TOTAL
	ADD	T1,.CPLS2##(P4)	;ADD PREV EXCESS
	IDIVI	T1,RTUPS##	;CONVERT TO JIFFY + EXCESS
	ADDM	T1,.CPLST(P4)	;INCREMENT JIFFY TOTAL
	MOVEM	T2,.CPLS2(P4)	;REMEMBER EXCESS
	SETZM	.CPPLT(P4)	;CLEAR LOST TIME FLAG

IFN FTKL10&FTMS,<
	SKIPN	.CPCLF##(P4)	;LOST TIME BECAUSE OF CACHE ON DUAL CPUS?
	JRST	INCNUL		;NO
	MOVE	T1,P1
	ADD	T1,.CPCL2##(P4)	;DO USUAL STUFF
	IDIVI	T1,RTUPS##
	ADDM	T1,.CPCLT##(P4)	;MORE LOST TIME 
	MOVEM	T2,.CPCL2##(P4)	;SAVE REMAINDER
	SETZM	.CPCLF##(P4)	;CLEAR FLAG
>;END FTKL10&FTMS
INCNUL:	MOVE	T1,P1		;INCREMENT IDLE TIME
	ADD	T1,.CPNL2##(P4)	;ADD PREV EXCESS
	IDIVI	T1,RTUPS	;CONVERT TO JIFFY + EXCESS
	ADDM	T1,.CPNUL##(P4)	;INCREMENT JIFFY TOTAL
	MOVEM	T2,.CPNL2(P4)	;REMEMBER EXCESS

;INCREMENT JOB'S RUNTIME
INCTIM:	PUSHJ	P,FNDPDB##	;GET ADDRESS OF PDB
	  JRST	CPOPJ1##	;NO PDB (KJOB UUO)
	.ADD	P1,.PDTT2(W)	;ADD JOB'S EXCESS BEYOND JIFFY
	IDIVI	P1,RTUPS	;CONVERT TO JIFFY + EXCESS
	.MOVEM	P2,.PDTT2##(W)	;REMEMBER EXCESS
IFN FTEMRT,<
	PUSHJ	P,GETEBT##	;GET EBOX TIME FROM EBOX CYCLE COUNTER
				; HIGH ORDER IN T1, LOW IN T2
	PUSHJ	P,CLREBT##	;CLEAR OUT COUNT SO NEXT TIME WE READ
				; FOR THIS JOB WE WILL GET INCREMENTAL
				; EBOX COUNTS.  THIS IS NECESSARY
				; SINCE JOBS DON'T ALWAYS HAVE UPT'S
	.ADD	T2,.PDEB2##(W)	;ADD IN EXCESS FROM LAST TIME
	TLZE	T2,(1B0)	;OVERFLOW?
	AOS	T1		;YES
	DIV	T1,.CPEBJ##(P4)	;DIVIDE BY EBOX COUNTS PER JIFFY
	.ADDM	T1,.PDEBT##(W)	;ADD TO TOTAL EBOX TIME FOR JOB
	.MOVEM	T2,.PDEB2##(W)	;SAVE LEFTOVERS FOR NEXT TIME
	MOVE	P2,T1		;SAVE EBOX COUNTS IN P2
	PUSHJ	P,GETMBT##	;GET MBOX COUNTS IN T1,T2
	PUSHJ	P,[PUSH	P,T1	;SAVE T1
		   PUSHJ P,CHKPMJ##	;CHECK JOB ENABLE CONDITION
		     JRST TPOPJ##
		     JRST TPOPJ1##]
	JRST	INCTAA		;PERF METER NOT RUNNING FOR LAST JOB, DON'T UPDATE
	DMOVE	T3,T1		;GET COPY OF MBOX REFS
	DADD	T3,.CPMM0##(P4)	;GET NEW TOTAL
	DMOVEM	T3,.CPMM0##(P4)	;STORE
INCTAA:	PUSHJ	P,CLRMBT##	;CLEAR OUT COUNT SO NEXT TIME WILL BE
				; INCREMENTAL. HAVE TO DO ALL THIS
				; CLEARING NOW, OR ELSE USERS WON'T
				; BE CHARGED OVERHEAD IF THAT IS DESIRED.
	.ADD	T2,.PDMB2##(W)	;ADD IN EXCESS FROM LAST TIME
	TLZE	T2,(1B0)	;OVERFLOW?
	AOS	T1		;YES, INCREMENT HIGH ORDER WORD
	DIV	T1,.CPMBJ##(P4)	;CONVERT TO JIFFIES
	.ADDM	T1,.PDMBT##(W)	;REMEMBER HOW MUCH IN .PDMBT
	.MOVEM	T2,.PDMB2##(W)	;AND SAVE REMAINDER
	ADD	P2,T1		;GET TOTAL RUNTIME IN P2
	MOVE	T1,CNFST2##	;GET STATES WORD
	TRNN	T1,ST%EMR	;EBOX/MBOX RUNTIME?
	JRST	INCTMA		;YES, WE'VE UPDATED PDB AND NOW WE USE
				; THE HIGH PRECISION RUNTIME WHICH IS STILL IN P1
	.ADDM	P2,.PDRTM##(W)	;OTHERWISE UPDATE USER RUNTIME WITH
	.ADDM	P2,.PDTTM##(W)	;ARTIFICIAL RUNTIME
	JRST	INCTMB		;AND CONTINUE
>;END IFN FTEMRT

INCTMA:
	SKIPN	P2,P1		;SINCE NOT USING EBOX/MBOX, SETUP P2 OLD STYLE
	POPJ	P,		;NOT PAST JIFFY SO DON'T INCREMENT TOTALS
;NOW P1 / NUMBER JIFFIES BY WHICH JOB'S RUN TIME
;HAS INCREASED SINCE THE LAST TIME IT WAS STOPPED. (NORMALLY THE
;INCREASE IN JIFFIES WILL BE 0 OR 1, BUT IT MIGHT POSSIBLY BE MORE.)

;NOTE: JOB 0 TIME IS NULL JOB TIME FOR ALL PROCESSORS IN A
;MULTIPROCESSOR SYSTEM.

	.ADDM	P1,.PDRTM##(W)	;INCREMENTAL RUN TIME
	.ADDM	P1,.PDTTM##(W)	;TOTAL RUN TIME
INCTMB:
IFN FTKCT,<			;KILO CORE TICKS?
	PUSHJ	P,JOBSIZ##	;GET SIZE OF JOB (LOW + HIGH SEG) INTO T2
	IMUL	T2,P1		;MULTIPLY BY INCREASE IN JIFFY RUN TIME

	.ADDM	T2,.PDKCT##(W)	;ADD TO KILO-CORE-TICKS
IFN FTVM&FTACCT,<
	PUSHJ	P,VMSIZE##	;JOB VIRTUAL SIZE
	ADDI	T2,UPMPSZ##(T1)
	LSH	T2,P2KLSH##	;CONVERT TO K
	IMUL	T2,P1		;VIRTUAL KCS
	ADDM	T2,.PDVKC##(W)	;ACCUMULATE
>
>				;END FTKCT CONDITIONAL
IFN FTNSCHED,<
	ADDM	P1,TOTUTM##	;ADD TO TOTAL TIME WE COULD GIVE TO USERS
	ADDM	P1,RTCTOT##	;UPDATE TOTAL TIME GIVEN OUT SINCE WE SET
				; CLASS QUOTAS
>;END IFN FTNSCHED
	JUMPE	J,CPOPJ1##	;IF JOB ZERO, RETURN
	.LDB	T2,PDYQNT##	;GET IN QUE TIME
	SUB	T2,P1		;SUBTRACT JIFFIES CHARGED FOR BY CLOCK
	JUMPGE	T2,.+2		;GONE NEGATIVE?
	SETZ	T2,		;YES. PUT IN A ZERO
	.DPB	T2,PDYQNT##	;STORE NEW VALUE FOR SCHED1
IFN FTPSCD,<
	LDB	T2,PJBST2##	;GET PHYSICAL QUEUE
	CAIN	T2,PQ1##
	ADDM	P1,RNTPQ1##	;CHARGE PQ1
	CAIN	T2,PQ2##
	ADDM	P1,RNTPQ2##	;CHARGE PQ2
	CAIN	T2,CMQ##	;HPQ?
	ADDM	P1,RNTHPQ##	;CHARGE HPQS
>
IFN FTNSCHED,<
	SKIPN	.CPSQF##(P4)	;EXIT IF THIS JOB NOT FROM SUBQUEUES
	JRST	CPOPJ1##	;GIVE ACCOUNTING DONE RETURN

;HERE IF SCHEDULER IS TRYING TO SATISFY QUOTAS FOR ONE OR MORE CLASSES.
; INCREMENT TOTAL RUNTIME, INCREMENTAL RUNTIME, AND QUOTA LEFT FOR
; THIS JOB'S CLASS.


	ADDM	P1,TOTRTC##	;INCREMENT TOTAL RUNTIME FOR ALL CLASSES
				;MINUS TIME THEY GOT WHEN ALL QUOTAS WERE
				;EXHAUSTED (WHEN RRFLAG = 0)
	LDB	T2,JBYCLS##	;GET THIS JOB'S CLASS NUMBER
	ADDM	P1,CLSITM##(T2)	;INCREMENT RUNTIME FOR THIS CLASS THIS INTERVAL
	ADDM	P1,CLSRTM##(T2)	;AND RUNTIME FOR THIS CLASS SINCE STARTUP
	SKIPG	CLSQTA##(T2)	;IF ALREADY OUT OF GAS
	JRST	CPOPJ1		;GO AWAY
	MOVN	T1,P1		;GET MINUS TIME
	ADDB	T1,CLSQTA##(T2)	;UPDATE QUOTA FOR THIS CLASS
	JUMPG	T1,CPOPJ1##	;IF ANY LEFT, EXIT
	SOS	RRFLAG##	;OTHERWISE DECREMENT COUNT OF
				;CLASSES WITH NONZERO QUOTA
>;END IFN FTNSCHED
	JRST	CPOPJ1##	;EXIT
;HERE IF CURRENT JOB HAS NO PDB (KJOB UUO)
CIP0:	MOVE	R,JBTADR(J)	;ADR OF JOB
	JUMPE	J,CIP2
IFN FTTLIM,<
	LDB	T3,JBYLTM##	;GET JOB'S TIME LIMIT
	JUMPE	T3,INCTM4	;NO LIMIT, CONTINUE
	SUB	T3,P2		;REDUCE REMAINING TIME BY RUN TIME
	JUMPG	T3,INCTM3	;REACH LIMIT?
;HERE WHEN TIME LIMIT EXCEEDED
CIPTLE:	MOVSI	T3,JACCT	; YES
	TDNE	T3,JBTSTS(J)	;PRIVILEGED PROGRAM?
	JRST	INCTM2		; YES, LET IT GO
	PUSHJ	P,SIMCHK	;CAN JOB BE STOPPED?
	  SKIPA	T3,JBTLIM(J)	;YES, GET BATCH-JOB BIT
	JRST	INCTM2		;NO, TRY LATER (IN MIDDLE OF MONITOR)
	TLNE	T3,(JB.LBT)	;SKIP IF NOT BATCH JOB
	JRST	INCTM1		;ELSE BOMB HIM OUT
IFN FTPI,<
	SIGNAL	C$TLE		;SIGNAL TIME LIMIT UP
	  JRST	INCT1A		;TRAP TO THE USER
>
	MOVEI	T4,.ERTLX	;TIME LIMIT EXCEEDED ERROR
	PUSHJ	P,CHKINT##	;NO, HE WANT THIS INTERCEPT
	  JRST	INCTM1		;NO, GIVE ERROR MSG
	MOVE	T2,.CPPC(P4)	;PC AT INTERRUPT
	MOVEM	T2,JOBPD1(R)	;SAVE FOR DOINT
	HLL	T1,.CPPC##(P4)	;FLAGS AT INTERRUPT
	TLNE	T1,(XC.USR)	;USER MODE?
	HRRM	T1,.CPPC##(P4)	;YES, NEW START LOC GOES INTO PC WORD
	PUSHJ	P,DOINT##	;TELL USER PC, SET EXIT LOC
	SKIPA			;SKIP THE ERROR MESSAGE
INCTM1:	PUSHJ	P,@.CPTLE##(P4)	;TYPE LIMIT EXCEEDED MESG
INCT1A:	TDZA	T3,T3		;NEW LIMIT WILL BE 0 (I.E. NO LIMIT)
INCTM2:	MOVEI	T3,1		;MINIMUM LIMIT
INCTM3:	DPB	T3,JBYLTM	;REPLACE LIMIT
INCTM4:
IFN FTVM,<
	JUMPE	R,INCTM6	;NOTHING TO DO IF NO CORE IN CORE
	SKIPL	JBTSTS##(J)	;JOB RUNNABLE?
	JRST	INCTM6		;NO, DON'T TEST
	SKIPE	.UPMP+.UPTMC	;COUNTER ZERO?
	SOSLE	.UPMP+.UPTMC	;NO, DECREMENT COUNTER
	JRST	INCTM6		;NO COUNT SETUP OR COUNT HASN'T GONE TO ZERO
	MOVE	T1,.CPPC##(P4)	;GET THE JOB'S PC
	TLNN	T1,(XC.USR)	;PC IN USER MODE?
	JRST	INCTM5		;NO, TRY AGAIN IN A TIC
	HRRZ	T2,.JBPFH##(R)	;START OF PFH
	HLRZ	T3,.JBPFH##(R)	;END OF PFH
	CAIG	T2,(T1)		;PC IN PFH?
	CAIGE	T3,(T1)		; ..
	SKIPA	T2,[EXP IC.UOU+TIMFLT##] ;NO, PC TO CATCH TIME FAULT AT UUO EXIT
	JRST	INCTM5		;YES, POSTPONE TIME FAULT ONE TICK
	MOVEM	T1,.UPMP+.UPTMC	;STORE OLD PC FOR TIMFLT AND
				; PSISER
	MOVEM	T2,.CPPC##(P4)	;MAKE CONTEXT SWITCH GO TO TIMFLT
	JRST	INCTM6
INCTM5:	MOVEI	T1,1		;WAIT ONE TICK FOR VIRTUAL TIME TRAP
	MOVEM	T1,.UPMP+.UPTMC	;STORE NEW VALUE IN COUNTER OR USER'S PC
INCTM6:>	;END FTVM
>				;END FTTLIM CONDITIONAL
>				;END FTTIME CONDITIONAL
;HERE AFTER ALL TIME CHARGING TO CURRENT USER HAS BEEN DONE
CIP1:
	MOVE	T1,.CPPC##(P4)	;PICK UP PC
	MOVE	J,.CPJOB##(P4)	;&JOB #
	SKIPN	T2,JBTADR##(J)	;ADDRESS OF JOBDAT
	JRST	CIP2		;NONE
	MOVEM	T1,JOBPC##(T2)	;STORE PC FOR ALL TO SEE
IFN FTWATCH,<
	MOVE	T2,JOBPD1##(T2)	;ADDRESS OF UUO
	SUBI	T2,1
	TLNE	T2,(XC.USR)	;IN USER MODE?
	HRRM	T2,JBTPC##(J)	;YES--STORE FOR CONTROL-T
	TLNE	T1,(XC.USR)	;ARE WE IN USER MODE?
	HRRM	T1,JBTPC##(J)	;YES--STORE PC
>;END FTWATCH

CIP2:	SKIPN	.CPTMF(P4)	;HAS THE JIFFY CLOCK TICKED SINCE
				; WE WERE HERE LAST?
	JRST	CIP6		; NO, JUST RESCHEDULE

;NOTE: ALL PROCESSING DRIVEN BY TIME INTERVALS EXCEPT
;THE ABOVE RUN TIME ACCOUNTING IS DRIVEN BY THE JIFFY (POWER LINE)
;CLOCK.  THE FLAG .CPTMF IS SET AT APR INTERRUPT LEVEL WHEN THE JIFFY
;CLOCK INTERRUPTS.  NONE OF THE FUNCTIONS CONTROLLED BY .CPTMF ARE
;CRITICALLY TIME DEPENDENT, IN THAT MISSING OR DELAYING THE PROCESSING
;OF ONE TICK WOULD BE A SERIOUS PROBLEM.

IFN FTMS,<		;MASTER/SLAVE?
	SKPCPU	(0)		;MASTER?
	JRST	CIP6		;NO, SLAVE DOES NOT UPDATE TIME
>
IFN FTMETR,<
	SKIPGE	T2,MP4##	;METER CLOCK TICKS
	PUSHJ	P,@MPDPRA##(T2)	;YES, CALL POINT ROUTINE
>
;DO SYSTEM TIME ACCOUNTING

	MOVE	T1,TIME##	;REMEMBER THIS TIME FOR
	EXCH	T1,TIMLST##	;  NEXT TIME & COMPUTE
	SUB	T1,TIMLST	;  DIFFERENCE (TIMINT)
	MOVNS	T1
	SKIPGE	T1		;IN CASE WENT THRU MIDNIGHT
	ADD	T1,MIDNIT##
	MOVEM	T1,TIMINT##

;UPDATE SMITHSONIAN DATE-TIME
				;T1 = # OF TICKS TO ADD
	HRLZ	T2,T1		;T2 = T1*1000000
	SETZM	T1
	ADD	T2,DATREM##	;  + REMAINDER FROM LAST TIME
	DIV	T1,MIDNIT##
	MOVEM	T2,DATREM##	;REMEMBER REMAINDER
	HRRZ	T2,DATE##	;RH=FRACT. OF DAY
	ADD	T2,T1
	TLNE	T2,-1		;DON'T BUMP DAY (RH)
	MOVEI	T2,-1		;  LET 'HOUR' DO IT
	HRRM	T2,DATE##

;PROCESS TIMING REQUESTS STORED IN QUEUE

	HRRZ	U,CLOCK		;GET END OF LIST
CIP4:	CAIN	U,CIPWTM	;END YET?
	JRST	CIP5		;YES
	HRRZ	T2,-1(U)	;DECREMENT TIME REQUEST
	SUB	T2,TIMINT##
	HRRM	T2,-1(U)
	SKIPLE	T2		;TIME EXPIRED?
	SOJA	U,CIP4A		;NO, CONTINUE SCAN
	MOVE	T1,(U)
	MOVE	T2,-1(U)
	CONO	PI,PIOFF	;YES, MOVE LAST ITEM IN LIST TO THIS
	MOVE	T3,@CLOCK
	SOS	CLOCK
	MOVEM	T3,(U)
	MOVE	T3,@CLOCK
	MOVEM	T3,-1(U)
	SOS	CLOCK
	CONO	PI,PION
	MOVSS	T2		;SETUP DISPATCH ADDRESS
	PUSH	P,U		;SAVE ONLY VALUABLE AC
	PUSHJ	P,(T2)		;AND DISPATCH TO TIMING REQUEST ROUTINE
	POP	P,U
	SUBI	U,1
CIP4A:	SOJA	U,CIP4		;GO BACK FOR MORE REQUESTS

CIP5:	SKIPG	HNGTIM		;SECOND COUNTER GONE TO ZERO (OR LESS)?
	PUSHJ	P,SECOND	;YES, GO DO ONCE-A-SECOND JOBS
IFN FTKI10!FTKL10,<
	SKIPE	T1,.C0JOB##	;CALL COMMAND DECODER IF NULL JOB IS RUNNING
	SKIPE	JBTADR##(T1)	;DON'T CALL COMMAND DECODER
				; IF CURRENT JOB LOGGED OUT SINCE
				; ITS CORE MAY BE REASSIGNED BEFORE
				; ITS REALLY STOPPED
>
	PUSHJ	P,TTYCMD##	;PROCESS ANY COMMAND
	MOVEI	P4,.C0CDB	;RESTORE P4 AFTER CALL TO COMCON
CIP6:
IFN FTKL10&FTMS,<
	PUSHJ	P,CSREQS##	;SERVICE POSSIBLE CACHE SWEEP REQUEST
				; BY ANOTHER CPU. DO IT BEFORE
				; GETTING INTERLOCK INCASE IT MIGHT
				; HELP OTHER CPU
>;END IFN FTKL10&FTMS
	CPLOCK	(SCD)		;LOCK SCHEDULER TO AVOID RACES
	PUSHJ	P,@.CPNXJ(P4)	;CALL SCHEDULER, SET J TO NEXT JOB # TO RUN
IFN FTMS,<
	CAME	J,.CPJOB(P4)	;IS THIS JOB SAME AS LAST JOB
	SKIPN	.CPADR(P4)	;OR WAS LAST JOB THE NULL JOB
	CPUNLK	(SCD)		;YES, CAN UNLOCK NOW
	SKIPE	T1,.CPJOB(P4)	;WAS LAST JOB THE NULL JOB
	CAMN	T1,J		;NO, IS THIS SAME AS LAST JOB
	JRST	CIP60		;YES, DON'T RING DRBELL
	HLRZ	T2,JBTSTS(T1)	;DO A QUICK RUNABILITY CHECK ON LAST JOB
	TRZ	T2,RUNMSK+CMWB	;CLEAR UNWANTED BITS
	CAIN	T2,RUNABL	;IS IT RUNABLE STILL
	SETOM	@.CPRDB##(P4)	;YES, RING OTHER CPU'S DOORBELL
CIP60:
	SKPCPU	(0)		;MASTER?
	JRST	CIP6A		;NO SLAVE DOES NOT DO MOVIE
>
				; TIME TO BE SKIPE SYSSNP
	SKIPE	SYSSNP##	;IF A PROGRAM WANT TO COLLECT
				; MONITOR DATA IT SHOULD POKE.
				; 27[SYSSNP] TO THE ABSOLUTE
				; LOCATION OF A ROUTINE TO CALL
	JSR	@SYSSNP##	;CALL THE ROUTINE
	REPEAT	0,<		;LEAVE OUT IN DISTRIBUTED VERSION
PATCHK::JFCL	CKJBAD		;IF THIS INSTRUCTION IS A PUSHJ P,CKJBAD
				; IT WILL:
				; 1. CHECK CORTAL MATCHES THE BIT MAP
				; 2. CHECK JBTADR AGAINST CORTAL
				; 3. EAT UP MASSIVE CPU TIME
				; THEREFOR, IT IS A JFCL. IF IT IS DESIRED
				; THE PATCH IS SIMPLE.
>;END REPEAT 0
CIP6A:	SETZM	.CPCKF(P4)	;CLEAR CLK INTERRUPT FLAG
				; SET ON ALL FORCED CLK INTERRUPTS
	SETZM	.CPTMF(P4)	;CLEAR TIMED (1 JIFFY) INTERRUPT FLAG.
	SETZM	.CPSCF(P4)	;CLEAR FORCED SCHEDULING FLAG
	SETZM	.CPRTF##(P4)	;CLEAR REAL TIME RESCHEDULE FLAG
IFN FTHPQ,<
	SETZM	.CPHQU##(P4)	;CLEAR FLAG SAYING CURRENT JOB DID A HPQ UUO
>
IFN <FTKI10!FTKL10>&FTSET,<
	CONI	APR,.CPAPR##(P4)  ;READ MI PROG DIS SETTING
>
	MOVE	U,.CPJOB(P4)	;T1 = LAST JOB RUN
	CAMN	J,U		;IS NEXT JOB SAME AS LAST ONE?
				;IF SEGMENT WAS MOVED, GO REMAP IT
	JRST	[MOVE	T1,JBTSGN##(J)
		 TLZN	T1,SEGMB	;WAS HIGH SEGMENT MOVED BY LOCK UUO?
		 JRST	CIPXIT	;NO, REMAP IS NOT NECESSARY.
		 MOVEM	T1,JBTSGN##(J)	;YES, CLEAR SEGMENT MOVED BIT.
		 PUSHJ	P,SETRL1##	;AND MAKE PAGE MAP REFLECT THE MOVE.
		 JRST	CIPXIT]
	SKIPE	U		;NO, SAVE PREVIOUS JOB NO. FOR PERFORMANCE
	MOVEM	U,.CPLJR(P4)	;MONITORING WITH A DISPLAY

IFN FTMETR,<			;METER NEW JOB #
	SKIPL	T2,MP2##	;POINT #2, IS IT ENABLED?
	JRST	CIP6A1		;NO
	HRRZ	T1,U		;POINT VAL.=LAST JOB TO RUN
	CAME	T1,MPDPAR##(T2)	;POINT PARAMETER SELECTS JOB NUMBER
	SKIPGE	MPDPAR(T2)	;OR ALL JOBS IF -1
	JRST	CIP6A0		;JOB NR OK, DO THE POINT
	JRST	CIP6A1		;WRONG JOB NO POINT
CIP6A0:	PUSHJ	P,FPDBT1##	;FIND PDB VIA T1
	  TDZA	T1,T1		;NO PDB
	HRL	T1,.PDTTM##(T1)	;PICK UP ITS CPU TIME
	HRR	T1,U		;RESTORE JOB#
	PUSHJ	P,@MPDPRA##(T2)
CIP6A1:
>				;IFN FTMETR
;DIFFERENT JOB, SAVE SOFTWARE STATE(HARDWARE ALREADY SAVED)

EXTERNAL JOBPRT,JOBJDA
	AOS	.CPTJC##(P4)	;COUNT NO. OF CONTEXT SWITCHES TO DIFF. JOB
				; (INCLUDE NULL JOB)

IFN FTKI10!FTKL10,<		;IF KI10,
	PUSHJ	P,SAVUAC##	;SAVE THE USER'S ACS (AC BLOCK 1) IN THE SHADOW AREA
>
	MOVEM	J,.CPJOB(P4)	;STORE NEW CURRENT JOB NUMBER
	SKIPN	R,.CPADR(P4)	;NULL JOB OR CORE 0 ON OLD JOB?
	JRST	CIP7		;YES, DO NO SAVE SOFTWARE STATE
IFE FTVM,<
	MOVEI	T1,JOBPRT(R)	;DEST.=FIRST LOC PROTECTED FROM USER
	HRLI	T1,.CPPRT##(P4)	;SOUR.=SYSTEM DATA STORAGE FOR CURRETN JOB
	SKIPL	T2,.CPHCU##(P4)	;MOVE NO. OF OLD USER IO CHAN. IN USE
	CAILE	T2,17		;MUST BE 17 OR LESS(IO MIGHT
				; CLOBBER IF ADDRESS CHECKING MISSES)
	MOVEI	T2,0		;MOVE ONLY CHN 0 IF NEG, OR GR 17
				; SAVGET SETS LH NEGATIVE DURING IO AS A FLAG
				; SINCE IT DOES IO INTO AND OUT OF
				; CHANNEL LOCATIONS (JOBJDA+1...JOBJDA+17).
	ADD	R,T2		;RELOCATE TO USER AREA
	BLT	T1,JOBJDA(R)	;MOVE TO USER JOB DATA AREA
				; STOP WITH USER CHANNEL 0-1+C(USRHCU)
>	;END IFE FTVM
IFN FTVM,<
	MOVE	T1,.CPPC##(P4)	;GET PC
	MOVEM	T1,JOBPC##(R)	;SAVE IT
	MOVE	T1,USRDDT##	;CONTEXT SWITCH JOBDDT SO THAT IT REMAINS
	MOVEM	T1,JOBDDT##(R)	;PROTECTED BUT USER CAN LOOK AT IT
>	;END IFN FTVM
IFN FTKL10&FTMS,<
	MOVE	T1,J		;SAVE NEW JOB NUMBER
	SETZ	J,		;SWITCH TO NULL JOB'S UPMP FOR A SEC
	PUSHJ	P,STEUB##	;BEFORE SETCSN IS CALLED SO THAT
				; ACCT METER STUFF IN UPMP IS STORED
				; BACK NOW
	MOVE	J,T1		;RESTORE
	PUSHJ	P,SETCSN##	;HERE WE ARE GUARANTEED TO HAVE DIFFERENT
				; NON-NULL JOB WITH CORE, SO CALL SETCSN.
				; ANY CACHE SWEEP ON THIS CPU AFTER THIS
				; CALL WILL MAKE THE OLD JOB
				; RUNNABLE ON ANOTHER CPU
	PUSHJ	P,CSHUUO##	;NOW DO A SWEEP IF OLD JOB IS ON THE
				; SLAVE NOW AND NEEDS A MASTER UUO
				; DONE.
>;END IFN FTKL10&FTMS
	CPUNLK	(SCD)		;UNLOCK SCHEDULER AFTER SAVING JOB'S STATE

;RESTORE SOFTWARE STATE OF NEW JOB,THEN HARDWARE STATE

INTERNAL NULJOB,NULADR
EXTERNAL JBTDAT,JOBPRT
EXTERNAL JOBHCU,JOBENB

NULJOB:				;TRANSFER HERE FROM SYSINI WITH J=0 AND .CPJOB(P4)=0
CIP7:
NULADR:
	PUSHJ	P,SETRL1##	;GO SETUP HARDWARE AND SOFTWARE RELOCATION
				; INFORMATION FOR NEW CURRENT USER

IFN FTKI10!FTKL10,<		;IF KI10,
	PUSHJ	P,RESUAC##	;RESTORE THE USER'S ACS (AC BLOCK 1)
				; FROM THE SHADOW AREA
>
	JUMPE	J,CIPXIT	;IS NEW JOB THE NULL JOB?

IFN FTHALT,<
	SKIPN	R		;DOES JOB HAVE CORE ASSIGNED?
	STOPCD	.,STOP,NCA,	;++NO CORE ASSIGNED
>
IFE FTVM,<
	MOVEI	T1,.CPPRT##(P4)	;NO, DEST.=PROTECTED AREA IN MONITOR
	HRLI	T1,JOBPRT(R)	;SOURCE=FIRST PROTECTED LOC. IN JB  DATA AREA
	SKIPL	T2,JOBHCU(R)	;MOVE NO. OF USER IO CHAN. IN USE
	CAILE	T2,17		;MUST BE 17 OR LESS(IO MIGHT CLOBBER
				; IF ADRRESS CHECKING MISSES
	MOVEI	T2,0		;MOVEJUST CHAN 0 IF NEG. OR GREATER THAN 17
				; SAVEGET SETS NEG.DURING IO
	ADDI	T2,(P4)		;RELOCATE PROPERTY INTO CDB
	BLT	T1,.CPJDA##(T2)	;AND MOVE INTO MONITOR
>	;END IFE FTVM

IFN FTVM,<
	MOVE	T1,JOBPC##(R)	;NEW USER'S PC
	MOVEM	T1,.CPPC##(P4)	;SAVE IT IN THE CDB
	MOVE	T1,JOBDDT##(R)	;CONTEXT SWITCH JOBDDT SO THAT
	MOVEM	T1,USRDDT##	;IT REMAINS PROTECTED BUT USER CAN LOOK AT IT
>	;END IFN FTVM
;RESTORE HARDWARE STATE OF NEW JOB
;CONTROL ALWAYS FLOWS THROUGH HERE (EVEN IF NULL JOB)
;  ON EACH CONTEXT SWITCH SO THAT MONITOR OVERHEAD
;  TIME MAY BE ACCUMULATED.

CIPXIT:
IFN FTKL10&FTMS,<
	SKIPN	J		;IF WE ARE RUNNING NULL JOB,
	PUSHJ	P,CSDMP##	;SWEEP CACHE, SINCE IT IS FREE.
>;END IFN FTKL10&FTMS
	PUSHJ	P,TIMEX		;GET OVERHEAD INTERVAL
	MOVE	T3,STATES##	;GET STATES
IFN FTEMRT,<
	TLNN	T3,(ST.EMO)	;AND EXCLUDE MONITOR OVERHEAD?
	JRST	CIPX1A		;NO
	PUSHJ	P,ACCMON##	;YES, SO WE TURNED METER OFF BEFORE. TURN ON AGAIN.
	SKIPN	.CPAPS##(P4)	;SCDPMR HAS BEEN CALLED IF ACC METER
				;AND PERF METER ARE IN SYNC
>;END IFN FTEMRT
IFN FTKL10,<
CIPX1A:	PUSHJ	P,SCDPMR##	;TURN PERF METER ON/OFF DEPENDING
				; ON JOB CONDITION
>
	TLNE	T3,(ST.EMO)	;EXCLUDE MONITOR OVERHEAD FROM USER RUNTIME?
	JRST	CIPXI1		;YES
	MOVE	T3,T1
	MOVE	T1,J
	PUSHJ	P,FPDBT1##
	  JRST	CIPXI0
IFN FTEMRT,<
	MOVE	T2,CNFST2##
	TRNN	T2,ST%EMR	;DON'T ADD OVERHEAD IF EBOX/MBOX RUNTIME
>;END IFN FTEMRT
	ADDM	T3,.PDTT2##(T1)	;YES - ADD TO LAST JOB'S TIME
CIPXI0:	SKIPN	J
	ADDM	T3,.CPNL2##(P4)	; & CDB NULL TIME
	MOVE	T1,T3
CIPXI1:	ADD	T1,.CPOH2##(P4)	;CONVERT TO JIFFYS
	IDIVI	T1,RTUPS##
	ADDM	T1,.CPOHT##(P4)	;ADD INTEGRAL JIFFYS
	MOVEM	T2,.CPOH2(P4)

	JUMPE	J,CIPXI2	;NULL JOB?
	MOVE	R,.CPADR(P4)	;NO-GET JOB DATA AREA
	MOVE	T2,JBTSTS##(J)	;GET THE JOB STATUS WORD
	TRNE	T2,JS.NTO	;IS HE DOING NON-BLOCKING TTY OUTPUT?
	PUSHJ	P,TTMORE##	;YES--DO SOME MORE OUTPUT


IFN FTPI,<
	MOVSI	T2,USRMOD	;USER MOD BIT IN PC WORD
	TDNN	T2,.CPPC##(P4)	;SKIP IF JOB IS IN USER MODE
	JRST	CIPPSI		;DO NOT TRAP IF EXEC MODE
	XCT	NOPISK##	;SKIP IF NO PI'S ARE TO BE GRANTED. THIS
				; IS EITHER BECAUSE THE JOB DID NOT DO
				; A PIINI., THE SYSTEM IS TURNED OFF, OR
				; PSISER IS NOT LOADED.
	XCT	@JBTPIA##(J)	;EXECUTE THE TRAP INSTRUCTION
CIPPSI::>

IFN FTCCIN!FTDAEM!FTOPRERR,<
	MOVEI	T1,UTRP		;TRAP PENDING BIT
	MOVSI	T2,USRMOD	;USER MODE
	TDNE	T2,.CPPC##(P4)	;CURRENT JOB IN USER MODE?
	TDNN	T1,JBTSTS(J)	; AND DOES IT HAVE A TRAP PENDING?
	JRST	CIPXI4		;NO, GO START THE USER
	ANDCAM	T1,JBTSTS(J)	;TURN OFF TRAP PENDING
	MOVE	T1,JOBFDV(R)	;GET OLD (IRP) PC
	MOVE	M,JOBINT(R)	;SETUP M FOR PUTWRD
	MOVEI	M,2(M)		; TO STORE PC IN THIRD WORD OF INT BLOCK
	PUSHJ	P,PUTWRD##	;STORE THE INTERRUPT PC
	  JFCL			;IGNORE ERROR
>
CIPXI4:
IFN FTVM!FTMS,<
	SETZM	.CPISF##(P4)	;FLAG NO LONGER IN SCHEDULAR
>
	JRST	@.CPRUA(P4)	;  & DISMISS
				;  (IMPURE--MASTER GOES TO CIP8A
CIPXI2:	IFN FTVM!FTMS,<
	SETZM	.CPISF##(P4)	;FLAG NO LONGER IN SCHEDULAR
>
	JUMPN	U,NULJB		;NULL JOB--WAS PREVIOUS JOB NULL?
				;NO--GO SET IT UP
	MOVE	R,.CPNJD(P4)	;YES--SET UP NULL JOB DATA AREA
	SKIPN	.CPNJE(P4)	;HAS AN ERROR OCCURRED WHILE NULL JOB
				; WAS RUNNING? IF YES, RESTORE ACS
				; ILL UUO LOSED ACS
	JRST	@.CPRUA(P4)	;DISMISS ROUTINE IS IMPURE
				; MASTER GOES TO CIP8A
				;IF NULL JOB ERROR FALL THRU TO NULJB

;THE NULL JOB
;RUNS IN USER MODE WITH PC=1 AND COUNTS IN AC 0

EXTERNAL TIME,THSDAT,MIDNIT

NULJB:
	SETZM	.CPNJE(P4)
				; CLEAR FLAG SAYING ERROR IN NULL JOB
				; LOC JOBDAT (LOCATION OF NULL JOB DATA AREA) TO 0
				; AS A FLAG (ONLY DUMP ACS USED IN NULL JOB DATA AREA)
				; IF ANY ERRORS (APRERR NON-ZERO) OCCURRED
				; WHILE CLK IN PROGRESS
				; CATCH THEM NEXT CLK INTERRUPT
	MOVSI	T1,NULCOD
	PXCTXU	<BLT T1,5>,<PX.MEM>	;CLEAR AC 0 USED FOR USUAL MONITORING OF
				; NULL TIME INTERVAL, INSTR. TO AC 1
IFN FTTRPSET,<
	MOVE	T1,AOJINS	;GET AOJA 1
	SKIPE	.CPSTS##(P4)	;IS TRPSET ENABLED
	EXCTXU	<MOVEM T1,3>	;YES DO NOT LOOK AT MEMORY
>
	EXCTXU	<MOVEM P4,P4>	;SETUP USER AC TO POINT TO PROPER CDB
IFN FTKL10,<
	USERAC
>;END IFN FTKL10
	JEN	@NULJPC##	;DISMISS IF INTERUPT IN PROGRESS
	XP	NULCNT,^D50	;# OF SOJG'S IN NULL JOB BEFORE
				;CHECKING DOORBELL
NULCOD:	0			;CLEAR AC0
	SOJG	6,1		;AC1 - DON'T CAUSE EXCESSIVE MEMORY INTERFERENCE
	MOVEI	6,NULCNT	;AC2 - START OF NULJOB
	SKIPE	400000+.CPDBL##(P4)	;AC3 - CHECK IF DOORBELL WAS RUNG
WAKINS::WAKE			;AC4 - WAKE UP MONITOR
AOJINS:	AOJA	1		;AC5 - COUNT UP LOC 0

;CPU0 COMES HERE TO START THE USER  (CIP8A IS IN .C0RUA)

	INTERN CIP8A
	EXTERNAL CURJOB
CIP8A:	HRRM	J,CURJOB	;PUT JOB NUMBER IN LOW CORE FOR OPERATOR (CPU0)
	JUMPE	J,CIP8B##	;GO IF NULL JOB
	MOVEI	T1,JS.APE	;DOES THIS JOB HAVE AN APR ERROR
	TDNN	T1,JBTSTS(J)	; PENDING FROM CPU1 OR INTERRUPT LEVEL ON CPU0?
	JRST	CIP8B##		;NO, RESTORE ACS AND START THE JOB RUNNING
IFN FTMS&FTTLIM,<	EXTERNAL CSPTLE
	PUSHJ	P,CSPTLE	;GO CHECK IF TIME LIMIT WAS EXCEEDED ON SLAVE
	  JRST	CIPTLE		;YES, JS.APE CLEARED, GO INTERCEPT OR PRINT MESSAGE
>
	MOVE	T1,JOBCNI(R)	;NO, GET APR ERROR CONI
IFN FTMEMPAR,<			;MEMORY PARITY OPTION?
	TLZ	T1,(CP.PS1!CP.PS2!CP.PS3!CP.PS4!CP.PS5)	;CLEAR REQUEST TO SWEEP
				;FOR ALL CPUS EXCEPT CPU0, SO CPU0 WILL NOT
				; SWEEP FOR ERROR ANOTHER CPU HAS ALREADY SWEPT FOR
>
	MOVEM	T1,.C0AEF	;STORE ERROR BITS FOR ERRCON
	MOVE	T1,JOBTPC(R)	;GET PC OF ERROR
	MOVEM	T1,.C0APC	;STORE IT FOR ERRCON PRINTING
	MOVE	P,.C0NPD##	;SETUP PUSH DOWN LIST POINTER
	JRST	CHKAPE		;GO HANDLE APR ERROR
REPEAT	0,<
;SUBROUTINE TO INSURE THAT CORTAL, CORTAB, AND JBTADR ALL MATCH
; EACH OTHER. THIS TEST MAKES DEBUGGING MUCH EASIER BUT USES MORE
; CPU TIME THAN IT IS WORTH AND SO IT SHOULD BE REPEAT 0'ED IN A 
; PRODUCTION MONITOR. TO CUT OUT OVERHEAD (BUT NOT SAVE
; ANY CORE YOU CAN PATCH "PATCHK" TO A JFCL.
;ALL AC'S ARE SAVED
;CALL WITH:
;	PUSHJ 	P,CHJBAD	
;	RETURN HERE OR HALT

CKJBAD:	PUSHJ	P,CHKTAL##	;FIRST MAKE SURE THAT CORTAB IS
				; NOT MESSED UP.
	PUSHJ	P,SAVE4##	;SAVE P1 THRU P4
IFN FTPDBS,< ;IS THE PDB'S LIVE IN USER CORE CHECK THEM
	MOVNI	P1,JOBN##	;START WITH PDB'S
> ;END FTPDBS
IFE FTPDBS,< ;IF THE PDB'S ARE IN MONITOR CORE START WITH JOB 1
	MOVEI	P1,1		;FIRST ENTRY IN JBTADR
> ;END FTPDBS
	SETZ	P2,0		;START WITH 0 WORDS IN USE
CHKADL:	HLRZ	P3,JBTADR(P1)	;GET SIZE OF SEGMENT
	PUSHJ	P,CNTCHK	;SEE IF WE SHOULD COUNT IT
	  ADDI	P2,1(P3)	;ADD IN NUMBER OF WORDS
	CAIE	P1,JBTMAX##	;GONE THROUGH WHOLE TABLE (DO NOT TRUST
				; HIGHJB)
	AOJA	P1,CHKADL	;NO--LOOP OVER ALL SEGMENTS
	MOVE	P3,MAXMAX##	;GET THE SIZE OF CORE IN WORDS
	SUB	P3,P2		;FREE CORE IN WORDS.
	LSH	P3,W2PLSH##	;CONVERT TO PAGES
	CAME	P3,CORTAL##	;DO THEY MATCH?
	STOPCD	.,STOP,JNE,	;++JBTADR NOT EQUAL TO CORTAL
	POPJ	P,		;YES--RETURN ALL IS WELL

;SUBROUTINE TO DECIDE IF NUMBER IN P3 SHOULD BE ADDED TO P2 TO ACCOUNT
; FOR A SEGMENT WHOSE NUMBER IS IN P1. CALLED ONLY FROM ABOVE.
; CLOBBERS P4.
;ONLY CALL IS ABOVE
CNTCHK:	JUMPE	P3,CPOPJ1	;DO NOT ACCOUNT FOR ZERO LENGTH SEGMENTS
				; BECAUSE ADDING THE 1 FOR ROUNDING WILL
				; MESS US UP.
	CAIG	P1,JOBMAX##	;IS THIS A HISEG?
	POPJ	P,		;NO--JUST ADD IT INTO TOTAL
	HRRZ	P4,JBTSTS(P1)	;PICK UP INCORE COUNT
	JUMPE	P4,CPOPJ1	;IDLE SEGMENT-DO NOT COUNT IT
	POPJ	P,		;ACTIVE SEGMENT. ADD IT INTO TOTAL
>;END REPEAT 0
;SUBROUTINE RETURNS INCREMENTAL TIME (SINCE LAST CALL)
;
;	PUSHJ	P,TIMEX		;GET INTERVAL (GETIME-UNITS*JIFFYS/SEC)
;	ADD	T1,EXCESS	;ADD LAST REMAINDER (FRAC.OF JIFFY)
;	IDIVI	T1,RTUPS##	;DIVIDE TO GET INTEGRAL JIFFYS
;	ADDM	T1,TIME		;ADD JIFFYS TO ACCUMULATED TIME
;	MOVEM	T2,EXCESS	;REMEMBER FRACTION FOR NEXT TIME

TIMEX:	PUSHJ	P,GETIME##	;GET CURRENT TIME IN GETIME-UNITS
	EXCH	T1,.CPXTM##(P4)	;SWAP WITH LAST VALUE
	SUB	T1,.CPXTM(P4)	;  COMPUTE DIFFERENCE
	MOVNS	T1		;  & LEAVE IN T1
	SKIPGE	T1		;IF NEGATIVE INCREMENT
	ADD	T1,RTCMAX##	;  WE MUST HAVE GONE THROUGH MIDNIGHT
	IMUL	T1,TICSEC##	;CONVERT TO GETIME-UNITS*JIFFIES/SEC SO THAT
	POPJ	P,		;  IDIV RTUPS WILL GIVE JIFFY QUOTIENT AND
				;  PARTIAL-JIFFY REMAINDER.

;SUBROUTINE CALLED AT CLOCK LEVEL ONCE A SECOND

EXTERNAL HNGTIM,TICSEC,DEVCHK,SCNSEC,HNGMIN

SECOND:	PUSHJ	P,SAVE2##	;SAVE P1,P2 FOR AVG JOB SIZE, # DAEMON
				;HUNG JOBS, MCU CALCULATION
	AOS	T1,LOCSEC##	;BUMP SECOND
	CAIL	T1,^D60		;NEW MINUTE?
	PUSHJ	P,MINUTE	;YES
	MOVE	T1,TICSEC	;RESTORE THE SECOND-COUNTER
	ADDM	T1,HNGTIM	;TO FULL SECOND
				;COUNT GOES TO -1 SO SCHED1 CAN TELL WHEN
				;EXACTLY ONE MINUTE HAS GONE BY
	PUSHJ	P,DEVCHK	;GO CHECK FOR HUNG DEVICES
IFN FTNET,<
	PUSHJ	P,NET2ND##	;CALL NETSER ONCE A SECOND
>
IFN FTNSCHED&FTSWAP,<
	PUSHJ	P,MCUCAL##	;SEE IF ITS MCU TIME YET
>;END IFN FTNSCHED&FTSWAP
IFN FTNET!FTCAFE!FTDAS78,<
	PUSHJ	P,DLXSEC##	;CHECK DL-10
>
	PUSHJ	P,TAPSEC##	;CALL TAPSER
IFN FTDAS78,<
	PUSHJ	P,D78SEC##	;CHECK DAS78'S
>;END OF IFN FTDAS78
	PUSHJ	P,XTCSEC##	;CHECK XTCDDB'S
	PUSHJ	P,DTASEC##	;CALL DTASER
IFN FTKA10!FTKI10,<
	CONO	TTY,SCNCHN##	;MAKE SURE CTY HAS A PIA
>
IFN FTKL10,<
	PUSHJ	P,DTESEC##	;CALL 1/SECOND 10/11 PROTOCOL ROUTINE
>;END IFN FTKL10
	PJRST	SCNSEC		;AND HANDLE TELETYPE PROBLEMS

;SUBROUTINE CALLED AT CLOCK LEVEL ONCE A MINUTE

MINUTE:	SETZB	P1,LOCSEC##	;CLEAR SECONDS AND NO. OF DAEMON ERROR JOBS
	SETZ	P2,		;CLEAR AVERAGE JOB SIZE COUNTER
	AOS	T1,LOCMIN##	;BUMP MINUTE
	CAIL	T1,^D60		;NEW HOUR?
	PUSHJ	P,HOUR		;YES
	PUSHJ	P,D76MIN##	;PRINT OUT PDP-11 MESSAGES
	PUSHJ	P,TAPMIN##	;PRINT TAPE CONTROLLER MESSAGES
IFN FTDAS78,<
	PUSHJ	P,D78MIN##	;CHECK DAS78'S
>;END OF IFN FTDAS78
	SKIPLE	J,HIGHJB##	;CHECK ALL JOBS
	PUSHJ	P,DECHJB	;MAKE SURE HIGHJB IS HONEST
MINUT1:
IFN FTJCON,<			;DEVICE PROBLEM FEATURE?
	MOVE	T1,JBTSTS(J)	;STATUS
	TLNN	T1,JERR		;IF JOB CAN CONTINUE,
	TRNN	T1,JDCON	;AND IS WAITING FOR A DEVICE,
	JRST	MINUT2
	MOVE	T1,J		;PUT JOB NUMBER IN T1
	PUSHJ	P,FCONRQ##	;AND TRY FORCED CONTINUE
	  JFCL
MINUT2:
>				;END DEVICE PROBLEM FEATURE
IFN FTDAEM,<			;DAEMON FEATURE?
	PUSHJ	P,DPMJOB##	;IS THIS JOB STILL WAITING FOR DAEMON SINCE LAST MINUTE?
	  ADDI	P1,1		;YES, KEEP COUNT SO TELL OPERATOR
	MOVEI	T2,JS.DPM	;DAEMON PROBLEM MESSAGE NEEDED NEXT MIN.
	MOVE	T3,JBTSTS##(J)	;JOB STATUS WORD
	LDB	T1,PJBSTS##	;JOB WAIT STATE CODE
	CAIE	T1,JDCQ		;JOB TYPED DCORE COMMAND?
	TRNE	T3,JS.DEM	;NO, WAITING FOR DAEMON (ERROR LOGGING OR DAEMON UUO)
	IORM	T2,JBTSTS##(J)	;YES, SET JOB TO GET MESSAGE NEXT MIN
				; IF STILL WAITING
>				;END DAEMON FEATURE
IFE FTDAEM,<MOVE	T3,JBTSTS(J)>
	TLNN	T3,JNA		;REAL JOB?
	JRST	MINUT3		;NO
	PUSHJ	P,JOBSIZ##	;YES, GET ITS TOTAL SIZE
	LSH	T2,K2PLSH##	;CONVERT TO PAGES (JOBSIZ IS IN K)
	ADD	P2,T2		;ACCUMULATE IN P2
MINUT3:	SOJG	J,MINUT1	;TEST ALL JOBS
	MOVE	T1,P2		;GET P2 IN T1 SO WE DON'T SMASH P3
	IDIV	T1,LOGNUM##	;GET AVERAGE JOB SIZE
	MOVEM	T1,AVJSIZ##	;SAVE IT FOR MCU CALCULATION

IFN FTDAEM,<			;DAEMON FEATURE?
	SKIPE	P1		;HOW MANY JOBS WAITING FOR DAEMON?
	PUSHJ	P,DPMOPR##	;ONE OR MORE, TELL OPR JOB #S.
>
IFN FTMS,<	EXTERNAL CP1CHK
	PUSHJ	P,CP1CHK	;CHECK IF DUAL PROCESSOR IS STILL RUNNING
>
IFN FTDISK&FTDBAD,<
EXTERN CHKUNI
	PUSHJ	P,CHKUNI	;CHECK ALL DISK UNITS
>
IFN FT5UUO,<
	SKIPE	T1,SYSKTM##	;IS A SHUTDOWN PENDING
	SOSE	T1,SYSKTM	;YES. COUNT DOWN TO ZERO
	SKIPA	T1,SYSKTM##	;NOT FIRST KSYS TIME
	SETOB	T1,SYSKTM##	;FLAG FOR PRIVILEDEGED CUSP
IFN FTPI,<
	JUMPE	T1,NOKSYS	;JUMP IF NO KSYS PENDING
	CAIGE	T1,^D10		;LONG TIME TILL KSYS?
	PUSHJ	P,PSIKSY##	;NO--TELL EVERYONE
NOKSYS:	> ;END FTPI
>	;END CONDITIONAL ON FT5UUO
	AOS	ARFLAG##	;COUNT UP AUTO RELOAD COUNTER
	SETOM	CHKQJB##	;CAUSE SCHEDULER TO CHECK JRQ FOR ALL JOBS
IFN FTKL10,<
	SOSN	KLETIM##	;TIME TO GIVE UP KL ERROR CHUNKS YET?
	PUSHJ	P,KLEREL##	;YES, GIVE THEM BACK
>;END IFN FTKL10
	POPJ	P,0		;RETURN
;SUBROUTINE CALLED ONCE AN HOUR

HOUR:	SETZM	LOCMIN##	;SET MINUTE TO 0
	AOS	T1,LOCHOR##	;BUMP HOUR
CHKMNT::CAIGE	T1,^D24		;MIDNIGHT?
	POPJ	P,		;NO
	SETZM	LOCHOR		;YES-RESET HOUR
	MOVE	T1,LOCMON##	;SET T1=DAYS/MONTH
	SOS	T1
	LDB	T2,PMONTB##
	SOJN	T1,HOUR2	;JUMP IF NOT FEB.
	MOVEI	T3,3		;LEAP YEAR?
	TDNN	T3,LOCYER##
	AOS	T2		;YES-29 DAYS
HOUR2:	CAML	T2,LOCDAY##	;NEW MONTH?
	JRST	HOUR4		;NO
	SETZM	LOCDAY##	;YES-RESET DAY (AOS'D BELOW)
	AOS	T1,LOCMON##	;BUMP MONTH
	CAIG	T1,^D12
	JRST	HOUR4
	AOS	LOCYER##	;!!!HAPPY NEW YEAR!!!
	MOVEI	T1,1
	MOVEM	T1,LOCMON
HOUR4:	AOS	LOCDAY##	;BUMP DAY
	HLRZ	T1,DATE##	;AND UNIV. DATE
	AOS	T1
	HRLZM	T1,DATE

;	DO OTHER MIDNIGHT THINGS

	MOVN	T1,MIDNIT##	;RESET TIME
	ADDM	T1,TIME##
	SKIPGE	TIME		;DONT LET IT GO NEGATIVE
	SETZM	TIME

	PUSHJ	P,RTCDAY##	;DK10 THINGS ARE IN COMMON

; HOUR5 (DELETED)

;FALL INTO THSDA1
;SUBROUTINE TO COMPUTE & STORE THSDAT

THSDA::	MOVE	T1,LOCYER
	SUBI	T1,^D1964
	IMULI	T1,^D12
	ADD	T1,LOCMON
	IMULI	T1,^D31
	ADD	T1,LOCDAY
	SUBI	T1,^D32
	MOVEM	T1,THSDAT##
	POPJ	P,

;SUBROUTINE TO COMPUTE & STORE 'DATE' (UNIVERSAL DATE-TIME)

;MAKE UNIVERSAL DATE-TIME WORD

SUDATE::
	MOVE	T1,LOCMON##	;GET MONTH
	MOVE	T3,LOCYER##	;CALCULATE LEAP DAYS
	IMULI	T3,^D12
	ADDI	T3,^D45(T1)
	IDIVI	T3,^D48
	SOJA	T1,SUDAT3
SUDAT2:	LDB	T2,PMONTB##
	ADDI	T3,1(T2)
SUDAT3:	SOJGE	T1,SUDAT2
	ADD	T3,LOCDAY##
	MOVE	T1,LOCYER##	;GET YEAR
	IMULI	T1,^D365	;ADD YEARS
	ADD	T3,T1
	SUB	T3,[^D678957]	;SUBTRACT NOV. 17 1858
	MOVE	T1,LOCHOR##	;GET HOUR
	IMULI	T1,^D60		;MAKE MINUTES
	ADD	T1,LOCMIN##	;ADD MINUTES
	IMULI	T1,^D60		;MAKE SECONDS
	ADD	T1,LOCSEC##	;ADD SECONDS
	HRLZS	T1		;CONVERT TO FRACT. OF DAY
	IDIVI	T1,^D24*^D3600
	HRLZS	T3		;DAYS TO LH
	ADD	T3,T1		;ADD DATE AND TIME
	SUB	T3,GMTDIF##	;CONVERT TO GMT
	MOVEM	T3,DATE##
	POPJ	P,

;CLKCHG IS A ROUTINE TO SEARCH THE CLOCK QUEUE FOR AN ENTRY FOR A
;PARTICULAR JOB AND TO CHANGE THE REMAINING CLOCK REQUEST TIME.
;THE CALLING SEQUENCE IS AS FOLLOWS:
;	MOVE T1,JOBNUM		;T1 = JOB TO SEARCH FOR
;	MOVE T2,NEW SLEEP TIME	;T2 = NEW SLEEP TIME IN  JIFFIES
;	PUSHJ P,CLKCHG		;CHANGE CLOCK REQUEST TIME
;	RETURN HERE IF AN ENTRY WAS NOT FOUND (T1=NEW SLEEP TIME)
;CLKCHG USES T2, T3 WITHOUT RESTORING THEM
;	RETURNS HERE, CLOCK REQUEST TIME UPDATED.

	EXTERNAL TPOPJ
	INTERNAL CLKCHG

CLKCHG:	PUSH	P,T2		;SAVE NEW SLEEP TIME FOR LATER
	HRRZ	T2,CLOCK	;GET RH OF CLOCK QUEUE POINTER
CLKCH1:	CAIN	T2,CIPWTM1	;AT TOP OF QUEUE?
	JRST	TPOPJ		;YES, JOB NOT IN QUEUE
	HLRZ	T3,-1(T2)	;GET TIME-OUT ADDRESS
	CAIE	T3,WAKEJ	;IS THIS JOB SLEEPING?
	SOJA	T2,CLKCH2	;NO. LOOK AT NEXT ONE.
	HRRZ	T3,(T2)		;GET DATA ITEM
	CAIE	T3,0(T1)	;NOW. DOES THAT EQUAL DESIRED JOB NO?
	SOJA	T2,CLKCH2	;NO. GO LOOK FOR NEXT JOB.
	POP	P,T3		;YES, GET THE NEW REQUEST TIME
	HRRM	T3,-1(T2)	; ..
IFN FTSWAP,<
	MOVSI	T2,SWP
	TDNE	T2,JBTSTS##(T1)	;IS JOB SWAPPED?
	JRST	CPOPJ1##	;YES, DON'T CHANGE IN-CORE PROTECT TIME
	PUSHJ	P,FPDBT1##	;FIND PDB VIA T1
	  JRST	CPOPJ1##	;NO PDB, DO NOT WORRY ABOUT
				; INCORE PROTECT TIME
	.LDB	T2,PDYIP2##	;GET ICPT
	CAIGE	T2,(T3)		; SLEEPING LONGER THAN ICPT?
	PUSHJ	P,CLRIP1##	;YES. CLEAR ICPT
>
	JRST	CPOPJ1##	;RETURN
CLKCH2:	SOJA	T2,CLKCH1
SUBTTL	RUNCSS - RUN CONTROL(STARTING AND STOPPING OF JOBS)

;RUN CONTROL IS A COLLECTION OF ROUTINES WHICH
;SET AND CLEAR BITS IN THE JOB STATUS WORDS OF
;ALL JOBS SO THAT THE SCHEDULER WILL START AND STOP
;THEM ACCORDINGLY

;COMMON ERROR STOPPING ROUTINES
;CALLED AT ANY LEVEL(UUO,CLK, OR INTERRUPT)
;CALL:	MOVE J,JOB CAUSING ERROR OR BEING STOPPED
;	MOVE F,ADRRESS OF THAT JOB TTY DEVICE DATA BLOCK
;	MOVE U,BYTE POINTER TO LAST CHAR. ALREADY MOVED
;			;TO TTY OUTPUT BUFFER
;	PUSHJ P,KSTOP,PHOLD,HOLD,OR ESTOP
;	NEVER RETURN IF CALLED AT UUO LEVEL

;ROUTINE TO STOP JOB AFTER KJOB COMMAND
;CALLED AT UUO LEVEL IF JOB HAD CORE,CLK LEVEL IF NOT

INTERNAL KSTOP,FTPRV,FT2REL,FTCNO,FTHALT,FTHIBW,FTHPQ,FTSPL,FTTLIM,FTUNAM,CLRJBT,DECHJB
EXTERNAL HIGHJB,TTYTAB

KSTOP:
	MOVSI	T1,JNA+JACCT	;CLEAR JOB NUMBER ASSIGNED AND LOGGED IN BITS
	ANDCAM	T1,JBTSTS(J)
	PUSHJ	P,CLRLOG	;CLEAR JLOG, COUNT DOWN LOGNUM & BATNUM
	PUSHJ	P,CLRJBT	;GO CLEAR ALL THE JOB TABLES
	PUSHJ	P,KILPDB##	;DEALLOCATE PDB
	HLLZS	TTYTAB(J)	;CLEAR TTY DDB LINK
	PUSHJ	P,DECHJB	;DECREMENT HIGHJB IF NOT REQUEUED
	JRST	ESTOP		;GO SET ERROR BIT

DECHJB:
				; IF THIS IS THE LARGEST JOB IN USE,FIND NEXT
				; HIGHEST AND SET HIGHJB
	CAMGE	J,HIGHJB	;IS THIS THE BIGGEST JOB NUMBER ASSIGNED?
	POPJ	P,0		;NO, LEAVE HOLE
	MOVSI	T2,JNA+CMWB+JRQ	;YES, LOOK FOR LAST JOB WITH
				;JOB NUMBER ASSIGNED BIT OR COMMAND WAIT BIT
	HRRZ	T1,J		;SCAN DOWNWARD
	TDNN	T2,JBTSTS(T1)	;ARE BITS SET FOR THIS JOB?
	SOJG	T1,.-1		;NO,KEEP LOOKING,FINISHED(TRUE IF THIS THE ONLY JOB
	MOVEM	T1,HIGHJB	;YES,STORE NEW HIGHEST JOB NUMBER ASSIGNED
	POPJ	P,0		;AND RETURN
;ROUTINE TO CLEAR ALL INTERESTING JOB TABLES AND PROCESS DATA BLOCK (PDB)
;COULD BE CALLED ANYTIME, BUT IS CALLED ONLY
;	FROM NEWJOB (COMCON) AT JOB INITIALIZATION
;	AND FROM KSTOP (CLOCK1) AT JOB TERMINATION

CLRJBT:
IFN FTPI,<
	PUSHJ	P,CLRPSI##	;CLEAR SOFTWARE INTERRUPT SYSTEM
>
IFN FTDISK,<IFN FTDSTT,<EXTERN JBTRCT,JBTWCT
	SETZM	JBTRCT(J)	;CLEAR NO. OF DISK BLOCKS READ BY JOB
	SETZM	JBTWCT(J)	;CLEAR NO. OF DISK BLOCKS WRITTEN BY JOB
>>
IFN FTSPL,<EXTERN JBTSPL
	SETZM	JBTSPL(J)	;CLEAR SPOOLING BITS
>
	MOVEI	T1,JS.SFL
	ANDCAM	T1,JBTSTS(J)
	MOVEI	T1,JS.MSK	;MASK FOR ACTUAL QUE
	ANDM	T1,JBTST2##(J)	;CLEAR ALL OTHER BITS IN JBTST2
IFN FTNSCHED,<
	SETZ	T2,		;CLEAR OUT FINAL RESULT
	MOVE	T1,DEFCLS##	;GET DEFAULT CLASS
	DPB	T1,[POINT 5,T2,17] ;PUT INTO T2
	SKIPGE	CLSSTS##(T1)	;IS DEFAULT CLASS FIXED QUOTA?
	TLO	T2,(JS.FXC)	;YES, SET THE BIT
	MOVEM	T2,JBTSCD##(J)	;SAVE INITIAL VALUE
>
IFN FTKL10&FTMS,<
	PUSHJ	P,CLCSN##	;CLEAR OUT JBTST3 ENTRY, IF IT EXISTS
>;END IFN FTKL10&FTMS
IFN FTHPQ!FTRTTRP!FTHIBWAK,<EXTERNAL CLRRTD
	XCT	CLRRTD		;CLEAR HPQ POSITION
>
IFN FTLOGIN,<EXTERN JBTPPN
	SETZM	JBTPPN(J)	;CLEAR PROJECT-PROGRAMMER NUMBER
	SETZM	JBTJLT##(J)	;CLEAR JOB'S LOGIN TIME
>
IFN FTTLIM,<
	MOVSI	T1,(JB.LCR)	;SET UP JOB CORE LIMIT FOR ALL CORE
	MOVEM	T1,JBTLIM##(J)	;AND NO TIME LIMIT
>
IFN FTPRV,<EXTERN JBTPRV
	SETZM	JBTPRV(J)	;CLEAR PRIVILEGES
>

IFN FTRSP,<EXTERN JBTRSP
	SETZM	JBTRSP(J)	;CLEAR RESPONSE TIME MEASURE
	SETZM	JBTRQT##(J)	;CLEAR RUN-QUEUES TIME
>
IFN FTMS,<	EXTERNAL SETJSP
	PUSHJ	P,SETJSP	;SET UP JBTSPS WORD WITH INITIAL CAN RUN BITS
>
IFE FTPDBS,< ;IF WE HAVE PDB'S IN MONITOR CORE
IFN FTTRACK,<
	PJRST	SETPDB##	;INITIALIZE PDB (SINCE SAME TYPE OF INFO AS
				; JOB TABLES) AND RETURN
>
IFE FTTRACK,<
	POPJ	P,
>
> ;END FTPDBS
IFN FTPDBS,<
	POPJ	P,
> ;END FTPDBS
;SUBROUTINE TO STOP CURRENT JOB, NOT SET ERROR BIT
; PUT TTY IN COMMAND MODE, START TTY0, CALL SCHEDULER

	INTERN	HOLDW

HOLDW:	PUSHJ	P,HOLD0		;PRINT CRLF, START TTY, TURN OFF RUN BIT
	PJRST	WSCHED		;NOW CALL SCHEDULER

;SUBROUTINE TO STOP JOB, BUT NOT SET ERROR BIT, PUT TTY IN COMMAND MODE
;AND START TTY

INTERN HOLD0

HOLD0:	PUSHJ	P,PRRSP1	;PRINT CRLF, [XXX], CRLF, CRLF, DOT
	PUSHJ	P,TTYSTC	;START TTY AND LEAVE IN MONITOR MODE
	PJRST	ESTOP3		;STOP JOB BUT DO NOT SET ERROR BIT
					;SO JOB CAN CONTINUE
;ROUTINE TO STOP JOB, SET ERROR BIT AND PRINT MESSAGE
;THEN ADD ^C<CRLF><CRLF><PERIOD>
;CALL:	MOVEI T1,ADR. OF MESSAGE
;	PUSHJ P,PHOLD

	INTERN	PHOLD

PHOLD:	PUSHJ	P,CONMES	;MOVE MESSAGE TO TTY OUTPUT BUFFER
				; FALL INTO HOLD
;ROUTINE TO STOP JOB, SET ERROR BIT,
;AND ADD "^C<CRLF><CRLF><PERIOD>

EXTERNAL TTYSTC,PRRSP1

HOLD::	JUMPE	F,HOLD1			;JUMP IF NO TTY DDB
	LDB	T1,PJOBN##	;THERE IS A DDB, GET THE OWNER'S JOB NUMBER
	CAMN	T1,J		;STOPPING THE JOB THAT OWN'S THE DDB?
	JRST	HOLD1		;YES, GO DO USUAL THINGS
	PUSHJ	P,CRLF##	;ADD <CRLF> TO THE MESSAGE
	PUSHJ	P,TTYSTR##	;START THE TTY
	JRST	ESTOP		;STOP THE JOB

HOLD1:	PUSHJ	P,PRRSP1	;PRINT CRLF, [XXX], CRLF, CRLF, DOT
	PUSHJ	P,TTYSTC	;MAKE SURE TTY STAYS IN MONITOR MODE
				; AND START TTY TYPING OUT MESSAGE
				; FALL INTO ESTOP
;ROUTINE TO STOP USER AND FLAG AS ERROR STOP


INTERNAL ESTOP,ESTOP1
EXTERNAL JBTSTS,TTYSRC,TTYDET
EXTERNAL CPOPJ

ESTOP:	JUMPE	J,CPOPJ		;IS THIS ERROR IN JOB 0?
ESTOP1:
IFN FTKI10!FTKL10,<
	SKIPE	JBTADR(J)	;DON'T MAKE JOB DATA AREA ADDRESSABLE IF THERE
				; ISN'T ONE
	PUSHJ	P,SVEUB##	;MAKE SURE JOB DATA AREA IS ADDRESSABLE
>
IFN FTDAEM,<
	MOVE	T1,JBTNAM(J)	;IS THIS THE SYSTEM DAEMON
	MOVE	T2,JBTSTS(J)	; IDENTIFIED BY NAME
	CAMN	T1,[SIXBIT /DAEMON/]
	TLNN	T2,JACCT	; AND COPY BIT
	JRST	ESTOP2	;NO--NOT DAEMON, STOP JOB
	MOVE	T1,JBTPPN##(J)
	CAME	T1,FSFPPN##
	JRST	ESTOP2
	PUSHJ	P,TTYSRC	;IS JOB DETACHED?
	  SKIPA			;YES--LEAVE IT ALONE
	PUSHJ	P,PTYDET##	;NO--DETACH IT.
	MOVEI	T4,0		;NO SPECIAL BIT
	PUSHJ	P,CHKINT##	;SETUP INTERCEPT
	  JRST	ESTOP2		;NO--STOP JOB
	PUSHJ	P,DOINT##	;PREPARE INTERCEPT
	SETO	T1,
	PUSHJ	P,PUTWR1##
	STOPCD	.+1,JOB,IBI,	;++INTERCEPT BLOCK ILLEGAL
	CAME	J,.C0JOB##	;DAEMON NOW RUNNING?
	POPJ	P,		;NO (CHAN 7). AVOID DISASTER
	PJRST	QKUSXT##	;GO DO QUICKY USER EXIT
ESTOP2:>
	MOVSI	T1,JACCT	;CLEAR PRIVS IF ERROR STOPPING
	ANDCAM	T1,JBTSTS##(J)
	MOVSI	T1,JERR		;SET ERROR BIT IN JOB STATUS WORD
	IORM	T1,JBTSTS(J)	;SO JOB CAN NOT CONTINUE(CONT COM.)
ESTOP3::MOVE	T1,JBTSTS(J)
	TLNN	T1,JLOG		;IF THIS GUY IS NOT LOGGED IN
	TLNN	T1,JNA		;  AND HAS JNA SET -- KILL HIM
	JRST	STOP1C		;JLOG SET OR JNA CLEAR
	CONSO	PI,PI.IPA	;NOT LOGGED IN - KILL JOB IF NOT ON CHAN 7
	JRST	JOBKL##		;CLEAR JNA
;ROUTINE TO STOP ANY JOB FROM BEING SCHEDULED
;CALL:
;	MOVE J, JOB NUMBER
;	PUSHJ P, STOP1
;	EXIT	;RETURN HERE IMMEDIATELY, IF CALLED FROM HIGHER
;PRIORITY PI CHANNEL THAN CLK(LOWEST), OTHERWISE WHEN JOB IS RUNABLE
;CALLED FROM COMMAND DECODER WHEN <CONTROL>C TYPED IN BY USER
;OR ON ANY ERROR MESSAGE(SEE PREVIOUS PAGE)

INTERNAL STOP1,STOP1C
EXTERNAL JBTSTS,PJBSTS,RQTBMQ,AVTBMQ,MINQ,MAXQ
STOP1C:
IFN FTGALAXY,<
	SKIPE	T2,JBTPPN##(J)	;IF PPN IS ZERO OR
	CAMN	T2,HELPPP##	; [2,5] DO NOT TRY
	JRST	STOPP		; TO LOG BACK IN
	MOVE	T2,JBTNAM##(J)	;GET PROGRAM NAME
	CAMN	T2,[SIXBIT/LOGOUT/]  ;IS IT LOGOUT?
	PUSHJ	P,SETLOG	;LOG JOB BACK IN
>
STOPP:	MOVSI	T1,RUN
	CONO	PI,PIOFF	;DONE AT INTERUPT LEVEL HIGHER THAN DT LEVEL
	TDNN	T1,JBTSTS(J)	;NO, IS RUN BIT OFF IN JOB STATUS WORD
	JRST	STOP1A		;YES
	TLO	T1,CNTRLC	;TURN OFF. "USER TYPED ^C WHILE STILL IN EXEC MODE"
	TRO	T1,JS.RUU+JS.ASA  ;TURN OFF RUN COMMAND BIT
	ANDCAM	T1,JBTSTS(J)
	CONO	PI,PION
IFN FTKI10!FTKL10,<
	MOVSI	T1,(JS.IGS)	;CLEAR "IN GETSEG" BIT
	ANDCAM	T1,JBTST2##(J)
>
	PUSHJ	P,TTYSRC##	;FIND CONTROLLING TTY
	  JRST	STOP1E		;NONE--SKIP ON
	JUMPE	U,STOP1E	;IF NO LDB FORGET FIXING UP TTY.
	PUSHJ	P,CNCMOD##	;SET TTY TO MONITOR LEVEL
IFN FTSET,<
	PUSHJ	P,FNDPDB##	;FIND PDB
	  JRST	STOP1E		;NO PDB
	SKIPN	.PDPGM##(W)	;GET CUSP TO RUN
	JRST	STOP1E		;NONE
	MOVEI	T1,TTFCXU##	;FORCE AN .R DUMP WHICH
	MOVEI	T2,JS.RPC	; WILL TURN INTO AN
	TDNE	T2,JBTST2##(J)	; .R C(.PDPGM). DO THIS
	PUSHJ	P,TTFORC##	; ONLY IF JS.RPC=1
>
STOP1E:	LDB	T1,PJBSTS	;GET JOB WAIT QUEUE CODE(IF ANY)
	CAIL	T1,MINQ		;SHARABLE RESOURCE STATE?
	CAILE	T1,MAXQ		;AND DOES STATE ALSO HAVE A Q?
	JRST	STOP1A		;NO
	SOSL	RQTBMQ(T1)	;YES. REDUCE IT.
	JRST	STOP1A		;NO
	SOSGE	AVTBMQ(T1)	;YES REDUCE  COUNT
	SETZM	AVTBMQ(T1)	;CLEAR AVAL FLAG IF NO ONE WAITING
STOP1A:	CONO	PI, PION	;MAKE SURE PI ON
IFN FTDHIA,<
	PUSHJ	P,DIACLR##	;CRANK UP DSK IO IF JOB HAD
				; IT STOPPED WITH DIAG.
>
	PUSHJ	P,TPFREE##	;CHECK FOR MTA'S
IFN FTMS,<	EXTERNAL CLRCCB
	PUSHJ	P,CLRCCB	;CLEAR CONTROL C BIT
>
IFN	FTRSP,<EXTERN JBTRSP
	SETZM	JBTRSP(J)	;CLEAR TIME USER STARTED TO WAIT FOR RESPONSE
				; SO COUNT NEW RESPONSE
>
IFN FTVM,<
	MOVSI	T1,(UP.GET)	;CLEAR GET IN PROGRESS FLAG
	ANDCAM	T1,.UPMP+.UPBTS
>
STOP1B:	CAME	J,.C0JOB	;NO, IS THIS JOB CURRENT USER
IFE FTSWAP,<
	POPJ	P,		;NO
>
IFN FTSWAP,<
	JRST	REQUE		;NO, SET REQUE JOB FLAG
>
	SKIPL	T1,JBTSTS(J)	;RUN FLAG OFF?
	TLNN	T1,JERR		;YES, IF JOB ERROR FLAG ON
	JRST	STOP2##		;NO, (IRP LEVEL ONLY) DO NOT SET .C0SCF IN CASE CURRENT USER
				; IS IN EXEC MODE, CALLING SCHEDULER, COMMAND DECODER
				; AND P HAS BEEN CHANGED TO NULPDL SO NO LONGER
				; STATE OF USER JOB. CHANNEL 7 WOULD SAVE P AGAIN
	SETOM	.C0SCF		;YES, FORCE RESCHEDULING EVEN IF JOB IN EXEC MODE
	JRST	STOP2##		;CAUSE CLK INTERRUPT

STOP1:
IFN FTCCIN,<
	MOVSI	T1,JACCT	;EVEN IF JACCT JOB IS
	TDNE	T1,JBTSTS##(J)	; ON A PTY LET THE
	JRST	STOP1J		; INTERCEPT HAPPEN
	HRRZ	T1,TTYTAB##(J)	;ADDRESS OF TTY DDB
	JUMPE	T1,STOP1J	;JUMP IF NO DDB
	HRRZ	U,DDBLDB##(T1)	;ADDRESS OF LDB
	JUMPE	U,STOP1J	;DETACHED (AND TYPED CNTRL-C?)
	HRLZ	T1,LDBDCH##(U)	;GET DEVICE BITS
	JUMPL	T1,STOP1G	;DO NOT INTERCEPT FOR PTY'S
STOP1J:	SKIPL	JBTSTS(J)	;RUN BIT ON?
	JRST	STOP1C		;NO, DON'T DO INTERCEPTING ^C'S
IFN FTPI,<			;IF WE WANT PSISER
	PUSHJ 	P,SAVE1##
	MOVE	P1,M
	SIGNAL	C$CTLC		;SIGNAL CONTROL-C INTERRUPT
	  JRST	STOP1F		;INTERRUPT NOW PENDING
	MOVE 	M,P1
> ;END FTPI
	MOVEI	T4,.ERICC	;FLAG FOR CONTROL-C
	PUSHJ	P,SETINT	;SET UP INTERRUPT IF HE WANTS TO
	  JRST	STOP1G		;NOT ENABLED
	JRST	STOP1D		;GO FINISH UP
IFN FTPI,<
STOP1F:	SKIPN	T1,TTYTAB##(J)	;GET TTY DDB
	JRST	STOP1H		;NO DDB?
	SKIPL	T1,DEVIOS(T1)	;GET I/O STATUS
	TLNN	T1,IOW		;IN INPUT WAIT?
STOP1H:	TDZA	T1,T1		;NO--ZERO AC
	MOVSI	T1,(1B0)	;YES--SET STATUS BIT
	EXCTUU	<MOVEM T1,IBKISW##(M)>
	MOVE	M,P1		;RESTORE FLAGS
	PUSHJ	P,CLRTI##	;GET DDB OUT OF TI WAIT
	JRST	STOP1D		;GO FINISH UP
>; END FTPI
>;END FTCCIN
STOP1G:	SKIPGE	T1,JBTSTS##(J)	;NO INTERRUPT BLOCK, SEE IF RUN AND JACCT
	TLNN	T1,JACCT	;  SET FOR JOB
	JRST	STOP1C		;NO--GO STOP JOB

STOP1D:	TLO	M,NOCRLP##	;SET FOR NO CRLF OR PER
	SKIPGE	T1,JBTSTS(J)	;IF RUNNABLE
	TLO	M,TTYRNM##	;SET TO USER LEVEL
	MOVSI	T1,CNTRLC	;CLEAR DELAYED
	ANDCAM	T1,JBTSTS(J)	;  .HALT HANDLING
IFN FTMS,<
	PUSHJ	P,CLRCCB	;CLEAR SECONDARY PROCESSOR ^C-BIT
>
	POPJ	P,		;AND RETURN

IFN FTCCIN!FTDAEM!FTOPRERR,<
INTERN	SETINT

;SUBROUTINE TO SET UP AN INTERCEPT
;CALL WITH T4=INTERCEPT BIT
;EXIT NON-SKIP IN NOT ENABLED
;SKIP-RETURN IF ENABLED, SET TO TRAP ON UUO EXIT
; (OR START AT TRAP LOC IF IN USER MODE).
SETINT:
IFN FTKI10!FTKL10,<
	PUSHJ	P,SVEUB##	;MAKE SURE JOB DATA AREA IS ADDRESSABLE
>
	PUSHJ	P,CHKINT##	;  SEE IF ENABLED
	  POPJ	P,		;NO
	MOVEI	T2,UTRP
	TDNE	T2,JBTSTS##(J)	;ALREADY BEEN THRU HERE
	JRST	CPOPJ1##	;YES, DON'T DO IT AGAIN
	PUSH	P,T1		;SAVE PC
	MOVE	T2,JOBPC(R)	;YES--GET CURRENT PC
	CAMN	J,.C0JOB	;CURRENT USER?
	MOVE	T2,USRPC##	;YES--GET PC FROM PROTECTED PLACE
	TLNE	T2,USRMOD	;SEE IF EXEC MODE
	JRST	STOP1U		;NO--DO USER MODE
	SETOM	T1		;SET DOINT FLAG
	PUSHJ	P,SETUTP	;YES--SET IF NEEDED TO TRAP UUO
	  JRST	STOP1U		;NO--GO START JOB
	POP	P,T2		;THROW AWAY PC
	JRST	CPOPJ1		;ALL DONE UNTIL UUO EXIT

;HERE WHEN UUO NOT IN PROGRESS
STOP1U:	MOVEM	T2,JOBPC(R)	;SETUP JOBPC FOR USTART
	PUSHJ	P,CLRTI##	;GET DDB OUT OF TI WAIT
	POP	P,T2		;GET START PC
	PUSH	P,JOBOPC(R)	;SAVE OPC FOR USER
	PUSHJ	P,USTART	;START IN USER MODE
	MOVE	T1,JOBOPC(R)	;GET OLD PC
	POP	P,JOBOPC(R)	;RESTORE OPC
	PJRST	STUTRP		;DONT DO INTERRUPT UNTIL JOB IS RUNNABLE
				; ELSE IRP CONDITION COULD OCCUR AGAIN AND STOP
				; THE JOB SINCE JOBINT+2 NON-ZERO
>				;IFN FTCCIN!FTDAEM!FTOPRER
;ROUTINE TO CHECK IF OK TO STOP JOB IN MONITOR (OR WAIT TILL UUO EXIT)
;CALLED ON CONTROL C AND ANY ERROR WHICH PUTS JOB IN DAEMON ERROR PAUSE
;CALL:	MOVE	J,JOB NUMBER
;	PUSHJ	P,SIMCHK
;	  OK TO STOP JOB NOW RETURN
;	WAIT TILL EXIT FROM MONITOR VIA UUO (BECAUSE JOB MAY HAVE A RESOURCE)

	INTERN	SIMCHK

SIMCHK:	LDB	T1,PJBSTS	;GET JOB STATUS CODE
	MOVEI	T2,1		;BIT POS. IN DELAYN FOR STATE CODE 0
	LSH	T2,(T1)		;MOVE LEFT ACCORDING TO STATE CODE
	SKIPL	T1,JBTSTS(J)	;JOB STATUS. IS RUN BIT OFF?
	POPJ	P,		;YES, STOP JOB BUT DO NOT PRINT WATCH STATUS
	TLNE	T1,JERR		;NO, IS ERROR BIT ON?
	POPJ	P,		;YES. STOP JOB EVEN IF IN EXEC MODE
	TLNE	T1,SWP		;IS JOB IN CORE?
	JRST	STOPC		;NO. ASSUME PC IN EXEC MODE
	MOVE	R,JBTADR(J)	;RELOCATION FOR JOB (LOW SEG)
				; (SIMCHK CALLED ON INT LEVEL ON DEVICE ERRORS)
	JUMPE	R,CPOPJ		;YES, DOES JOB HAVE CORE IN CORE?
	PUSHJ	P,SCPCDB##	;SET UP P4
	MOVE	T1,JOBPC##(R)	;YES, GET PC
	CAMN	J,.CPJOB##(P4)	;IS THIS JOB THE CURRENT JOB?
	MOVE	T1,.CPPC##(P4)	;YES, GET PC AND FLAGS FOR CURRENT JOB
	TLNE	T1,USRMOD	;JOB PC IN USER MODE?
	POPJ	P,		;YES, JOB CAN BE STOPPED
	TLZ	T1,-1		;CLEAR PC FLAGS
	CAIE	T1,UUODON##	;AT THE END OF A UUO?
STOPC:	TDNN	T2,DELAYN	;NO, IS JOB IN A STATE(IN EXEC) WHICH
				; CAN BE STOPPED IMMEDIATELY
	POPJ	P,		;YES, STOP JOB RETURN
	PJRST	CPSCHK##	;EXEC MODE PC AND NO DELAY, DOES JOB HAVE A
				; RUNNABLE CPU SPECIFICATION? RETURN CPOPJ IF NO,
				; CPOPJ1 TO CATCH JOB AT UUO EXIT

;DEFINE A BIT FOR EACH STATE CODE
; WHICH IS 1(DJ) MEANS DELAY JOB(IF PC IN EXEC MODE) WHEN CONTROL C TYPED
; IF 0(SJ), OK TO STOP JOB(IN EXEC MODE)

DEFINE X(A,B,C)
<	IFIDN <C><DJ>,<QQ==1>
	IFIDN	<C><SJ>,<QQ==0>
	YY==ZZ*QQ	;;SET THIS STATE CODE BIT TO 0 OR 1
	XX==XX!YY	;;ACCUMULATE VALUES IN XX
	ZZ==ZZ*2	;;MOVE MASK BIT LEFT ONE PLACE
>

QQ==0	;MAKE SURE INTERMEDIATE VALUE IS 0
XX==0	;START FINAL VALUE AT 0
ZZ==1	;START OFF BIT FOR STATE 0

	QUEUES
	RWAITS
	CODES

	INTERN	DELAYN

DELAYN:	EXP	XX		;GENERATE THE DELAY WORD BIT 35=STATE 0,
			; BIT 34=STATE 1, ETC.
			; BIT 35-I=1 IF STATE I MUST BE DELAYED ON CONTROL C

;SETUTP -- ROUTINE TO SET UUO TRAP
;CALL:	MOVE	T1,NEW ADDR	(-1 = JOBINT)
;	PUSHJ	P,SETUTP
;NON-SKIP IF START IMMEDIATELY
;SKIP IF DELAY TO END OF UUO

	INTERN SETUTP

CHKUTP::LDB	T3,PJBSTS	;GET WAIT CODE
	CAIE	T3,NAPQ##	;SEE IF NAPPING OR
	CAIN	T3,SLPQ		;SLEEPING
	POPJ	P,		;YES--START IMMEDIATELY
	CAIE	T3,TIOWQ	;SEE IF TTY WAIT (IN OR OUT)
	JRST	CPOPJ1##	;NO--DELAY
	MOVE	T3,TTYTAB##(J)	;GET TTY DDB
	MOVE	T3,DEVIOS(T3)	;GET STATUS
	TLNE	T3,IOW		;SEE IF IN IOWAIT
	TLNN	T3,TTYOUW##	;YES--SEE IF OUTPUT WAIT
	POPJ	P,		;NO--STARTUP IMMEDIATELY
	JRST	CPOPJ1##	;YES--DELAY
SETUTP:	PUSHJ	P,CHKUTP	;SEE IF WE CAN TRAP NOW
	  POPJ	P,		;YES--DO IT NOW
;HERE IF TRAP MUST BE DELAYED UNTIL UUO EXIT
STUTRP:	MOVEM	T1,JOBFDV##(R)	;NO--SAVE START IN JOBDAT
	MOVEI	T3,UTRP		;SET FLAG FOR UUO EXIT
	IORM	T3,JBTSTS(J)	;  THAT JOB DOESN'T DO NORMAL THING
	JRST	CPOPJ1		;SKIP
;ROUTINE TO REQUE JOB WHICH HAS HAD A COMMAND TYPED
;WHICH NEEDS CORE AND THE CORE IMAGE IS ON THE DISK.
;OR IS IN CORE AND HAS ACTIVE DEVICES.
;CALLED FROM COMMAND DECODER
;CALL:	MOVE J,JOB NO.
;	PUSHJ P,DLYCOM

INTERNAL DLYCOM

DLYCOM:	MOVSI	T1,CMWB		;SET COMMAND WAIT BIT
IFN FTSWAP,<
	TDNE	T1,JBTSTS(J)	;IS JOB ALREDY IN COMMAND WAIT?
	POPJ	P,		;YES,JUST EXIT
>
	IORM	T1,JBTSTS(J)	;IN JOB STATUS WORD

INTERNAL FTSWAP
IFN FTSWAP,<
	PJRST	REQUE
>
IFE FTSWAP,<
	POPJ	P,
>

;ROUTINE TO PUT JOB IN NO CORE QUEUE


INTERNAL FTSWAP
IFN FTSWAP,<INTERNAL NOCORQ
	EXTERNAL NULQ

NOCORQ:	MOVEI	T1,NULQ		;NO JOB NO. OR NO CORE QUEUE
	DPB	T1,PJBSTS
	JRST	REQUE
>
;SUBROUTINE TO SAVE AND RESTORE THE CONTEXT OF A JOB SO THAT THE
; JOB CAN BE CONTINUED AFTER RUNNING THE MONITOR JOB
;CALLING SEQUENCE:
;	MOVE	S,ITEM TO BE RETURNED
;	MOVE	J,JOB NUMBER
;	PUSHJ	P,SAVCTX
;RETURN HERE AT UUO LEVEL WITH THE FOLLOWING ACS CONTAINING THE
; FOLLOWING ITEMS
; P CONTAINS A POINTER TO THE STACK
; S CONTAINS THE ITEM TO BE RETURNED
; R CONTAINS THE PROTECTION,,RELOCATION OF THE JOB
; J CONTAINS THE JOB NUMBER
;UPON A POPJ FROM THE CALLING ROUTINE, THE JOB'S CONTEXT IS RESTORED
;N.B. THE STACK MUST BE SUCH THAT A "JRST DLYCM" WILL WORK
;IF THE JOB IS RUNNING (RUNNABLE), THE USER WILL GET THE MESSAGE
;"PLEASE TYPE ^C FIRST"

SAVCTX::SKIPGE	JBTSTS##(J)	;JOB RUNNING OR RUNNABLE?
	JRST	SAVCT3		;YES, FLUNK OUT NOW
	PUSHJ	P,FNDPDS##	;ADDRESS OF THE PDB
	HRRZ	T1,.PDSCX##(W)	;ALREADY BEEN HERE ONCE?
	JUMPE	T1,SAVCT1	;JUMP IF NO
	MOVE	T2,4+P(T1)	;SAVED PUSH DOWN LIST POINTER
	MOVEM	T2,JOBDPD##(R)	;STORE IT FOR REUSE
	JRST	SAVCT2		; AND PROCEED
SAVCT1:	MOVEI	T2,NWSCTX	;NUMBER OF WORDS REQUIRED TO SAVE THE JOB'S CONTEXT
	PUSHJ	P,GETWDS##	;GET THAT MUCH FREE CORE
	  JRST	[POP P,(P)	;NOT AVAILABLE, POP OFF CALLERS PC
		 JRST DLYCM##]	;WAIT A TICK AND TRY AGAIN
	MOVE	T2,JBTSTS##(J)	;THE JOB'S CURRENT STATUS
	MOVEM	T2,2(T1)	;SAVE THAT
	MOVE	T2,JOBPC##(R)	;THE JOB'S CURRENT PC
	MOVEM	T2,3(T1)	;SAVE THAT TOO
	MOVSI	T2,JOBDAC##(R)	;MAKE A BLT POINTER TO THE JOB'S
	HRRI	T2,4(T1)	; USER AND EXEC ACS
	BLT	T2,17+4(T1)	;SAVE THE JOB'S ACS
SAVCT2:	MOVEM	S,(T1)		;STORE ITEM TO BE RETURNED TO THE CALLER
	POP	P,1(T1)		;STORE THE CALLER'S PC
	MOVE	T2,TTCMCH##	;SAVE TIMESHARED LOCS FOR COMCON
	MOVEM	T2,24(T1)
	MOVE	T2,TTCMCA##
	MOVEM	T2,25(T1)
	HRRM	T1,.PDSCX##(W)	;REMEMBER THE ADDRESS OF THE BLOCK CONTAINING
				; THE JOB'S CONTEXT
	TLO	M,RUNFLG##	;TTYRNU+NOMESS+NOCRLF+NOPER
	PJSP	T2,MSTART	;START THE MONITOR JOB
;RETURN HERE AT UUO LEVEL
	MOVE	J,.C0JOB##	;CURRENT JOB'S JOB NUMBER
	MOVE	R,JBTADR##(J)	; AND ITS ADDRESS
	HRRZ	W,JBTPDB##(J)	;ADDRESS OF THE PDB
	HRRZ	T1,.PDSCX##(W)	;ADDRESS OF THE SAVED CONTEXT
	MOVE	T2,3(T1)	;THE JOB'S PC WHEN STOPPED
	MOVE	T3,2(T1)	;JBTSTS
	TLNE	T3,JERR		;JOB NOT CONTINUABLE?
	JRST	.+3		;YES, USE UUO LEVEL STACK ALWAYS
	TLNN	T2,(XC.USR)	;WAS THE JOB IN USER MODE?
	SKIPN	P,JOBDPD##(R)	;NO, USE THE CURRENT STACK POINTER IF THERE IS ONE
	JRST	[MOVSI P,MJOBPD## ;YES OR NO EXEC STACK POINTER,
		 HRRI P,JOBPDL##(R) ; SO SETUP THE STACK TO POINT AT THE
		 JRST .+1]	; JOB'S JOB DATA AREA
	PUSHJ	P,TTYFUW##	;FIND THE JOB'S TTY (WAIT IF NECESSARY
				; BEFORE RESTORING TTCMCH AND TTCMCA)
	HRRZ	T1,.PDSCX##(W)	;RESTORE THE ADDRESS OF THE CONTEXT BLOCK
	HRRZM	U,CMDLIN##	;SEE STOPCM IN SCNSER
	MOVE	T2,24(T1)	;RESTORE TIMESHARED LOCS FOR COMCON
	MOVEM	T2,TTCMCH##	;SAVE TIMESHARED LOCS FOR COMCON
	MOVE	T2,25(T1)
	MOVEM	T2,TTCMCA##
	MOVE	S,(T1)		;SETUP ITEM TO BE RETURNED
	TLO	M,400000	;INDICATE THIS IS A COMMAND
	PUSHJ	P,@1(T1)	;CALL THE CALLER TO SAVCTX AS A SUBROUTINE
	  JFCL			;ALLOW A SKIP RETURN AS A CONVENIENCE
	PUSHJ	P,TTYFUW##	;FIND THE JOB'S TTY AND RESTORE J
	PUSHJ	P,FNDPDS##	;ADDRESS OF THE PDB
	HRRZ	T2,.PDSCX##(W)	;ADDRESS OF THE JOB'S SAVED CONTEXT
	PUSH	P,3(T2)		;THE SUPPENDED JOB'S PC
	MOVSI	T1,4(T2)	;FORM A BLT POINTER
	HRRI	T1,JOBDAC##(R)	; TO THE JOB'S SAVED ACS
	BLT	T1,JOBD17##(R)	;RESTORE THE JOB'S SAVED ACS
	PUSH	P,2(T2)		;JOB'S PREVIOUS JBTSTS
	MOVEI	T1,NWSCTX	;NUMBER OF WORDS TO RETURN TO FREE CORE
	PUSHJ	P,GIVWDS##	;RETURN MONITOR FREE CORE
	HLLZS	.PDSCX##(W)	;INDICATE NO SAVED CONTEXT
	POP	P,T1		;RESTORE PREVIOUS JBTSTS
	TLNE	T1,JERR		;WAS THE JOB IN A CONTINUABLE STATE?
	PJRST	HOLD		;NO, STOP THE JOB AND DON'T ALLOW CONTINUE
	PUSHJ	P,HOLD0		;YES, ITS STILL CONTINUABLE
	PJRST	USCHED
SAVCT3:	MOVEI	T1,RUNERR##	;"PLEASE TYPE ^C FIRST"
	POP	P,(P)		;POP OFF CALLER'S PC
	PJRST	ERRMES##	;PRINT THAT AND RETURN TO COMCON
;ROUTINE TO SETUP MONITOR JOB TO RUN LATER AT UUO LEVEL
;CALLED BY COMMANDS WHICH MAY OR MAY NOT NEED TO
;RUN MONITOR JOB DEPENDING ON WHETHER JOB HAS CORE(KJOB,IJOB)
;TTY WILL REMAIN IN MONITOR MODE
;JOB MUST HAVE CORE ASSIGNED
;CALL:	MOVE J, JOB NUMBER
;	MOVEI T2,ADDR. OF MONITOR JOB TO BE RUN
;	PUSHJ P,MONJOB
;WHEN SCHEDULED TO RUN, MONITOR JOB MUST SET UP ITS OWN ACS

INTERNAL MONJOB

MONJOB:
IFN FTMS,<	EXTERNAL CLRJSP
	PUSHJ	P,CLRJSP	;RESET JBTSPS WORD FOR THIS JOB
				;THIS INSURES THAT THE MONITOR JOB RUNS ON MASTER
>
	PUSHJ	P,MSTART	;START WITH PC IN MONITOR
	JRST	SETRUN		;SET TTY TO START JOB WHEN COMMAND RESPONSE
				; IS FINISHED AND KEEP TTY IN MONITOR MODE

;ROUTINE TO SETUP ACS FOR MONITOR JOB STARTING AT UUO LEVEL
;SETS UP J, WITH JOB NO.; R WITH RELOCATION, AND P
;WITH PUSH DOWN LIST ADR. IN JOB DATA AREA
;USED BY KJOB,CORE 0,SAVE,GET,RUN,R,REASSIGN AND FINISH COMMANDS
;CALL:	MOVEI T2,MONITOR JOB STOP ADDRESS
;	JSP T1,MONSTR
;	RETURN WITH ACS P,R,W,M, AND J SETUP

INTERNAL MONSTR
EXTERNAL JBTADR,MJOBPD,JOBPDL,JBTDAT

MONSTR:	SKIPN	J,.C0JOB	;CURRENT JOB NUMBER
	STOPCD	.,STOP,NDS,	;++NULL-JOB DID SAVGET
	MOVE	R,JBTDAT(J)	;ADR. OF JOB DATA AREA
	MOVSI	P,MJOBPD	;MINUS LENGTH OF SYSTEM PD LIST
	HRRI	P,JOBPDL(R)	;FIRST LOC.-1 OF PD LIST
	PUSHJ	P,FNDPDB##	;ADDRESS OF PDB FOR THIS JOB
	  JFCL
IFN FTMS,<	EXTERNAL CLRJSP
	PUSHJ	P,CLRJSP	;CLEAR JBTSPS WORD FOR THIS JOB
>
	TLZ	T2,-1		;CLEAR STRAY PC BITS
	PUSH	P,T2		;SAVE STOP ADRRESS
	MOVSI	M,FLMCOM##	;SET FLAG FOR COMMAND AT UUO LEVEL
	JRST	(T1)		;RETURN AND DO MONITOR JOB
				; WITH TTY DDB,OUTPUT BYTE POINTER, AND JOB NO.
;ROUTINE TO SET JOB STATE TO BE SCHEDULED TO RUN
;WITH SPECIFIED STARTING ADDRESS INCLUDING PC FLAGS
;CALLED ONLY WHEN JOB IN CORE AND AFTER JOB HAS BEEN
;SAFELY STOPPED IN ONE OF 3 STATES:
;1) PC IN USER MODE
;2) JOB IN A WAIT FOR SHARABLE DEVICE, OR IO WAIT
;3) JOB JUST ABOUT TO RETURN TO USER MODE FROM A UUO CALL
;CALL:	MOVE T2,STARTING PC
;	MOVE J, JOB NUMBER
;	MOVE R,ADR. OF JOB DATA AREA WHICH MUST BE IN CORE
;	PUSHJ P,USTART(PC TO USER MODE),MSTART(PC TO MONITOR MODE)
;	RETURN HERE IMMEDIATELY

INTERNAL MSTART,USTART,RSTART
EXTERNAL JOBPC,JOBDAC,JOBD17,JOBOPC,JOBPD1

USTART:
	MOVE	T1,JOBPC(R)	;GET OLD PC
	TLNE	T1,USRMOD	;IS IT IN USER MODE TOO?
	JRST	USTRT1		;YES, DUMP ACS AND PC FLAGS ARE ALREADY HIS
IFN FTKA10,<
	MOVEI	T1,JOBDAC(R)	;NO, MOVE USERS(UUO) ACS TO DUMP ACS
	HRL	T1,R		;SOURCE=REL. 0,DEST.=JOBDAC IN JOB DATA AREA
	BLT	T1,JOBD17(R)	;MOVE ALL ACS
>
	PUSH	P,M		;SAVE M
	MOVE	M,JOBPD1(R)	;GET LAST PC + 1
	HRRI	M,-2(M)		;THIS HORRIBLE KLUDGE CHECKS SPECIAL CASE
	PUSH	P,T2
	PUSHJ	P,GETWRD##	; OF THE HIBER UUO, SINCE HIBER
	  SETZ	T1,		; INCREMENTS JOBPD1 BEFORE THE UUO
	POP	P,T2
	TLZ	T1,740		; COMPLETES, UNLIKE ALL OTHER UUO'S
	CAME	T1,[HIBER]	;WERE WE RIGHT IN BACKING PC BY 2?
	HRRI	M,1(M)		;NO, INCREMENT
	TLZ	M,37		;CLEAR INDEX
	MOVE	T1,M		;GET PC OF LAST INSTRUCTION EXECUTED
	POP	P,M		;RESTORE M
				; (RH=0 ON HALT 0 OR FIRST START)
USTRT1:
	MOVEM	T1,JOBOPC(R)	;STORE OLD PC FOR USER TO LOOK AT
	HLL	T2,T1		;PRESERVE USER APR FLAGS
	TLO	T2,USRMOD	;MAKE SURE NEW PC IN USER MODE
IFN FTKI10!FTKL10,<
	TLO	T2,(XC.PUB)	;INSURE PUBLIC IS SET
>
	TLZ	T2,37		;MAKE SURE NO INDIRECT BITS OR INDEX FIELD
IFN FTMS,<	EXTERNAL DPXST
	PUSHJ	P,DPXST		;MAKE JOB RUNNABLE ON SLAVE NOW
>
	JRST	MSTRT1		;DON'T CLEAR JSP WORD

MSTART:
IFN FTKI10!FTKL10,<
	TLO	T2,(IC.UOU)	; INSURE USER IOT IS ON
>
IFN FTMS,<	EXTERNAL CLRJSP
	PUSHJ	P,CLRJSP	;INITIALIZE JBTSPS ENTRY
>
MSTRT1:	CAMN	J,.C0JOB	;IS IT THE CURRENTLY RUNNING JOB?
	MOVEM	T2,.C0PC	;YES - SAVE NEW PC IN USRPC IN CASE WE'RE AT
				; CLOCK LEVEL AND HAVE EXITED FROM CURRENT JOB.
				; THIS WILL AVOID THE PROBLEM OF GOING BACK TO JOB.
				; THE LOCATION AFTER THE "CALLI 12" BECAUSE
				; SOFTWARE AND HARDWARE STATUS OF JOB ARE NEVER CHANGED.
	MOVEM	T2,JOBPC(R)	;STORE NEW PC
	MOVE	T1,[XWD WTMASK+JERR,UTRP] ;CLEAR TRAP TO USER AT UUO EXIT,
				; WAIT STATE CODE AND ERROR IN JOB BIT
	ANDCAM	T1,JBTSTS(J)	;IN JOB STATUS WORD

;ROUTINE TO CLEAR FLAGS SO A JOB CAN CONTINUE IN MIDDLE OF MONITOR
; (CALLED ON REENTER AND DDT COMMANDS).
RSTART:	MOVE	T1,[XWD CNTRLC,JS.MPE+JS.JDP+JS.APE+JS.DPM] ;CLEAR TYPED ^C FLAG
				; CLEAR MEM PAP ERR, MEM PAR IN JOB DATA AREA,
				; APR ERROR, DAEMON PROBLEM MESSAGE
	ANDCAM	T1,JBTSTS(J)	;IN JOB STATUS WORD
	MOVSI	T1,(JS.SLP)	;CLEAR SLEEP BIT
	ANDCAM	T1,JBTST2##(J)
	POPJ	P,		;RETURN
;ROUTINE TO SET JOB STATUS RUN BIT(RUN)
;CALLED BY SCANNER SERVICE WHEN TTY MONITOR COMMAND
;RESPONSE FINISHES.  THIS ACTION IS ENABLED BY CALLING
;TTYUSR, OR TTYURC IN SCNSER
;CALL:	MOVE J,JOB NUMBER
;	PUSHJ P,SETRUN

INTERNAL SETRUN,SETR2
EXTERNAL JBTSTS,PJBSTS,RQTBMQ,AVTBMQ
EXTERNAL MINQ,MAXQ

SETRUN:	IFN FTDAEM,<
	MOVEI	T1,JDC		;SEE IF WAITING
	TDNE	T1,JBTSTS(J)	;  FOR DAEMON
	POPJ	P,		;YES--DO NOT REQUEUE
>
	LDB	T1,PJBSTS	;GET JOB STATUS WAIT QUEUE CODE
IFN FTSWAP,<
	CAIL	T1,MINQ		;SHARABLE RESOURCE STATE CODE?
>
	CAILE	T1,MAXQ		;DOES JOB STATUS CODE HAVE A QUEUE?
	JRST	SETR1		;NO
	AOSLE	RQTBMQ(T1)	;ADD TO REQUEST COUNT
	JRST	SETR1		;OTHERS WAITING?
	AOSG	AVTBMQ(T1)	;MAKE AVAILABLE
	SETOM	AVTBMQ(T1)	;FLAG AS JUST AVAILABLE, BECAUSE
				; NO JOB WAS USING DEVICE. SCHEDULER
				; WILL SCAN THIS QUEUE
SETR1:	CAIE	T1,EWQ		;IF IN EVENT WAIT
	JRST	SETR1A
	MOVEI	T1,RNQ##	;THEN SET TO RUN STATE
	DPB	T1,PJBSTS
SETR1A:	IFN FTRSP,<
	PUSHJ	P,SETRSP	;SET TIME USER BEGAN TO WAIT FOR RESPONSE
>
IFN FTKL10&FTMS,<
	PUSHJ	P,SETCSJ##	;CAN'T RUN ON CPU1 UNTIL A SWEEP IS DONE
>
	MOVSI	T1,RUN		;SET RUN BIT IN JOB STATUS WORD
	IORM	T1,JBTSTS(J)

;HERE FROM WAKE UUO IN UUOCON
SETR2:	MOVE	T1,QADTAB##	;SET QUANTUM TIME TO RUN QUEUE QUANTUM
	PUSH	P,W
IFE FTPDBS,< ;IF WE KNOW PDB IS IN CORE
	SKIPN	T2,JBTPDB##(J)	;GET PDB ADR
	STOPCD	.,JOB,CFP,	;++CAN'T FIND PDB
	.DPB	T1,PDYQT2##	;SET QUANTUM RUN TIME
> ;END FTPDBS
IFN FTPDBS,< ;IF PDB MAY BE ON THE DISK
	PUSHJ	P,SETQNT##	;CALL SUBROUTINE TO SET UP .PDQNT
> ;END FTPDBS
	POP	P,W

INTERNAL FTSWAP
IFE FTSWAP,<
		JRST NJBTST	;GO SEE IF NULL JOB IS RUNNING
>
IFN FTSWAP,<
	INTERNAL REQUE
	EXTERNAL QJOB,JBTSTS

REQUE:	SKIPN	J		;TRYING TO REQUEUE THE NULL JOB?
	STOPCD	CPOPJ,DEBUG,PJ0,	;++REQUEUE JOB 0
	MOVSI	T1,JRQ		;MARK JOB TO BE REQUEUED WITH JRQ BIT
	CONO	PI,PIOFF	;GUARD AGAINST COUNTING QJOB UP TWICE
	TDNE	T1,JBTSTS(J)	;INCREMENT COUNT ONLY ONCE FOR EACH JOB
	JRST	REQUE1		;JOB IS ALREADY MARKED FOR REQUEING
	IORM	T1,JBTSTS(J)	;SET REQUE BIT FOR SCHEDULER
	AOS	QJOB		;INCREMENT COUNT OF NO. OF JOBS WAITING TO BE REQUEUED
	MOVSI	T1,(JS.SLP)	;CLEAR SLEEP BIT
	ANDCAM	T1,JBTST2##(J)
REQUE1:	PJRST	ONPOPJ##	;TURN ON
				;PI AND RETURN
>
;SUBROUTINE TO PUT JOB IN EVENT WAIT
;CALL:	MOVE T1,<REASON>
;	MOVE J,<JOB NUMBER>
;	PUSHJ	P,ESLEEP
;	RETURN HERE WHEN SOME EVENT HAPPENS

;ENTER AT FSLEEP IF THE EVENT WHICH IS BEING WAITED FOR IS LIKELY
; TO OCCUR SOON (WITHIN MILLISECONDS) AND THE JOB SHOULD NOT
; BECOME MORE SWAPPABLE AS A RESULT OF GOING INTO EVENT WAIT

ESLEEP::PUSH	P,W		;SAVE W
	PUSHJ	P,ZERIPT##	;FIND PDB, MARK JOB AS SWAPPABLE
	PUSHJ	P,FSLEEP	;WAIT FOR THE EVENT
	JRST	WPOPJ##		;RESTORE W AND RETURN

FSLEEP::PUSHJ	P,SAVE1##	;SAVE P1
	MOVEI	T2,EWAKEB	;WAKUP BIT
	MOVEI	P1,EWQ##	;Q TO PUT JOB INTO
	CONO	PI,PIOFF##	;SOLVES ALL RACES
	TDNN	T2,JBTST2##(J)	;LOOK IN STATUS WORD
	JRST	ESLP1		;PUT HIM TO SLEEP
	ANDCAM	T2,JBTST2##(J)	;ELSE CLEAR BIT
	PJRST	ONPOPJ##	;  TURN ON PI
				;  AND RETURN

;HERE TO PUT JOB TO SLEEP

ESLP1:	DPB	P1,PJBSTS##	;SET WAIT STATE
	DPB	T1,JBYEWT##	;SET REASON CODE
	CONO	PI,PION##	;RESTORE PI SYSTEM
	PJRST	WSCHED		;RESCHEDULE
;SUBROUTINE TO WAKE UP JOB IN EW
;CALL:	MOVE T1,<JOB NUMBER>
;	PUSHJ P,EWAKE
;	RETURN HERE
;CLOBBERS T1,T2

EWAKE::	PUSH	P,J		;SAVE J
	MOVE	J,T1		;JOB # TO J
	MOVEI	T1,RNQ##	;RUN QUEUE
	CONO	PI,PIOFF##	;INTERLOCK
	LDB	T2,PJBSTS##	;GET STATE CODE
	CAIE	T2,EWQ##	;WAITING?
	JRST	NOTEW		;NO - REMEMBER THEN
IFN FTPSCD,<
	AOS	%EWCNT##	;COUNT EW SATISFIED
>

	PUSH	P,W		;SAVE W
	PUSHJ	P,WAKOKE##	;WAKE UP JOB
	  JFCL			;IN CASE OF NON-SKIP
	POP	P,W		;RESTORE W
	PJRST	JPOPJ##		;RESTORE J AND RETURN

NOTEW:	MOVEI	T2,EWAKEB	;SET BIT FOR LATER
	IORM	T2,JBTST2##(J)
	CONO	PI,PION##
	PJRST	JPOPJ##		;EXIT
;SUBROUTINE TO SET TIME USER STARTED TO WAIT FOR RESPONSE
; IF NOT ALREADY CALLED WHEN A COMMAND IS DELAYED

IFN	FTRSP,<EXTERN JBTRSP
	INTERN	SETRSP


SETRSP:	MOVE	T1,.C0UPT	;TIME SYSTEM HAS BEEN UP IN JIFFIES
	SKIPE	T2,JBTRSP(J)	;HAS USER STOPPED WAITING?
				; (DELAYED COMMAND)
	TLNE	T2,(JR.RXX)	;NO, HAVE ANY RESPONSES BEEN STORED?
				; (NEXT CALL ON DELAYED COMMAND WILL NOT
				; STORE, SO INCLUDE DELAY IN RESPONSE TIME)
	MOVEM	T1,JBTRSP(J)	;YES, STORE TIME USER BEGAN TO WAIT FOR RESPONSE
				; SEE SYSRSP, NUMRSP. SCHEDULER ACCUMULATES AVERAGE
				; RESPONSE
	POPJ	P,
>

;ROUTINE TO RECORD RESPONSE SATISFIED BY TTY OUTPUT UUO EXECUTION
;
;CALL:	PUSHJ	P,RSPTOR
;	RETURN

IFN FTRSP,<
RSPTOR::MOVEI	T1,.C0AOR##	;BASE ADR FOR 3 WORD TTY OUTPUT UUO RSP
				; ON CPU0
	MOVSI	T2,(JR.ROR)	;RECORD TTY OUT UUO RSP FOR THIS JOB
	PJRST	RSPRC1		;GO RECORD UNLESS ALREADY

;ROUTINE TO RECORD RESPONSE SATISFIED BY TTY INPUT UUO EXECUTION
;CALL:	PUSHJ	P,RSPTIR
;	RETURN

RSPTIR::MOVEI	T1,.C0AIR##	;BASE ADR. FOR 3 WORD TTY INPUT UUO RSP
				; ON CPU0
	MOVSI	T2,(JR.RIR)	;RECORD TTY INPUT UUO RSP FOR THIS JOB
				;FALL INTO RSPRC1

;ROUTINES TO RECORD RESPONSE DATA FOR VARIOUS TYPES OF RESPONSES
;CALL:	MOVE	P4,CPU DAT BLOCK
;	MOVE	J,JOB NUMBER
;	MOVEI	T1,.CPA??##(P4)	;BASE ADR OF 3 WORD BLOCK IN CDB
;	MOVSI	T2,(RS.R??)	;BIT - ALREADY RECORDED THIS RESPONSE
;	TDNN	T2,JBTRSP(J)	;OPTIONAL TEST TO SEE IF RECORDED
;	PUSHJ	P,RSPRC2 OR RSPREC
;	RETURN

RSPRC1::MOVEI	P4,.C0CDB##	;SETUP CPU0 CDB POINTER
	MOVE	J,.C0JOB##	;CURRENT JOB ON CPU0
RSPRC2::PUSHJ	P,RSPREC	;RECORD THIS RESPONSE
	MOVEI	T1,.CPAXR##(P4)	;ADDR FOR ANY OF TTY OUT, TTY IN, OR REQUE
				; RESPONSE TERMINATIONS
	MOVSI	T2,(JR.RXR)	;RECORDED ANY OF TTYOUT, TTYIN, OR REQUE
				;UNTIL FIRST CPU RESPONSE ONLY
RSPREC::TDNE	T2,JBTRSP##(J)	;RECORDED IT YET?
	POPJ	P,		;YES, RETURN
	IORB	T2,JBTRSP##(J)	;GET UP TIME STARTED TO WAIT FOR RESPONSE
	TLZ	T2,(JR.RXX)	;CLEAR OUT ALL RESPONSE BITS
	MOVNS	T2		;NEGATIVE
	ADD	T2,.C0UPT	;UP TIME NOW - START=RESPONSE TIME
	ADDM	T2,RSPAXR##(T1)	;ACCUM SUM OF RSP OF THIS TYPE FOR THIS CPU
	MUL	T2,T2		;T2,T3=SQUARE OF RESPONSE
				; (FOR STANDARD PEVIATION)
	TLO	T3,400000	;FORCE SIGN NEG OF LOW ORDER WORD
				; SO DIFFERENT FROM ACCUM SO NEVER OVF. INT.
	CONO	PI,PIOFF	;ALLOW ONLY ONE UPDATE AT A TIME
	ADD	T3,RSPLXR##(T1)	;ADD LOW ORDER SQUARE
	TLZN	T3,400000	;DID AN OVERFLOW OCCUR?
	ADDI	T2,1		;YES, PROPAGATE CARRY TO HIGH ORDER WORD
	MOVEM	T3,RSPLXR##(T1)	;NOW STORE LOW ORDER WITH SIGN ALWAYS 0
	CONO	PI,PION		;ALLOW INT AGAIN
	ADDM	T2,RSPHXR##(T1)	;ACCUM. HIGH ORDER SQUARE
	AOS	RSPNXR##(T1)	;COUNT NO. OF RESPONSES OF THIS TYPE
	POPJ	P,
>
				;END RESPONSE

IFN FTTLIM,<	INTERNAL MTIMLM,TLEMES
MTIMLM:	PUSHJ	P,TTYERP##	;LIMIT JUST WENT TO 0 - FIND TTY DDB
IFN FTOPRERR,<
	  JRST	MTIML1		;TIME LIMIT EXCEEDED FOR DETACHED JOB
>
	PUSHJ	P,INLMES##	; AND THE MESSAGE:
TLEMES:	ASCIZ	/?
?Time limit exceeded
/
IFN FTPI,<
	PUSHJ	P,PSIERR##	;IF INTERCEPTING TLE,
	  POPJ	P,		; GO TO THE USER
	  POPJ	P,
>
	PUSHJ	P,TSETBI	;CLEAR TYPE AHEAD
	JRST	HOLD0		;STOP JOB, DONT SET JERR
				; (SO "CONT" WILL WORK)
IFN FTOPRERR,<
MTIML1:	PUSHJ	P,ERINDJ##	;SET UP TO GIVE MESSAGE TO OPR
	MOVEI	T1,TLEMES	;
	PUSHJ	P,CONMES##	; AND GO GIVE IT
	JRST	ESTOP3		; AND THEN STOP THE USER
>	;END FTOPRERR
>	;END FTTLIM
;ROUTINE TO PUT A JOB TO SLEEP AND WAKE UP AGAIN LATER
;CALLED AFTER CLOCK QUEUE REQUEST PUT IN BY UUO ROUTINE

INTERNAL FTSLEEP

IFN FTSLEEP,<
INTERNAL SETSLP
EXTERNAL JBTSTS,SLPQ

SETSLP:
	MOVEI	16,SLPQ		;SLEEP STATE CODE
	JRST	SETNP1		;SET STATUS AND RESCHEDULE

;HERE FROM UUOCON TO PUT A JOB INTO NAP STATE.  THIS MERELY
; HAS THE EFFECT OF MAKING ITS WAIT STATE CODE NON-ZERO WHILE
; LEAVING IT IN THE RUN QUEUE.  IF A JOB SLEEPS OR HIBERNATES
; FOR LESS THAN ONE SECOND, IT IS PUT INTO NAP STATE RATHER THAN
; SLEEP, SO THAT IT WILL NOT GET BACK INTO PQ1 WHEN IT WAKES UP.

SETNAP::MOVEI	16,NAPQ##	;PUT INTO NAP STATE
SETNP1:	MOVEI	T1,CLKR		;FLAG THAT A CLOCK REQUEST HAS BEEN PUT IN
	IORM	T1,JBTSTS##(J)
	JRST	SETSTT		;SET STATUS AND RESCHEDULE


;HERE AT CLOCK LEVEL WHEN CLOCK REQUEST TIMES OUT FOR SLEEP
;JOB NO. IN AC T1

INTERNAL WAKEJ
EXTERNAL PJBSTS,SLPQ

WAKEJ:	MOVEI	T2,RNQ##	;RUN QUEUE CODE
	MOVE	J,T1		;JOB NO.
	MOVEI	T1,CLKR		;CLEAR CLOCK REQUEST BIT FOR THIS JOB
	ANDCAM	T1,JBTSTS(J)	;SO IT CAN PUT ANOTHER ONE IN
	LDB	T1,PJBSTS	;GET QUEUE CODE
	CAIE	T1,NAPQ##	;IS JOB NAPPING?
	JRST	WAKE1		;NO.
	MOVEI	T2,RNQ##	;YES, MAKE HIM RUNNABLE AGAIN
	DPB	T2,PJBSTS##
	POPJ	P,		;RETURN

WAKE1:	CAIE	T1,SLPQ		;IS JOB STILL SLEEPING?
	POPJ	P,		;NO. RETURN TO CLOCK ROUTINE
IFN FTPSCD,<
	AOS	REQSS##		;COUNT A SLEEP SATISFIED
>
	DPB	T2,PJBSTS	;YES, STORE RUN QUEUE CODE
				; (CONTROL C, START CAN GET JOB OUT OF SLEEP)
	JRST	SETR2
>

;ROUTINE TO WAKE UP DAEMON AND STOP USER WITH DEVICE ERROR
; UNTIL DAEMON HAS A CHANCE TO ENTER ERROR IN LOG FILE.
;CAN BE CALLED AT ANY LEVEL:
;CALL:	MOVE	F,DEVICE DATA BLOCK ADR.
;	MOVEI	T1,CODE FOR THIS ERROR
;	HRL	T1,CDB OR DDB ADDR
;	PUSHJ	P,DAEERR OR DAESJE
;	ALWAYS RETURN J PRESERVED, T1, T2 USED

IFN FTEL,<			;ERROR LOGGING?
	INTERN	DAEERR,DAESJE,DAEEIM,DAERPT
	EXTERN	JOB,PJOBN,SYSERR

DAEERR:	PUSH	P,J		;SAVE J(FILIO USES J FOR CONTROLLER DATA BLOCK)
	LDB	J,PJOBN		;GET JOB NUMBER FORM DEVICE DATA BLOCK
	MOVE	T2,DEVSTA(F)	;WHERE DISABLE ERROR LOGGING BUT IS
	TRNE	T2,DEPDEL	;ERROR LOGGING DISABLED FOR THIS DEVICE
				; BY USER ON OPEN UUO (USER MODE DIAG)
	AOSA	DELCNT##	;YES, JUST KEEP COUNT AND RETURN
				; DO NOT STOP USER OR WAKE DAEMON
	PUSHJ	P,DAESJE	;STOP JOB AS SPECIFIED BY J
	JRST	JPOPJ##		;RESTORE J AND RETURN

;ROUTINE TO WAKE DAEMON AND, STOP SPECIFIED JOB
;CALL:	MOVE	J,JOBNUMBER
;	MOVEI	T1,CODE FOR THIS ERROR
;	HRL	T1,CDB OR DDB ADDR
;	PUSHJ	P,DAESJE
;	ALWAYS RETURN

DAEEIM:	MOVEI	J,0		;ERROR IN MONITOR, BLAME JOB 0
DAESJE:	AOS	SYSERR		;INCREMENT NO OF SYSTEM ERRORS FOR DAEMON
DAERPT:	CONO	PI,PIOFF##	;NEED TO TURN OF PI'S TO STOP TWO I
				; HITTING END OF TABLE AT SAME TIME
	AOS	ESVIDX##
	AOS	T2,ESVIDX##	;GET INDEX FOR NEXT ERROR TO SAVE
	CAIL	T2,ERPTMX##	;HAVE WE EXCEEDED MAX
	SETZB	T2,ESVIDX##	;YES, JUST RESET ESVIDX
	CONO	PI,PION##	;TURN THE PI'S BACK ON
	SKIPE	ERPTBK##(T2)	;HAVE WE OVERLAPPED
	JRST	MNYERR		;YES, DAEMON ISN'T KEEPING UP, LOSE THIS ERROR
	DPB	J,[POINT 9,T1,26]
	MOVEM	T1,ERPTBK##(T2)	;SAVE T1 FOR ERRPT. UUO
	MOVE	T1,U
	HRL	T1,F
	MOVEM	T1,ERPTBK##+1(T2)
	PUSHJ	P,STDAEM	; SO DAEMON WILL KNOW AN ERROR HAPPENED
				;WAKE UP DAEMON - RETURN T1=DAEMON JOB #
	  POPJ	P,		;DAEMON NOT RUNNING
	JUMPE	J,CPOPJ		;IF ERROR IN MONITOR DON'T TRY TO STOP A JOB
	MOVEI	T2,JS.DEP	;STOP USER WHO HAD ERROR
	PUSHJ	P,FLSDR##	;JOB HAVE DISK RESOURCE?
	CAMN	J,T1		;NO. IS IT DAEMON?
	POPJ	P,		;YES, DONT STOP HIM
	IORM	T2,JBTSTS(J)	;NO, STOP HIM, DAEMON WILL CONTINUE
	PUSHJ	P,REQUE		;FORCE REQUEUE FOR DAEMON
IFN FTKI10!FTKL10,<
	PUSHJ	P,SVEUB##	;SINCE CAN BE AT INTERRUPT LEVEL, MAKE THE
				; JOB DATA AREA ADDRESSABLE
>
	PUSHJ	P,SIMCHK	;CAN JOB BE STOPPED NOW (OR MUST IT
				; WAIT TILL UUO EXIT)?
	  PJRST	STOP1B		;YES, STOP HIM NOW

	POPJ	P,		;NO, LET UUO RETURN STOP JOB
MNYERR:	AOS	ERRLAP##	;COUNT TIMES WE'VE OVERFLOWED BLOCK
	POPJ	P,		;AND JUST RETURN
>				;END FTEL
IFE FTEL,<
DAEERR::DAEEIM::DAESJE::	POPJ	P,
>
IFN	FTDAEM,<		;DAEMON FEATURE?
INTERN STDAEM
;ROUTINE TO FIND DAEMON, START RUNNING
;RETURNS POPJ IF CANT FIND, CPOPJ1 IF OK, T1 = DAEMON JOB #

STDAEM:	MOVE	T1,HIGHJB	;SCAN ALL JOBS
STDAE1:	MOVE	T2,JBTNAM(T1)	;PROGRAM NAME
	CAME	T2,[SIXBIT/DAEMON/]	;IS THIS DAEMON?
	JRST	STDAE2		;NO
	MOVE	T2,JBTSTS(T1)	;JOB STATUS WORD
IFN FTLOGI,<
	TLNE	T2,JACCT
>				;IS THIS DAEMON PRIVELEGED?
	TLNN	T2,RUN		;YES, IS IT RUNNING
	JRST	STDAE2		;NO, KEEP LOOKING
	LDB	T2,PJBS2
	CAIN	T2,TIOWQ
	JRST	STDAE2
	PUSH	P,T1		;WAKJOB DESTROYS THE DAEMON JOB NUMBER
	PUSHJ	P,WAKJOB##	;WAKE UP DAEMON
	PJRST	TPOPJ1##	;AND OK RETURN (DAEMON STARTED)

STDAE2:	SOJG	T1,STDAE1	;LOOP FOR MORE JOBS
	POPJ	P,		;COULD NOT FIND DAEMON, 'ERROR RETURN'

;ROUTINE TO START A JOB WHEN DAEMON IS DONE
;CALL:	MOVE	J,JOB NO. OF USER TO START
;	PUSHJ	P,DAEDON
;	ALWAYS RETURN HERE
;CALLED FROM DAEFIN UUO
	INTERN	DAEDON

DAEDON:	MOVEI	T1,JDC!JS.DPM	;DAEMON BIT FOR REQUEING AND DAEMON PROBLEM
				; MESSAGE BIT (ONCE-A-MIN)
	ANDCAM	T1,JBTSTS(J)	;CLEAR IT IN JOB STATUS WORD
	MOVEI	T1,JS.DEP	;DAEMON ERROR PAUSE BIT
	LDB	T2,PJBSTS	;USER WAIT STATE CODE
	TDNN	T1,JBTSTS(J)	;WAS USER IN ERROR PAUSE?
	CAIN	T2,JDCQ##	;NO, WAS USER IN DAEMON QUEUE?
	JRST	DAEFN3		;YES, START USER UP IF STILL RUNNABLE
	PUSHJ	P,TTYSRC##	;NO, MUST HAVE BEEN DUMP COMMAND, FIND TTY
	  MOVEI	  U,0		;NONE FOUND
	TRNE	U,-1		;FIND A LINE?
	PUSHJ	P,TTYSTC	;YES, SET BACK TO COMMAND LEVEL
	POPJ	P,		;RETURN

;HERE ON UUO CALL TO DAEMON OR DAEMON ERROR PAUSE
DAEFN3:	ANDCAM	T1,JBTSTS(J)	;CLEAR DAEMON ERROR PAUSE BIT
IFN FTPSCD,<
	AOS	REQJSD##		;COUNT DAEMON RESPONSE
>
	MOVEI	T1,RNQ##	;SET WAIT STATE CODE BACK TO RUN
	CAIN	T2,JDCQ##	;DON'T REQUEUE IF NOT IN DAE QUEUE
	DPB	T1,PJBSTS	;IN JOB STATUS WORD
	PJRST	REQUE		;REQUE USER SO WILL RUN IF HE
				; HASN'T TYPED CONTROL C.
>				;END FTDAEM
IFN FTDAEM,<
;ERRPT. UUO
;USED BY DAEMON TO OBTAIN NEXT DEVICE/CONDITION
;WITH AN ERROR THAT MUST BE LOGGED
;NON SKIP RETURN IF NO OTHER ERRORS OR NO PRIVS
;RETURNS CODE,,DDB ADDRESS IN AC ON SKIP RETURN

ERRPT.::PUSHJ	P,PRVJ##	;IS THIS GUY PRIVILEGED?
	SKIPA	T2,EPKIDX##	;GET NEXT WORD TO LOOK AT IN TABLE
	  POPJ	P,		;NO, GIVE ERROR RETURN
	CAIL	T2,ERPTMX##	;OFF END OF TABLE?
	SETZ	T2,		;YES, RESET POINTERS
	HRR	M,T1
ERPTLP:	SKIPE	T1,ERPTBK##(T2)	;IS THIS ENTRY 0?
	JRST	GOTONE		;NO, RETURN IT
	ADDI	T2,2
	CAMN	T2,EPKIDX##	;LOOKED AT ALL ENTRIES?
	POPJ	P,		;YES, NONE FOUND
	CAIL	T2,ERPTMX##	;OFF END OF TABLE
	SETZ	T2,		;YES, RESET TO BEGINNIG OF TABLE
	CAMN	T2,EPKIDX##	;LOOKED AT ALL ENTRIES?
	POPJ	P,		;YES, NOTHING FOUND
	JRST	ERPTLP		;LOOP BACK FOR NEXT ENTRY
GOTONE:	SETZM	ERPTBK##(T2)	;ZERO THIS ENTRY
	PUSHJ	P,PUTWDU##
	MOVE	T1,ERPTBK##+1(T2)
	PUSHJ	P,PUTWD1##
	ADDI	T2,2
	MOVEM	T2,EPKIDX##	; AND SAVE FOR WHERE TO LOOK NEXT
	JRST	CPOPJ1		;AND SKIP
>	;END FTDAEM
IFE FTDAEM,<
ERRPT.==:CPOPJ##
>

IFN FTDAEM,<			;DAEMON FEATURE?
;SUBROUTINE TO CALL DAEMON FOR DEBUG OR JOB STOPCD
;DOES NOT TRY TO STOP ANY JOB
DAEEST::MOVEI	T1,.ERMSE	;GET CODE FOR DAEMON
	HRLI	T1,.C0CAC##	;PUT INTERSTING ADDR IN T1 FOR DAEMON
	AOS	ESVIDX##
	AOS	T2,ESVIDX##	;GET INDEX FOR NEXT ERROR TO SAVE
	CAIL	T2,ERPTMX##	;HAVE WE EXCEEDED MAX
	SETZB	T2,ESVIDX##	;YES, JUST RESET ESVIDX
	SKIPE	ERPTBK##(T2)	;HAVE WE OVERLAPPED
	JRST	MNYERR		;YES, DAEMON ISN'T KEEPING UP, LOSE THIS ERROR
	MOVEM	T1,ERPTBK##(T2)	;SAVE T1 FOR ERRPT. UUO
	MOVE	T1,U
	HRL	T1,F
	MOVEM	T1,ERPTBK##+1(T2)
	PUSHJ	P,STDAEM	; SO DAEMON WILL KNOW AN ERROR HAPPENED
	  JFCL
	POPJ	P,
>				;END FTDAEM
REPEAT 0,<
;THIS SUBROUTINE USED ONLY IF PDP-6 DECTAPES
;ROUTINE TO GET DATA CONTROL AND ANOTHER SHARABLE DEVICE
;JOB NEVER GETS ONE DEVICE AND WAITS FOR SECOND, SINCE TYPING
;CONTROL C WOULD NEVER FINISH WITH FIRST DEVICE
;CALL	PUSHJ P,GETDCXX
;	AOSE XXREQ	;REQUEST COUNT FOR OTHER DEVICE
;	RETURN WHEN BOTH AVAILABLE

INTERNAL GETDCDT,GETDCMT
EXTERNAL DCREQ,REQTAB,AVALTB,DCAVAL,CPOPJ1

GETDCDT:GETDCMT:
	XCT	@(P)		;INCREASE SHARABLE DEVICE REQ. COUNT
GETWT:	PUSHJ	P,DVWAT1	;NOT AVAIL., GO WAIT FOR IT
	AOSN	DCREQ		;IS DATA CONTROL AVAILABLE?
	JRST	CPOPJ1		;YES, RETURN BOTH AVAILABLE
	MOVE	P1,@(P)		;DATA CONTROL NOT AVAILABLE
	SUBI	P1,REQTAB
	SOSL	REQTAB(P1)	;REDUCE REQ. COUNT FOR OTHER
				; SHARABLE DEVICE.
	SETOM	AVALTB(P1)	;SET AVAILABLE IF OTHER JOBS WAITING
	JFCL	DCREQ		;ARGUMENT FOR DCWAIT
	PUSHJ	P,DCWAIT	;WAIT FOR DATA CONTROL FREE
	MOVE	P1,@(P)		;INCREMENT REQ. COUNT
	AOSN	@P1		;NOW IS SHARABLE DEVICE FREE?
	JRST	CPOPJ1		;YES
	SOSL	DCREQ		;NO, REDUCE DATA CONTROL REQUEST
	SETOM	DCAVAL		;SET AVAIL., SOME OTHER JOB WAITING FOR IT
	JRST	GETWT		;TRY AGAIN
>	;END REPEAT 0
;ROUTINE TO WAIT FOR A SHARABLE RESOURCE
;CALLED AT UUO LEVEL ONLY
;	PUSHJ P,XXWAIT
;	RETURN WHEN RESOURCE AVAILABLE

;INITIALLY THE REQUEST COUNT IS -N, WHERE N IS THE
;NUMBER OF JOBS WHICH CAN USE THE SHARABLE RESOURCE AT THE SAME TIME
;A REQUEST COUNT OF 0 MEANS THE MAXIMUM NO. OF JOBS ARE
;USING THE RESOURCE, A POSITIVE NUMBER IS THE
;NUMBER OF JOBS WAITING IN THE SHARABLE RESOURCE WAIT QUEUE
;MUMERIC ACS  16 AND 17 ARE PRESERVED SINCE THE NEW AC CONVENTION DEPENDS
;ON THEM BEING SAVED. NUMERIC ACS ARE USED RATHER THAN SYMBOLIC SO THAT
;THE PROPER ACS WILL BE SAVED IN THE DUMP ACS EVEN IF THE SYMBOLIC AC 
;VALUES ARE CHANGED

	EXTERNAL JOBD16,JOBD17,REQTAB

DEFINE X(A,B,C)<
	MQ==MQ+1>
	MQ==0
	QUEUES

DEFINE X(A,B,C)<
A'WAIT:	PUSHJ	P,SRWAIT
INTERNAL A'WAIT
>

DVWAIT:	RWAITS
SRWAIT:
	MOVEM	16,JOBD16(R)	;SAVE AC16 (SINCE IT IS A PRESERVED AC)
	MOVEM	17,JOBD17(R)	;ALSO AC17
	POP	P,16		;GET ENTRY ADDRESS
	SUBI	16,DVWAIT-MQ+1	;COMPUTE WAIT-STATE QUEUE CODE
	MOVE	17,.C0JOB	;PICK UP JOB NUMBER
	AOSG	REQTAB-MQ(16)	;IS THE RESOURCE AVAILABLE?
	JRST	SRAVAL		;YES, GO USE IT
SETSTT:	MOVE	17,.C0JOB	;JOB NUMBER OF RESOURCE REQUESTER
	DPB	16,PJBS3	;STORE QUEUE CODE IN JOB STATUS
	MOVE	16,JOBD16(R)	;RESTORE AC16
	PJRST	RMEVM##		;REMEMBER EVM IF ANY AND
				; RESCHEDULE AND RETURN TO CALLER
				; WHEN SHARABLE DEVICE BECOMES AVAILABLE
				; SEE CLOCK AND CLKCSS


;HERE WHEN THE REQUESTED SHARABLE RESOURCE WAS AVAILABLE

SRAVAL:	MOVE	17,.C0JOB	;JOB NUMBER OF RESOURCE OWNER
IFN FTDISK,<
	CAMN	17,FORCEF##	;IS THIS JOB SELECTED TO BE SWAPPED?
	PUSHJ	P,CFLSDR	;YES, DOES HE HAVE ANY RESOURCES?
	  JRST	SRAVL1		;NOT IN FORCEF OR HAS RESOURCES + IS
	SETOM	AVALTB-MQ(16)	;SET AVAL BUT DON'T GIVE UP RESOURCE
	JRST	SETSTT		;AND MAKE HIM WAIT FOR SCHED.
>
SRAVL1:	MOVEM	17,USRTAB-MQ(16);REMEMBER IT SO RESOURCE CAN BE GIVEN
				; UP IN THE EVENT OF A CATASTROPIC ERROR
	MOVE	17,JOBD17(R)	;RESTORE AC17
	MOVE	16,JOBD16(R)	;AND AC16
	POPJ	P,		;RETURN TO THE CALLER WITH THE
				; REQUESTED RESOURCE
PJBS1:	POINT	JWSIZ,JBTSTS(P3),JWPOS	;BYTE POINTER TO JOB STATUS
				; WORD WAIT QUEUE CODE
PJBS3:	POINT	JWSIZ,JBTSTS(17),JWPOS

;SUBROUTINE TO RETURN A SHARABLE RESOURCE AND FLAG IT
; AS AVAILABLE IF ANY JOBS ARE WAITING FOR IT.  IF
; JOBS ARE WAITING, THE SCHEDULAR WILL GIVE THE RESOURCE
; TO THE HIGHEST PRIORITY JOB.
;CALL:	PUSHJ	P,XXFREE
;	RETURN HERE - ALL ACS PRESERVED

	EXTERNAL REQTAB,AVALTB,USRTAB
	INTERNAL DVFREE
DEFINE X(A,B,C)<
A'FREE:	PUSHJ	P,SRFREE
INTERNAL A'FREE
>
DVFREE:	RWAITS
SRFREE:	EXCH	T1,(P)		;GET ENTRY ADDRESS AND SAVE T1
	SUBI	T1,DVFREE+1	;CALCULATE WAIT STATE INDEX
	HRRZS	T1		;CLEAR ANY PC BITS
	SOSL	REQTAB(T1)	;DECREMENT REQUEST COUNT.  ANY JOBS WAITING?
	SETOM	AVALTB(T1)	;YES, FLAG IT AS AVAILABE SO THS SCHEDULAR WILL
				; GIVE THE RESOURCE TO A WAITER
	HRLZS	USRTAB(T1)	;XWD LAST USER, 0 (NO CURRENT USER)
IFN FTDISK,<
	SKIPE	DINITF##	;NO UNWINDING DURING ONCE-ONLY
	JRST	TPOPJ##
>
	PUSH	P,J		;SAVE J
	HLRZ	J,USRTAB(T1)	;GET OWNER OF RESOURCE
IFN FTDISK,<
	CAIN	T1,MQWAIT-DVWAIT ;IF MQ RESOURCE
	LDB	J,PJOBN		; GET J FOR DDB (USRTAB ISN'T RIGHT)
>
	MOVEI	T1,JS.OOO	;WAS HE RUN OUT OF ORDER?
	TDNN	T1,JBTST2##(J)	;...
	JRST	SRFRE5		;NO. DON'T FIDDLE
	PUSH	P,T3		;SAVE T3
	PUSH	P,P1		;AND P1
	SETZB	T1,P1		;SET UP FOR NXTJBB, AND SCAN
SRFRE1:	CAMN	J,USRTAB(T1)	;DOES JOB OWN ANY OTHER RESOURCES?
	JRST	SRFRE4		;YES
	CAIGE	T1,AVLNUM##
	AOJA	T1,SRFRE1
SRFRE2:	PUSHJ	P,NXTJBB##	;DOES IT OWN A MON-BUF?
	  JRST	SRFRE3		;NO
	CAME	T3,J
	JRST	SRFRE2
	JRST	SRFRE4		;YES
;HERE IF JOB OWNS NO OTHER RESOURCES - FLAG FOR FORCED RESCHEDULE
SRFRE3:	CONO	PI,PI.OFF	;NO PI'S
	SKIPN	.C0RTF##	;FORCED RESCHEDULE IN PROGRESS?
	SETOM	.C0RTF		;NO PUT ONE IN
	CONO	PI,PI.ON	;ALLOW PI'S
	MOVEI	T1,JS.OOO	;CLEAR OUT OF ORDER BIT
	ANDCAM	T1,JBTST2##(J)
SRFRE4:	POP	P,P1		;RESTORE ACS
	POP	P,T3
SRFRE5:	MOVEI	T1,JS.DEP!JDC	;JOB GAVE BACK RESOURCE
	TDNE	T1,JBTSTS##(J)	;WAS HE WAITING TO GO INTO DAEMON 0?
	PUSHJ	P,REQUE		;YES-SEE THAT HE GETS THERE NOW
				; IF HE HAS MORE RESOURCES AT THE MOMENT,
				; THE SCHEDULER WILL DEFER THE REQUEUE AGAIN AND EVENTUALLY
	POP	P,J		;RESTORE J
				; GET BACK HERE.
IFN FTKA10,<
	JRST	TPOPJ		;RESTORE T1 AND RETURN
>
IFN FTKI10!FTKL10,<
	POP	P,T1		;RESTORE T1
	PJRST	RTEVM##		;AND GIVE UP EVM IF ANY
>

IFN FTDISK,<

CFLSDR:	PUSH	P,J		;SAVE J
	PUSH	P,T3		;SAVE T3
	MOVE	J,17		;SET UP J FOR FLSDR
	PUSHJ	P,FLSDR##	;DOES HE HAVE ANY DISK RESOURCE?
	AOS	-2(P)		;
	POP	P,T3		;RESTORE T3
	JRST	JPOPJ##		;RESTORE J AND RETURN
>;END IFN FTDISK
;SUBROUTINE TO SET JLOG AND COUNT UP LOGNUM
;CALL WITH:
;	MOVE	J,JOB#
;	PUSHJ	P,SETLOG
;USES T1,T2
SETLOG::MOVSI	T1,JLOG		;THE BIT OF INTEREST
	TDNE	T1,JBTSTS##(J)	;IS IT SET?
	POPJ	P,		;YES--ALL DONE
	IORM	T1,JBTSTS##(J)	;NO--SET IT
	MOVEI	T1,1		;INDICATE SETTING
	PJRST	CLRLG1		;FIX LOGNUM & BATNUM

;SUBROUTINE TO CLEAR JLOG AND DECREMENT LOGNUM
;CALL WITH:
;	MOVE	J,JOB#
;	PUSHJ	P,CLRLOG
;USES T1,T2
CLRLOG::MOVSI	T1,JLOG		;THE BIT OF INTEREST
	TDNN	T1,JBTSTS##(J)	;IS IT SET?
	POPJ	P,		;NO--ALL DONE
	ANDCAM	T1,JBTSTS##(J)	;YES--CLEAR IT
	SETOM	T1
;HERE FROM SETLOG
CLRLG1:	ADDM	T1,LOGNUM##	;DECREMENT LOGNUM
IFN FTTLIM,<
	MOVSI	T2,(JB.LBT)	;IS THIS A BATCH JOB?
	TDNE	T2,JBTLIM##(J)	;--
	ADDM	T1,BATNUM##	;YES--ADJUST LOGNUM
>
	POPJ	P,		;RETURN
;ROUTINE TO SET JOB TO RUN AFTER IT HAS BEEN STOPPED
;BECAUSE IT HAD TO WAIT FOR IO TO COMPLETE FOR SOME DEVICE
;EACH SERVICE ROUTINE AT INTERRUPT LEVEL
;CHECK EACH TIME IT FINISHED A TASK(BUFFERFUL)
;TO SEE IF THE JOB USING THE DEVICE HAS
;PREVIOUSLY CAUGHT UP WITH DEVICE AND HAS BEEN STOPPED
;CALL:	MOVE F,ADR. OF DEVICE DATA BLOCK
;	MOVE S,DEVIOS(F)	;GET DEVICE IO STATUS WORD FROM DDB
;	PUSHJ P,SETIOD	;YES, GO FLAG JOB TO START UP AGAIN
;	RETURN
;SETS THE JOB QUEUE WAIT CODE TO WSQ IN JOB STATUS WORD.
;THE SCHEDULER THEN SEES THAT THIS JOB HAS ITS
;IO WAIT SATISFIED AND IS WAITING TO BE RUN AGAIN

INTERNAL SETIOD,STTIOD
EXTERNAL WSQ,TSQ,JOB,PJOBN
IFN FTDISK,<EXTERN DSQ
INTERN	STDIOD>

PJBS2:	POINT	JWSIZ,JBTSTS(T1),JWPOS	;BYTE POINTER TO JOB STATUS
				; WORD QUEUE CODE

IFN FTVM,<
STPIOD::MOVEI	T2,PSQ##	;REQUE TO PAGING I/O WAIT SATISFIED
	JRST	SETID2
>
STTIOD:	LDB	T1,PJOBN	;JOB NUMBER
IFN	FTRSP,<EXTERN JBTRSP
	MOVE	T2,.C0UPT	;TIME SYSTEM HAS BEEN UP IN JIFFIES
	TLNN	S,IO		;IS USER DOING INPUT?
	MOVEM	T2,JBTRSP(T1)	;YES, STORE TIME USER BEGAN TO WAIT FOR RESPONSE
>
IFN FTHPQ,<
	LDB	T2,HPQPT1##	;GET HPQ NUMBER OF JOB IN T1
	JUMPE	T2,STTID2	;IF ZERO, NOTHING TO WORRY ABOUT
	PUSH	P,T3		;SAVE T3
	MOVSI	T3,SWP		;GET BIT TO TEST FOR
	CONO	PI,PIOFF##	;TURN OFF PI'S
	TDNN	T3,JBTSTS##(T1)	;HPQ JOB SWAPPED OUT, COMMING OUT OF
				;TI WAIT?
	JRST	STTID1		;NOT SWAPPED OUT, TURN ON PIS AND CONTINUE
	SKIPG	T3,.C0RTF##	;ANY REALTIME RESCHEDULE BEING DONE?
	JRST	STTID0		;NO, FLAG THAT THERES AN HPQ JOB ON DSK
	LDB	T3,HPQPN3##	;YES, GET OTHER JOB'S HPQ NUMBER
	CAMG	T2,T3		;IS HE GREATER THAN OURS?
	JRST	STTID1		;YES, DON'T DO ANYTHING.
STTID0:	MOVEM	T1,.C0RTF##	;YES, USE OUR JOB NUMBER
	SETOM	.C0CKF##	;FLAG THAT WE'RE DOING CH7 INTERRUPT
	CONO	PI,PICLK##	;CAUSE INTERRUPT TO HAPPEN
	POP	P,T3
	JRST	STTID2		;CONTINUE

STTID1:	CONO	PI,PION##	;TURN PI'S BACK ON
	POP	P,T3		;RESTORE T3

STTID2:>;END OF IFN FTHPQ
	MOVEI	T2,TSQ		;SET TTY IO WAIT SATISFIED QUEUE CODE
IFE FTSWAP,<
	AOS	TSAVAL##
>
	JRST	SETID1

SETIOD:	MOVEI	T2,WSQ		;REQUE TO WAIT SATISFIED Q
IFE FTSWAP,<
	AOS	WSAVAL##	;INCR. NO. OF JOBS WITH IO WAIT
				; SATISFIED. NON-ZERO WSAVAL WILL
				; CAUSE SCHED. TO SCAN FOR IO
				; SATISFIED JOB.

>
IFN FTDISK,<
	JRST	SETID0

STDIOD:	MOVEI	T2,DSQ		;SET DISK IO WAIT STATISFIED QUEUE
IFE FTSWAP,<
	AOS	DSAVAL##
>
>	;END CONDITIONAL ON FTDISK


SETID0:
IFN FTHPQ,<
	LDB	T1,PJOBN##	;GET JOB NUMBER OF DDB IN F
	LDB	T1,HPQPT1##	;GET HIS HPQ NUMBER
	JUMPE	T1,SETID1	;HE'S NOT IN AN HPQ
	CONO	PI,PIOFF##	;TURN OFF PI'S
	SKIPN	.C0RTF##	;ANY REAL TIME RESCHEDULE TO DO?
	SETOM	.C0RTF##	;NO, FLAG UUOCON AND SCHED1 THAT THERE IS
				;AN HPQ JOB TO SCHEDULE
	SETOM	.C0CKF##	;DOING A CH7 INTERRUPT
	CONO	PI,PICLK##
>;END IFN FTHPQ

SETID1:	LDB	T1,PJOBN	;GET QUEUE CODE
IFN FTPI,<
	TLNN	S,IOSTBL	;IS OFF-LINE, CATCH IT AT UUO LEVEL
	PUSHJ	P,PSIIOD##	;CALL PSISER TO CHECK FOR TRAPS
>
IFE FTMSGSER,<
	TLZN	S,IOW		;IN I/O WAIT?
>
IFN FTMSGSER,<
	TLZE	S,IOW		;IN I/O WAIT?
	JRST	SETID2		;YES
	PUSHJ	P,MPXIOD##	;MAYBE - ASK MSGSER
>
	JRST	SETID3		;NO, SEE IF HIBERNATING ON I/O ACTIVITY
SETID2:	DPB	T2,PJBS2	;IN JOB STATUS WORD

INTERNAL FTSWAP
IFN FTSWAP,<
	PUSH	P,J		;SAVE J
	MOVE	J,T1		;GET JOB NUMBER
	PUSHJ	P,REQUE		;REQUE THIS JOB
	POP	P,J		;RESTORE J
>
NJBTST::SKIPE	.C0JOB		;IS NULL JOB RUNNING?
	POPJ	P,		;NO LET OTHER JOB RUN TILL SCHEDULER IS TRAPPPED TO
	PJRST	STOP2##		;YES, CAUSE RESCHEDULE
SETID3:
IFN FTHIBWAK,<
	MOVSI	T2,IOACE##	;JOB ENABLED FOR WAKEUP ON I/O ACTIVITY?
	TDNE	T2,JBTRTD##(T1)
	PJRST	WAKJOB##	;YES, WAKE THE JOB
>
	POPJ	P,		;NO, RETURN
;ROUTINE TO WAIT TILL DEVICE CATCHES UP WITH USER AND BECOMES INACTIVE
;CALLING SEQUENCE
;     PUSHJ P, WAIT1
;     EXIT	  ALWAYS RETURNS HERE
	
;IF THE DEVICE IS INACTIVE (IOACT=0), RETURNS TO EXIT. OTHERWISE, SETS
;IOW:=1 AND ENTERS WAIT UNLESS IOACT BECOMES ZERO BEFORE THE
;JUMP IS MADE, IN WHICH CASE IT SETS IOW:=0 AND RETURNS TO EXIT.
;ON LEAVING THE WAIT STATE, RETURNS TO EXIT.
;THIS ROUTINE PREVENTS THE STATE IOACT=0 AND IOW=1 FROM OCCURING
;CALLING SEQUENCE
;     PUSHJ P, WSYNC
;     EXIT             ALWAYS RETURNS HERE
;SETS IOW:=1 AND ENTERS WAIT ROUTINE. RETURNS TO EXIT WHEN IOACT=0.

INTERNAL WAIT1

WAIT1:	MOVE	S,DEVIOS(F)
	TRNN	S, IOACT	;IS DEVICE ACTIVE? (IOACT=1?)
	POPJ	P,		;RETURN
	PUSHJ	P,WSYNC		;WAIT
	JRST	WAIT1
;WSYNC IS CALLED TO WAIT UNTIL SETIOD IS CALLED BY INTERRUPT SERVICE ROUTINE
;IE  UNTIL CURRENT BUFFER ACTIVITY IS COMPLETED
;CALLED ONLY FROM UUO LEVEL
;CALL:	MOVE F,ADR. OF DEVICE DATA BLOCK
;	PUSHJ P,WSYNC
;	RETURN IMMEDIATELY IF DEVICE IS INACTIVE
;	RETURN WHEN DEVICE FINISHES NEXT BUFFER IF IT IS ACTIVE


INTERNAL WSYNC
EXTERNAL IOWQ,TIOWQ,PION,PIOFF
IFN FTDISK,<EXTERN DIOWQ>

WSYNC:	PUSHJ	P,SAVE3##	;SAVE P1-P3
IFN FTHALT,<
	TRNN	F,777700	;IS RHDEVDAT LESS THAN 100?
	STOPCD	CPOPJ,DEBUG,NDP, ;++NOT DDB POINTER
>
	MOVSI	S,IOW		;SETUP DEVICE IO WAIT BIT
	MOVEI	P1,IOWQ		;IO WAIT STATE CODE
	MOVE	P3,DEVMOD(F)	;DEVICE CHARACTERISTICS
	TLNE	P3,DVTTY	;IS THIS DEVICE A TTY?
	MOVEI	P1,TIOWQ	;YES, SET TTY WAIT STATE CODE

IFN FTDISK,<
IFN FTSPL,<
	SKIPL	DEVSPL(F)	;ITS ALWAYS A DSK IF SPOOLED
>
	TLNE	P3,DVDSK	;IS THIS DEVICE A DISK?
	MOVEI	P1,DIOWQ	;YES, SET DISK WAIT STATE CODE
>

	MOVE	P3,.C0JOB	;CURRENT JOB NO.
	MOVEI	P2,IOACT	;DEVICE ACTIVE BIT
	CONO	PI, PIOFF	;TURN PI OFF
	TDNN	P2,DEVIOS(F)	;IS THE DEVICE ACTIVE?
	JRST	WSYNC1		;NO
	IORM	S,DEVIOS(F)	;YES, SET DEVICE IO-WAIT BIT
				; AND SETUP S FOR RETURN WHEN WAIT SATISFIED
	DPB	P1,PJBS1	;SET JOB WAIT STATE CODE
				; IN JOB STATUS WORD
	CONO	PI, PION	;TURN PI ON
IFN FTWATCH,<HRLM F,JBTPC##(P3)>
	PUSHJ	P,WSCHED	;CALL SCHEDULER TO FIND ANOTHER JOB TO RUN
				; RETURN WHEN NEXT BUFFERFUL IS FINISHED
				; WITH ACS 0-14 OCTAL RESTORED
				; RETURN WHEN IO-WAIT FINISHED
IFN FTWATCH,<HRRZS JBTPC(P3)>
WSYNC1:	CONO	PI, PION
	ANDCAB	S, DEVIOS(F)	;CLEAR DEVICE IO-WAIT BIT
WSYNC2:	POPJ	P,		;HALT HERE IF F LESS THAN 100
	$LIT

CLKEND:	END