;<135-TENEX>SIGNAL.MAC;57    11-Aug-76 16:17:35    EDIT BY CALVIN
; Move NOINT at .SIGNL+4 to .SIGNL+1 since SGNWAT should be called NOINT
;<135-TENEX>SIGNAL.MAC;56     9-FEB-76 10:09:58    EDIT BY PLUMMER
; FIX NOINT STUFF AT SIGNL4
;<135-TENEX>SIGNAL.MAC;55     4-FEB-76 10:13:09    EDIT BY PLUMMER
; FIX LOST FLAGS IN WTFOR0
; CORRECT CHECK ON "DONT WAIT" BIT IN WTFOR0
;<134-TENEX>SIGNAL.MAC;53    28-AUG-75 14:03:56    EDIT BY PLUMMER
; ADD "PEEK" OPTION TO WTFOR
;<134-TENEX>SIGNAL.MAC;51    28-AUG-75 11:59:00    EDIT BY PLUMMER
; ADD GTSIG FLAG WHICH REQUIRES ASSIGNMENT OF A SYSTEM SIGNAL
; FIX ACCESSIBILTY CHECKS IN SIGNL
;<134-TENEX>SIGNAL.MAC;48     2-APR-75 11:27:48    EDIT BY PLUMMER
; SIGNAL WAITS FOR PREVIOUS DATA TO BE READ ONLY IF NEW DATA SUPPLIED
;<134-TENEX>SIGNAL.MAC;47    13-MAR-75 15:56:28    EDIT BY PLUMMER
; FIX RLSIG
;<134-TENEX>SIGNAL.MAC;46    12-MAR-75 22:13:40    EDIT BY PLUMMER
; MAKE WTFOR RETURN SIGNL-ER'S JOB NUMBER IN RH(3) IF DATA RETURNED
; REPAIRS, REARRANGE, ETC
;<134-TENEX>SIGNAL.MAC;40    12-MAR-75 09:59:03    EDIT BY PLUMMER
; INCLUDE CHANGES BY TOMLINSON
;<134-TENEX>SIGNAL.MAC;39    11-MAR-75 18:09:43    EDIT BY PLUMMER

	SEARCH	STENEX,PROLOG
IFDEF SIGIPC,<		;ASSEMBLE ONLY IF CONFIGURATION REQUIRES
	TITLE	SIGNAL
	SUBTTL	WILLIAM W. PLUMMER, 25FEB75


SID=<T1==1>
T2=2
T3=3
T4=4


INTERN	.GTSIG,.RLSIG,.SIGNL,.WTFOR
INTERN	SIGINI,WTFORT,SIGKIL,RMJBRF


EXTERN	MENTR,MRETN,MRETNE,SKMRTN
EXTERN	CAPENB,FKJOB,JOBRT,LSTERR,MINUS1
EXTERN	EDISMS,DISGE,FORKX,JOBNO



DEFINE RETERR(CODE,EXTRA)<
	JRST [	EXTRA
		IFDIF <CODE>,<>,<MOVEI 1,CODE>
		JRST MRETNE]>


LS (SIGLCK,1)			;LOCK ON SIG TABLES
LS (SIGNAL,NSSIGS+NUSIGS)	;SEMAPHORE CELLS: RUN IF AOSLE SKIPS
LS (SIGJOB,NSSIGS+NUSIGS)	;FLAGS,,OWNING JOB  OR -1 IF NOT IN USE
LS (SIGQUE,NSSIGS+NUSIGS)	;SIGNL FORK QUEUE:  IN,,OUT
LS (SIGJB1,NSSIGS+NUSIGS)	;JOBS ALLOWED TO SIGNL THIS SID
LS (SIGJB2,NSSIGS+NUSIGS)	;...


LS (FKDATA,NFKS)		;SIGNL DATA WORD
LS (FKLIST,NFKS)		;SID,,Q-POINTER.	B0: DATA QUEUED
				;			B1: SID VALID


;TEMPORARY DEFINITIONS UNTIL PUT INTO ERRMES

SGNLX1==602001
SGNLX2==602002
SGNLX3==602003
SGNLX4==602004
SGNLX5==602005
SGNLX6==602006
SGNLX7==602007
SGNLX8==602010
SGNLX9==602011


	USE SWAPPC

