Google
 

Trailing-Edge - PDP-10 Archives - AP-D543V_SB - ipcser.mac
There are 12 other files named ipcser.mac in the archive. Click here to see a list.
TITLE IPCSER -- INTER PROCESS COMMUNICATION FACILITY V11121
SUBTTL J. SAUTER/T WACHS/LSS/CDO   28 NOV 78
	SEARCH	F,S
	$RELOC
	$HIGH



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

ENTRY IPCSER		;LOAD THIS MODULE IF REQUESTED

IPCSER::

;IPCSER PROVIDES A FACILITY WHICH PERMITS TWO JOBS TO EFFICIENTLY
; EXCHANGE LIMITED AMOUNTS OF DATA.  THE MONITOR MAY ALSO PARTICIPATE
; IN THIS EXCHANGE BY MEANS OF "EXEC PSEUDO-PROCESSES".
;DATA STRUCTURES:
XX=.			;REMEMBER LOCATION
;EXECUTIVE PROCESS CONTROL BLOCK
	PHASE 	0

;NOTE THAT .EPIPC,.EPIPA, .EPIPQ MUST REMAIN IN THIS ORDER
; (SAME ORDER AS .PDIPC,.PDIPA, .PDIPQ)

.EPIPC:!BLOCK	1	;LH=POINTER TO OLDEST PACKET
			;18-26 = PACKETS SENT & NOT RECEIVED
			;27-35 = PACKETS WAITING TO BE REC.
.EPIPA:!BLOCK	1	;LH = COUNT OF SENDS SINCE LOGIN
			;RH = COUNT OF RECEIVES SINCE LOGIN
.EPIPQ:!BLOCK	1	;FLAGS AND QUOTAS
IP.DSB==(1B0)		;RECEIVER IS DISABLED
IP.HBS==(1B1)		;QUOTAS HAVE BEEN SET
IP.DPR==(1B2)		;AT LEAST 1 PID FOR JOB IS TO BE DROPPED ON RESET
IP.DPL==(1B3)		;AT LEAST 1 PID TO BE DROPPED ON LOGOUT
			;18-26 = SEND QUOTA
			;27-35 = RECEIVE QUOTA
	IP.SBT==1000	;1ST BIT IN SEND QUOTA/COUNT BYTE

;THE .EPXXX WORDS ABOVE HAVE CORRESPONDING .PDXXX WORDS IN
;  THE PDB FOR USER JOBS.

.EPADR:!BLOCK	1	;PUSHJ @ HERE WHEN A PACKET ARRIVES
				;  FOR THIS PROCESS.
	DEPHASE
;DEFINITION OF PACKET DESCRIPTOR BLOCK

	PHASE 	0
.IPCFL::!BLOCK	1	;LINK AND FLAGS
	IP.CFB==(1B0)	;UUO BLOCK: DONT BLOCK READ UUO
	IP.IAS==(1B1)	;UUO BLOCK: INDIRECT ADDRESS FOR SENDER'S PID
	IP.IAR==(1B2)	;UUO BLOCK: INDIRECT ADDRESS FOR RECEIVER'S PID
			;IN PACKET, LH = POINTER TO NEXT
	IP.LPC==(1B3)	;UUO BLOCK: "LAST PHONE CALL" - SEND EVEN THO QUOTA
			; IS OVERDRAWN (ONLY ALLOWS OVERDRAW OF 1)
	IP.TTL==(1B4)	;UUO BLOCK-TRUNCATE PACKET IF TOO LONG
	IP.LPK==(1B5)	;PACKET IS LONGER THAN MAX SYSTEM SIZE (PRIVID)
	IP.SIP==1B18	;SENDER IS PRIVLEGED
	IP.CFV==1B19	;VM PAGE MODE
	IP.CFZ==1B20	;DATA LENGTH=0
	IP.AKR==1B21	;SENDER REQUESTS ACKNOWLEGEMENT FROM RECEIVER
	IP.CFE==77B29	;(UNPRIV) ERROR RETURN
	IP.CFM==77B35	;SPECIAL MESSAGE FIELD
	   .IPCMN==1	;MESSAGE 1: MESSAGE WAS UNDELIVERABLE

.IPCFS::!BLOCK	1	;SENDER'S PID
.IPCFR::!BLOCK	1	;RECEIVER'S PID
.IPCFP::!BLOCK	1	;LH = LENGTH  OF PACKET'S DATA
			;IN UUO BLOCK, RH = USER'S PACKET BUFFER
			;IN PACKET, RH = RESERVED FOR VIRTUAL FEATURE
.IPCFM::!BLOCK	0	;MINIMUM LENGTH OF DESCRIPTOR BLOCK
.IPCFU::!BLOCK	1	;SENDER'S PPN.  FILLED IN BY MONITOR ON SEND
			;UUO NEVER FILLED IN BY USER.
.IPCFC::!BLOCK	1	;SENDER'S CAPABILITIES WORD.  FILLED IN SAME
			;FASHION AS .IPCFU.
	IP.JAC==(1B0)	;SENDER HAS JACCT ON
	IP.JLG==(1B1)	;SENDER IS LOGGED-IN
	IP.SXO==(1B2)	;SENDER IS EXECUTE-ONLY
	IP.POK==(1B3)	;SENDER CAN POKE THE MONITOR
	IP.IPC==(1B4)	;SEND HAS IPCF PRIVS
			;BITS 27:35 = JOB NO OF SENDER
.IPCFD::!BLOCK	0	;IN PACKET ONLY, START OF DATA.
	DEPHASE
	RELOC	XX	;DONT WASTE ANY SPACE
TRNPTR:	POINT	9,.IPCFC(P1),35
TRNPT2:	POINT	9,.IPCFC(P2),35
IFN FTGALAXY,<

;DESCRIPTION OF SPOOL, LOGIN AND LOGOUT MESSAGES
;	ALL MESSAGES FROM IPCC TO QUASAR HAVE A TWO WORD HEADER AS
;	DESCRIBED BELOW.  THE LOGOUT MESSAGE CONSISTS SOLELY OF THESE
;	TWO WORDS, AND THE SPOOL MESSAGE HAS FILE INFORMATION APPENDED,
;	THE LOGIN MESSAGE HAS JOB INFORMATION APPENDED.

	XX=.				;REMEMBER LOCATION

	PHASE	0			;START AT 0

SPBMAX==:11				;LENGTH OF SPOOLING PARAMETER BLOCK
SPBCOR==:<SPBMAX+3>/4			;# OF 4 WD BLOCK IN SPB
GALMSG:!BLOCK	1			;MESSAGE HEADER
					; XWD LENGTH,,FUNCTION

GALSTS:!BLOCK	1			;STATUS WORD
	GALJOB==-1,,0			;BITS 0-17 IS JOB NUMBER
	GALLOC==777000			;    18-26 IS LOCATION
	GALFLG==777			;    27-35 ARE FLAGS
		GALBAT==1B27		;BATCH JOB
		GALDFR==1B28		;DEFERRED SPOOLING
		GALIUD==1B29		;SPOOLED FILE IN USERS DIRECTORY

	LGMSIZ==.-GALMSG		;SIZE OF LOGOUT MESSAGE

SPMUSR:!BLOCK	2			;USER NAME IN 6BIT
SPMIDV:!BLOCK	1			;INITED DEVICE
SPMSTR:!BLOCK	1			;STRUCTURE NAME
SPMFIL:!BLOCK	1			;FILENAME
SPMEFN:!BLOCK	1			;ENTER'ED FILE NAME
SPMFSZ:!BLOCK	1			;FILE SIZE IN BLOCKS
SPMPRM:!BLOCK	SPBMAX			;PARAMS

	SPMSIZ==.-GALMSG		;SIZE OF SPOOL MESSAGE

	PHASE	GALSTS+1
LOMUSR:!BLOCK	2			;USER NAME IN 6BIT
LOMCTL:!BLOCK	1			;CONTROLLERS JOB NUMBER
LOMTTY:!BLOCK	1			;TTY
	LOMSIZ==.-GALMSG

	DEPHASE
	RELOC	XX			;RECLAIM SPACE

>  ;END OF IFN FTGALAXY
;ERROR CODES:

IPCAC%==1		;ADDRESS CHECK (UUO BLOCK OR PACKET BUFFER)
IPCNL%==2		;NOT LONG ENOUGH (UUO BLOCK)
IPCNP%==3		;NO PACKET IN LIST (READ UNBLOCKED)
IPCIU%==4		;(PAGE) IN USE (PART OF VIRTUAL FEATURE)(PAGE IS LOCKED)
IPCTL%==5		;(PACKET) TOO LONG (FOR USER'S BUFFER)
IPCDU%==6		;DESTINATION UNKNOWN (SEND)
IPCDD%==7		;DESTINATION DISABLED (SEND)
IPCRS%==10		;(NO) ROOM (IN) SENDER'S (QUOTA)
IPCRR%==11		;(NO) ROOM (IN) RECEIVER'S (QUOTA)
IPCRY%==12		;(NO) ROOM (IN) SYSTEM (STORAGE)
IPCUP%==13		;UNKNOWN PAGE (SEND) EXISTING PAGE (REC)
IPCIS%==14		;INVALID SEND ADDRESS
IPCPI%==15		;PRIVLEGES INSUFFICIENT
IPCUF%==16		;UNKNOWN FUNCTION
IPCBJ%==17		;BAD JOB NUMBER
IPCPF%==20		;PIDTAB FULL
IPCPR%==21		;PAGED PACKET REQUESTED, REGULAR PACKET IN QUEUE OR VICE VERSA(VM)
IPCIE%==22		;PAGING IO ERROR (VM)
IPCBI%==23		;BAD INDEX SPECIFIED FOR SYSTEM PID TABLE
IPCUI%==24		;UNDEFINED ID IN SYSTEM PID TABLE
;SUBROUTINE TO VALIDATE ARGUMENTS AND FETCH THEM INTO P1-P4.
;  SKIP RETURN ON OK, LEAVES ADDR OF ARG IN M.

VALARG:	HLRZ	T2,T1		;GET USER'S AC LEFT HALF
	CAIGE	T2,.IPCFM	;LONG ENOUGH?
	JRST	ERRNL		;NO.
	MOVE	P4,T1		;YES, COPY USER'S AC
	HRRI	M,.IPCFL(P4)	;FIRST LOCATION OF BLOCK
	PUSHJ	P,GETWRD##	;FETCH .IPCFL
	  JRST	ERRAC		;ADDRESS CHECK
	MOVE	P1,T1		;PUT .IPCFL IN P1
IFE FTVM,<
	TRNE	T1,IP.CFV	;TRYING TO DO A WHOLE PAGE?
	JRST	ERRNL		;YES, ERROR
>
	PUSHJ	P,GETWR1##	;FETCH SENDER'S PID
	  JRST	ERRAC		;ADDRESS CHECK
	TLNN	P1,IP.IAS	;IS SENDER'S PID INDIRECTED?
	JRST	VALAR1		;NO.
	HRR	M,T1		;YES, GET ADDRESS
	TLNN	T1,-1		;LH = 0?
	PUSHJ	P,GETWRD##	;YES, FETCH THAT WORD.
	  JRST	ERRAC		;ADDRESS CHECK
VALAR1:	MOVE	P2,T1		;PUT .IPCFS IN P2
	HRRI	M,.IPCFR(P4)	;THIRD LOCATION OF BLOCK
	PUSHJ	P,GETWRD##	;FETCH RECEIVER'S PID
	  JRST	ERRAC		;ADDRESS CHECK
	TLNN	P1,IP.IAR	;IS RECEIVER'S PID INDIRECTED?
	JRST	VALAR2		;NO.
	HRR	M,T1		;YES, PUT ADDRESS IN M
	TLNN	T1,-1		;IS LH = 0?
	PUSHJ	P,GETWRD##	;YES, GET THE WORD.
	  JRST	ERRAC		;ADDRESS CHECK
VALAR2:	MOVE	P3,T1		;GET RECEIVER PID
	CAMN	P3,%IPCFP##	;PUBLIC VALUE FOR [SYSTEM]IPCF?
	MOVE	P3,PIDTAB##	;YES, CONVERT TO ACTUAL VALUE
	HRRI	M,.IPCFP(P4)	;FOURTH LOCATION OF BLOCK
	PUSHJ	P,GETWRD##	;FETCH PACKET DESCRIPTOR
	  JRST	ERRAC		;ADDRESS CHECK
	HRRI	M,.IPCFL(P4)	;POINT BACK TO FRONT OF BLOCK
	MOVE	P4,T1		;PUT .IPCFP IN P4
IFN FTVM,<
	TRNN	P1,IP.CFV	;ASKING FOR A PAGE?
	JRST	VALAR3		;NO
	HLRZ	T1,P4		;YES, EXACTLY 1 PAGE?
	TLNE	P1,IP.TTL	;TRUNCATE IF TOO LONG?
	JUMPE	T1,VALAR3	;YES, LENGTH =0 IS OK
	CAIE	T1,PAGSIZ##
	JRST	ERRTL		;CANT DO MORE THAN 1 PAGE AT A TIME
	HRRZS	P4		;OK, SET LENGTH OF DATA TO 0 (NO DATA WDS IN PACKET)
	MOVSI	T1,NSHF!NSWP	;LOCKED BITS
	SKIPLE	T2,JBTSGN##(J)	;DOES JOB HAVE A HIGH SEG
	TLNE	T2,SHRSEG	;YES, IS IT SHAREABLE
	MOVEI	T2,0		;NO HIGH SEG OR NOT SHAREABLE
	TDNN	T1,JBTSTS##(J)	;LOW SEG LOCKED
	TDNE	T1,JBTSTS(T2)	;OR HIGH SEG LOCKED
	  PJRST	ERRIU		;YES, GIVE ERROR
	HRLI	P4,-1
	JRST	VALAR4
VALAR3:
>
	HRRZ	T1,P4		;START ADR
	PUSHJ	P,CHKADR	;CHECK IT
	  PJRST	ERRAC
	HLRE	T2,P4
	JUMPLE	T2,VALAR4	;OK IF NO DATA WORDS
	ADDI	T1,-1(T2)	;TOP ADR
	PUSHJ	P,CHKADR	;CHECK
	  PJRST	ERRAC
VALAR4:	MOVSI	T1,JP.IPC	;NO PRIV BIT DEFINED
	PUSHJ	P,PRVBIT##	;IS THIS JOB PRIV?
	  CAIA			;YES
	TRNN	P1,-1-IP.CFE-IP.CFV-IP.AKR  ;NO, PRIV'D FUNCTION?
	AOSA	(P)		;NOT PRIV'D FNC, OR JOB HAS PRIVS
	JRST	ERRPI		;PRIV'D FNC, NON-PRIV'D JOB
	PJRST	FNDPDS##	;SET UP W AND RETURN
;SUBROUTINE TO ADDRESS CHECK
CHKADR:	PUSH	P,T1
	PUSH	P,M		;SAVE M
	HRR	M,T1
	PUSHJ	P,GETWRD##
	  SOS	-2(P)
	POP	P,M
	PJRST	TPOPJ1##
;SUBROUTINE TO LOAD J AND W BASED ON PID IN T1.
;RETURNS CPOPJ ON ERROR, ERROR CODE IN T1
;RETURNS CPOPJ1 IF OK

VALPID:	JUMPE	T1,VALPD4	;ZERO PID IS INVALID
	CAIG	T1,JOBMAX##	;SEE IF JOB NUMBER
	JUMPG	T1,VALPD1	;JOB NO
	MOVE	T2,T1		;COPY OF PID
	AND	T2,%IPCPM##	;MASK TO INDEX
	CAMGE	T2,%IPCMP##	;IN RANGE?
	SKIPN	T2,PIDTAB##(T2)	;YES, PICK UP ENTRY.
	JRST	VALPD4		;NO ENTRY HERE
	MOVE	T3,T2		;SAVE IT FOR LATER
	XOR	T2,T1		;CLEAR BITS IN COMMON
	TDZ	T2,%IPCPM##	;CLEAR UNWANTED BITS
	JUMPN	T2,VALPD4	;SEQ # ARE THE SAME IF 0
	AND	T3,%IPCPM	;GET JOB NUMBER
	SKIPA	J,T3		;SET J
VALPD1:	MOVE	J,T1
	JUMPE	J,VALPD3	;EXECUTIVE PROCESS
	PUSHJ	P,FNDPDB##	;FIND JOB'S PDB
	  JRST	VALPD4		;NONE - PID IS BAD
VALPD2:	MOVE	T2,.PDIPQ##(W)	;GOOD--CHECK QUOTA FOR SET UP
	TLON	T2,IP.HBS	;HAS QUOTA BEEN SET?
	HRR	T2,%CNIPQ##	;NO, SET IT TO DEFAULT VALUE
	MOVEM	T2,.PDIPQ##(W)
	PJRST	CPOPJ1##	;AND GIVE GOOD RETURN

VALPD3:	HLRZ	W,T1		;POINT TO EXECUTIVE PROCESS CTL BLK
	HRLS	W		;SAVE LOC OF EXEC CTL BLOCK
	SUBI	W,.PDIPC##	;FIX OFFSET SO .PDXXX POINTS TO .EPXXX
	JRST	VALPD2

;HERE ON ERROR
VALPD4:	MOVEI	T1,IPCIS%	;ERROR CODE
	POPJ	P,
;ERROR ROUTINES.  THESE LOAD IPCXX% INTO T1 FOR EACH ERRXX.
;  ERROR ROUTINES ARE CALLED VIA PUSHJ, BUT THEY NEVER RETURN.
;THE POSITION RELATIVE TO ERRAC DEFINES THE ERROR VALUE.

	ERCODE	ERRAC,IPCAC%	;(1) ADDRESS CHECK
	ERCODE	ERRNL,IPCNL%	;(2) NOT LONG ENOUGH
	ERCODE	ERRNP,IPCNP%	;(3) NO PACKET IN QUEUE
	ERCODE	ERRIU,IPCIU%	;(4) PAGE IN USE (VIRTUAL FEATURE)
	ERCODE	ERRTL,IPCTL%	;(5) PACKET TOO LONG
	ERCODE	ERRDU,IPCDU%	;(6) DESTINATION UNKNOWN
	ERCODE	ERRDD,IPCDD%	;(7) DESTINATION DISABLED
	ERCODE	ERRRS,IPCRS%	;(10) NO ROOM IN SENDER'S QUOTA
	ERCODE	ERRRR,IPCRR%	;(11) NO ROOM IN RECEIVER'S QUOTA
	ERCODE	ERRRY,IPCRY%	;(12) NO ROOM IN SYSTEM FOR PACKET
	ERCODE	ERRUP,IPCUP%	;(13) UNKNOWN PAGE (SEND) OR ALREADY EXISTING (REC)
	ERCODE	ERRIS,IPCIS%	;(14) INVALID SENDER'S ADDRESS
	ERCODE	ERRPI,IPCPI%	;(15) INSUFFICIENT PRIVILEGES
	ERCODE	ERRUF,IPCUF%	;(16) - UNKNOWN FUNCTION
	ERCODE	ERRBJ,IPCBJ%	;(17) - BAD JOB NUMBER
	ERCODE	ERRPF,IPCPF%	;(20) - PIDTAB FULL
	ERCODE	ERRPR,IPCPR%	;(21) - PAGE REQUESTED, NOT-A-PAGE IN QUEUE
	ERCODE	ERRIE,IPCIE%	;(22) - PAGING IO ERROR
	ERCODE	ERRBI,IPCBI%	;(23) - BAD INDEX FOR .GTSID
	ERCODE	ERRUI,IPCUI%	;(24) - UNDEFINED ID  REQUESTED

SUBTTL IPCFR - RECEIVE UUO

UIPCFR::PUSHJ	P,SAVE4##	;SAVE P1-P4
	PUSH	P,T1		;SAVE USER ARG ON THE STACK
	PUSHJ	P,VALARG	;LOAD ARGS
	  JRST	[POP P,(P)	;BRING STACK INTO PHASE
		 POPJ P,]	;AND RETURN
	POP	P,T4		;RESTORE T1 INTO T4
	HLRZS	T4		;JUST NEED THE LENGTH
IPFR1:	HLRZ	P2,.PDIPC##(W)	;POINTER TO OLDEST PACKET
	JUMPE	P2,IPFR7	;NONE.
	HRRZ	T1,.IPCFL(P2)	;GET FLAG WORD
	TRNE	T1,IP.CFV	;PAGED PACKET?
	TRZE	P1,IP.CFV	;MUST HAVE REQUESTED A PAGE
	TRNE	P1,IP.CFV	;ERR IF REQUESTED A PAGE
	JRST	ERRPR		;WRONG MODE
	MOVE	P3,T1
	TRNN	P1,IP.SIP	;IS CALLER PRIV AND ASKING FOR PRIVS?
	TRZ	T1,IP.SIP	;NO, HE DOESNT CARE IF PACKET PRIV
	HLRZ	T2,P4		;SPACE PROVIDED
	HLRZ	T3,.IPCFP(P2)	;LENGTH OF PACKET
	SUB	T3,T2
	SKIPG	T3		;LONG ENOUGH?
	TLZA	P1,IP.TTL	;YES, CLEAR TTL BIT
	TLO	T1,IP.TTL	;NO, SET TTL IN UUO BLOCK
	PUSHJ	P,PUTWDU##	;STORE IN USER'S ARG BLOCK
	MOVE	T1,.IPCFS(P2)	;GET SENDER'S PID
	PUSHJ	P,PUTWD1##	;STORE SENDER'S PID
	MOVE	T1,.IPCFR(P2)	;RECEIVER'S PID
	PUSHJ	P,PUTWD1##	;STORE RECEIVER'S PID
	TLNN	P1,IP.TTL	;TRUNCATE IF TOO LONG?
	JUMPG	T3,ERRTL	;NO, ERROR IF TOO LONG
;COME HERE TO COPY PACKET TO USER'S CORE.

	MOVE	T1,.IPCFP(P2)	;LENGTH IN LH
	HRR	T1,P4		;HDR
IFN FTVM,<
	TRNE	P3,IP.CFV
	HRLI	T1,PAGSIZ##	;WHOLE PAGE
>
	TLNE	P1,IP.TTL	;PACKET TOO LONG?
	HLL	T1,P4		;YES, TELL TRUNCATED LENGTH
	PUSHJ	P,PUTWD1##	;TELL USER THE LENGTH
	MOVE	T1,.IPCFU(P2)	;GET SENDER'S PPN
	CAILE	T4,.IPCFU	;DID HE ASK FOR IT?
	PUSHJ	P,PUTWD1##	;YES, GIVE IT TO HIM
	MOVE	T1,.IPCFC(P2)	;GET CAPABILITIES WORD
	CAILE	T4,.IPCFC	;DID HE ASK FOR IT ALSO?
	PUSHJ	P,PUTWD1##	;YES, GIVE IT TO HIM
	HLRE	T1,.IPCFP(P2)	;LENGTH
	TLNE	P1,IP.TTL	;TOO LONG?
	HLRE	T1,P4		;YES, JUST FILL HIS BLOCK
	JUMPLE	T1,IPFR4	;NOTHING TO STORE IF 0 WDS IN PACKET
	HRRI	M,-1(P4)	;USER'S ADDRESS
	MOVN	T2,T1		;FORM AOBJN WORD
	HRLZS	T2
	HRR	T2,P2		;ADR OF PACKET
IPFR3:	MOVE	T1,.IPCFD(T2)	;FETCH DATA FROM EXEC
	PUSHJ	P,PUTWD1##	;STORE IN USER'S AC
	AOBJN	T2,IPFR3	;COPY WHOLE PACKET

IPFR4:
IFN FTVM,<
	TRNN	P3,IP.CFV	;WHOLE PAGE?
	JRST	IPFR5		;NO
	TLNE	P1,IP.TTL	;TOO LONG?
	JRST	[HRRZ T2,.IPCFP(P2)  ;YES, DELETE THE PAGE
		 JUMPE T2,IPFR5  ;FORGET IT IF IO ERROR
		 PUSHJ P,IPCDEL##
		 JRST IPFR5]
	HRRZ	T1,P4		;NO, GET VIRTUAL PAGE NO
	HRRZ	T2,.IPCFP(P2)	;DSK OR CORE ADR
	JUMPE	T2,ERRIE	;ERROR PAGING OUT THE PAGE
	PUSHJ	P,IPCINS##	;PUT PAGE INTO THIS MAP
	  JRST	[JUMPE	T1,ERRUP	;T1=0 IF NO SUCH PAGE
		JRST	ERRIE]		;OTHERWISE PAGING IO ERROR
IPFR5:>
;COME HERE TO DECREMENT RECEIVER'S AND SENDER'S COUNTERS,
;  FREE EXEC COPY OF PACKET, ETC.  NO ERROR EXITS ARE
;  PERMITTED BEYOND THIS POINT SINCE EXEC INFORMATION IS
;  ALTERED.

	HLRZ	T1,.IPCFL(P2)	;POINTER TO NEXT BLOCK
	HRLM	T1,.PDIPC##(W)	;MAKE IT THE OLDEST
	JUMPE	T1,IPFR5A
	HLL	T1,.IPCFP(T1)	;LENGTH OF NEXT PACKET
	HRR	T1,.IPCFL(T1)	;FLAGS FOR NEXT PACKET
IFN FTVM,<
	TRNE	T1,IP.CFV	;PAGE?
	HRLI	T1,PAGSIZ##	;YES, SET LENGTH
>
IPFR5A:	PUSHJ	P,STOTAC##	;RETURN INFO ABOUT NEXT PACKET IN AC
	SOS	.PDIPC##(W)	;DEC COUNT OF PACKETS WAITING
	AOS	T1,.PDIPA##(W)	;INCR RECEIVE COUNT
	TRNN	T1,-1
	SOS	.PDIPA##(W)	;OVERFLOW, COUNT IT DOWN AGAIN

;NOW MOVE TO THE SENDER'S ENVIRONMENT TO DECREMENT THE
;  COUNT OF HIS UNRECEIVED SENDS.  SENDER'S PID HAS BEEN
;  KEPT IN P1 FROM WAY BACK.

	MOVE	T2,.IPCFS(P2)	;IS SENDER A SYSTEM PROCESS?
	AND	T2,%IPCPM##
	CAIGE	T2,%IPCNS##
	TDZA	T2,T2		;YES, DON'T USE .IPCFC
	LDB	T2,TRNPT2	;IF TURNED-AROUND MSG THE PID
	SKIPN	T1,T2		; MAY HAVE BEEN DESTROYED,
	MOVE	T1,.IPCFS(P2)	;SO GET W FROM PID
	PUSH	P,J		;SAVE J
	PUSHJ	P,VALPID	;SET UP J & W
	  JRST	IPFR6		;NO GOOD, SENDER MUST BE GONE.
	MOVNI	T1,IP.SBT	;DECREMENT COUNT OF PACKETS SENT BUT
	MOVE	T2,.PDIPC##(W)	;ANY SEND-COUNT OUTSTANDING?
	TRNE	T2,777000	; (SEND FROM JOB-NO,LOGOUT;NEW JOB SAME SLOT)
	ADDM	T1,.PDIPC##(W)	; NOT YET RECEIVED
IPFR6:	HLRE	T1,.IPCFP(P2)	;GET LENGTH OF THIS BLOCK
IFN FTVM,<
	SKIPGE	T1		;PAGE?
	SETZ	T1,		;YES, NO DATA WORDS
>
	ADDI	T1,.IPCFD	;PLUS OVERHEAD WORDS
	HRRZ	T2,P2		;ADDRESS
	PUSHJ	P,GIVWDS##	;FREE THE PACKET SPACE
	SOSL	%CNIIP##	;DEC COUNT OF PACKETS OUTSTANDING
	PJRST	JPOPJ1##
	STOPCD	.+1,DEBUG,PCN,	;++PACKET COUNT NEGATIVE
	SETZM	%CNIIP##	;CONTINUED - ZERO COUNT SO WONT STOP AGAIN
	PJRST	JPOPJ1##	;RESTORE J AND SKIP-RETURN


;COME HERE IF THERE IS NO PACKET IN THE USER'S LIST.
IPFR7:	JUMPL	P1,ERRNP	;BIT 0 = DONT BLOCK
	MOVSI	T1,IPCACE##	;FLAG HIBERNATING FOR IPCF
	IORB	T1,JBTRTD##(J)
	MOVEI	T1,SLPQ##	;PUT JOB IN SLEEP QUEUE
	DPB	T1,PJBSTS##
	PUSHJ	P,CLRIPT##	;ZAP IN-CORE PROTECT SO JOB CAN BE SWAPPED
	PUSHJ	P,WSCHED##	;WAIT FOR AWAKENING
IFN FTPI,<
	MOVEI	T1,(JFCL)
	XCT	NOPISK##	;IF PSISER INSTALLED
	HLRZ	T1,@JBTPIA##(J)  ;PICK UP INTERRUPT INSTRUCTION
	CAIN	T1,(JFCL)	;SKIP IF INTERRUPT PENDING
>
	JRST	IPFR1		;GO TRY AGAIN.
IFN FTPI,<
	SOS	JOBPD1##(R)	;BACK UP USER PC
	POPJ	P,		;EXIT SO INTERRUPT WILL HAPPEN
>
SUBTTL IPCFS - SEND UUO

UIPCFS::PUSHJ	P,SAVE4##	;SAVE P1-P4
	PUSHJ	P,VALARG	;LOAD ARGS
	  POPJ	P,		;WRONG
	MOVE	T2,.PDIPQ##(W)	;CHECK FOR QUOTA NOT SET
	TLON	T2,IP.HBS	;HAS QUOTA BEEN SET?
	HRR	T2,%CNIPQ	;NO, SET TO DEFAULT VALUE
	MOVEM	T2,.PDIPQ##(W)
	LDB	T1,[POINT 9,T2,26] ;SEND QUOTA
	LDB	T2,[POINT 9,.PDIPC##(W),26] ;SEND COUNT
	TLNE	P1,IP.LPC	;"LAST PHONE CALL"?
	ADDI	T1,1		;YES, ADD 1 TO QUOTA
	CAMG	T1,T2		;QUOTA DEPLETED?
	JRST	ERRRS		;YES, DON'T SEND
	JUMPN	P3,IPCS0	;IF REC'R FIELD IS 0,
	SKIPN	P3,.PDIPI##(W)	; SEND MSG TO [SYSTEM]INFO FOR THIS JOB
	MOVE	P3,%SIINF##	; (LOCAL OR GLOBAL)
	JUMPE	P3,ERRDU	;DESTINATION UNKNOWN IF NO [SYSTEM]INFO
;COME HERE TO VALIDATE SENDER'S PID

IPCS0:	JUMPN	P2,IPCS3	;"SENDER'S PID" SPECIFIED?
	MOVN	T1,%IPCMP##	;NO, FIND A DEFAULT PID
	HRLZS	T1
	SKIPN	T2,PIDTAB##(T1) ;SEARCH FOR A VALID PIDTAB ENTRY
IPCS1:	AOBJN	T1,.-1
	JUMPGE	T1,IPCS2	;DONE, NO PIDS FOR THIS JOB
	AND	T2,%IPCPM##	;ISOLATE JOB NO.
	CAME	T2,J		;THIS JOB?
	JRST	IPCS1		;NO.
	MOVE	P2,PIDTAB##(T1)	;PUT ENTRY IN P2
	ANDCM	P2,%IPCPM##	;REMOVE JOB NUMBER
	TROA	P2,(T1)		;INCLUDE PID INDEX
IPCS2:	MOVE	P2,J		;NO PIDS, USE JOB NUMBER
IPCS3:	PUSH	P,J		;SAVE J
	MOVE	T1,P2		;GET SENDER'S PID
	PUSHJ	P,VALPID	;CHECK OUT SENDER
	  JRST	[TRNE	P1,IP.SIP ;PRIV'D?
		JRST	IPCS4     ;YES, OK (TURNING AROUND A MSG CAUSE REC'R DIED)
		POP	P,J       ;NO - INVALID SENDER
		JRST	ERRIS]
	JUMPE	J,[POP P,J	;CAN'T SEND "FROM" AN EXEC PROCESS
		   JRST ERRIS]
	SUB	J,(P)		;PID IS LEGAL, IS IT HIS?
	TRNN	P1,IP.SIP	;IF SENDER ISN'T PRIV'D,
	JUMPN	J,[POP	P,J
		   PJRST	ERRIS]	; SEND MUST BE FROM HIS JOB

;COME HERE TO VALIDATE RECEIVER

IPCS4:	MOVE	T1,P3		;PUT PID INTO T1
	PUSHJ	P,VALPID	;SET UP J AND W
	  JRST	[POP P,J	;RESTORE J
		JRST	ERRDU]	;DESTINATION UNKNOWN
	POP	P,J		;RESTORE J (REAL JOB NO OF SENDER)
;COME HERE TO CHECK THAT THE THE RECEIVER'S QUOTA IS NOT
;  EXHAUSTED AND THAT THE RECEIVER IS NOT DISABLED.

	LDB	T1,[POINT 9,.PDIPC(W),35] ;RECEIVE COUNT
	LDB	T2,[POINT 9,.PDIPQ(W),35] ;RECEIVE QUOTA
	CAML	T1,T2		;QUOTA EXHAUSTED?
	JRST	ERRRR
	SKIPGE	.PDIPQ##(W)	;NO, IS RECEIVER DISABLED?
	JRST	ERRDD
	HLRE	T2,P4		;GET DATA LENGTH
	CAMLE	T2,%CNIPL##	;TOO LONG?
	JRST	[TLNN	P1,IP.LPK  ;TRYING TO SEND A LONG MESSAGE?
		 JRST	ERRTL	;NO, PACKET IS TO LONG
		 MOVSI	T1,JP.IPC  ;YES, REQUIRES PRIVILEGES
		 PUSHJ	P,PRVBT##  ;PRIVILEGED?
		   JRST	IPCS4B	;YES, PROCEED
		 JRST	ERRTL]	;NO
	JUMPG	T2,IPCS4B
	TRNN	P1,IP.CFV
	TROA	P1,IP.CFZ
	SETZ	T2,
IPCS4B:	ADDI	T2,.IPCFD	;NO, GET ROOM TO HOLD BLOCK
	PUSHJ	P,GETWDS##	;IN EXEC CORE
	  JRST	ERRRY		;NO ROOM.
	TRNE	P1,70		;SENDER FIELD 0?
	JRST	IPCS4A
	CAMN	P2,%SIINF##	;YES, SENDER =[SYSTEM]INFO?
	TRO	P1,20		;YES
	CAMN	P2,.PDIPI##(W)	;SENDER=LOCAL[SYSTEM]INFO?
	TRO	P1,30		;YES
IPCS4A:	HRRZM	P1,.IPCFL(T1)	;STORE FLAGS (LH=INTERNAL POINTER)
	MOVEM	P2,.IPCFS(T1)	;STORE SENDER'S PID (FUDGED)
	MOVEM	P3,.IPCFR(T1)	;STORE RECEIVER'S PID
	HLLZM	P4,.IPCFP(T1)	;STORE LENGTH (RH RESERVED)
	PUSH	P,J		;SAVE CURRENT INFORMATION
	PUSH	P,W
	PUSH	P,T1
	MOVE	T1,P2		;GET FUDGED SENDERS PID
	PUSHJ	P,VALPID	; AND FIND ITS JOB
	  MOVE	J,-2(P)		;USE CURRENT J IF NOT HERE
	POP	P,T1		;RESTORE T1
	POP	P,W		; AND W
	MOVE	T3,JBTPPN(J)	;GET FUDGED SENDERS PPN
	MOVEM	T3,.IPCFU(T1)	;SAVE IT
	PUSHJ	P,IPCSCA	;STORE CAPABILITIES
	POP	P,J		; AND RESTORE REAL SENDERS J
	HRRI	M,-1(P4)	;POINTER TO BLOCK IN USER CORE
	MOVE	P3,T1		;COPY ADDR OF CORE BLOCK
	HLLZ	P2,P4		;FORM AOBJN WORD
	JUMPLE	P2,IPCS6	;DONT STORE DATA IF LENGTH=0
	MOVNS	P2
	HRR	P2,T1
IPCS5:	PUSHJ	P,GETWD1##	;GET WORD FROM USER CORE
	MOVEM	T1,.IPCFD(P2)	;STORE DATA WORD
	AOBJN	P2,IPCS5	;COPY WHOLE BLOCK
;COME HERE WITH P3 POINTING TO A BLOCK IN EXEC CORE
;  CONTAINING THE UUO ARGS AND THE DATA.  MOVE TO RECEIVER'S
;  ENVIRONMENT AND PUT THE PACKET ON HIS LIST.

IPCS6:
IFN FTVM,<
	TRNN	P1,IP.CFV
	JRST	IPCS7		;NOT A PAGE
	HRRZ	T1,P4		;PAGE - GET ITS VIRTUAL PAGE NUMBER
	PUSHJ	P,IPCRMV##	;REMOVE FROM SENDERS MAP
	  JRST	[HRRZ	T2,P3	;ERROR - GET ADR OF 4-WD BLOCK
		MOVEI	T1,.IPCFD ;LENGTH OF BLOCK
		PUSHJ	P,GIVWDS## ;RETURN THE SPACE
		JRST	ERRUP]	;AND ERROR RETURN

	MOVE	P2,T2		;SAVE CORE ADR
	TRNE	T2,400000	;PAGE ON DSK?
	JRST	IPCS6C		;YES
	MOVE	T1,.IPCFR(P3)	;RECEIVER
	PUSHJ	P,VALPID	;SET UP J AND W
	  JRST	IPCS6A		;SHOULD NEVER HAPPEN
	SKIPGE	T1,JBTSTS##(J)	;JOB RUNNING?
	TLNE	T1,SWP		; AND IN CORE?
	JRST	IPCS6A		;NO, PAGE THE PAGE OUT
IFN FTLOCK,<
	SKIPN	T1,LOCK##	;ALWAYS PAGE IT IF SOMEONE IS LOCKING
>
	HLRZ	T1,.PDIPC##(W)	;YES
	JUMPN	T1,IPCS6A	;PAGE OUT PACKET IF WONT BE FIRST ON 0
	MOVSI	T1,IPCACE##	;1ST IN QUEUE, IS REC'R HIBERING FOR IPC?
	TDNE	T1,JBTRTD##(J)	
	JRST	IPCS6D		;YES, DONT PAGE OUT THE PAGE
IFN FTPI,<
	HRROI	T1,C$IPC	;NO, IS HE PSI'ING FOR IPC?
	PUSHJ	P,PSITST##
	  JRST	IPCS6A		;NOT ENABLED, PAGE OUT THE PAGE
>	;END IFN FTPI

;ENABLED OR HIBERING FOR THE PAGE, SEE IF ROOM IN CORE
IPCS6D:	MOVE	T1,MAXMAX##	;TOTAL USER CORE ON SYSTEM
	SUB	T1,CORMAX##	;MAX SIZE A JOB CAN BECOME
	LSH	T1,W2PLSH##	;NUMBER OF PAGES AVAILABLE FOR IPCF
	MOVE	T2,%CNPIC##	;NUMBER OF PAGES IN USE BY IPCF
	ADDI	T2,1		;NUMBER WHICH WILL BE IN USE
	CAMLE	T2,T1		;ENOUGH ROOM?
	JRST	IPCS6A		;NO, PAGE OUT THE PAGE
	MOVEM	T2,%CNPIC##	;IPCF PAGES IN CORE
	JRST	IPCS6C		;LEAVE THE PAGE IN CORE
IPCS6A:	MOVE	J,.C0JOB##	;RESTORE J
	MOVE	T2,P2
	PUSHJ	P,IPCPAG##	;PAGE OUT THE PAGE
	  MOVEI	T2,0		;PAGING I/O ERROR
	MOVE	P2,T2
IPCS6C:	HRRM	P2,.IPCFP(P3)	;SAVE DSK ADR IN THE PACKET
IPCS7:>		    ;END FTVM
	MOVEI	T2,.PDIPC##-.IPCFL(W) ;PRESET PREDECESSOR
IPCS8:	HLRZ	T1,.IPCFL(T2)	;NEXT PACKET IN QUEUE
	JUMPE	T1,IPCS9	;END OF QUEUE IF 0
	MOVE	T2,T1		;NOT END, STEP TO NEXT
	JRST	IPCS8
IPCS9:	HRLM	P3,.IPCFL(T2)	;SAVE THIS PACKET ON END OF QUEUE

;COME HERE AFTER THE PACKET IS ON THE RECEIVER'S LIST.

	AOS	.PDIPC##(W)	;INC COUNT
	MOVE	T1,.IPCFS(P3)	;SENDER (MIGHT NOT BE SAME J)
	PUSHJ	P,VALPID	;SET UP (PRIV'D JOB CAN SEND FROM ANOTHER JOB)
	  PJRST	IPCS9A		;BAD - TURNING AROUND MSG TO A DROPPED PID
	MOVEI	T1,IP.SBT	;INCREMENT SEND COUNT
	ADDM	T1,.PDIPC##(W)
	HLRZ	T1,.PDIPA##(W)	;COUNT OF SEND UUOS
	ADDI	T1,1
	TRNE	T1,-1		;OVERFLOW?
	HRLM	T1,.PDIPA##(W)	;NO, STORE INCREMENTED COUNT
IPCS9A:	AOS	%CNIIP##	;INCREMENT OUTSTANDING PACKETS
	AOS	%CNIPS##	;INCREMENT SENT PACKETS

;COME HERE TO AWAKEN A USER JOB OR PUSHJ TO AN EXEC PROCESS
;  THAT HAS JUST HAD A PACKET ARRIVE ON ITS LIST.

	MOVE	T1,.IPCFR(P3)	;RECEIVER'S PID
	PUSHJ	P,VALPID	;SET UP J AND W
	  PJRST	CPOPJ1##	;SHOULD NEVER HAPPEN
	JUMPE	J,EXECPR	;SPECIAL HANDLING FOR EXEC PROCESS
	PUSHJ	P,WAKEUP
	PJRST	CPOPJ1##	;AND GIVE SKIP RETURN

;SUBROUTINE TO STORE CAPABILITIES OF THE SENDER
;CALLING SEQUENCE:
;	MOVEI	T1,ADDRESS OF THE PACKET HEADER
;	MOVE	J,JOB NUMBER OF THE SENDER
;	PUSHJ	P,IPCSCA
;ALWAYS RETURN CPOPJ

IPCSCA:	MOVE	T4,J		;CLEAR CAPABILITIES
	MOVE	T3,JBTSTS##(J)	;GET JBTSTS
	TLNE	T3,JACCT	;SENDER HAS JACCT?
	TLO	T4,IP.JAC	;YES
	TLNE	T3,JLOG		;SENDER HAS JLOG?
	TLO	T4,IP.JLG	;YES
	TRNE	T3,JS.XO	;IS SENDER XCT ONLY?
	TLO	T4,IP.SXO	;YUP!
	MOVE	T3,JBTPRV##(J)	;GET JBTPRV WORD
	TLNE	T3,JP.POK	;CAN SENDER POKE MONITOR?
	TLO	T4,IP.POK	;YES,
	TLNE	T3,JP.IPC	;DOES HE HAVE IPCF PRIVS?
	TLO	T4,IP.IPC	;YES
	MOVEM	T4,.IPCFC(T1)	;AND STORE SENDER'S CAPABILITIES
	POPJ	P,		;RETURN
;COME HERE IF EXEC PROCESS.

EXECPR:	HLRZ	T1,W		;NON-OFFSET LOC OF EXEC CTL BLOCK
	PUSHJ	P,@.EPADR(T1)	;CALL THE PACKET HANDLER
	PJRST	CPOPJ1##	;GIVE SKIP-RETURN
WAKEUP:
	PUSHJ	P,WAKEJB##	;YES, AWAKEN IT.
IFN FTPI,<
	SIGNAL	C$IPC		;SIGNAL MESSAGE AVAILABLE
	  PUSHJ	P,STRSIG
>;END IFN FTPI
	POPJ	P,

IFN FTPI,<
;SUBROUTINE TO STORE REASON WORD IN INTERRUPT VECTOR
STRSIG::MOVE	T1,JBTPDB##(J)	;PDB LOC
	MOVEI	T2,0		;IN CASE NO PACKETS
	HLR	T1,.PDIPC##(T1)	;LOC OF 1ST PACKET
	JUMPE	T1,STRSG1
	MOVE	T2,.IPCFP(T1)	;LENGTH OF TOP PACKET TO LH
	HRR	T2,.IPCFL(T1)	;FLAGS
IFN FTVM,<
	TRNE	T2,IP.CFV	;PAGE?
	HRLI	T2,PAGSIZ##	;YESM LENGTH = 1 PAGE
>
STRSG1:	EXCTXU	<MOVEM T2,3(M)>	;STORE LEN,,FLAGS
	POPJ	P,		; AND RETURN
>
SUBTTL IPCFQ - QUERY UUO

UIPCFQ::HRR	M,T1		;ADDRESS OF UUO BLOCK
	HLRZ	T4,T1		;SAVE COUNT
	PUSHJ	P,GETWRD	;GET WORD 0
	  JRST	ERRAC
	MOVE	T3,T1		;SAVE PRIV BIT
	HLRZ	T2,.PDIPC##(W)	;IS THERE A PACKET?
	SKIPE	T1,T2		;NO
	HRRZ	T1,.IPCFL(T2)	;YES, PASS INFO TO CALLER
	TRNN	T3,IP.SIP	;IS HE PRIV?
	TRZ	T1,IP.SIP	;NO, SUPPRESS PRIV BIT IN PACKET
	PUSHJ	P,PUTWRD##	;STORE .IPCFL
	  JRST	ERRAC		;ADDRESS CHECK.
	SKIPE	T1,T2
	MOVE	T1,.IPCFS(T2)	;SENDER'S PID
	PUSHJ	P,PUTWR1##	;STORE SENDER'S PID
	  JRST	ERRAC
	SKIPE	T1
	MOVE	T1,.IPCFR(T2)	;RECEIVER'S PID
	PUSHJ	P,PUTWR1##	;STORE RECEIVER'S PID
	  JRST	ERRAC		;ADDRESS CHECK
	JUMPE	T1,IPCFQ2
	LDB	T1,[POINT 9,.PDIPC##(W),35] ;COUNT
IFN FTVM,<
	MOVE	T3,.IPCFL(T2)	;FLAGS
	TRNE	T3,IP.CFV	;PAGE?
	TLOA	T1,PAGSIZ##	;YES, LENGTH = 1 PAGE
>
	HLL	T1,.IPCFP(T2)	;LENGTH
IPCFQ2:	PUSHJ	P,PUTWR1##	;STORE IN USER'S CORE
	  JRST	ERRAC		;ADDRESS CHECK
	MOVE	T1,.IPCFU(T2)	;GET SENDERS PPN
	CAIG	T4,.IPCFU	;DID HE ASK FOR IT?
	PJRST	CPOPJ1##	;NO, JUST RETURN
	PUSHJ	P,PUTWR1##	;YES, GIVE IT TO HIM
	  JRST	ERRAC
	MOVE	T1,.IPCFC(T2)	;GET SENDERS PRIVS
	CAIG	T4,.IPCFC	;DID HE ASK FOR THEM?
	  PJRST	CPOPJ1##	;NO, RETURN
	PUSHJ	P,PUTWR1##	;YES, GIVE THEM TO HIM
	  JRST	ERRAC
	PJRST	CPOPJ1##	;SKIP RETURN TO USER
SUBTTL [SYSTEM]IPCF - THE EXEC PROCESS

IPCFPR::PUSHJ	P,SAVE3##
IPCF1:	TLO	M,400000	;SET SO ERR WONT CALL STOTAC
	PUSHJ	P,GETPAK	;GET OLDEST PACKET
	  POPJ	P,		;NONE, EXIT.
	HRRZ	P1,T1		;PACKET ADDRESS
	HRRZ	T4,.IPCFD(P1)	;PICK UP CODE (WORD 0)
IFN FTVM,<
	MOVE	T1,.IPCFL(P1)	;PASSING A PAGE TO [SYSTEM] IPCF?
	TRNN	T1,IP.CFV	;YES, THAT ISN'T LEGAL
>
	CAILE	T4,IPCFM	;VALID?
	SKIPA	T4,BADCOD	;NO, SET FOR ERROR
	MOVE	T4,BADCOD(T4)	;YES, GET DISPATCH ADR
	MOVE	T1,.IPCFS(P1)	;SENDER
	HLRZ	T2,.IPCFP(P1)	;LENGTH
	MOVE	T3,.IPCFL(P1)	;FLAGS
	TRNE	T3,1		;TURNED-AROUND MSG?
	JRST	IPCF3		;YES, JOB MUST HAVE LOGGED OUT
	PUSH	P,W		;PRESERVE W
	TRNN	T3,400000	;JOB HAVE PRIV'S?
	JUMPL	T4,PRVERR	;NO, ERROR IF FUNCTION REQUIORES PRIVS
	LDB	P2,[POINT 3,T4,17] ;GET NEEDED LENGTH OF UUO BLOCK
	CAIGE	T2,(P2)		;UUO BLOCK LONG ENOUGH?
	JRST	SHRTER		;NO, ERROR
	PUSHJ	P,(T4)		;DISPATCH
IPCF2:	  DPB	T1,[POINT 6,.IPCFL(P1),29] ;BAD - STORE ERROR CODE IN FLAG WORD
	PUSHJ	P,DECSND	;DECREMENT SENDER'S COUNTS
	POP	P,W		;RESTORE W

;IN ORDER FOR THE JOB TO RECEIVE THE MSG IT MUST BE ENABLED
;ANSWER WILL THUS ENABLE THE JOB. IN ORDER TO PREVENT THIS
;BIT 0 OF P1 MUST BE LIT BY THE SUBROUTINE (DISABLE FUNCTION)
	PUSHJ	P,ANSWER	;TURN PACKET AROUND TO USER
	JRST	IPCF1		;AND CHECK FOR ANOTHER.

;SUBROUTINE TO GET POINTER TO PACKET INTO T1.

GETPAK:	HLRZ	T1,.PDIPC##(W)	;POINTER OR ZERO
	JUMPE	T1,CPOPJ##	;NONE.
	PJRST	CPOPJ1##	;HAVE ONE - SKIP RETURN
;DISPATCH ERRORS - 
SHRTER:	SKIPA	T1,[IPCNL%]	;UUO BLOCK NOT LONG ENOUGH
PRVERR:	MOVEI	T1,IPCPI%	;PRIV'S INSUFFICIENT
	JRST	IPCF2		;STORE ERROR CODE IN PACKET AND ANSWER

IPCF3:	HLRZ	T1,.IPCFL(P1)	;NEXT PACKET
	HRLM	T1,.PDIPC##(W)	;MAKE IT THE OLDEST
	SOS	.PDIPC##(W)	;FIX UP THE COUNTS
	PUSH	P,W
	LDB	T1,TRNPTR	;SENDER JOB NO
	PUSHJ	P,VALPID	;SET W
	  JRST	IPCF4		;OOPS, HE REALLY IS GONE
	MOVNI	T1,IP.SBT
	MOVE	T2,.PDIPC##(W)	;ANY SENDS NOT YET REC'D?
	TRNE	T2,777000
	ADDM	T1,.PDIPC##(W)	;YES, DECREMENT COUNT
IPCF4:	POP	P,W
	PUSHJ	P,REMPAK	;GET RID OF THIS PACKET
	JRST	IPCF1		;AND GO LOOK AT NEXT PACKET

;SUBROUTINE TO DECREMENT COUNT OF PACKETS SENT BUT NOT RECEIVED
DECSND:	MOVE	T1,.IPCFS(P1)	;SENDERS PID
	PUSHJ	P,VALPID	;GET W
	 TDZA	T1,T1		;SHOULDN'T HAPPEN
	MOVNI	T1,IP.SBT	;DEC COUNT OF SENT BUT NOT
	ADDM	T1,.PDIPC##(W)	; REC'D PACKETS FOR SENDER
	POPJ	P,		;RETURN

DECSSW:	PUSH	P,W
	PUSHJ	P,DECSND
	JRST	WPOPJ##
;DISPATCH TABLE FOR [SYSTEM]IPCF

;EACH SUBROUTINE IS CALLED WITH P1 POINTING TO THE PACKET
; IN EXEC STORAGE
;P2-P4 ARE AVAILABLE FOR USE
;T1=PID OF SENDER  T2=LENGTH OF DATA  T3=FLAGS
;W AND J ARE SET UP FOR RECEIVER, BUT MAY BE CHANGED

BADCOD:	EXP	ERRUF		;(BAD CODE) - UNKNOWN FNCTN
IPCFTB:	XWD	000000,ENABL	;(1)ENABLE
	XWD	000000,DISAB	;(2)DISABLE
	XWD	000003,WHOIS	;(3)TELL PID OF [SYSTEM]INFO
	XWD	400003,MKINFO	;(4)MAKE [SYSTEM]INFO
	XWD	400002,DESTRY	;(5)DESTROY A PID
	XWD	400003,CREATE	;(6)CREATE A PID
	XWD	400003,QUOTA	;(7) SET QUOTA
	XWD	400003,OWNER	;(10)CHANGE OWNERSHIP OF A PID
	XWD	000003,JOBNO	;(11)FIND JOB NUBER FOR A PID
	XWD	000004,RDPIDS	;(12)FIND PID(S) FOR A JOB
	XWD	000003,RDQTA	;(13)FIND QUOTA FOR A JOB
	XWD	400002,CPOPJ1##	;(14)WAKE UP JOB HIB'ING FROM RESET
IPCFRF:	EXP	ERRUF		;(15)SENT BY IPCF ON RESET
	EXP	ERRUF		;(16)
	EXP	ERRUF		;(17)
	EXP	ERRUF		;(20)
	EXP	ERRUF		;(21)
	EXP	ERRUF		;(22)
	EXP	ERRUF		;(23)
	XWD	400003,SIDSET	;(24)SET SYSTEM PID TABLE
	XWD	000003,SIDRD	;(25)READ SYSTEM PID TABLE
IPCFSM:	EXP	ERRUF		;(26)SPOOL MSG SENT "TO" QUASAR
IPCFLM:	EXP	ERRUF		;(27)LOGOUT MESSAGE SENT "TO" QUASAR
IPCFTM:	EXP	ERRUF		;(30)TAPE LABELING MESSAGE
IPCFUO:	EXP	ERRUF		;(31)MOUNTABLE UNIT ON-LINE
IPCFON:	EXP	ERRUF		;(32)LOGON MESSAGE SENT "TO" QUASAR
IPCFAC:	EXP	ERRUF		;(33)ACCOUNTING MESSAGES
.IPCTL==:IPCFTM-IPCFTB+1
.IPCUO==:IPCFUO-IPCFTB+1
IPCFM==.-IPCFTB			;LENGTH OF TABLE
;SUBROUTINE TO GIVE ANSWER TO AN EXEC CALL
ANSWER:	MOVEI	T2,1	
REPEAT 0,<	;NOT NEEDED TILL OTHER EXEC PROCESSES EXIST
	CAMN	T1,PIDTAB##	;SENDER = [SYSTEM]IPCF?
>
;ENTER HERE TO INDICATE MESSAGE SENT BY OTHER THAN IPCC (SENDER'S CODE IN T2)

ANSWE1:	MOVE	T1,.IPCFR(P1)	;SWITCH SENDER & RECEIVER
	DPB	T2,[POINT 3,.IPCFL(P1),32] ;TELL REC'R THAT MSG IS FROM IPCF
	EXCH	T1,.IPCFS(P1)
	MOVEM	T1,.IPCFR(P1)
IFN FTVM,<
	MOVE	T1,.IPCFL(P1)	;IF A WHOLE PAGE PASSED,
	TRNN	T1,IP.CFV	; DON'T CLEAR ITS ADDRESS
>
	HLLZS	.IPCFP(P1)	;ZERO PACKET ADR
  	HLRZ	T1,.IPCFL(P1)	;POINTER TO NEXT PACKET
	HRLM	T1,.PDIPC##(W)	;MAKE IT THE OLDEST.
	SETZM	.IPCFC(P1)	;CLEAR FLAG WRDS ON SEND FROM
	SETZM	.IPCFU(P1)	; AN EXEC PROCESS
	PUSHJ	P,SNDMSG	;RETURN PACKET TO SENDER OF ORIGINAL MSG
	  PUSHJ	P,REMPAK	;COULDNT DO IT - REMOVE THE PACKET
	SOS	.PDIPC##(W)
	AOS	T1,.PDIPA##(W)	;COUNT OF RECEIVES SINCE LOGIN
	TRNN	T1,-1		;OVERFLOW?
	SOS	.PDIPA##(W)	;YES, SET IT BACK
	POPJ	P,		;AND RETURN TO CALLER

;SUBROUTINE TO REMOVE THE OLDEST PACKET.

REMPAK::HRRZ	T2,P1		;ADR OF PACKET TO REMOVE
	SOS	%CNIIP##	;DEC COUNT OF OUTSTANDING PACKETS
	HLRE	T1,.IPCFP(T2)	;LENGTH OF DATA
	ADDI	T1,.IPCFD	;PLUS OVERHEAD
IFE FTVM,<
	PJRST	GIVWDS##	;FREE THE BLOCK AND RETURN
>
IFN FTVM,<
	HRL	T3,.IPCFP(P1)	;SAVE LOC OF DATA FOR MSG
	HRR	T3,.IPCFL(P1)	;SAVE FLAGS
	PUSH	P,T3
	PUSHJ	P,GIVWDS##	;RETURN THE PACKET (OR HEADER)
	POP	P,T1
	TRNN	T1,IP.CFV	;IS IT A PAGE?
	POPJ	P,		;NO, RETURN
	HLRZ	T2,T1		;YES, GET CORE OR DSK ADR OF THE PAGE
	PJRST	IPCDEL##	;AND RETURN IT
>
;SUBROUTINE TO SEND A PACKET.  ADDRESS OF UUO ARGS AND PACKET
;  DATA IN P1.  SOURCE MUST BE AN EXEC PROCESS, TARGET
;  MAY BE EITHER EXEC OR USER.  TARGET MUST BE USER
;  IF AT INTERRUPT LEVEL.  SKIP RETURN ON OK,
;  NON-SKIP RETURN HAS T1=ERROR CODE.

SNDMSG:	PUSHJ	P,SAVE3##	;SAVE P2 AND 3
	MOVE	P2,J		;SAVE J
	MOVE	P3,W		;SAVE W
	MOVE	T1,.IPCFR(P1)	;CHECK RECEIVER
	PUSHJ	P,VALPID	;SET UP J AND W
	  JRST	SNDERR		;DESTINATION UNKNOWN
	MOVSI	T1,400000	;SET TO ENABLE RECEIVER
	TLNN	P1,400000	;UNLESS BIT 0 ON IN P1
	ANDCAM	T1,.PDIPQ##(W)	;HE IS NOW ENABLED
	LDB	T1,[POINT 9,.PDIPQ##(W),35] ;RECEIVE QUOTA
	LDB	T2,[POINT 9,.PDIPC##(W),35] ;RECEIVE COUNT
	CAMG	T1,T2		;ROOM LEFT?
	JRST	SNDERR
	AOS	.PDIPC##(W)	;INCR COUNT OF REC'D MSGS

;COME HERE TO PUT THE MESSAGE ON THE RECEIVER'S LIST
SND0:	CONO	PI,PION##	;TURN PI SYSTEM ON IN CASE IT WAS OFF
	MOVEI	T2,.PDIPC##-.IPCFL(W) ;PRESET PREDECESSOR
SND1:	HLRZ	T1,.IPCFL(T2)	;NEXT PACKET ON QUEUE
	JUMPE	T1,SND2		;GO IF END
	MOVE	T2,T1		;NOT END, SAVE PRED.
	JRST	SND1		;AND STEP TO NEXT
SND2:	CONO	PI,PIOFF##	;NO INTERRUPT HERE
	HLRZ	T1,.IPCFL(T2)	;LAST PACKET ON QUEUE
	JUMPN	T1,SND0		;JUMP IF NOT THE LAST PACKET
				; (QUEUE WAS CHANGED AT INTERRUPT LEVEL
	HRLM	P1,.IPCFL(T2)	;SAVE THIS PACKET ON END OF QUEUE
	HRRZS	.IPCFL(P1)	;ZERO LINK OF THE PACKET
	CONO	PI,PION##	;ALLOW INTERRUPTS AGAIN
;COME HERE AFTER PUTTING PACKET ON LIST.  UPDATE COUNTERS.

	HLRZ	W,.IPCFS(P1)	;RETURN TO SENDER'S PDB
	HRRZ	T1,.EPIPC(W)	;INCREMENT COUNT OF MSGS SENT
	ADDI	T1,IP.SBT
	HRRM	T1,.EPIPC(W)	;GUARD AGAINST OVERFLOW
	HLRZ	T1,.EPIPA(W)	;COUNT OF SENDS
	ADDI	T1,1		;INCREMENT IT
	TRNE	T1,-1		;OVERFLOW?
	HRLM	T1,.EPIPA(W)	;NO, STORE INCREMENTED COUNT
	JUMPN	J,SND3		;IS DEST A USER JOB?
	PUSHJ	P,@.EPADR(W)	;NO, GO RUN EXEC PROCESS.
	JRST	SND4		;RETURN TO MAIN LINE.

;COME HERE TO AWAKEN A USER'S JOB.

SND3:	PUSHJ	P,WAKEUP
SND4:	AOS	%CNIPS##	;INC TOTAL PACKETS SENT
	AOS	(P)		;SKIP RETURN
	JRST	SNDER1		;RESTORE AC'S

;HERE ON A SEND ERROR
SNDERR:	HRRZ	T1,.IPCFD(P1)	;CODE
	CAIE	T1,6		;CREATE A PID?
	JRST	SNDER1		;NO
	MOVE	T2,.IPCFL(P1)	;FLAGS WORD
	TRNE	T2,IP.CFE	;IF NO ERROR ON CREATING THE PID,
	JRST	SNDER1
	MOVE	T1,.IPCFD+2(P1)	;GET RID OF IT
	AND	T1,%IPCPM##	;INDEX INTO TABLE
	SETZM	PIDTAB##(T1)
	SOS	%IPCNP##	;DECR CURRENT # OF PIDS
SNDER1:	MOVE	W,P3		;RESTORE W
	MOVE	J,P2		;RESTORE J
	POPJ	P,0		;RETURN
;ENABLE THE OWNER OF THE PID IN WORD 1, OR THE SENDER IF WORD
;  1 IS NOT PROVIDED.  USE OF WORD 1 IS A PRIV. FUNCTION.
ENABL:
	CAIGE	T2,2		;WORD 1 SUPPLIED?
	PJRST	CPOPJ1		;NO, SENDER IS AUTOMATICALLY ENABLED
	TRNN	T3,IP.SIP	;NO, PRIV'D?
	PJRST	ERRPI		;NO, ERROR
	MOVE	T1,.IPCFD+1(P1)	;YES, GET PID SUPPLIED
	PUSHJ	P,VALPID	;SET UP J AND W.
	  POPJ	P,		;BAD PID, FLUSH
	MOVSI	T1,IP.DSB	;CLEAR JOB'S DISABLE BIT
	ANDCAM	T1,.PDIPQ##(W)
	PJRST	CPOPJ1		;AND GOOD RETURN


;DISABLE THE OWNER OF THE PID IN WORD 1, OR SENDER IF NO WORD 1.
;  USE OF WORD 1 IS A PRIV. FUNCTION.
DISAB:	TRNE	T3,IP.SIP	;PRIV'D?
	CAIGE	T2,2		;YES, WORD 1 SUPPLIED?
	TLOA	P1,400000	;NO, USE SENDER (ALREADY IN T1), DONT ENABLE HIM
	MOVE	T1,.IPCFD+1(P1)	;YES, GET PID SUPPLIED
	CAIL	T2,2		;TRYING TO DISABLE ANOTHER JOB?
	JUMPL	P1,ERRPI	;YES, ERR IF NOT PRIV'D
	PUSHJ	P,VALPID	;SET UP J AND W
	  POPJ	P,		;WRONG, FLUSH
	MOVSI	T1,IP.DSB	;SET JOB'S DISABLE BIT
	IORM	T1,.PDIPQ##(W)
	PJRST	CPOPJ1##	;GOOD RETURN
;MAKE A [SYSTEM]INFO.  ARG IS NOT CHECKED SINCE IT MAY BE
;  DELIBERATELY INVALID (I.E., 0) TO TERMINATE A LOCAL
;  [SYSTEM]INFO OR TO INDICATE THAT THE REAL [SYSTEM]INFO IS LOGGING
;  OUT.
MKINFO:	SKIPN	T1,.IPCFD+2(P1)	;USER OR SYS?
	JRST	MKINF2		;SYS.
	PUSHJ	P,VALPID	;SET UP J AND W FOR TARGET
	  POPJ	P,		;NONE SUCH, FLUSH
	JUMPE	J,CPOPJ##	;NOT VALID FOR EXEC PROCESSES
	SKIPN	%SIINF##	;IF NO GLOBAL OR LOCAL [SYSTEM]INFO
	SKIPE	.PDIPI##(W)	; IS RUNNING THEN MAKING A LOCAL IS OK
	SKIPA	T1,.IPCFS(P1)	;IF SENDER CHECKS OUT
	JRST	MKINF1		;NONE RUNNING NOW - OK
	CAME	T1,%SIINF##	;IS SENDER GLOBAL [SYSTEM]INFO?
	CAMN	T1,.PDIPI##(W)	; OR LOCAL [SYSTEM]INFO?
MKINF1:	SKIPA	T2,.IPCFD+1(P1)	;YES, GET PID TO BECOME THE LOCAL [SYSTEM]INFO
	JRST	ERRPI		;NO, ERROR RETURN
	MOVEM	T2,.PDIPI##(W)	;STORE WITHOUT CHECKING
	PJRST	CPOPJ1##	;GOOD RETURN

;COME HERE TO MAKE SYSTEM'S [SYSTEM]INFO

MKINF2:	MOVE	T1,.IPCFD+1(P1)	;THE PID
	MOVEM	T1,.IPCFD+2(P1)	;MOVE IT OVER
	MOVEI	T1,1		;SYSID INDEX
	MOVEM	T1,.IPCFD+1(P1)	;INTO BLOCK
	PJRST	SIDSET		;USE COMMON CODE


;SEND MESSAGE IDENTIFYING [SYSTEM]INFO

WHOIS:	TRNE	T3,IP.SIP	;PRIV'D?
	SKIPN	T1,.IPCFD+1(P1)	;YES, GET JOB NO WHOSE INFO IS WANTED
	MOVE	T1,.IPCFS(P1)	;NO, TELL HIM HIS OWN [SYSTEM]INFO
	PUSHJ	P,VALPID	;LOAD J AND W
	  POPJ	P,		;BAD PACKET
	SKIPE	J		;EXEC PROCESS HAS NO PDB
	SKIPN	T2,.PDIPI##(W)	;PID OF [SYSTEM]INFO
	MOVE	T2,%SIINF##	;EXEC OR NO LOCAL SPECIFIED
	MOVEM	T2,.IPCFD+1(P1)	;THE ONE WORD OF DATA
	PJRST	CPOPJ1##	;GOOD RETURN
;CREATE A PID. WORD 1 HAS JOB NUMBER, BIT 0=1 IF DROP PID ON RESET
CREATE:	MOVN	P2,%IPCMP##	;SET AOBJN WORD TO SCAN TABLE
	HRLZS	P2
	SKIPE	PIDTAB##(P2)	;FIND AN EMPTY SLOT
	AOBJN	P2,.-1
	JUMPGE	P2,ERRPF	;ERROR IF TABLE FULL
	MOVE	T1,.IPCFD+1(P1)	;USER ARG
	TLZ	T1,400000	;REMOTE TYPE FLAG
	JUMPE	T1,ERRBJ
	TLNN	T1,377777	;ONLY SIGN BIT IS GOOD
	PUSHJ	P,FPDBT1##	 ;GET ITS PDB (INTO T1)
	  PJRST	ERRBJ		;BAD JOB NUMBER OR NO PDB
	AOS	T2,%IPCTP##	;TOTAL # OF PIDS SINCE RELOAD
	LSH	T2,%IPCLS##	;POSITION PAST JOB #/INDEX SLOT
	IOR	T2,.IPCFD+1(P1)	;ADD JOB NO, (BIT 0 IF DROP ON RESET)
	MOVEM	T2,PIDTAB##(P2)
	ANDCM	T2,%IPCPM##	;REMOVE JOB NUMBER
	IORI	T2,(P2)		;INSERT INDEX INTO TABLE FOR PID AS TOLD
	MOVEM	T2,.IPCFD+2(P1)	; TO USER ("PUBLIC" PID)
	MOVSI	T3,IP.DPR
	SKIPL	T2		;DROP PID ON RESET?
	MOVSI	T3,IP.DPL	;NO, DROP ON LOGOUT
	IORM	T3,.PDIPQ##(T1)	;REMEMBER THAT FACT
	AOS	%IPCNP##	;INCR CURRENT # OF PIDS
	PJRST	CPOPJ1##	;AND GOOD RETURN


;FIND JOB NUMBER ASSOCIATED WITH A PID
JOBNO:	MOVE	T1,.IPCFD+1(P1)	;PID
	PUSHJ	P,VALPID	;LEGAL?
	  PJRST	ERRBJ		;NO
	MOVEM	J,.IPCFD+2(P1)	;YES, RETURN JOB NO TO CALLER
	PJRST	CPOPJ1##	;AND TAKE GOOD RETURN

;TELL QUOTA FOR A JOB
RDQTA:	MOVE	T1,.IPCFD+1(P1)	;JOB NUMBER (OR SOME PID FOR JOB)
	PUSHJ	P,VALPID	;LEGAL?
	  PJRST	ERRBJ		;NO
	MOVE	T1,.PDIPQ##(W)	;YES, GET QUOTA
	HRRZM	T1,.IPCFD+2(P1)	;SAVE IN PACKET
	PJRST	CPOPJ1##	;AND GOOD RETURN

;SET QUOTA FOR PID IN WORD 2.

QUOTA:	MOVE	T1,.IPCFD+1(P1)	;PICK UP JOB NUMBER
	PUSHJ	P,VALPID	;SET UP J + W
	  PJRST	ERRBJ		;ERROR, FLUSH
	MOVE	T2,.IPCFD+2(P1)	;GET QUOTA WORD
	HRRM	T2,.PDIPQ##(W)	;STORE AS NEW QUOTA
	PJRST	CPOPJ1##	;GOOD RETURN
;TELL PID(S) ASSOCIATED WITH A JOB
RDPIDS:	MOVEI	P2,-2(T2)	;NUMBER OF VALUES TO RETURN
	SKIPN	T1,.IPCFD+2(P1)	;STARTING PID
	JRST	RDPID1		;START AT BEGINNING OF TABLE
	PUSHJ	P,VALPID	;CHECK IT OUT
	  PJRST	ERRDU		;CANT START AT AN ILLEGAL PID
	MOVE	T1,.IPCFD+2(P1)	;OK, GET PID AGAIN
	AND	T1,%IPCPM##	;GET START INDEX INTO TABLE
RDPID1:	SKIPLE	T2,.IPCFD+1(P1)	;DESIRED JOB NUMBER
	CAILE	T2,JOBMAX##
	PJRST	ERRBJ		;BAD JOB NUMBER
	MOVNS	P2
	HRLZS	P2		;SET AN AOBJN WORD FOR STORING VALUES
	HRR	P2,P1
	MOVN	T3,%IPCMP	;MAKE AN AOBJN WORD
	HRLZS	T3		; FOR SCANNING PIDTAB
	ADDI	T1,1
	HRLS	T1
	ADD	T1,T3
RDPID2:	SKIPE	T3,PIDTAB##(T1)	;GET A PID
	AND	T3,%IPCPM##	;JOB NUMBER
	CAIE	T3,(T2)		;TARGET JOB NO?
	JRST	RDPID3		;NO
	MOVE	T3,PIDTAB##(T1)	;YES, GET FULL PID AGAIN
	ANDCM	T3,%IPCPM##	;REMOVE JOB NO
	IORI	T3,(T1)		;ADD INDEX
	MOVEM	T3,.IPCFD+2(P2)	;SAVE IN PACKET
	AOBJP	P2,CPOPJ1##	;DONE IF NO MORE ROOM
RDPID3:	AOBJN	T1,RDPID2	;SCAN WHOLE TABLE
	SETZM	.IPCFD+2(P2)	;TERMINATE WITH A 0
	PJRST	CPOPJ1##	;AND TAKE GOOD RETURN
;DESTROY A PID.

DESTRY:	MOVE	T1,.IPCFD+1(P1)	;PID BEING DESTROYED
	PUSHJ	P,CHKSID	;SEE IF A SYSTEM PID
	  PJRST	ERRPI		;YES, CAN'T DO THAT
	PUSHJ	P,VALPID	;VALIDATE IT
	  PJRST	ERRBJ		;NO GOOD, FLUSH
	MOVE	P3,W		;OLD PDB LOC IN P3
	MOVE	P2,.IPCFD+1(P1)	;PID
	MOVE	T1,.IPCFS(P1)	;SENDER
	PUSHJ	P,VALPID	;SET UP W
	  POPJ	P,		;NO GOOD (SHOULD NEVER HAPPEN)
	CAMN	P2,.IPCFS(P1)	;SENDER DESTROYING HIS OWN PID?
	MOVEM	J,.IPCFS(P1)	;YES, SEND ANSWER BACK TO THE JOB NO.
	MOVE	T2,P2
	AND	T2,%IPCPM##	;MASK TO INDEX
	SETZM	PIDTAB##(T2)
	PUSHJ	P,CHANGE	;PUT ANY MSGS FOR PID INTO SENDER'S QUEUE
	SOS	%IPCNP##	;DECREMENT COUNT OF CURRENT PID'S
	MOVE	J,HIGHJB##	;DO ALL JOBS
DSTRY1:	PUSHJ	P,FNDPDB##	;SET UP W
	JRST	DSTRY2		;NO JOB
	CAMN	P2,.PDIPI##(W)	;DESTROY LOCAL INFO FOR THIS JOB?
	SETZM	.PDIPI##(W)	;CLEAR IT!
DSTRY2:	SOJG	J,DSTRY1		;LOOP FOR ALL JOBS.
	PJRST	CPOPJ1##	;AND GOOD RETURN

;CHANGE THE OWNERSHIP OF A PID.  WORD 1 HAS THE PID, WORD 2 THE NEW
; JOB NUMBER.

OWNER:	MOVE	T1,.IPCFD+1(P1)	;PID TO CHANGE
	PUSHJ	P,CHKSID	;SEE IF A SYSTEM PID
	  PJRST	ERRPI		;YES, CAN'T DO THAT
	PUSHJ	P,VALPID	;SET UP J + W
	  PJRST	ERRDU		;BAD PID
	MOVE	T2,.IPCFD+1(P1)	;GET PID BEING CHANGED
	CAMN	T2,.IPCFS(P1)	;GIVING SELF AWAY?
	MOVEM	J,.IPCFS(P1)	;YES, SEND BACK TO JOB
	JUMPE	J,ERRDU		;CANNOT CHANGE OWNERSHIP OF EXEC PROC.
	MOVE	P3,W		;SOURCE PDB
	SKIPLE	J,.IPCFD+2(P1)
	PUSHJ	P,FNDPDB##	;FIND JOB'S PDB
	  PJRST	ERRBJ		;CANT FIND PDB, BAD JOB NO
	MOVE	P2,.IPCFD+1(P1)	;PID TO CHANGE IN P2
	PUSHJ	P,CHANGE	;CHANGE THE OWNERSHIP OF THE PID
	MOVE	T1,P2		;GET OLD PID
	AND	T1,%IPCPM##	;MASK TO INDEX
	MOVE	T2,PIDTAB##(T1)	;GET OLD PID
	ANDCM	T2,%IPCPM##	;REMOVE OLD JOB
	IOR	T2,.IPCFD+2(P1)	;INCLUDE NEW JOB
	MOVEM	T2,PIDTAB##(T1)	;STORE BACK IN PID TABLE
	PJRST	CPOPJ1##	;AND GOOD RETURN
;SUBROUTINE TO CHANGE THE OWNERSHIP OF A PID
;ENTER W=PDB OF NEW OWNER  P2=PID TO CHANGE  P3=PDB OF OLD OWNER
CHANGE:	MOVEI	T1,.PDIPC##-.IPCFL(W) ;PRESET PREDECESSOR
CHNGE1:	HLRZ	T2,.IPCFL(T1)	;STEP TO NEXT
	JUMPE	T2,CHNGE2
	MOVE	T1,T2		;NEW PREDECESSOR
	JRST	CHNGE1		;FIND END OF QUEUE FOR NEW OWNER
CHNGE2:	MOVEI	T2,.PDIPC##-.IPCFL(P3) ;WHERE TO UNQUEUE FROM

CHNGE3:	HLRZ	T3,.IPCFL(T2)	;NEXT ITEM FROM QUEUE
	JUMPE	T3,CPOPJ##	;DONE IF 0
	CAME	P2,.IPCFR(T3)	;FOR THE PID BEING CHANGED?
	JRST	CHNGE4		;NO
	CAMN	W,P3		;CHANGING OWNERSHIP TO SAME JOB NO?
	MOVEM	J,.IPCFR(T3)	;YES, MAKE REC'R BE THE JOB ITSELF
				; (OTHERWISE A LOOP MAY RESULT)
	HRLM	T3,.IPCFL(T1)	;YES, PUT ON NEW QUEUE
	MOVE	T4,.IPCFL(T3)	;QUEUE POINTER OF THIS PACKET
	HLLM	T4,.IPCFL(T2)	;REMOVE FROM OLD QUEUE
	HRRZS	.IPCFL(T3)	;LAST ENTRY ON NEW QUEUE
	PUSH	P,T2
	PUSH	P,T3
	PUSHJ	P,WAKEUP	;PSI OR UNHIBER NEW RECEIVER
	POP	P,T1
	POP	P,T2
	SOS	.PDIPC##(P3)	;UPDATE COUNTS FOR OLD AND NEW OWNERS
	AOSA	.PDIPC##(W)
CHNGE4:	MOVE	T2,T3		;STEP TO NEXT ENTRY IN (OLD) QUEUE
	JRST	CHNGE3		;AND TEST IT
;FUNCTION 24:  SET SYSTEM PID TABLE

SIDSET:	PUSHJ	P,CHKIDX	;GET INDEX AND CHECK IT
	  JRST	ERRBI		;BAD INDEX
	JUMPE	T2,ERRBI	;DON'T LET HIM SET IPCC
	SETZ	J,		;IN CASE CLEARING THE TABLE
	SKIPN	T1,.IPCFD+2(P1)	;GET PID FROM USER
	JRST	SETST1		;ZERO MEANS CLEAR THE ENTRY
	PUSHJ	P,VALPID	;VALIDATE THE PID
	  POPJ	P,		;RETURN ERROR CODE
	MOVE	T2,.IPCFD+1(P1)	;GET INDEX BACK
	MOVE	T1,.IPCFD+2(P1)	;GET THE PID
SETST1:	MOVE	T3,SIDJOB##(T2)	;CHECK OWNER
	CAME	T3,.C0JOB##	;AGAINST CALLER
	JUMPN	T3,ERRPI	;ERROR IF NOT OWNER OF TABLE ENTRY
	MOVEM	T1,.GTSID##(T2)	;STORE IT
	MOVEM	J,SIDJOB##(T2)	;AND IN JOB NUMBER TABLE
	CAIN	T2,1		;[SYSTEM]INFO
	MOVEM	T1,%CNIPI##	;YES, UPDATE OLD GETTAB
	JRST	CPOPJ1		;AND RETURN SUCCESS

;FUNCTION 25:  READ SYSTEM PID TABLE

SIDRD:	PUSHJ	P,CHKIDX	;GET INDEX AND CHECK IT
	  JRST	ERRBI		;BAD INDEX
	MOVE	T1,.GTSID##(T2)	;GET THE PID
	MOVEM	T1,.IPCFD+2(P1)	;GIVE IT TO THE USER
	PJRST	CPOPJ1		;AND RETURN SUCCESSFUL


;CHKIDX  --  ROUTINE TO VALIDATE INDEX AND RETURN IT IN T2.
;	SKIP IF OK, NON-SKIP IF NO GOOD.
CHKIDX:	MOVEI	T1,SIDMXL##	;GET <MAX>B26
	LSH	T1,-^D9		;SHIFT IT OVER
	SKIPL	T2,.IPCFD+1(P1)	;GET THE INDEX
	CAMLE	T2,T1		;IN RANGE?
	POPJ	P,		;NO
	PJRST	CPOPJ1		;YES
;HERE FROM UUOCON ON A LOGOUT UUO
IPCLGO::PUSHJ	P,SAVE2##	;SAVE P1
IFN FTGALAXY,<
	PUSHJ	P,QSRLGO	;SEND LOGOUT MESSAGE TO QUASAR
>
	SETO	P1,		;SETUP MASK TO TEST PIDS
	MOVSI	T1,IP.DPL	;LOAD UP THE LOGOUT FLAG
	JRST	IPCFR1		;SEND MSG TO INFO, DROP PIDS ETC.

;HERE FROM UUOCON ON A RESET UUO.  SEND A MESSAGE TO INFO AND
;	DESTROY THE APPROPRIATE PIDS.
IPCFRS::PUSHJ	P,SAVE2##	;SAVE P1
	MOVSI	P1,(1B0)	;MASK FOR PIDS TO DROP
	MOVSI	T1,IP.DPR	;SET UP CONDITION FOR TEST

;COMMON CODE FOR RESET AND LOGOUT STARTS HERE
IPCFR1:	PUSHJ	P,FNDPDS##	;SET UP W
	PUSHJ	P,TURNQ		;TURN ANY MSGS AROUND FOR THIS JOB
	TDNN	T1,.PDIPQ##(W)	; IF CONDITIONS AREN'T MET
	POPJ	P,		;DONT SEND A MSG TO ANYBODY
	ANDCAM	T1,.PDIPQ##(W)	;AND SAY "NO MORE"
	MOVEI	T2,IPCFRF-IPCFTB+1  ;CODE FOR RESET/LOGOUT
	MOVEM	T2,INFMSG##	;SAVE IT
	HRR	T1,J			;GET FLAG,,JOB
	MOVEM	T1,INFMSG##+1	;STORE

	MOVN	P2,%IPCMP	;SET AN AOBJN WORD FOR LOOKING
	HRLZS	P2		; AT ALL OF PIDTAB
IPCLG1:	MOVE	T2,PIDTAB##(P2)	;PIDTAB ENTRY
	TDNN	P1,T2		;DROP THIS PID?
	JRST	IPCLG2		;NO--KEEP LOOKING
	MOVE	T1,T2		;COPY PID
	AND	T2,%IPCPM	;JOB NUMBER
	CAIE	T2,(J)		;FOR THIS JOB?
	JRST	IPCLG2		;NO
	SETZM	PIDTAB##(P2)	;YES, CLEAR IT
	SOS	%IPCNP##	;1 LESS PID CURRENTLY ACTIVE
	TDZ	T1,%IPCPM	;REMOVE JOB NUMBER
	IORI	T1,0(P2)	;INSERT PIDTAB INDEX
	MOVEI	T2,SIDMXL##	;NUMBER OF SYSTEM PIDS
	LSH	T2,-^D9		;POSITION IT
	CAMN	T1,.GTSID##(T2)	;THIS IT
	JRST	[SETZM	.GTSID##(T2)	;YES, CLEAR ENTRY
		 SETZM	SIDJOB##(T2)	;AND THE JOB NUMBER
		 JRST	.+1]	;RETURN A LINE
	SOJGE	T2,.-2		;TRY THE NEXT
	MOVE	T2,%SIINF##	;UUO'S PID
	MOVEM	T2,%CNIPI##	;KEEP THE GETTAB STRAIGHT
IPCLG2:	AOBJN	P2,IPCLG1	;DO FOR ALL ENTRIES IN PIDTAB
	MOVEI	T1,%SIINF##	;LOCATION OF INFO'S PID
	SKIPE	.PDIPI##(W)	;PRIVATE INFO?
	MOVEI	T1,.PDIPI##(W)	;YES, USE IT
	MOVE	T2,[2,,INFMSG##]  ;POINT TO MESSAGE
	PJRST	SENDSN		;SEND IT AND RETURN
;SUBROUTINE TO TURN MESSAGES AROUND FOR A JOB ON RESET/LOGOUT
;CALL WITH T1=IP.DPR OR IP.DPL IN T1
;IF IP.DPR, TURNS AROUND ONLY THOSE MESSAGES FOR PIDS TO BE DROPPED ON RESET
;IF IP.DPL, TURNS AROUND ALL MESSAGES
;PRESERVES T1
TURNQ:	PUSHJ	P,SAVE3##	;SAVE P1,-P3
	PUSH	P,J		;SAVE J
	MOVE	P3,J
	PUSH	P,T1
	MOVEI	P2,.PDIPC##-.IPCFL(W) ;PRESET PREDECESSOR
	TLNN	T1,IP.DPR
	TLO	P2,-1		;P2 NEGATIVE IF LOGOUT
TURNQ0:	HLRZ	P1,.IPCFL(P2)	;GET NEXT ENTRY IN QUEUE FOR JOB
TURNQ1:	JUMPE	P1,TURNQ7	;DONE IF 0
	SKIPL	T1,.IPCFR(P1)	;IF REC'R IS TO BE DROPPED ON LOGOUT,
	JUMPGE	P2,TURNQ6	; STEP TO NEXT PACKET IF THIS IS RESET
	AOS	T2,.IPCFL(P1)	;SET BIT 35 (UNDELIVERABLE) IN PACKET HEADER
	TRNE	T2,2		;ALREADY BEEN THIS WAY?
	JRST	TURNQ5		;YES, MAKE THE PACKET GO AWAY
	EXCH	T1,.IPCFS(P1)
	MOVEM	T1,.IPCFR(P1)
	PUSH	P,W		;SAVE W
	PUSHJ	P,VALPID	;SET W FOR REC'R (ORIGINAL SENDER)
	  JRST	TURNQ4		;HE'S GONE TOO - REMOVE THE PACKET
	DPB	P3,TRNPTR	;SAVE JOB NUMBER FOR TURN-AROUND RCV.
	MOVE	T2,.PDIPC##(W)	;CURRENT COUNT OF SENDS & REC'S
	TRNN	T2,777000	;ANY PACKETS SENT, NOT REC'D?
	AOSA	T2		;NO, JUST INCR REC'S (SEND FROM JOB NUMBER N)
	SUBI	T2,777		;YES, DECR SEND COUNT, INCR REC COUNT
	MOVEM	T2,.PDIPC##(W)	;STORE UPDATED NUMBER
	MOVEI	T1,.PDIPC##-.IPCFL(W) ;SET TO FIND END OF NEW QUEUE
	EXCH	W,(P)		;RESTORE W OF LOGGING-OUT JOB
	MOVEI	T2,777		;ADJUST COUNT OF OLD JOB
	ADDM	T2,.PDIPC##(W)
TURNQ2:	HLRZ	T2,.IPCFL(T1)
	JUMPE	T2,TURNQ3	;FOUND END IF NEXT=0
	MOVE	T1,T2		;NOT END, GET NEXT
	JRST	TURNQ2
TURNQ3:	HRLM	P1,.IPCFL(T1)	;STICK THIS PACKET ON END OF QUEUE
	MOVE	T1,.IPCFL(P1)	;LINK TO NEXT IN OLD JOB'S QUEUE
	HRRZS	.IPCFL(P1)	;THIS IS END IN FORMER SENDER'S QUEUE
	HLRZ	P1,T1		;POINT P1 TO NEXT IN OLD QUEUE
	HRLM	P1,.IPCFL(P2)	;LINK NEXT TO PREDECESSOR IN OLD Q
	JUMPN	J,[POP P,(P)
		   PUSHJ P,WAKEUP   ;WAKE UP ORIGINAL SENDER
		   JRST  TURNQ1]  ;GO TURN AROUND NEXT MSG
	EXCH	W,(P)
	HLRZ	T1,W		;LOC OF EXEC PID
	PUSHJ	P,@.EPADR(T1)	;CALL THE EXEC PROCESS
	POP	P,W
	JRST	TURNQ1		;GO TURN AROUND NEXT MSG IN QUEUE

;HERE IF MSG COULDN'T BE TURNED AROUND
TURNQ4:	POP	P,W		;RESTORE W
TURNQ5:	HLRZ	T1,.IPCFL(P1)	;LINK TO NEXT PACKET
	HRLM	T1,.IPCFL(P2)	;MAKE NEXT IN QUEUE
	PUSHJ	P,REMPAK	;REURN THIS PACKET TO FREE CORE
	JRST	TURNQ0		;AND TRY NEXT PACKET

;HERE IF PACKET IS FOR A PID TO BE DROPPED ON LOGOUT, THIS IS RESET
TURNQ6:	HRR	P2,P1		;SAVE POINTER TO LAST ON OLD QUEUE
	JRST	TURNQ0		;GO PROCESS NEXT QUEUE ENTRY

;HERE WHEN DONE
TURNQ7:	POP	P,T1		;RESET T1
	PJRST	JPOPJ##		;AND RETURN TO CALLER
SUBTTL	IPCC INTERFACE FOR GALAXY-10

IFN FTGALAXY,<
IFN FTSPL,<
;HERE ON THE CLOSE OF A SPOOLED FILE FROM FILUUO.  CALLED WITH F
;	CONTAINING THE ADDRESS OF THE SPOOLED DDB.

QSRSPL::PUSHJ	P,SAVT##		;SAVE T1 - T4
	PUSH	P,J			;SAVE J
	LDB	J,PJOBN##		;LOAD UP J
	MOVSI	T1,SPMSIZ		;MESSAGE SIZE
	HRRI	T1,IPCFSM-IPCFTB+1	;SPOOL FUNCTION
	PUSHJ	P,SETQSR		;SETUP THE PACKET
	PUSHJ	P,FNPDBS##		;SETUP W
	MOVE	T1,.PDNM1##(W)		;GET FIRST HALF OF USER NAME
	MOVEM	T1,QSRMSG##+SPMUSR	;STORE IT
	MOVE	T1,.PDNM2##(W)		;GET SECOND HALF OF USER NAME
	MOVEM	T1,QSRMSG##+SPMUSR+1	;STORE IT
	MOVE	T1,DEVNAM(F)		;GET INITED DEVICE
	MOVEM	T1,QSRMSG##+SPMIDV	;AND SAVE IT
	HLRZ	T1,DEVUNI##(F)		;GET ADR OF UDB
	HRRZ	T1,UNISTR##(T1)		;GET ADR OF SDB
	MOVE	T1,STRNAM##(T1)		;GET STRUCTURE NAME
	MOVEM	T1,QSRMSG##+SPMSTR	;STORE IT
	MOVE	T1,DEVFIL(F)		;GET FILENAME
	MOVEM	T1,QSRMSG##+SPMFIL	;STORE IT
	MOVE	T1,DEVPPN(F)		;GET THE PPN OF FILE
	MOVEI	T2,GALIUD		;GET "IN USER'S DIRECTORY" BIT
	CAME	T1,QUEPPN##		;IS FILE IN THE QUE DIRECTORY?
	IORM	T2,QSRMSG##+GALSTS	;NO, SET BIT
	SKIPN	T1,DEVSPN##(F)		;GET ENTER'ED NAME IF SETUP
	MOVE	T1,JBTNAM##(J)		;USE PROG NAME IF 0.
	MOVEM	T1,QSRMSG##+SPMEFN	;AND SAVE IT
	MOVE	T1,DEVACC##(F)		;GET ADDRESS OF ACCESS TABLE
	MOVE	T1,ACCWRT##(T1)		;GET BLOCKS WRITTEN
	MOVEM	T1,QSRMSG##+SPMFSZ	;AND SAVE FILE SIZE
	HRLZ	T1,DEVSPM##(F)		;GET ADDRESS OF SPOOLING PARAMETER BLOCK
	JUMPE	T1,QSRSP1		;IF NO PARAMETER BLOCK
	HRRI	T1,QSRMSG##+SPMPRM	;WHERE TO COPY BLOCK TO
	BLT	T1,QSRMSG##+SPMSIZ	;COPY TO END OF MESSAGE
	JRST	QSRSP2			;AND SEND IT ALL
QSRSP1:	MOVE	T1,[QSRMSG##+SPMPRM,,QSRMSG##+SPMPRM+1]
	SETZM	QSRMSG##+SPMPRM		;CLEAR FIRST WORD
	BLT	T1,QSRMSG##+SPMSIZ	;CLEAR REST SINCE NO SPOOLING PARAMETERS
QSRSP2:
	MOVEI	T1,%SIQSR##		;GET LOCATION OF QUASAR'S PID
	MOVE	T2,[SPMSIZ,,QSRMSG##]	;GET LEN,,ADR
	PUSHJ	P,SENDSN		;AND SEND THE MESSAGE
	JRST	JPOPJ##
>	;END IFN FTSPL

;STILL IN IFN FTGALAXY
;STILL IN IFN FTGALAXY

;HERE ON LOGOUT UUO.  LOGOUT MESSAGE IS SENT TO QUASAR IF %SIQSR
;	CONTAINS A VALID PID.

QSRLGO:	MOVSI	T1,LGMSIZ	;SIZE OF MESSAGE
	HRRI	T1,IPCFLM-IPCFTB+1 ;CODE
	PUSHJ	P,SETQSR	;SETUP THE MESSAGE
	MOVEI	T1,%SIQSR##	;GET ADR OF QUASAR'S PID
	MOVE	T2,[LGMSIZ,,QSRMSG##]	;GET LEN,,ADR
	PJRST	SENDSN		;SEND THE MESSAGE


;HERE ON LOGIN UUO TO SEND MESSAGE TO QUASAR

QSRLGI::MOVSI	T1,LOMSIZ	;SIZE OF MESSAGE
	HRRI	T1,IPCFON-IPCFTB+1  ;CODE
	PUSHJ	P,SETQSR	;SETUP THE MESSAGE
	DMOVE	T1,.PDNM1(W)	;GET USER NAME
	DMOVEM	T1,QSRMSG+LOMUSR  ;STORE
	PUSH	P,F
	MOVE	F,TTYTAB##(J)
	PUSHJ	P,CTLJBD##
	MOVEM	T1,QSRMSG##+LOMCTL
	MOVE	T1,DEVNAM(F)
	MOVEM	T1,QSRMSG##+LOMTTY
	POP	P,F
	MOVEI	T1,%SIQSR
	MOVE	T2,[LOMSIZ,,QSRMSG##]
	PJRST	SENDSN		;AND SEND MESSAGE TO QUASAR

;SETQSR  --  ROUTINE TO SETUP A PACKET TO SEND TO QUASAR.  CALL
;	WITH T1 CONTAINING SIZE,,CODE, RETURN QSRMSG BLOCK
;	WITH GALMSG AND GALSTS ALL SETUP.

SETQSR:	MOVEM	T1,QSRMSG##+GALMSG	;AND STORE FIRST WORD
	HRLZ	T1,J			;GET JOB,,0
IFN FTNET,<
	HRRZ	T2,JBTLOC##(J)		;GET HIS LOCATION
	LSH	T2,^D9			;SHIFT OVER 9 BITS
	IOR	T1,T2			;OR IT IN
>  ;END IFN FTNET
	MOVSI	T2,(JB.LBT)		;GET BATCH BIT
	TDNE	T2,JBTLIM##(J)		;IS HE A BATCH JOB?
	TRO	T1,GALBAT		;YES, SET THE FLAG
	MOVEI	T2,JB.DFR		;GET DEFERED BIT
	TDNE	T2,JBTSPL##(J)		;TEST IT
	TRO	T1,GALDFR		;ITS ON
	MOVEM	T1,QSRMSG##+GALSTS	;AND STORE 2ND DATA WORD
	POPJ	P,			;AND RETURN



>  ;END OF IFN FTGALAXY
IFN FTMDA,<
;SUBROUTINE TO SEND THE CONTENTS OF T1 AND T2 TO [SYSTEM]MDC
;CALLING SEQUENCE:  (MAY BE CALLED AT INTERRUPT LEVEL)
;	MOVE	T1,UNIT NAME
;	MOVEI	T2,DEVICE TYPE
;	PUSHJ	P,SNDMDC
;RETURNS CPOPJ IF THE MESSAGE COULDN'T BE SENT, CPOPJ1 IF OK

SNDMDC::PUSH	P,T1		;SAVE ARGUMENTS
	PUSH	P,T2
	MOVEI	T2,3		;GET THREE WORDS OF FREE STORAGE
	PUSHJ	P,GETWDS##
	  JRST	[POP	P,T2	;FAIL
		 JRST	TPOPJ##]
	MOVEI	T2,.IPCUO
	MOVEM	T2,(T1)
	POP	P,2(T1)		;DEVICE TYPE
	POP	P,1(T1)		;UNIT NAME
	PUSH	P,T1		;SAVE FREE CORE ADDRESS
	MOVE	T2,T1		;ADDRESS OF THE MESSAGE
	MOVEI	T1,%SIMDC##	;PID OF [SYSTEM]MDC
	HRLI	T2,3		;LENGTH OF THE MESSAGE
	PUSH	P,J		;SAVE J
	SETZB	J,T4		;JOB NUMBER AND PPN OF SENDER ARE ZERO
	PUSHJ	P,SENDS0	;SEND THE MESSAGE
	  SOS	-2(P)		;FAILED
	POP	P,J		;RESTORE J
	POP	P,T2		;AND FREE CORE ADDRESS
	MOVEI	T1,3		;RETURN THREE WORDS TO FREE CORE
	AOS	(P)		;SKIP RETURN IF SUCCESSFUL
	PJRST	GIVWDS##	;RETURN FREE CORE
>
;SUBROUTINE TO SEND A PACKET TO A PID AND WAIT FOR A RESPONSE
; FROM THE RECEIVER
;CALLING SEQUENCE:
;	MOVE	T1,["SENT BY",,%SIDXXX]
; OR	MOVE	T1,RECEIVER'S PID
;	MOVE	T2,[LENGTH,,ADDRESS]
;	MOVE	T3,SENDER'S PID
;	MOVE	T4,SENDER'S PPN
;	PUSHJ	P,SENDSP	;IF SENDING TO A SPECIAL SYSTEM PROCESS
; OR	PUSHJ	P,SENDAP	;IF SENDING TO AN ARBITRARY PID
;RETURNS CPOPJ IF THE MESSAGE COULLD NOT BE DELIVERED
; RETURNS CPOPJ1 IF THE MESSAGE WAS SUCCESSFULLLY SENT AND A REPLY
; HAS BEEN RECEIVED. THE POINTER TO THE PACKET RECEIVED IS IN .PDEPA.
; IT IS THE CALLLER'S RESPONSIBILLITY TO RETURN THE PACKET TO MONITOR
; FREE CORE AFTER PROCESSING ITS CONTENTS

SENDAP::PUSHJ	P,SAVE4##
	MOVE	P4,T3
	MOVE	P3,T1
	MOVE	P2,T2
	PUSHJ	P,VALPID
	  POPJ	P,
	AND	P3,%IPCPM##
	ADDI	P3,PIDTAB##	;ADDRESS OF THE PID IN PIDTAB
	MOVE	J,.C0JOB##
	PUSHJ	P,SENDS1
	  POPJ	P,
	JRST	SENDP1
SENDSP::MOVE	J,.C0JOB##
	PUSHJ	P,SENDS0
	  POPJ	P,
SENDP1:	MOVEI	T1,EV.IPC
	PUSHJ	P,ESLEEP##
	HRRZ	T1,.PDEPA##(W)
	JUMPN	T1,SENDP1	;THIS DEPENDS ON A SYSTEM PROCESS NOT SENDING TO
				;[SYSTEM]IPCC
	PJRST	CPOPJ1##
;HERE ON RECEIPT OF A MESSAGE SENT TO THE EXEC PSUEDO-PROCESS
; [SYSTEM]GOPHER  IF THE INTENDED RECEIVING PROCESS IS BLOCKED WAITING
; FOR A RESPONSE, STORE THE ADDRESS OF THE PACKET IN THE RECEIVER'S
; PDB AND WAKEUP THE RECEIVER. OTHERWISE, RETURN THE PACKET AS
; UNDELIVERABLE.

IPCSPR::PUSHJ	P,SAVE1##
IPCSP1:	PUSHJ	P,GETPAK
	  POPJ	P,
	HRRZ	P1,T1
	MOVE	T1,.IPCFD(P1)
	MOVE	J,T1
	PUSHJ	P,FPDBT1##	;VALIDATE JOB NUMBER AND GET OBJECT JOB'S PDB
	  JRST	IPCSP2
	MOVE	T2,.IPCFS(P1)
	LDB	T3,JBYEWT##
	CAMN	T2,.PDEPA##(T1)
	CAIE	T3,EV.IPC
	JRST	IPCSP2
	HRLZM	P1,.PDEPA##(T1)
	MOVE	T1,J
	PUSHJ	P,EWAKE##
	SOS	.PDIPC(W)
	HLRZ	T1,.IPCFL(P1)
	HRLM	T1,.PDIPC##(W)
	PUSHJ	P,DECSSW
	SOS	%CNIIP
	JRST	IPCSP1
IPCSP2:	MOVEI	T1,IPCDU%
	DPB	T1,[POINT 6,.IPCFL(P1),29]
	PUSHJ	P,DECSSW
	MOVEI	T2,4
	PUSHJ	P,ANSWE1
	JRST	IPCSP1

SUBTTL	MONITOR INTERFACE ROUTINES

;SENDSI -- ROUTINE TO SEND A MESSAGE TO ANY SPECIAL SYSTEM PROCESS 
;
;CALL:
;	MOVEI	T1,%SIXXX
;	HRLI	T1,"SENT BY [SYSTEM]?", 0 IF IPCC
;	MOVE	T2,[XWD LEN,ADR]
;	MOVE	T3,SYSTEM PID, IGNORED IF IPCC
;	PUSHJ	P,SENDSI
;
;	ALWAYS RETURN HERE
;
;USES T1-T4
;
;NOTE: THE BLOCK SPECIFIED BY THE CALLER BELONGS "TO THE CALLER".
;	IT IS COPIED AND RETURNED TO THE CALLER INTACT.  SPECIFICALLY,
;	IF THE CALLER GOT THE BLOCK FROM THE SYSTEM FREE SPACE, "HE"
;	MUST RETURN IT.
;
SENDSN::PUSHJ	P,SENDSI
	  POPJ	P,
	POPJ	P,

SENDSI::MOVE	T4,JBTPPN##(J)	;SENDER'S PPN
;ENTER HERE WITH (T4) = SENDER'S PPN
SENDS0:	SKIPN	0(T1)
	POPJ	P,
	PUSHJ	P,SAVE4##	;SAVE P1-P4
	MOVE	P4,T3
	MOVE	P3,T1		;SAVE T1
	MOVE	P2,T2		; AND T2
	MOVE	P1,T4
	TLNE	P3,-1
	JRST	SENDS1
	HRLI	P3,10
	MOVE	P4,PIDTAB##

;FALL INTO SENDS1
SENDS1:	HLRZ	T2,P2		;GET LENGTH
	ADDI	T2,.IPCFD	;ADD HEADER
	PUSHJ	P,GETPKT	;GET FREE SPACE
	  POPJ	P,
	MOVEM	P1,.IPCFU(T1)
	HLRZM	P3,.IPCFL(T1)
	MOVEM	P4,.IPCFS(T1)
	HRL	P1,P2		;GET SOURCE,,0
	HRRI	P1,.IPCFD(T1)	;GET SOURCE,,DEST
	HLRZ	P4,P2		;GET LEN
	MOVSI	T2,IP.LPK	;GET "LARGE PACKET"
	CAMLE	P4,%CNIPL##	;IS IT LARGE?
	IORM	T2,.IPCFL(T1)	;YES, SET IT
	ADDI	P4,.IPCFD-1(T1)	;GET END OF MSG
	BLT	P1,(P4)		;MOVE THE MSG OVER
	MOVE	T2,(P3)		;GET RECEIVER'S PID
	MOVEM	T2,.IPCFR(T1)	;SAVE IT
	PUSHJ	P,FNDPDS##	;SENDER'S PDB
	MOVEM	T2,.PDEPA##(W)	;STORE THE PID OF WHO CAN ANSWER
	HLLZM	P2,.IPCFP(T1)	;STORE LENGTH
	PUSHJ	P,IPCSCA	;SET CAPABILITIES OF THE JOB PACKET IS BEING SENT FOR
	MOVE	P1,T1		;PUT ADDRESS IN P1
	PUSHJ	P,SNDMSG	;SEND IT
	  JRST	SENDS2		;LOSE!
	AOS	%CNIIP		;ONE MORE IN
	JRST	CPOPJ1##

SENDS2:	HLRZ	T1,P2		;GET MSG LENGTH
	ADDI	T1,.IPCFD	;ADD HDR SIZE
	HRRZ	T2,P1		;GET ADR
	PJRST	GIVWDS##	;RETURN SPACE AND RETURN
;GETPKT  --  GET A PACKET OF FREE CORE.  CALL WITH T2 CONTAINING
;	NUMBER OF WORDS NEEDED.  RETURNS WITH ADDRESS OF PACKET
;	IN T1.  GETPKT "WAITS" IF NO FREE SPACE IS AVAILABLE.  ALWAYS
;	RETURNS CPOPJ.

GETPKT:	PUSHJ	P,GETWDS##		;GET THE FREE SPACE
	  JRST	GETPK1			;LOSE, WAIT
	JRST	CPOPJ1##		;WIN!!

GETPK1:	JUMPE	J,CPOPJ##	;LOSE IF AT INTERRUPT LEVEL
	PUSH	P,T2
	MOVEI	T1,1			;ONE SECOND
	PUSH	P,F
	PUSHJ	P,SLEEP##		;SLEEP
	POP	P,F
	POP	P,T2
	JRST	GETPKT			;AND TRY AGAIN


;CHKSID  --  CHECK IF PID IS ONE OF THE "FRIENDS OF THE MONITOR"
;CALLED WITH T1=THE PID
;DESTROYS T2
;RETURNS CPOPJ IF TRUE, CPOPJ1 OTHERWISE

CHKSID:	MOVEI	T2,SIDMXL##	;NUMBER OF PIDS<B26>
	LSH	T2,-^D9		;POSITION IT
CHKS.1:	CAMN	T1,.GTSID##(T2)	;THIS IT
	POPJ	P,		;YES, RETURN
	SOJGE	T2,CHKS.1	;NO, TRY THE NEXT
	JRST	CPOPJ1##	;NOT A SYSTEM
	LIT
IPCEND:	END