Google
 

Trailing-Edge - PDP-10 Archives - bb-jr93d-bb - 7,6/ap017/clock1.x17
There is 1 other file named clock1.x17 in the archive. Click here to see a list.
TITLE	CLOCK1 - CLOCK, CONTEXT SWITCHING, AND JOB STARTUP AND STOP ROUTINES - V1426
SUBTTL APRINT TH/CHW/RCC/PFC/JE/DAL/EVS/JBS 30 JUL 86
	SEARCH	F,S
	$RELOC
	$HIGH

;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED
;  OR COPIED IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
.CPYRT<1973,1986>
;COPYRIGHT (C) 1973,1974,1975,1976,1977,1978,1979,1980,1982,1984,1986
;BY DIGITAL EQUIPMENT CORP., MAYNARD, MASS.
;ALL RIGHTS RESERVED.



;
XP VCLOCK1,1426
		; 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







	$LOW
DAMESS::ASCIZ	/-Jan-/
CLOCK::	POINT	36,CIPWTM##,35	;BYTE POINTER TO CLOCK REQ QUEUE
	$HIGH


;FORMAT OF THE CLOCK QUEUE IS
;WORD 0:  ADDRESS TO DISPATCH TO WHEN COUNT GOES TO ZERO,,COUNT
;WORD 1:  <CPU THAT CLOCK REQUEST SHOULD BE PROCESSED ON>B2,,DATA
; WHERE DATA IS A HALF WORD PRESENTED TO THE ROUTINE
; DISPATCHED TO WHEN COUNT GOES TO ZERO
;SUBROUTINE TO SERVICE COMMON APR INTERRUPTS (PARITY, NXM, AND CLOCK)
;CALL:	PUSHJ P,APRSUB
;	ALWAYS RETURN HERE
;
;FATAL AND CPU DEPENDENT ERRORS ARE FILTERED OUT BEFORE CALLING APRSUB

APRSUB::
IFN FTKL10,<
	CONSO	@.CPNXM##	;NON-EXISTENT MEMORY
	CONSZ	@.CPMPE##	; OR MEMORY PARITY ERROR?
	JRST	APRPAR		;YES--GO PROCESS IT
>
	XCT	.CPHCT##	;IS THIS AN APR CLOCK TICK?
	JRST	APRERR		;NO--GO CHECK OTHER APR CONDITIONS
	SOS	.CPHTM##	;YES--DECREMENT HNGTIM FOR THIS CPU
	PUSH	P,T1		;SAVE AN AC
IFN FTMP,<
	SKIPL	INTDIE##	;ANY CPU PROCESSING A STOPCD?
	PUSHJ	P,CHKDIE##	;YES, WAIT FOR IT TO FINISH
	SKIPE	.CPNBI##	;ANYBODY BREAK MY INTERLOCKS?
	STOPCD	.,CPU,CIB,	;++CPU INTERLOCKS BROKEN
	SKPCPU	(0)		;IS THIS THE POLICY CPU? (CPU0)
	JRST	APRSU1		;NO--DO NOT DO TIME ACCOUNTING FOR SYSTEM AS WHOLE
	MOVE	T1,NCPRUN##	;GET THE NUMBER OF RUNNING CPUS
	MOVE	T1,COKTAB##-1(T1) ; -(RUNNING CPUS-1)*JIFSEC GOES IN
	MOVEM	T1,.CPOK##	; THE POLICY CPU'S OK WORD
	MOVEI	T1,.C0CDB##	;FIRST CPU'S CDB
APRSU0:	AOSN	.CPOK##-.CPCDB##(T1) ;COUNT EVERYONE ELSE'S KEEP ALIVE
	PUSHJ	P,BRKLOK##	;CPU IS DOWN, BREAK ANY INTERLOCKS IT MAY OWN
	HLRZ	T1,.CPCDB##-.CPCDB##(T1) ;NEXT CDB
	JUMPN	T1,APRSU0	;LOOP IF MORE
>
	AOS	TIME##		;INCREMENT TIME OF DAY FOR SYSTEM
	AOS	SYSUPT##	; AND SYSTEM UPTIME
	JRST 	APRSU2
APRSU1:	MOVN	T1,TICSEC##	;-TICS/SECOND
	MOVEM	T1,.CPOK##	;NUMBER OF COUNTS UNTIL WE ARE DEAD
APRSU2:	AOS	.CPUPT##	;INCREMENT THIS CPU'S UPTIME
	AOSN	.CPTMF##	;SET FLAG THAT APR CLOCK HAS TICKED
	AOS	.CPTMF##	;I SAID SET IT (KAF BEFORE WRAPAROUND ANYWAY)
	SETOM	.CPCKF##	;SET FLAG FOR CLK FORCED SCHEDULER INTERRUPT
	CONO	PI,XI.RQC##	;REQUEST INTERRUPT ON CLK (SCHEDULER) CHANNEL
IFN FTKL10&FTRSP,<
	AOSN	.CPBPF##	;WHEN BACKGROUND PERF ANAL COUNT HITS 0
	PUSHJ	P,BPAUPD##	;UPDATE PERFORMANCE ANALYSIS COUNTS
>
IFN FTMP,<
	AOSN	@.CPOK1##	;CHECK IF BOOT PROCESSOR IS ALIVE
	PUSHJ	P,BECOM0##	;BOOT CPU DIED, ASSUME ITS ROLE
>
	XCT	.CPCCF##	;CLEAR CLOCK FLAG
	MOVEI	T1,XP.CLK	;USER ENABLED FOR CLOCK INT BIT
	TDNN	T1,.CPCN1##	;IS HE ENABLED?
	JRST	TPOPJ##		;NO--DISMISS INTERRUPT
	POP	P,T1		;RESTORE T1
	PUSHJ	P,SAVT##	;AND THEN SAVE ALL T REGS
	PUSHJ	P,APRPTS	;GET THE REAL PC
	TLNN	T1,(XC.USR)	;IS PC FROM USER MODE ?
	POPJ	P,		;NO--DISMISS INTERRUPT
	MOVEM	T3,.CPPIP##	;YES--SAVE POINTER TO INTERRUPT PC
	MOVEI	T4,XP.CLK	;CLOCK BIT
	IORM	T4,.JDAT+.JBCNI## ;STORE STATUS FOR USER
	PUSHJ	P,SAVJW##	;SAVE J (W COMES ALONG FOR THE RIDE)
	MOVE	J,.CPJOB##	;SET UP J WITH CURRENTLY RUNNING JOB
	JRST	APRUTP		;GO TRAP TO HIM
;HERE TO HANDLE MEMORY PARITY OR NXM INTERRUPT
IFN FTKL10,<
APRPAR:	PUSHJ	P,SAVT##	;SAVE T REGS
	PUSHJ	P,SAVJW##	;SAVE J (W COMES ALONG FOR THE RIDE)
	PUSHJ	P,CPUSTS##	;READ CPU STATUS
	PUSHJ	P,DVCSTS##	;AND DEVICE STATUS
	CONI	APR,.CPPEF##	;SAVE THE APR STATUS
	CONI	PI,.CPPPI##	;SAVE THE PI STATE
	RDERA	.CPAER##	;SAVE THE ERA ON KL10
	PUSHJ	P,REDSBC##	;READ AND CLEAR MEMORY CONTROLLERS
	MOVEI	T4,UE.PEF	;ASSUME PARITY ERROR
	CONSZ	@.CPNXM##	;IS THIS A NXM INTERRUPT?
	MOVEI	T4,UE.NXM	;YES--NXM (AND TAKES PRECEDENCE OVER PARITY)
	CONO	APR,@.CPIEF##	;NOW CLEAR THE APR
	PUSHJ	P,APRPTS	;GET REAL PC
	DMOVEM	T1,.CPAPC##	;SAVE IN CDB
	DMOVEM	T1,.CPMDP##	; AND HERE FOR ERROR REPORTING
	IOR	T1,T2		;PHONEY IT UP FOR ERROR REPORTING
	MOVEM	T1,.CPMPP##	;FOR DAEMON
	MOVEM	T3,.CPPIP##	;SAVE POINTER TO INTERRUPT PC
	TRNN	T4,UE.PEF	;IS THIS A PARITY INTERRUPT?
	JRST	APRPA1		;NO--JUST GO ON
	SKIPE	.CPCHE##	;CHANNEL ERROR REPORT IN PROGRESS?
	POPJ	P,		;YES--JUST IGNORE IT THEN, IT'S EXPECTED
APRPA1:	SKIPE	.CPPSP##	;IS A PI 7 MEMORY SCAN IN PROGRESS?
	POPJ	P,		;YES--IGNORE THIS INTERRUPT, TRAP WILL HANDLE
	MOVSI	T1,(EA.CHN)	;NO--CHANNEL REFERENCE BIT IN ERA
	TDNN	T1,.CPAER##	;IS FAILURE FROM A CHANNEL DOING SOMETHING?
	JRST	APRPA2		;NO--GO PRINT INTERRUPT MESSAGE
	MOVE	T1,.CPLCI##	;YES--GET TIME OF LAST CHANNEL INTERRUPT
	ADDI	T1,5*JIFSEC##	;ADD FIVE SECONDS
	MOVE	T2,TIME##	;GET JIFFY CLOCK
	CAMLE	T1,T2		;HAS IT BEEN FIVE SECONDS SINCE LAST?
	POPJ	P,		;NO--DON'T FLOOD CTY ON RETRIES TO SAME PLACES
	MOVEM	T2,.CPLCI##	;YES--UPDATE "LAST" CHAN INT TIME
APRPA2:	PUSHJ	P,SVPPC##	;SWITCH TO SECONDARY PROTOCOL
	MOVEI	T1,.ERKLP	;GET CODE FOR DAEMON
	HRL	T1,.CPSLF##	;GET ADDRESS OF OUR CPU DATA BLOCK
	PUSHJ	P,DAEEIM	;POKE DAEMON TO LOG THIS
	PUSHJ	P,RCDSTD##	;ALSO LOG CPU AND DEVICE STATUS BLOCKS
	MOVE	J,.CPJOB##	;SET UP J WITH CURRENTLY RUNNING JOB
	DIELOK			;GRAB THE DIE INTERLOCK
	PUSH	P,.CPTOA##	;SAVE TYPEOUT ROUTINE ADDRESS
	MOVEI	T3,CTYWAT##	;REPLACE WITH ONE THAT DOESN'T
	MOVEM	T3,.CPTOA##	; USE PI SYSTEM
	MOVEI	T1,SDELIM##	;GET ADDRESS OF TEXT
	PUSHJ	P,CONMES##	;PRINT START DELIMITER
	MOVE	T2,.CPLOG##	;GET THIS CPU'S NAME
	PUSHJ	P,PRNAME##	;PRINT IT
	TRNN	T4,UE.NXM	;SELECT PROPER MESSAGE
	SKIPA	T1,[[ASCIZ / parity error interrupt/]]
	MOVEI	T1,[ASCIZ / non-existent memory interrupt/]
	PUSHJ	P,CONMES##	;PRINT IT
	DMOVE	T1,.CPAPC##	;GET THE INTERRUPT PC
	PUSHJ	P,DPCP##	;PRINT IT
	MOVEI	T1,[ASCIZ/ on /]
	PUSHJ	P,CONMES##	;PRINT "ON"
	PUSHJ	P,DAYTIM##	;FINISH LINE WITH DATE/TIME
	MOVEI	T1,[ASCIZ /CONI APR, = /]
	PUSHJ	P,CONMES##	;PRINT "CONI APR, ="
	MOVE	T1,.CPPEF##	;GET THE CONI APR DATA
	PUSHJ	P,HWDPNT##	; AND PRINT IT
	PUSHJ	P,CRLF##	;END WITH CRLF
	MOVEI	T1,[ASCIZ /CONI PI, = /]
	PUSHJ	P,CONMES##	;PRINT "CONI PI, ="
	MOVE	T1,.CPPPI##	;GET THE CONI PI DATA
	PUSHJ	P,HWDPNT##	; AND PRINT IT
	PUSHJ	P,CRLF##	;END WITH CRLF
;	JRST	APPKLE		;GO EXAMINE THE ERA FOR FURTHER INFO
;HERE TO EXAMINE THE ERA FOR FURTHER DECISIONS
APPKLE:	MOVEI	T1,[ASCIZ /ERA = /]
	PUSHJ	P,CONMES##	;PRINT "ERA ="
	MOVE	T1,.CPAER##	;GET THE ERA DATA
	PUSHJ	P,HWDPNT##	; AND PRINT IT
	PUSHJ	P,CRLF##	;END WITH CRLF
	MOVEI	T1,[ASCIZ /Error invoked by a /]
	PUSHJ	P,CONMES##	;PRINT DIAGNOSIS PREAMBLE
	MOVE	T3,.CPAER##	;GET THE ERA CONTENTS
	TLNN	T3,(EA.SWP)	;WAS A CACHE SWEEP THE CULPRIT?
	 JRST	APPKL1		;NO--PRESS ON
	MOVEI	T1,[ASCIZ /cache write-back forced by a sweep instruction.
/]
	JRST	APPKL3		;YES--GO PRINT REASON AND DISMISS
APPKL1:	TLNN	T3,(EA.CHN)	;WAS A CHANNEL INVOLVED?
	 JRST	APPKL4		;NO--MUST BE CPU
	TLNN	T3,(EA.WRT)	;YES--IS IT A WRITE OPERATION?
	 JRST	APPKL2		;NO--CONTINUE
	TLNN	T3,(EA.SRC)	;YES--GET PROPER MESSAGE
	SKIPA	T1,[[ASCIZ /channel status word write.
/]]
	MOVEI	T1,[ASCIZ /channel data word write.
/]
	JRST	APPKL3		;GO PRINT MESSAGE AND DISMISS
APPKL2:	TLNN	T3,(EA.SRC)	;GET PROPER MESSAGE
	SKIPA	T1,[[ASCIZ /channel read from memory.
/]]
	MOVEI	T1,[ASCIZ /channel read from cache.
/]
APPKL3:	PUSHJ	P,PRTSBD	;PRINT SBUS DIAG INFO AND END MESSAGE
	POP	P,.CPTOA##	;RESTORE TYPEOUT ADDRESS
	DIENLK			;GIVE BACK THE DIE LOCK
	POPJ	P,		;NOW JUST DISMISS INTERRUPT
APPKL4:	TLNN	T3,(EA.WRT)	;IS IT A WRITE OF SOME SORT?
	 JRST	APPKL6		;NO--CONTINUE
	TLNN	T3,(EA.SRC)	;YES--GET PROPER MESSAGE
	SKIPA	T1,[[ASCIZ /CPU write to memory (not cache).
/]]
	MOVEI	T1,[ASCIZ /cache write-back forced by a CPU write.
/]
	JRST	APPKL7		;GO PRINT MESSAGE
APPKL6:	TLNN	T3,(EA.SRC)	;GET PROPER MESSAGE
	SKIPA	T1,[[ASCIZ /CPU read or page refill from memory.
/]]
	MOVEI	T1,[ASCIZ /page refill from cache.
/]
APPKL7:	TRNE	T4,UE.NXM	;IS THIS A NXM?
	JRST	APPK10		;YES--WANT TO CONTINUE AT INTERRUPT LEVEL
	TLNE	T3,(EA.DAT!EA.SRC!EA.WRT) ;NO--PARITY, IS THIS A READ FROM MEMORY?
	JRST	APPKL3		;NO--THEN JUST PRINT MESSAGES AND DISMISS
	HLLZ	T2,.CPMPS##	;GET CPU REQUESTS SCAN BITS
	TRO	T2,(T4)		;SCAN FOR PARITY ERRORS
	IORM	T2,.CPAEF##	;SET BITS TO FORCE SCAN AT NEXT CLK RESCHEDULE
	LDB	T2,[POINT 5,.USPFW,5] ;PF CODE
	CAIL	T2,PF.ARP	;HAS A PF TRAP OCCURED?
	JRST	APPKL3		;YES, LET TRAP ROUTINE HANDLE IT
	MOVEI	T2,JS.MPE	;STOP THE CURRENT JOB
	IORM	T2,JBTSTS##(J)	; TO PREVENT A POSSIBLE LOOP
	PUSHJ	P,PRTSBD	;FINISH MESSAGE AND PRINT SBUS DIAGS
	POP	P,.CPTOA##	;RESTORE TYPE OUT ADDRESS
	JRST	APRUTZ		;STOP USER AND SCAN
APPK10:	PUSHJ	P,PRTSBD	;PRINT SBUS DIAG INFO AND END MESSAGE
	DMOVE	T1,.CPAPC##	;GET INTERRUPT PC
	TLNN	T1,(XC.USR)	;PC IN USER MODE?
	JRST	APPMON		;NO--GO DO MONITOR CHECKS
	POP	P,.CPTOA##	;YES--RESTORE TYPEOUT ADDRESS
	JRST	APPUSR		;GO DO USER CHECKS
;HERE ON EXEC PARITY IN NO SPECIAL PLACE - CHECK FOR SAME AS LAST INTERRUPT
; ANNOUNCE OUR INTENTION TO SWEEP SINCE IT TAKES A LONG TIME SO THE OPR WON'T
; GET EXCITED
APPMON:	PUSHJ	P,APASWP	;ANNOUNCE INTENTION TO DO A SWEEP, DO IT
				; AT INTERRUPT LEVEL SO IT WILL BE GUARANTEED
				; TO COME OUT QUICKLY SO THE OPR DOESN'T GET EXCITED
	MOVE	T1,.CPAPC##+1	;AND THE NXM PC
	SKIPN	.CPISF##	;IF IN THE SCHEDULER, OR
	CAMN	T1,.CPLPP##	; 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
	CONSZ	PI,@.CPNAP##	;ARE ANY PI'S (BELOW APR) IN PROGRESS?
	JRST	APPSWP		;YES--SWEEP AT APR PI LEVEL
	POP	P,.CPTOA##	;NO--RESTORE TYPEOUT ADDRESS
	JRST	APPUPE		;GO REQUEST PI 7 SWEEP OF CORE AND
				; 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 OR NXM
APPSWP:	MOVEM	17,.CPA17##	;SAVE AC 17
	MOVEI	17,.CPA00##	;FIRST ADR. OF PARITY SWEEP SAVE AC AREA
	BLT	17,.CPA17##-1	;SAVE ALL ACS IN CDB BLOCK
	MOVE	17,.CPA17##	;RESTORE AC 17
	HLLZ	S,.CPMPS##	;REQUEST CPU SWEEP
	TRO	S,(T4)		;FLAG WHETHER NXM OR PARITY SWEEP
	PUSHJ	P,ANNSWP	;ANNOUNCE SWEEP
	PUSHJ	P,PARSWP##	;CALL MEMORY SCAN ROUTINE
	TLZ	S,(CP.PSX)	;CLEAR REQUEST TO SWEEP BIT
	IORM	S,.CPAEF##	;SET PRINT ONLY REQUEST
	SKIPGE	.CPMPC##	;ANY SERIOUS ERRORS?
	PJRST	PARHLT##	;YES--PRINT MESSAGE AND HALT CPU
	MOVSI	17,.CPA00##	;RESTORE ALL ACS FROM CPU DATA BLOCK
	BLT	17,17		;...
	POP	P,.CPTOA##	;RESTORE TYPEOUT ADDRESS
;	TLZ	T4,UE.NXM	;DON'T GIVE UP THE INTERLOCK AGAIN
	JRST	APRSTU		;GO RESCHEDULE
;HERE ON PARITY ERROR WHEN PC REALLY IN USER MODE - T1 HAS REAL PC
APPUSR:	MOVE	T3,.CPCN1##	;USER ENABLED APR AND PI TRAPS
	TRNN	T3,(T4)		;ENABLED FOR NXM OR PARITY ERROR?
	JRST	APPUPE		;NO--STOP JOB AND REQUEST MEMORY SCAN
	MOVE	T3,JBTSTS##(J)	;YES, JOB STATUS WORD
	TLNE	T3,JACCT	;IS JOB PRIVILEGED?
	JRST	APPPET		;YES, ALLOW PARITY ERROR TRAP
	MOVE	T3,JBTPPN##(J)	;JOB PROJECT-PROGRAMMER NO.
	CAME	T3,FFAPPN##	;IS IT THE OPERATOR PROJ-PROG
	CAMN	T3,UMDPPN##	; OR THE USER MODE DIAGNOSTIC PPN?
	JRST	APPPET		;YES--ALLOW THE TRAP
	JRST	APPUPE		;NO--STOP JOB AND REQUEST MEMORY SCAN