;GET SIGNAL ID

;1/	FLAGS,,COUNT		;B0: MAKE ACCESSIBLE TO JOBS IN 2,3,...
				;B4: REQUIRE SYSTEM SIGNAL
;				;B3: MAKE ACCESSIBLE TO ALL JOBS
;2,3/	9-BIT BYTES: 777 OR JOB # IN EACH
;
;	GTSIG
;
;R+1:	 ERROR, NUMBER IN 1
;R+2:	OK, SID IN 1


.GTSIG::JSYS MENTR		;ENTER MONITOR
	NOINT
	TLNN 1,(1B0)		;MAKE ACCESSIBLE TO OTHER JOBS?
	SETOB 2,3		;NO. USE NULL JOB NUMBERS FOR CHECKS
	PUSH P,2
	PUSH P,3
	PUSH P,1

GTSIG1:	MOVE T2,[POINT 9,-2(P)]
	MOVEI T3,4*2		;NUMBER OF JOBS TO CHECK
	CALL LOCKSG		;LOCK THE SIGNAL TABLES
	NOSKED			;STOP ALL OTHER FORKS
GTSI11:	ILDB T1,T2		;GET NEXT JOB NUMBER
	CAIN T1,777		;NULL?
	 JRST GTSI19		;YES, SKIP CHECK
	CAIL T1,0		;REASONABLE?
	CAIL T1,NJOBS
	 RETERR(SGNLX1,<OKSKED
			SETOM SIGLCK>)	;"BAD JOB SPEC"
	SKIPGE JOBRT(T1)		;LOGGED IN?
	 RETERR(SGNLX1,<OKSKED
			SETOM SIGLCK>)
GTSI19:	SOJG T3,GTSI11		;LOOP OVER ALL BYTES

GTSIG2:	MOVEI T2,WHEEL!OPER
	MOVSI T3,(1B4)		;REQUIRE SYSTEM SIGNAL BIT
	TDNN T3,0(P)		;SEE IF THAT IS WHAT CALLER WANTS
	 JRST GTSI20		;NO.  SEARCH USER SIGNALS
	TDNN T2,CAPENB		;CHECK THAT HE IS ALLOWED SYSTEM SIGNAL
	 RETERR(CAPX1,<	SETOM SIGLCK
			OKSKED>)
	SKIPA SID,[-NSSIGS,,0]		;SEARCH SYSTEM SIGNALS
GTSI20:	MOVE SID,[-NUSIGS,,0+NSSIGS]	;SEARCH USER SIGNALS
GTSI21:	MOVE T2,SIGJOB(SID)
	AOJE T2,GTSIG3		;JUMP IF THIS IS A FREE SID
	AOBJN SID,GTSI21	;TRY NEXT
	RETERR(SGNLX2,<OKSKED
			SETOM SIGLCK>)	;"NO SIDS AVAILABLE"

GTSIG3:	MOVSI T2,SIGQUE(SID)
	MOVEM T2,SIGQUE(SID)	;BE SURE QUEUE IS EMPTY
	POP P,T2		;CALLER'S AC1
	POP P,SIGJB2(SID)
	POP P,SIGJB1(SID)
	HRRE T3,T2		;GET COUNT
	MOVNM T3,SIGNAL(SID)	;AND INITIALIZE THE SIGNAL
	HRR T2,JOBNO		;FORM FLAGS,,JOB
	MOVEM T2,SIGJOB(SID)	;MAKE THE SIGNAL EXIST
	SETOM SIGLCK
	OKSKED
	HRRZS SID		;SAVE ONLY RIGHT HALF
	UMOVEM SID,1		;RETURN SID TO USER
	JRST SKMRTN		;WITH A SKIP

;RELEASE A SIGNAL ID

;1/	AN SID OR -1 TO RELEASE ALL OWNED BY THIS JOB
;
;	RLSIG
;
;
;R+1:	 ERROR, CODE IN 1
;R+2:	SUCCESS


