comment \ (****************************************************************************) (* *) (* Copyright (C) 1984, 1985, 1986, 1987, 1988 by *) (* Stacken, Royal Institute Of Technology, Stockholm, Sweden *) (* All rights reserved. *) (* *) (* This software is furnished under a license and may be used and copied *) (* only in accordance with the terms of such license and with the *) (* inclusion of the above copyright notice. This software or any other *) (* copies thereof may not be provided or otherwise made available to any *) (* other person. No title to and ownership of the software is hereby *) (* transferred. *) (* *) (* The information in this software is subject to change without notice *) (* and should not be construed as a commitment by Stacken. *) (* *) (* Stacken assumes no responsibility for the use or reliability of its *) (* software on equipment which is not supported by Stacken. *) (* *) (****************************************************************************) \ TITLE LNKSER - TTY LINK SERVICE ROUTINES SUBTTL VERSION 2b (FOR 7.02) SEARCH F,S $RELOC $HIGH ENTRY LNKSER LNKSER:: ;LOAD ON LIBRARY SEARCH IFE FTLINK,< PRINTX ?FTLINK CONDITIONAL MUST BE ON > COMMENT \ LNKSER CONTAINS ALL THE ROUTINES NEEDED TO INTERPRET THE LINK AND BREAK COMMANDS, AND TO PROCESS ACTIVE LINKS. THE COMMAND "LINK" ESTABLISHES A CONNECTION BETWEEN A PAIR OF TERMINALS, SUCH THAT ANY OUTPUT (INCLUDING FILLS AND ECHO) WHICH APPEARS ON ONE TERMINAL WILL APPEAR ON THE OTHER. "BREAK" DISCONNECTS ANY AND ALL LINKS TO THE TERMINAL ISSUING THE COMMAND. IN ADDITION, LOGIN, ATTACH, DETACH AND KJOB PEFORM AN AUTOMATIC "BREAK". TWO OTHER COMMANDS ASSOCIATED WITH LINK ARE "SET TTY LINK", WHICH ALLOWS A LINK TO BE MADE TO THAT TERMINAL, AND "SET TTY NO LINK" WHICH WILL REFUSE ALL FURTHER ATTEMPTS TO LINK, BUT CONTINUES EXISTING ONES. WITH RESPECT TO TERMINALS ACCEPTING LINKS, LINK FOLLOWS THE LOGIC OF THE "SEND" COMMAND. LINKS TO THE OPR ARE ALWAYS REFUSED UNLESS THE LINKER IS [1,2]; LINKS REQUESTED BY [1,2] ARE ALWAYS GRANTED REGARDLESS OF THE GAG AND REFUSE CONDITIONS. THE COMMAND TO LINK IS "LINK TTYNN" AFTER THE FORMAT OF THE SEND COMMAND. IF IT IS SUCCESSFUL, THE MESSAGE "LINK FROM (NAME) ON TTYNN" WILL BE TYPED, AND OF COURSE APPEAR ON THE LINKED TERMINAL AS WELL. ANY NUMBER OF LINKS MAY BE ESTABLISHED, ONE PAIR AT A TIME, UP TO SYSTEM CAPACITY (SEE BELOW). THE BREAK COMMAND DOES NOT HAVE ANY ARGUMENTS. IF NO LINKS ARE ACTIVE, THE COMMAND ACTS AS A NULL. THE BASIC PURPOSE OF THE LINK SUSSYSTEM IS TO FACILITATE COMMUNICATION AMONG USERS, AND TO GIVE OR REQUEST ADVICE REGARDING THE RUNNING OF PROGRAMS, SINCE THE ADVISOR CAN LINK OR BE LINKED TO AND WATCH THE PROGRAM RUNNING ON THE OTHER TERMINAL AND MAKE COMMENTS. SINCE THESE COMMANDS DO NOT RUN PROGRAMS (LINK REQUIRES LOGIN, BREAK DOES NOT), THE TERMINALS REMAIN IN MONITOR MODE AND ANY TYPEOUT WILL, IN ADDITION TO BEING ECHOED ON THE LINKED TERMINALS, BE PROCESSED BY THE MONITOR AS WELL. THEREFORE IT IS RECOMMENDED THAT A SIMPLE PROGRAM BE WRITTEN LOOPING AROUND AN INCHWL, WHICH WILL SWALLOW ALL INPUT WITHOUT EFFECT. THIS NEGATES THE NEED TO TYPE ; BEFORE EACH LINE, WHICH GETS TO BE A PAIN. INTERNAL STRUCTURE EXTERNALLY, LINK IS MODELLED PRIMARILY ON THE TENEX LINK COMMAND, BUT THE INTERNAL STRUCTURE IS COMPLETELY DIFFERENT. TWO EXTRA WORDS ARE NEEDED IN EACH LDB. THE FIRST WORD (LDBLNK) HAS VARIOUS CONTROL BITS, STATING WHETHER THIS TTY HAS ACTIVE LINKS, IS REFUSING FURTHER LINKS, IS WAITING TO SEND A CHRACTER FROM THE TTY IT IS LINKED TO, AND A POINTER (RELATIVE) TO AN ENTRY IN THE LINK TABLE, WHICH IS ARRANGED AS A LINKED LIST OF ALL TTY'S TO WHICH THIS TTY IS LINKED. WITH THIS ARRANGEMENT, THERE IS NO INTRINSIC LIMIT TO THE NUMBER OF SIMULTANEOUS LINKS A TERMINAL CAN HAVE, BUT THERE IS A SYSTEM-WIDE LIMIT BASED ON THE SIZE OF THE TABLE (LNKTBL IN COMMON), AND WHICH IS NATURALLY OPEN TO MANIPLUATION. EACH ACTIVE LINK REQUIRES TWO WORDS IN THE TABLE, ONE FOR EACH TERMINAL. BECAUSE OF THE DIFFICULTIES INVOLVED IN ACTIVATING A TERMINAL ON ANOTHER'S INTERRRUPT LEVEL (ESPECIALLY ON THE ARPANET), A TWOFOLD SCHEME HAS BEEN ARRANGED. CHARACTERS ARRIVING ON THE COMCON/UUO LEVEL ARE SENT IMMEDIATELY TO THE OTHER TERMINAL(S) VIA ScnSer (LnkCpy). CHARACTERS BEING ECHOED, EITHER DIRECTLY OR THROUGH (INPUT) FILLS, ARE FIRST PLACED IN A HOLDING AREA, ANOTHER LINKED LIST, WHOSE HEAD AND TAIL ARE IN THE SECOND WORD OF THE LDB (LDBLKB), POINTING TO AN AREA IN COMMON (LNKBUF), WHICH SHOULD HAVE APPROXIMATELY 3 WORDS PER LINK AT MAXIMUM. IN EACH CASE, A BIT IS SET IN LDBLNK INDICATING THAT THIS TERMINAL (CURRENTLY THE PASSIVE ONE IN THE LINK) HAS LINKED OUTPUT WAITING TO BE SENT. ON THE CLOCK TICK (JIFFY), ALL LDB'S ARE CHECKED FOR THIS BIT (ASSUMING A SEMAPHORE HAS BEEN SET), AND THE BUFFER IS DUMPED INTO THE OUTPUT BUFFER FOR THAT TTY, AND OUTPUT STARTED. IF NOT IN PROGRESS. THE ROUTINES HAVE BEEN DESIGNED TO BE AS MODULAR AS POSSIBLE, REQUIRING THE FEWEST CHANGES TO EXISTING CODE. CALLS TO CHKLNK AND CHKLKF (FOR FILL ECHO) HAVE BEEN INSERTED IN SCNSER AS APPROPRIATE, AND THE LDB EXPANDED. COMCON, CLOCK1 AND COMMON ALSO HAVE MINOR CHANGES. ACKNOWLEDGEMENT IS MADE TO RIC WERME, AT DEC, AND ED TAFT AT XEROX, FOR THEIR COMMENTS AND SUGGESTIONS. DANIEL KOHANSKI RUTGERS UNIVERSITY DECEMBER 1975 VERSION 2A (FOR 6.02) THE FOLLOWING MAJOR CHANGE TO THE INTERNAL STRUCTURE WAS NECESSITATED BY 6.02: ALL OUTPUT IS NOW DIVERTED TO INTERNAL LINK BUFFERS UNTIL THE CLOCK LEVEL. THIS MEANS THAT COMCON AND UUO ROUTINES SEND THEIR OUTPUT TO LNKPUT INSTEAD OF LKPUTC, IN THE SAME MANNER AS ECHO INTERRUPT. THIS HAS SOMEWHAT SIMPLIFIED MATTERS, AS NOW ONLY FILL OUTPUT MUST BE HANDLD SEPARATELY. BUT AN ADDITIONAL PROBLEM HAS ARISEN WHICH IS MORE EVIDENT WHEN THE TERMINALS INVOLVED HAVE WIDELY DIFERENT BAUD RATES: UNDER THE CURRENT SCHEME, OUTPUT TO THE SLOWER TERMINAL MAY BE LOST. THIS WILL BE INDICATED BY A BELL SENT TO THE PRIMARY TERMINAL, AND CONSEQUENTLY TO THE LINKED ONES AS WELL. TO HELP IN SETTING AN APPROPRIATE BUFFER SIZE, THEREFORE, STATTISTIC COLLECTION ROUTINES HAVE BEEN ADDED, AND CAN BE MADE AVAILABLE TO GENERAL USERS AS A GETTAB TABLE. OF PRIMARY INTEREST FOR THIS PURPOSE ARE THE FIGURES FOR AVERAGE AND MAX PERCENTAGE OF BUFFER USE, AND THE NUMBER OF TIMES THE BUFFER OVERFLOWED (THIS IS NOT THE NUMBER OF LOST CHARACTERS, WHICH WILL BE HIGHER). A USER WITH PEEK PRIVELEGES CAN ALSO USE THE TABLE TO HELP IN PRINTING OUT THE CURRENT LINKS; TO THIS END, THE LINK TABLE HAS BEEN CHANGEDTO INCLUDE BOTH TERMINALS IN THE PAIR. APRIL 1976 \ ;AFAL local revision history ;(175) 21-MAR-79, Nick Eastridge ; Modules Effected: LNKSER ; Edit Type: Kluge ; If a high speed terminal links to a slower one or any terminal ; links to a ^S'ed terminal the TTY linking code can swiftly take ; over all the TTY chunks. This edit, inserted into LNKSER, ; prevents the linking code from using the last 10% of the chunks ; or sending any more characters to a terminal whose output ; buffer is using more than 25% of chunkspace. The percentages ; are parameterized. Edit installed at LKPUTC:+. ;(212) 29-NOV-79, Nick Eastridge ; Modules Effected: LNKSER ; Edit Type: Bug Fix ; Symptom: Occasionally TTY linking doesn't work ; because all the buffers in LNKBUF get filled up but ; are not being emptied. ; Diagnosis: In routine LNKTIK of LNKSER, if no TTY ; chunks are available to feed the output to the buffer ; copying stops-- without dumping the rest of the LNKBUF ; buffers. This locks up those buffers. ; Cure: Even if no more TTY chunks continue to unlink ; LNKBUF buffers (they will be thrown away). ; See code under label LNKTKG in LNKTIK. ;(240) 6-Mar-81, Jim McCool ; Edit type: Bug fix ; Modules affected: LNKSER,UUOCON ; Symptom: User A is linked to terminal T. User B assigns (via ; assign command or OPEN UUO. Voila, the line from user A is broken. ; Another variation of the same bug is User A assigns terminal T to ; do some output to it. User B links to terminal T. Voici, output ; to the terminal is a non-deterministic combination from the two ; users. ; Diagnosis: Linking code doesn't care if the terminal is assigned to ; someone else; Assign code doesn't care if the terminal is linked to ; someone else. ; Cure: In the linking code, if the terminal is assigned to someone ; else and is not controlling a job, refuse the link. In the assign ; code, if the terminal is linked to by someone else, don't allow the ; assign. ; ;end of local revision history SUBTTL DEFINITIONS AND POINTERS ;LDB BITS ;LDBLNK ;BIT NAME POINTER USE ;0 LNKXMT TTY IS ABOUT TO TRANSMIT BECAUSE OF LINK ;1 LNKACV TTY HAS ACTIVE LINKS ;2 LNKREF TTY IS REFUSING FURTHER LINKS ;3-11 LNKPTR HEAD OF LINKED LIST OF LINKED TTY'S (LNKTBL IN COMMON) ;12 LNKECH SENDING ECHO CHAR TO LINKED TTY ;13 LNKFLP SEND INPUT FILLS TO LINKED TTY (LDBFLP) ;14 LNKOPD ON CLOCK TICK, START OUTPUT TO THIS TTY IF NOT ACTIVE ;BITS ARE DEFINED IN S FOR BOTH SCNSER AND LNKSER ;LNKTBL BITS ;BITS NAME POINTER USE ;0 LKTSNT THIS LINK HAS BEEN SENT TO (MUST BE SIGN BIT) ;1 LKTNIU THIS NODE IS IN USE (COVERS CASE OF TTY0) ;3-11 LKTPTR LINK TO NEXT ELEMENT OR NULL (GOOD ONLY IF T2 HOLDS LAST LINK) ;18-26 LT3PTR TTY NUMBER LINK IS FROM (FOR SYSTAT) ;27-35 LTYPTR NUMBER OF TTY LINKED TO (POINTER TO LINTAB) LKTSNT==400000 LKTNIU==200000 LDRPTY==400000 ;IN LDBDCH, MEANS IS PSEUDO-TELETYPE EXTERN LDLCOM,L2LSND,LDR2741,LDBBY2,LDBTOC ;POINTERS LNKPTR: POINT 9,LDBLNK##(U),11 ;POINT TO HEAD OF LINKED LIST LKTPTR: POINT 9,LNKTBL##(T2),11 ;POINT TO NEXT LINK IN TABLE LT3PTR: POINT 9,LNKTBL##(T3),26 ;POINT TO TTY # THE LINK IS FROM LTYPTR: POINT 9,LNKTBL##(T2),35 ;POINT TO TTY # LINKED TO ;GETTAB TABLE OF STATISTICS $LOW LNKSTS::0,,0 ;AVG BUFFER UTILIZATION,,MAX 0 ;# OF TIMES LNKTIK CALLED (FIGURED FOR BUFFER AVG) 0,,0 ;CURRENT # OF ACTIVE LINKS,,MAX # 0 ;TIMES LKPUTC CALLED TO OUTPUT A CHARACTER 0 ;TIMES TSETBO CALLED BY LKPUTC 0 ;TIMES LNKPUT FAILED (BUFFER FULL) 0 ;# OF CHARACTERS CURRENTLY IN BUFFER LKTSIZ##,,LNKTBL## ;VALUES FOR TABLE OF LINKED TTY'S LCHFLS: 0 ;NUMBER OF CHARS REJECTED BECAUSE NO FREE ;CORE. LKSMXL==:<.-LNKSTS-1>B26 ;LENGTH OFTABLE (FOR GETTAB) $HIGH SUBTTL INTERRUPT ROUTINES - CALLED FROM SCNSER EXTERN LDBLNK,LDPSVC,LNKTBL,FLLFLG,RCHLT1,LDBLKB,LDBFLP EXTERN CRLF ;SUBROUTINE TO CHECK IF THIS TTY (U) HAS ANY ACTIVE LINKS. IF SO, ;PREPARE TO TRANSMIT TO EACH LINK IN THE LINKE LIST IN TURN. CHARACTER ;IS IN T3, BUT IS NOT TOUCHED. AS EACH LINK IN THE CHAIN IS PROCESSED, IT ;IS MARKED (LKTSNT = SIGN BIT SET TO 1), AND THE CHAIN CONTINUED FROM ;THE BEGINNING, PRECLUDING THE NECESSITY OF KEEPING ANOTHER POINTER ;AROUND, AND ALSO MINIMIZING THE CRITICAL SECTION. ; to avoid hanging, calls to ChkLkf and ChkLnk *CANNOT* be within ; a ScnOff/ScnOn pair. ;ENTRY TO SEND FILLS TO LINKS CHKLKF::MOVSI T1,LNKFLP ;MARK LDB FOR FILLS IORM T1,LDBLNK(U) ;... IFN FTCIMP, ;AVOID CHECK FOR TELNET CODE CHKLNK:: IFN FTCIMP,< CAIL T3,400 ;IF SPECIAL TELNET CHARACTER, JRST CHKLNX ;DONT SEND CHKLK1:> ScnOff ;AVOID INTERFERENCE MOVSI T1,LNKACV TDNN T1,LDBLNK(U) ;ANY ACTIVE LINKS? JRST chklx0 ;NO - TURN ON AND EXIT PUSHJ P,SAVE3## ;NEED A PERMANENT REG PUSH P,T3 ;PRESERVE FROM RAVAGES PUSH P,U ;SAME HERE ;IF CALLED BY FILL ROUTINE, SET UP FILL POINTER AND SAVED CHARACTER. ;OTHERWISE CALLED BY ECHO OR COMCON/UUO - JUST SEND TO BUFFER. LDB P3,LDPSVC ;JUST IN CASE SETZ P1, ;NOW ASSUME REGULAR MOVSI T1,LNKFLP TDNE T1,LDBLNK(U) ;FILL? MOVE P1,LDBFLP(U) ;YES - GET FILL POINTER ;NOW LOOK THROUGH THE LINKED LIST AND FIND THE NEXT TTY TO SEND THE CHARACTER TO LINK00: LDB T2,LNKPTR ;GET THE HEAD OF THE LINKED LIST LINK01: MOVE T1,LNKTBL(T2) ;GET AN ELEMENT JUMPGE T1,LINKNX ;FOUND ONE WE HAVEN'T DONE YET LDB T2,[POINT 9,T1,11] ;GET NEXT LINK JUMPE T2,LINKCL ;ALL DONE JRST LINK01 ;FOUND A LINK - NOW FAKE EVERYBODY OUT BY MAKING THIS THE TERMINAL TO SEND ;TO - MOMENTARILY LINKNX: LDB T1,LTYPTR ;GET THE NEW U FROM THE LINK ELEMENT MOVE U,LINTAB(T1) ;WHICH IS AN ADDRESS INTO LINTAB MOVSI T1,LKTSNT ;MARK THIS LINK IORM T1,LNKTBL(T2) ;AS HAVING BEEN SENT TO JUMPE P1,LINKNE ;REGULAR OR FILL? MOVE P2,P1 ;FILL ECHO...GET PRESERVED POINTER LINKEF: ILDB T3,P2 ;AND PUT ALL CHARACTERS JUMPE T3,LINKES ;UNTIL NULL CAIN T3,FLLFLG ;OR FINISHING FLAG... JRST LINKCR ;... PUSHJ P,LNKPUT ;INTO LINK BUFFER JRST LKWRNN ;OVERFLOW IS UNLIKELY JRST LINKEF ;AS LONG AS HAVE A FILL LINKCR: MOVEI T3,215 ;USE OF FLLFLG MEANS CRLF AFTERWARDS PUSHJ P,LNKPUT ;...OBLIGE JRST LKWRNN MOVEI T3,12 PUSHJ P,LNKPUT JRST LKWRNN JRST LINKNN LINKES: MOVE T3,P3 ;GET SAVED CHAR FROM LDPSVC PUSHJ P,LNKPUT ;AND PACK IT IN JRST LKWRNN JRST LINKNN LINKNE: PUSHJ P,LNKPUT ;;ECHO OR COMCON/UUO - SEND TO BUFFER JRST LKWRNN ;RAN OUT OF ROOM LINKNN: MOVSI T1,LNKOPD ;MARK LINK PENDING IORM T1,LDBLNK(U) ;FOR LATER CLOCK TICK MOVE U,(P) ;AND RETRIEVE U JRST LINK00 ;GO ON TO THE NEXT LINK ;HERE IF OUT OF LINK BUFFER SPACE. WARN USER ;HAVE SENT ALL LINKS. NOW GARBAGE COLLECT - TURN OFF SENT-TO BIT LKWRNN: LINKCL: POP P,U POP P,T3 ;BACK TO ONE WE STARTED WITH MOVSI T1,LNKECH ;MAKE SURE INDICATOR ANDCAM T1,LDBLNK(U) ;IS TURNED OFF SETOM LNKSMP ;MARK FOR CLOCK TICK TO PICK UP LDB T2,LNKPTR MOVSI T1,LKTSNT ;BIT TO TURN OFF LINKCX: ANDCAM T1,LNKTBL(T2) ;TURN OFF BIT LDB T2,LKTPTR ;GET NEXT LINK JUMPE T2,chklx0 ;EXIT ON LAMDBA LINK JRST LINKCX ;EXIT SEQUENCE. CLEAR PATH INDICATORS AND EXIT ChkLx0: ScnOn ;MAKE SURE INTERRUPTS ON CHKLNX: MOVSI T1,LNKECH!LNKFLP ANDCAM T1,LDBLNK(U) POPJ P, SUBTTL CLOCK LEVEL ROUTINES ; ROUTINE CALLED ONCE EACH CLOCK TICK (60 TIMES A SECOND). CHECKS TO ; SEE IF ANYONE HAS SENT DATA TO A LINKED TTY, AND IF SO, STARTS UP ; THAT TTY (BIT LNKOPD IN LDBLNK). THIS IS A SAFETY MEASURE, SINCE ; TELETYPES, AND ESPECIALLY THE IMPS, DO NOT LIKE BEING STARTED FROM ; SOMEONE ELSE'S INTERUPT LEVEL, BUT ARE PEFECTLY WILLING TO BE STARTED ; BY THE CLOCK. ; DK/JUL 75 EXTERN LDLIDL LNKTIK::SKPCPU (0) ;ONLY DO THIS ON NTHE BOOT CPU POPJ P, SETZM LNKSMP ;CLOCK HAS TICKED PUSHJ P,SAVE4## ;NEED SOME UNTOUCHABLE REGS SETZ P1, ;COUNT OF CHARS PUSH P,U IFE FTCIMP,< MOVEI P4,TCONLN## ;NUMBER OF TTY'S > IFN FTCIMP,< MOVEI P4,TTPLEN##-1 ;NUMBER OF TTY'S, INCLUDING IMPS > MOVSI P2,LNKOPD ;FLAG FOR CHECKING MOVSI P3,LDLIDL ;FLAG TO CHECK IF LINE IDLE LNKTK1: MOVE U,LINTAB##(P4) ;GET A TELETYPE DATA BLOCK TDNN P2,LDBLNK(U) ;LINK PENDING? JRST LNKTK2 ;NO... LNKTKG: ScnOff ; don't let any one cause trouble PUSHJ P,LNKGET ;GET ECHO CHAR IF ANY JRST LNKTKP ;OUT OF CHARS ScnOn ; no one did. AOJ P1, ;COUNT NO. OF CHARS = BUFFER SPACE IN USE PUSHJ P,LKPUTC ;USE ScnSer TO KEEP PATTERN JRST LNKTKG ; loop for next char LNKTKP: ScnOn ; let people do things again TDNE P3,LDBDCH(U) ;IS LINE IDLE? PUSHJ P,XMTIN1## ;YES - START IT UP ANDCAM P2,LDBLNK(U) ;UNMARK FLAG LNKTK2: SOJGE P4,LNKTK1 ;CHECK ALL LINES POP P,U IMULI P1,^D100 IDIVI P1,LKBSIZ## ;CONVERT TO %AGE HLRZ P3,LNKSTS ;GET PREVIOUS AVERAGE IMUL P3,LNKSTS+1 ;TIMES OF TIMES AVERAGED SO FAR ADD P3,P1 ;PLUS LATEST FIGURE AOS LNKSTS+1 ;INCREMENT NUMBER OF AVERAGES IDIV P3,LNKSTS+1 ;FIGURE NEW AVERAGE HRLM P3,LNKSTS ;AND PUT INTO TABLE HRRZ P3,LNKSTS ;GET PREVIOUS MAX AVG CAMGE P3,P1 ;CURRENT %AGE GREATER? HRRM P1,LNKSTS ;YES - USE THAT POPJ P, ;EXIT, RESTORING $LOW LNKSMP::0 ;SIGNAL TO CLOCK TICK THAT LINKS WAITING $HIGH SUBTTL CHKLNK, CLOCK SUBROUTINES ;SUBROUTINES USED BY CHKLNK ROUTINES ;SUBROUTINE TO PUT ONE CHARACTER IN THE OUTPUT BUFFER USING ScnSer (LnkCpy ; entry to tyo9a). ; always returns non-skip EXTERN LDBDCH,LDBTOP,LDBTOT ;(175) AFAL local edit 175. Prevent TTY links from taking ;(175) over chunk space. CHLEF%== ^D10 ;(175) percent of free chunk space linking cannot touch ;(175) above parameter may be changed; for patching it appears ;(175) in an immediate instruction below. The following parameters are ;(175) used in this edit: ;(175) TTCHKN= total number of TTY chunks ;(175) TTFREN/ number of free chunks ; TIWrnN= number of chars allowed before we hang tty ;(175) LDBTOC(U)/ number of bytes in tty buffer we're putting into ;(175) ;(175) The basic idea is not to let the percent of free chunks drop ;(175) below CHLEF% and not to let a TTY buffer build up to greater ;(175) than CHUSE% of the total chunk space. ;D (175) LKPUTC: MOVE T1,TTFREN## ;MAKE SURE ENOUGH ROOM ;D (175) CAIG T1,6 ;AT LEAST SIX.. ;D (175) JRST [AOS LCHFLS ;FLUSH THE CHAR AND NON-SKIP RETURN ;D (175) POPJ P,] ;(175) here to flush a character we can't handle FLUSHC: AOS LCHFLS ;(175) add one to loast char count POPJ P, ;(175) and take error return ;(175) ;(175) New version of first part of LKPUTC. LKPUTC: MOVE T1, TTFREN## ;(175) number of free chunks IMULI T1, ^D100 ;(175) pre-multiply by 100 to get % below IDIVI T1, TTCHKN## ;(175) divided by total number of chunks CAIG T1, CHLEF% ;(175) skip if > min. % chunks to leave alone JRST FLUSHC ;(175) get rid of it MOVE T1, LDBTOC(U) ;(175) number of char's TTY to output subi t1,^D200 ;[JEQ] in CAML, offsets are to the adress... caml t1,TiWrnn## ; does he have room for it? JRST FLUSHC ;(175) no. throw it out. addi t1,^D200 ;[JEQ] restore T1, just in case... ;(175) end of edit AOS LNKSTS+3 ;NUMBER OF TIMES LKPUTC CALLED ; following 4 lines should not be necessary. provan, march 1, 1983 ; ScnOff ; watch out for a race ; SKIPN LDBTOP(U) ;PREPARE TO ADD OUTPUT BUFFER ; PUSHJ P,tyovri## ;CREATE NEW OUTPUT BUFFER (TYOVRG ; ; with interrupts off). ; ScnOn ; turn scanning back on pjrst LnkCpy## ; call ScnSer to copy char to other guy. ; and return ;SUBROUTINES TO MANIPULATE THE ECHO HOLDING BUFFER. THERE IS ONE BUFFER ; HEAD PER LDB, SHOWING BOTH HEAD AND TAIL; EACH LINK CONSISTS OF THE ; CHARACTER IN LH AND THE POINTER TO THE NEXT LINK IN RH, OR LAMBDA. THE ; CHARACTER IS TAKEN FROM/PUT INTO T3, AND IS THE CHARACTER THAT WAS SENT ; AT RECIEVE INTERRUPT TIME. SINCE WE DO NOT WANT TO CALL ScnSer AT ; SOMEONE ELSE'S INTERRUPT LEVEL, WE USE THIS HOLDING BUFFER. AT ; THE CLOCK TICK, THE BUFFER IS EMPTIED INTO ScnSer via LnkCpy. IT IS ASSUMED ; THAT NO ONE CAN TYPE MORE THAN ONE OR TWO CHARACTERS PE CLOCK ; TICK, EVEN INCLUDING INPUT FILLS, AND SO 3 OR 4 NODES IN THE ; BUFFER PER TTY LINK SHOULD BE AMPLE, THE MORE SO SINCE EACH LINK GRABS AS ; MANY NODES AS IT NEEDS AT ANY ONE MOMENT, UNTIL THE BUFFER AS A WHOLE IS FULL. ;LNKGET - GET ONE CHARACTER FROM THE BUFFER, PUT IT IN T3. ; ERROR RETURN - NO MORE CHARACTERS ; NORMAL RETURN - CHAR IN T3 ;CALLED WITH PI OFF, BUT DOES NOT TURN IT BACK ON. LNKGET: HLRZ T1,LDBLKB(U) ;GET HEAD ADDRESS JUMPE T1,CPOPJ## ;NOTHING TO GET - ALL OVER AOS (P) ;FOR LATER SKIP RETURN HLRZ T3,(T1) ;GET CHARACTER HRRZ T2,(T1) ;GET LINK ADDRESS HRLM T2,LDBLKB(U) ;AND PUT AWAY FOR NEXT GET CHARACTER SETZM (T1) ;RETURN NODE TO FREE POOL SOS LNKSTS+6 ;NUMBER OF CHARACTERS LEFT IN BUFFER JUMPN T2,CPOPJ## ;STILL HAVE LINK IN CHAIN SETZM LDBLKB(U) ;IF NO HEAD, CLEAR TAIL POPJ P, ;LNKPUT - PUT CHAR T3 INTO OUTPUT BUFFER ; ERROR RETURN - NO BUFFER SPACE (SHOULD NOT HAPPEN) ; NORMAL RETURN - CHARACTER STORED (OR WAS NULL) LNKPUT: JUMPE T3,CPOPJ1## ;NULL GIVES GOOD RETURN BUT IS NOT STORED MOVEI T1,LNKBUF## ;ADDRESS OF BUFFER IN COMMON LNKPTC: SKIPN (T1) ;LOOK FOR A FREE NODE JRST LNKPFF ;FOUND IT CAIGE T1,LNKBND## ;PAST END OF BUFFER SPACE? AOJA T1,LNKPTC ;NOT YET - KEEP LOOKING AOS LNKSTS+5 ;NUMBER OF TIMES BUFFER OVEFLOWED POPJ P, ;ERROR RETURN LNKPFF: HRLZM T3,(T1) ;PUT CHAR ONTO LINKED LIST HRRZ T2,LDBLKB(U) ;AND GET PREVIOUS TAIL - IF ANY HRRM T1,LDBLKB(U) ;NEW TAIL AOS LNKSTS+6 ;NUMBER OF CHARACTES NOW IN BUFFER JUMPE T2,LNKPTO ;NEW LIST? HRRM T1,(T2) ;MAKE LINK POINT TO NEW TAIL JRST CPOPJ1## ;GOOD RETURN LNKPTO: HRLM T1,LDBLKB(U) ;NEW LIST...MAKE NODE BOTH HEAD AND TAIL JRST CPOPJ1## SUBTTL COMMAND LEVEL ROUTINES - CALLED FROM COMCON ; LINK TO A SPECIFIED TERMINAL, PROVIDED THE TERMINAL IS NOT ; THE OPERATOR OR PTY, AND IS NOT REFUSING LINKS (SET TTY NO LINK), ; AND ALSO IF THERE IS ROOM IN THE LINK TABLE (SCNSER). EXTERN CTXDEV,NOTENF,INLMES,CONMES,ERRMES LNKCMD::PUSHJ P,SAVE2## PUSHJ P,CTXDEV ;GET ARG FOR LINK - FOLLOWS SEND PATTERN JUMPE T2,NOTENF ;MUST HAVE ONE PUSH P,U ;PRESERVE AND ;ALLOW LINK NNN OR LINK TTYNNN: TO LINK TO A GIVEN TERMINAL HLRZ T1,T2 ;SEE IF TTY SPECIFIED CAIN T1,(SIXBIT /TTY/) JRST LNPHY ;'TTY' TYPED HLRZ T2,T2 ;MAKE AAABBB INTO HRLI T2,(SIXBIT /TTY/);TTYAAA LNPHY: MOVE T1,T2 ;PREPARE PUSHJ P,TTYPHY## ;TO FIND DEVICE LDB JRST LNKNST ;NOT A TTY LDB T1,LDPLNO## ;GET LINE NUMBER POP P,U ;AND RESTORE IFN FTCIMP, ;ALSO PRESERVE PUSHJ P,LNKTTY ;LINK IF POSSIBLE JRST LINKE1 ;REFUSED JRST LINKE2 ;NO TABLE SPACE HLRZ T2,LNKSTS+2 AOJ T2, ;INCREMENT CURRENT NUMBER OF LINKS HRLM T2,LNKSTS+2 HRRZ T3,LNKSTS+2 ;GET PREVIOUS MAX CAMGE T3,T2 ;IS THIS ONE GREATER? HRRM T2,LNKSTS+2 ;YES - USE IT PUSHJ P,INLMES ;LINKED - ANNOUNCE SELF BYTE (7) 7,177,177,177,177 ;BELLS AND WHISTLES ASCIZ / Link from / MOVE T2,.PDNM1##(W) ;GET FIRST PART OF NAME PUSHJ P,PRNAME## ;AND PRINT SKIPE T2,.PDNM2##(W) ;GET SECOND PART - IF ANY PUSHJ P,PRNAME## ;PRINT IT TOO PUSHJ P,INLMES ASCIZ / on TTY/ LDB T1,LDPLNO## ;GET ORIGINATOR'S LINE NUMBER PUSHJ P,PRTDI8## ;TO BE PRINTED IFN FTCIMP,< ;IF VICTIM IS CROSSPATCHED, IMP/MAY 75 POP P,T2 ;THEN GIVE LOCAL HOST ALSO MOVE T2,LINTAB(T2) ;GET VICTIM'S LDB SKIPN LDBIMP##(T2) ;CROSSPATCHED? PJRST CRLF ;NO...FINIS PUSHJ P,INLMES ;ADDITIONAL MESSAGES ASCIZ / at / MOVEI T1,HSTNAM## ;GET THE HOST NAME PUSHJ P,CONMES ;AND PRINT > PJRST CRLF ;FINIS LNKNST: POP P,U JSP T1,ERRMES ASCIZ /No such tty / LNKBSI: JSP T1,ERRMES ASCIZ /Busy / LINKE1: IFN FTCIMP, ;STACK MANAGEMENT JUMPE T3,LNKBSI ;REFUSED BECAUSE BUSY JSP T1,ERRMES ;REFUSED - SAY SO ASCIZ /Refused / LINKE2: IFN FTCIMP, ;FIX THE STACK JUMPE T3,LNKE2A ;T3=0 MEANS ALREADY LINKED JSP T1,ERRMES ASCIZ /Link table full / LNKE2A: JSP T1,ERRMES ASCIZ /Already linked / ;ROUTINES TO PROCESS USER REQUEST FOR LINKS AND BREAKING THEM. ;ALL LINKS ARE IN PAIRS. ;WHEN A TWO-WAY LINK IS ESTABLISHED, BOTH TTY'S MUST BE LINKED. WHEN A TTY ;BREAKS LINKS, ALL ITS PAIRS MUST BE BROKEN. ALL LINKS OWNED BY ONE ;TERMINAL ARE KEPT IN A LINKED LIST WHOSE HEAD IS IN LDBLNK(U) ;AND WHOSE BODY IS IN THE LNKTBL. ;SUBROUTINE TO ATTACH A LINK. U CONTAINS THE REQUESTING TTY LDB, T1 CONTAINS ; THE NUMBER TO TTY TO BE LINKED TO (RELATIVE LOCA IN LINTAB), F CONTAINS THE ; ADDRESS OF THE DDB OF THE TTY TO BE LINKED TO, J CONTAINS THE JOB NUMBER OF ; THE PROSPECTIVE LINKER ; RETURNS: +0 REFUSED (OR PTY OR OPR) (IF T3=0, TTY IS BUSY) ; +1 NO TABLE SPACE LEFT (IF T3=0, ALREADY LINKED) ; +2 OK -LINK ESTABLISHED LNKTTY::PUSH P,T1 ;SAVE VALUE PUSHJ P,SETLGL## ;IF SYSTEM PRIV, NEVER REFUSE SKIPA ;(UNLESS PTY) JRST LNKTT1 POP P,T1 ;RETRIEVE IT AGAIN HRRZ T3,LINTAB(T1) ;GET U OF VICTIM MOVSI T2,LNKREF TDNE T2,LDBLNK(T3) ;IS THE VICTIM REFUSING? POPJ P, ;VICTIM IS NOT SO HELPLESS JUMPE F,LNKTTA ;(240) IF NO DDB FOR VICTIM, NOT ASSIGNED MOVSI T4,TTYATC ;(240) SEE IF IT'S A CONTROLLING TERMINAL TDNE T4,DEVMOD(F) ;(240) JRST LNKTTA ;(240) IT IS, CHECK GAG SETTING ETC. MOVEI T4,ASSCON!ASSPRG;(240) NOT CONTROLLING, ASSIGNED? TDNN T4,DEVMOD(F) ;(240) JRST LNKTTA ;(240) NOT ASSIGNED LDB T2,PJOBN## ;(240) ASSIGNED, ASSIGNED BY LINKER? CAME T2,J ;(240) JRST LNKTER ;(240) NO, ERROR (REFUSED) LNKTTA: ;(240) CAMN T3,OPRLDB## ;IS HE TRYING TO LINK TO OPR? POPJ P, ;YES MOVE T2,LDBDCH(T3) ;CHECK TO SEE IF BUSY - HLR T2,LDBBY2(T3) ;UNLESS VICTIM HAS SET NO GAG TDNE T2,[LDLCOM,,L2LSND] JRST LNKTT1+1 LNKTER: SETZ T3, ;ERROR INDICATOR POPJ P, ;AND RETURN LNKTT1: POP P,T1 ;ENTRY IF PRIV USER HRRZ T3,LINTAB(T1) MOVEI T2,LDRPTY ;IS VICTIM A PTY... IORI T2,LDR2741 ;OR 2471? TDNE T2,LDBDCH(T3) ;.... POPJ P, ;YES - REFUSED TDNE T2,LDBDCH(U) ;HOW ABOUT SELF? POPJ P, ;SAME HERE HRRZ T2,U ;ELIMINATE UNNECESARY PIECES CAMN T3,T2 ;USER CANNOT LINK POPJ P, ;TO HIMSELF... AOS (P) ;PAST THE FIRST HURDLE MOVSI T2,LNKACV ;ANY ACTIVE LINKS NOW? TDNN T2,LDBLNK(U) ;... JRST LNKTT2 ;NO LDB T2,LNKPTR ;CHECK IF ALREADY LINKED TO THIS TTY LNKTCL: LDB T4,LTYPTR ;GET LINK VALUE CAMN T4,T1 ;AND COMPARE WITH REQUESTED NUMBER JRST LNKTER ;MATCH - LOSER LDB T2,LKTPTR ;GET MEXT LINK JUMPN T2,LNKTCL ;AND TRY THAT - UNLESS FOUND LAMBDA LNKTT2: MOVEI T3,1 ;FIND AN OPENING IN TABLE (WORD 0 IS NOT USED) PUSHJ P,LNKFHL ;FIND ONE HOLE POPJ P, ;NOT THERE PUSH P,T3 ;HOLD ADDRESS OF HOLE AOJ T3, ;AND GO FIND THE NEXT ONE PUSHJ P,LNKFHL ;.... PJRST TPOPJ## ;ONLY ONE FOUND - TOO BAD ; CRITICAL SECTION - ADD TTY LINK TO LIST SYSPIF ;ENTRY INTO CRITICAL PART PUSHJ P,LNKADL ;SET UP THE FIRST LINK POP P,T3 ;RETRIEVE THE OTHER HOLE PUSH P,U ;AND HOLD U FOR AWHILE LDB T2,LDPLNO ;GET LINE NUMBER MOVE U,LINTAB(T1) ;WHILE GETTING U OF OTHER HALF OF THE PAIR MOVE T1,T2 ;SETUP FOR SUBROUTINE PUSHJ P,LNKADL ;STICK 'EM IN POP P,U ;RECOVER REAL U SYSPIN ;BACK TO NORMAL JRST CPOPJ1## ;SUCCESSFULLY ;FIND A HOLE IN LNKTBL; SKIP RETURN IF FOUND. ;START ADDRESS (RELATIVE) TO LOOK IS IN T3; ANSWER RETURNED THERE. LNKFHL: MOVE T2,LNKTBL##(T3) ;GET A POSSIBILITY JUMPE T2,CPOPJ1## ;FOUND FREE SPOT AOJ T3, ;TRY NEXT ONE CAIG T3,LKTSIZ## ;AS LONG AS WE ARE STILL IN BOUNDS JRST LNKFHL ;KEEP GOING POPJ P, ;LOSER... ;BUILD THE ACTUAL LINK. START WITH LDBLNK(U) AND FOLLOW POINTERS. ;TTY TO LINK TO IS IN T1 (LINE NO., RELATIVE TO LINTAB). TABLE HOLE ;IS IN T3 (RELATIVE). LNKADL: HRRZM T1,LNKTBL(T3) ;MAKE ENTRY IN TABLE - LINK IN LH IS NULL LDB T2,LDPLNO## ;GET CURRENT TTY NUMBER DPB T2,LT3PTR ;DEPOSIT IN LINK TABLE (FOR SYSTAT) MOVSI T2,LKTNIU ;MARK NODE IN USE, SO NOT EMPTY IORM T2,LNKTBL(T3) ;IN CASE T1 IS FOR TTY0 DK/OCT 75 MOVSI T2,LNKACV ;CHECK ACTIVE BIT TDNN T2,LDBLNK(U) ;IN THIS LDB JRST LNKADF ;FIRST ONE FOR HIM LDB T2,LNKPTR ;CHASE DOWN THE CHAIN LNKADC: LDB T4,LKTPTR ;GET NEXT LINK JUMPE T4,LNKALF ;FOUND LAST ONE MOVE T2,T4 ;NOT YET - JRST LNKADC ;KEEP MOVING LNKALF: DPB T3,LKTPTR ;DEPOSIT WHERE WAS FORMERLY LAST LINK POPJ P, ;AND REMOVE THYSELF LNKADF: DPB T3,LNKPTR ;DEPOSIT IN HEAD MOVSI T3,LNKACV ;AND SET ACTIVE BIT IORM T3,LDBLNK(U) ;IN THIS LDB POPJ P, ;EXIT, STAGE CENTER ;SUBROUTINE TO BREAK ALL LINKS FOR ONE TTY. CALLED BY ;COMMAND "BREAK" OR IF TERMINAL IS DETACHED OR LOGS OFF. CRITICAL SECTION. $LOW LNKACM: 0 ;HOLDING THE HEAD OF THE CURRENT LIST LNKCMP: 0 ;FOR COMPARISON $HIGH LNKBRK::pjumpe f,cpopj## ; don't bother if DDB not set pushj p,savt## ; don't hurt any TEMP regs. PUSH P,U ;SAVE U MOVE U,DDBLDB##(F) ;GET A GOOD U MOVSI T1,LNKACV ;ANY ACTIVE LINKS? TDNN T1,LDBLNK(U) ;.... JRST UPOPJ## ;RESTORE U AND LEAVE SYSPIF ;CRITIQUE BEGINS LDB T3,LDPLNO ;GET LINE NUMBER MOVEM T3,LNKCMP ;AND HOLD FOR COMPARISON LDB T2,LNKPTR ;GO TO THE HEAD OF THE LIST LNKBK1: LDB T3,LTYPTR ;GET LDB ADDRESS MOVE T3,LINTAB(T3) ;AND FROM THAT GET LDB PUSH P,T2 ;HOLD FOR THE MOMENT MOVEI T3,LDBLNK(T3) ;ARRANGEFOR THE ADDRESS MOVEM T3,LNKACM ;NOW FIND THE CORRESPONDING LINK AND REOMVE IT. POSSIBLY THIS ;ACTION WILL REMOVE THE LAST LINK FROM THE OTHER HALF OF THE PAIR, ;IN WHICH CASE IT WILL BE NO LONGER ACTIVE. LDB T2,[POINT 9,(T3),11] ;GET HEAD OF THIS LIST LNKBK2: LDB T4,LTYPTR ;GET CURRENT LINK CAMN T4,LNKCMP ;AND COMPARE WITH BREAKING TTY JRST LNKBKF ;MATCH MOVEI T3,LNKTBL(T2) ;HOLD ADDRESS OF LAST LINK LDB T2,LKTPTR ;AND CONTINUE DOWN THE CHAIN JUMPN T2,LNKBK2 ;UNLESS GONE TOO FAR STOPCD TPOPJ##,STOP,LTE, ;++LINK TABLE ERROR LNKBKF: LDB T4,LKTPTR ;GET THE LINK FROM THIS ONE DPB T4,[POINT 9,(T3),11] ;AND PUT IT WHERE THIS USED TO POINT TO SETZM LNKTBL(T2) ;CLEAR THE TABLE WORD JUMPN T4,LNKBK3 ;LINK NOT NULL - STILL ACTIVE CAME T3,LNKACM ;IS THIS THE HEAD OF THE LIST? JRST LNKBK3 ;NO - STILL MORE MOVSI T4,LNKACV ;YES - HEAD IS NULL - MEANS TURN OFF ACTIVE BIT ANDCAM T4,(T3) ;T3 IS ABSOLUTE AND POINTS TO LDBLNK LNKBE1: PUSHJ P,LNKGET ;CLEAR OUT LINK BUFFER SKIPA ;DONE JRST LNKBE1 ;STILL MORE TO GO ;HAVE SETTLED THE OTHER END OF THE PAIR. NOW MUST SETTLE FIRST HALF. LNKBK3: POP P,T2 HLRZ T1,LNKSTS+2 ;KNOCK OFF ONE FROM CURRENT LINK COUNT SOJ T1, HRLM T1,LNKSTS+2 LDB T1,LKTPTR ;GET THE NEXT LINK SETZM LNKTBL(T2) ;AND CLEAR TH CURRENT ENTRY MOVE T2,T1 ;SWITCH FROM TEMP JUMPN T2,LNKBK1 ;IF NOT AT LAMBDA, CONTINUE MOVSI T1,LNKACV ;FINALLY - TURN OFF OUR ACTIVE BIT ANDCAM T1,LDBLNK(U) ;.... LNKBE2: PUSHJ P,LNKGET ;CLEAR OUT THIS LINK BUFFER SKIPA ;OF ALL RESIDUAL CHARACTERS JRST LNKBE2 ;STILL MORE TO GO SYSPIN ;WHEW.... POP P,U POPJ P, $LIT END