;HERE TO TRAP TO PRIVILEGED, ENABLED USER - (J SET TO JOB NO, T1 TO REAL PC)
APPPET:	IORM	T4,.JDAT+.JBCNI## ;STORE PARITY/NXM FLAG FOR USER
	TRNN	T4,UE.PEF	;A PARITY ERROR?
	AOSA	.CPUEN##	;NO, NXM BUMP COUNT OF USER ENABLED NXM'S
	AOS	.CPUEP##	;INCREMENT COUNT OF USER ENABLED PAR ERRORS
				; ON THIS CPU
				; TO LOOK AT IN HIS INTERRUPT ROUTINE
	;JRST	APRUTP		;HANDLE TRAPS TO USER
>; END IFN FTKL10
;HERE TO SET UP THE TRAP TO THE USER
;HERE WITH T1=ERROR PC, T4=APRENB BITS
APRUTP:	HRR	T1,T2		;ADDRESS TO T1 (SINCE USER, MUST BE IN SECTION 0)
	MOVEM	T1,.JDAT+.JBTPC## ;STORE ERROR PC
	HRRZ	T3,.JDAT+.JBAPR## ;GET USER TRAP ADDRESS
	CAIN	T3,(T1)		;IS INT FROM 1ST INSTR. IN HIS TRAP CODE?
	JRST	APRUT2		;YES, GO STOP USER IF SAME INT PC
				; AS LAST, SET PC = 0 SO PI 7 CAN INT.
	HRRI	T3,1(T3)	;INCREMENT TRAP ADR BY 1
	CAIE	T3,(T1)		;SAME AS PC STORED BY INT?
	JRST	APRUT3		;NO--GO TRAP TO USER
APRUT2:
IFN FTKL10,<
	TRNE	T4,UE.PEF!UE.NXM;IS THIS A NXM/PARITY ERROR?
	JRST	APPUPE		;YES, FLAG JOB AS SUCH
>; END IFN FTKL10
	MOVEI	T3,XP.LTH	;NO, SET STUCK IN LOOP BIT
	IORM	T3,.CPAEF##
	DMOVE	T3,@.CPPIP##	;FLAGS AND PC
	DMOVEM	T3,.CPAPC##	;AND SAVE FOR THE ERROR MESSAGE
	JRST	APRUTW		;STOP JOB

;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.)
APRUT3:	HRR	T1,.JDAT+JOBENB## ;GET SAVED SOFTWARE ENABLE FLAGS
	TRNE	T1,XP.DDU	;DOES USER WANT TRAPS DISABLED WHENEVER ONE OCCURS?
	JRST	APRUT4		;NO, GO DISABLE CLOCK ONLY
;HERE TO DISABLE ALL USER ENABLED INTERRUPTS
	HLLZS	.JDAT+JOBENB##	;CLEAR SOFTWARE FLAGS SO THAT USER MUST DO
				; ANOTHER APRENB UUO IN ORDER TO ENABLE TRAPS
	SETZM	.CPCN1##	;ALSO CLEAR IN CDB
	HRRI	T1,@.CPEEB##	;RESET APR CONSO MASK
	HRRM	T1,.CPCON##	; TO STANDARD SETTINGS
APRUT4:	TRZN	T1,XP.CCF	;ALWAYS DISABLE CLOCK INTERRUPT
	JRST	APRUT5		;BECAUSE USER CANNOT CONTROL ITS
	HRRM	T1,.JDAT+JOBENB## ; COMING AND COULD INTERRUPT HIS OWN
	ANDM	T1,.CPCN1##	; INTERRUPT PROCESSOR WITHOUT MEANING TO.
APRUT5:
IFN FTKL10,<
	TLO	T1,(XC.PUB)	;FORCE HARDWARE TO TEST FOR PORTAL
>
	HRR	T1,.JDAT+.JBAPR## ;GET USER TRAP ADDRESS
	PUSHJ	P,APRUTS	;STORE PC TO DISMISS TO
IFN FTKL10,<
	TRNN	T4,UE.PEF!UE.NXM ;IS THIS A PARITY/NXM ERROR?
	JRST	APRUT6		;NO--PROCEED
>; END IFN FTKL10
	DIENLK			;GIVE BACK THE DIE LOCK
APRUT6:	POPJ	P,		;DISMISS INTERRUPT
APRLOP:	JRST	APRLOP		;WAIT HERE FOR THE INTERRUPT
APRUTW:	SKIPA	T1,[IC.UOU+APRLOP];DON'T GO TO THE TRAP ROUTINE
APRUTZ:	MOVSI	T1,(XC.USR)	;DISMISS TO USER PC 0
	PUSHJ	P,APRUTS	;STORE PC TO DISMISS TO
	JRST	APRSTU		;GO STOP THE JOB

;HERE WITH T1=PC TO DISMISS TO
APRUTS:	HRRZ	T2,T1		;SECTION 0
	TRZ	T1,-1		;NO FLAGS
	DMOVEM	T1,@.CPPIP	;STORE IT
	POPJ	P,

;ANNOUNCE THAT A SWEEP HAS BEEN REQUESTED BY THIS CPU

IFN FTKL10,<
APASWP:	PUSH	P,S		;PRCHCP WANTS S SETUP
	HLLZ	S,.CPMPS##	;CPU
	TRO	S,(T4)		;INDICATE NXM
	PUSHJ	P,ANNSWP	;OUTPUT THE MESSAGE
	POP	P,S		;RESTORE S
	POPJ	P,		;RETURN
>; END IFN FTKL10

;SUBROUTINE TO WARN THE OPR THAT A MEMORY SWEEP IS GOING TO HAPPEN

ANNSWP::MOVEI	T1,SDELIM##	;GET ADDRESS OF TEXT
	PUSHJ	P,CONMES##	;PRINT START DELIMITER
	TRNE	S,UE.PEF	;PARITY ERROR?
	SKIPA	T1,[[ASCIZ /Memory parity scan initiated by /]]
	MOVEI	T1,[ASCIZ /Non-existent memory scan initiated by /]
	PUSHJ	P,CONMES##	;ANNOUNCE SWEEP
	PJRST	PRCHCP##	;FINISH SWEEP MESSAGE

;SUBROUTINE TO TYPE SBUS DIAG INFO

IFN FTKL10,<
PRTSBD:	PUSHJ	P,CONMES##	;PRINT REASON MESSAGE
	MOVEI	T1,[ASCIZ /SBUS DIAGS:
CNTRLR FNC 0          FNC 1
/]
	PUSHJ	P,CONMES##	;PRINT SBDIAG HEADER
	PUSHJ	P,TYPSBD##	;PRINT THE SBDIAG INFO
	MOVEI	T1,EDELIM##	;GET ADDRESS OF TEXT
	PJRST	CONMES##	;PRINT END DELIMITER
>
;HERE ON USER PARITY/NXM ERROR
;FLAG CURRENT USER THIS CPU AS HAVING ERROR AND HAVE TO BE STOPPED
IFN FTKL10,<
APPUPE:	DMOVE	T1,.CPAPC##	;GET THE INTERRUPT PC
	CAMN	T2,.CPLPP##	;IS IT THE SAME AS LAST PC?
	JRST	APRUTZ		;YES, CLEAR PC TO 0, SO CAN DISMISS TO PI7
				; MUST BE MEM PAR/NXM ON INSTR. FETCH

;HERE TO REQUEST PI 7 MEMORY SCAN
	HLLZ	T3,.CPMPS##	;GET SWEEP REQUESTED BY CPU N (THIS CPU) BITS
	TRO	T3,(T4)		;SET PARITY OR NXM FLAG
	IORM	T3,.CPAEF##	;SET FLAG FOR PI 7 TO SWEEP MEMORY
	DMOVE	T1,.CPAPC##	;GET THE ERROR PC
	MOVEM	T2,.CPLPP##	;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)
>; END IFN FTKL10

;HERE TO STOP THE CURRENT JOB
APRSTU:	SETOM	.CPCKF##	;SET FLAG FOR SCHEDULER INTERRUPT (PI 7)
	SETOM	.CPSCF##	;FORCE RESCHEDULE EVEN IF ERROR IN MONITOR
IFN FTKL10,<
	TRNN	T4,UE.PEF!UE.NXM ;IS THIS A PARITY/NXM ERROR?
	JRST	APRST1		;NO--PROCEED
	DIENLK			;YES, GIVE BACK THE DIE LOCK
APRST1:>
	CONO	PI,XI.RQC##	;REQUEST PI 7 INTERRUPT
	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
; KL10 - NXM AND PARITY ERROR - REAL PC EXEC OR USER MODE
; CALLED ON EVERY MEMORY PARITY INTERRUPT
;CALL:
;	PUSHJ	P,APRPTS
;	RETURN HERE, C(T1)=REAL ERROR FLAGS
;		     C(T2)=REAL ERROR PC
;		     C(T3)=POINTER TO LOCATION OF SAVED USER MODE PC

APRPTS:	MOVE	T1,@.CPCHL##	;GET INTERRUPT PC
	TLNE	T1,(XC.USR)	;INTERRUPT PC IN USER MODE?
	JRST	APRPT1		;YES, EASY TO SET UP
IFN FTKL10,<
	DMOVE	T1,@.CPCHL##	;GET THE PC
	CAIL	T2,SEILM##	;IN TRAP ROUTINE?
	CAILE	T2,SEIL1##	; ...
	JRST	APRPT0		;NO, LOOK ELSEWHERE
	DMOVE	T1,.USPFP	;YES, GET THE DOUBLE WORD PC
	TDZ	T1,[7777,,-1]	;FOR GETTAB
	MOVE	T3,.CPCHL##	;WHERE TO STORE THE PC IF NECESSARY
	POPJ	P,
APRPT0:>
	CONI	PI,T1		;GET PI'S CURRENTLY IN PROGRESS
	ANDI	T1,@.CPNAP##	;EXCEPT APR CHANNEL
	JFFO	T1,.+2		;DETERMINE CHANNEL NUMBER
	JRST	APRPT1		;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,.CPEPT##	;0 OR 100 FOR TRAP OFF SET
	HLRZ	T1,(T2)		;GET INSTRUCTION FROM PI LOCATION
	ANDI	T1,777740	;GET RID OF NOISE BITS
	CAIE	T1,(XPCW)
	AOS	T2		;MUST BE BLKI(O), GO TO 41+2N
	HRRZ	T3,(T2)		;GET CH'N
	DMOVE	T1,@.CPCHL	;T2=STORED PC
	MOVE	T1,3(T3)	;PC TO XPCW TO
	CAME	T1,T2		;IS STORED PC FIRST ONE IN ROUTINE?
APRPT1:	MOVE	T3,.CPCHL##	;NO, POINT TO SAVED APR INTERRUPT PC
	DMOVE	T1,(T3)		;RETURN PC
	POPJ	P,
;HERE ON APR INTERRUPTS OTHER THAN THE CLOCK

APRERR:
IFN FTKS10,<
	CONSO	APR,SP.FEI	;FRONT END?
	JRST	NOTFE		;NO, GO CHECK ERROR FLAGS
	SETOM	.CPFEF##	;YES, SET SOFTWARE FLAG FOR SCNSER
	WRPI	REQCTY##	;AND CAUSE AN INTERRUPT FOR CTY
	WRAPR	SP.CSF!SP.FEI	;CLEAR THE FRONT END FLAG
	POPJ	P,		;AND DISMISS SO "CTY" INTERRUPT WILL HAPPEN
NOTFE:>
	EXCH	T1,@.CPCHL##	;GET INTERRUPT PC
	AOS	.CPEDI##	;COUNT NO OF EXEC DON'T-CARE INTERRUPTS (AOV,FOV)
				; HAPPENS ONLY IF USER IS ENABLED WHEN MONITOR
				; CAUSES CONDITION
	HRLM	T1,.CPEDI##	;STORE OFFENDING PC SO WE CAN FIX CODE -
				; SINCE THIS SLOWS DOWN SYSTEM
	EXCH	T1,@.CPCHL##	;RESTORE INTERRUPT PC
	POPJ	P,		;DISMISS INTERRUPT
;HERE ON CHANNEL 7 CLOCK INTERRUPT