.RLSIG::JSYS MENTR		;ENTER THE MONITOR
	NOINT			;KEEP ACS STABLE
	CALL LOCKSG
	CAMN SID,MINUS1		;DO ALL SIDS OWNED BY THIS JOB?
	 JRST RLSIG1		;YES.
	CAIL SID,0		;REASONABLE SID?
	CAIL SID,NSSIGS+NUSIGS
	 RETERR(SGNLX3,<SETOM SIGLCK>)	;"ILLEGAL SID"
	CALL RLSIG0			;ACTUALLY RELEASE THE SID
	 RETERR(SGNLX4,<SETOM SIGLCK>)	;"SID NOT OWNED BY THIS JOB"
	JRST RLSIGX			;INDICATE SUCCESS

RLSIG1:	MOVNI SID,NSSIGS+NUSIGS
	HRLZS SID
	CALL RLSIG0
	 JFCL			;IGNORE THOSE NOT OWNED BY THIS JOB
	AOBJN SID,.-2
RLSIGX:	SETOM SIGLCK
	JRST SKMRTN



;RELEASE SID GIVEN BY RH(SID)
;SKIP IF ACTUALLY DONE, NO SKIP IF NOT

RLSIG0:	HRRZ T2,SIGJOB(SID)	;GET OWNING JOB
	CAME T2,JOBNO		;THIS JOB?
	 RET			;NO
	HRRZ T3,SIGQUE(SID)	;CLEAR THE QUEUE
RLSG01:	JUMPE T3, RLSG02	;JUMP IF DONE
	MOVEI T2,0(T3)		;POINTS TO CURRENT ITEM
	HRRZ T3,0(T2)		;POINTS TO NEXT ITEM
	SETZM 0(T2)		;CLEAR "DATA PRESENT" AND "SID VALID"
	JRST RLSG01		;FOR ALL QUEUED FORKS
RLSG02:	MOVSI T2,SIGQUE(SID)
	MOVEM T2,SIGQUE(SID)	;RE INITIALIZE THE QUEUE HEAD
	SETOM SIGJOB(SID)	;DEASSIGN.  CAUSE WTFORS,SIGNLS TO RET!
	AOS 0(P)
	RET

;WAIT FOR A SIGNAL EVENT


;1/	FLAGS,,SID		;BIT-1: DON'T WAIT, JUST CHECK
;				;BIT-5: JUST PEEK, DON'T DEQUEUE
;	WTFOR
;
;R+1/	 ERROR, CODE IN 1
;R+2/	OK, DATA IN 2, JOB NUMBER OF SIGNL-ING FORK IN RH(3)


.WTFOR::JSYS MENTR		;ENTER THE MONITOR
	PUSH P,1
	HRRZ SID,1		;GET SID
	CAIL SID,0		;REASONABLE?
	CAIL SID,NSSIGS+NUSIGS
	 RETERR(SGNLX3)		;"BAD SID"
WTFOR0:	NOINT
	MOVE SID,0(P)		;GET BACK FLAGS
	CALL LOCKSG		;LOCK THE SIGNAL TABLES
	MOVE T2,SIGJOB(SID)
	CAMN T2,MINUS1			;IN USE?
	 RETERR(SGNLX5,<SETOM SIGLCK>)	;"SID NOT OWNED"
	HRRZS T2			;GET JOB NUMBER OF OWNER
	CAME T2,JOBNO			;THIS JOB?
	 RETERR(SGNLX4,<SETOM SIGLCK>)	;"OWNED BY SOME OTHER JOB"
	TLNE SID,(1B5)			;"JUST PEEK"
	 JRST WTFOR4			;YES.  NO NEED TO WAIT.
	TLNE SID,(1B1)		;"DONT WAIT" BIT
	 JRST WTFOR3		;TRUE. JUST OPERATE ON THE SIGNAL

WTFOR1:	JSP 4,WTFORT		;WAKE UP ALREADY WAITING?
	 JRST [	SETOM SIGLCK
		OKINT
		HRLZ 1,SID	;NO, WAIT FOR IT TO ARRIVE
		HRRI 1,WTFORT
		JSYS EDISMS
		JRST WTFOR0]	;TRY AGAIN

WTFOR3:	AOSG SIGNAL(SID)	;OPERATE ON THE SIGNAL
	 JRST WTFOR4		;RESUME
	SOS SIGNAL(SID)		;UNDO THE AOS
	TLNE SID,(1B1)		;"DON'T WAIT"
	 RETERR (SGNLX7,<SETOM SIGLCK>)	;"NO SIGNALS WAITING"
	JRST WTFOR1		;TRY AGAIN

