TITLE TSKSER -TASK TO TASK COMMUNICATION SERVICE ROUTINE - V100 SUBTTL W. E. MATSON/WEM 08 JAN 80 SEARCH F,S,NETPRM $RELOC $HIGH Comment @ End Comment @ ;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED ; OR COPIED IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE. ; ; COPYRIGHT (C) 1978,1979,1980 BY DIGITAL EQUIPMENT CORP., MAYNARD, MASS. XP VTSKSER,100 ;PUT VERSION NUMBER IN GLOB AND LOADER MAP NETTSK::ENTRY NETTSK ;LOADING IF IN LIBRARY SEARCH MODE ;TSK. ERROR CODES TK%TNL==ECOD1## ; 1 = TSKSER NOT LOADED. TK%ATS==ECOD2## ; 2 = ARG LIST TOO SHORT TK%UNP==ECOD3## ; 3 = USER NOT PRIVLEDGED TK%ILF==ECOD4## ; 4 = ILLEGAL FUNCTION TK%ILC==ECOD5## ; 5 = ILLEGAL CHANNEL (OR NOT TASK) TK%ILN==ECOD6## ; 6 = ILLEGAL NPD TK%NTS==ECOD7## ; 7 = NPD TOO SHORT TK%ILS==ECOD10## ; 10 = ILLEGAL FUNCTION WHILE IN THIS STATE TK%NFC==ECOD11## ; 11 = NO MONITOR FREE CORE TK%NFL==ECOD12## ; 12 = NO FREE LINKS TK%NXN==ECOD13## ; 13 = ATTEMPT TO CONNECT TO A NONEXISTANT NODE TK%UDW==ECOD14## ; 14 = UUO (IN OR OUT) DIDN'T SKIP ;TSK. FUNCTION CODES .TKFRS==1 ; 1 = RETURN STATUS .TKFEP==2 ; 2 = ENTER PASSIVE STATE .TKFEA==3 ; 3 = ENTER ACTIVE STATE .TKFEI==4 ; 4 = ENTER IDLE STATE .TKFWT==5 ; 5 = WAIT .TKFOT==6 ; 6 = OUTPUT WITH CONTROL OF TYPE/E-O-R .TKFIN==7 ; 7 = INPUT WITH NOTIFICATION OF TYPE/E-O-R ;TSK. STATE VALUES .TKSID==0 ; 0 = LINE IS IDLE .TKSCI==1 ; 1 = WAITING FOR CONNECT INITIATE .TKSCC==2 ; 2 = WAITING FOR CONNECT CONFIRM .TKSOK==3 ; 3 = LINK IS OPERATIONAL .TKSDC==4 ; 4 = WAITING FOR A DISCONNECT CONFIRM COMMENT @ The first NPD in the UUO argument list is the Right-hand one (RH(DEVNPD)) The second NPD is the Left-hand one (LH(DEVNPD)) For the passive task. 1) The enter passive state uuo - NPD1 := Name we wish to be identified as (our process name) - NPD2 := The "pattern" we wish to match 2) After a successful connection, - NPD1 := The "actual" that the pattern successfully matched - NPD2 := The name of the remote process that sent the connect. For the active task. 1) The enter active state uuo - NPD1 := The name we want to return as "ours" on the confirm - NPD2 := The the "actual" we try to connect to. 2) After a successful connection, - NPD1 := The name the remote thinks we are. - NPD2 := The name he gave us as "his" @ TSK.:: PUSHJ P,SAVE4## ;WE USE A LOT OF P'S HLRZ P4,T1 ;P4 := LENGTH OF ARG LIST HRRZ P3,T1 ;P3 := ADDRESS OF ARG LIST CAIGE P4,2 ;MAKE SURE AT LEAST FCN & CHAN ARE THERE PJRST TK%ATS ;ERROR: ARG LIST TOO SHORT HRRI M,(P3) ;SET "M" UP TO READ FUNCTION CODE PUSHJ P,GETWDU## ;READ FUNCTION SKIPG P2,T1 ;P2 := FUNCTION CODE PJRST TK%ILF ;ILLEGAL FUNCTION CODE PUSHJ P,GETWD1## ;GET THE CHANNEL NUMBER MOVE P1,T1 ;P1 := CHANNEL NUMBER PUSHJ P,SETUF## ;SET UP F WITH ADDRESS OF DDB PJRST TK%ILC ;ERROR: ILLEGAL CHANNEL HRLM P1,.UPMP+.UPCTA ;SET UP THE EXTENDED CHANNEL NUMBER LDB T1,PDVTYP## ;GET THE DEVICE TYPE CAIE T1,<.TYTSK/.TYEST> ;MAKE SURE THAT THIS IS A TASK DEVICE PJRST TK%ILC ;ERROR: ILLEGAL CHANNEL CAILE P2,TSKMX ;IS THIS A LEGAL FUNCTION CODE PJRST TK%ILF ;ILLEGAL FUNCTION JRST @.(P2) ;DISPATCH TO SUBFUNCTION JRST TSKRS ; 1 = RETURN TASK STATUS JRST TSKEP ; 2 = ENTER PASSIVE TASK STATE JRST TSKEA ; 3 = ENTER ACTIVE TASK STATE JRST TSKEI ; 4 = ENTER IDLE TASK STATE JRST TSKWT ; 5 = WAIT FOR CONNECT INITIATE/CONFIRM/REJECT JRST TSKOU ; 6 = OUT WITH CONTROL OF E-O-R. JRST TSKIN ; 7 = IN WITH NOTIFICATION OF E-O-R. TSKMX=7 ; 7 = MAXIMUM LEGAL FUNCTION. ;SUB-FUNCTION #1 = RETURN STATUS TSKRS: PUSHJ P,GETSTA ;GET THE CONNECTION STATE CAIGE P4,3 ;IF WE CAN'T STORE THE STATUS JRST TK%ATS ;ERROR: ARG LIST TOO SHORT HRRI M,2(P3) ;GET THE ADDRESS OF THE RETURN VALUE AREA PUSHJ P,PUTWDU## ;RETURN THE STATE CAIN T1,LAT.ID ;SKIP IF WE HAVE TO RETURN NPD'S JRST [LDB T1,NETRSN##;GET REASON FOR LAST DISCONNECT PUSHJ P,PUTWD1## ;RETURN THAT AS SECOND ARG RETSKP] ;GIVE GOOD RETURN CAIGE P4,4 ;IF THE LIST IS ONLY 3 WDS LONG JRST CPOPJ1 ; THEN WE'RE DONE HRRI M,3(P3) ;GET ADDRESS OF THE FIRST NPD POINTER HRRZ J,DEVNPD(F) ;GET THE POINTER TO THE LOCAL NPD PUSHJ P,WRTNPD ;STORE THE NPD IN THE USER'S AREA POPJ P, ;PROPAGATE THE ERROR RETURN CAIGE P4,5 ;IF THE LIST ISN'T LONG ENOUGH JRST CPOPJ1 ; THEN RETURN HRRI M,4(P3) ;GET THE ADDRESS OF THE SECOND NPD POINTER HLRZ J,DEVNPD(F) ;GET THE POINTER TO THE REMOTE NPD PUSHJ P,WRTNPD ;STORE THE NPD POPJ P, ;PROPAGATE THE ERROR RETURN RETSKP ;ALL DONE, GOOD RETURN ;SUB-FUNCTION #2 = ENTER PASSIVE STATE. (WAITING FOR CONNECT INITIATE) TSKEP: PUSHJ P,GETSTA ;GET AND RANGE CHECK THE STATE CAIE T1,LAT.ID ;THIS FUNCTION IS ONLY LEGAL IN IDLE STATE PJRST TK%ILS ;ERROR: ILLEGAL STATE PUSHJ P,RD2NPD ;READ THE TWO NPD'S (ARG'S 1 & 2) POPJ P, ;NPD WAS BAD, PROPAGATE THE ERROR RETURN NETDBJ ;GET THE NETSER INTERLOCK PUSHJ P,T.PSIV ;ENTER PASSIVE STATE. JRST [PUSHJ P,GV2NPD## ;NO FREE LAT'S, FIRST RETURN THE NPD'S PJRST TK%NFL] ; THEN GIVE "NO FREE LINK ADDRESSES" ERROR RETSKP ;GIVE GOOD RETURN. STATE = LAT.CI ;SUB;SUB-FUNCTION #3 = ENTER ACTIVE STATE. (SEND CONNECT INITIATE) TSKEA: PUSHJ P,GETSTA ;GET AND RANGE CHECK THE STATE CAIE T1,LAT.ID ;THIS FUNCTION IS ONLY LEGAL IN IDLE STATE PJRST TK%ILS ;ERROR: ILLEGAL STATE PUSHJ P,RD2NPD ;READ THE TWO NPD'S (ARG'S 1 & 2) POPJ P, ;NPD WAS BAD, PROPAGATE THE ERROR RETURN HLRZ J,DEVNPD(F) ;GET THE ADDRESS OF THE REMOTE NPD SKIPG T1,NPDNOD(J) ;T1 := THE NODE NUMBER TO SEND CONNECT TO JRST [PUSHJ P,GV2NPD## ;IF IT'S NEGATIVE, RETURN NPD'S JRST TK%NXN] ; GIVE ILLEGAL NODE ERROR. NETDBJ ;GET THE NETSER INTERLOCK PUSHJ P,SRCNDB## ;W := NDB ADDRESS (IF NODE IS UP) JRST [PUSHJ P,GV2NPD## ;RETURN THE NPD'S PJRST TK%NXN] ; AND GIVE AN ILLEGAL NODE ERROR HRRM T1,DEVNET(F) ;MAKE THIS TASK'S NODE BE .T1 (FOR NCSCNT) PUSHJ P,T.ACTV ;ENTER ACTIVE STATE. SEND CONNECT INITIATE JRST [PUSHJ P,GV2NPD## ;NO FREE CORE. FIRST RETURN THE NPD'S PJRST TK%NFC] ; THEN GIVE "NO FREE CORE" ERROR RETSKP ;GIVE GOOD RETURN. STATE = LAT.CC ;SUB-FUNCTION #4 = ENTER IDLE STATE. SEND DISCONNECT IF NECESSARY. TSKEI: PUSHJ P,GETSTA ;GET AND RANGE CHECK THE CONNECTION STATE JRST @[EXP CPOPJ1##,TSKEI1,TK%ILS,TSKEI2,TK%ILS](T1) ;DISPATCH TSKEI1: NETDBJ ;GET THE NETSER INTERLOCK PUSHJ P,GV2NPD## ;RETURN THE TWO NPD'S PUSHJ P,GIVSLA## ;RETURN THE SLA, ENTER STATE LAT.ID RETSKP ;GIVE GOOD RETURN TSKEI2: NETDBJ ;GET THE NETSER INTERLOCK MOVEI T1,RSN.OK ;GET THE "NORMAL" REASON FOR DISCONNECT PUSHJ P,NTDXDS ;SEND THE DISCONNECT, ENTER LAT.DC STATE PJRST TK%NFC ;ERROR: NO MONITOR FREE CORE RETSKP ;GIVE GOOD RETURN ;SUB-FUNCTION #5 = WAIT FOR CONNECT INITIATE/CONFIRM/REJECT TSKWT: PUSHJ P,T.WAIT ;WAIT FOR TASK TO ENTER "ID" OR "OK" STATE RETSKP ;GIVE GOOD RETURN ;SUB-FUNCTION #6 = OUTPUT WITH CONTROL OF INTERRUPT/DAP MESSAGE TYPE TSKOU: PUSHJ P,GETSTA ;GET THE STATE OF THE CONNECTION, CAIE T1,LAT.OK ; AND IF WE AREN'T CONNECTED, THEN PJRST TK%ILS ; GIVE "ILLEGAL STATE" ERROR CODE HRRI M,2(P3) ;GET THE ADDRESS OF TSKOP.'S ARG #1 PUSHJ P,GETWDU## ;READ THE DAP TYPE PUSH P,T1 ;SAVE THE TYPE FOR A BIT HLR M,DEVBUF(F) ;GET THE ADDRESS OF THE BUFFER CONTROL BLOCK PUSHJ P,GETWDU## ;GET THE ADDRESS OF THE BUFFER HEADER JUMPL T1,TSKOU1 ;RING NOT SET UP. CALL "TOUT" TO SET UP RING HRRI M,(T1) ;GET THE USE BIT PUSHJ P,GETWDU## ; TO SEE IF THIS BUFFER HAS HAD AN "OUT" JUMPL TSKOU1 ; DONE. IF SO, DON'T CHANGE THE DAP TYPE PUSHJ P,GETWD1## ;GET "XWD 0,WORD-COUNT" HRL T1,(P) ;T1 := "XWD DAP-TYPE,WORD-COUNT" PUSHJ P,PUTWDU## ;STORE TYPE AND COUNT IN THE BUFFER HEADER TSKOU1: POP P,T2 ;CLEAN UP THE STACK HLLZS M,M ;CLEAR "BUFFER POINTER" BEFORE DOING AN OUT PUSHJ P,TOUT## ;DO THE OUT. (NTDXMT WILL NOTICE THE DAP TYPE) RETSKP ;IF UUO SUCCEEDS, RETURN NOW. JRST TSKIOE ;IF THE UUO DIDN'T WORK, TELL THE USER ;SUB-FUNCTION #7 = INPUT WITH NOTIFICATION OR INTERRUPT/MESSAGE TYPE TSKIN: HRRZ T1,DEVPCB(F) ;FIRST SEE IF ANY INPUT IS QUEUED JUMPN T1,TSKIN1 ;IF SO, READ IT. (EVEN IF DISCONNECTED) PUSHJ P,GETSTA ;GET OUR STATE AND MAKE SURE CAIE T1,LAT.OK ; THAT WE ARE CONNECTED. PJRST TK%ILS ;IF NOT CONNECTED, "ILLEGAL STATE" TSKIN1: HLLZS M,M ;CLEAR THE "BUFFER POINTER" PUSHJ P,TIN## ;DO THE "IN" UUO SKIPA ;SKIP IF THE UUO WAS SUCCESSFUL JRST TSKIOE ;IF UUO DIDN'T GIVE A BUFFER, GO SEE WHY HRR M,DEVBUF(F) ;TO RETURN E-O-R NOTIFICATION, GET BUFFER PUSHJ P,GETWDU## ; HEADER, AND FROM THAT TRACK DOWN THE HRRI M,1(T1) ; ".BTCNT" WORD OF THE BUFFER JUST PUSHJ P,GETWDU## ; RETURNED. HLRZ T1,T1 ;TSKSER PUTS THE DAP TYPE IN LH(.BFCNT) HRRI M,2(P3) ;GET THE ADDRESS OF ARG#1 OF THE TSKOP. PUSHJ P,PUTWDU## ; BLOCK AND RETURN THE DAP TYPE CODE RETSKP ;GIVE A GOOD RETURN TO THE ENTIRE UUO. TSKIOE: HRRZ T1,DEVIOS(F) ;IF UUO FAILS, GET THE DEVICE STATUS HRRI M,2(P3) ; AND RETURN IT IN ARG #1 OF THE PUSHJ P,PUTWDU## ; TSK. ARGUMENT BLOCK. PJRST TK%UDW ;TELL THE USER IT FAILED WITH "UUO DIDN'T WORK" ;T.WAIT ROUTINE TO WAIT FOR A TASK TO ENTER EITHER "LAT.ID" OR "LAT.OK" STATE ;CALL F := DDB POINTER ;RETURN CPOPJ ;ALWAYS T.WAIT: PUSHJ P,GETSTA ;GET THE CONNECTION STATE CAIE T1,LAT.ID ;IF IT'S IDLE, OR CAIN T1,LAT.OK ; IF IT'S "RUNNING" POPJ P, ; THEN RETURN PUSHJ P,NETHIB## ;OTHERWISE SLEEP TILL SOMEONE WAKES US. JRST T.WAIT ;UPON AWAKING, SEE IF THE STATE CHANGED. ;T.PSIV ROUTINE TO PUT A TASK IN THE PASSIVE (LAT.CI) STATE. ;CALL F := DDB POINTER ;RETURN CPOPJ ;IF NO FREE LINK ADDRESSES (LAT FULL) ; CPOPJ1 ;LINK ADDRESS ASSIGNED. WAITING FOR CI T.PSIV: IFN PARANOID&P$TSK,< ;IF WE'RE BEING CAUTIOUS, PUSHJ P,T.CHKC ;MAKE SURE WE'RE NOT CONNECTED > MOVEI T1,(F) ;RH(LAT-ENTRY) := DDB ADDRESS HRLI T1,LAT.CI ;LH(LAT-ENTRY) := NEW LINK STATE PUSHJ P,GETSLA## ;ASSIGN A SLA, SET NEW STATE POPJ P, ;NO FREE LINK ADDRESSES DPB T1,NETSLA## ;REMEMBER THE LINK ADDRESS RETSKP ;GIVE GOOD RETURN ;T.ACTV ROUTINE TO PUT A TASK IN THE ACTIVE (LAT.CC) STATE. SENDS CONNECT ;CALL F := DDB POINTER (WITH RH(DEVNET) := NODE NUMBER) ;RETURN CPOPJ ;NO CORE, OR NO FREE LINKS, OR NO NODE ; CPOPJ1 ;CONNECT INITIATE SENT. STATE := LAT.CC T.ACTV: IFN PARANOID&P$TSK,< ;IF WE'RE BEING CAUTIOUS, PUSHJ P,T.CHKC ;MAKE SURE WE'RE NOT CONNECTED > MOVEI T1,(F) ;RH(LAT-ENTRY) := DDB ADDRESS HRLI T1,LAT.CC ;LH(LAT-ENTRY) := LAT.CC PUSHJ P,GETSLA## ;ASSIGN A LINK ADDRESS POPJ P, ;ERROR: NO FREE LINK ADDRESSES DPB T1,NETSLA## ;REMEMBER OUR LINK ADDRESS MOVE T1,[XWD T.XSPN,T.XDPN] ;GET ADDRESS OF ROUTINE TO SEND "DPN" PUSHJ P,NCSCNT## ;CALL ROUTINE TO ACTUALLY SEND THE CONNECT PJRST GIVSLA ;ERROR: NO CORE. FREE THE SLA AND RETURN RETSKP ;GIVE GOOD RETURN IFN PARANOID&P$TSK,< ;IF CHECKING, STOP IF DDB IS CONNECTED T.CHKC: PUSHJ P,GETSTA ;GET THE STATE (BETTER BE ZERO) MOVE S,DEVIOS(F) ;GET THE "CONNECTED" BIT (AND OTHERS...) CAIN T1,LAT.ID ;DIE IF STATE /= "IDLE" TLNE S,IOSCON ;DIE IF DEVIOS THINK'S WERE CONNECTED PUSHJ P,NTDSTP## ;DIE, DIE, DIE... POPJ P, ;RETURN IF EVERYTHING'S OK > SUBTTL 1.0 UUOCON INTERFACE. ;DISPATCH TABLE (FROM UUOCON) POPJ P, ;(-5) DEVICE OFF LINE POPJ P, ;(-4) SPECIAL ERROR STATUS JRST REGSIZ## ;(-3) LENGTH CAN BE GOTTEN FROM DDB JRST CPOPJ## ;(-2) INITIALIZE JRST CPOPJ## ;(-1) HUNG DEVICE NDEVTS::JRST NTDREL## ;(0) RELEASE JRST T.CLSO ;(1) CLOSE OUTPUT JRST T.OUT ;(2) OUTPUT JRST T.IN ;(3) INPUT JRST T.ENTR ;(4) ENTER JRST T.LOOK ;(5) LOOKUP JRST NTDILI## ;(6) DUMP MODE INPUT JRST NTDILO## ;(7) DUMP MODE OUTPUT POPJ P, ;(10) USETO POPJ P, ;(11) USETI POPJ P, ;(12) GETF UUO POPJ P, ;(13) RENAME UUO JRST T.CLSI ;(14) CLOSE INPUT POPJ P, ;(15) UTPCLR POPJ P, ;(16) MTAPE UUO SUBTTL 1.1 DDB SEARCH LOGIC INTERFACE. ;TSTTSK ROUTINE TO SEE IF A TASK DDB SHOULD BE CREATED. ;CALL MOVEI P1,FLAGS ;DD%PHY=1B34, DD%LOG=1B35 ; MOVE T1,[SIXBIT /DEVICE/] ; PUSHJ P,TSTTSK ;RETURN CPOPJ ;NOT A TSK ; CPOPJ1 ;WAS A TSK, F := DDB POINTER ; DD%LOG==1B35 ;I HOPE IT'S THE SAME AS UUOCON. TSTTSK::TRNE P1,DD%LOG ;IS THIS A LOGICAL SEARCH? POPJ P, ;IF SO, THEN DON'T MATCH PHYSICAL TASKS TLC T1,(SIXBIT /TSK/) ;IF T1 := "TSKNNM" THEN THE LH(T1) TLNE T1,-1 ; IS NOW ZERO. JRST [TLC T1,(SIXBIT /TSK/) ;IF IT'S NOT, FIXUP T1 AGAIN POPJ P,] ; AND FAIL RETURN TLC T1,(SIXBIT /TSK/) ;FIX UP T1 AGAIN... NETDBJ ;INTERLOCK THIS CODE PUSHJ P,SAVE4## ;SAVE THE P'S PUSHJ P,SAVT## ;UUOCON LIKES IT'S TEAS MOVE P2,T1 ;COPY DEVICE NAME TO A REASONABLE REGISTER PUSHJ P,DVSCVT## ;CONVERT THE NETWORD DEVICE NAME, GET NODE # POPJ P, ;ILLEGAL DEVICE NAME MOVEI T1,(T2) ;COPY THE NODE NUMBER FOR SRCNDB PUSHJ P,SRCNDB## ;DOES THE NODE EXIST POPJ P, ;IF NOT, WE CAN'T CONNECT TO IT'S DEVICES MOVEI P1,(W) ;COPY THE NDB FOR SRCNDT SETZ P3, ;CLEAR THE LOGICAL NAME WORK HLRZ T1,P2 ;GET THE GENERIC DEVICE NAME PUSHJ P,SRCNDT## ;DOES THIS NODE SUPPORT THIS DEVICE? POPJ P, ;IF NOT. THEN SEARCH FAILS PUSHJ P,MAKDDB## ;IF NODE DOES SUPPORT THEM, THEN MAKE A DDB POPJ P, ;IF NO CORE. JUST MAKE SEARCH FAIL PUSHJ P,LNKDDB## ;LINK IN THIS DDB (EVEN THOUGH NOT CONNECTED) RETSKP ;RETURN WITH NEWLY CONSTRUCTED DDB. SUBTTL 1.2 OUTPUT UUO. ;T.OUT ROUTINE TO HANDLE THE OUT UUO FOR THE TSK DEVICE. ; T.OUT: PUSHJ P,SAVE4## ;THEY GET CLOBBERED NTDXMT AND FRIENDS MOVSI S,IOSUSO ;CLEAR "UUOCON STOPED OUTPUT" SINCE IT ANDCAB S,DEVIOS(F) ; APPEARS TO BE TRYING TO START IT AGAIN TOLOOP: PUSHJ P,NTDSET## ;SET UP S, W ETC MOVSI S,IO ;SET DIRECTION TO "OUTPUT" IORB S,DEVIOS(F) ; SO THAT UUOCON WILL BE HAPPY (WAIT1 ETC) PUSHJ P,NTDONL## ;SEE IF THIS DEVICE IS STILL CONNECTED. PJRST T.SERR ;NOT CONNECTED. SET IOSERR ; ; AS AN ECONOMY OF CODE, SET P1 := XWD CONVERSION-CODE, BYTE-SIZE. P1 ; SHOULD CONTAIN THESE VALUES UNTIL NTDISP IS CALLED. ; LDB T1,PIOMOD## ;GET THE CURRENT MODE MOVE P1,[XWD PCV.NC,^D07] ;ASSMUE ASCII MODE. (NO CONVERSION, 7 BIT) CAILE T1,AL ;IF IT'S NOT ASCII, IT'S IMAGE/BINARY MOVE P1,[XWD PCV.BN,^D12] ; (BINARY CONVERSION, 12 BITS) CAIN T1,BYTMOD ;UNLESS IT'S BYTE MODE. MOVE P1,[XWD PCV.NC,^D08] ; (NO CONVERSION, 8 BIT BYTES) MOVEI T1,(P1) ;GET THE BYTE SIZE PUSHJ P,NTDSOB## ;SET UP THE OUTPUT BUFFER JRST TODONE ;IF NO BUFFER, OUTPUT UUO IS DONE. ; ; NOTE: THIS CODE ALLOWS ZERO LENGTH DATA BUFFERS ; HRRZ T1,DEVOAD(F) ;GET A POINTER TO THE BUFFER HEADER EXCTUX ; AND USE IT TO GET THE TYPE/INTERRUPT BIT PUSHJ P,NTDPRV## ;DOES THIS GUY HAVE NETWORK PRIVS TRZ P2,(1B0) ;IF NOT, DON'T LET HIM SEND INTERRUPT MSGS TRZN P2,(1B0) ;IS THIS AN INTERRUPT MESSAGE? JRST [PUSHJ P,NTDCDQ## ;IF NOT, COUNT DOWN THE DATA REQUEST JRST TOWAIT ;IF NONE, THEN GO WAIT FOR SOME JRST .+1] ;WE HAVE DATA-REQUESTS. CONTINUE HLRZ T1,P1 ;GET THE CONVERSION CODE SKIPN T2,P2 ;GET THE IDC TYPE FIELD MOVEI T2,DC.DAR ;IF THE USER DIDN'T SPECIFY ONE. USE THE DEFAULT PUSHJ P,NTDXMT## ;SEND A PCB'S WORTH OF DATA JRST T.IMPM ;A NON-DATA MSG DIDN'T FIT. BLOCK TOO LARGE. SKIPN DEVAXO+1(F) ;IS THE BUFFER FINALLY EMPTY PUSHJ P,NTDAOB## ;IF SO, ADVANCE THE OUTPUT BUFFER JRST TOLOOP ;CONTINUE TILL SOMEONE GET'S BORED. ;TOWAIT ROUTINE TO WAIT FOR TASK OUTPUT DATA REQUESTS ; TOWAIT: PUSHJ P,NTDWTO## ;LET NETSER DO THE WORK. POPJ P, ;NON-BLOCKING. RETURN TO UUOCON JRST TOLOOP ;WHEN WE WAKE UP. TRY TO DO MORE OUTPUT ;TODONE HERE WHEN WE HAVE OUTPUT ALL THE USERS BUFFERS ; TODONE: POPJ P, SUBTTL 1.3 INPUT UUO. ;T.IN ROUTINE TO HANDLE THE "IN" UUO ENTRY TO THE TSK DEVICE ; T.IN: PUSHJ P,SAVE4## ;WE CLOBBER MOST OF THEM MOVSI S,IOSUSI ;CLEAR "UUOCON STOPED INPUT" SINCE IT'S ANDCAB S,DEVIOS(F) ; OBVIOUSLY TRYING TO START IT AGAIN TILOOP: PUSHJ P,NTDSET## ;USE COMMON SETUP ROUTINE (S, W, ETC) MOVE S,DEVIOS(F) ;GET STATUS BITS BACK AFTER A POSSIBLE SLEEP TLNE S,IOBEG ;IS THIS THE FIRST TIME THROUGH JRST TIFRST ;IF SO, LOOK FOR PSUEDO NON-BLOCKING CONNECT MOVSI S,IO ;CLEAR THE DIRECTION BIT SO THAT ANDCAB S,DEVIOS(F) ; UUOCON WON'T GET CONFUSED. PUSHJ P,NTDIBA## ;IS THEIR AN INPUT BUFFER AVAILABLE? POPJ P, ;IF NOT, WE ARE DONE. HRRZ T1,DEVPCB(F) ;GET A POINTER TO THE LIST OF INPUT PCB'S JUMPE T1,TIWAIT ;IF NO DATA, WE MUST WAIT PUSHJ P,NTDDID## ;DO THE DELAYED INPUT DISPATCH JRST TILOOP ;KEEP IT UP TILL WE RUN OUT OF DATA. ;TIFRST HERE WE CHECK TO SEE IF WE ARE CONNECTED. IF NOT, AND THIS IS NON- ; BLOCKING STYLE I/O. THEN WE DO A DEVERR RETURN TO UUOCON. OTHERWISE WE JUST ; WAIT. WHEN WE FINNALY GET CONNECTED. WE MUST REMEMBER TO TURN OFF "IOSERR" ; WHICH GOT SET BY NTDSET. ; TIFRST: TLNE S,IOSCON ;ARE WE CONNECTED YET JRST [MOVSI S,IOBEG!IOSERR!IOSREL ;IF WE ARE CONNECTED, CLEAR ANDCAB S,DEVIOS(F) ; THESE BITS, JRST TILOOP] ; AND TRY ONCE AGAIN TO PROCESS DATA. PUSHJ P,NTDWTI## ;IF NON CONNECTED, THEN WAIT FOR CONNECT/DATA POPJ P, ;IF NONBLOCKING, RETURN TO UUOCON JRST TILOOP ;TRY ONCE MORE TO DO INPUT ;TIWAIT HERE IF WE HAVE NO INPUT PCB'S TO PROCESS. FIRST MAKE SURE WE HAVEN'T ; BEEN DISCONNECTED. IF SO, SET EOF. OTHERWISE SEND DATA REQUESTS, AND ; WAIT IT OUT. ; TIWAIT: PUSHJ P,NTDONL## ;IS THERE ANY PARTICULAR PROBLEM?? JRST T.EOF ; IF SO, GO SEE WHAT IT IS PUSHJ P,NTDXDQ## ;SEE IF WE ARE BEHIND ON OUR DATA-REQUESTS PUSHJ P,NTDWTI## ;WAIT FOR DATA POPJ P, ;RETURN TO UUOCON IF NON-BLOCKING JRST TILOOP ;AND GO MUNCH IT ;T.EOF ROUTINE TO RETURN END-OF-FILE ON FIRST "IN" AFTER DISCONNECT. ; T.EOF: MOVSI S,IOEND ;GET THE END-OF-FILE BIT TDOE S,DEVIOS(F) ;SEE IF IT'S ALREADY SET. JRST T.SERR ;IF SO, THEN START COMPLAINING MOVEM S,DEVIOS(F) ;OTHERWISE JUST SET THE BIT POPJ P, ;AND GO BACK TO UUOCON ;T.IMPM, T.SERR ROUTINES TO SET ERROR BITS AND RETURN ; T.SERR: MOVE S,[XWD IOSERR,IODERR] ;THE TWO DEVICE ERROR BITS JRST T.SET ; AND SET THEM IN DEVIOUS T.IMPM: MOVEI S,IOIMPM ;IMPROPER MODE (NOT LOOKED UP/ENTERED) T.SET: IORB S,DEVIOS(F) ;SET THE BITS POPJ P, ;RETURN TO UUOCON. SUBTTL 1.4 ENTER UUO. ;T.ENTR ROUTINE TO HANDLE THE ENTER VECTORED ENTRY FROM UUOCON ;CALL F := XWD FLAGS,DDB ; M := UUO ;POINTE TO LOOKUP/ENTER BLOCK (LEB) ;RETURN CPOPJ ;NOT ENTERED. ERROR STORED IN LEB ; CPOPJ1 ;ENTERED. TASK IS CONNECTED. T.ENTR: PUSHJ P,GETSTA ;GET OUR STATE. MOVEI T2,1 ;GET A "1" LSH T2,(T1) ;MAKE IT A 1 BIT MASK TRNN T2,1_LAT.ID!1_LAT.CI!1_LAT.OK ;LEGAL STATES FOR ENTER'ING PJRST RTNISU ;OTHERWISE RETURN "ILLEGAL SEQUENCE OF UUO'S" PUSHJ P,SAVJW## ;WE CLOBBER THEM WITH NPD'S AND NDB'S PUSHJ P,SAVE4## ;SAVE THE P'S PUSHJ P,GETLEA ;GET THE LOOKUP ENTER ARG'S IN THE P'S PJRST RTNLEE ; IF LEB ARGS BAD, STORE ERROR IN LEB & RETURN PUSHJ P,GETSTA ;GET THE STATE AGAIN CAIN T1,LAT.ID ;IF WE ARE IDLE, THEN JRST T.ENT1 ; GO STORE ARGS & CONTINUE ;HERE IF TASK HAS BEEN LOOKED-UP (PUT IN PASSIVE STATE, POSSIBLY CONNECTED) PUSHJ P,CHKLEA ;MAKE SURE THAT THE LEB'S ARE IN AGREEMENT PJRST RTNAEF ; IF LEB BAD, GIVE AN "AEF" ERROR PUSHJ P,GETSTA ;GET THE CONNECTION STATE CAIN T1,LAT.OK ;IF WE'RE ALREADY CONNECTED, THEN RETSKP ; GIVE A GOOD RETURN TO THE ENTER. IFN PARANOID&P$TSK,< ;IF WE'RE BEING PARANOID, MAKE SURE CAIE T1,LAT.CI ; WE'RE IN THE "PASSIVE" STATE PUSHJ P,NTDSTP## ; IF NOT, THEN WE'VE SCREWED UP. > PUSHJ P,GV2NPD ;RETURN THE LOOKUP'S NPDS PUSHJ P,GIVSLA## ;RETURN THE LAT (T.ACTV ASSIGNS A NEW ONE) JRST T.ENT2 ;GO SEND THE CONNECT INITIATE AND RETURN ;HERE IF WE HAVEN'T BEEN LOOKED UP YET. (STATE IS "IDLE") T.ENT1: PUSHJ P,STOLEA ;STORE THE LOOKUP/ENTER ARGS ; PJRST T.ENT2 ;GO SEND THE CONNECT INITIATE ;HERE WE SET UP "W", BUILD TWO NPD'S, SEND THE CONNECT & WAIT FOR A REPLY T.ENT2: HRRZ T1,DEVNET(F) ;GET THIS DEVICE'S NODE NUMBER PUSHJ P,SRCNDB## ;SET W := NDB POINTER. PJRST RTNUNN ; ERROR. RETURN "UNKNOWN NETWORK NODE" PUSHJ P,LE2NPD ;MAKE 2 NPD'S, REMOTE & LOCAL FOR T.ACTV PJRST RTNENC ; IF NO CORE "EXCEEDED NETWORK CAPACITY" HLRZ T1,NDBNNM(W) ;GET THE NODE NUMBER WE'RE TRYING TO CONNECT TO HLRZ J,DEVNPD(F) ;GET THE "REMOTE" NPD MOVEM T1,NPDNOD(J) ;SET THE NPD'S NODE NUMBER PUSHJ P,T.ACTV ;SEND THE CONNECT INITIATE JRST [PUSHJ P,GV2NPD ;IF NO CORE, OR NO LATS, FREE NPD'S PJRST RTNENC] ;RETURN EXCEEDED NETWORK CAPACITY ;IF NONBLOCKING, WE MIGHT WANT TO RETURN HERE PUSHJ P,T.WAIT ;WAIT FOR CONNECT CONFIRM/REJECT PUSHJ P,GETSTA ;GET OUR STATE (TO SEE IF CONFIRM/REJECT) CAIE T1,LAT.OK ;IF WE'RE NOT CONNECTED, THEN JRST [PUSHJ P,GV2NPD ; RETURN BOTH THE NPD'S, AND PJRST RTNTNA] ; GIVE A "TASK NOT AVAILABLE" ERROR RETSKP ; OTHERWISE, GIVE A GOOD RETURN SUBTTL 1.5 LOOKUP UUO. ;T.LOOK ROUTINE TO HANDLE THE LOOKUP VECTORED ENTRY FROM UUOCON ;CALL F := XWD FLAGS,DDB ; M := UUO ;POINTS TO THE USERS LOOKUP/ENTER BLOCK (LEB) ;RETURN CPOPJ ;IF ERROR, CODE RETURNED IN LEB ; CPOPJ1 ;TASK LOOKED-UP. NOW IN "PASSIVE" STATE T.LOOK: PUSHJ P,GETSTA ;GET OUR CONNECTION STATE MOVEI T2,1 ;GET A "1" LSH T2,(T1) ;MAKE IT A 1 BIT MASK TRNN T2,1_LAT.ID!1_LAT.OK ;LEGAL STATES FOR LOOKING UP PJRST RTNISU ;OTHERWISE RETURN "ILLEGAL SEQUENCE OF UUO'S" PUSHJ P,SAVJW## ;J := NPD'S, W := NDB'S PUSHJ P,SAVE4## ;WE PUT THE LOOKUP/ENTER ARGS HERE PUSHJ P,GETLEA ;GET THE LEB'S DATA PJRST RTNLEE ;LEB BAD, RETURN ERROR CODE IN "T1" PUSHJ P,GETSTA ;GET THE STATE AGAIN CAIN T1,LAT.ID ;IF NOT IDLE, JUST CHECK THE ARGUMENTS JRST T.LOO1 ;IF IDLE, GO TO "PASSIVE" STATE ;HERE IF WE'VE BEEN ENTERED, CHECK THE LEB'S ARGS AND RETURN PUSHJ P,CHKLEA ;MAKE SURE THE LOOKUP AGREES WITH THE ENTER PJRST RTNAEF ; IF LEB IS BAD, RETURN "AEF" RETSKP ;GIVE GOOD RETURN TO THE LOOKUP ;HERE IF WE'VE NOT BEEN ENTERED, MAKE 2 NPD'S AND ENTER PASSIVE STATE T.LOO1: PUSHJ P,STOLEA ;STORE DEVFIL AND FRIENDS FOR LE2NPD. IFN PARANOID&P$TSK,< ;IF WERE CAUTIOUS, MAKE SURE NOT CONNECTED SKIPE DEVNPD(F) ;DIE IF WE'VE ALREADY GOT 1 OR MORE NPD'S PUSHJ P,NTDSTP## ;DIE DIE DIE... > HRRZ T1,DEVNET(F) ;GET THE NUMBER OF THIS TASK'S NODE PUSHJ P,SRCNDB## ;SET W := NDB POINTER. PJRST RTNUNN ; ERROR. RETURN "UNKNOWN NETWORK NODE" PUSHJ P,LE2NPD ;MAKE NPD'S BASED ON DEVFIL & FRIENDS PJRST RTNENC ; NO CORE. RETURN "EXCEEDED NET CAP" CAIE W,NETNDB## ;IF HE SPECIFIED "ANY" NODE, DON'T SET NPDNOD JRST [HLRZ J,DEVNPD(F) ;GET ADDRESS OF "REMOTE" NPD. HLRZ T1,NDBNNM(W) ;GET OUR NODE NUMBER MOVEM T1,NPDNOD(J) ;SET THE NODE NUMBER JRST .+1] ;CONTINUE WITH MAIN CODE PUSHJ P,T.PSIV ;ENTER "PASSIVE" STATE JRST [PUSHJ P,GV2NPD ;IF NO CORE, OR NO LATS, FREE NPD'S PJRST RTNENC] ;RETURN EXCEEDED NETWORK CAPACITY RETSKP ;GIVE GOOD RETURN TO THE LOOKUP SUBTTL 1.6 CLOSE UUO. ;T.CLS ROUTINE TO HANDLE THE CLOSE ENTRY FROM UUOCON ;CALL MOVEI F,DDB ; PUSHJ P,T.CLS ;FROM CLOSE1 CODE IN UUOCON ;RETURN CPOPJ ; ;THE CLOSE UUO CODE DOES NOTHING IF THE TSK HAS NOT BEEN CLOSED ON BOTH INPUT ; AND OUTPUT. IF IT HAS, IT DOES THE FINAL "OUT" TO FLUSH THE BUFFERS, AND ; SENDS A DISCONNECT INITIATE WAITING FOR THE DISCONNECT CONFIRM. ; T.CLSO: TLNE F,ENTRB ;DON'T FORCE OUTPUT IF NOT ENTERED PUSHJ P,NTDCLO## ;FORCE OUT THE LAST BUFFER (AND WAIT) TLZA F,ENTRB ;SIGNIFY THAT WE ARE NO LONGER "ENTERED" T.CLSI: TLZ F,LOOKB ;SIGNIFY THAT WE ARE NO LONGER "LOOKED UP" T.CLS: TLNE F,ICLOSB ;IF WE HAVEN'T CLOSED BOTH INPUT AND TLNN F,OCLOSB ; OUTPUT, THEN POPJ P, ; DON'T ATTEMPT TO DISCONNECT THIS TASK T.CLS1: PUSHJ P,T.WAIT ;WAIT FOR CONNECTS/DISCONNECTS TO FINISH MOVE S,DEVIOS(F) ;NOW SEE IF WE ARE CONNECTED TLNN S,IOSCON JRST T.CLS4 ;DON'T SEND DISCONNECT IF NOT CONNECTED T.CLS2: MOVEI T1,RSN.OK ;STANDARD REASON PUSHJ P,NTDXDS## ;SEND THE DISCONNECT JRST [PUSHJ P,NETSLP## ;IF WE CAN'T SEND THE DISCONNECT, THEN JRST T.CLS2] ; THEN WAIT FOR A BIT AND TRY AGAIN T.CLS3: PUSHJ P,NETHIB## ;WAIT FOR THE CONFIRM LDB T1,NETSLA## ;GET OUR LAT ADDRESS JUMPE T1,T.CLS5 ;THE DISCONNECT CONFIRM CODE WILL ZERO IT IFN PARANOID&P$LAT,< ;MAKE SURE LAT ENTRY IS RIGHT LDB T1,LATSTA## ;GET THE STATE CAIE T1,LAT.DC ;SHOULD STILL BE DISCONNECT CONFIRM PUSHJ P,NTDSTP## ;++ WRONG CONNECTION STATE > JRST T.CLS3 ;MUST HAVE BEEN A SPURIOUS WAKE T.CLS4: LDB T1,NETSLA## ;FIRST CHECK TO SEE IF WE HAVE JUMPE T1,T.CLS5 ;LAT ASSIGNED. IF NOT, DON'T FREE IT. IFN PARANOID&P$LAT,< LDB T2,LATSTA## ;GET THE STATE CAIE T2,LAT.CI ;THE ONLY LEGAL STATE AT THIS POINT IS "CI" PUSHJ P,NTDSTP## ;++ ILLEGAL STATE FOR TASK LAT > PUSHJ P,GIVSLA## ;FREE THE SLA T.CLS5: PUSH P,J ;NOW FREE THE NPD'S. FIRST SAVE J PUSHJ P,GV2NPD## ;FREE THE NPD'S POP P,J SETZM DEVFIL(F) ;CLEAR THE FILE NAME HRRZS DEVEXT(F) ; THE EXTENSION SETZM DEVPPN(F) ; THE PPN POPJ P, ;ALL DONE. SUBTTL 2.0 NETSER INTERFACE. ;TSKSER'S NDP DISPATCH VECTOR (HERE ON MESSAGES FROM NETSER) JRST NTDNWD## ;COMMON CODE FOR CRASHED NODE JRST NTDDSC## ;COMMON CODE FOR DISCONNECT JRST T.CONC ;SPECIAL CODE FOR CONNECT CONFIRM JRST T.CONI ;SPECIAL CODE FOR CONNECT INITIATE JRST NTDRDQ## ;COMMON CODE FOR DATA-REQUESTS TSKNDP::JRST NTDQIP## ;QUEUE INCOMING PCB'S TO UUO LEVEL JRST T.DAPI ;DATA WITH OUT EOR JRST T.DAPI ;DATA WITH EOR JRST T.DAPI ;STATUS JRST T.DAPI ;CONTROL JRST T.DAPI ;UNIT ID JRST T.DAPI ;FILE SPEC SUBTTL 2.1 CONNECT CONFIRM NCL MESSAGE. ;T.CONC ROUTINE TO PROCESS THE CONNECT CONFIRM FOR A TASK ;CALL MOVEI F,DDB ; P1, P4 := POINT TO THE "SLA" FIELD OF THE CONNECT ;RETURN CPOPJ1 ;ALWAYS ; T.CONC: PUSHJ P,SAVJW## ;WE USE J FOR THE NPD ;SLA PUSHJ P,EBI2BI## ;READ OUR REMOTE LAT ADDRESS DPB T1,NETDLA## ;SAVE IT SO WE CAN TALK TO HIM PUSHJ P,GV2NPD ;RETURN THE TWO STALE NPD'S. ;DPN(OBJ) PUSHJ P,XSKIP## ;WE'RE NOT INTERESTED ;DPN(PID) PUSHJ P,GETSPN ;GET WHAT HE THINKS WE ARE SETZ J, ; IF NO CORE, DON'T WORRY... HRRM J,DEVNPD(F) ;STORE NEW LOCAL NPD ;SPN(OBJ) PUSHJ P,XSKIP## ;WE'RE NOT INTERESTED ;SPN(PID) PUSHJ P,GETSPN ;GET HIS ID SETZ J, ; IF NO CORE, JUST RETURN ZERO HRLM J,DEVNPD(F) ;STORE THE NEW REMOTE NPD ;MML,FEA(DCM,RLN,DVT) PUSHJ P,GETFEA ;READ THE "FEATURES" PUSHJ P,T.OK ;SET BITS SAYING WE ARE CONNECTED RETSKP ;GIVE GOOD RETURN SUBTTL 2.2 CONNECT INITIATE NCL MESSAGE. ;T.CONI ROUTINE TO HANDLE THE CONNECT INITIATE ENTRY FOR THE TSK DEVICE. ;CALL MOVEI F,DDB ; MOVE P3,[XWD SLA,OBJ] ; P1, P4 := POINT TO THE "DPN(PID)" FIELD OF THE CONNECT MESSAGE ;RETURN CPOPJ ;DIDN'T LIKE THE CONNECT ; CPOPJ1 ;OK. CONNECT CONFIRM SENT. LINK IN "OK" STATE ; T.CONI: HRRZ T1,P3 ;GET THE OBJECT TYPE CAIE T1,OBJ.TK ; AND MAKE SURE IT'S FOR TYPE "TSK" POPJ P, ; IF NOT FOR US, EXIT NOW PUSHJ P,SAVJW## ;WE CLOBBER J PUSHJ P,SAVE4## ; AND MASSACRE THE P'S MOVS J,DEVNPD(F) ;GET THE "PATTERN" NPD POINTER TLNE J,-1 ;MAKE SURE THAT BOTH NPD'S TRNN J,-1 ; EXIST POPJ P, ;IF EITHER NPD MISSING, DON'T MATCH HLRZ T1,NDBNNM(W) ;GET THIS NODE'S NUMBER SKIPL T2,NPDNOD(J) ;GET THE PATTERN'S NODE NUMBER CAIN T1,(T2) ;SKIP IF THEY DON'T MATCH SKIPA ;EITHER WILD CARD, OR MATCH, SUCCEED. POPJ P, ;NO MATCH. EXIT NOW. PUSHJ P,T.CON1 ;CALL ROUTINE TO DO PATTERN MATCH POPJ P, ; IF NO MATCH, GIVE "REJECT" RETURN HLRZ T1,P3 ;GET THE SLA DPB T1,NETDLA## ; AND REMEMBER IT. HLRZ T1,NDBNNM(W) ;GET THE NODE NUMBER HRRM T1,DEVNET(F) ; AND REMEMBER THAT TO. ;READ NCD'S ;DPN(PID) PUSHJ P,GETSPN ;SET J := NPD DESCRIBING WHAT WE MATCHED POPJ P, ; NO CORE, GIVE ERROR RETURN FROM T.CONI HLRZ T1,NDBNNM+NETNDB## ;GET OUR NODE NUMBER MOVEM T1,NPDNOD(J) ;AND USE THAT INSTEAD OF HIS. PUSH P,J ;SAVE NPD FOR A BIT ;SPN(OBJ) PUSHJ P,XSKIP## ;WE'RE NOT INTERESTED ;SPN(PID) PUSHJ P,GETSPN ;READ THE SOURCE PID JRST [POP P,J ;IF NO CORE, GET LAST NPD READ PJRST GIVNPD] ; RETURN IT, AND ERROR RETURN FROM T.CONI HRLM J,0(P) ;SAVE THE NEW "REMOTE" NPD ;MML,FEA(DCM,RLN,DVT) PUSHJ P,GETFEA ;READ THE "FEATURES" ;SEND CONFIRM HLRZ J,DEVNPD(F) ;GET OLD "REMOTE" NPD AND FREE IT. PUSHJ P,GIVNPD## ; (THERE MUST BE ONE TO GET THIS FAR...) HLRZ J,0(P) ;GET THE NEW "REMOTE" NPD HRLM J,DEVNPD(F) ; AND PUT IT WHERE T.XDPN CAN FIND IT. MOVE T1,[XWD T.XSPN,T.XDPN] ;ROUTINES TO SEND SPN AND DPN EMRGCY ;USE EMERGENCY MEMORY IF NECESSARY PUSHJ P,NCSCNT## ;SEND THE CONNECT CONFIRM PUSHJ P,NTDSTP## ;WE'VE SCREWED UP... SHOULDN'T HAPPEN HRRZ J,DEVNPD(F) ;GET OLD "LOCAL" NPD AND FREE IT PUSHJ P,GIVNPD## ; (THERE MUST BE ONE IF WE GOT THIS FAR) POP P,J ;GET NEW "LOCAL" NPD HRRM J,DEVNPD(F) ;AND PUT IT WHERE A ".TKFRS" CAN FIND IT PUSHJ P,T.OK ;DECLARE THE TSK UP, WAKE ANY WAITING JOBS RETSKP ;GIVE GOOD RETURN ;T.CON1 SUB-ROUTINE TO SET THINGS UP FOR THE "MATCH" ROUTINE. ; THE ONLY REASON THAT THIS IS A SUBROUTINE IS TO MAKE IT EASY ; TO SKIP/NON-SKIP RETURN. ;CALL J := POINTER TO THE "PATTERN" NPD ; P1, P4 := MESSAGE POINTER,COUNT TO PID (AS USUAL) ;RETURN CPOPJ ;PATTERN DIDN'T MATCH PID ; CPOPJ1 ;PATTERN DID MATCH, P1, P4 UPDATED TO AFTER ; ; PID T.CON1: PUSH P,P3 ;SAVE THE "XWD SLA,OBJ" INFORMATION PUSH P,P1 ;SAVE THE BYTE POINTER TO THE MESSAGE PUSH P,P4 ;SAVE THE LENGTH OF THE MESSAGE MOVE P3,P4 ;COPY THE LENGTH FOR MATCH PUSHJ P,XSKIP## ;ADVANCE PAST PID SO WE CAN CALCULATE LENGTH SUB P3,P4 ;SET P3 := LENGTH(PID) MOVE P4,-1(P) ;SET P4 := BYTE-POINTER TO PID MOVE P1,NPDNLN(J) ;SET P1 := LENGTH OF THE "PATTERN" MOVEI P2,NPDNAM(J) ;GET THE ADDRESS OF THE "PATTERN" HRLI P2,(POINT 7) ;SET P2 := BYTE-POINTER TO "PATTERN" SETZ T4, ;GET A ZERO EXCH T4,TKMTCH ;SEE IF THERE IS ALREADY A PSUEDO-STACK JUMPE T4,[MOVEI T2,100 ;GET LENGTH OF PSUEDO-STACK PUSHJ P,GETZWD## ;TRY TO ALLOCATE A NEW PSUEDO-STACK JRST T.CON2 ;IF NO CORE, CLEAN UP AND ERROR RETURN MOVEI T4,(T1) ;COPY ADDRESS OF NEW STACK HRLI T4,-100 ;MAKE IT AN AOBJN POINTER JRST .+1] ;RETURN TO MAIN CODE WITH T4 := STACK POINTER PUSHJ P,MATCH ;SEE IF THE PID MATCHES THE PATTERN JRST T.CON2 ; IF NO MATCH, CLEAN UP AND ERROR RETURN AOS -3(P) ;IF IT MATCHES. GIVE SKIP RETURN (UGH...) T.CON2: EXCH T4,TKMTCH ;PUT STACK IN THE PSUEDO-STACK CACHE JUMPN T4,[MOVEI T1,(T4) ;IF THERE IS ALREADY A P-STACK, HRLI T2,(T4) ; THEN WE MUST FREE THE EXTRA MOVN T2,T2 ; ONE. PUSHJ P,GIVZWD## ;CALL NETSER TO FREE THE CORE. JRST .+1] ;RETURN TO MAIN LINE CODE. POP P,P4 ;SET P4 := LENGTH(MESSAGE-PID) POP P,P1 ;SET P1 := BYTE-POINTER TO PID POP P,P3 ;SET P3 := "XWD SLA,OBJ" POPJ P, ;GIVE (POSSIBLY SKIP) RETURN SUBTTL 2.3 DAP MESSAGES. ;T.DAPI HERE TO PROCESS ALL OF THE INCOMING DAP MESSAGES ;CALL MOVEI T1,IDC MESSAGE TYPE ; MOVEI F,DDB OF DEVICE GETTING MESSAGES ;RETURN CPOPJ ;MESSAGE BAD ; CPOPJ1 ;MESSAGE OK ; T.DAPI: HRRZ T2,DEVPCB(F) ;GET A POINTER TO THE PCB WE'RE READING MOVE T2,PCBIAD(T2) ;GET A BYTE POINTER TO THE NCT FIELD OF THE MSG ILDB T2,T2 ;GET THE NCT BYTE TLNE T2,NCT.IT ;IF THIS IS AN INTERRUPT MESSAGE, IORI T1,(1B0) ; REMEMBER, SET "INTERRUPT" BIT IN BUFFER HEAD MOVE P2,T1 ;COPY THE HALFWORD INTO A SAFER REGISTER. LDB T1,PIOMOD## ;GET THE MODE WE ARE READING IN. CAIG T1,AL ;ASCII OR ASCII LINE? JRST T.ASCI ;IF SO, GO TO ASCII CODE CAIN T1,BYTMOD ;BYTE MODE? JRST T.BYTE ;IF SO, SPECIAL CODE JRST T.IMAG ;ALL THE REST IS IMAGE. T.ASCI: SKIPA T4,[7] ;SEVEN BIT BYTES IN ASCII T.BYTE: MOVEI T4,8 ;EIGHT BIT BYTES IN BYTE MODE PUSHJ P,T.SIB ;USE COMMON SET-UP ROUTINE T.BYT1: SOJL P4,T.ADVB ;IF DONE. ADVANCE PCB & USER'S BUFFERS ILDB T1,P1 ;GET THE NEXT DATA BYTE SOSGE DEVAXI+1(F) ;COUNT OFF NEXT BYTE IN THE BUFFER JRST T.BKTL ;IF NO ROOM, SET IOBKTL EXCTUU ;STORE THE BYTE JRST T.BYT1 ;LOOP UNTIL INPUT MESSAGE IS USED UP. T.IMAG: MOVEI T4,^D12 ;12 BIT BYTES PUSHJ P,T.SIB ;USE COMMON SETUP ROUTINE T.IMG1: SOJL P4,T.ADVB ;IF NO MORE, ADVANCE PCB'S AND USER'S BUFFERS ILDB T1,P1 ;GET THE TOP 8 BITS OF THE FIRST BYTE LSH T1,4 ;POSITION THEM IN THE 12 BIT FIELD SOJL P4,T.IMG2 ;IF NO MORE, STORE THIS WITH ZERO FILL ILDB T2,P1 ;GET LOW 4 BITS THIS BYTE, HIGH 4 OF THE NEXT ROT T2,-4 ;POSITION THE LOW 4 BITS IORI T1,(T2) ;COMBINT BOTH HALVS FOR A 12 BIT BYTE SOSGE DEVAXI+1(F) ;COUNT OFF THIS BYTE JRST T.BKTL ;GIVE AN ERROR IF IT WON'T FIT EXCTUU ;STORE THIS FIRST 12 BIT BYTE SOJL P4,T.ADVB ;IF NO MORE, LAST 4 BITS ARE GARBAGE. ILDB T1,P1 ;GET THE LAST 8 BITS OF THE SECOND 12 BIT BYTE ROT T2,^D12 ;ISOLATE THE LOW 4 BITS AS THE HIGH 4 IORI T1,(T2) ;BUILD THE SECOND 12 BIT BYTE T.IMG2: SOSGE DEVAXI+1(F) ;COUNT OFF THIS BYTE JRST T.BKTL ;GIVE AN ERROR IF IT WON'T FIT EXCTUU ;STORE THE SECOND 12 BIT BYTE JRST T.IMG1 ;LOOP UNTIL ALL INPUT IS PROCESSED. ;T.SIB ROUTINE TO SET UP AN INPUT BUFFER FOR TSK INPUT ; CALLS NTDSIB, AND STORES THE MESSAGE TYPE AND INTERRUPT BIT IN THE ; USER'S BUFFER HEADER. ; T.SIB: PUSHJ P,NTDSIB## ;SET UP THE INPUT BUFFER PUSHJ P,NTDSTP## ;++ NO INPUT BUFFER (BUT WE CHECKED IN T.IN) HRRZ T1,DEVIAD(F) ;GET THE ADDRESS OF THE BUFFER HEADER EXCTUU ;STORE THE MESSAGE TYPE AND INTERRUPT BIT POPJ P, ;RETURN TO MAIN-LINE CODE. ;T.ADVB TASK ADVANCE BUFFER AND PCB ROUTINE. THIS ROUTINE ADVANCES ; THE BUFFER IFF THE MESSAGE RECEIVED WAS NOT DATA-WITHOUT-EOR, OR ; IF THE "DISABLE MESSAGE RE-ASSEMBLY" (IOSDMR) BIT WAS SET. ;CALL P2 := IDC TYPE ;LEFT OVER FROM EARLIER ;RETURN CPOPJ1 ;ALWAYS. T.ADVB: TRZ P2,(1B0) ;MAKE SURE THE "INTERRUPT" BIT IS OFF CAIN P2,DC.DAT ;IF IT'S NOT DATA-WITHOUT-EOR, TLNE S,IOSDMR ; OR WE'RE NOT RE-ASSEMBLING BUFFERS PJRST NTDA1B## ; THEN ADVANCE THE BUFFER RETSKP ;IF DATA WITHOUT-EOR, THEN DON'T ADVANCE ; THE BUFFER ;T.BKTL ROUTINE TO SET THE "IOBKTL" ERROR BIT IF A USERS BUFFER IS TOO SMALL ; IT ADVANCES THE USERS BUFFER, AND SKIP RETURNS (ADVANCING THE DAP MESSAGE) ; T.BKTL: MOVEI S,IOBKTL ;GET THE BLOCK TOO LARGE BIT IORB S,DEVIOS(F) ;SET IT PJRST NTDA1B## ;ADVANCE THE USERS BUFFER AND THE DAP MESSAGE SUBTTL X.X ONCE/SECOND TASK CODE ;FREE THE TEMPORARY "PSUEDO-STACK" USED BY TSKSER TSKSEC::SETZ T2, ;GET A ZERO TO INDICATE NO BLOCK EXCH T2,TKMTCH ;GET "XWD LENG,ADDR" OF BLOCK JUMPE T2,CPOPJ## ;IF NONE, RETURN NOW HLRE T1,T2 ;COPY (MINUS) THE LENGTH MOVN T1,T1 ;MAKE THE LENGTH POSITIVE PJRST GIVZWD## ;RETURN THE STORAGE SUBTTL 3.0 SUBROUTINES. SUBTTL 3.1 LOOKUP/ENTER BLOCK MANIPULATION ;GETLEA ROUTINE TO GET THE LOOKUP/ENTER ARGUMENTS FOR THE TSK DEVICE. ;CALL MOVE M,THE UUO ; PUSHJ P,GETLEA ;RETURN CPOPJ ;ERROR CODE IN T1 ; CPOPJ1 ;P1 := DEVNAM ; ;P2 := DEVEXT ; ;P3 := DEVPPN (THE USERS IF NOT PRVJ) ; GETLEA: ;HERE TO GET LOOKUP/ENTER ARGS PUSH P,U ;USE U AS A TEMP TO MOVE U,M ; THE ADDRESS OF THE ARGUMENT LIST PUSHJ P,GETWDU## ;GET THE FIRST (DEVNAM OR COUNT) MOVE P1,T1 ;RETURN FIRST WORD AS DEVNAM TLNN T1,-1 ;IS IT AN EXTENDED BLOCK JRST GETLEE ; IF SO. GO TO SPECIAL CODE TO READ IT HRRI M,UUNEXT(U) ;GET THE EXTENSION PUSHJ P,GETWDU## ; FROM THE USERS MEMORY, AND MOVE P2,T1 ; RETURN THAT AS DEVEXT HRRI M,UUNPPN(U) ;GET THE PPN FROM THE USERS MEMORY JRST GETLE1 ; AND GO TO COMMON CODE. GETLEE: MOVEI T1,FNFERR ;IN CASE TOO SHORT CAIGE P1,UUXEXT ;IS THIS BLOCK LONG ENOUGH JRST UPOPJ## ; IF TOO SHORT, GIVE AN ERROR RETURN HRRI M,UUXNAM(U) ;GET THE FILE NAME PUSHJ P,GETWDU## ; FROM THE USERS MEMORY, MOVE P1,T1 ; AND RETURN AS DEVNAM HRRI M,UUXEXT(U) ;GET THE EXTENSION PUSHJ P,GETWDU## ; FROM THE USER MOVE P2,T1 ; AND RETURN AS DEVEXT HRRI M,UUXPPN(U) ;GET THE PPN GETLE1: PUSHJ P,GETWDU## ;GET THE PPN MOVE T2,.CPJOB## ;GET THIS GUY'S JOB NUMBER SKIPN P3,T1 ;GET USER-SPECIFIED PPN MOVE P3,JBTPPN##(T2) ;HE DIDN'T SPECIFY ONE, USE JOB'S PPN. CAME P3,JBTPPN##(T2) ;SPECIFYING A PPN OTHER THAN HIS? CAMN P3,[-1] ;(OR [777777,777777]?) JRST GETLE2 ;NO, IT IS OK MOVEI T1,PRTERR ;IN CASE NOT PRIVILEGED PUSHJ P,NTDPRV## ; HE MUST BE PRIVILEGED JRST UPOPJ## ; AND HE IS NOT, PROTECTION ERROR GETLE2: MOVE T1,P3 ;GET THE PPN THAT WE WILL USE PUSHJ P,PUTWDU## ;TELL THE USER WHAT PPN WE REALLY ARE USING MOVE M,U ;RESTORE THE UUO PJRST UPOPJ1## ;GIVE A GOOD RETURN ;CHKLEA ROUTINE TO CHECK TO MAKE SURE THAT THE DDB'S DEVNAM, DEVEXT, AND ; DEVPPN AGREE WITH THE LOOKUP/ENTER BLOCK'S ;CALL MOVEI F,DDB ;WITH DEVNAM ... SET UP ; P1, P2, P3 := THE LOOKUP/ENTER ARGS ;RETURN CPOPJ ;THEY DON'T AGREE (AEF ERROR RETURNED) ; CPOPJ1 ;THEY AGREE ; CHKLEA: CAMN P1,DEVFIL(F) ;COMPARE THE FILE NAMES CAME P3,DEVPPN(F) ;COMPARE THE PPN'S JRST RTNAEF ;GIVE THE "AEF" ERROR (ALREADY EXISTING FILE) XOR P2,DEVEXT(F) ;COMPARE THE EXTENSIONS TLNE P2,-1 ; AND ONLY THE EXTENSIONS JRST RTNAEF ;DIFFERENT. GIVE ERROR RETSKP ;ALL THE SAME. GIVE GOOD RETURN ;STOLEA ROUTINE TO STORE THE LOOKUP/ENTER ARGS IN P1, P2, P3 INTO A DDB ;CALL MOVEI F,DDB ; P1, P2, P3 := FILE NAME, EXTENSION, PPN ; PUSHJ P,STOLEA ;RETURN CPOPJ ;ALWAYS ; STOLEA: MOVEM P1,DEVFIL(F) ;STORE THE FILE NAME HLLM P2,DEVEXT(F) ;STORE JUST THE EXTENSION MOVEM P3,DEVPPN(F) ;STORE THE PPN POPJ P, ;ALL DONE ;ERRORS ROUTINES TO RETURN VARIOUS LOOKUP/ENTER ERRORS ; ; RTNFNF ;(00) FILE NOT FOUND ; RTNPRT ;(02) PROTECTION ERROR ; RTNAEF ;(04) ALREADY EXISTING FILE ; RTNENC ;(37) EXCEEDED NETWORK CAPACITY ; RTNTNA ;(40) TASK NOT AVAILABLE ; RTNUNN ;(41) UNKNOWN NETWORK NODE DEFINE X(CODE),< ;;SIMPLE MACRO TO MAKE DEFINING THESE EASY RTN'CODE: MOVEI T1,CODE'ERR ;;S.MAC HAS ALL THESE SYMBOLS DEFINED PJRST RTNLEE ;;COMMON CODE TO RETURN THE ERROR > X FNF ;FILE NOT FOUND X PRT ;PROTECTION FAILURE (USER NOT PRIVILEGED) X AEF ;ALREADY EXISTING FILE X ISU ;ILLEGAL SEQUENCE OF UUO'S X ENC ;EXCEEDED NTEWORK CAPACITY X TNA ;TASK NOT AVAILABLE X UNN ;UNKNOWN NETWORK NODE ;RTNLEE ROUTINE TO RETURN A LOOKUP/ENTER ERROR CODE. ;CALL MOVE U,UUO ; MOVEI T1,ERROR NUMBER ; PUSHJ P,RTNLEE ;RETURN CPOPJ ;ALWAYS ; RTNLEE: PUSH P,M ;SAVE THE UUO PUSH P,T1 ;STORE THE ERROR CODE FOR LATER PUSHJ P,GETWDU## ;GET THE FIRST WORD (TO SEE IF EXTENDED L/E) MOVEI M,UUNEXT ;ASSUME THAT THIS IS THE OLD NON-EXTENDED FORM TLNN T1,-1 ; BUT IF IT IS EXTNEDED, MOVEI M,UUXEXT ; THEN CHANGE OUR MIND ADD M,-1(P) ;ADD IN OFFSET OF THE BASE OF THE BLOCK PUSHJ P,GETWDU## ;GET THE "EXTENSION" FIELD HRR T1,(P) ;PUT THE ERROR CODE IN THE RH PUSHJ P,PUTWDU## ;STORE THE ERROR CODE IN THE USERS MEMORY POP P,T1 ;RESTORE THE ERROR CODE POP P,M ;RESTORE THE UUO POPJ P, ;ALL DONE SUBTTL 3.2 NPD MANIPULATION SUBTTL 3.2.1 USER NPD MANIPULATION ;ADCNPD ROUTINE TO ADDRESS CHECK AN NPD ;CALL M := USER ADDRESS OF NPD POINTER (XWD LENGTH,ADDR) ;RETURN NOT AT ALL -- PAGE FAULT, OR ADDRESS ERROR ; CPOPJ NPD TOO SHORT ; CPOPJ1 ALL'S OK ADCNPD: PUSHJ P,GETWDU## ;GET XWD LENGTH,ADDRESS HLRZ T2,T1 ;COPY THE LENGTH CAIGE T2,3 ;IS IT LONG ENOUGH TO HOLD A VALID NPD JRST TK%ILN ;IF NOT, SAY "ILLEGAL NPD" HRRZI T1,(T1) ;CLEAR LH(T1) FOR BRNGE ADDI T2,-1(T1) ;SET T2 := LAST WORD OF NPD PUSHJ P,LRNGE## ;MAKE SURE THAT THE NPD IS INCORE RETSKP ;IF IT IS, GIVE GOOD RETURN ;REDNPD ROUTINE TO READ AN NPD. NPD MUST BE ADDRESSABLE (FAULT = "IME") ;CALL M := USER ADDRESS OF NPD POINTER (XWD LENGTH,ADDR) ;RETURN CPOPJ SOME SORT OF ERROR, ERROR CODE STORED ; CPOPJ1 J := NPD REDNPD: PUSHJ P,SAVE1## ;USE P1 FOR A TEMP PUSHJ P,GETWDU## ;GET "XWD LENGTH,ADDRESS" OF NPD MOVE P1,T1 ;SAVE XWD LENGTH,ADDR EXCTUX ;GET THE LENGTH OF THE NAME-STRING CAILE T1,^D100 ;ALLOW THIS MANY CHARS FOR THE NPD PJRST TK%ILN ;GIVE ILLEGAL NPD ERROR IF BAD LENGTH ADDI T1,<2*5>+4 ;ADD 3 WORDS, ROUND UP IDIVI T1,5 ;CALCULATE NUMBER OF WORDS TO HOLD NPD HLRZ T2,P1 ;GET "DECLARED" LENGTH CAILE T1,(T2) ;MAKE SURE NPD FITS IN RANGE-CHECKED REGION PJRST TK%ILN ;GIVE ILLEGAL NPD ERROR IF IT DOESN'T FIT ADDI T1,1 ;ACCOUNT FOR MONITOR'S "NPDBLK" WORD PUSHJ P,GETNPD## ;ALLOCATE AN NPD, J := ADDRESS PJRST TK%NFC ;ERROR: NO MONITOR FREE CORE HRLZ T1,P1 ;MAKE BLT POINTER: FROM = USER ADDRESS HRRI T1,NPDNOD(J) ; TO = MONITOR NPD ADDRESS HLRZ T2,NPDBLK(J) ;J := LENGTH OF THE NPD ADDI T2,-1(J) ;T2 := ADDRESS OF LAST WORD IN THE NPD EXCTUX ;COPY THE NPD RETSKP ;GIVE GOOD RETURN ;RD2NPD ROUTINE TO READ BOTH NPD'S FOR .TKFEA OR .TKFEP SUB FUNCTIONS ; FREE'S OLD NPD'S FIRST, THEN READS NEW ONES. ;CALL P1, P2, P3, P4 := CHANNEL, SUB=FUNCTION, ADDRESS, LENGTH ;RETURN CPOPJ SOMETHING'S WRONG, ERROR CODE STORED ; CPOPJ1 NPD'S READ. DEVNPD(F) HAS POINTERS TO BOTH RD2NPD: SKIPE DEVNPD(F) ;MAKE SURE THAT THERE AREN'T ANY NPD'S ASSIGNED PUSHJ P,NTDSTP## ;?? NPD'S ALREADY THERE ?? HRRI M,2(P3) ;GET THE ADDRESS OF THE FIRST NPD POINTER PUSHJ P,ADCNPD ;ADDRESS CHECK IT POPJ P, ;ERROR? PASS IT BACK HRRI M,3(P3) ;GET THE ADDRESS OF THE SECOND NPD POINTER PUSHJ P,ADCNPD ;ADDRESS CHECK THIS ONE TOO POPJ P, ;ERROR. PASS IT BACK HRRI M,2(P3) ;GET THE ADDRESS OF THE FIRST NPD POINTER AGAIN PUSHJ P,REDNPD ;GET J := ADDRESS OF NPD IN MONITOR FREE CORE POPJ P, ;SOME RANDOM ERROR. CODE ALREADY STORED HRRM J,DEVNPD(F) ;STORE "LOCAL" NPD HRRI M,3(P3) ;GET ADDRESS OF SECOND NPD POINTER PUSHJ P,REDNPD ;GET J := ADDRESS OF COPY JRST [SETZ J, ;ERROR. FIRST FREE "LOCAL" NPD EXCH J,DEVNPD(F) ;AND CLEAR DEVNPD PJRST GIVNPD##];THEN RETURN. (ERROR CODE ALREADY STORED) HRLM J,DEVNPD(F) ;STORE THE "REMOTE" NPD RETSKP ;WRTNPD ROUTINE TO COPY A MONITOR NPD BACK INTO USER SPACE. ;CALL M := ADDRESS OF USER'S NPD POINTER (XWD LENGTH,ADDR) ; J := ADDRESS OF MONITOR NPD. ;RETURN CPOPJ ;USER'S NPD DESCRIPTOR IS BAD ; CPOPJ1 ;ALL'S OK. NPD RETURNED. WRTNPD: JUMPE J,[SETZ T1, ;IF NO NPD, (PROBABLY SHORT OF CORE) PJRST PUTWDU##] ;WRITE ZERO'S OVER THE USERS NPD POINTER PUSHJ P,SAVE1## ;WE USE P1 AS A TEMP PUSH P,J ;SAVE NPD POINTER (???WDU## CLOBBERS J) PUSHJ P,GETWDU## ;GET THE NPD POINTER (XWD LENGTH,ADDRESS) POP P,J ;GET NPD POINTER BACK HLRZ T2,NPDBLK(J) ;GET THE LENGTH OF THE MONITOR NPD SUBI T2,1 ; LESS ONE (MONITOR'S LENGTH INCLUDES NPDBLK) HLRZ T3,T1 ;GET THE LENGTH OF THE USER'S AREA CAIGE T3,(T2) ;SEE IF THE NPD WILL FIT. PJRST TK%NTS ;ERROR: USER'S NPD IS TOO SHORT MOVNI T2,1(T2) ;GET NEGATIVE COUNT (+1 FOR AOBJP) HRLZ P1,T2 ;SET UP THE LH OF THE AOBJN POINTER HRRI P1,(J) ;SET UP THE RH. HRRI M,(T1) ;GET THE ADDRESS OF THE USER'S NPD AREA PUSH P,J ;SAVE NPD POINTER AGAIN. (PUTWRD...) WRTNP1: AOBJP P1,JPOPJ1## ;COUNT OFF THE NEXT ITEM, EXIT IF DONE MOVE T1,(P1) ;FETCH THE NEXT WORD OF THE NPD PUSHJ P,PUTWDU## ;STORE THE WORD AOJA M,WRTNP1 ;INCREMENT USER'S ADDRESS AND DO NEXT WORD. SUBTTL 3.2.2 MONITOR NPD MANIPULATION ;GETSPN ROUTINE TO BUILD A REMOTE NPD BASED ON CONNECT MSG DATA ;CALL P1, P4 := POINTER TO THE "PID" ; W := POINTER TO NDB OF REMOTE NODE ; PUSHJ P,GETPID ;RETURN CPOPJ ;NO CORE ; CPOPJ1 ;J := POINTER TO A NEWLY CONS-ED NPD ; ; P1, P4 POINT AFTER THE PID GETSPN: MOVE T2,P1 ;COPY THE BYTE POINTER HRREI T1,-1(P4) ;GET THE COUNT -1 GETSP1: ILDB T4,T2 ;GET THE NEXT CHAR FROM THE MESSAGE TRNE T4,200 ;SKIP OUT OF THE LOOP IF NOT EXTENSIBLE SOJGE T1,GETSP1 ;LOOP COUNTING ALL CHARS IN THE PID SUBM P4,T1 ;CALCULATE THE NUMBER OF CHARS IN THE PID PUSH P,T1 ;SAVE THE PID'S LENGTH (IN CHARACTERS) ADDI T1,3*5+4 ;ACCOUNT FOR NPDNOD AND NPDNLN, ROUND UP IDIVI T1,5 ;DIVIDE TO GET WORDS NEEDED TO HOLD PID PUSHJ P,GETNPD## ;ALLOCATE A NEW NPD JRST [PUSHJ P,XSKIP##;SKIP OVER THE PID JRST TPOPJ##] ; FIXUP STACK, RETURN WITH PID NOT COPIED HLRZ T1,NDBNNM(W) ;GET THE NODE NUMBER OF THE REMOTE MOVEM T1,NPDNOD(J) ; AND SAVE IT IN THE NPD POP P,T4 ;GET THE CHARACTER COUNT BACK MOVEM T4,NPDNLN(J) ; AND SAVE THAT TOO MOVE T3,[POINT 7,NPDNAM(J)] ;GET A POINTER TO THE "NAME" PART SUBI P4,(T4) ;MAKE T4 REFLECT THE CHARS WE ARE ABOUT TO READ GETSP2: ILDB T1,P1 ;READ A CHAR FROM THE MESSAGE IDPB T1,T3 ;STORE IT IN THE NEW PID STRING SOJG T4,GETSP2 ;LOOP OVER ALL CHARACTERS RETSKP ;ALL DONE. GIVE GOOD RETURN ;GETFEA ROUTINE TO COPY THE "FEA" FIELDS FROM A MESSAGE TO A DDB ;CALL P1, P4 := MESSAGE POINTERS ; F := DDB POINTER ; PUSHJ P,GETFEA ;RETURN CPOPJ ;ALWAYS ; GETFEA: ;HERE TO COPY FEA ;MML PUSHJ P,XSKIP## ;WE DON'T CARE... ;FEA(DCM) PUSHJ P,XSKIP## ;WE DON'T CARE ABOUT THIS ;FEA(RLN) PUSHJ P,EBI2BI## ;GET THE RECORD LENGTH DPB T1,NETRLN## ;SAVE IT IN THE DDB ;FEA(DVT) PUSHJ P,EBI2BI## ;GET THE DEVICE ATTRIBUTES DPB T1,NETDVT## ;SAVE IT IN THT DDB POPJ P, ;ALL DONE ;GETSTA ROUTINE TO RETURN THE CONNECTION STATE OF A TASK ;CALL F := DDB ADDRESS ;RETURN T1 := CONNECTION STATE GETSTA: LDB T1,NETSLA## ;GET THE SOURCE LINK ADDRESS SKIPE T1 ;IF NONE, THEN ZERO IS THE STATE LDB T1,LATSTA## ;GET THE STATE CAIG T1,LAT.MX ;MAKE SURE THAT IT'S A LEGAL STATE SKIPGE T1 ; AND NOT NEGATIVE PUSHJ P,NTDSTP## ;STATE IS OUT OF RANGE POPJ P, ;RETURN ;LE2NPD ROUTINE TO DUMMY UP THE NPD'S FOR TASKS OPENED VIA THE ; LOOKUP/ENTER MECHANISM. THIS ROUTINE CREATES 2 NPD'S ; (ONE REMOTE AND ONE LOCAL) BASED ON THE TASK'S FILE-NAME ; AND THE JOB'S NAME ;CALL F := DDB POINTER ;RETURN CPOPJ ;IF NO CORE ; CPOPJ1 ;DEVNPD(F) := XWD RMT,LOCAL NPD'S LE2NPD: SKIPE DEVNPD(F) ;MAKE SURE THAT THERE AREN'T ANY NPD'S PUSHJ P,NTDSTP## ;DIE IF THERE ARE... ;FIRST BUILD THE "LOCAL" NPD MOVEI T1,3+5 ;5 WORDS HOLDS ANY "NAME[P,PN]" PUSHJ P,GETNPD## ;GET STORAGE FOR A "LOCAL" NPD POPJ P, ;IF NO CORE, JUST GIVE ERROR RETURN HLRZ T1,NDBNNM+NETNDB## ;GET OUR NODE NUMBER MOVEM T1,NPDNOD(J) ;STORE IT IN THE NPD MOVE P2,[POINT 7,NPDNAM(J)] ;P2 := BYTE POINTER TO STRING AREA SETZ P3, ;COUNT STARTS AT ZERO MOVE T1,.CPJOB## ;GET OUR JOB NUMBER MOVE T1,JBTNAM##(T1) ;GET OUR JOB NAME PUSHJ P,SX2EAS## ;WRITE THE NAME MOVE T1,.CPJOB## ;GET OUR JOB NUMBER AGAIN... MOVE T1,JBTPPN##(T1) ;GET OUR P,PN PUSHJ P,PP2EAS## ;WRITE THE "[P,PN]" MOVEM P3,NPDNLN(J) ;STORE THE STRING'S LENGTH HRRM J,DEVNPD(F) ;STORE THE NPD POINTER IN THE DDB ;NOW BUILD THE "REMOTE" NPD MOVEI T1,3+5 ;GET THE LENGTH OF THE NPD PUSHJ P,GETNPD## ;TRY TO ALLOCATE ONE PJRST GV2NPD ;IF NO CORE, RETURN THE "LOCAL" NPD AND ERR SETOM NPDNOD(J) ;DEFAULT TO A WILD-CARD NODE. MOVE P2,[POINT 7,NPDNAM(J)] ;P2 := BYTE POINTER TO STRING AREA SETZ P3, ;COUNT STARTS AT ZERO MOVE T1,DEVFIL(F) ;GET THE FILE NAME PUSHJ P,SX2EAS## ; AND "OUTPUT" THAT MOVE T1,DEVPPN(F) ;GET THE PPN, AND CAMN T1,[-1] ; IF IT'S -1, THEN JRST [XMTI "*" ; OUTPUT A WILDCARD (*) JRST LE2NP1] ; AND WE'RE DONE WITH THE PPN XMTI "[" ;OUTPUT THE OPEN BRACKET HLRZ T1,DEVPPN(F) ;GET THE PROJECT NUMBER PUSHJ P,OC2EAS## ;OUTPUT THE NUMBER XMTI "," ;OUTPUT THE COMMA HRRZ T1,DEVPPN(F) ;GET THE PROGRAMMER NUMBER PUSHJ P,OC2EAS## ;OUTPUT THAT TOO XMTI "]" ;CLOSE OFF THE PPN LE2NP1: MOVEM P3,NPDNLN(J) ;REMEMBER THE LENGTH HRLM J,DEVNPD(F) ;SAVE THE "REMOTE" NPD RETSKP ;GIVE A GOOD RETURN ;T.X?PN ROUTINE CALLED BY NCSCNT TO SEND THE "?PN" PART OF A CONNECT MESSAGE ;CALL P2, P3 := POINTERS TO CONNECT MESSAGE SO FAR ; F := POINTER TO TASK DDB ;RETURN CPOPJ ;ALWAYS T.XSPN: HRRZ J,DEVNPD(F) ;GET NPD FOR LOCAL TASK NAME PJRST T.XPN ;GO TO COMMON ROUTINE TO SEND "SPN" T.XDPN: HLRZ J,DEVNPD(F) ;GET NPD FOR REMOTE TASK NAME ; PJRST T.XPN ;GO TO COMMON ROUTINE TO SEND "DPN" T.XPN: ;ROUTINE TO SEND A "DPN/SPN" J := NPD. ;?PN(OBJ) XMTI OBJ.TK ;SEND THE TASK OBJECT TYPE ;?PC(PID) SKIPE J ;IF NO NPD, SKIPN T3,NPDNLN(J) ; OR IF NAME IS OF LENGTH "ZERO" JRST J,[XMTI 0 ; SEND A "ZERO" NAME POPJ P,] ; AND RETURN MOVE T4,[POINT 7,NPDNAM(J)] ;GET A POINTER TO THE NAME T.XPN1: ILDB T1,T4 ;GET THE NEXT CHARACTER IORI T1,200 ;SET THE EXTENSIBLE BIT. XMT1 T1 ;SEND THE CHAR SOJG T3,T.XPN1 ;LOOP OVER ALL CHARACTERS PJRST CLRBT8## ;CLEAR THE BIT ON LAST CHAR & RETURN ;T.OK ROUTINE CALLED WHEN A TASK CONNECTION COMPLETED. SETS THE TASK ; AS ONLINE (CONNECTED, LAT-STATE OK) ; T.OK: LDB T1,NETSLA## ;GET THE LAT ADDRESS MOVEI T2,LAT.OK ;THE "OK" STATE DPB T2,LATSTA## ;SET THE STATE OF THE LAT MOVSI S,IOSCON IORB S,DEVIOS(F) ;SET THE "WE ARE CONNECTED" BIT MOVE S,[XWD IOSERR+IOEND,IODERR] ANDCAB S,DEVIOS(F) ;CLEAR THESE ERROR BITS. PUSHJ P,PSIONL## ;GIVE THE USER AN ON-LINE INTERRUPT PUSHJ P,NTDIAV## ;SAY INPUT IS NOW AVAILABLE PJRST NETWAK## ; AND WAKE HIM IF SLEEPING OR HIBERING ;MATCH Routine to perform a pattern match. ;Call P1, P2 := Length, Byte pointer to the "Pattern" ; P3, P4 := Length, Byte pointer to the "Source" ; T4 := Aobjn pointer to block of "free" storage. This ; is used as a Psuedo-stack. This routine uses no ; "real" stack. ;Return CPOPJ ;Source did not match Pattern ; CPOPJ1 ;Source did match Pattern ; ;Note Only T1, T2 and T3 are modified. T4, and P1 - P4 are returned ; unchanged. ; ; The algorithm works in the obvious way. Special "pattern" ; characters are: ; ; ? Match any next source character. ; * Match zero or more next source characters. ; ^V (Control "V") Treat the next "pattern" char as a normal ; char even if it is a "?" or a "*". MATCH: MOVE T3,T4 ;COPY THE PSUEDO-STACK POINTER HLRE T1,T3 ;GET MINUS(LENGTH) OF STACK LEFT CAMLE T1,[EXP -4] ;MAKE SURE WE HAVE AT LEAST 4 WORDS LEFT POPJ P, ;GIVE ERROR RETURN IF NOT ENOUGH STORAGE ;BIG LOOP. ONCE PER STRING MATCH1: DMOVEM P1,0(T3) ;SAVE THE PATTERN DESCRIPTORS DMOVEM P3,2(T3) ;SAVE THE SOURCE DESCRIPTORS ;LOOP. ONCE PER CHARACTER MATCH2: SOJL P1,[SOJL P3,MATCHS ;IF BOTH ARE NULL, RETURN SUCCESS JRST MATCH3];IF SOURCE STRING TOO LONG, BACK-UP ILDB T1,P2 ;GET THE NEXT PATTERN CHARACTER CAIN T1,"*" ;SEE IF IT'S A STAR JRST MATCH4 ; IF IT'S A STAR, GO RECURSE ON REST. CAIN T1,"?" ;SEE IF IT'S A WILD CHARACTER JRST [SOJL P3,MATCHF ; IF SO, COUNT ONE SOURCE CHAR (FAIL IF NONE) IBP P4 ; SKIP OVER NEXT SOURCE CHAR JRST MATCH2] ; AND CONTINUE THE MATCH WITH NEXT CHAR CAIN T1,"V"-100 ;IS IT A ^V? JRST [SOJL P1,MATCHF ; IF IT'S A ^V, COUNT OFF ON PATTERN CHAR ILDB T1,P2 ; GET THE NEXT "QUOTED" CHAR JRST .+1] ; AND CONTINUE WITH THE MATCH SOJL P3,MATCHF ;COUNT OFF SOURCE CHAR. COMPLETE FAIL IF NONE. ILDB T2,P4 ;GET THE NEXT SOURCE CHARACTER XORI T1,(T2) ;COMPARE THE CHARACTERS TRNN T1,177 ; BUT ONLY LOOK AT LOW 7 BITS JRST MATCH2 ;IF THEY MATCH, GO COMPARE NEXT CHARS. ;BACKUP. HERE IF CHARS DON'T MATCH MATCH3: CAMN T3,T4 ;ARE WE AT "LEVEL 0" JRST MATCHF ;IF AT LEVEL 0 THEN THE MATCH FAILED DMOVE P1,0(T3) ;GET BACK ORIGIONAL PATTERH DMOVE P3,2(T3) ;GET BACK SOURCE SOJL P3,MATCHF ;WE ARE PROCESSING A "*". EAT ONE MORE SOURCE IBP P4 ; CHARACTER. DMOVEM P3,2(T3) ;REMEMBER THE UPDATED SOURCE JRST MATCH2 ;NOW TRY THE COMPARE AGAIN ON SHORTER SOURCE ;STAR. RECURSE MATCH4: ADD T3,[XWD 4,4] ;BUMP OUR "PSUEDO-STACK" POINTER HLRE T1,T3 ;GET THE NUMBER OF WORDS LEFT CAMLE T1,[EXP -4] ;MAKE SURE THERE ARE AT LEAST 4 LEFT. JRST MATCHF ;IF NO "STACK", RETURN FAILURE JRST MATCH1 ;GO "RECURSE" MATCHS: AOS (P) ;IF WE SUCCEED, GIVE SKIP RETURN MATCHF: DMOVE P1,0(T4) ;LOAD ORIGIONAL P1 & P2 DMOVE P3,2(T4) ; OLD P3 & P4 POPJ P, ;RETURN SUBTTL 4.0 TSKSER IMPURE STORAGE. $LOW TKMTCH: EXP 0 ;THIS TEMP CONTAINS THE "PATTERN" MATCH ; TEMPORARY PSUEDO-STACK. XLIST ;DON'T LIST LITERALS $LIT LIST TSKEND::END