CLKINT::CONO	PI,II.CCI##	;CLEAR SOFTWARE REQUESTED INTERRUPT
	DMOVEM	17,.CPS17##
	DMOVE	17,@.CPCKL##
	CAIE	0,EACAPC##	;DOING EFFECTIVE ADDRESS CALCULATION?
	CAMN	0,[MCSEC1+EACAPC##] ;PERHAPS IN SECTION ONE?
	JRST	[MOVE	17,.CPJOB##	;GET CURRENT JOB ON THIS CPU
		 MOVE	17,JBTSTS##(17)	;AND THE ASSOCIATED JOB STATUS WORD
		 TLNE	17,CNTRLC	;WAS CONTROL-C TYPED?
		 HRRI	0,EACACC##	;YES--ALTER THE PC TO LET THE USER OUT
		 MOVE	17,@.CPCKL##	;GET PC FLAGS BACK
		 DMOVEM	17,@.CPCKL##	;UPDATE POSSIBLY CHANGED PC DOUBLE WORD
		 JRSTF	@SAVPC]		;AND RESCHEDULE OUT OF EXEC MODE
	TLNN	17,(XC.USR)	;PC IN USER MODE?
	SKIPE	.CPSCF##	;NO, IS THIS A FORCED RESCHEDULING INTERRUPT?
	JRSTF	@SAVPC		;YES--IT IS OK TO RESCHEDULE NOW
	DMOVE	17,.CPS17##
	XJEN	@.CPCKL##

SAVPC:	XWD	XC.UOU##,.+1	;JRSTF @ HERE TO RESCHEDULE
	DMOVEM	17,.CPPC##
	TLNE	17,(XC.USR)	;PC IN USER MODE?
	JRST	[DMOVE 17,.CPS17## ;RESTORE USER AC 17
		 EXECAC		;SWITCH TO EXEC AC BLOCK
		 JRST CLKSPD]	;CONTEXT SWITCH WILL SAVE USER ACS
	DMOVE	17,.CPS17##
	EXECAC			;EXEC MODE DOESN'T NECESSARILY MEAN EXEC AC'S
	MOVEM	17,.CPS17##	;SAVE AC 17
	SKIPN	17,.CPADR##	;CURRENT JOB DATA AREA, IS THERE ONE?
	MOVE	17,.CPNJD##	;NO, MUST BE NULL JOB OR CORE 0
	MOVEM	16,JOBD16##(17)	;SAVE AC 16 IN DUMP AC PART OF JOB DATA AREA
	MOVEI	16,JOBDAC##(17)	;SOURCE=0,DESTINATION=DUMP AC 0
	BLT	16,JOBD15##(17)	;SAVE ACS 0-15 JUST BELOW AC 16
	MOVE	T1,.CPS17##	;NOW SAVE 17 IN JOB DATA AREA
	MOVEM	T1,JOBD17##(17)	;ALONG WITH OTHER ACS
CLKSPD::
IFN FTXMON,<
	JRST	@[0,,.+1]
>
	MOVE	P,.CPNPD##	;SET UP PUSH DOWN LIST IN NULL JOB DATA
				; AREA IN LOWER CORE
IFN FTMP,<
	SKPCPU	(1)		;CHECK FOR BOOT CPU
	JRST	SAVPC2		;DON'T WANT EVERYBODY TO STICK THEIR HEADS IN THE SAND
	SKIPE	MOFLPG##	;IF SETTING MONITOR MEMORY OFF-LINE
	JRST	CP1MFL##	; FORCE ALL OTHER CPUS TO JUMP INTO THE ACS
>
SAVPC2::SETOM	.CPISF##	;FLAG THAT WE'RE IN THE SCHEDULER
	MOVE	S,.CPAEF##	;COMMUNICATION FLAG BETWEEN HIGHER PI LEVELS AND CLK
	JUMPE	S,RSCHED	;ANY APR ERRORS? NO--RESCHEDULE
	PUSHJ	P,APRILM##	;YES--GO PROCESS IMMEDIATELY
	JRST	RSCHED		;NOW RESCHEDULE
;HERE AT UUO LEVEL WHEN CURRENT JOB RETURNS TO USER MODE FROM UUO 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
USCHD1::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
USCHED::XSFM	.CPPC##		;FLAGS DON'T REALLY MATTER BUT EXEC MODE DOES
	POP	P,.CPPC##+1	;SAVE PC IN PROTECTED PART OF SYSTEM DATA
	MOVEM	F,.JDAT+JOBDAC##+F ;SAVE F
;				; SINCE CAN START UP ON EITHER CPU
USCHE1::MOVEM	J,.JDAT+JOBDAC##+J ;SAVE CURRENT JOB NUMBER
				; NEEDED ON CALL FROM USER UUO EXIT
	MOVEM	P,.JDAT+JOBDPD## ;SAVE P
	JRST	WSCHD2		;GO SETUP LONGER PDL AND RESCHEDULE

;ROUTINE TO ALLOW INTERRUPTION OF LONG UUO'S
SCDCHK::SKIPN	SCDRTF##	;FORCED RESCHEDULE PENDING?
	SKIPE	.CPTMF##	;OR CLOCK TICKED?
	PJRST	WSCHED		;YES, PROCESS COMMNAND, SCAN JOBS
	POPJ	P,		;NO, CONTINUE THE UUO A WHILE

;HERE AT UUO LEVEL WHEN JOB GOES INTO IO WAIT OR SHARABLE DEVICE WAIT
;CALL:	PUSHJ P,WSCHED
;	RETURN HERE WHEN RUNABLE AGAIN
WSCHED::MOVEM	17,.JDAT+JOBD17## ;SAVE AC17 IN DUMP ACS (P4 IN NEW ACS)
WSCHD1::XSFM	.CPPC##		;FLAGS DON'T REALLY MATTER BUT EXEC MODE DOES
	POP	P,.CPPC##+1	;SAVE PC IN PROTECTED PART OF SYSTEM DATA
	MOVEI	17,.JDAT+JOBDAC## ;SAVE ACS 0-16 IN DUMP ACS
	BLT	17,.JDAT+JOBD16## ;IN CURRENT JOB DATA AREA
WSCHD2:	HRRZS	P		;RIGHT HALF FOR COMPARE
	CAMGE	P,SYSSIZ##	;UUO LEVEL PDL?
	STOPCD	.+1,JOB,WTP,	;++WRONG TYPE OF PDL
WSCHD3::MOVE	P,.CPNPD##	;NULL JOB PD LIST (ELSE GET PDL OVF)
				;USED TO CALL SCHEDULER AND COMMAND DECODER
				;FALL INTO RSCHED AND RESCHEDULE

RSCHED::SETOM	.CPISF##	;FLAG IN THE SCHEDULAR
	MOVSI	T1,777740	;CLEAR FLAGS STORED BY PUSH/POP
	ANDCAM	T1,.CPPC##+1
IFN FTXMON,<
	JRST	@[0,,.+1]	;FOR THE TIME BEING, ALWAYS RUN THE SCHEDULER IN SECTION0
>
	MOVE	J,.CPJOB##	;GET CURRENT JOB #
IFN FTPI,<
	SKIPN	.CPTMF##	;DID CLOCK TICK?
	JRST	CPUTIM		;NOT APR CLOCK
	SIGNAL	C$APRC		;YES, SIGNAL APR CLOCK
	  JFCL			;NO TICK OR NOT ENABLED
>;END FTPI
;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.


CPUTIM:	PUSHJ	P,TIMEX		;GET TIME IN T1
IFE FTEMRT,<
	SKIPN	P1,T1		;TEST FOR 0 (& SAVE TIME IN P1)
	JRST	CIP1
>;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	INCJOB		;YES, MUST INCREMENT USER TIME EVEN
				; THOUGH REAL TIME WAS NOT A TICK
>;END IFN FTEMRT

;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:	JUMPN	J,INCTIM	;LAST JOB. WAS IT NULL JOB?
	SKIPN	.CPPLT##	; YES..WAS IT LOST TIME?
	JRST	INCNUL		; NOT LOST, JUST IDLE.
	MOVE	T1,P1		; LOST, INCREMENT TOTAL
	ADD	T1,.CPLS2##	;ADD PREV EXCESS
	IDIVI	T1,RTUPS##	;CONVERT TO JIFFY + EXCESS
	ADDM	T1,.CPLST##	;INCREMENT JIFFY TOTAL
	MOVEM	T2,.CPLS2##	;REMEMBER EXCESS
	SETZM	.CPPLT##	;CLEAR LOST TIME FLAG

IFN FTKL10&FTMP,<
	SKIPN	.CPCLF##	;LOST TIME BECAUSE OF CACHE ON DUAL CPUS?
	JRST	INCNUL		;NO
	MOVE	T1,P1
	ADD	T1,.CPCL2##	;DO USUAL STUFF
	IDIVI	T1,RTUPS##
	ADDM	T1,.CPCLT##	;MORE LOST TIME
	MOVEM	T2,.CPCL2##	;SAVE REMAINDER
	SETZM	.CPCLF##	;CLEAR FLAG
>;END FTKL10&FTMP
INCNUL:	MOVE	T1,P1		;INCREMENT IDLE TIME
	ADD	T1,.CPNL2##	;ADD PREV EXCESS
	IDIVI	T1,RTUPS##	;CONVERT TO JIFFY + EXCESS
	ADDM	T1,.CPNUL##	;INCREMENT JIFFY TOTAL
	MOVEM	T2,.CPNL2##	;REMEMBER EXCESS
INCJOB:	JUMPN	J,INCTIM	;DO ALL THE WORK IF A REAL USER
IFN FTEMRT,<
	PUSHJ	P,CHKPMJ##	;WORRY ABOUT PERF METER RUNNING
	  JRST	CIP2		;NO, GO SCHEDULE
	PUSHJ	P,GETMBT##	;GET MBOX COUNTERS
	DADD	T1,.CPMM0##	;GET NEW TOTAL
	DMOVEM	T1,.CPMM0##	;WISH WE HAD DADDM
	PUSHJ	P,CLREMB##	;RESET VALUES
>
	JRST	CIP2		;NOW GO SCHEDULE
;INCREMENT JOB'S RUNTIME
INCTIM:	SKIPN	JBTADR##(J)
	JRST	CIP2
	PUSHJ	P,FNDPDB##	;GET ADDRESS OF PDB
	  JRST	CIP0		;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
	.ADD	T2,.PDEB2##(W)	;ADD IN EXCESS FROM LAST TIME
	TLZE	T2,(1B0)	;OVERFLOW?
	AOS	T1		;YES
	DIV	T1,.CPEBJ##	;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##	;GET NEW TOTAL
	DMOVEM	T3,.CPMM0##	;STORE
INCTAA:	PUSHJ	P,CLREMB##	;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##	;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
	TRNE	T1,ST%EMR	;EBOX/MBOX RUNTIME?
	MOVE	P1,P2		;YES, REPLACE HIGH PRECISION RUNTIME WITH EBOX/MBOX TIME
>;END IFN FTEMRT

	SKIPN	P2,P1		;SINCE NOT USING EBOX/MBOX, SETUP P2 OLD STYLE
	JRST	CIP1		;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
	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
	PUSHJ	P,VMSIZE##	;JOB VIRTUAL SIZE
	ADDI	T2,(T1)
	LSH	T2,P2KLSH##	;CONVERT TO K
	IMUL	T2,P1		;VIRTUAL KCS
	ADDM	T2,.PDVKC##(W)	;ACCUMULATE

IFN FTNSCHED,<
	ADDM	P1,RTCTOT##	;UPDATE TOTAL TIME GIVEN OUT SINCE WE SET
				; CLASS QUOTAS
>;END IFN FTNSCHED
	.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
	CAILE	T2,PQ2##	;HPQ?
	ADDM	P1,RNTHPQ##	;CHARGE HPQS
>
IFN FTNSCHED,<
	SKIPN	.CPSQF##	;EXIT IF THIS JOB NOT FROM SUBQUEUES
	JRST	CIP0		;GIVE ACCOUNTING DONE RETURN

;HERE IF SCHEDULER IS TRYING TO SATISFY QUOTAS FOR ONE OR MORE CLASSES.
; INCREMENT TOTAL RUNTIME, AND PER CLASS RUNTIME.
; 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,CLSRTM##(T2)	;AND RUNTIME FOR THIS CLASS SINCE STARTUP
>;END IFN FTNSCHED
;HERE IF CURRENT JOB HAS NO PDB (KJOB UUO)
CIP0:	JUMPE	J,CIP2
	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
	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
	  SKIPA			;USER DOESN'T WANT TRAP
	JRST	INCT1A		;TRAP THE JOB
>
	MOVEI	T4,.ERTLX	;TIME LIMIT EXCEEDED ERROR
	PUSHJ	P,CHKINT##	;NO, HE WANT THIS INTERCEPT
	  JRST	INCTM1		;NO, GIVE ERROR MSG
	GETPC	T2,.CPPC##	;PC AT INTERRUPT
	TLNE	T2,(XC.USR)	;JOBPD1 IS OK IF DURING A UUO
	PUTPC	T2,.JDAT+JOBPD1##	;SAVE FOR DOINT
	HLL	T1,.CPPC##	;FLAGS AT INTERRUPT
	TLNE	T1,(XC.USR)	;USER MODE?
	PUTPC	T1,.CPPC##	;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,MTIMLM	;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:	SKIPE	JBTADR##(J)	;NOTHING TO DO IF NO CORE IN CORE
	SKIPL	T3,JBTSTS##(J)	;JOB RUNNABLE?
	JRST	INCTM6		;NO, DON'T TEST
	TLNN	T3,NSHF!NSWP	;LOCKED?
	PUSHJ	P,FNDPDB##	;GET THE JOB'S PDB
	  JRST	INCTM6		;DON'T TEST IF NOT THERE
	SKIPE	.PDTMC##(W)	;COUNTER ZERO?
	SOSLE	.PDTMC##(W)	;NO, DECREMENT COUNTER
	JRST	INCTM6		;NO COUNT SETUP OR COUNT HASN'T GONE TO ZERO
	DMOVE	T1,.CPPC##	;GET THE JOB'S PC
	TLNN	T1,(XC.USR)	;PC IN USER MODE?
	JRST	INCTM5		;NO, TRY AGAIN IN A TIC
	HRRZ	T3,.JDAT+.JBPFH## ;START OF PFH
	HLRZ	T4,.JDAT+.JBPFH## ;END OF PFH
	CAIG	T3,(T2)		;PC IN PFH?
	CAIGE	T4,(T2)		; ..
	SKIPA	T3,[EXP IC.UOU+TIMFLT##]	;NO, PC TO CATCH TIME FAULT AT UUO EXIT
	JRST	INCTM5		;YES, POSTPONE TIME FAULT ONE TICK
	DMOVEM	T1,.USPFP	;STORE OLD PC FOR TIMFLT
	PUTPC	T3,.CPPC##	;MAKE CONTEXT SWITCH GO TO TIMFLT
	JRST	INCTM6
INCTM5:	MOVEI	T1,1		;WAIT ONE TICK FOR VIRTUAL TIME TRAP
	MOVEM	T1,.PDTMC##(W)	;STORE NEW VALUE IN COUNTER OR USER'S PC
INCTM6:
;HERE AFTER ALL TIME CHARGING TO CURRENT USER HAS BEEN DONE
CIP1:	DMOVE	T1,.CPPC##
	MOVE	J,.CPJOB##	;&JOB #
	SKIPN	JBTADR##(J)	;ADDRESS OF JOBDAT
	JRST	CIP2		;NONE
	DMOVEM	T1,USRPC##
	DMOVE	T3,.JDAT+JOBPD1## ;ADDRESS OF UUO
	SUBI	T4,1
	TLNE	T3,(XC.USR)	;IN USER MODE?
	MOVEM	T4,JBTPC##(J)	;YES--STORE FOR CONTROL-T
	TLNE	T1,(XC.USR)	;ARE WE IN USER MODE?
	MOVEM	T2,JBTPC##(J)	;YES--STORE PC
CIP2:
IFN FTKL10&FTMP,<
	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
	SKIPN	.CPTMF##	;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.
;DO SYSTEM TIME ACCOUNTING

	SETOM	.CPCHT##	;REMEMBER CLOCK TICKED
	MOVE	T1,TIME##	;REMEMBER THIS TIME FOR
	EXCH	T1,.CPTML##	;  NEXT TIME & COMPUTE
	SUB	T1,.CPTML##	;  DIFFERENCE (TIMINT)
	MOVNS	T1
	SKIPGE	T1		;IN CASE WENT THRU MIDNIGHT
	ADD	T1,MIDNIT##
	ADDM	T1,.CPTNT##
IFN FTMP,<
	SKPCPU	(0)		;POLICY CPU?
	JRST	CIP3		;NO, DON'T UPDATE TIME OR DO COMMANDS
>

;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##
	MOVSI	T1,(DF.RQC)	;DID SOME CPU REQUEST THAT WE
	TDNE	T1,DEBUGF##	; CALL CRSCPY ON THE NEXT TICK?
	PUSHJ	P,[ANDCAM T1,DEBUGF## ;IF SO, CLEAR THE REQUEST
		   JRST CRSCPY##] ;AND CAUSE CRASH COPY PROGRAM TO START
IFN FTKS10&FTNET,<
	MOVSI	T1,(DF.RQK)	;DID SOME ONE WANT KDPLDR TO RUN
	TDNE	T1,DEBUGF##	; ON THIS CLOCK TICK?
	PUSHJ	P,[ANDCAM T1,DEBUGF## ;IF SO, CLEAR THE REQUEST
		   JRST KDPLDR##] ;AND CALL KDPLDR
>
IFN FTKL10,<
	MOVSI	T1,(DF.RQN)	;DID SOME ONE WANT KNILDR TO RUN
	TDNE	T1,DEBUGF##	; ON THIS CLOCK TICK?
	PUSHJ	P,[ANDCAM T1,DEBUGF## ;IF SO, CLEAR THE REQUEST
		   JRST KNILDR##] ;AND CALL KNILDR
>
;PROCESS ANY COMMANDS TYPED

	SKIPE	.CPJOB##	;NULL JOB?
	SKIPE	.CPADR##	;NO, JOB HAVE CORE?
	SKIPN	COMCNT##	;YES, ANYTHING TYPED
	JRST	CIP3		;NO, DON'T DO COMMAND PROCESSING
	PUSHJ	P,COMMAND##	;YES, GO PROCESS
;PROCESS TIMING REQUESTS STORED IN QUEUE

CIP3:	MOVE	T1,.CPCPN##	;OUR CPU NUMBER
	SKIPGE	T2,.CPTNT##	;TICKS GONE BY SINCE LAST TIME
	SETZB	T2,.CPTNT##
	SETZ	T3,		;FOR BOOT CPU CHECK
IFN FTMP,<SKPCPU (1)>		;DO WE MAINTAIN "SYSTEM" QUEUE AS WELL
	EXCH	T3,CLKNEW##	;YES, GET/CLEAR NEW REQUEST FLAG
	CAMGE	T2,CLKMIN##(T1)	;TIME TO PROCESS YET
	JUMPE	T3,CIP5		;NO, DO ONCE A TICK STUFF UNLESS SOMETHING NEW
	HLLOS	CLKMIN##(T1)	;COMPUTE NEW MINIMUM TIME
	CLKLOK			;KEEP OTHER CPU'S FROM PROCESSING THE QUEUE
	SYSPIF			;AND NEW REQUESTS FROM COMMING IN
	HRRZ	U,CLOCK		;GET END OF LIST
	SYSPIN			;OK TO PUT NOW, WE KNOW THE END OF THE LIST
	CAIL	U,CIPWTE##	;MAKE SURE IT DIDN'T GO OVER END
	STOPCD	.,STOP,CQO,	;CLOCK QUEUE OVERFLOWED AT SOME TIME.
CIP4:	CAIN	U,CIPWTM##	;END YET?
	JRST	CIP4C		;YES
IFN FTMP,<
	SKIPL	(U)		;CPU SPECIFIC REQUEST
	SKIPA	T1,BOOTCP##	;NO, ONLY BOOT CPU PROCESSES THE "SYSTEM" QUEUE
	LDB	T1,[POINT 3,(U),3] ;YES, GET CPU THAT IS TO DO THE WORK
	CAME	T1,.CPCPN##	;IS IT ME
	SOJA	U,CIP4B		;NO, LOOK AT NEXT ENTRY
>
IFE FTMP,<SETZ	T1,>		;USE "CPU0" ON SINGLE SYSTEMS
	MOVSI	T3,(1B4)	;GET SCANNED REQUEST BIT
	HRRZ	T2,-1(U)	;DECREMENT TIME REQUEST
	TDNN	T3,(U)		;IS THIS A NEW REQUEST
	SOSA	T2		;YES, DECREMENT BY ONLY ONE TICK
	SUB	T2,.CPTNT##	;SEEN BEFORE, REDUCE BY TIME GONE BY
	JUMPLE	T2,CIP4A	;REMOVE IF REQUEST HAS TIMED OUT
	HRRM	T2,-1(U)	;NOT EXPIRED, STORE NEW WAIT TIME
	IORM	T3,(U)		;AND MARK REQUEST AS SCANNED
	CAMGE	T2,CLKMIN##(T1)	;FIND NEW MINIMUM TIME
	MOVEM	T2,CLKMIN##(T1)	;THIS IS IT SO FAR
	SOJA	U,CIP4B		;CONTINUE SCAN
CIP4A:	HRRZ	T1,(U)		;GET DATA ITEM TO BE RETURNED
	MOVS	T2,-1(U)	;AND DISPATCH ADDRESS
	SYSPIF			;MOVE LAST ITEM IN LIST TO THIS
	MOVE	T3,@CLOCK
	SOS	CLOCK
	MOVEM	T3,(U)
	MOVE	T3,@CLOCK
	SOS	CLOCK
	MOVEM	T3,-1(U)
	SYSPIN			;DONE RE-ARRANGING THE QUEUE
	PUSH	P,U		;SAVE ONLY VALUABLE AC
	PUSHJ	P,(T2)		;AND DISPATCH TO TIMING REQUEST ROUTINE
	POP	P,U		;GET CURRENT ENTRY POINTER BACK
	SUBI	U,1		;ADJUST POINTER
CIP4B:	SOJA	U,CIP4		;GO BACK FOR MORE REQUESTS
CIP4C:	CLKNLK			;OPEN THE FLOOD GATES
	SETZM	.CPTNT##	;START NEW TIMER
CIP5:	SKIPG	.CPHTM##	;SECOND COUNTER GONE TO ZERO (OR LESS)?
	PUSHJ	P,SECOND	;YES, GO DO ONCE-A-SECOND JOBS
CIP6:	CPLOCK	(SCD)		;LOCK SCHEDULER TO AVOID RACES
CIP601:	PUSHJ	P,NXTJOB##	;CALL SCHEDULER, SET J TO NEXT JOB # TO RUN
IFN FTMP,<
	SKIPE	.CPADR##	;WAS LAST JOB NULL JOB, OR
	CAMN	J,.CPJOB##	;IS THIS JOB SAME AS LAST JOB
	CPUNLK	(SCD)		;YES, CAN UNLOCK NOW
CIP60:	SKPCPU	(0)		;BOOT
	JRST	CIP6A		;NO, ONLY THE BOOT CPU DOES 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
				; THEREFORE, IT IS A JFCL. IF IT IS DESIRED
				; THE PATCH IS SIMPLE.
>;END REPEAT 0
CIP6A:	CONO	PI,PI.OFF
	SETZM	.CPCKF##	;CLEAR CLK INTERRUPT FLAG
				; SET ON ALL FORCED CLK INTERRUPTS
	CONO	PI,PI.ON+II.CCI## ;ENABLE INTRPS, CLEAR SOFTWARE INTRP
	SETOM	.CPPTF##	;RESET PAGE TABLE PARITY COUNT
				; DO IT HERE RATHER THAT APR LEVEL TO AVOID A LOOP
IFN FTHPQ!FTNSCHED,<
	SKIPL	T2,SCDRTF##	;NEED TO FORCE SCHEDULAR CYCLE?
	  JRST	CIP70		;NO
	MOVNS	T2		;MAKE JOB NUMBER
	TRNN	T2,-1		;JOB 0= ONLY IF IDLE
	  JRST	[JUMPN	J,CIP70	;THIS IS A RARE CASE
IFN FTMP,<
		 SKIPN	.CPADR## ;UNLOCK SCHEDULAR (SINCE J=0, WAS LAST JOB NUL OR DESTROYED?)
		   JRST	CIP6	;YES
		 PUSHJ P,SETSJ0## ;SET SP.SJx SO JOB IN .CPJOB DOESN'T BECOME
				;RUNNABLE BEFORE WE GET TO SAVUAC AND FRIENDS
				;SHOULD THIS TRIP THRU NXTJOB UNLOCK THE
				;SCHEDULER TO WANDER THRU THE SWAPPER (CKJB6)
>
		   JRST	CIP601]	;NO, DON'T GET INTERLOCK AGAIN
>				;END FTHPQ!FTNSCHED
IFN FTHPQ,<
	HLRZ	T1,JBTRTD##(J)	;CURRENT JOB
	HLRZ	T2,JBTRTD##(T2)	;JOB IN SCDRTF
	ANDI	T1,HPUMSK##	;THIS SHOULD BE FASTER THAN LDB?
	ANDI	T2,HPUMSK##
	CAMGE	T1,T2		;CURRENT JOB OR REQUESTED JOB HIGHER?
IFN FTMP,<
	  JRST	[CAME	J,.CPJOB## ;IF NEW JOB NOT THE OLD JOB,
		 PUSHJ	P,CLRSJ0## ;CLEAR CP.SJ0 ON JOB JUST SELECTED
		 SKIPE	.CPADR	;IF LAST JOB NULL OR DESTROYED OR SAME,
		 CAMN	J,.CPJOB ;UNLOCK SCHEDULAR ALREADY?
		   JRST	CIP6	;YES
		 PUSHJ	P,SETSJ0## ;MAKE SURE JOB IN .CPJOB DOESN'T RUN
				;ELSEWHERE IF NXTJOB UNLOCKS THE SCHEDULER
				;TO SERVICE THE SWAPPER(SCHED1-CKJB6)
		 JRST	CIP601]	;
>
IFE FTMP,<
	  JRST	CIP601
>
>				;END IFN FTHPQ
CIP70:
	SETZM	.CPTMF##	;CLEAR TIMED (1 JIFFY) INTERRUPT FLAG.
	SETZM	.CPSCF##	;CLEAR FORCED SCHEDULING FLAG
IFN FTHPQ!FTNSCHED,<
	SETZM	.CPHQU##	;CLEAR FLAG SAYING CURRENT JOB DID A HPQ UUO
>
	MOVE	U,.CPJOB##	;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)
		TLNE	T1,SEGMB	;WAS HIGH SEGMENT MOVED BY LOCK UUO?
		PUSHJ	P,SETRL1##	;AND MAKE PAGE MAP REFLECT THE MOVE.
		JRST	CIPXIT]
	SKIPE	U		;NO, SAVE PREVIOUS JOB NO. FOR PERFORMANCE
	MOVEM	U,.CPLJR##	;MONITORING WITH A DISPLAY

;DIFFERENT JOB, SAVE SOFTWARE STATE(HARDWARE ALREADY SAVED)

	AOS	.CPTJC##	;COUNT NO. OF CONTEXT SWITCHES TO DIFF. JOB
				; (INCLUDE NULL JOB)
	CAMN	U,.USJOB	;DON'T SAVE IF NOT MAPPED TO RIGHT USER
				;(SWITCHING AWAY FROM DESTROYED CONTEXT)
	PUSHJ	P,SAVUAC	;SAVE THE USER'S ACS (AC BLOCK 1) IN THE SHADOW AREA
	MOVEM	J,.CPJOB##	;STORE NEW CURRENT JOB NUMBER
	PUSHJ	P,CTXJCJ##	;GET JCH
	  MOVE	T1,.CPJOB##	;CALL IT SAME AS JOB
	MOVEM	T1,.CPJCH##	;SAVE
IFN FTKL10&FTMP,<
	SKIPE	J		;NO I/O FROM NULL JOB
	PUSHJ	P,SETCSJ##	;SET FOR CURRENT JOB FOR I/O
>
	SKIPN	.CPADR##	;NULL JOB OR CORE 0 ON OLD JOB?
	JRST	CIP7		;YES, DO NOT SAVE SOFTWARE STATE
	DMOVE	T1,.CPPC##	;GET PC
	DMOVEM	T1,USRPC##	;SAVE IT

	MOVE	T1,USRDDT##	;CONTEXT SWITCH JOBDDT SO THAT IT REMAINS
	MOVEM	T1,.JDAT+JOBDDT## ;PROTECTED BUT USER CAN LOOK AT IT
IFN FTKL10&FTMP,<
	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,CTXSWP##	;NOW DO A SWEEP IF OLD JOB IS ON THE
				; SLAVE NOW AND NEEDS A MASTER UUO
				; DONE.
>;END IFN FTKL10&FTMP
	CPUNLK	(SCD)		;UNLOCK SCHEDULER AFTER SAVING JOB'S STATE

;RESTORE SOFTWARE STATE OF NEW JOB,THEN HARDWARE STATE


NULJOB::			;TRANSFER HERE FROM SYSINI WITH J=0 AND .CPJOB=0
CIP7:
NULADR::PUSHJ	P,SETRL1##	;GO SETUP HARDWARE AND SOFTWARE RELOCATION
				; INFORMATION FOR NEW CURRENT USER
	PUSHJ	P,RESUAC	;RESTORE THE USER'S ACS (AC BLOCK 1)
				; FROM THE SHADOW AREA
	JUMPE	J,CIPXIT	;IS NEW JOB THE NULL JOB?

	SKIPN	JBTADR##(J)	;DOES JOB HAVE CORE ASSIGNED?
	STOPCD	.,STOP,NCA,	;++NO CORE ASSIGNED

	DMOVE	T1,USRPC##	;NEW USER'S PC
	DMOVEM	T1,.CPPC##	;SAVE IT IN THE CDB

	MOVE	T1,.JDAT+JOBDDT## ;CONTEXT SWITCH JOBDDT SO THAT
	MOVEM	T1,USRDDT##	;IT REMAINS PROTECTED BUT USER CAN LOOK AT IT
IFN FTMP&FTPEEKSPY,<
	MOVSI	T1,(UP.CSP)	;SPY PAGES BIT
	TDNE	T1,.USBTS	;MIGHT THIS USER BE SPYING?
	SKIPN	.USCDB		;AND SPYING ON THE CDB?
	JRST	CIPXIT		;NO, DON'T UPDATE .USCDB
	MOVE	T1,[<PM.ICD>B2!PM.PUB!PM.SPY!<XWD <.CPCDB##/PAGSIZ##>,<SPTLOW##-SPTTAB##>>]
	ADD	T1,.CPCPN##	;BUILD INDIRECT POINTER TO .CPCDB
	CAMN	T1,.USCDB	;HAS IT CHANGED?
	JRST	CIPXIT		;NO, DON'T BOTHER ME
	MOVE	T2,T1		;YES, COPY PAGE POINTER
	ADD	T2,[XWD 1,0]	;ACCOUNT FOR TWO-PAGE CDBS
	DMOVEM	T1,.USCDB	;STORE NEW MAPPING
	PUSHJ	P,STEUB##	;DO THE WRUBR AGAIN
	;FALL THROUGH TO CIPXIT
> ;END OF IFN FTMP&FTPEEKSPY
;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:	SKIPN	.CPCHT##	;CLOCK TIC?
	JRST	CIPX0A		;NO
	SETZM	.CPCHT##	;CLEAR FLAG
	PUSH	P,U
	MOVE	U,.CPUPT##	;CURRENT UPTIME
STOPAT::TRNN	U,M.STOF##	;CORRECT TIC TO START TERMINAL OUTPUT?
	PUSHJ	P,@.CPSTO##	;START OUTPUT FOR ANY LINES WAITING
IFN FTMP,<
	PUSHJ	P,DSKTIC##	;DO DISK-CPU QUEING
	PUSHJ	P,TAPTIC##	;SAME FOR TAPE
IFN FTKL10,<
	PUSHJ	P,KNITIC##	;SAME FOR KLNI
>; END IFN FTKL10
>; END IFN FTMP
IFN FTDECNET,<
IFN FTXMON,<
	PUSHJ	P,DCNJIF##	;CALL DECNET
>
IFE FTXMON,<
	DNCALL	DCNJIF##
>
>
IFN FTSCA,<
	PUSHJ	P,SC.TIC##	;DO SCS ONCE PER TICK PROCESSING
	PUSHJ	P,PPDTIC##	;DITTO FOR THE KLIPA
	PUSHJ	P,SCSCLK##	;DITTO FOR SCS. UUO
>; END IFN FTSCA
	SKPCPU	(0)		;ON THE BOOT CPU?
	JRST	CIPXT1		;NO
	SKIPE	CLPTOP##	;NEED TO ALLOCATE PAGES AT CLOCK LEVEL?
	PUSHJ	P,CRECLP##	;YES, GO WORK ON IT
CIPXT1:	POP	P,U		;RESTORE LAST JOB RUN
	MOVE	J,.CPJOB##	;AND CURRENT JOB
CIPX0A:	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##	;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
	ADDM	T3,.PDTT2##(T1)	;YES - ADD TO LAST JOB'S TIME
CIPXI0:	SKIPN	J
	ADDM	T3,.CPNL2##	; & CDB NULL TIME
	MOVE	T1,T3
CIPXI1:	ADD	T1,.CPOH2##	;CONVERT TO JIFFYS
	IDIVI	T1,RTUPS##
	ADDM	T1,.CPOHT##	;ADD INTEGRAL JIFFYS
	MOVEM	T2,.CPOH2##
	JUMPE	J,CIPXI2	;NULL JOB?
IFN FTPI,<
	MOVSI	T2,USRMOD	;USER MOD BIT IN PC WORD
	TDNN	T2,.CPPC##	;SKIP IF JOB IS IN USER MODE
	JRST	CIPPSI		;DO NOT TRAP IF EXEC MODE
	XCT	PINOJN##	;SKIP IF CANNOT GRANT PSI INTERRUPTS
	PUSHJ	P,PSIGEN##	;CAN, SEE IF THERE ARE ANY PENDING
CIPPSI::>
	MOVEI	T1,UTRP		;TRAP PENDING BIT
	MOVSI	T2,USRMOD	;USER MODE
	TDNE	T2,.CPPC##	;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,.JDAT+JOBFDV## ;GET OLD (IRP) PC
	MOVE	M,.JDAT+JOBINT## ;SETUP M FOR PUTWRD
	JUMPE	M,CIPXI4	;UTRP MAY GET SET BY PSISER. IGNORE (.JBINT)=0
	MOVEI	M,2(M)		; TO STORE PC IN THIRD WORD OF INT BLOCK
	PUSHJ	P,PUTWRD##	;STORE THE INTERRUPT PC
	  JFCL			;IGNORE ERROR

CIPXI4:	SETZM	.CPISF##	;FLAG NO LONGER IN SCHEDULAR
CIP8A:	MOVE	T1,.CPPC##	;GET THE PC FOR THE CURRENT JOB
	TLNN	T1,(XC.USR)	;IS IT IN USER MODE
	JRST	[MOVSI 17,.JDAT+JOBDAC##	;NO, RESTORE EXEC MODE ACS
		 BLT 17,17	;FROM THE DUMP AREA
		 XJEN .CPPC##]	;RETURN TO INTERRUPTED EXEC
	MOVE	T1,JBTSTS##(J)	;JOB HAVE NON-BLOCKING TTY I/O PENDING?
	TRNE	T1,JS.NTO	;?
	JRST	CIP9		;YES, CONTINUE
IFN FTKL10,<MOVSI T1,(LG.LUB)>
IFN FTKS10,<MOVSI T1,(SG.LUB)>
	ANDCAM	T1,.USUPF	;DON'T CAUSE REFILLS
IFN FTKL10,<MOVSI T1,(LG.LAB+LG.LPC+1B8+1B11)>
IFN FTKS10,<MOVSI T1,(SG.LAB+1B8+1B11)>
	IORM	T1,.USUPF	;USERACS + LOAD PCS
	DATAO	PAG,.USUPF	;RESET USER AC BLOCK #'S
	XJEN	.CPPC##		;RETURN TO THE USER PROGRAM

;HERE WHEN JOB HAS NON-BLOCKING TTY I/O PENDING AND WE WOULD HAVE GONE TO USER MODE
CIP9:	DMOVE	T2,.CPPC##	;GET PC USER NEEDS TO BE RESTARTED AT
	DMOVEM	T2,.JDAT+JOBPDL##+1 ;SET UP
	MOVE	T2,[IC.UOU+USRXNX##]
	PUTPC	T2,.CPPC##
	MOVE	P,[MJOBPD##+2,,.JDAT+JOBPDL##+2] ;SET UP EXEC STACK POINTER
	XJEN	.CPPC##		;..
;HERE WHEN ABOUT TO RUN THE NULL JOB

CIPXI2:	SETZM	.CPISF##	;FLAG NO LONGER IN SCHEDULAR
	MOVE	T1,.CPRUN##	;RUNNABILITY BITS
	TLNN	T1,(CR.SPD)	;SUSPEND THIS CPU?
	JRST	CIPXI3		;NO
IFN FTNET,<
	PUSHJ	P,FEKCPS##	;TELL FRONT ENDS WE ARE GOING AWAY
>
	TLNN	T1,(CR.TSS)	;SHOULD THIS CPU SNAP SHOT THE SYSTEM?
	JRST	CIPXI3		;NO, JUST SUPPEND
	PUSHJ	P,CSDMP##	;MAKE SURE EVERYTHING IS IN CORE BEFORE DUMPING
	CONO	PI,PI.OFF	;MONBTS WANTS THE PI SYSTEM OFF
	PUSHJ	P,[IFN FTKL10,<PUSHJ P,SVPPC##> ;SAVE PROTOCAL
IFN FTKS10, <PUSHJ P,DISKAL##>	;DISABLE KEEP ALIVE
		   PUSHJ P,SLPDMP##	;TAKE A SYSTEM SNAP SHOT
		     CAIA
		   JRST [MOVEI T1,[ASCIZ /[SYSTEM suspended]
/]
			PUSHJ P,CTYTYP##
			PJRST RMVCPU##] ;SUCCEEDED, STICK OUR HEAD IN THE SAND
IFN FTKS10, <PUSHJ P,ENAKAL##>	;ENABLE KEEP ALIVE
		   CONO PI,PI.ON	;FAILED
		   MOVSI T1,(CR.SPD)
		   ANDCAB T1,.CPRUN##	;GIVE USER THE ERROR RETURN
		   POPJ P,]
CIPXI3:	TLNE	T1,(CR.RMV!CR.SPD)	;REMOVED OR SUSPENDED CPU?
	PUSHJ	P,RMVCPU##	;YES, DO IT NOW THAT ONLY NULL JOB LEFT
	JUMPN	U,NULJB		;NULL JOB--WAS PREVIOUS JOB NULL?
				;NO--GO SET IT UP
	SKIPN	.CPNJE##	;HAS AN ERROR OCCURRED WHILE NULL JOB
				; WAS RUNNING? IF YES, RESTORE ACS
				; ILL UUO LOSED ACS
	JRST	CIP8A		;GO RESUME THE NULL JOB
				; 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


NULJB:	SETZM	.CPNJE##
				; 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
	EXCTXU	<BLT T1,6>	;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##	;IS TRPSET ENABLED
	EXCTXU	<MOVEM T1,3>	;YES DO NOT LOOK AT MEMORY
>
	MOVE	T1,.CPDBM##
	EXCTXU	<MOVEM T1,7>	;SETUP USER AC TO POINT TO PROPER CDB
	USERAC
	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
	TDNE	7,DOORBL##	;AC3 - CHECK IF DOORBELL WAS RUNG
WAKINS::WAKE			;AC4 - WAKE UP MONITOR
AOJINS:	AOJA	1		;AC5 - COUNT UP LOC 0
	0			;CLEAR AC6
;ROUTINE TO SAVE THE USER'S ACS IN AC BLOCK 1 IN THE SHADOW AC
; AREA IN THE JOB DATA AREA ON A CONTEXT SWITCH
;CALLING SEQUENCE:
;	SETUP THE USER BASE REGISTER TO POINT TO THE CURRENT JOB'S UPMP
;	PUSHJ	P,SAVUAC
;	ALWAYS RETURN HERE

SAVUAC:	PUSH	P,J		;SAVE CURRENT JOB NUMBER
	MOVE	J,U		;J 2 JOB NUMBER OF THE LAST JOB RUN
	PUSHJ	P,SETUPR	;SETUP T2 TO POINT TO SHADOW AREA
	JRST	JPOPJ##		;NO CORE IN CORE
	MOVEI	T1,(T2)		;SOURCE = USER AC 0,
				; DESTINATION = AC 0 IN SHADOW AREA
	EXCTUX	<BLT	T1,17(T2)>
				;SAVE USER ACS 0-17
	JRST	JPOPJ##		;RETURN

;ROUTINE TO RESTORE THE USER'S ACS TO AC BLOCK 1 FROM THE SHADOW AC
; AREA IN THE JOB DATA AREA ON A CONTEXT SWITCH
;CALLING SEQUENCE:
;	SETUP THE USER BASE REGISTER TO POINT TO CURRENT JOB'S UPMP
;	PUSHJ	P,RESUAC
;	ALWAYS RETURN HERE

RESUAC:	PUSHJ	P,SETUPR	;SETUP T2 TO POINT TO SHADOW AREA
	  POPJ	P,		;NO CORE IN CORE
	MOVSI	T1,(T2)		;SOURCE = AC 0 IN THE SHADOW AREA,
				; DESTINATION = USER AC 0
	EXCTXU	<BLT	T1,17>	;RESTORE USER ACS 0-17
	POPJ	P,		;RETURN

;SUBROUTINE TO SETUP T2 TO POINT TO SHADOW AC AREA FOR THE CURRENT JOB
;CALLING SEQUENCE:
;	MOVE	J,JOB NUMBER OF CURRENT JOB
;	PUSHJ	P,SETUPR
;	RETURN HERE IF NOT THE NULL JOB BUT HAS NO CORE (CORE 0,KJOB)
;	RETURN HERE - T2 POINTS TO THE CURRENT JOBS SHADOW ACS

SETUPR:	MOVEI	T1,JS.ASA	;DON'T SAVE ACS IF THE SHADOW AREA ISN'T FREE
	TDNE	T1,JBTSTS##(J)	;IS IT?
	POPJ	P,		;NO
	SKIPN	T2,JBTADR##(J)	;SETUP T2 - DOES THE JOB HAVE CORE IN CORE?
	JUMPN	J,CPOPJ##	;NO, IF J IS NON-ZERO (I.E., NOT THE NULL
				; JOB) GIVE NON-SKIP RETURN (JOB HAS NO ACS)
	JUMPN	T2,CPOPJ1##	;IS IT THE NULL JOB?
	MOVE	T2,.CPNJD##	;YES, RETURN ADDRESS OF NULL JOBS SHADOW AREA
	ADDI	T2,JOBDAC##	; ..
	JRST	CPOPJ1##	;GIVE SKIP (THERE IS A PLACE TO STORE ACS) RETURN
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
	MOVEI	P1,1		;FIRST ENTRY IN JBTADR
	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##	;SWAP WITH LAST VALUE
	SUB	T1,.CPXTM##	;  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

SECOND:	PUSHJ	P,DTASEC##
	MOVE	T1,TICSEC##	;RESTORE THE SECOND-COUNTER
	ADDM	T1,.CPHTM##	;TO FULL SECOND
				;COUNT GOES TO -1 SO SCHED1 CAN TELL WHEN
				;EXACTLY ONE MINUTE HAS GONE BY
IFN FTMP,<
	SKPCPU	(0)		;ON CPU0?
	JRST	SECON1		;NO
>
	AOSGE	COMCNT##	;BUMP FOR SAFETY
	SETZM	COMCNT##	;DON'T LET COMCNT GO NEGATIVE
	AOS	T1,LOCSEC##	;BUMP SECOND
	CAIL	T1,^D60		;NEW MINUTE?
	PUSHJ	P,MINUTE	;YES
	PUSHJ	P,XTCSEC##	;CHECK XTCDDB'S
	MOVEI	T1,FRCQUE##	;FORCE COMMAND LDB/TTY OUTPUT HEADER
	PUSHJ	P,TOTAKE##	;ANY OUTPUT THERE
	  JRST	SECON1		;NO, PRESS ON
	SE1XCT	<SKIPGE	LDBDCH##(U)> ;IS THE LINE IDLE
SECON0: PUSHJ	P,XMTCHR##	;YES, GET SOME OUTPUT
	  JRST	SECON1		;ALL DONE
	MOVSI	T1,(DF.WFL)	;"WATCH FRCLIN"
	TDNN	T1,DEBUGF##	;WANT TO SEE WHATS GOING ON
	JRST	SECON0		;NO,THROW IT ON THE FLOOR
	PUSH	P,U		;SAVE THE LDB ADDRESS
	HRRZ	U,BOOTCT##	;CTY LINE NUMBER
	MOVE	U,LINTAB##(U)	;CTY LDB
	PUSHJ	P,CCTYO##	;OUTPUT IT
	POP	P,U		;RESTORE FRCLIN
	JRST	SECON0		;AND GET SOME MORE
;MOVE THIS LABEL UP AS MORE ONCE A SECOND CODE CAN BE
; EXECUTED ON ALL CPUS
SECON1:	SOSG	.CPSEC##	;TIME TO DO ONE-A-MINUTE STUFF ON THIS CPU?
	PUSHJ	P,CPUMIN	;YES
	MOVE	T1,.CPUPT##
	CAMGE	T1,.CPIUT##
	POPJ	P,
	ADD	T1,TICSEC##
	MOVEM	T1,.CPIUT##
IFN FTNET!FTDN60,<
	PUSHJ	P,DLXSEC##	;CHECK DL-10, DTE-20 OR KMC/DUP
>
IFN FTKL10,<
	PUSHJ	P,DTESEC##	;CALL 1/SECOND 10/11 PROTOCOL ROUTINE
>;END IFN FTKL10
IFN FTKS10,<
	PUSHJ	P,KSSEC##	;DO ONCE/SECOND FOR KS10
>;IFN FTKS10
IFN FTSCA,<
	PUSHJ	P,SC.SEC##	;CALL ONCE/SECOND SCA PROTOCOL ROUTINE
	PUSHJ	P,PPDSEC##	;CALL ONCE/SECOND CI PORT DRIVER ROUTINE
>; END IFN FTSCA
	PUSHJ	P,SCNSEC##	;AND HANDLE TELETYPE PROBLEMS
IFN FTENET,<
	PUSHJ	P,ETHSEC##	;CALL ONCE/SECOND ETHERNET SERVICE
IFN FTKL10,<
	PUSHJ	P,KNISEC##	;CALL ONCE/SECOND KLNI DEVICE SERVICE
>; END IFN FTKL10
>; END IFN FTENET
IFN FTDECNET,<
	PUSHJ	P,DCNSEC##	;CALL DECNET
>
	PUSHJ	P,TAPSEC##	;CALL TAPSER
IFN FTDAS78,<
	PUSHJ	P,D78SEC##	;CHECK DAS78'S
>;END OF IFN FTDAS78
	PUSHJ	P,DSKSEC##	;CHECK FOR HUNG DISK DDBS
IFN FTDAS78!FTDN60!FTNET,<
	MOVEI	J,FEKFST##	;GET ADDRESS OF FIRST FEK (0 IF NONE)
	CAIA			;SKIP INTO THE SCAN LOOP
SECND1:	HRRZ	J,FEKBLK(J)	;STEP TO THE NEXT FEK
	JUMPE	J,SECND2	;EXIT LOOP IF WE'VE DONE ALL THE FEKS.
IFN FTMP,<			;FOR SMP, SEE IF OWNING CPU DIED.
	MOVSI	T1,FK.CPD	;FLAG SET AT APR-CLOCK LEVEL WHEN CPU DIES.
	TDNE	T1,FEKBLK(J)	;SEE IF THIS FEK'S CPU DIED ON HIM.
	PUSHJ	P,[MOVEI T1,FI.DWN	;IF CPU DOWN, GET "FEK DOWN" CODE,
		   PJRST FEKINT##]	;  AND TELL NETSER THE FEK HAS GONE
	HLRE	T1,FEKUNI(J)	;GET NUMBER OF CPU THAT THIS FEK IS ON.
	SKIPGE	T1		;  A CPU NUMBER OF "-1" MEANS
	MOVE	T1,BOOTCP##	;  "THE POLICY CPU"
	CAME	T1,.CPCPN##	;IF WE AREN'T ON THE RIGHT CPU FOR THIS FEK
	JRST	SECND1		;  GO DO THE NEXT FEK.  HIS CPU WILL CALL HIM.
>
	MOVEI	T1,FF.SEC	;GET THE "ONCE/SEC" FUNCTION CODE.
	XCT	FEKDSP(J)	;CALL THE FEK
	JRST	SECND1		;GO DO THE REST OF THE FEKS

SECND2:	PUSHJ	P,NETSEC##	;POKE NETSER
> ;END OF IFN FTDAS78!FTDN60!FTNET
IFN FTKS10,<
	PUSHJ	P,KDPSEC##	;GO CHECK THE KMC-11
	PUSHJ	P,DMRSEC##	;GO WORRY ABOUT DMR11s
>
	PJRST	DEVCHK##	;GO CHECK FOR HUNG DEVICES
;SUBROUTINE CALLED ONCE A MINUTE ON ALL CPU'S.

CPUMIN:	MOVEI	T1,^D60		;REFRESH ONCE-A-MINUTE
	MOVEM	T1,.CPSEC##	; COUNTER FOR THIS CPU
	PUSHJ	P,TAPMIN##	;PRINT TAPE CONTROLLER MESSAGES
REPEAT	0,<			;CAN'T REALLY RETURN CHUNKS OUT FROM UNDER DAEMON
				;SINCE WE MADE AN ENTRY IN THE QUEUE
IFN FTKL10,<
	SOSN	.CPETM##	;TIME TO GIVE UP KL ERROR CHUNKS YET?
	PUSHJ	P,KLEREL##	;YES, GIVE THEM BACK
>
>;END OF REPEAT 0
IFN FTMOS,<
	PUSHJ	P,MOSMIN##	;CLEAR MOS ERROR TIMER
>
IFN FTKL10,<
	SOSLE	.CPDTT##	;TIME TO UPDATE -20F'S IDEA OF DATE/TIME?
	 POPJ	P,		;NOT YET
	MOVEI	T1,^D15		;DO IT AGAIN IN 15 MINUTES
	MOVEM	T1,.CPDTT##	;JUST TO KEEP TOO MUCH SKEW FROM DEVELOPING
	MOVSI	T1,F20SDT##	;BIT TO REQUEST DTESER (UMM, TTDINT) TO
	IORM	T1,.CP20F##	;SEND THE DATE/TIME ABOUT NOW
>;FTKL10
	POPJ	P,		;RETURN
;SUBROUTINE CALLED AT CLOCK LEVEL ONCE A MINUTE

MINUTE:	PUSHJ	P,SAVE2##	;SAVE P1,P2 FOR AVG JOB SIZE, # DAEMON
				;HUNG JOBS, MCU CALCULATION
	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
IFN FTDAS78,<
	PUSHJ	P,D78MIN##	;CHECK DAS78'S
>;END OF IFN FTDAS78
IFN FTENET,<
IFN FTKL10,<
	PUSHJ	P,LLMMIN##	;CHECK LLMOP
> ;END IFN FTKL10
> ;END IFN FTENET
	SOSLE	OMSMIN##	;NEED TO PRINT OPR MESSAGE YET?
	JRST	MINUT0		;NO
	MOVE	T1,OMSINI##	;RESET COUNTER TO
	MOVEM	T1,OMSMIN##	;INITIAL VALUE
	MOVE	U,OPRLDB##	;GET LDB ADDRESS OF OPR
	PUSHJ	P,BIGBEN##	;PRINT CURRENT DATE/TIME
	MOVE	U,BOOTCT##	;GET LINE NUMBER OF THE CTY
	MOVE	U,LINTAB##(U)	;GET LDB ADDRESS
	CAME	U,OPRLDB##	;SAME AS OPR?
	PUSHJ	P,BIGBEN##	;NO, PRINT THERE ALSO
MINUT0:	PUSHJ	P,D76MIN##	;PRINT OUT PDP-11 MESSAGES
	SKIPLE	J,HIGHJB##	;CHECK ALL JOBS
	PUSHJ	P,DECHJB	;MAKE SURE HIGHJB IS HONEST
	PUSHJ	P,FJCONT	;FORCE A JCONT ON ALL WAITING JOBS
	PUSHJ	P,ENQMIN##	;LOOK FOR STALE LOCK BLOCKS
MINUT1:
	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
	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

	SKIPE	P1		;HOW MANY JOBS WAITING FOR DAEMON?
	PUSHJ	P,DPMOPR##	;ONE OR MORE, TELL OPR JOB #S.

IFN FTMP,<
	PUSHJ	P,CP1CHK##	;CHECK IF DUAL PROCESSOR IS STILL RUNNING
>
	PUSHJ	P,CHKUNI##	;CHECK ALL DISK UNITS
	SKIPN	T1,SYSKTM##	;IS A SHUTDOWN PENDING
	JRST	NOKSYS		;NO SHUTDOWN PENDING
	SOSE	T1,SYSKTM##	;YES. COUNT DOWN TO ZERO
	SKIPA	T1,SYSKTM##	;NOT FIRST KSYS TIME
	SETOM	SYSKTM##	;FLAG FOR PRIVILEDEGED CUSP
IFN FTPI,<
	JUMPL	T1,NOKSYS	;JUMP IF NO KSYS PENDING
	PUSHJ	P,PSIKSY##	;TELL EVERYONE
> ;END FTPI
NOKSYS:	AOS	ARFLAG##	;COUNT UP AUTO RELOAD COUNTER
	POPJ	P,0		;RETURN

;ROUTINE TO FORCE A JCONT COMMAND ON ALL THE JOBS THAT ARE WAITING
FJCONT::PUSHJ	P,SAVJW##	;SAVE J, W COMES ALONG FOR A RIDE
	PUSH	P,F		;SAVE F
	MOVE	J,HIGHJB##	;HIGHEST JOB
FJCNT1:	MOVE	T1,JBTSTS##(J)	;STATUS
	TLNN	T1,JERR		;IF JOB CAN CONTINUE,
	TRNN	T1,JDCON	;AND IS WAITING FOR A DEVICE,
	JRST	FJCNT2
	PUSHJ	P,DETJCK##	;DETACHED JOB?
	  JRST	FJCNT8		;YES
	MOVE	T1,J		;PUT JOB NUMBER IN T1
	PUSHJ	P,FCONRQ##	;AND TRY FORCED CONTINUE
	  JFCL
	JRST	FJCNT2		;LOOK ON
FJCNT8:	MOVEI	T1,JDCON	;YES, CAN'T FORCE A COMMAND
	ANDCAM	T1,JBTSTS##(J)	;CLEAR OW BIT
	PUSHJ	P,SETRUN	;TRY TO CONTINUE THE JOB
FJCNT2:	SOJG	J,FJCNT1	;TEST ALL JOBS
	PJRST	FPOPJ##
;SUBROUTINE CALLED ONCE AN HOUR

HOUR:	SETZM	LOCMIN##	;SET MINUTE TO 0
	AOS	LOCHOR##	;BUMP HOUR
CHKMNT::MOVE	T1,LOCHOR##	;MIDNIGHT?
	CAIGE	T1,^D24
	POPJ	P,		;NO, ALL DONE
	SUBI	T1,^D24		;YES, BACK UP A DAY
	MOVEM	T1,LOCHOR##
	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
	PUSHJ	P,THSDA		;RECOMPUTE THSDAT
	PUSHJ	P,SUDATE	;RECOMPUTE 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

	JRST	CHKMNT		;AGAIN
;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
	SKIPL	LOCSEC##	;IF TIME INVALID DON'T DECREMENT DATE
	ADD	T3,T1		;ADD DATE AND TIME
	SUB	T3,GMTDIF##	;CONVERT TO GMT
	MOVEM	T3,DATE##
	SETZM	DATREM##	;CLEAR LEFT OVER REMAINDER
	POPJ	P,

;SUBROUTINE TO RECOMPUTE NUMBER OF MINUTES TO NEXT OPR
; MESSAGE

OMSTIM::MOVE	T1,LOCMIN##	;GET CURRENT MINUTE
	IDIV	T1,OMSINI##	;DIVIDE BY PERIOD, T3=# MINUTES
	MOVE	T1,OMSINI##	;IN CURRENT PERIOD
	SUBI	T1,(T2)		;COMPUTE TIME TO END OF PERIOD
	MOVEM	T1,OMSMIN##	;STORE
	POPJ	P,		;RETURN
;CLKCHG IS A ROUTINE TO SEARCH THE CLOCK QUEUE FOR AN ENTRY FOR A
;PARTICULAR JOB AND TO CHANGE THE REMAINING CLOCK REQUEST TIME.
;	MOVE T1,JOBNUM		;T1 = JOB TO SEARCH FOR
;	MOVE T2,[POST ADDR,,NEW INTERVAL] ;T2 = WHERE TO GO WHEN EXPIRES,,TIME IN JIFFIES
;	PUSHJ P,CLKCHG		;CHANGE CLOCK REQUEST TIME
;	RETURN HERE IF AN ENTRY WAS NOT FOUND (T1=NEW SLEEP TIME)
;	RETURNS HERE, CLOCK REQUEST TIME UPDATED.
;CLKCHG USES T2, T3 WITHOUT RESTORING THEM

CLKCHG::PUSH	P,T2		;SAVE NEW SLEEP TIME FOR LATER
	HLRZ	T4,T2		;COPY POST ROUTINE ADDRESS
	CLKLOK			;INTERLOCK QUEUE
	PUSHJ	P,CLKFND
	  JRST	[CLKNLK		;UNLOCK CLOCK
		 JRST	TPOPJ##] ;RETURN
	POP	P,T3		;RESTORE SLEEP TIME
	HRRM	T3,(T2)	; ..
	MOVSI	T3,(1B4)	; ..
	ANDCAM	T3,1(T2)	; ..
	SETOM	CLKNEW##	; ..
	CLKNLK
	CAIE	T4,CTXWKJ##	;IS THIS A SLEEP/HIBER REQUEST
	JRST	CPOPJ1##	;NO, DONT DIDDLE IN-CORE PROTECT TIMES
	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
;HERE ON CLOCK REQUEST TO ALLOW MORE INITIA'S TO RUN

CLKCMD::MOVEI	T2,20		;ALLOW MORE INITIA'S TO RUN
	ADDM	T2,COMCNT##	;BUMP COUNT OF COMMANDS
	SUBI	T1,20		;DECREMENT ORIGINAL (SYSINI) COUNT
	JUMPLE	T1,CPOPJ##	;DONE IF EXHAUSTED
	MOVE	T2,[CLKCMD,,JIFSEC##] ;COME BACK IN A SECOND
	SYSPIF
	IDPB	T2,CLOCK
	IDPB	T1,CLOCK
	SETOM	CLKNEW##	;NEW ENTRY IN QUEUE
	PJRST	ONPOPJ##	;RESTORE PI AND RETURN
;HERE TO FIND A CLOCK REQUEST FOR A JOB.  RETURNS WITH T2 POINTING
;AT THE INTERLOCK.  MUST BE CALLED WITH THE CLOCK INTERLOCK
;ON ENTRY T1 CONTAINS JCH FOR THE JOB LOOKED FOR AND T4 THE POST ADDRESS
;ON SUCCESS EXIT, T2 POINTS TO THE 1ST WORD OF THE APPROPRIATE REQUEST

CLKFND:	SYSPIF			;MAKE SURE GET THE RIGHT PARITY OF ENTRY
	HRRZ	T2,CLOCK	;GET RH OF CLOCK QUEUE POINTER
	SYSPIN
CLKFD1:	CAIG	T2,CIPWTM##	;AT TOP OF QUEUE?
	POPJ	P,		;YES, JOB NOT IN QUEUE
	HLRZ	T3,-1(T2)	;GET TIME-OUT ADDRESS
	CAIE	T3,(T4)		;POST ADDRESS THE SAME AS NEW ENTRY
	SOJA	T2,CLKFD2	;NO. LOOK AT NEXT ONE.
	HRRZ	T3,(T2)		;GET DATA ITEM
	CAIN	T3,0(T1)	;NOW. DOES THAT EQUAL DESIRED JOB NO?
	SOJA	T2,CPOPJ1##	;POINT TO FIRST WORD
	SOS	T2		;ENTRIES ARE TWO WORDS LONG
CLKFD2:	SOJA	T2,CLKFD1
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


KSTOP::	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
	MOVSI	T1,JNA+JACCT	;CLEAR JOB NUMBER ASSIGNED AND LOGGED IN BITS
	ANDCAM	T1,JBTSTS##(J)
	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
>
	SETZM	JBTRCT##(J)	;CLEAR NO. OF DISK BLOCKS READ BY JOB
	SETZM	JBTWCT##(J)	;CLEAR NO. OF DISK BLOCKS WRITTEN BY JOB

IFN FTSPL,<	SETZM	JBTSPL##(J)	;CLEAR SPOOLING BITS
>
	MOVSI	T1,JXPN
	TDNN	T1,JBTSTS##(J)
	  JRST	CLRJBL
	LDB	T1,IMGOUT##
	SKIPN	T1
	DPB	T1,IMGIN##
CLRJBL:
	PUSHJ	P,FIXXPN##	;IF JOB WAS EXPANDING, DEC. XJOB
	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	JBTSCD##(J)	;IS HE IN PQ2?
	TLO	T2,(JS.PQ2)	;YES, SET THE BIT
	MOVEM	T2,JBTSCD##(J)	;SAVE INITIAL VALUE
>
IFN FTKL10&FTMP,<
	PUSHJ	P,CLCSN##	;CLEAR OUT JBTST3 ENTRY, IF IT EXISTS
>;END IFN FTKL10&FTMP
IFN FTHPQ!FTRTTRP,<	XCT	CLRRTD##	;CLEAR HPQ POSITION
>
	HRRZS	JBTCCC##(J)	;CLEAR CONTROL-C COUNT
	SETZM	JBTPPN##(J)	;CLEAR PROJECT-PROGRAMMER NUMBER
	SETZM	JBTJLT##(J)	;CLEAR JOB'S LOGIN TIME

	SETZM	JBTCLM##(J)	;CLEAR OUT CORE LIMIT
	SETZM	JBTLIM##(J)	;AND TIME LIMIT

	SETZM	JBTPRV##(J)	;CLEAR PRIVILEGES


IFN FTRSP,<	SETZM	JBTRSP##(J)	;CLEAR RESPONSE TIME MEASURE
	SETZM	JBTRQT##(J)	;CLEAR RUN-QUEUES TIME
>
IFN FTMP,<	PUSHJ	P,SETJSP##	;SET UP JBTSPS WORD WITH INITIAL CAN RUN BITS
>
	POPJ	P,
;SUBROUTINE TO STOP CURRENT JOB, NOT SET ERROR BIT
; PUT TTY IN COMMAND MODE, START TTY0, CALL SCHEDULER


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


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 <CRLF><PERIOD>
;CALL:	MOVEI T1,ADR. OF MESSAGE
;	PUSHJ P,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>


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,CHKPOP	;WANT TO AUTO-POP?
	JRST	HOLD2		;NO, WE'RE REALLY GOING TO STOP THE JOB
	SKIPN	JBTADR##(J)	;IF NO JOB DATA AREA,
	JRST	HOLD2		;GIVE UP
	PUSHJ	P,SVEUB##	;MAKE SURE IT'S ADDRESSABLE
	PUSHJ	P,CRLF##	;PRINT A CRLF
	PUSHJ	P,TTYSTR##	;START TTY IN USER MODE
	PJRST	STOP1C		;STOP JOB

HOLD2:	PUSHJ	P,PRRSP1##	;NO, 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



ESTOP::	JUMPE	J,CPOPJ##	;IS THIS ERROR IN JOB 0?
ESTOP1::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

	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,FFAPPN##
	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,.CPJOB##	;DAEMON NOW RUNNING?
	POPJ	P,		;NO (CHAN 7). AVOID DISASTER
	PJRST	QKUSXT##	;GO DO QUICKY USER EXIT
ESTOP2:
	MOVE	T1,[JACCT,,JS.RUU+JS.ASA] ;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.)
	MOVSI	T1,(JS.IGS)	;CLEAR "IN GETSEG" BIT
	ANDCAM	T1,JBTST2##(J)
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
	SKIPN	.CPISF##	;RUNNING SCHEDULER AT UUO LEVEL?
	CONSZ	PI,PI.IPA	;NOT LOGGED IN - KILL JOB IF NOT ON CHAN 7
	JRST	STOP1C		;AT CHANNEL 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)

STOP1::
	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
	MOVE	U,DDBLDB##(T1)	;ADDRESS OF LDB
	JUMPE	U,STOP1J	;DETACHED (AND TYPED CTRL/C?)
	SE1XCT	<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
	SKIPN	T1,TTYTAB##(J)	;GET TTY DDB
	JRST	STOP1H		;NO DDB?
	SKIPL	T2,DEVIOS(T1)	;GET I/O STATUS
	TLNN	T2,IOW		;IN INPUT WAIT?
	JRST	STOP1H		;NO
	PUSHJ	P,TICAVL##	;ANY CHARACTERS TO BE INPUT?
	  SKIPA	T2,[IOW,,IOACT]	;PRESERVE ONLY I/O BITS
	JRST	STOP1M		;SET STATUS TO "TI"
	ANDCAM	T2,DEVIOS(F)	;PREVENT TI HANGS
STOP1H:	TDZA	T2,T2		;NO, ZERO STATUS
STOP1M:	GETPCS	T1,.JDAT+JOBPD1## ;YES, GET UUO PC
	GETPCS	T1,USRPC##	 ;NO, GET CURRENT
	MOVSI	T2,(1B0)	;YES, SET STATUS BIT
	PUSH	P,T1		;SAVE PC ACROSS SIGNAL
	SIGNAL	C$CTLC		;SIGNAL CONTROL-C INTERRUPT
	  JRST	STOP1F		;USER DOESN'T WANT THE INTERRUPT
	POP	P,T1		;GET NEW PC
	PUSHJ	P,SETPIT	;GET JOB STARTED
	  JFCL			;IGNORE NOT ENABLED RETURN
	JRST	STOP1D		;GO FINISH UP

STOP1F:	POP	P,T1		;CLEAN STACK
> ;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
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 FTMP,<
	PUSHJ	P,CLRCCB##	;CLEAR SECONDARY PROCESSOR ^C-BIT
>
	POPJ	P,		;AND RETURN
;HERE TO UNCONDITIONALLY STOP THE JOB

STOP1C::SKIPE	T2,JBTPPN##(J)	;IF PPN IS ZERO OR
	CAMN	T2,HLPPPN##	; [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
	SYSPIF			;DONE AT INTERUPT LEVEL HIGHER THAN DT LEVEL
	TDNN	T1,JBTSTS##(J)	;NO, IS RUN BIT OFF IN JOB STATUS WORD
	JRST	[SYSPIN		;YES
		JRST STOP1A]
	TLO	T1,CNTRLC	;TURN OFF. "USER TYPED ^C WHILE STILL IN EXEC MODE"
	ANDCAM	T1,JBTSTS##(J)
	SYSPIN
	MOVSI	T1,(UP.DST)	;DON'T SEARCH TO TERMINAL?(HNGSTP)
	SKIPE	JBTADR##(J)	;NO UPBTS IF NO CORE
	TDNN	T1,.USBTS	;IF ON, LEAVE TERMINAL AT USER LEVEL
	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
	PUSHJ	P,FNDPDB##	;FIND PDB
	  JRST	STOP1E		;NO PDB
	SKIPN	.PDPGM##(W)	;GET CUSP TO RUN
	JRST	STOP1E		;NONE
	MOVEI	T1,TTFCXI##	;FORCE AN .R INITIA 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
	CAIE	T1,DAQ##	;IS IT DA?
	 JRST	STP1E1		;NO
	HLRZ	T1,JBTDAU##(J)	;YES. GET WHICH ONE
	JUMPE	T1,STOP1A	;STRANGE
	UUOLOK			;
	HLRZ	T2,UNIAJB##(T1)	;GET WAIT COUNT
	SOSL	T2		;DECREMENT IT
	HRLM	T2,UNIAJB##(T1)	;STORE IT BACK
	UUONLK			;UNLOCK IT
	JRST	STOP1A		;AND PROCEED
STP1E1:	CAIE	T1,AUQ##	;IS IT AUQ?
	 JRST	STP1E2		;NO. NORMAL
	HRRZ	T1,JBTDAU##(J)	;YES. WHICH ONE
	JUMPE	T1,STOP1A	;STRANGE
	UUOLOK			;LOCK IT
	SOSGE	UFBWAT##(T1)	;DECREMENT WAITERS
	SETZM	UFBWAT##(T1)	;PRECAUTION?
	UUONLK			;UNLOCK IT
	JRST	STOP1A		;PROCEED
STP1E2:	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:
	PUSHJ	P,DIACLR##	;CRANK UP DSK IO IF STOPPED WITH DIAG.

	PUSHJ	P,TPFREE##	;CHECK FOR MTA'S
IFN FTMP,<
	PUSHJ	P,CLRCCB##	;CLEAR CONTROL C BIT
>
IFN FTRSP,<
	SETZM	JBTRSP##(J)	;CLEAR TIME USER STARTED TO WAIT FOR RESPONSE
				; SO COUNT NEW RESPONSE
>
	MOVSI	T1,(UP.GET+UP.MPF+UP.IYB+UP.DST) ;CLEAR GET IN PROGRESS FLAG
	SKIPE	JBTADR##(J)	;DON'T DO ANDCAM IF NO MAP
	ANDCAM	T1,.USBTS
STOP1B:	PUSHJ	P,CHKPOP	;WANT TO AUTO-POP?
	JRST	STOP1K		;NO, DON'T DO IT
	ANDCAM	T1,JBTST2##(J)	;YES, CLEAR BIT FOR NEXT TIME
	PUSHJ	P,FNDPDS##	;FIND THE PDB
	PUSHJ	P,INTLVL##	;AT INTERRUPT LEVEL?
	  JRST	STOP1I		;NO
	JSP	T2,MONJOB	;RUN AT UUO LEVEL
	MOVEI	T2,ESTOP	;PUT ESTOP ON THE STACK
	JSP	T1,MONSTR	;SET UP ACS
STOP1I:	PUSHJ	P,CTXPOP##	;DO AUTO-RESTORE

STOP1K:	CAME	J,.CPJOB##	;NO, IS THIS JOB CURRENT USER
	JRST	REQUE		;NO, SET REQUE JOB FLAG
	SKIPN	JBTADR##(J)	;JOB HAVE CORE?
	JRST	STOP1L		;NO, CAN HAPPEN IF CURRENT CONTEXT HAS BEEN DESTROYED

	SKIPL	T1,JBTSTS##(J)	;RUN FLAG OFF?
	TLNN	T1,JERR		;YES, IF JOB ERROR FLAG ON
	JRST	STOP2		;NO, (IRP LEVEL ONLY) DON'T SET .CPSCF 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
STOP1L:	SETOM	.CPSCF##	;YES, FORCE RESCHEDULING EVEN IF JOB IN EXEC MODE
;	JRST	STOP2		;CAUSE CLK INTERRUPT

;ROUTINE TO CAUSE CLK ROUTINE TO RESCHEDULE
;CALLED AT ANY LEVEL
;CALL:	PUSHJ P,STOP2
;	RETURN IMMEDIATELY EXCEPT IF AT UUO LEVEL
;	IF AT UUO LEVEL, RETURN WHEN JOB IS RUNABLE AGAIN

STOP2::	CONO	PI,PI.OFF	;PREVENT CLOCK INTERRUPT DURING STOP2 CODE
	SETOM	.CPCKF##	;SET FLAG TO INDICATE CLK INTERRUPT
				; EVEN THOUGH CLK INTERRUPT IS NOT A TIME INTERRUPT
	CONO	PI,PI.ON+PI.IIO+CLKBIT##  ;TURN PI BACK ON AND REQUEST INTERRUPT TO
				; CLK PI CHANNEL(LOWEST PRIORITY CHANNEL)
	CONSZ	PI,II.IPA	;AT INTERRUPT LEVEL?
	POPJ	P,		;YES, RETURN IMMEDIATELY

	PUSH	P,T1		;NO, AT UUO LEVEL
STOP3:	CONI	PI,T1		; MAKE SURE CLOCK LEVEL PROCESSING
	TLNE	T1,CLKBIT##	; HAPPENS BEFORE DOING ANYTHING ELSE
	JRST	STOP3		; SINCE MAY NOT HAVE ANY CORE
	JRST	TPOPJ##		;RETURN

;HERE TO CHECK WHETHER JOB SHOULD DO AN AUTO-POP RATHER THAN EXIT
;
;CALL:	J/ JOB TO CHECK
;
;RETURN 1:  NO, DO THE EXIT
;RETURN 2:  YES, AUTO-POP
;		T1/ JS.SAC

CHKPOP:	MOVEI	T1,JDCON	;OW STATE BIT
	TDNE	T1,JBTSTS##(J)	;TEST FOR HNGSTP
	POPJ	P,		;YES, ALLOW THE CONTEXT TO RECOVER
	MOVSI	T1,(JS.SAC)	;NO, GET AUTO-POP BIT
	TDNE	T1,JBTST2##(J)	;IF LIT,
	AOS	(P)		;FLAG FOR SELF-DESTRUCTION
	POPJ	P,		;RETURN STATUS TO CALLER
;HERE (FROM COMCON) TO PREFORM THE ACTUAL ^D BREAKPOINT TRAP.
;
;JOB IS IN SAFE STATE (I.E., SIMCHK SAYS OK)
;
;***GETPC***PUTPC***  EXTENDED ADDRESSING MAY GET IMPACTED HERE

CDBRK::	XMOVEI	T4,USRPC##	;ASSUME RANDOM JOB PC
	CAMN	J,.CPJOB##	;IS THIS JOB CURRENTY SCHEDULED?
	XMOVEI	T4,.CPPC##	;YES, THEN THE PC IS ACTUALLY STORED HERE
	DMOVE	T1,@T4		;GET THE JOB'S CURRENT PC
	TLNE	T1,USRMOD	;IS THE JOB IN USER MODE?
	JRST	CDBRK2		;YES, TRIVIAL CASE
	XMOVEI	T4,.JDAT+JOBPD1##  ;NO, EXEC MODE, MUST BE UUO (SIMCHK)
	HRRZ	T3,T2
	DMOVE	T1,@T4		;NOW GET THE REAL USER PC
	CAIE	T3,UUODON##	;UUO COMPLETION?
	JRST	CDBRK5		;NO, THIS GETS MORE COMPLICATED!
	HRRZ	T4,.JDAT+JOBDAC##+P ;GET SAVED P
	MOVEI	T4,-1(T4)
	DMOVE	T1,@T4		;GET PC


;HERE WITH T1 CONTAINING THE USER PC A LA THE "JSR @.JBBPT", AND T4
;CONTAINING THE MONITOR ADDRESS FROM WHENCE THE USER PC CAME.

CDBRK2:	TLNN	T1,USRMOD	;JUST MAKING SURE
	STOPCD	.,JOB,BPE,	;++ BREAKPOINT PC EXEC MODE
	PUSHJ	P,INDDT		;IS USER PC FROM WITHIN DDT?
	 POPJ	P,		;YES, FORGET IT!
	PUSH	P,T1		;SAVE DOUBLE-WORD PC FLAGS WORD
	TLNE	T2,-1		;IS USER PC FROM SECTION 0?
	SKIPA	T1,T2		;NO, GLOBAL PC (SECTION,,PC)
	HRR	T1,T2		;YES, LOCAL PC (FLAGS,,PC)
	MOVEM	T1,.JDAT+JOBOPC##  ;STORE THE PC AS IF ^C, DDT
	HRR	M,.JDAT+JOBBPT##;POINT M TO THE BREAKPOINT TRAP ROUTINE
	PUSHJ	P,PUTWRD##	;STORE THE USER PC A LA "JSR @.JBBPT"
	 STOPCD	.,JOB,BPF,	;++ BREAKPOINT PUTWRD FAILED
	POP	P,T1		;RESTORE CURRENT USER PC FLAGS
	MOVE	T2,.JDAT+JOBBPT##  ;ADDRESS OF BREAKPOINT TRAP ROUTINE
	HRRI	T2,1(T2)	;CONCOCT NEW USER PC A LA "JSR @.JBBPT"
	DMOVEM	T1,@T4		;AND SET THE NEW USER PC
IFN FTKL10&FTMP,<
	PUSHJ	P,SETCSJ##	;THIS JOB IS NOW CACHE-DEPENDENT ON THIS CPU
> ;END IFN FTKL10&FTMP
	JRST	CPOPJ1##	;SUCCESSFUL RETURN
;THE USER PROGRAM IS IN A UUO WHICH SIMCHK SAYS CAN BE ABORTED. BACK OUT
;OF THE UUO, BACKUP THE USER PC, AND CONTINUE AS THOUGH THE UUO HADN'T
;BEEN EXECUTED. "$P" WILL RE-EXECUTE THE UUO.

CDBRK5:	MOVSI	T3,(JS.HIB)	;THE STUPID HIBER BIT
	TDNE	T3,JBTST2##(J)	;WAS IT A HIBER UUO?
	HRRI	T2,-1(T2)	;ACCOUNT FOR HIBER'S STUPID AOS
	HRRI	T2,-1(T2)	;BACKUP USER PC TO POINT TO THE UUO
	XMOVEI	T4,USRPC##	;ASSUME NON-SCHEDULED JOB
	CAMN	J,.CPJOB##	;CURRENTLY-SCHEDULED JOB?
	XMOVEI	T4,.CPPC##	;YES (???HUH??? CAN THIS HAPPEN???)
	PUSHJ	P,CDBRK2	;SIMULATE THE "JSR" FOR THE "JSR @.JBBPT"
	 POPJ	P,		;PC FROM WITHIN DDT? FLICK IT IN
	LDB	T3,PJBSTS##	;GET JOB WAIT CODE (IF ANY)
	CAIL	T3,MINQ##	;SHARABLE RESOURCE WAIT?
	CAILE	T3,MAXQ##	;AND DOES STATE ALSO HAVE A Q?
	JRST	CDBRK6		;NO
	SOSL	RQTBMQ(T3)	;YES, REDUCE IT
	JRST	CDBRK6		;NO
	SOSGE	AVTBMQ(T3)	;YES, REDUCE COUNT
	SETZM	AVTBMQ(T3)	;CLEAR AVAILABLE FLAG IF NO ONE ELSE WAITING
CDBRK6:	MOVEI	T3,RNQ##	;THE RUN QUEUE
	DPB	T3,PJBSTS##	;POOF! THE JOB IS NOW RUNNABLE!
	TLO	M,TTYRNU##	;TELL COMCON TO RUN TTYUSR ON RETURN
				; THIS WILL DO MANY AND WONDROUS THINGS
				;  PUT TTY IN USER MODE (BREAK FROM TTCALL)
				;  SET NEW QUANTUM RUN TIME
				;  REQUE THE JOB, ETC.
	JRST	CPOPJ1##	;SUCCESS RETURN TO COMCON
;SUBROUTINE TO SEE IF USER PC IS IN DDT.
;CALL IS:
;
;	D/MOVE	T1,<PC>
;	PUSHJ	P,INDDT
;	 PC IS IN DDT
;	PC IS NOT IN DDT
;
;WHERE PC IS ONE-WORD PC IF KI-STYLE PAGING, TWO-WORD PC IF KL-STYLE
;PAGING (ASSUMES STUCK IN SECTION 0).
;
;USES T3.

INDDT::	PUSHJ	P,SAVE2##	;NEED A COUPLA SCRATCH ACS HERE
	HRRZ	T3,T2
	HRRZ	P1,.JDAT+JOBDDT##  ;GET START ADDRESS OF DDT
	HLRZ	P2,.JDAT+JOBDDT##  ;GET END ADDRESS OF DDT(PLUS 1)
	CAML	T3,P1		;USER PC IN DDT?
	CAML	T3,P2		; . . .
	JRST	CPOPJ1##	;NO
	JUMPN	P1,CPOPJ##	;YES
	JRST	CPOPJ1##	;NO
;SUBROUTINE TO SET UP AN INTERCEPT
;CALL WITH T4=INTERCEPT BIT
;EXIT NON-SKIP IF NOT ENABLED
;SKIP-RETURN IF ENABLED, SET TO TRAP ON UUO EXIT
; (OR START AT TRAP LOC IF IN USER MODE).
SETINT::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
SETPIT:	PUSH	P,T1		;SAVE PC
	GETPC	T2,USRPC##	;YES--GET CURRENT PC
	TLNE	T2,USRMOD	;SEE IF EXEC MODE
	JRST	SETPIU		;NO--DO USER MODE
	SETOM	T1		;SET DOINT FLAG
	PUSHJ	P,SETUTP	;YES--SET IF NEEDED TO TRAP UUO
	  JRST	SETPIU		;NO--GO START JOB
	POP	P,T2		;THROW AWAY PC
	JRST	CPOPJ1##	;ALL DONE UNTIL UUO EXIT

;HERE WHEN UUO NOT IN PROGRESS
SETPIU:	PUTPC	T2,USRPC##	;SETUP JOBPC FOR USTART
	PUSHJ	P,CLRTI##	;GET DDB OUT OF TI WAIT
	POP	P,T2		;GET START PC
	PUSH	P,.JDAT+JOBOPC## ;SAVE OPC FOR USER
IFN FTXMON,<
	HRRZS	T2		;AVOID ILLEGAL SECTION PAGE FAULTS
>
	PUSHJ	P,USTART	;START IN USER MODE
	MOVE	T1,.JDAT+JOBOPC## ;GET OLD PC
	POP	P,.JDAT+JOBOPC## ;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
;ROUTINE TO DECREASE # OF USERS WHO DON'T WANT THIS JOB TO ^C OUT
;AND CHECK VALUE

DECCCC::
	PUSH	P,T1		;SAVE AC
	MOVSI	T1,1
	ADDB	T1,JBTCCC##(J)	;INCREMENT
	JUMPL	T1,TPOPJ##	;IF STILL NEGATIVE, OK
	TRNE	T1,-1		;OR IF ZERO, OK
	STOPCD	DECCC1,DEBUG,CCW, ;++CONTROL-C COUNT WRONG
	JRST	TPOPJ##		;RETURN

DECCC1:	HRRZS	JBTCCC##(J)	;FIX COUNT
	JRST	TPOPJ##		;RETURN
;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)

SIMCHK::SKIPGE	JBTCCC##(J)	;SOMEONE WANT HIM STUCK?
	AOSA	(P)		;YES, NEVER LET HIM GO
	SKIPL	T1,JBTSTS##(J)	;JOB STATUS. IS RUN BIT OFF?
	POPJ	P,		;YES, STOP JOB BUT DO NOT PRINT WATCH STATUS
	TLNE	T1,JERR		;IS ERROR BIT ON?
	TRNE	T1,JS.RUU	;AND NOT IN RUN/GET CODE?
	CAIA			;NO TO ONE OF ABOVE, SO SKIP ON
	POPJ	P,		;JERR AND NOT IN RUN/GET, SO STOP JOB NOW
	TLNN	T1,SWP		;IS JOB IN CORE?
	SKIPN	JBTADR##(J)	;YES, DOES JOB HAVE CORE IN CORE?
	JRST	STOPC		;NO. ASSUME PC IN EXEC MODE
	DMOVE	T1,USRPC##	;YES, GET PC
	CAMN	J,.CPJOB##	;IS THIS JOB THE CURRENT JOB?
	DMOVE	T1,.CPPC##	;YES, GET PC AND FLAGS FOR CURRENT JOB
	TLNE	T1,USRMOD	;JOB PC IN USER MODE?
	POPJ	P,		;YES, JOB CAN BE STOPPED
	HRRZ	T1,T2		;PC

	CAIN	T1,UUODON##	;AT THE END OF A UUO?
	POPJ	P,		;YES, STOP JOB RETURN
STOPC:
STOPD:	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
	TDNE	T2,DELAYN	;NO, IS JOB IN A STATE(IN EXEC) WHICH
				; CAN BE STOPPED IMMEDIATELY
	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
	LDB	T1,PJBSTS##	;GET STATE CODE
	CAIE	T1,EWQ##	;EVENT WAIT QUEUE?
	POPJ	P,		;NO, GO STOP JOB
	LDB	T2,JBYEWT##	;GET REASON CODE
	MOVE	T1,EWCCMK	;GET MASK OF BITS TO SEE IF DELAY OR STOP
	LSH	T1,-1(T2)	;SHIFT BIT TO BIT 0 POSITION
	PJUMPL	T1,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
	POPJ	P,		;STOP JOB
;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


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

;DEFINE A BIT FOR EACH EVENT WAIT CODE
; WHICH INDICATES WHETHER TO DELAY OR STOP THE JOB.
; 1 = DELAY (DJ), 0 = STOP (SJ)

DEFINE	X(SYM,CODE),<
	SYM==SYM			;;FORCE INTO SYMBOL TABLE
	IFIDN	<CODE><SJ>,<QQ==0>	;;STOP
	IFIDN	<CODE><DJ>,<QQ=1>	;;DELAY
	YY==ZZ*QQ			;;SET THIS TO 1 OR 0
	XX==XX!YY			;;ACCUMULATE VALUES IN XX
	ZZ==ZZ_<-1>			;MOVE MASK BIT RIGHT ONE PLACE
>;END DEFINE X
	QQ==0				;MAKE SURE INTERMEDIATE VALUE IS 0
	XX==0				;START FINAL VALUE AT 0
	ZZ==1B0				;START WITH BIT 0 AND SHIFT RIGHT
	EWCODE				;GENERATE BIT MASK IN XX

EWCCMK:	EXP	XX			;EVENT WAIT CODE BIT MASK WITH
					; BIT ON IF JOB IS TO BE DELAYED,
					; OR OFF IF IT IS TO BE STOPPED
					; BITS GO FROM LEFT TO RIGHT
					; IE, EV CODE 1 IS BO, 2 IS B1.
;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


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	CHKUT1		;NO, CHECK FOR EVENT WAIT
	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

CHKUT1:	CAIE	T3,EWQ##	;EVENT WAIT?
	JRST	CPOPJ1##	;NO--DELAY
	PUSH	P,T1		;SAVE T1
	LDB	T1,JBYEWT##	;GET STATE SUB-CODE
	MOVE	T3,EWCCMK	;GET MASK BITS
	LSH	T3,-1(T1)	;POSITION TO SIGN BIT
	JUMPL	T3,TPOPJ1##	;BIT SET--DELAY TRAP
	JRST	TPOPJ##		;BIT CLEAR--OKAY TO TRAP NOW
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,.JDAT+JOBFDV##	;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


DLYCOM::MOVSI	T1,CMWB		;SET COMMAND WAIT BIT
	TDNE	T1,JBTSTS##(J)	;IS JOB ALREDY IN COMMAND WAIT?
	POPJ	P,		;YES,JUST EXIT

	IORM	T1,JBTSTS##(J)	;IN JOB STATUS WORD

	PJRST	REQUE


;ROUTINE TO PUT JOB IN NO CORE QUEUE



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
;	JSP	T2,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
; 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"

SAVCTD::TLNE	P4,SWP!SHF	;JOB IN CORE?
	JRST	DLYCM		;NO, WAIT UNTIL IT COMES IN
SAVCTX::SKIPGE	JBTSTS##(J)	;JOB RUNNING OR RUNNABLE?
	JRST	SAVCT3		;YES, FLUNK OUT NOW
	SKIPN	JBTADR##(J)	;DOES THIS JOB HAVE CORE?
	S0PSHJ	GETCIC##	;NO, ASSIGN A MINIMAL AMOUNT
	PUSHJ	P,FNDPDS##	;ADDRESS OF THE PDB
	PUSHJ	P,SAVCTS	;GO DO THE REAL WORK
	  JRST	DLYCM##		;CORE NOT AVAILABLE YET, CAN'T SAVE CONTEXT
	  JRST	ABORTC##	;WORKED

;RETURN HERE AT UUO LEVEL
;RETURN HERE AT UUO LEVEL
	MOVE	J,.CPJOB##	;CURRENT JOB'S JOB NUMBER
	HRRZ	W,JBTPDB##(J)	;ADDRESS OF THE PDB
	HRRZ	T1,.PDSCX##(W)	;ADDRESS OF THE SAVED CONTEXT
	MOVE	T2,.SCPPC(T1)	;THE JOB'S PC WHEN STOPPED
	MOVE	T3,.SCJST(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,.JDAT+JOBDPD## ;NO, USE THE CURRENT STACK POINTER IF THERE IS ONE
	MOVE	P,[MJOBPD##,,.JDAT+JOBPDL##] ;YES OR NO EXEC STACK POINTER,
				; SO SETUP THE STACK TO POINT AT THE
		 		; JOB'S JOB DATA AREA
	PUSHJ	P,TTYFNU##	;FIND OUR TTY
	  JUMPE	U,ESTOP3	;IF NOT ATTACHED, GIVE UP AND STOP THE JOB
	HRRZ	T1,.PDSCX##(W)	;RESTORE THE ADDRESS OF THE CONTEXT BLOCK
	MOVEM	U,.CPCML##	;SEE STOPCM IN SCNSER
	MOVE	S,.SCCIT(T1)	;SETUP ITEM TO BE RETURNED
	TLO	M,400000	;INDICATE THIS IS A COMMAND
	PUSHJ	P,@.SCCPC(T1)	;CALL THE CALLER TO SAVCTX AS A SUBROUTINE
	  JFCL			;ALLOW A SKIP RETURN AS A CONVENIENCE
	PUSHJ	P,TTYFUW##	;FIND OUR TTY, U := ZERO IF DETACHED
	PUSHJ	P,FNDPDS##	;ADDRESS OF THE PDB
	PUSHJ	P,RESCTS	;RESTORE CONTEXT
	PUSH	P,T1		;SAVE PC
	PUSH	P,T2		;SECOND HALF
	PUSH	P,T3		;SAVE JBTSTS
	JUMPE	U,SAVCT4	;DON'T TYPE IF DETACHED
	PUSHJ	P,PRDOTM##	;OUTPUT A PERIOD
	PUSHJ	P,TTYSTC##	;START TTY,LEAVE AT MONITOR LEVEL
SAVCT4:	POP	P,T1		;RESTORE PREVIOUS JBTSTS
	;JUMPE	U,ESTOP3	;IF WE'RE DETACHED, JUST STOP THE JOB
	TLNE	T1,JERR		;WAS THE JOB IN A CONTINUABLE STATE?
	JRST	[HRRZS .JDAT+JOBPD1## ;NO, STOP THE JOB AND DON'T ALLOW CONTINUE
		PJRST ESTOP]
	PUSHJ	P,ESTOP3	;YES, ITS STILL CONTINUABLE
	POP	P,T2		;PC
	POP	P,T1		;FLAGS
	DMOVEM	T1,.CPPC##	;STORE FOR SCHEDULER
	PJRST	USCHE1		;SAVE SOME ACS AND RESCHEDULE
SAVCT3:	MOVEI	T1,RUNERR##	;"PLEASE TYPE ^C FIRST"
	PJRST	ERRMES##	;PRINT THAT AND RETURN TO COMCON
;HERE TO DO THE REAL CLOCK LEVEL WORK.  SWAPPER AND SAVCTX USE THIS
;(SWAPPER FOR MAPBAK).  CALL IS:
;
;		MOVEI	T2,<TOP LEVEL PC TO RETURN TO AT UUO LEVEL>
;		PUSHJ	P,SAVCTS
;		  <CAN'T GET CORE>
;		  <SET UP TO RUN AT .+1 AT UUO LEVEL>
;		<HERE AT UUO LEVEL>
;OTHER ITEMS (I.E. S) AS SET UP FOR SAVCTX


SAVCTS::PUSH	P,T2		;SAVE HIS CALLER'S PC
	HRRZ	T1,.PDSCX##(W)	;ALREADY BEEN HERE ONCE?
	JUMPE	T1,SAVCT1	;JUMP IF NO
	MOVE	T2,.SCDAC+P(T1)	;SAVED PUSH DOWN LIST POINTER
	MOVEM	T2,.JDAT+JOBDPD## ;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	T2POPJ##	;CAN'T DO ANYTHING NOW
	MOVE	T2,JBTSTS##(J)	;THE JOB'S CURRENT STATUS
	MOVEM	T2,.SCJST(T1)	;SAVE THAT
	DMOVE	T2,USRPC##	;THE JOB'S CURRENT PC
	DMOVEM	T2,.SCPPC(T1)	;SAVE THAT TOO
	MOVSI	T2,.JDAT+JOBDAC## ;MAKE A BLT POINTER TO THE JOB'S
	HRRI	T2,.SCDAC(T1)	; USER AND EXEC ACS
	BLT	T2,.SCDAC+17(T1) ;SAVE THE JOB'S ACS
SAVCT2:	MOVEM	S,.SCCIT(T1)	;STORE ITEM TO BE RETURNED TO THE CALLER
	POP	P,.SCCPC(T1)	;STORE THE CALLER'S PC
	HRRM	T1,.PDSCX##(W)	;REMEMBER THE ADDRESS OF THE BLOCK CONTAINING
				; THE JOB'S CONTEXT
	MOVEM	M,.SCCCF(T1)	;SAVE FLAGS FOR PRDOTM (EXAMINE COMMAND)
	TLO	M,NOFLM##!LHRUNF##	;TTYRNU+NOMESS+NOCRLF+NOPER+NOFLM
	TLZ	M,NOINCK##	;MAKE SURE JNA GETS TURNED ON SO JOB
				; CORE IMAGE, ETC. WILL GO AWAY IF NOT LOGGED IN
	AOS	T2,(P)		;RETURN ADDRESS
	AOJA	T2,MSTART	;SET UP FOR UUO LEVEL AND RETURN

;HERE TO RESTORE THINGS SET UP BY SAVCTS
;RETURN WITH T1, T2 CONTAINING SAVED PC AND T3 CONTAINING SAVED JBTSTS

RESCTS::HRRZ	T2,.PDSCX##(W)	;ADDRESS OF THE JOB'S SAVED CONTEXT
	PUSH	P,.SCPPC(T2)	;THE SUSPENDED JOB'S FLAGS
	PUSH	P,.SCPPC+1(T2)	;THE SUSPENDED JOB'S PC
	MOVSI	T1,.SCDAC(T2)	;FORM A BLT POINTER
	HRRI	T1,.JDAT+JOBDAC## ; TO THE JOB'S SAVED ACS
	BLT	T1,.JDAT+JOBD17## ;RESTORE THE JOB'S SAVED ACS
	PUSH	P,.SCJST(T2)	;JOB'S PREVIOUS JBTSTS
	MOVE	M,.SCCCF(T2)	;ORIGINAL M (FOR FLAGS)
	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,T3		;RESTORE PREVIOUS JBTSTS
	JRST	TTPOPJ##	;PUT PC IN T1,T2 AND RETURN
;SUBROUTINE TO ZERO F, F IN THE DUMP AC'S, AND F IN THE JOB'S
;SAVED CONTEXT, IF ANY
;CALLING SEQUENCE:
;	MOVE	J,JOB NUMBER
;	MOVEI	F,DDB ADDRESS
;	PUSHJ	P,DMPFZR
DMPFZR::PUSHJ	P,SAVJW##	;PRESERVE J
	MOVE	J,.USJOB	;SET UP TO FIND PDB OF RIGHT JOB
	PUSH	P,T1		;SAVE T1
	PUSHJ	P,FNDPDS##	;FIND JOB'S PDB
	HRRZ	T1,.PDSCX##(W)	;ADDR OF SAVED CONTEXT
	JUMPE	T1,DMPFZ1	;JUMP IF NONE
	PUSH	P,T2		;SAVE T2
	HRRZ	T2,.SCDAC+F(T1)	;GET RH OF F IN SAVED CONTEXT
	CAIN	T2,(F)		;SAME AS ONE WE ARE RETURNING?
	SETZM	.SCDAC+F(T1)	;YES, ZERO F IN SAVED CONTEXT
	POP	P,T2		;RESTORE T2
DMPFZ1:	SETZB	F,.JDAT+JOBDAC##+F ;ZERO F & DUMP AC F
	PJRST	TPOPJ##		;RESTORE T1 & RETURN
;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


MONJOB::
IFN FTMP,<
	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.; 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,W,M, AND J SETUP


MONSTR::SKIPN	J,.CPJOB##	;CURRENT JOB NUMBER
	STOPCD	.,STOP,NDS,	;++NULL-JOB DID SAVGET
	MOVSI	P,MJOBPD##	;MINUS LENGTH OF SYSTEM PD LIST
	HRRI	P,.JDAT+JOBPDL##	;FIRST LOC.-1 OF PD LIST
	PUSHJ	P,FNDPDB##	;ADDRESS OF PDB FOR THIS JOB
	  JFCL
IFN FTMP,<
	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
	MOVE	T2,[IOW,,IOACT]	;JOB IS NOT IN TIOW WHEN RUNNING THE MONITOR JOB
	SKIPE	T3,TTYTAB##(J)	;SO IF THE JOB HAS A TTY, CLEAR IOW
	ANDCAM	T2,DEVIOS(T3)	;SINCE A CALL TO STTIOD WILL ZAP WAIT STATE CODES
	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
;	PUSHJ P,USTART(PC TO USER MODE),MSTART(PC TO MONITOR MODE)
;	RETURN HERE IMMEDIATELY


USTART::GETPC	T1,USRPC##	;GET OLD PC
	TLNE	T1,USRMOD	;IS IT IN USER MODE TOO?
	JRST	USTRT1		;YES, DUMP ACS AND PC FLAGS ARE ALREADY HIS
	GETPC	T1,.JDAT+JOBPD1## ;GET LAST PC + 1
	HRRI	T1,-2(T1)	;ASSUME HE DID A HIBER
	PUSH	P,T2
	MOVSI	T2,(JS.HIB)	;WAS HE HIBERNATING?
	TDNN	T2,JBTST2##(J)
	HRRI	T1,1(T1)	;NO, DON'T DECREMENT TWICE
	POP	P,T2
USTRT1:	MOVEM	T1,.JDAT+JOBOPC##	;STORE OLD PC FOR USER TO LOOK AT
IFN FTMP,<
	PUSHJ	P,DPXST##	;MAKE JOB RUNNABLE ON SLAVE NOW
>
	MOVE	T1,USRPC##
	TLNN	T1,USRMOD
	MOVE	T1,.JDAT+JOBPD1##
	TLO	T1,(XC.USR+IFN FTKL10,<XC.PUB>)
	TLZ	T1,37
	JRST	MSTRT1		;DON'T CLEAR JSP WORD
MSTART::
IFN FTXMON,<
	MOVSI	T1,MXSECN
	ANDCAM	T1,.USUPF	;ALWAYS START MONITOR JOB WITH PCS=0
>
	MOVSI	T1,(IC.UOU)
	TLZ	T2,777740

IFN FTMP,<
	PUSHJ	P,CLRJSP##	;INITIALIZE JBTSPS ENTRY
>
MSTRT1:	CAMN	J,.CPJOB##	;IS IT THE CURRENTLY RUNNING JOB?
	DMOVEM	T1,.CPPC##
	DMOVEM	T1,USRPC##
	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.DPM] ;CLEAR TYPED ^C FLAG
				; CLEAR MEM PAP ERR, DAEMON PROBLEM MESSAGE
	ANDCAM	T1,JBTSTS##(J)	;IN JOB STATUS WORD
	MOVSI	T1,(JS.HIB)	;CLEAR HIBER 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


SETRUN::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
	CAIL	T1,MINQ##	;SHARABLE RESOURCE STATE CODE?
	CAILE	T1,MAXQ##	;DOES JOB STATUS CODE HAVE A QUEUE?
	JRST	SETR1		;NO
	CAIE	T1,AUQ##	;HAVE AU?
	CAIN	T1,DAQ##	;OR DA?
	STOPCD	.,STOP,CCR,	;CAN'T CONTINUE WITH RESOURCE
	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&FTMP,<
	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
	HRRZ	T2,JBTPDB##(J)
	SKIPN	T2
	STOPCD	.,JOB,CFP,	;++CAN'T FIND PDB
	.DPB	T1,PDYQT2##	;SET QUANTUM RUN TIME


REQUE::	CAIG	J,JOBMAX##	;TOO HIGH?
	SKIPN	J		;TRYING TO REQUEUE THE NULL JOB?
	STOPCD	CPOPJ##,DEBUG,RJ0,	;++REQUEUE JOB 0
	MOVSI	T1,JRQ		;MARK JOB TO BE REQUEUED WITH JRQ BIT
	SYSPIF			;GUARD AGAINST COUNTING QJOB UP TWICE
	TDNE	T1,JBTSTS##(J)	;INCREMENT COUNT ONLY ONCE FOR EACH JOB
	JRST	ONPOPJ##	;JOB IS ALREADY MARKED FOR REQUEING
	IORM	T1,JBTSTS##(J)	;SET REQUE BIT FOR SCHEDULER
	CAMN	J,JBTJRQ##	;ABOUT TO CAUSE SCHEDULER LOOP?
	STOPCD	ONPOPJ##,DEBUG,RSJ, ;++REQUEUE SAME JOB
	MOVE	T1,JBTJRQ##
	HRRZM	J,JBTJRQ##
	MOVEM	T1,JBTJRQ##(J)
	SYSPIN			;TURN ON
	PJRST	NJBTST		;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
	SYSPIF			;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
	SYSPIN			;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
	HRRZ	J,T1		;JOB # TO J
	MOVEI	T1,RNQ##	;RUN QUEUE
	SYSPIF			;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)
	SYSPIN
	PJRST	JPOPJ##		;EXIT
;SUBROUTINE TO SET TIME USER STARTED TO WAIT FOR RESPONSE
; IF NOT ALREADY CALLED WHEN A COMMAND IS DELAYED

IFN	FTRSP,<

SETRSP::MOVE	T1,SYSUPT##	;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,.CPAOR##	;BASE ADR FOR 3 WORD TTY OUTPUT UUO RSP
	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,.CPAIR##	;BASE ADR. FOR 3 WORD TTY INPUT UUO RSP
	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	J,JOB NUMBER
;	MOVEI	T1,.CPA??##	;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::MOVE	J,.CPJOB##	;CURRENT JOB ON CPU0
RSPRC2::PUSHJ	P,RSPREC	;RECORD THIS RESPONSE
	MOVEI	T1,.CPAXR##	;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,SYSUPT##	;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.
	SYSPIF			;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
	SYSPIN			;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
MTIMLM:	PUSHJ	P,TTYERP##	;LIMIT JUST WENT TO 0 - FIND TTY DDB
	  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
	MOVE	T3,JBTLIM##(J)	;GET BATCH LIMIT WORD
	TLNN	T3,(JB.LBT)	;A BATCH JOB?
	JRST	HOLD0		;NO--STOP JOB, DON'T ALLOW CONTINUE
	PUSHJ	P,CTLJBD##	;FIND THE CONTROLLING JOB
	SE1XCT	<LDB T2,LDPMJN##>	;GET LINES MIC MASTER JOB NUMBER
	CAME	T1,T2		;IF CONTROLLING JOB NUMBER MATCHES MIC
				; MASTER JOB NUMBER, THEN THIS IS A MIC
				; COJOB AND WE DON'T WANT TO ZAP MIC
				; MIC STATUS. (COJOBS DON'T CARE ABOUT TIME
				; LIMIT EXCEEDED.
	SE1XCT	<SETZM LDBMIC##(U)>	;PREVENT MIC FROM MESSING WITH A REAL
				; "BATCON" BATCH JOB
	JRST	HOLD0		;STOP JOB, DONT SET JERR
				; (SO "CONT" WILL WORK)
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
;ROUTINE TO PUT A JOB TO SLEEP AND WAKE UP AGAIN LATER
;CALLED AFTER CLOCK QUEUE REQUEST PUT IN BY UUO ROUTINE



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 IF ALREADY THE WAIT STATE CODE SET UP (HIBER)

SETHBR::MOVEI	T1,CLKR
	IORM	T1,JBTSTS##(J)	;SAY WE SET THE REQUEST
	PUSHJ	P,SETSTX	;WAIT
	CLKLOK			;HERE ON RETURN, KILL ANY DANGLING CLOCK REQS
	MOVE	T1,.CPJCH##	;JCH
	MOVEI	T4,CTXWKJ##	;ROUTINE ADDRESS
	PUSHJ	P,CLKFND	;IS THERE ONE?
	  JRST	SETHB4		;NO, JUST RETURN (AOS'D EARLIER)
	SYSPIF			;LOCK OUT CHANGES
	MOVE	T1,@CLOCK	;MOVE LAST ENTRY TO THIS SLOT
	MOVEM	T1,1(T2)
	SOS	CLOCK
	MOVE	T1,@CLOCK
	MOVEM	T1,(T2)
	SOS	CLOCK		;DECREMENT
	SYSPIN
SETHB4:	CLKNLK			;UNLOCK CLOCK QUEUE
	POPJ	P,


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


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.
	DPB	T2,PJBSTS##	;YES, MAKE HIM RUNNABLE AGAIN
	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


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 LOG AN ERROR BUT NOT BLOCK THE JOB
;CALL:	MOVE	J,JOB NUMBER
;	MOVEI	T1,CODE FOR THIS ERROR
;	HRLI	T1,CDB OR DDB ADDRESS
;	PUSHJ	P,DAEDSJ##
;	ALWAYS	RETURN

DAEDSJ::PUSH	P,J		;SAVE J
	DPB	J,[POINT 9,T1,26] ;STORE IN CODE WORD
	PUSHJ	P,DAEEIM	;LOG IT BUT DON'T STOP JOB
	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,PI.OFF	;NEED TO TURN OF PI'S TO STOP TWO I
IFN FTMP,<
	SKIPGE	DAELOK		;DON'T TRY IF CAN'T POSSIBLY GET IT
	AOSE	DAELOK		;GET CPU INTERLOCK
	JRST	.-2		;WAIT UNTIL AVAILABLE
>
	MOVE	T2,ERPSIZ##	;GET SIZE OF ERPTBK ENTRY
	ADDB	T2,ESVIDX##	;GET INDEX FOR NEXT ERROR TO SAVE
	CAIL	T2,ERPTMX##	;HAVE WE EXCEEDED MAX
	SETZB	T2,ESVIDX##	;YES, JUST RESET ESVIDX
IFN FTMP,<
	SETOM	DAELOK
>
	CONO	PI,PI.ON
	SKIPE	ERPTBK##(T2)	;HAVE WE OVERLAPPED
	JRST	MNYERR		;YES, DAEMON ISN'T KEEPING UP, LOSE THIS ERROR
	TRNE	J,-1		;DON'T STORE JOB NUMBER IF ZERO
	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)
	MOVS	T1,.CPCPN##	;GET CPU NUMBER OF THIS CPU
	TRO	T1,777		;SET TO WHAT LOOKS LIKE A JUNK
	MOVEM	T1,ERPTBK##+2(T2) ; CODE TO OLD VERSIONS OF DAEMON FOR COMPATABILITY
	SETZM	ERPTBK##+3(T2)	;ZERO FINAL WORD
	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,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
;ROUTINE TO FIND DAEMON, START RUNNING
;RETURNS POPJ IF CANT FIND, CPOPJ1 IF OK, T1 = DAEMON JOB #

STDAEM::MOVEI	T1,1		;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
	TLNE	T2,JACCT
	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:	CAMG	T1,HIGHJB##	;LOOP FOR MORE JOBS
	AOJA	T1,STDAE1
	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

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?
	CAIA			;START USER IF RUNNABLE
	POPJ	P,		;RETURN
	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.
;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
	PUSHJ	P,SAVE1##	;SAVE PI
	CAIL	T2,ERPTMX##	;OFF END OF TABLE?
	SETZ	T2,		;YES, RESET POINTERS
	HRR	M,T1
	HLRZ	P1,T1		;GET LENGTH
	CAIGE	P1,2		;LESS THAN 2?
	MOVEI	P1,2		;YES, OLD DAEMON
	CAMLE	P1,ERPSIZ##	;LARGER THAN ENTRY SIZE?
	MOVE	P1,ERPSIZ##	;YES, MAKE IT ENTRY SIZE
	MOVNI	P1,-1(P1)	;GET -VE COUNT FOR AOBJP POINTER
	HRLZS	P1		;MAKE AOBJP POINTER TO ARGS .GT. 2
ERPTLP:	SKIPE	T1,ERPTBK##(T2)	;IS THIS ENTRY 0?
	JRST	GOTONE		;NO, RETURN IT
	ADD	T2,ERPSIZ##
	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##
	HRR	P1,T2		;POINT TO ENTRY WITH P1
ERPLP1:	AOBJP	P1,ERPLPE	;DONE IF COUNT RAN OUT
	MOVE	T1,ERPTBK##+1(P1) ;GET NEXT ENTRY
	PUSHJ	P,PUTWD1##	;GIVE IT TO DAEMON
	JRST	ERPLP1		;LOOP FOR NEXT
ERPLPE:	ADD	T2,ERPSIZ##
	MOVEM	T2,EPKIDX##	; AND SAVE FOR WHERE TO LOOK NEXT
	JRST	CPOPJ1##	;AND SKIP
;SUBROUTINE TO CALL DAEMON FOR DEBUG OR JOB STOPCD
;DOES NOT TRY TO STOP ANY JOB
DAEEST::MOVEI	T1,41		;LENGTH OF STOPCODE ENTRY
	PUSHJ	P,ALCSEB##	;GET A SYSTEM ERROR BLOCK
	  POPJ	P,		;COULDN'T? DON'T LOG IT
	MOVEI	T2,.ERMSE	;GET CODE FOR DAEMON
	DPB	T2,[POINT 9,.EBTYP(T1),8] ;STUFF IT IN ENTRY
	MOVE	T3,.CPJOB##	;GET RUNNING JOB NUMBER
	MOVSI	T2,CONFIG##	;BUILD BLT POINTER
	HRRI	T2,.EBHDR(T1)	;TO COPY SYSTEM NAME
	BLT	T2,.EBHDR+6(T1)	;(R0-R6) AND DATE
	XMOVEI	T2,.EBHDR+6(T1)	;POINT TO NEXT PLACE FOR ITEMS
	PUSH	T2,.CPASN##	;(R7) CPU SERIAL NUMBER
	PUSH	T2,MONVER##	;(R10) MONITOR VERSION NUMBER
	PUSH	T2,%SYSCD##	;(R11) STOPCODE NAME
	PUSH	T2,T3		;(R12) JOB NUMBER
	PUSH	T2,@TTYTAB##(T3)	;(R13) TTY NAME
	PUSH	T2,JBTPRG##(T3)	;(R14) PROGRAM NAME
	PUSH	T2,JBTPPN##(T3)	;(R15) PPN
	PUSH	T2,%SYNJS##	;(R16) NUMBER OF JOB STOPCODES
	PUSH	T2,%SYNDS##	;(R17) NUMBER OF DEBUG STOPCODES
	HRLZ	T2,.CPACA##
	HRRI	T2,.EBHDR+20(T1)	;SET UP TO COPY ACs WHICH WERE ACTIVE
	BLT	T2,.EBHDR+37(T1)	;(R20-R37) AT TIME OF STOPCODE
	MOVE	T2,.CPCPI##		;GET PI STATUS
	MOVEM	T2,.EBHDR+40(T1)	;(R40) AND SAVE IT
	JRST	QUESEB##	;QUEUE THE ERROR BLOCK AND KICK DAEMON
;SUBROUTINE TO CALL DAEMON FOR ANY ERROR TO BE REPORTED
;DURING STOPCD PROCESSING.
;ARGS SAME AS DAEEIM.
DAEDIE::
IFN FTMP,<
	MOVEI	T2,^D100	;MAX COUNT TO WAIT FOR INTERLOCK
	SKIPGE	DAELOK		;DON'T TRY IF CAN'T POSSIBLY GET IT
	AOSE	DAELOK		;GET INTERLOCK
	SOJG	T2,.-2		;FAILED, LOOP BUT NOT TOO LONG
>;END IFN FTMP
	MOVE	T2,ERPSIZ##	;GET SIEZ OF ENTRY
	ADDB	T2,ESVIDX##	;GET INDEX FOR NEXT ERROR TO SAVE
	CAIL	T2,ERPTMX##	;HAVE WE EXCEEDED MAX
	SETZB	T2,ESVIDX##	;YES, JUST RESET ESVIDX
IFN FTMP,<
	SETOM	DAELOK		;RELEASE INTERLOCK
>
	SKIPE	ERPTBK##(T2)	;HAVE WE OVERLAPPED
	JRST	MNYERR		;YES, DAEMON ISN'T KEEPING UP, LOSE THIS ERROR
	DPB	J,[POINT 9,T1,26] ;PUT IN JOB NUMBER
	MOVEM	T1,ERPTBK##(T2)	;SAVE T1 FOR ERRPT. UUO
	MOVE	T1,U
	HRL	T1,F
	MOVEM	T1,ERPTBK##+1(T2)
	MOVS	T1,.CPCPN##	;GET CPU NUMBER OF THIS CPU
	TRO	T1,777		;JUNK CODE FOR COMPATABABILITY WITH OLD DAEMON'S
	MOVEM	T1,ERPTBK##+2(T2) ;STORE IN BLOCK
	SETZM	ERPTBK##+3(T2)	;CLEAR LAST WORD
	POPJ	P,


IFN FTMP,<
	$LOW
DAELOK:	-1			;INTERLOCK TO PREVENT MORE THAN ONE
				;CPU IN A MULTIPROCESSOR SYSTEM FROM
				;GETTING TO DAEDIE AT THE SAME TIME.
				;THE SYSPIF INTERLOCK IS NOT USED HERE
				;BECAUSE WAITING FOR THE INTERLOCK MAY
				;HAVE CAUSED THE CRASH.
	$HIGH
>
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


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


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

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

DVWAIT:	RWAITS
SRWAIT:	MOVEM	16,.JDAT+JOBD16##	;SAVE AC16 (SINCE IT IS A PRESERVED AC)
	MOVEM	17,.JDAT+JOBD17##	;ALSO AC17
	POP	P,16		;GET ENTRY ADDRESS
	MOVEI	16,-DVWAIT+MQ-1(16)	;COMPUTE WAIT-STATE QUEUE CODE
	MOVE	17,.CPJOB##	;PICK UP JOB NUMBER
	CPLOCK	(SCD)
	AOSG	REQTAB##-MQ(16)	;IS THE RESOURCE AVAILABLE?
	JRST	SRAVAL		;YES, GO USE IT
SETSTT:	MOVE	17,.CPJOB##	;JOB NUMBER OF RESOURCE REQUESTER
	DPB	16,PJBS3	;STORE QUEUE CODE IN JOB STATUS
SETSTX:
	MOVE	16,.JDAT+JOBD16##	;RESTORE AC16
IFN FTMP,<
	PUSHJ	P,SCDOWN##	;OWN?
	  CPUNLK (SCD)
> ;END IFN FTMP
	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:	 CPUNLK (SCD)
IFN FTMP,<
	SETZM	AVALTB-MQ(16)	;MMAVAL COULD BE -1 IF ONE
				; CPU WAS IN GETMM WHILE
				; ANOTHER CPU IS IN SRFREE
>
	MOVE	17,.CPJOB##	;JOB NUMBER OF RESOURCE OWNER
	CAIE	16,CBQ##		;ALWAYS GIVE THE JOB THE CB RESOURCE
	SKIPE	DINITF		;IF ONCE
	JRST	SRAVL0		; ONLY
	PUSH	P,T3		;PRESERVE T3
	MOVE	T3,JBTSTS##(17)	;JOB STATUS
	TLNN	T3,JXPN		;EXPANDING?
	CAMN	17,FORCEF##	;OR BEING FORCED OUT?
	JRST	SRAVL2		;YES, CHECK FUTHER
SRAVL1:	POP	P,T3		;RESTORE T3
SRAVL0:	MOVEM	17,USRTAB##-MQ(16);REMEMBER IT SO RESOURCE CAN BE GIVEN
				; UP IN THE EVENT OF A CATASTROPIC ERROR
	MOVE	17,.JDAT+JOBD17##	;RESTORE AC17
	MOVE	16,.JDAT+JOBD16##	;AND AC16
	POPJ	P,		;RETURN TO THE CALLER WITH THE
				; REQUESTED RESOURCE
SRAVL2:	PUSH	P,J		;PRESERVE J
	MOVE	J,17		;JOB NUMBER FOR FLDSR
	PUSHJ	P,FLSDR##	;HAVE DISK RESOURCE?
	  JRST	SRAVL3		;NO, DON'T GIVE HIM ANOTHER
	POP	P,J		;RESTORE J AND LET HIM
	JRST	SRAVL1		; CONTINUE UNTIL HE HAS NONE

SRAVL3:	POP	P,J
	POP	P,T3		;RESTORE AC'S
	SETOM	AVALTB-MQ(16)	;SET AVAL BUT DON'T
	JRST	SETSTT		; GIVE UP 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

DEFINE X(A,B,C)<
A'FREE::	PUSHJ	P,SRFREE
>
DVFREE::RWAITS
SRFREE:	EXCH	T1,(P)		;GET ENTRY ADDRESS AND SAVE T1
	SUBI	T1,DVFREE+1	;CALCULATE WAIT STATE INDEX
	HRLZS	USRTAB##(T1)	;XWD LAST USER, 0 (NO CURRENT USER)
	SOSL	REQTAB##(T1)	;DECREMENT REQUEST COUNT.  ANY JOBS WAITING?
	SETOM	AVALTB##(T1)	;YES, FLAG IT AS AVAILABE SO THIS SCHEDULER WILL
				; GIVE THE RESOURCE TO A WAITER
	SKIPE	DINITF##	;NO UNWINDING DURING ONCE-ONLY
	JRST	TPOPJ##

	PUSH	P,J		;SAVE J
	HLRZ	J,USRTAB##(T1)	;GET OWNER OF RESOURCE

SRFRCX::
SRFRAU::			;
SRFRDA::			;
SRFRIP::
SRFRDT::
	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
	MOVSI	T1,-AVLNUM##	;# OF QUEUES
SRFRE1:	PUSHJ	P,@TSTSRT(T1)	;JOB OWN RESOURCE OF THIS TYPE?
	  AOBJN	T1,SRFRE1	;NO
	JUMPL	T1,SRFRE4	;JOB OWNS SOMETHING
;HERE IF JOB OWNS NO OTHER RESOURCES - FLAG FOR FORCED RESCHEDULE
	SYSPIF			;NO PI'S
	SKIPN	SCDRTF##	;FORCED RESCHEDULE IN PROGRESS?
	HRROS	SCDRTF##	;SEMI-PREEMPTIVE RESCHEDULE
	SYSPIN			;ALLOW PI'S
	MOVEI	T1,JS.OOO	;CLEAR OUT OF ORDER BIT
	ANDCAM	T1,JBTST2##(J)
	SETZM	UNWIND##	;ALLOW ANOTHER UNWIND CYCLE
SRFRE4:	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.
	POP	P,T1		;RESTORE T1
	PJRST	RTEVM##		;AND GIVE UP EVM IF ANY

;TABLE USED BY THE ABOVE

DEFINE	X(A,B,C,D,E,F)<
	IFB	\'F'\,<IFIW	TSTSR>
	IFNB	\'F'\,<IFIW	'F'##>
	>
TSTSRT:	RWAITS

;DEFAULT TEST ROUTINE:

TSTSR:	CAMN	J,USRTAB##(T1)
	AOS	(P)		;OWN RESOURCE OF THIS TYPE
	POPJ	P,
;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
	PUSHJ	P,FNDPDS##	;GET ADDRESS OF PDB
	MOVSI	T1,(PD.LGN)	;GET THE COUNT BIT
	TDNN	T1,.PDDFL##(W)	;HAVE WE COUNTED YET?
	POPJ	P,		;YES, ALL DONE
	ANDCAM	T1,.PDDFL##(W)	;NO, SO CLEAR IT AND
	AOS	LOGNUM##	;INCREMENT LOGNUM
	POPJ	P,		;RETURN

;SUBROUTINE TO CLEAR JLOG AND DECREMENT LOGNUM
;CALL WITH:
;	MOVE	J,JOB#
;	PUSHJ	P,CLRLOG
;USES T1,T2
CLRLOG::
	MOVSI	T2,(JB.LBT)	;IS THIS A BATCH JOB?
	TDNE	T2,JBTLIM##(J)	;--
	SOS	BATNUM##	;DECREMENT BATNUM
	PUSHJ	P,FNDPDS##	;GET ADDRESS OF PDB
	MOVSI	T1,(PD.LGN)	;GET THE COUNT BIT
	TDNN	T1,.PDDFL##(W)	;HAVE WE COUNTED DOWN YET?
	TRNA			;NO, SO SKIP
	JRST	CLRJLG		;YES, JUST CHECK JLOG NOW
	IORM	T1,.PDDFL##(W)	;FLAG THAT WE HAVE COUNTED
	SOS	LOGNUM##	;DECREMENT LOGNUM
CLRJLG::			;HERE JUST TO CLEAR JLOG
	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
	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

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

STPIOD::MOVEI	T2,PSQ##	;REQUE TO PAGING I/O WAIT SATISFIED
	JRST	STIDZA

STTIOD::LDB	T1,PJOBN##	;JOB NUMBER
IFN FTRSP,<
	MOVE	T2,SYSUPT##	;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
	CAMGE	T2,FRSHPQ##	;FORCE SCHEDULER CYCLE.
	JRST	STTID2		;NO, NOT HPQ OR HPQ TOO LOW
	PUSH	P,T3		;SAVE T3
	MOVSI	T3,SWP		;GET BIT TO TEST FOR
	SYSPIF			;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,SCDRTF##	;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,SCDRTF##	;YES, USE OUR JOB NUMBER
	SETOM	.CPCKF##	;FLAG THAT WE'RE DOING CH7 INTERRUPT
	SYSPIN	(CLKBIT##+PI.IIO)	;CAUSE INTERRUPT TO HAPPEN
	POP	P,T3
	JRST	STTID2		;CONTINUE

STTID1:	SYSPIN			;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
	JRST	SETID1
SETIOD::MOVEI	T2,WSQ##		;REQUE TO WAIT SATISFIED Q
	JRST	SETID0

STDIOD::MOVEI	T2,DSQ##		;SET DISK IO WAIT STATISFIED QUEUE


SETID0:
IFN FTHPQ,<
	LDB	T1,PJOBN##	;GET JOB NUMBER OF DDB IN F
	LDB	T1,HPQPT1##	;GET HIS HPQ NUMBER
	CAMGE	T1,FRSHPQ##	;FORCE SCHEDULER CYCLE NOW
	JRST	SETID1		;NO,NOT HPQ OR HPQ TO LOW
	LDB	T1,PJOBN##	;GET JOB # AGAIN
	SYSPIF			;TURN OFF PI'S
	SKIPN	SCDRTF##	;ANY REAL TIME RESCHEDULE TO DO?
	MOVNM	T1,SCDRTF##	;SET AS HPQ JOB FORCING RESCHEDULE
	SETOM	.CPCKF##	;DOING A CH7 INTERRUPT
	SYSPIN	(CLKBIT##+PI.IIO)
>;END IFN FTHPQ

SETID1:	LDB	T1,PJOBN##	;GET JOB NUMBER
IFN FTPI,<
	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:	MOVEM	S,DEVIOS(F)	;MAKE SURE IOS IS IN MEMORY BEFORE MAKING JOB RUNNABLE
STIDZA:	CAIN	T2,TSQ##	;TIOW SATISFIED?
	JRST	STID2B		;YES, REQUEUE
	MOVEI	T2,RNQ##	;MAKE JOB RUNNABLE
	DPB	T2,PJBS2
	JRST	NJBTST		;SEE IF WE SHOULD FORCE REQUE
STID2B:	DPB	T2,PJBS2	;IN JOB STATUS WORD

	PUSH	P,J		;SAVE J
	MOVE	J,T1		;GET JOB NUMBER
	PUSHJ	P,REQUE		;REQUE THIS JOB
	POP	P,J		;RESTORE J
NJBTST::SKIPN	.CPJOB##	;IS NULL JOB RUNNING?
	PJRST	STOP2		;YES, CAUSE RESCHEDULE
IFN FTMP,<
	MOVE	T1,.CPSCS##	;RUN THE SCHEDULER
	IORM	T1,DOORBL##	;DONG!
>
	POPJ	P,		;NO LET OTHER JOB RUN TILL SCHEDULER IS TRAPPPED TO
SETID3:
	MOVSI	T2,IOACE##	;JOB ENABLED FOR WAKEUP ON I/O ACTIVITY?
	TDNN	T2,JBTRTD##(T1)
	POPJ	P,		;NO, RETURN
	TLNN	S,IOSTBL	;IF OFFLINE, NO IO ACTIVITY OCCURS
	PJRST	WAKJOB##	;OK TO 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.


WAIT1::

IFN	FTMSGSER,<
	PUSH	P,T1		;NEED A SPARE AC
	LDB	T1,PDVTYP##	;GET DEVICE TYPE
	CAIN	T1,<.TYMPX/.TYEST>  ;AN MPX CHANNEL?
	PJRST	MPXWAI##	;YES, SPECIAL MSGSER CODE THEN
	POP	P,T1		;NO, NORMAL DEVICE HANDLING
WAIT1M::> ;END IFN FTMSGSER

	MOVE	S,DEVIOS(F)	;GET I/O STATUS WORD
	TRNN	S,IOACT		;IS DEVICE ACTIVE? (IOACT=1?)
	JRST	WAIT2		;RETURN
	PUSHJ	P,WSYNC		;WAIT
	JRST	WAIT1

IFN FTMP,<
WAIT2:	PUSH	P,T1		;SAVE A TEMP
	HRRZ	T1,DEVCPU(F)	;GET ADDR OF INTERLOCK WORD
	SKIPL	(T1)		;WAIT UNTIL CPU DOING IO
	JRST	.-1		; LEAVES INTERRUPT LEVEL
	JRST	TPOPJ##		;RESTORE AC AND RETURN
>
IFE FTMP,<
	WAIT2==CPOPJ##
>
;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



WSYNC::	PUSHJ	P,SAVE3##	;SAVE P1-P3
	TRNN	F,777700	;IS RH(F) LESS THAN 100?
	STOPCD	CPOPJ##,JOB,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 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,.CPJOB##	;CURRENT JOB NO.
	MOVEI	P2,IOACT	;DEVICE ACTIVE BIT
	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
	PION			;TURN PI ON
	HRRM	F,JBTDDB##(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
	HLLZS	JBTDDB##(P3)
	JRST	WSYNC2
WSYNC1:	PION
WSYNC2:	ANDCAB	S,DEVIOS(F)	;CLEAR DEVICE IO-WAIT BIT
	POPJ	P,		;HALT HERE IF F LESS THAN 100
	$LIT

CLKEND:	END