WTFOR4:	POP P,SID
	CALL WT4DAT		;GET THE DATA IF ANY
	 RETERR(SGNLX8,<SETOM SIGLCK>)		;"NO DATA RETURNED"
	SETOM SIGLCK
	UMOVEM T2,2
	UMOVEM T3,3		;0,,JOB#
	JRST SKMRTN

;GET DATA FROM SIGNAL QUEUE
;SKIP IF SUCCESSFUL
;SID/	FLAGS,,SID		;SIGLCK SET AND NOINT
;RETURNS DATA IN T2, AND JOB NUMBER OF FORK WHICH PUT IT THERE IN RH(3)

WT4DAT:	HRRZ T2,SIGQUE(SID)	;GET OUT POINTER
	JUMPE T2,WT4DAX		;QUEUE IS EMPTY
	TLNN SID,(1B5)		;"JUST PEEK", DON'T DEQUEUE
	CALL DQITEM		;DEQUEUE 1ST ITEM, RETURN DATA IN T2
	CALL GTDATA		;COPY DATA OUT OF DEQUEUED ITEM
	AOS 0(P)		;...AND JOB # OF SIGNL-ER IN RH(3)
WT4DAX:	RET



;DEQUEUE THE ITEM POINTED TO BY T2 (A FKLIST POINTER)

DQITEM:	PUSH P,SID
	LDB SID,[POINT 9,0(T2),17]	;EXTRACT THE SID
	MOVEI T4,SIGQUE(SID)	;POINTER TO QUEUE HEAD

DQITM1:	HRRZI T3,0(T4)		;ADVANCE PREDECESSOR POINTER
	HRRZ T4,0(T3)		;GET CURRENT ITEM
	CAIE T4,0(T2)		;IS THIS THE ONE TO BE DELETED?
	JRST DQITM1		;NO, CDR SOMEMORE

DQITM2:	HRRZ T4,0(T4)		;SUCCESSOR OF CURRENT ITEM
	HRRM T4,0(T3)		;BECOMES SUCCESSOR OF PREDECESSOR
	SKIPN T4		;AND IF LAST ITEM WAS DEQUEUED
	HRLM T3,SIGQUE(SID)	;UPDATE THE "IN" POINTER

DQITM3:	MOVSI T3,(1B0)
	ANDCAM T3,0(T2)		;CLEAR THE DATA PRESENT FLAG
	POP P,SID
	RET



;GET DATA FROM A POSSIBLY DEQUEUED ITEM
;TAKES A FORKX IN T2
;RETURN DATA IN T2
;RETURN JOB # OF FORK IN WHICH THE SIGNL WAS DONE IN RH(3)

GTDATA:	SUBI T2,FKLIST		;GET BACK FORKX
	HLRZ T3,FKJOB(T2)	;JOB # OF FORK WHICH QUEUED THE DATA
	MOVE T2,FKDATA(T2)	;FETCH THE DATA WORD FOR CALLER
	RET


	USE RESPC

;SCHEDULER TEST FOR ACTIVITY ON A SIGNAL
;AWAKES IF A SIGNAL ARRIVES OR IF THE SID GETS RELEASED

WTFORT::SKIPGE SIGNAL(1)	;DID SIGNAL ARRIVE?
	 JRST 1(4)		;YES, WAKE UP
	MOVE 2,SIGJOB(1)
	AOJE 2,1(4)		;GOT RELEASED
	JRST 0(4)


	USE SWAPPC

;GENERATE A SIGNAL EVENT

;1/	FLAGS,,SID	;B1: DON'T WAIT,  B2: DATA SUPPLIED
;2/	DATA
;
;	SIGNL
;
;R+1:	 ERROR, CODE IN 1
;R+2:	OK


.SIGNL::JSYS MENTR		;ENTER THE MONITOR
	NOINT			; Go NOINT here since SGNWAT requires it
	TLNE 1,(1B2)		;SKIP IF NO DATA SUPPLIED, ELSE ...
	CALL SGNWAT		;WAIT FOR NOTHING QUEUED BY THIS FORK
	 JFCL
	UMOVE 1,1
	UMOVE 2,2
	PUSH P,1
	PUSH P,2
	HRRZ SID,1
	CAIL SID,0
	CAIL SID,NSSIGS+NUSIGS
	 RETERR (SGNLX3)
	CALL LOCKSG
	MOVE T2,SIGJOB(SID)
	CAMN T2,MINUS1
	 RETERR (SGNLX5,<SETOM SIGLCK>)	;"SID NOT OWNED"
	MOVE T3,JOBNO
	TLNN T2,(1B3)		;ACCESSIBLE TO ALL JOBS?
	CAIN T3,0(T2)		;OWNED BY THIS JOB?
	 JRST SIGNL2		;YES
	TLNN T2,(1B0)		;ACCESSIBLE TO OTHER JOBS?
	 RETERR (SGNLX4,<SETOM SIGLCK>)	;"SID NOT ACCESSIBLE TO CALLER"

SIGNL1:	MOVE T2,JOBNO		;SEARCH FOR THIS JOB NUMBER
	MOVE T3,SIGJB1(SID)	;IN THIS WORD
	CALL JOBTST
	 SKIPA T2,JOBNO		;NOT THERE, TRY NEXT
	JRST SIGNL2		;FOUND, USE IT
	MOVE T3,SIGJB2(SID)	;TRY THIS WORD NEXT
	CALL JOBTST
	 RETERR (SGNLX4,<SETOM SIGLCK>)	;"ILLEGAL SID"

SIGNL2:	POP P,T2		;DATA
	POP P,SID
	TLNE SID,(1B2)		;SKIP IF NO DATA SUPPLIED
	CALL NQITEM		;QUEUE THE DATA
	SOS SIGNAL(SID)		;GUNCH THE SIGNAL
	SETOM SIGLCK
	TLNE SID,(1B1)		;SKIP IF SUPPOSED TO WAIT
	 JRST SIGNL9
SIGNL4:	CALL SGNWAT		;WAIT FOR IT TO BE READ BY WTFOR
	 RETERR(SGNLX5)		;SID GOT RELEASED
	MOVE T2,FORKX		;INDEX OF THIS FORK
	LDB T3,[POINT 9,FKLIST(T2),17]	;GET THE SID
	CAIE T3,0(SID)		;STILL SAME AS WHAT WE STARTED WITH?
	 RETERR (SGNLX6)	;NO.  SIGNL WAS DONE AT PSI LEVEL
SIGNL9:	JRST SKMRTN


;QUEUE SIGNL DATA
;SID/	SID
;T2/	DATA TO BE QUEUED

NQITEM:	MOVE T3,FORKX		;THIS FORK
	MOVEM T2,FKDATA(T3)	;STORE THE DATA WORD
	MOVEI T2,FKLIST(T3)	;POINTER TO CELL IN QUEUE CHAIN
	MOVSI T3,600000(SID)	;"DATA PRESENT" AND "SID VALID" AND SID
	MOVEM T3,0(T2)		;STORE IN FKLIST(NEW ITEM)
	HLRZ T3,SIGQUE(SID)	;GET POINTER TO LAST QUEUED ITEM
	HRRM T2,0(T3)		;ADD NEW ITEM TO END OF QUEUE
	HRLM T2,SIGQUE(SID)	;AND UPDATE TAIL POINTER
	RESKED			;WAKE UP THE SCHEDULER
	RET



;SKIP IF ITEM QUEDED BY THIS FORK GETS DEQUEUED
;NO SKIP IF SID DISSAPPEARS.  CALLED NOINT.  RETURNS NOINT.


SGNWAT:	PUSH P,SID
	MOVE 1,FORKX		;INDEX OF THIS FORK
	ADDI 1,FKLIST		;POINTER TO THE FKLIST CELL
SGNWA0:	SKIPGE T2,0(1)		;ALREADY GONE?
	 JRST [	OKINT
		CALL DISGE	;NO, HANG UNTIL IT IS
		NOINT
		JRST SGNWA0]
	POP P,SID
	TLNE T2,(1B1)		;"SID VALID" BIT (CLEARED BY RLSIG)
	AOS 0(P)
	RET

	RESCD

;SIGNAL FACILITY INITIALIZATION
;TO BE CALLED WHEN SYSTEM IS COMING UP

SIGINI::MOVNI SID,NSSIGS+NUSIGS
	HRLZS SID
SIGIN1:	SETOM SIGJOB(SID)
	MOVSI T2,SIGQUE(SID)
	MOVEM T2,SIGQUE(SID)
	AOBJN SID,SIGIN1

	MOVNI T1,NFKS
	HRLZS T1
SIGIN2:	SETZM FKLIST(T1)
	SETZM FKDATA(T1)
	AOBJN T1,SIGIN2
	SETOM SIGLCK		;UNLOCK THE TABLES
	RET

	SWAPCD



;TO BE CALLED BY A FORK KILLING ITSELF (NOINT)

SIGKIL::CALL LOCKSG
	HRRZ T2,FORKX		;SYSTEM INDEX OF THIS FORK
	SKIPL T3,FKLIST(T2)	;SEE IF ANYTHING QUEUED BY THIS FORK
	 JRST SIGKIX		;NO
	LDB SID,[POINT 9,T3,17]	;BE VERY SURE OF THAT
	HRRZ T3,SIGQUE(SID)	;"OUT" POINTER (TO FKLIST)
	JUMPE T3,SIGKIX		;SHOULD PROBABLY BUGCHK
	MOVEI T2,0(T3)		;POINTER TO ITEM TO BE REMOVED
	CALL DQITEM		;DO IT
SIGKIX:	SETOM SIGLCK
	RET


;TO BE CALLED BY A JOB GOING AWAY
;REMOVES ALL REFERENCES TO THE JOB FROM SIGJB1,2

RMJBRF::CALL LOCKSG
	MOVNI SID,NSSIGS+NUSIGS
	HRLZS SID		;AOBJN POINTER TO SIGNAL TABLES
RMJBR0:	MOVE T3,SIGJOB(SID)	;FLAGS,,OWNING JOB
	CAMN T3,MINUS1		;THIS SIGNAL IN USE?
	 JRST RMJBR4		;NO, SKIP IT
	MOVE T2,JOBNO		;OUR JOB NUMBER
	CAIN T2,0(T3)		;DO WE OWN THIS SID?
	SETOM SIGJOB(SID)	;YES, RELEASE IT.
	JUMPGE T3,RMJBR4	;JUMP IF NO JOBS REFERENCE THIS SID
	MOVE T3,SIGJB1(SID)	;DATA TO CHECK
	CALL JOBTST		;IS IT IN THERE?
	 JRST RMJBR2		;NO, FORGE AHEAD
RMJBR1:	MOVE T3,SIGJB1(SID)	;GET THE DATA WORD AGAIN
	CALL REMJBR		;REPLACE ALL JOBNO'S BY 777
	MOVEM T3,SIGJB1(SID)	;AND STORE BACK

RMJBR2:	MOVE T3,SIGJB2(SID)	;SAME FOR OTHER WORD
	MOVE T2,JOBNO
	CALL JOBTST
	 JRST RMJBR4
	MOVE T3,SIGJB2(SID)
	CALL REMJBR
	MOVEM T3,SIGJB2(SID)

RMJBR4:	AOBJN SID,RMJBR0	;LOOP OVER ALL SIGS
	SETOM SIGLCK
	RET


REMJBR:	PUSH P,SID		;SAVE SID
	PUSH P,[POINT 9,T3]
	PUSH P,[4]
	MOVEI T2,777
REMJB0:	ILDB T1,-1(P)
	CAMN T1,JOBNO
	DPB T2,-1(P)
	SOSLE 0(P)
	 JRST REMJB0
	SUB P,[2,,2]
	POP P,SID
	RET

;TEST WORD IN T3 FOR NUMBER IN T2


JOBTST:	DPB T2,[POINT 9,T2,26]
	HRLS T2
	EQVB T2,T3
	JCRY0 .+1
	ADD T2,[BYTE (9) 1,1,1,1]
	EQV T2,T3
	JCRY0 .+2
	TDNE T2,[BYTE (9) 1,1,1,1]
	AOS 0(P)
	RET



;LOCK THE SIGNAL TABLES

LOCKSG:	PUSH P,SID
	MOVEI 1,SIGLKT
	AOSE SIGLCK
	 JSYS EDISMS
	POP P,SID
	RET


	RESCD

SIGLKT:	AOSE SIGLCK
	JRST 0(4)
	JRST 1(4)

	SWAPCD

>	;END IFDEF BEFORE TITLE

	END

