cdc:nos2.source:opl871:fsework
Table of Contents
FSEWORK
Table Of Contents
- [00006] WORKFILE ACCESS METHOD FOR FULL SCREEN EDITOR.
- [00087] INITFET - INITIALIZE FILE ENVIRONMENT TABLE.
- [00117] BUFAVAIL - FUNCTION TO COMPUTE BUFFER FREE SPACE.
- [00135] BUFUSAGE - FUNCTION TO COMPUTE BUFFER UTILIZATION.
- [00153] LSTUSAGE - COMPUTE UTILIZATION OF READ LIST.
- [00171] LSTAVAIL - COMPUTE SPACE AVAILABLE IN READ LIST.
- [00189] RDWBUF - READ WORDS FROM BUFFER WITH NO I/O.
- [00236] WTWBUF - WRITE WORDS TO BUFFER WTH NO I/O.
- [00280] WAIT - WAIT (RECALL) FOR I/O TO FINISH.
- [00302] DISOWNCACHE - RELEASE CACHE FRAME FROM OWNERSHIP.
- [00331] COUNTCACHE - DETERMINE HOW MANY CACHE FRAMES ARE NOT USED.
- [00353] SEARCHCACHE - DETERMINE BEST CACHEFRAME TO TAKE OVER.
- [00389] ALLOCCACHE - LAY CLAIM TO A CACHE FRAME.
- [00416] RECLAIMCACHE - IDENTIFY CACHE FRAME WRONGLY RELEASED.
- [00457] MOVEIO - INITIATE ANY CIO CALLS AS NEEDED.
- [00612] PAUSEIO - AWAIT AND/OR ENFORCE CIO COMPLETION.
- [00691] SETREAD - ADD DISK ADDRESS TO READ LIST.
- [00878] READPA - READ NEXT DEEPER TREE PATH SECTOR.
- [01060] ALLOC - ASSIGN DISK ADDRESS.
- [01088] DEALLOC - DISCARD DISK SECTOR.
- [01136] SETWRITE - SCHEDULE EXTENSION/ALTERATION OF FILE.
- [01182] TRYWRITE - TRANSMIT SECTOR TO CIRCULAR BUFFER.
- [01260] FLUSHCACHE - UPDATE ALTERED CACHE FRAMES TO DISK.
- [01410] CLOSEOUT - FINISH UPDATE OF DISK.
- [01484] CLEAN - DISCONNECT SECTOR FROM LOWEST TREE LEVEL.
- [01549] CLEANALL - CLEAN ENTIRE TREE STRUCTURE AND DATA SEGEMENTS.
- [01579] BK - BACK UP ONE LINE.
- [01681] FW - ADVANCE ONE LINE.
- [01788] POSR - POSITION TO A RANDOMLY SELECTED LINE.
- [01916] FWD - EXTERNAL INTERFACE FOR FORWARD MOVEMENT.
- [01946] FWD - EXTERNAL INTERFACE FOR BACKWARD MOVEMENT.
- [01976] POS - EXTERNAL INTERFACE FOR RANDOM MOVEMENT.
- [02014] SPLITTOP - SPLIT ROOT SECTOR TO MAKE NEW LEVEL.
- [02099] SPLITAPEND - SPLIT SECTOR JUST AFTER CURRENT CONTENT.
- [02172] SPLITBEFORE - SPLIT SECTOR JUST BEFORE INSERTION POINT.
- [02275] SPLITAFTER - SPLIT SECTOR JUST AFTER INSERTION POINT.
- [02375] CHANGE - APPLY CHANGES TO TREE STRUCTURE.
- [02499] INS - INTERFACE FOR INSERTION OF LINES.
- [02533] REP - INTERFACE FOR REPLACEMENT OF LINES.
- [02566] DEL - INTERFACE FOR DELETION OF LINES.
- [02610] INIT - INITIALIZE MEMORY CELLS FOR WORKIO.
- [02659] RESUMIO - RESUME EDITOR STATUS FROM LEFTOVER WORKFILE.
- [02794] INITIO - FORMAT A NEW WORKFILE.
- [02850] CHECKIO - CHECKPOINT WORKFILE.
Source Code
- FSEWORK.txt
- PROC FSEWORK;
- BEGIN
- #
- *** FSEWORK - WORKFILE ACCESS METHOD FOR FULL SCREEN EDITOR.
- *
- * COPYRIGHT CONTROL DATA SYSTEMS INC. 1992.
- #
- DEF LISTCON #0#;
- CONTROL EJECT; # UNIVERSAL DEFINITIONS #
- *IFCALL SINGLE,COMFSGL
- *IFCALL ONLY,COMFONL
- *IFCALL MULTI,COMFMLT
- *CALL COMFFSE
- CONTROL IFEQ MULTI,1;
- DEF RECALL(AA) #SMFRCL(AA)#;
- DEF DELAY #SMFDLY#;
- XREF PROC SMFRCL;
- XREF PROC SMFDLY;
- CONTROL FI;
- CONTROL IFEQ SINGLE,1;
- XREF PROC RECALL;
- DEF DELAY #RECALL(0)#;
- CONTROL FI;
- XREF # SYSTEM PROCS #
- BEGIN
- PROC WRITE;
- PROC REWRITE;
- PROC RPHR;
- PROC RPHRLS;
- PROC SKIPEI;
- PROC REWIND;
- PROC READ;
- PROC WRITER;
- PROC WRITEW;
- PROC REWRITR;
- CONTROL IFEQ SINGLE,1;
- PROC EVICT;
- CONTROL FI;
- END
- XREF # COMPASS PROCS #
- BEGIN
- PROC MOVEWD;
- PROC EXCHWD;
- FUNC MOVELN;
- FUNC LINESZ;
- END
- XREF
- BEGIN
- *CALL COMFXSB
- END
- XDEF
- BEGIN
- *CALL COMFXWK
- END
- # COMMON DATA #
- CONTROL IFEQ MULTI,1;
- XREF ARRAY RENTSTK [1:MAXREENT]; # SUBROUTINE STACK #
- BEGIN
- ITEM RSTK;
- END
- XREF ITEM RSTKPTR;
- XREF PROC WIOSTAT;
- CONTROL FI;
- *CALL COMFDS1
- *CALL COMFVD2
- *CALL COMFDS2
- PAGE
- PROC INITFET(BUFF,LEN); # INITIALIZE FET #
- BEGIN
- #
- ** INITFET - INITIALIZE FILE ENVIRONMENT TABLE.
- *
- * INITFET IS SPECIALIZED FOR THE WORKFILE MANAGER. THE FET
- * IS ASSUMED TO BE MAPPED BY THE BASED ARRAY "FET". THE
- * LENGTH OF THE FET IS ASSUMED TO BE AT LEAST SEVEN WORDS,
- * AND RANDOM I/O FLAGS WILL BE SET.
- *
- * ENTRY BUFF - THE ARRAY PROVIDED AS A BUFFER.
- * LEN - INTEGER LENGTH OF BUFFER.
- *
- * EXIT FET - INITIALIZED FOR RANDOM I/O.
- * QUARTER - INITIALIZED AS APPROX LEN/4.
- #
- ARRAY BUFF;;
- ITEM LEN;
- QUARTER=(LEN+O"300")/4;
- FETNAM = WORKNAM;
- FETCOD = 0;
- FETDUN = TRUE;
- FETR = TRUE;
- FETW = FALSE;
- FETOUT = LOC(BUFF); FETLIM = LOC(BUFF) + LEN;
- FETL = 2;
- FETFIR = LOC(BUFF); FETIN = LOC(BUFF);
- END
- FUNC BUFAVAIL I;
- BEGIN
- #
- ** BUFAVAIL - FUNCTION TO COMPUTE BUFFER FREE SPACE.
- *
- * BUFAVAIL COMPUTES THE SPACE AVAILABLE IN THE CIRCULAR
- * BUFFER ASSIGNED TO THE FET MAPPED BY THE BASED ARRAY
- * "FET".
- *
- * ENTRY FET - FET.
- *
- * EXIT BUFAVAIL - WORDS OF SPACE STILL AVAILABLE FOR DATA.
- #
- IF FETIN LS FETOUT THEN BUFAVAIL=FETOUT-FETIN;
- ELSE BUFAVAIL=(FETLIM-FETFIR)-(FETIN-FETOUT);
- END
- FUNC BUFUSAGE I;
- BEGIN
- #
- ** BUFUSAGE - FUNCTION TO COMPUTE BUFFER UTILIZATION.
- *
- * BUFUSAGE IS THE COUTERPART TO BUFAVAIL, COMPUTING THE
- * NUMBER OF WORDS ALREADY USED IN THE CIRCULAR BUFFER
- * ASSIGNED TO THE FET MAPPED BY BASED ARRAY "FET".
- *
- * ENTRY FET - FET.
- *
- * EXIT BUFUSAGE - RESULT.
- #
- IF FETIN GQ FETOUT THEN BUFUSAGE=FETIN-FETOUT;
- ELSE BUFUSAGE=(FETLIM-FETFIR)-(FETOUT-FETIN);
- END
- FUNC LSTUSAGE I;
- BEGIN
- #
- ** LSTUSAGE - COMPUTE UTILIZATION OF READ LIST.
- *
- * LSTUSAGE COMPUTES THE NUMBER OF WORDS USED IN THE READ
- * LIST.
- *
- * ENTRY RDIN, RDOUT - BOUNDS FOR PORTION OF LIST USED.
- * LSTSIZE - SIZE OF LIST.
- *
- * EXIT LSTUSAGE - RESULT.
- #
- LSTUSAGE=RDIN-RDOUT;
- IF RDIN LS RDOUT THEN LSTUSAGE=LSTSIZE-1-RDOUT+RDIN;
- END
- FUNC LSTAVAIL I;
- BEGIN
- #
- ** LSTAVAIL - COMPUTE SPACE AVAILABLE IN READ LIST.
- *
- * LSTAVAIL COMPUTES THE NUMBER OF WORDS AVAILABLE FOR USE
- * IN THE RANDOM READ LIST.
- *
- * ENTRY - RDIN, RDOUT, LSTSIZE - CONTROL READ LIST.
- *
- * EXIT LSTAVAIL - RESULT.
- *
- * CALLS LSTUSAGE.
- #
- LSTAVAIL=LSTSIZE-1-LSTUSAGE;
- END
- PROC RDWBUF(LENGTH);
- BEGIN
- #
- ** RDWBUF - READ WORDS FROM BUFFER WITH NO I/O.
- *
- * RDWBUF FUNCTIONS AS A SPECIALIZED READW MACRO. A STANDARD
- * FET IS ASSUMED AND THE DATA TRANSFER WORKING BUFFER IS
- * ASSUMED TO BE MAPPED BY A STANDARD BASED ARRAY. MOST
- * IMPORTANT, THIS ROUTINE IS GUARANTEED TO NEVER CALL CIO.
- * THE CALLER IS RESPONSIBLE TO ASSURE THAT THE CIRCULAR
- * BUFFER HAS ENOUGH DATA TO SATISFY THE REQUEST.
- *
- * ENTRY LENGTH - AMMOUNT OF DATA NEEDED.
- * FET - FET AND CIRCULAR BUFFER HAVE ENOUGH DATA.
- * TOO - MAPPED TO USER'S WORKING BUFFER.
- *
- * EXIT FET - INDICATES DATA TRANSFERRED.
- * TOO - DATA IS TRANSFERRED.
- *
- * CALLS MOVEWD, TRAGIC, BUFUSAGE.
- *
- * USES FROM.
- #
- ITEM LENGTH, X1;
- IF BUFUSAGE LS LENGTH OR LENGTH LS 0 THEN
- BEGIN
- TRAGIC(" WORKFILE BUFFER EMPTY ON READ.$");
- END
- P<FROM>=FETOUT;
- IF FETIN GR FETOUT OR FETLIM-FETOUT GR LENGTH THEN
- BEGIN
- MOVEWD(LENGTH,FROM,TOO);
- FETOUT=FETOUT+LENGTH;
- END
- ELSE
- BEGIN
- X1=FETLIM-FETOUT;
- MOVEWD(X1,FROM,TOO);
- P<TOO>=LOC(TOO)+X1;
- X1=LENGTH-X1;
- P<FROM>=FETFIR;
- MOVEWD(X1,FROM,TOO);
- FETOUT=FETFIR+X1;
- END
- END
- PROC WTWBUF(LENGTH);
- BEGIN
- #
- ** WTWBUF - WRITE WORDS TO BUFFER WTH NO I/O.
- *
- * WTWBUF PERFORMS THE ROLE OF THE WRITEW MACRO, BUT IS
- * SPECIALIZED TO USE AN ASSUMED FET AND WORKING BUFFER, AND
- * IS GUARANTEED TO NEVER PERFORM ANY CIO CALLS. THE CALLER
- * IS RESPONSIBLE TO ASSURE THE CIRCULAR BUFFER HAS ROOM TO
- * ACCEPT THE DATA.
- *
- * ENTRY LENGTH - NUMBER OF WORDS.
- * FET - THE CIRCULAR BUFFER HAS ROOM.
- * FROM - MAPPED ONTO WORKING BUFFER.
- *
- * EXIT FET - THE CIRCULAR BUFFER HAS DATA.
- *
- * CALLS BUFAVAIL, TRAGIC, MOVEWD.
- *
- * USES TOO.
- #
- ITEM LENGTH, X1;
- IF BUFAVAIL LS LENGTH OR LENGTH LS 0 THEN
- BEGIN
- TRAGIC(" WORKFILE BUFFER FULL ON WRITE.$");
- END
- P<TOO>=FETIN;
- IF FETOUT GR FETIN OR FETLIM-FETIN GR LENGTH THEN
- BEGIN
- MOVEWD(LENGTH,FROM,TOO);
- FETIN=FETIN+LENGTH;
- END
- ELSE
- BEGIN
- X1=FETLIM-FETIN;
- MOVEWD(X1,FROM,TOO);
- P<FROM>=LOC(FROM)+X1;
- X1=LENGTH-X1;
- P<TOO>=FETFIR;
- MOVEWD(X1,FROM,TOO);
- FETIN=FETFIR+X1;
- END
- END
- PROC WAIT;
- IOBEGIN(WAIT)
- #
- ** WAIT - WAIT (RECALL) FOR I/O TO FINISH.
- *
- * WAIT DELAYS THIS TASK UNTIL THE FET IS FOUND TO INDICATE
- * COMPLETION OF A PREVIOUS I/O OPERATION. WAIT IS A NO-OP
- * IF THE FET ALREADY INDICATES COMPLETION.
- *
- * ENTRY FETDUN - SHOWS WHETHER DELAYS REALLY NEEDED.
- *
- * EXIT FETDUN - TRUE.
- *
- * CALLS RECALL.
- #
- IF NOT FETDUN THEN
- BEGIN
- RECALL(FET);
- END
- IOEND
- PROC DISOWNCACHE(PARM);
- BEGIN
- #
- ** DISOWNCACHE - RELEASE CACHE FRAME FROM OWNERSHIP.
- *
- * DISOWNCACHE IS USED TO RELEASE A PAGE FROM OWNERSHIP BY
- * A LEVEL OF THE TREE STRUCTURE. RELEASE OF A PAGE MAKES
- * IT ELIGIBLE TO BE FLUSHED OUT OF MEMORY (AND POSSIBLY
- * REWRITTEN BACK TO DISK) ANYTIME THE FLUSHCACHE ROUTINE
- * IS NEEDED. DISOWNCACHE ALSO SETS THE AGE FOR THE PAGE
- * SO THAT FLUSHCACHE CAN DO ANY REWRITES IN THE MANDATORY
- * ORDER OF RELEASE. THE GLOBAL AGE COUNTER IS INCREMENTED.
- *
- * ENTRY PARM - TREE LEVEL.
- * CACHEOWNED[PARM] - TRUE FOR NON-TRIVIAL OPERATON.
- * AGECOUNT - HIGHEST AGE YET ASSIGNED TO ANY PAGE.
- *
- * EXIT AGECOUNT - INCREMENTED.
- * CACHEOWNED[PARM] - FALSE.
- * CACHEAGE[PARM] - SETUP.
- #
- ITEM PARM;
- IF PARM LS 0 OR NOT CACHEOWNED[PARM] THEN RETURN;
- CACHEOWNED[PARM]=FALSE;
- AGECOUNT=AGECOUNT+1;
- CACHEAGE[PARM]=AGECOUNT;
- END # OF DISOWNCACHE #
- FUNC COUNTCACHE;
- BEGIN
- #
- ** COUNTCACHE - DETERMINE HOW MANY CACHE FRAMES ARE NOT USED.
- *
- * COUNTCACHE TELLS THE CALLER HOW MANY CACHE FRAMES ARE
- * NEITHER OWNED BY ANY TREE LEVEL NOR CONTAIN DATA, WHICH
- * HAS BEEN ALTERED IN THE CACHE BUT NOT YET ON DISK.
- *
- * ENTRY CACHEOWNED[ALL] - SETUP.
- * CACHEDIRTY[ALL] - SETUP.
- *
- * EXIT COUNTCACHE - RESULT.
- #
- ITEM I, J;
- J=0;
- FOR I=0 STEP 1 UNTIL MAXCACHE DO IF NOT
- (CACHEDIRTY[I] OR CACHEOWNED[I]) THEN J=J+1;
- COUNTCACHE=J;
- END # OF COUNTCACHE #
- PROC SEARCHCACHE(M);
- BEGIN
- #
- ** SEARCHCACHE - DETERMINE BEST CACHEFRAME TO TAKE OVER.
- *
- * SEARCHCACHE TESTS ALL CACHE FRAMES FOR THOSE WHICH ARE
- * AVAILABLE TO BE CLAIMED AND USED FOR DIFFERENT DATA THAN
- * PRESENTLY IN MEMORY. THE OLDEST AVAILABLE FRAME IS
- * CONSIDERED THE BEST CANDIDATE FOR RECYCLE. A FRAME
- * IS AVAILABLE IF IT IS NEITHER CURRENTLY OWNED BY ANY TREE
- * LEVEL NOR CONTAINS DATA ALTERED IN MEMORY BUT NOT ON DISK.
- *
- * ENTRY CACHEOWNED[ALL] - SETUP.
- * CACHEDIRTY[ALL] - SETUP.
- * CACHEAGE[ALL] - SETUP FOR UNOWNED, UNDIRTY FRAMES.
- *
- * EXIT M - CHOSEN FRAME.
- *
- * CALLS TRAGIC.
- #
- ITEM K,L,M;
- M=-1;
- K=999999999;
- FOR L=0 STEP 1 UNTIL MAXCACHE DO
- BEGIN
- IF CACHEAGE[L] LS K AND
- NOT (CACHEDIRTY[L] OR CACHEOWNED[L]) THEN
- BEGIN # SEARCH OLDEST AVAIL PAGE #
- M=L;
- K=CACHEAGE[L];
- END
- END
- IF M LS 0 THEN TRAGIC(" ALL WORKFILE BUFFERS ARE FULL.$");
- END # OF SEARCHCACHE #
- PROC ALLOCCACHE;
- BEGIN
- #
- ** ALLOCCACHE - LAY CLAIM TO A CACHE FRAME.
- *
- * ALLOCCACHE IS CALLED TO CLAIM A FRAME OF MEMORY IN THE
- * DISK CACHE, AND ATTACH IT TO A PARTICULAR TREE LEVEL.
- * THE DISK ADDRESS OF THE DISK DATA IS SAVED IN THE HEADER
- * WORD OF THE CACHE FRAME, SO IT CAN BE MATCHED FOR
- * PURPOSES OF AVOIDING DISK READS.
- *
- * ENTRY PL - CURRENT TREE LEVEL.
- * PADA[PL] - DISK ADDRESS ASSIGNED FOR REAL DATA.
- *
- * EXIT PACACHE[PL] - WHICH CACHE FRAME WAS SELECTED.
- * BFDA[PL] - DISK ADDRESS IS STORED IN CACHE FRAME.
- *
- * CALLS SEARCHCACHE.
- #
- ITEM TMP1;
- SEARCHCACHE(TMP1);
- PACACHE[PL]=TMP1;
- CACHEOWNED[TMP1]=TRUE;
- BFDA[TMP1]=PADA[PL];
- END # OF ALLOCCACHE #
- PROC RECLAIMCACHE;
- BEGIN
- #
- ** RECLAIMCACHE - IDENTIFY CACHE FRAME WRONGLY RELEASED.
- *
- * RECLAIMCACHE IS USED TO MATCH A TREE LEVEL TO A CACHE
- * FRAME WHICH CONTAINS THE VIRTUAL DISK SECTOR FOR THE
- * TREE LEVEL, AND REESTABLISH OWNERSHIP. THIS IS DONE
- * BECAUSE THERE ARE SITUATIONS WHERE A PAGE MUST BE
- * TEMPORARILY RELEASED FROM OWNERSHIP SO IT CAN BE WRITTEN
- * TO DISK, BUT FORFEITURE OF OWNERSHIP IS NOT INTENDED
- * FOR ANY OTHER REASON. RECLAIMCACHE CAN BE CALLED AFTER
- * A SEQUENCE OF DISOWNCACHE AND FLUSHCACHE, AND THE TREE
- * LEVELS ARE THEN AS THEY WERE BUT DATA ALTERATIONS ARE
- * UP TO DATE ON DISK. REMEMBER THAT THE ORDER IN WHICH PAGES
- * CAN BE UPDATED TO DISK DEPENDS ON THE TREE HIERARCHY, SO
- * IT IS SOMETIMES NECESSARY TO GO THRU THIS SEQUENCE WITH ONE
- * TREE LEVEL IN ORDER TO ACHIEVE THE ACTUAL PURPOSE OF
- * WRITING A DIFFERENCE TREE LEVEL TO DISK.
- *
- * ENTRY PL - CURRENT TREE LEVEL.
- * PALVL - DEEPEST VALID TREE LEVEL.
- * CACHEOWNED[ALL], PACACHE[ALL], BFDA[ALL] - SETUP.
- *
- * EXIT CACHEOWNED[PL THRU PALVL] - TRUE.
- *
- * CALLS TRAGIC.
- *
- * USES TPL.
- #
- FOR TPL=PL STEP 1 UNTIL PALVL DO
- BEGIN
- IF CACHEOWNED[PACACHE[TPL]] THEN TEST TPL;
- IF BFDA[PACACHE[TPL]] NQ PADA[TPL] THEN
- BEGIN
- TRAGIC(" WORKFILE BUFFER CONTAINS WRONG TEXT.$");
- END
- CACHEOWNED[PACACHE[TPL]]=TRUE;
- END
- END # OF RECLAIMCACHE #
- PAGE
- PROC MOVEIO;
- BEGIN
- #
- ** MOVEIO - INITIATE ANY CIO CALLS AS NEEDED.
- *
- * MOVEIO IS CALLED ANY TIME CIO CALLS ARE KNOWN TO BE
- * NECESSARY, AND CAN ALSO BE CALLED ANY TIME CIO CALLS MIGHT
- * BE DESIRABLE. MOVEIO BECOMES A NO-OP IF A CIO CALL IS
- * ALREADY IN PROGRESS, OR IF NO CIO CALL IS NEEDED. THE
- * CALLER IS RESPONSIBLE TO PREPARE THE FET AND CIRCULAR
- * BUFFER IN ALL WAYS EXCEPT THE CHOICE OF CIO FUNCTION CODE.
- *
- * WRITES ARE INITIATED WHEN THE IOWRITE FLAG HAS BEEN
- * PREPARED TO INDICATE THAT WRITES ARE NEEDED, THE FET IS NOT
- * PREVIOUSLY INTERLOCKED, AND THE CIRCULAR BUFFER CONTAINS
- * SOME DATA. READS ARE INITIATED WHEN THE IOREAD FLAG HAS
- * BEEN PREPARED TO INDICATE THAT READS ARE NEEDED, THE FET IS
- * NOT PREVIOUSLY INTERLOCKED, AND THE RDIN/RDOUT POINTERS
- * INDICATE THERE IS A NON-TRIVIAL LIST OF PRUS STILL AWAITING
- * READS.
- *
- * MOVEIO ALSO PERFORMS THE FUNCTION OF RECOGNIZING THAT ALL
- * DESIRED I/O HAS BEEN COMPLETED, SUCH AS ALL WRITEABLE DATA
- * REMOVED FROM CIRCULAR BUFFER OR ALL READABLE PRUS REMOVED
- * FROM READ LIST. UNDER THESE CONDITIONS, MOVEIO CLEARS THE
- * IOXXXX FLAGS SO THAT NO FURTHER DESIRE FOR CIO CALLS WILL
- * BE INDICATED, UNTIL AND UNLESS SOMEONE TURNS THE FLAGS ON
- * AGAIN.
- *
- * IN THE CASES WHERE THE CIRCULAR BUFFER CONTAINS DATA TO BE
- * WRITTEN, THE ACTUAL CIO FUNCTION CODE IS CHOSEN FROM FOUR
- * POSSIBILITIES BASED ON EXTENSION/ALTERATION OF THE FILE AND
- * NEED OR NON-NEED FOR END-OF-RECORD TO BE WRITTEN. WHEN THE
- * DISK IS TO BE READ, THE FUNCTION CODE IS ALWAYS "RPHRLS",
- * AKA "READ PRUS RANDOMLY BY LIST".
- *
- * NOTE THAT MOVEIO NEVER WAITS FOR ANY CIO TO COMPLETE, THUS
- * MOVEIO IS NOT A REENTRANT ROUTINE.
- *
- * ENTRY FETDUN - WHETHER ANY PREVIOUS I/O IS DONE.
- * IOACT - WHETHER I/O SHOULD BE DONE SOMETIME SOON.
- * IOWRITE - WHETHER I/O NEEDED IS A WRITE.
- * IOREAD - WHETHER I/O NEEDED IS A READ.
- * IOAPEND - WHETHER WRITE IS TO EXTEND FILE OR ALTER.
- * IOWRTEOR - WHETHER WRITE IS TO PRODUCE EOR.
- * FETIN, FETOUT - INDICATE WHETHER UNWRITTEN DATA IS
- * STILL IN THE BUFFER.
- * RDIN, RDOUT - INDICATE WHETHER THERE ARE PRUS
- * IDENTIFIED IN READ LIST AS DESIRABLE TO READ,
- * BUT NOT YET READ IN.
- * FETLA, FETLAW - CURRENT POSITION IN READ LIST.
- * RDLIST[ALL] - SETUP.
- * CIOCOUNT - ACCOUNTING ACCUMULATOR.
- * MAXDA, LASTDA - USED TO DETERMINE VALIDITY OF
- * WRITE PARAMETERS, WHEN CONSISTENCY CHECKING
- * IS ENABLED IN THE SOURCE CODE.
- * FETCRI - USED WITH MAXDA AND LASTDA FOR VALIDITY.
- *
- * EXIT FETDUN - FALSE IF A CIO CALL STARTED UP.
- * CIOCOUNT - INCREMENTED IF CIO CALLED.
- * IOACT, IOREAD, IOWRITE, IOAPEND - CLEARED IF AND
- * ONLY IF ALL MOVEIO DETERMINES THAT ALL
- * PREVIOUSLY REQUESTED I/O HAS COMPLETED.
- *
- * CALLS WRITE, REWRITE, WRITER, REWRITR, RPHRLS, TRAGIC.
- #
- ITEM I;
- SWITCH CALLWRITE WRTFUNC,RWRTFUNC,WRTRFUNC,RWRTRFUNC;
- IF IOACT AND FETDUN THEN
- BEGIN
- IF IOWRITE AND FETIN NQ FETOUT THEN # WRITE NOT DONE #
- BEGIN
- CIOCOUNT = CIOCOUNT + 1;
- I=1;
- IF IOAPEND THEN I=0;
- IF IOWRTEOR THEN I=I+2;
- IOWRTEOR=FALSE;
- GOTO CALLWRITE[I];
- WRTFUNC:
- WRITE(FET,0);
- RETURN;
- RWRTFUNC:
- FETEP = TRUE; # SET ERROR PROCESSING BIT #
- REWRITE(FET,0);
- FETEP = FALSE; # CLEAR ERROR PROCESSING BIT #
- IF FETAT EQ O"22" THEN
- BEGIN # IF FATAL ERROR #
- TRAGIC(" WORKFILE BUFFER EMPTY ON REWRITE.$");
- END
- RETURN;
- WRTRFUNC:
- WRITER(FET,0);
- RETURN;
- RWRTRFUNC:
- FETEP = TRUE; # SET ERROR PROCESSING BIT #
- REWRITR(FET,0);
- FETEP = FALSE; # CLEAR ERROR PROCESSING BIT #
- IF FETAT EQ O"22" THEN
- BEGIN # IF FATAL ERROR #
- TRAGIC(" WORKFILE BUFFER EMPTY ON REWRITER. $");
- END
- RETURN;
- END
- ELSE IF IOREAD AND RDIN NQ RDOUT THEN # READ NOT DONE #
- BEGIN
- IF FETLA EQ LOC(RDLIST[RDLIM])
- THEN FETLAW = LOC(RDLIST[0]);
- IF FETLA NQ LOC(RDLIST[RDIN]) THEN
- BEGIN
- CIOCOUNT = CIOCOUNT + 1;
- RPHRLS(FET,0);
- END
- END
- ELSE # READ AND WRITE DONE #
- BEGIN
- CONTROL IFGQ PARANOIA,5;
- IF IOWRITE THEN # CHECK WRITE CRI #
- BEGIN
- IF IOAPEND THEN
- BEGIN
- IF FETCRI NQ MAXDA+1 THEN
- BEGIN
- TRAGIC(" FILE SIZE INCORRECT.$");
- END
- END
- ELSE
- BEGIN
- IF FETCRI NQ LASTDA+1 THEN
- BEGIN
- TRAGIC(" RANDOM ADDRESS INCORRECT.$");
- END
- END
- END
- CONTROL FI;
- IOACT = FALSE;
- IOWRITE = FALSE; IOAPEND = FALSE;
- IOREAD = FALSE;
- END
- END
- END
- PAGE
- PROC PAUSEIO;
- IOBEGIN(PAUSEIO)
- #
- ** PAUSEIO - AWAIT AND/OR ENFORCE CIO COMPLETION.
- *
- * PAUSEIO IS CALLED FOR ONE OF THREE REASONS: (1) THE CALLER
- * HAS STARTED SOME I/O VIA MOVEIO AND NEEDS TO WAIT FOR IT TO
- * FINISH, OR (2) THE CALLER NEEDS SOME OLD I/O TO FINISH SO
- * THAT THE FET CAN BE USED TO INITIATE NEW DESIRED I/O, OR
- * (3) THE CALLER NEEDS SOME OLD I/O TO FINISH, TO FREE THE
- * CIRCULAR BUFFER AND READ LIST SO THOSE MEMORY RESOURCES CAN
- * BE MANAGED AND POSSIBLY RE-ASSIGNED.
- *
- * PAUSEIO THEREFORE GUARANTEES THAT ANY WRITEABLE DATA IN THE
- * CIRCULAR BUFFER REALLY GETS WRITTEN, AND THAT ANY INITIATED
- * READS ARE FINISHED WITH THE DATA DISCARDED AND THE CIRCULAR
- * BUFFER EMPTY. PAUSEIO IS ALLOWED TO HANDLE READS WHICH
- * HAVE BEEN REQUESTED BUT NOT YET INITIATED BY SIMPLE
- * CANCELLATION. THUS, PAUSEIO IS MEANINGFUL TO THE TYPE 1
- * CALLER ONLY FOR THE WRITE DIRECTION - THE READ DIRECTION IS
- * A THROWAWAY WHILE THE WRITE DIRECTION HAS ASSURANCE OF
- * COMPLETION.
- *
- * SINCE THE TYPE 3 CALLER OFTEN DOES NOT KNOW HOW (OR IS NOT
- * ALLOWED) TO DETERMINE IF THE MEMORY RESOURCES ARE ALREADY
- * AVAILABLE FOR REASSIGNMENT, PAUSEIO CAN BE CALLED CASUALLY,
- * AND WILL NO-OP ITSELF IF THE DESIRED CONDITIONS ARE ALREADY
- * TRUE.
- *
- * PAUSEIO ALSO ZEROES OUT FETCHGUIDE. THIS IS USED TO CONTROL
- * THE QUANTITY OF DATA PREFETCHED AS A FUNCTION OF HOW MUCH
- * SUCCESS WE HAVE HAD IN UTILIZING PREFETCHED DATA IN RECENT
- * HISTORY. A PAUSEIO CALL IS REGARDED AS AN ADMISSION THAT
- * ANY CURRENT PREFETCHING HAS LOST ALL RELEVANCE.
- *
- * ENTRY IOREAD - WHETHER WE WERE PREVIOUSLY TRYING TO READ
- * SOMETHING WHICH MUST NOW BE THROWN AWAY.
- * IOWRITE - WHETHER WE HAD PREVIOUSLY REQUESTED THAT
- * SOMETHING BE WRITTEN, WHICH MUST NOW BE BROUGHT
- * TO FASTEST POSSIBLE COMPLETION.
- * RDIN, RDOUT - BRACKET ACTIVE SEGMENT OF READ LIST.
- * FETIN, FETOUT - BRACKET CIRCULAR BUFFER DATA.
- *
- * EXIT IOREAD, IOWRITE, IOACT - GUARANTEED FALSE.
- * FET - CIRCULAR BUFFER GUARANTEED EMPTY.
- * RDLIST[ALL], RDIN, RDOUT - GUARANTEED EMPTY.
- * FETCHGUIDE - ZEROED.
- *
- * CALLS WAIT, MOVEIO.
- #
- ITEM I, J, K;
- FETCHGUIDE=0;
- IF IOREAD THEN
- BEGIN
- WAIT; # FOR ACTIVE TRANSFER TO FINISH #
- FOR I = RDIN WHILE I NQ RDOUT DO # CLEAN OUT READLIST #
- BEGIN
- I = I - 1;
- IF I LS 0 THEN I = RDLIM - 1;
- RDLIST[I] = 0;
- END
- FETOUT = FETIN; # ABANDON CIRCULAR BUFFER CONTENT #
- IOACT = FALSE;
- IOREAD = FALSE;
- END
- ELSE IF IOWRITE THEN
- BEGIN
- WHYLE IOWRITE DO
- BEGIN
- MOVEIO;
- WAIT;
- END
- END
- IOEND
- PAGE
- PROC SETREAD((DA));
- BEGIN
- #
- ** SETREAD - ADD DISK ADDRESS TO READ LIST.
- *
- * SETREAD PERFORMS FET INITIALIZATION AS NEEDED, TO ASSURE
- * THAT THE BUFFER AND FET ARE TURNED AROUND TO THE INPUT
- * DIRECTION, AND APPENDS THE SPECIFIED DISK ADDRESS ONTO THE
- * READ LIST. THE CALLER IS RESPONSIBLE TO ASSURE THAT
- * SETREAD WILL NOT ENCOUNTER A FULL READ LIST. THE CALLER IS
- * ALLOWED TO CALL SETREAD FOR AN ADDRESS ALREADY LISTED, IN
- * WHICH CASE SETREAD NO-OPS ITSELF. THE USER IS REQUIRED TO
- * PROVIDE AN IN-BOUNDS DISK ADDRESS, AND TO HAVE USED PAUSEIO
- * TO COMPLETE ANY PREVIOUS OUTPUT ACTIVITIES.
- *
- * ENTRY DA - SECTOR NUMBER FOR DESIRED PRU.
- * IOREAD - WHETHER FET ALREADY INITIALIZED FOR INPUT.
- * IOWRITE, MAXDA - WHEN CONSISTENCY CHECKING IS ENABLED,
- * THESE ARE USED TO VERIFY VALIDITY.
- * RDIN, RDOUT - BRACKET ACTIVE SEGMENT OF READ LIST.
- * RDLIST[ALL] - SETUP FOR EXISTING DISK ADDRESSES
- * AND WITH ZEROES IN EXCESS LIST AREAS.
- *
- * EXIT IOREAD, IOACT - TRUE.
- * FET AND CIRCULAR BUFFER - VALID FOR MOVEIO CALL.
- * RDIN, RDOUT - UPDATED FOR ENLARGED READ LIST.
- * RDLIST[NEW RDIN-1] - DISK ADDRESS STORED HERE.
- *
- * CALLS TRAGIC, INITFET.
- #
- ITEM DA;
- ITEM P;
- CONTROL IFGQ PARANOIA,5;
- IF DA LQ 0 OR DA GR MAXDA THEN
- BEGIN
- TRAGIC(" OUT OF BOUNDS PRU ADDRESS ON READ (1).$");
- END
- IF IOWRITE THEN TRAGIC(" WORKFILE BUFFER FULL ON READ.$");
- CONTROL FI;
- IF NOT IOREAD THEN
- BEGIN
- INITFET(DISK,DSKSIZ);
- RDIN = 0;
- RDOUT = 0;
- FETLAW = LOC(RDLIST[0]);
- IOACT = TRUE;
- IOREAD = TRUE;
- END
- FOR P = RDOUT WHILE RDLIST[P] NQ DA DO
- BEGIN
- IF P EQ RDIN THEN
- BEGIN
- RDLIST[RDIN] = DA;
- RDIN = RDIN + 1;
- IF RDIN EQ RDLIM THEN RDIN = 0;
- CONTROL IFGQ PARANOIA,5;
- IF RDIN EQ RDOUT THEN TRAGIC(" RPHRLS LIST BUFFER IS FULL.$");
- CONTROL FI;
- END
- ELSE
- BEGIN
- P = P + 1;
- IF P EQ RDLIM THEN P = 0;
- END
- END
- END
- PAGE
- PROC PREFETCH((DD));
- BEGIN
- #
- ** ARRANGE READ LIST FOR SEVERAL PREFETCHES.
- *
- * PREFETCH SHOULD BE CALLED ONCE PER SECTOR PROCESSED, BY
- * THOSE PROCESSES WHICH ACT UPON POTENTIALLY LARGE SERIES OF
- * DISK SECTORS IN EITHER THE FORWARD OR BACKWARD LOGICAL
- * ORDER OF TEXT IN THE FILE. THE LOGICAL ORDER CAN BE QUITE
- * DIFFERENT FROM THE PHYSICAL ORDER DUE TO THE TREE LINKAGES.
- *
- * PREFETCH DETERMINES SEVERAL DISK ADDRESSES WHOSE NEED IS
- * ANTICIPATED ON BEHALF OF THE CALLER, AND USES SETREAD TO
- * ARRANGE THAT SUCH SECTORS CAN BE READ IN THE LOGICAL ORDER.
- * IT IS THE CALLING PROCESSES RESPONSIBILITY TO OCCASIONALLY
- * CALL MOVEIO FOR ACTUAL INITIATION OF CIO.
- *
- * TO MINIMIZE OVERHEAD, PREFETCH CHOOSES A DEPTH OF
- * PREFETCHING BASED ON APPARENT RECENT SUCCESS IN UTILIZING
- * PREFETCHED DATA, AND SUCCESSIVELY UPDATES THE DEPTH OF
- * PREFETCH. THIS DEPTH INDICATOR MAY BE CLEARED BY PAUSEIO
- * IN RECOGNITION OF THE ABANDONMENT OF A READ, OR BY THE
- * CALLER WHEN A LOGICAL BREAK IN SEQUENTIAL PROCESSING IS
- * KNOWN TO OCCUR.
- *
- * TO MINIMIZE OVERHEAD, PREFETCH ATTEMPTS TO PRODUCE EITHER
- * ZERO OR SEVERAL NEW ENTRIES IN THE READ LIST, AND ATTEMPTS
- * TO NO-OP ITSELF WHEN IT IS RECOGNIZED THAT ONLY ONE OR A
- * FEW ENTRIES COULD BE PRODUCED. PREFETCH MUST KEEP THE
- * DEPTH OF PREFETCHING WITHIN THE LEGAL BOUNDS OF THE SETREAD
- * ROUTINE.
- *
- * THE DEPTH OF PREFETCHING IS LIMITED TO THE SMALLEST OF THE
- * FOLLOWING FACTORS - (1) THE FETCHGUIDE QUANTITY, WHICH
- * REPRESENTS RECENT SUCCESS, (2) THE LEGAL LIMITS IMPOSED BY
- * SETREAD, AND (3) ONE AND A HALF TIMES THE SIZE OF THE
- * CIRCULAR BUFFER. PREFETCHING IS SET UP ONLY WHEN THE
- * EXISTING QUEUE IS LESS THAN HALF THE DESIRED DEPTH. FOR
- * LARGER QUEUES, IT IS ANTICIPATED THE QUEUE WILL BE SHRUNK
- * BACK DOWN AT SOME FUTURE CALL TO PREFETCH, AT WHICH TIME
- * A LARGE BATCH OF QUEUE ENTIRES CAN BE PRODUCED.
- *
- * ONCE PREFETCH DECIDES TO SET UP A BATCH OF READ LIST QUEUE
- * ENTRIES, IT IDENTIFIES THE SECTORS TO BE READ AS ALL DATA
- * (BOTTOM) LEVEL PRUS, POINTED TO BY THE NEXT-TO-BOTTOM
- * DIRECTORY, LOGICALLY ADJACENT TO THE CURRENT DATA SECTOR IN
- * THE SPECIFIED DIRECTION. PREFETCH ALSO CAN QUEUE THE NEXT
- * LOGICALLY ADJACENT NEXT-TO-BOTTOM DIRECTORY, BY LOOKING
- * ANOTHER LEVEL TOWARDS THE ROOT OF THE TREE.
- *
- * ENTRY FETCHGUIDE - CURRENT GUIDELINE FOR DEPTH.
- * RDIN, RDOUT - DESCRIBE CURRENT READ LIST.
- * DSKSIZ - CIRCULAR BUFFER SIZE.
- * PALVL - DEEPEST TREE LEVEL CURRENTLY VALID.
- * PACACHE[ALL] - CACHE FRAMES AT EACH TREE LEVEL.
- * BFPRU[ALL] - DISK ADDRESSES FOR EACH FRAME.
- * PAFINAL[ALL] - LAST WORDS IN EACH SECTOR OF TREE.
- * IOWRITE - WHETHER FET INTERLOCKED FOR OUTPUT.
- *
- * EXIT RDLIST[ALL], RDIN, RDOUT - UPDATED.
- * FETCHGUIDE - INCREMENTED UNLESS DIRECTORY INCLUDED.
- *
- * CALLS LSTAVAIL, LSTUSAGE, MIN, MAX, SETREAD.
- *
- * USES P<PRU> WITH RESTORATION.
- #
- ITEM DD,N;
- ITEM DSTOP;
- ITEM DONE B;
- ITEM TMPPRU;
- ITEM TMPPL,TMPD;
- ITEM I;
- IF FETCHGUIDE LS 0 OR IOWRITE THEN RETURN;
- FETCHGUIDE=FETCHGUIDE+2;
- N=LSTAVAIL;
- N=MIN(N-3,3*DSKSIZ/O"200");
- N=MIN(N,FETCHGUIDE);
- IF LSTUSAGE LQ N/2 THEN
- BEGIN
- TMPPRU = P<PRU>;
- DONE = FALSE;
- FOR TMPPL = PALVL-1 STEP -1 WHILE TMPPL GQ 0 AND NOT DONE DO
- BEGIN
- TMPD = PADISP[TMPPL] + DD;
- P<PRU> = LOC(BFPRU[PACACHE[TMPPL]]);
- IF DD GR 0 THEN DSTOP = MIN(PAFINAL[TMPPL]+1,TMPD+N);
- ELSE DSTOP = MAX(0,TMPD-N);
- IF DSTOP EQ TMPD+N*DD THEN DONE = TRUE;
- ELSE FETCHGUIDE=-1;
- N=1;
- FOR TMPD = TMPD STEP DD WHILE TMPD NQ DSTOP DO
- BEGIN
- FOR I=0 STEP 1 UNTIL MAXCACHE DO
- BEGIN
- IF BFDA[I] EQ DIRDA[TMPD] THEN TEST TMPD;
- END
- SETREAD(DIRDA[TMPD]);
- END
- END
- P<PRU> = TMPPRU;
- END
- END
- PAGE
- PROC READPA;
- IOBEGIN(READPA)
- #
- ** READPA - READ NEXT DEEPER TREE PATH SECTOR.
- *
- * READPA IS USED TO ACCESS THE SECTOR OF DIRECTORY OR DATA
- * FOR A SPECIFIED LEVEL OF THE TREE. THE HIGHER LEVELS OF
- * THE TREE MUST ALREADY BE PROPERLY FILLED IN. ANY RESIDUAL
- * SECTOR IN THE CURRENT TREE LEVEL MUST BE PROPERLY RELEASED
- * FROM OWNERSHIP, SO THAT READPA WILL NOT NEED TO CONCERN
- * ITSELF WITH THE UPDATING OF ALTERED DATA TO DISK. THE
- * CALLER DOES NOT NEED TO SETUP THE FET AND CIRCULAR BUFFER
- * FOR INPUT, AND READPA WILL TAKE CARE OF THAT IF NEEDED.
- *
- * WHEN POSSIBLE, READPA WILL ACCESS THE DESIRED DISK SECTOR
- * BY SIMPLY IDENTIFYING IT IN CACHE AND CLAIMING OWNERSHIP OF
- * THE RIGHT CACHE FRAME. WHEN THE CACHE DOES NOT PROVIDE THE
- * NECESSARY DATA, READPA WILL READ IT FROM DISK. IF THE FET
- * AND CIRCULAR BUFFER ARE PREVIOUSLY INTERLOCKED FOR PENDING
- * OUTPUT, READPA WILL ASSURE THAT THE UNFINISHED WRITES GET
- * DONE. IF THE FET IS ALREADY SETUP FOR INPUT BUT HAS THE
- * WRONG DISK ADDRESS COMING IN AT THE FRONT OF THE CIRCULAR
- * BUFFER, READPA WILL DISCARD SUCH INCORRECT INPUT AND
- * REINITIALIZE TO INPUT THE RIGHT DISK ADDRESS. IF THE FET
- * IS ALREADY SET UP FOR INPUT WITH THE RIGHT SECTOR IN OR
- * COMING INTO THE CIRCULAR BUFFER, READPA WILL MAKE USE OF
- * THAT CIO ACTIVITY.
- *
- * IF READPA READS THE SECTOR FROM DISK, IT CLEANS UP THE
- * RANDOM READ LIST AFTERWARDS, ATTEMPTING TO SHUFFLE THE
- * ACTIVE SEGMENT OF THE READ LIST TO MAXIMIZE THE REMAINING
- * LIST CAPACITY BEFORE WRAPAROUND. READPA ALSO CHECKS TO SEE
- * IF THE BUFFER IS SUFFICIENTLY EMPTY WITH A SUFFICIENTLY
- * FULL PREFETCH LIST SO THAT ANTICIPATORY READS SHOULD BE
- * STARTED.
- *
- * ENTRY TEMP - SECTOR NUMBER.
- * PL - CURRENT PATH LEVEL.
- * PACACHE[ALL] - CACHE FRAMES CURRENTLY OWNED.
- * CACHEOWNED[ALL] - SETUP.
- * BFDA[ALL] - IDENTIFY SECTOR ADDRESSES EACH FRAME.
- * BFHEAD[ALL] - HEADER WORDS FOR EACH CACHED SECTOR.
- * ACCTPRU - PRU TRANSFER COUNT.
- * IOWRITE - WHETHER FET ALREADY SET FOR WRITES.
- * RDIN, RDOUT - READ LIST BRACKETING.
- * RDLIST[ALL] - SETUP.
- * IOREAD - WHETHER SOME READ ALREADY SCHEDULED.
- * FETCHGUIDE - PREFETCH QUANTITY GUIDELINE.
- * QUARTER - APPROX ONE FOURTH BUFFER SIZE.
- *
- * EXIT PACACHE[PL] - INDICATES CACHE FRAME WITH SECTOR.
- * CACHEOWNED[PACACHE[PL]] - TRUE.
- * ANY OLD CACHE FRAMES MAY HAVE BEEN FLUSHED TO
- * DISK AND/OR REASSIGNED IN MEMORY.
- * PAHEAD[PL] - HEADER WORD.
- * IOWRITE - FALSE IF NOT CACHE HIT.
- * IOREAD - POSSIBLY CHANGED.
- * RDOUT - ADVANCED IF DISK READ DONE.
- * RDIN - RDIN AND RDOUT POSSIBLY RELOCATED IF READ
- * DONE AND CIO TERMINATED.
- * ACCTPRU - INCREMENTED IF NO CACHE HIT.
- * FETCHGUIDE - POSSIBLY NEW VALUE.
- * ANTICIPATORY CIO POSSIBLY CALLED.
- *
- * CALLS TRAGIC, COUNTCACHE, FLUSHCACHE, DISOWNCACHE,
- * WIOSTAT, PAUSEIO, ALLOCCACHE, SETREAD, MOVEIO,
- * DELAY, RECALL, RDWBUF, BUFUSAGE.
- *
- * USES P<TOO>.
- #
- ITEM X1;
- CONTROL IFGQ PARANOIA,5;
- IF PADIRTY[PL] THEN TRAGIC(" ALTERED PRU WAS NOT REWRITTEN.$");
- CONTROL FI;
- IF COUNTCACHE LQ 2 THEN FLUSHCACHE;
- # FIRST RELEASE CURRENTLY OWNED SECTOR IF ANY #
- DISOWNCACHE(PACACHE[PL]);
- FOR X1=0 STEP 1 UNTIL MAXCACHE DO
- BEGIN # TRY TO FIND IN CACHE #
- IF BFDA[X1] EQ TEMP THEN # GOT IT #
- BEGIN
- CONTROL IFGQ PARANOIA,5;
- IF CACHEOWNED[X1] THEN
- BEGIN
- TRAGIC(" WORKFILE BUFFER ALLOCATED TWICE.$");
- END
- CONTROL FI;
- PACACHE[PL]=X1;
- CACHEOWNED[X1]=TRUE;
- PAHEAD[PL] = BFHEAD[X1];
- CONTROL IFEQ MULTI,1;
- WIOSTAT(1); # ACCUMULATE CACHE HITS #
- CONTROL FI;
- IORET
- END
- END
- CONTROL IFEQ MULTI,1;
- WIOSTAT(2); # ACCUMULATE SECTORS READ #
- ACCTPRU=ACCTPRU+1;
- CONTROL FI;
- IF IOWRITE THEN # DO ANY PENDING WRITES #
- BEGIN
- PAUSEIO;
- CONTROL IFEQ MULTI,1;
- WIOSTAT(3); # ACCUMULATE FLUSHED WRITES #
- CONTROL FI;
- END
- CONTROL IFGQ PARANOIA,5;
- IF TEMP LQ 0 OR TEMP GR MAXDA THEN
- BEGIN
- TRAGIC(" OUT OF BOUNDS PRU ADDRESS ON READ (2).$");
- END
- CONTROL FI;
- PADA[PL] = TEMP;
- ALLOCCACHE;
- IF IOREAD AND RDLIST[RDOUT] NQ TEMP THEN
- BEGIN
- PAUSEIO;
- CONTROL IFEQ MULTI,1;
- WIOSTAT(4); # ACCUMULATE READ REJECTS #
- CONTROL FI;
- END
- IF NOT IOREAD THEN
- BEGIN
- SETREAD(TEMP);
- FETCHGUIDE=2;
- END
- WHYLE FETIN EQ FETOUT DO
- BEGIN
- CONTROL IFEQ MULTI,1;
- WIOSTAT(10); # ACCUMULATE NOT ALREADY IN BUFFER #
- CONTROL FI;
- MOVEIO;
- CONTROL IFEQ MULTI,1;
- WAIT;
- CONTROL FI;
- CONTROL IFEQ SINGLE,1;
- IF NOT FETDUN THEN DELAY;
- CONTROL FI;
- END
- P<TOO> = LOC(BFPRU[PACACHE[PL]]);
- RDWBUF(O"100");
- PAHEAD[PL] = BFHEAD[PACACHE[PL]];
- CONTROL IFGQ PARANOIA,5;
- IF TEMP NQ RDLIST[RDOUT] THEN
- BEGIN
- TRAGIC(" RANDOM READ LIST INCORRECT.$");
- END
- IF PADA[PL] NQ TEMP THEN TRAGIC(" PRU CONTENT INCORRECT.$");
- IF PADIRTY[PL] THEN
- BEGIN
- TRAGIC(" STATUS FLAGS SHOULD HAVE BEEN CLEARED.$");
- END
- CONTROL FI;
- RDLIST[RDOUT] = 0;
- IF RDOUT EQ RDLIM-1 THEN RDOUT = 0;
- ELSE RDOUT = RDOUT + 1;
- IF FETDUN AND RDIN EQ RDOUT THEN
- BEGIN
- RDIN=0;
- RDOUT=0;
- FETCHGUIDE=ABS(FETCHGUIDE);
- END
- IF BUFUSAGE LQ QUARTER THEN MOVEIO;
- IOEND
- PAGE
- PROC ALLOC;
- BEGIN
- #
- ** ALLOC - ASSIGN DISK ADDRESS.
- *
- * ALLOC IS CALLED WHEN A NEW SECTOR MUST BE CREATED. THE
- * NEXT PRU OFF THE LOGICAL END OF THE FILE IS CHOSEN. NOTE
- * THAT THE LOGICAL END OF THE FILE REPRESENTS THOSE ADDRESSES
- * WHICH HAVE BEEN ALLOCATED. THE PHYSICAL END OF THE FILE
- * REPRESENTS THOSE ADDRESSES ACTUALLY WRITTEN ONTO THE FILE,
- * AND CAN BE A SMALLER NUMBER THAN THE LOGICAL END.
- *
- * ENTRY PL - CURRENT PATH LEVEL.
- * DANEXT - ALLOCATION THRESHOLD.
- *
- * EXIT PADA[PL] - SETUP.
- * DANEXT - INCREMENTED.
- *
- * CALLS TRAGIC.
- #
- CONTROL IFGQ PARANOIA,5;
- IF PADIRTY[PL] THEN TRAGIC(" OLD SECTOR MUST BE WRITTEN.$");
- CONTROL FI;
- PADA[PL] = DANEXT;
- DANEXT = DANEXT + 1;
- END
- PROC DEALLOC;
- BEGIN
- #
- ** DEALLOC - DISCARD DISK SECTOR.
- *
- * DEALLOC IS USED TO DISCARD A DISK SECTOR WHICH CAN NO
- * LONGER BE USED. THIS CAN BE NEEDED WHEN A SECTOR HAS
- * OVERFLOWED AND HAS BEEN SPLIT INTO TWO NEW SECTORS. IF THE
- * ROOT SECTOR NEEDS TO BE SPLIT, A COMPLETE NEW TREE LEVEL IS
- * CREATED WITH NEW SECTORS, THE ROOT SECTOR IS MODIFIED TO
- * BECOME A DIRECTORY FOR THE NEW LEVEL, AND NO DEALLOCATION
- * IS NEEDED. IF A NON-ROOT SECTOR NEEDS TO BE SPLIT EXACTLY
- * AT (JUST AFTER) ITS EXISTING LAST FIELD, THEN THAT SECTOR
- * IS PRESERVED WITHOUT DEALLOCATION AND A NEW SECTOR IS
- * CREATED FOR THE OVERFLOW CONTENT. BUT IF A NON-ROOT SECTOR
- * MUST BE SPLIT SOMEWHERE IN THE MIDDLE OF ITS EXISTING
- * CONTENT, IT MUST BE DEALLOCATED AND BE REPLACED BY TWO
- * COMPLETELY NEW SECTORS.
- *
- * THE REASON FOR DEALLOCATION IS THAT NOTHING MUST BE ALLOWED
- * TO BE POINTED TO UNTIL AND UNLESS IT ALREADY EXISTS, AS
- * UPDATED TO DISK ALTHOUGH NOT NECESSARILY AS CACHED IN
- * MEMORY. SINCE A NON-ROOT SECTOR IS POINTED TO BE
- * HIGHER-LEVEL DIRECOTRIES, IT CANNOT BE TOTALLY REFORMATTED
- * IN PLACE, THEREFORE IT IS LEFT AS IS AND NEW SECTORS
- * REPLACE IT. THE DIRECTORIES WHICH POINT TO THE DISCARDED
- * SECTOR WILL EVENTUALLY BE UPDATED THEMSELVES. UNTIL THEN,
- * THOSE HIGHER DIRECTORIES MAY BE OUT OF DATE BUT AT LEAST
- * POINT TO A VALID DATA STRUCTURE.
- *
- * ENTRY PL - CURRENT TREE LEVEL.
- *
- * EXIT PADA[PL] - CLEARED AWAY.
- *
- * CALLS TRAGIC.
- #
- CONTROL IFGQ PARANOIA,5;
- IF PL EQ 0 OR PADA[PL] EQ 0 THEN
- BEGIN
- TRAGIC(" SECTOR CANNOT BE DEALLOCATED.$");
- END
- CONTROL FI;
- PADA[PL] = 0;
- PADIRTY[PL] = FALSE;
- END
- PROC SETWRITE(PARM);
- BEGIN
- #
- ** SETWRITE - SCHEDULE EXTENSION/ALTERATION OF FILE.
- *
- * SETWRITE INITIALIZES THE FET FOR OUTPUT. IT SETS THE IOACT
- * FLAG TO INDICATE THAT I/O IS SCHEDULED, SETS IOWRITE TO
- * INDICATE THAT THE I/O SHALL BE AN OUTPUT FUNCTION, AND
- * SETS OR CLEARS IOAPEND ACCORDING TO WHETHER THE SECTOR TO
- * BE WRITTEN IS WITHIN THE CURRENT PHYSICAL BOUNDARIES OF THE
- * FILE OR REPRESENTS AN EXTENSION OF PHYSICAL SIZE.
- *
- * ENTRY PARM - DISK ADDRESS TO BE WRITTEN.
- * MAXDA - CURRENT PHYSICAL SIZE OF FILE.
- *
- * EXIT FET - INITIALIZED WITH EMPTY CIRCULAR BUFFER.
- * IOACT - TRUE.
- * IOWRITE - TRUE.
- * IOAPEND - TRUE OR FALSE BASED ON PARM AND MAXDA.
- * LASTDA - SET TO KEEP TRACK OF WHERE WE ARE IN FILE.
- * FETRR - SETUP.
- *
- * CALLS INITFET.
- #
- ITEM PARM;
- INITFET(DISK,DSKSIZ);
- IOACT = TRUE;
- IOWRITE = TRUE;
- IF PARM GR MAXDA THEN
- BEGIN
- IOAPEND = TRUE;
- FETRR = LOC(DUMB);
- END
- ELSE
- BEGIN
- IOAPEND = FALSE;
- FETRR = PARM;
- LASTDA = PARM - 1;
- END
- END
- PAGE
- PROC TRYWRITE(PARM,FLAG);
- BEGIN
- #
- ** TRYWRITE - TRANSMIT SECTOR TO CIRCULAR BUFFER.
- *
- * TRYWRITE ATTEMPTS TO TRANSMIT A SECTOR TO THE CIRCULAR
- * BUFFER. IT MAY FAIL TO DO SO IF THE CIRCULAR BUFFER ALREADY
- * CONTAINS SECTORS FOR WHICH THIS SECTOR IS NOT CONTIGUOUS.
- * THE CALLER SHOULD CALL PAUSEIO WHEN TRYWRITE FAILS, AND
- * THEN CALL THIS ROUTINE AGAIN. TRYWRITE CANNOT FAIL IF
- * PAUSEIO IS USED.
- *
- * ENTRY P<FROM> - POINTS TO TEXT OF SECTOR.
- * PARM - DISK ADDRESS.
- * MAXDA - PHYSICAL FILE SIZE.
- * LASTDA - MOST RECENT DISK ADDRESS TRANSMITTED.
- *
- *
- * EXIT P<FROM> - POSSIBLY DESTROYED.
- * MAXDA - INCREMENTED IF FILE EXTENDED.
- * LASTDA - INCREMENTED IF CONTIGUOUS EARLIER OUTPUT.
- * FET - GUARANTEED SETUP FOR OUTPUT WITH THIS SECTOR
- * OF TEXT IN CIRCULAR BUFFER. EXISTING FET SETUP
- * AND CIRCULAR BUFFER CONTENT, IF ANY, ARE NOT
- * DISTURBED WITH REGARD TO EARLIER OUTPUT.
- * FLAG - TRUE IF THIS SECTOR TRANSMITTED. FALSE IF
- * UNABLE TO TRANSMIT DUE TO DISCONTIGUITY WITH
- * EARLIER OUTPUT.
- * IOACT, IOWRITE - TRUE.
- * IOAPEND - SETUP.
- *
- * CALLS SETWRITE, WTWBUF.
- #
- ITEM PARM, FLAG B, ZERO = 0; # ZERO IS A CONSTANT #
- FLAG = TRUE;
- IF NOT IOWRITE THEN SETWRITE(PARM);
- IF IOAPEND THEN
- BEGIN
- IF MAXDA+1 LS PARM THEN # ADD PADDING SECTOR #
- BEGIN
- MAXDA = MAXDA + 1;
- P<FROM>=LOC(ZERO);
- WTWBUF(O"100");
- END
- ELSE IF MAXDA+1 EQ PARM THEN # ADD REAL SECTOR #
- BEGIN
- MAXDA = MAXDA+1;
- WTWBUF(O"100");
- END
- ELSE
- BEGIN
- FLAG = FALSE;
- END
- END
- ELSE
- BEGIN
- IF LASTDA+1 EQ PARM AND PARM LQ MAXDA THEN
- BEGIN
- LASTDA = LASTDA+1;
- WTWBUF(O"100");
- END
- ELSE
- BEGIN
- FLAG = FALSE;
- END
- END
- END
- PAGE
- PROC FLUSHCACHE;
- IOBEGIN(FLUSHCACHE)
- #
- ** FLUSHCACHE - UPDATE ALTERED CACHE FRAMES TO DISK.
- *
- * FLUSHCACHE IS OBLIGATED TO ASSURE THAT ALL ALTERED, UNOWNED
- * CACHE PAGES BECOME UNALTERED IN CACHE. THIS REQUIRES THAT
- * SUCH PAGES BE TRANSMITTED TO THE CIRCULAR BUFFER. THIS IN
- * TURN CAN BE DONE ONLY IN ORDER OF AGE AND IN ADDRESS ORDER.
- *
- * UNALTERED FRAMES DO NOT NEED TO BE UPDATED TO DISK. OWNED
- * FRAMES CANNOT YET BE UPDATED - IN THE AGE-RESTRICTED ORDER
- * OF UPDATE, OWNED PAGES CAN BE THOUGHT OF AS HAVING THE
- * WORST AGE CATEGORY.
- *
- * EACH SECTOR CAN BE TRANSMITTED TO THE CIRCULAR BUFFER IF
- * THE BUFFER AND FET ARE AVAILABLE FOR OUTPUT, AND IF THE
- * BUFFER IS EITHER EMPTY OR HAS ONE OR MORE SECTORS ALREADY IN
- * IT FOR WHICH THE NEW SECTOR IS CONTIGOUS IN ADDRESS. IF THE
- * FET IS ALREADY CLAIMED FOR INPUT PROCESSING, PAUSEIO CAN BE
- * CALLED TO STOP AND DISCARD SUCH INPUT. FOR SPANNED
- * ADDRESSES, WE MUST CALL PAUSEIO. THIS LOGIC IS PROVIDED BY
- * INSPECTING THE FLAG RETURNED BY TRYWRITE, AND CALLING
- * TRYWRITE A SECOND TIME WITH PAUSEIO, WHEN TRYWRITE FAILED.
- *
- * BECAUSE THE ALLOCATION OF NEW SECTORS AT THE LOGICAL END OF
- * THE FILE CAN RUN SEVERAL UNITS AHEAD OF THE ACTUAL
- * EXTENDING OF THE PHYSICAL END OF THE FILE, AND BECAUSE THE
- * AGE-DEPENDENT ORDERING MIGHT REQUIRE A HIGH ADDRESS SECTOR
- * TO BE WRITTEN BEFORE A LOWER ADDRESS SECTOR MAY BE LEGALLY
- * WRITTEN, A SITUATION CAN ARISE WHERE A SECTOR MUST BE
- * WRITTEN SEVERAL ADDRESSES BEYOND THE CURRENT PHYSICAL END
- * OF FILE. WHEN THIS OCCURS, FLUSHCACHE RECOGNIZES THE
- * SITUATION AND PADS THE PHYSICAL END OUT TO WITHIN ONE
- * SECTOR OF THE SECTOR THAT MUST BE NEXT WRITTEN. THE
- * INTERMEDIATE SECTORS THUS GET A DISK IMAGE WHICH IS NOT UP
- * TO DATE IN ANY WAY WHATSOEVER. THIS IS NOT A PROBLEM - THE
- * UP TO DATE FRAMES FOR SUCH PADDING WILL EVENTUALLY BE
- * RELEASED FOR ACTUAL DISK UPDATE. THE CONTENT OF PADDING
- * SECTORS IS INNOCUOUS, TO FOLLOW THE RULE THAT NOTHING CAN
- * BE POINTED TO ON DISK UNTIL THE OBJECT ITSELF IS UP TO DATE
- * ON DISK.
- *
- * ENTRY CACHEDIRTY[ALL] - SETUP.
- * CACHEAGE[ALL] - SETUP.
- * CACHEOWNED[ALL] - SETUP.
- * BFDA[ALL] - SETUP.
- * IOREAD - WHETHER OBSOLETE INPUT SCHEDULED.
- * IOACT - WHETHER ANY PREVIOUS I/O SCHEDULED.
- * FETDUN - FET INTERLOCK.
- * IOAPEND - WHETHER A PREVIOUS WRITE EXTENDS.
- * QUARTER - APPROX ONE FOURTH BUFFER CAPACITY.
- * ACCTPRU - SECTOR TRANSFER ACCUMULATOR.
- * MAXDA - FILE PHYSICAL BOUNDARY.
- *
- * EXIT ALL ALTERED AND UNOWNED CACHE FRAMES OUTPUT TO DISK
- * OR BUFFERED FOR OUTPUT.
- * IOREAD - FORCED FALSE IF ANY OUTPUT NEEDED.
- * IOACT, IOWRITE, IOAPEND - POSSIBLY TRUE.
- * CACHEDIRTY[ALL] - FALSE WHERE CACHEOWNED IS FALSE.
- * ACCTPRU - INCREMENTED FOR ANY WORK DONE.
- * MAXDA - INCREMENTED IF FILE EXTENDED.
- *
- * CALLS WIOSTAT, PUSHTEMP, POPTEMP, PAUSEIO, BUFAVAIL,
- * MOVEIO, WAIT, DELAY, TRYWRITE, TRAGIC.
- *
- * USES P<FROM>, TEMP(RESTORED).
- #
- ITEM TMP1, TMP2, BOOL B;
- CONTROL IFEQ MULTI,1;
- WIOSTAT(5); # ACCUMULATE CACHE FLUSHES #
- CONTROL FI;
- PUSHTEMP;
- FLUSHLOOP:
- TMP1=999999999;
- TEMP=-1;
- FOR TMP2=0 STEP 1 UNTIL MAXCACHE DO
- BEGIN # SEARCH FOR OLDEST DIRTY #
- IF CACHEDIRTY[TMP2] AND CACHEAGE[TMP2] LS TMP1
- AND NOT CACHEOWNED[TMP2] THEN
- BEGIN
- TEMP=TMP2;
- TMP1=CACHEAGE[TMP2];
- END
- END
- IF TEMP LS 0 THEN # NO MORE FLUSH NEEDED #
- BEGIN
- POPTEMP;
- IORET
- END
- CACHEDIRTY[TEMP]=FALSE;
- IF BFDA[TEMP] EQ 0 THEN GOTO FLUSHLOOP;
- IF IOREAD THEN # COMPLETE ANY INPUT #
- BEGIN
- PAUSEIO;
- CONTROL IFEQ MULTI,1;
- WIOSTAT(6); # ACCUMULATE READ REJECTS #
- CONTROL FI;
- END
- WRITELOOP:
- WHYLE IOACT AND BUFAVAIL LS O"100" DO
- BEGIN # NEED ROOM IN BUFFER #
- MOVEIO;
- CONTROL IFEQ MULTI,1;
- WAIT;
- CONTROL FI;
- CONTROL IFEQ SINGLE,1;
- IF NOT FETDUN THEN DELAY;
- CONTROL FI;
- END
- CONTROL IFEQ MULTI,1;
- WIOSTAT(7); # ACCUMULATE SECTORS WRITTEN #
- ACCTPRU=ACCTPRU+1;
- CONTROL FI;
- P<FROM>=LOC(BFPRU[TEMP]);
- TRYWRITE(BFDA[TEMP],BOOL);
- IF NOT BOOL THEN
- BEGIN # ONE FAILURE ALLOWED, NOT TWO #
- PAUSEIO;
- CONTROL IFEQ MULTI,1;
- WIOSTAT(8); # ACCUMULATE DISCONTIGUOUS WRITES #
- CONTROL FI;
- P<FROM>=LOC(BFPRU[TEMP]);
- TRYWRITE(BFDA[TEMP],BOOL);
- IF NOT BOOL THEN TRAGIC(" UNABLE TO WRITE FROM BUFFER.$");
- END
- # EITHER ADD MORE PADDING FOR THIS FLUSH OR FLUSH ANOTHER #
- IF IOAPEND AND MAXDA LS BFDA[TEMP] THEN
- BEGIN
- CONTROL IFEQ MULTI,1;
- WIOSTAT(9); # ACCUMULATE PADDING SECTORS #
- CONTROL FI;
- GOTO WRITELOOP;
- END
- IF BUFAVAIL LQ QUARTER THEN MOVEIO;
- GOTO FLUSHLOOP;
- IOEND # OF FLUSHCACHE #
- PROC CLOSEOUT;
- IOBEGIN(CLOSEOUT)
- #
- ** CLOSEOUT - FINISH UPDATE OF DISK.
- *
- * WORKFILE CLOSEOUT CONDITIONS HAVE BEEN DETECTED. UNDER
- * CLOSEOUT CONDITIONS, WE MUST WRITE NOT ONLY THE ZERO-LEVEL
- * SECTOR, BUT ALSO THE DATA SEGMENT (RIGHT AFTER ROOT SECTOR)
- * FOLLOWED BY EOR THEN ARRAY SEGMENT THEN A SECOND EOR.
- *
- * THE CLOSEOUT ROUTINE WRITES THE TWO BINARY SEGMENTS, BUT
- * REQUIRES THAT THE CALLER FIRST FLUSH ALL TREE STRUCTURE
- * SECTORS TO DISK OR AT LEAST TO THE CIRCULAR BUFFER. THE
- * CALLER SHOULD USE THE CLEAN ROUTINE WITH PL=0 TO MEET THAT
- * REQUIREMENT. THE CLOSEOUT ROUTINE DEPENDS ON THE RULE THAT
- * THE ROOT SECTOR OF THE TREE STRUCTURE MUST BE THE LAST
- * (CHRONOLOGICALLY) TO BE FREED FOR UPDATE TO DISK, AND
- * DEPENDS ON THE RULE THAT THE ROOT SECTOR IS AT DISK ADDRESS
- * 1 AND THEREFORE IS CONTIGUOUS WITH NO PREVIOUSLY RELEASED
- * SECTORS. THUS, CLOSEOUT EXPECTS THAT ALL SECTORS EXCEPT
- * THE ROOT HAVE BEEN ACTUALLY WRITTEN TO DISK, AND THE ROOT
- * SECTOR IS EXPECTED TO BE SCHEDULED FOR UPDATE BUT STILL IS
- * PRESENT IN THE CIRCULAR BUFFER.
- *
- * CLOSEOUT INTERCEPTS THE ISSUANCE OF CIO FUNCTION CODES FOR
- * THE UPDATE OF THE ROOT SECTOR, AND AFTER APPENDING THE
- * SCALAR DATA SEGMENT ONTO THE ROOT SECTOR IN THE CIRCULAR
- * BUFFER, CLOSEOUT CALLS PAUSEIO (AND THUS MOVEIO) SUCH THAT
- * ONE WRITE WITH END OF RECORD OCCURS. THEN CLOSEOUT
- * CONSTRUCTS A NEW CIRCULAR BUFFER IMAGE FOR THE ARRAY
- * SEGMENT, AND USES PAUSEIO A SECOND TIME TO WRITE ANOTHER
- * MULTIPLE SECTOR RECORD.
- *
- * ENTRY CLEAN HAS BEEN CALLED WITH PL=0.
- * IOAPEND - WHETHER FILE PRESENTLY EMPTY.
- * LASTDA, MAXDA - LOGICAL AND PHYSICAL FILE SIZES.
- * DATALEN, ARRAYLEN - LENGTHS OF BINARY SEGMENTS.
- * DATAPRUS, ARRAYPRUS - LENGTHS IN SECTORS.
- *
- * EXIT FILE COMPLETELY DRAINED TO DISK, FET INACTIVE.
- * LASTDA, MAXDA - ONE OF THESE TWO IS INCREMENTED.
- *
- * CALLS FLUSHCACHE, WTWBUF, PAUSEIO, INITFET.
- *
- * USES P<FROM>, IOWRITE, IOWRTEOR, IOAPEND, IOACT.
- #
- FLUSHCACHE; # PUT SECTOR 1 (ROOT PRU) INTO BUFFER #
- IOWRTEOR=TRUE; # WRITE ROOT PRU PLUS DATA SEGMENT #
- P<FROM>=LOC(DATASTART);
- WTWBUF(DATALEN);
- IF IOAPEND THEN MAXDA=MAXDA+DATAPRUS;
- ELSE LASTDA=LASTDA+DATAPRUS;
- PAUSEIO;
- INITFET(DISK,DSKSIZ); # NOW SET UP FOR ARRAYS #
- IOACT=TRUE;
- IOWRITE=TRUE;
- IF FETCRI GR MAXDA THEN
- BEGIN
- IOAPEND=TRUE;
- FETRR=LOC(DUMB);
- MAXDA=MAXDA+ARRAYPRUS;
- END
- ELSE
- BEGIN
- IOAPEND=FALSE;
- FETRR=FETCRI;
- LASTDA=LASTDA+ARRAYPRUS;
- END
- IOWRTEOR=TRUE;
- P<FROM>=LOC(ARRAYSTART);
- WTWBUF(ARRAYLEN);
- PAUSEIO;
- IOEND # OF CLOSEOUT #
- PAGE
- PROC CLEAN;
- IOBEGIN(CLEAN)
- #
- ** CLEAN - DISCONNECT SECTOR FROM LOWEST TREE LEVEL.
- *
- * CLEAN IS CALLED WHENEVER A ROUTINE WISHES TO DISCARD THE
- * SECTOR PRESENTLY ASSOCIATED WITH A TREE LEVEL. THIS CAN BE
- * DONE ONLY IN THE REVERSE ORDER OF THE TREE HIERARCHY, IE,
- * THE BOTTOM LEVEL FIRST AND THE ROOT LEVEL LAST. THE EFFECT
- * OF CALLING CLEAN IS TO DISCONNECT THE SECTOR FROM THE TREE
- * STRUCTURE BY FREEING THE CACHE FRAME FROM OWNERSHIP, FIRST
- * DISCONNECTING ANY TREE LEVELS LOWER THAN THE CURRENT LEVEL.
- *
- * IF THE TREE LEVEL WAS PREVIOUSLY FLAGGED AS ALTERED, THE
- * FREED CACHE FRAME IS SIMILARLY FLAGGED. ALL HEADER WORD
- * DATA IS COPIED FROM THE TREE CONTROL VECTOR TO THE SECTOR
- * IMAGE IN CACHE.
- *
- * ENTRY PL - LEVEL TO BE FREED.
- * PALVL - DEEPEST ACTIVE TREE LEVEL.
- * PAHEAD[ALL] - HEADER WORDS IN TREE VECTOR.
- * PACACHE[ALL] - SETUP.
- * CACHEOWNED[ALL] - SETUP.
- * PADIRTY[ALL] - ALTERATION FLAG.
- *
- * EXIT THIS LEVEL AND ALL DEEPER LEVELS FREED.
- * CACHEOWNED[ANY] - FORCED TRUE FOR THOSE FREED.
- * CACHEDIRTY[ANY] - FORCED TRUE FOR THOSE FREED
- * WITH PADIRTY TRUE.
- * CACHEAGE[ANY] - INITIALIZED FOR THOSE FREED.
- *
- * CALLS DROPIT(INTERNAL), DISOWNCACHE.
- *
- * USES TPL.
- #
- PROC DROPIT;
- BEGIN
- IF CACHEOWNED[PACACHE[TPL]] THEN BFHEAD[PACACHE[TPL]]=PAHEAD[TPL];
- DISOWNCACHE(PACACHE[TPL]);
- END # OF DROPIT #
- # START OF MAIN CODE #
- IF PADIRTY[PL] THEN
- BEGIN
- FOR TPL = PALVL STEP -1 UNTIL PL DO
- BEGIN
- IF PADIRTY[TPL] THEN
- BEGIN
- PADIRTY[TPL]=FALSE;
- CACHEDIRTY[PACACHE[TPL]]=TRUE;
- DROPIT;
- END
- ELSE DROPIT;
- END
- END
- ELSE
- BEGIN
- FOR TPL=PALVL STEP -1 UNTIL PL DO DROPIT;
- END
- IOEND
- PROC CLEANALL;
- IOBEGIN(CLEANALL)
- #
- ** CLEANALL - CLEAN ENTIRE TREE STRUCTURE AND DATA SEGEMENTS.
- *
- * CLEANALL IS USED TO INITIATE CLOSEOUT OF THE WORKFILE
- * MANAGER. THE ENTIRE TREE STRUCTURE IS CLEANED WITH ANY
- * ALTERED SECTORS WRITTEN TO DISK, AND THE SCALAR AND ARRAY
- * DATA SEGMENTS ARE UPDATED.
- *
- * ENTRY CACHEOWNED[ALL] - SETUP.
- * PACACHE[ALL] - SETUP.
- * PADIRTY[ALL] - SETUP.
- * PAHEAD[ALL] -SETUP.
- * PALVL - DEEPEST TREE LEVEL.
- *
- * EXIT PL - ZERO.
- * CACHEDIRTY[ALL] - FALSE.
- * FET AND CIRCULAR BUFFER - COMPLETE/EMPTY.
- * PADIRTY[ALL] - FALSE.
- *
- * CALLS CLEAN, CLOSEOUT, RECLAIMCACHE.
- #
- PADIRTY[0]=TRUE;
- PL=0;
- CLEAN;
- CLOSEOUT;
- RECLAIMCACHE;
- IOEND # OF CLEANALL #
- PAGE
- PROC BK;
- IOBEGIN(BK)
- #
- ** BK - BACK UP ONE LINE.
- *
- * BK IS ORGANIZED INTO THREE OPERATIONAL PHASES. THE FIRST
- * PHASE DETERMINES WHETHER THE CURRENT TREE PATH ALREADY
- * CONTAINS THE SECTOR WITH THE DESIRED LINE OF TEXT, AND IF
- * NOT, IT CLEANS AWAY AS MANY TREE LEVELS AS NECESSARY, FROM
- * THE BOTTOM TOWARDS THE ROOT, UNTIL WE ARE IN A DIRECTORY
- * WHOSE SPHERE OF INFLUENCE INCLUDES THE DESIRED LINE.
- *
- * THE SECOND PHASE ASSURES THAT WE HAVE A FULL DEPTH TREE
- * STRUCTURE CONTAINING THE RIGHT SECTOR AT THE DATA (BOTTOM)
- * LEVEL. IF THE FIRST PHASE WAS NON-TRIVIAL, THEN THE SECOND
- * PHASE WILL ALSO HAVE REAL WORK TO PERFORM, WORKING BACK
- * TOWARD DEEP TREE LEVELS, READING IN EACH SECTOR NEEDED.
- * THE SECOND PHASE IS A NO-OP IF THE FIRST PHASE WAS A NO-OP
- * AND IF THE TREE ALREADY EXISTS ALL THE WAY DOWN TO THE DATA
- * LEVEL. HOWEVER, THE FIRST PHASE COULD HAVE BEEN A NO-OP
- * FOR AN INCOMPLETE TREE PATH, IN WHICH CASE THE SECOND PHASE
- * MUST DEEPEN THE TREE PATH.
- *
- * THE THIRD PHASE SCANS THE DATA SECTOR TO FIND THE RIGHT
- * LINE IMAGE. THE INTERNAL LINE IMAGE FORMAT USES THE SIGN
- * BIT TO INDICATE WORDS WHICH ARE THE LAST WORDS OF LINES.
- *
- * ENTRY CURRENT - CURRENT LINE.
- * PALVL - DEEPEST TREE LEVEL.
- * ALL PATH AND CACHE CONTROLS SETUP.
- * P<MVLNBUF> - WHERE TO PUT LINE OF TEXT.
- * DISP, CURNW - DESCRIBE WORD OFFSET AND LENGTH OF
- * PREVIOUS CURRENT LINE.
- *
- * EXIT CURRENT - DECREMENTED.
- * MVLNBUF - CONTAINS LINE OF TEXT.
- * PALVL - NEW VALUE FOR DEEPEST TREE LEVEL.
- * ALL PATH CONTROLS - MAY CONTROL DIFFERENT SECTORS
- * FOR DEEPER TREE LEVELS.
- * ALL CACHE CONTROLS - MAY CONTROL DIFFERENT SECTORS.
- * FET, CIRCULAR BUFFER, READ LIST - MAY CONTROL
- * A PREFETCH OPERATION.
- * CURNW - SIZE OF NEW LINE.
- * DISP - OFFSET OF NEW LINE.
- *
- * CALLS TRAGIC, CLEAN, PUSHTEMP, READPA, POPTEMP, PREFETCH,
- * MOVELN.
- *
- * USES TEMP(RESTORED), P<PRU>, PL.
- #
- IF CURRENT LQ 0 THEN TRAGIC(" BAK BEFORE START OF FILE.$");
- CURRENT = CURRENT - 1;
- FOR PL = PALVL WHILE PAFIRST[PL] GR CURRENT DO
- BEGIN
- CLEAN;
- PL = PL - 1;
- END
- P<PRU> = LOC(BFPRU[PACACHE[PL]]);
- DISP = PADISP[PL] - 1;
- CONTROL IFGQ PARANOIA,5;
- IF DISP LQ 0 THEN TRAGIC(" DIRECTORY BLOCK POINTER TOO SMALL.$");
- CONTROL FI;
- PADISP[PL] = DISP;
- IF PADIR[PL] THEN
- BEGIN
- FOR PL = PL WHILE PADIR[PL] DO
- BEGIN
- PL = PL + 1;
- PALVL = PL;
- PUSHTEMP;
- TEMP=DIRDA[DISP];
- READPA;
- POPTEMP;
- PAFIRST[PL] = CURRENT - DIRNL[DISP] + 1;
- PALAST[PL] = CURRENT;
- P<PRU> = LOC(BFPRU[PACACHE[PL]]);
- DISP = PAFINAL[PL];
- PADISP[PL] = DISP;
- END
- PREFETCH(-1);
- END
- # NOTE THIS CODE REQUIRES INTERNAL CHARSET USAGE OF SIGN BIT #
- FOR DISP = DISP - 1 WHILE DISP NQ 0 AND B<0,1>DATWORD[DISP] EQ 0
- DO DISP = DISP - 1;
- PADISP[PL] = DISP + 1;
- P<FROM> = LOC(BFPRU[PACACHE[PALVL]]) + PADISP[PALVL];
- CURNW = MOVELN(FROM,MVLNBUF);
- IOEND
- PAGE
- PROC FW;
- IOBEGIN(FW)
- #
- ** FW - ADVANCE ONE LINE.
- *
- * FW IS ORGANIZED INTO THREE OPERATIONAL PHASES. THE FIRST
- * PHASE DETERMINES WHETHER THE CURRENT TREE PATH ALREADY
- * CONTAINS THE SECTOR WITH THE DESIRED LINE OF TEXT, AND IF
- * NOT, IT CLEANS AWAY AS MANY TREE LEVELS AS NECESSARY, FROM
- * THE BOTTOM TOWARDS THE ROOT, UNTIL WE ARE IN A DIRECTORY
- * WHOSE SPHERE OF INFLUENCE INCLUDES THE DESIRED LINE.
- *
- * THE SECOND PHASE ASSURES THAT WE HAVE A FULL DEPTH TREE
- * STRUCTURE CONTAINING THE RIGHT SECTOR AT THE DATA (BOTTOM)
- * LEVEL. IF THE FIRST PHASE WAS NON-TRIVIAL, THEN THE SECOND
- * PHASE WILL ALSO HAVE REAL WORK TO PERFORM, WORKING BACK
- * TOWARD DEEP TREE LEVELS, READING IN EACH SECTOR NEEDED.
- * THE SECOND PHASE IS A NO-OP IF THE FIRST PHASE WAS A NO-OP
- * AND IF THE TREE ALREADY EXISTS ALL THE WAY DOWN TO THE DATA
- * LEVEL. HOWEVER, THE FIRST PHASE COULD HAVE BEEN A NO-OP
- * FOR AN INCOMPLETE TREE PATH, IN WHICH CASE THE SECOND PHASE
- * MUST DEEPEN THE TREE PATH.
- *
- * THE THIRD PHASE IDENTIFIES THE CORRECT LINE IMAGE WITHIN
- * THE DATA SECTOR. THE MECHANISM USED DEPENDS ON WHETHER THE
- * SECOND PHASE WAS ACTUALLY PERFORMED, SINCE FOR A NO-OP THE
- * DISP AND CURNW PARAMETERS FOR THE PREVIOUS CURRENT LINE
- * PROVIDE ALL INFORMATION REQUIRED TO ADVANCE ONE LINE.
- *
- * ENTRY CURRENT - CURRENT LINE.
- * PALVL - DEEPEST TREE LEVEL.
- * ALL PATH AND CACHE CONTROLS SETUP.
- * P<MVLNBUF> - WHERE TO PUT LINE OF TEXT.
- * DISP, CURNW - DESCRIBE WORD OFFSET AND LENGTH OF
- * PREVIOUS CURRENT LINE.
- *
- * EXIT CURRENT - INCREMENTED.
- * MVLNBUF - CONTAINS LINE OF TEXT.
- * PALVL - NEW VALUE FOR DEEPEST TREE LEVEL.
- * ALL PATH CONTROLS - MAY CONTROL DIFFERENT SECTORS
- * FOR DEEPER TREE LEVELS.
- * ALL CACHE CONTROLS - MAY CONTROL DIFFERENT SECTORS.
- * FET, CIRCULAR BUFFER, READ LIST - MAY CONTROL
- * A PREFETCH OPERATION.
- * CURNW - SIZE OF NEW LINE.
- * DISP - OFFSET OF NEW LINE.
- *
- * CALLS TRAGIC, CLEAN, PUSHTEMP, READPA, POPTEMP, PREFETCH,
- * MOVELN.
- *
- * USES TEMP(RESTORED), P<PRU>, PL.
- #
- IF CURRENT GQ PALAST[0] THEN TRAGIC(" FWD BEYOND END OF FILE.$");
- CURRENT = CURRENT + 1;
- FOR PL = PALVL WHILE PALAST[PL] LS CURRENT DO
- BEGIN
- CLEAN;
- PL = PL - 1;
- END
- P<PRU> = LOC(BFPRU[PACACHE[PL]]);
- DISP = PADISP[PL];
- IF PADIR[PL] THEN
- BEGIN
- DISP = DISP + 1;
- CONTROL IFGQ PARANOIA,5;
- IF DISP GR PAFINAL[PL] THEN
- BEGIN
- TRAGIC(" DIRECTORY BLOCK POINTER TOO LARGE (1).$");
- END
- CONTROL FI;
- PADISP[PL] = DISP;
- FOR PL = PL WHILE PADIR[PL] DO
- BEGIN
- PL = PL + 1;
- PALVL = PL;
- PUSHTEMP;
- TEMP=DIRDA[DISP];
- READPA;
- POPTEMP;
- PAFIRST[PL] = CURRENT;
- PALAST[PL] = CURRENT + DIRNL[DISP] - 1;
- P<PRU> = LOC(BFPRU[PACACHE[PL]]);
- DISP = 1;
- PADISP[PL] = 1;
- END
- PREFETCH(+1);
- END
- ELSE PADISP[PL] = DISP + CURNW;
- P<FROM> = LOC(BFPRU[PACACHE[PALVL]]) + PADISP[PALVL];
- CURNW = MOVELN(FROM,MVLNBUF);
- IOEND
- PAGE
- PROC POSR;
- IOBEGIN(POSR)
- #
- ** POSR - POSITION TO A RANDOMLY SELECTED LINE.
- *
- * POSR IS ORGANIZED INTO THREE OPERATIONAL PHASES. THE FIRST
- * PHASE DETERMINES WHETHER THE CURRENT TREE PATH ALREADY
- * CONTAINS THE SECTOR WITH THE DESIRED LINE OF TEXT, AND IF
- * NOT, IT CLEANS AWAY AS MANY TREE LEVELS AS NECESSARY, FROM
- * THE BOTTOM TOWARDS THE ROOT, UNTIL WE ARE IN A DIRECTORY
- * WHOSE SPHERE OF INFLUENCE INCLUDES THE DESIRED LINE.
- *
- * THE SECOND PHASE ASSURES THAT WE HAVE A FULL DEPTH TREE
- * STRUCTURE CONTAINING THE RIGHT SECTOR AT THE DATA (BOTTOM)
- * LEVEL. IF THE FIRST PHASE WAS NON-TRIVIAL, THEN THE SECOND
- * PHASE WILL ALSO HAVE REAL WORK TO PERFORM, WORKING BACK
- * TOWARD DEEP TREE LEVELS, READING IN EACH SECTOR NEEDED.
- * THE SECOND PHASE IS A NO-OP IF THE FIRST PHASE WAS A NO-OP
- * AND IF THE TREE ALREADY EXISTS ALL THE WAY DOWN TO THE DATA
- * LEVEL. HOWEVER, THE FIRST PHASE COULD HAVE BEEN A NO-OP
- * FOR AN INCOMPLETE TREE PATH, IN WHICH CASE THE SECOND PHASE
- * MUST DEEPEN THE TREE PATH.
- *
- * THE THIRD PHASE SCANS THE DATA SECTOR TO FIND THE RIGHT
- * LINE IMAGE. THE INTERNAL LINE IMAGE FORMAT USES THE SIGN
- * BIT TO INDICATE WORDS WHICH ARE THE LAST WORDS OF LINES.
- *
- * ENTRY NEWCURL - DESIRED LINE.
- * PALVL - DEEPEST TREE LEVEL.
- * ALL PATH AND CACHE CONTROLS SETUP.
- * P<MVLNBUF> - WHERE TO PUT LINE OF TEXT.
- * DISP, CURNW - DESCRIBE WORD OFFSET AND LENGTH OF
- * PREVIOUS CURRENT LINE.
- *
- * EXIT CURRENT - MATCHES NEWCURL.
- * MVLNBUF - CONTAINS LINE OF TEXT.
- * PALVL - NEW VALUE FOR DEEPEST TREE LEVEL.
- * ALL PATH CONTROLS - MAY CONTROL DIFFERENT SECTORS
- * FOR DEEPER TREE LEVELS.
- * ALL CACHE CONTROLS - MAY CONTROL DIFFERENT SECTORS.
- * FET, CIRCULAR BUFFER, READ LIST - MAY CONTROL
- * A PREFETCH OPERATION.
- * CURNW - SIZE OF NEW LINE.
- * DISP - OFFSET OF NEW LINE.
- *
- * CALLS TRAGIC, CLEAN, PUSHTEMP, READPA, POPTEMP, PREFETCH,
- * MOVELN.
- *
- * USES TEMP(RESTORED), P<PRU>, PL.
- #
- IF NEWCURL LS 0 OR NEWCURL GR PALAST[0] THEN
- BEGIN
- TRAGIC(" LINE NOT FOUND IN FILE.$");
- END
- PUSHTEMP;
- CURRENT = NEWCURL;
- FOR PL=PALVL WHILE
- NOT(CURRENT GQ PAFIRST[PL] AND CURRENT LQ PALAST[PL]) DO
- BEGIN
- CLEAN;
- PL = PL - 1;
- END
- P<PRU> = LOC(BFPRU[PACACHE[PL]]);
- FOR PL = PL WHILE PADIR[PL] DO
- BEGIN
- TEMP = PAFIRST[PL];
- FOR DISP = 1 WHILE CURRENT GQ TEMP+DIRNL[DISP] DO
- BEGIN
- TEMP = TEMP + DIRNL[DISP];
- DISP = DISP + 1;
- END
- CONTROL IFGQ PARANOIA,5;
- IF DISP GR PAFINAL[PL] THEN
- BEGIN
- TRAGIC(" DIRECTORY BLOCK POINTER TOO LARGE (2).$");
- END
- CONTROL FI;
- PADISP[PL] = DISP;
- PL = PL + 1;
- PALVL = PL;
- PAFIRST[PL] = TEMP;
- PALAST[PL] = TEMP + DIRNL[DISP] - 1;
- PUSHTEMP;
- TEMP=DIRDA[DISP];
- READPA;
- POPTEMP;
- P<PRU> = LOC(BFPRU[PACACHE[PL]]);
- END
- TEMP = PAFIRST[PL];
- FOR DISP = 1 WHILE CURRENT NQ TEMP DO
- BEGIN
- # NOTE THIS CODE REQUIRES INTERNAL CHARSET USAGE OF SIGN BIT #
- IF B<0,1>DATWORD[DISP] NQ 0 THEN TEMP = TEMP + 1;
- DISP = DISP + 1;
- END
- CONTROL IFGQ PARANOIA,5;
- IF DISP GR PAFINAL[PL] THEN
- BEGIN
- TRAGIC(" DIRECTORY BLOCK POINTER TOO LARGE (3).$");
- END
- CONTROL FI;
- PADISP[PL] = DISP;
- P<FROM> = LOC(BFPRU[PACACHE[PALVL]]) + PADISP[PALVL];
- CURNW = MOVELN(FROM,MVLNBUF);
- POPTEMP;
- IOEND
- PAGE
- PROC FWD;
- IOBEGIN(FWD)
- #
- ** FWD - EXTERNAL INTERFACE FOR FORWARD MOVEMENT.
- *
- * FWD INTERFACES TO THE FW ROUTINE TO ADVANCE ONE LINE
- * FROM THE CURRENT POSITION. FWD ALSO CONTROLS THE BASE
- * ADDRESS FOR MVLNBUF AND ACCUMULATES STATISTICS.
- *
- * ENTRY P<LINEBUF> - WHERE TO PUT TEXT OR ZERO FOR INVISIBLE
- * POSITIONING FUNCTION.
- * CURRENT - CURRENT LINE.
- *
- * EXIT CURRENT - INCREMENTED.
- * LINEBUF - TEXT MOVE HERE IF BASE ADDRESS NONZERO.
- *
- * CALLS FW.
- *
- * USES P<MVLNBUF>.
- #
- CONTROL IFEQ MULTI,1;
- WIOSTAT(0); # ACCUMULATE LINE ACCESES #
- CONTROL FI;
- P<MVLNBUF>=LOC(LINEBUF);
- FW;
- P<MVLNBUF>=0;
- IOEND
- PROC BAK;
- IOBEGIN(BAK)
- #
- ** FWD - EXTERNAL INTERFACE FOR BACKWARD MOVEMENT.
- *
- * BAK INTERFACES TO THE BK ROUTINE TO REGRESS ONE LINE
- * FROM THE CURRENT POSITION. BAK ALSO CONTROLS THE BASE
- * ADDRESS FOR MVLNBUF AND ACCUMULATES STATISTICS.
- *
- * ENTRY P<LINEBUF> - WHERE TO PUT TEXT OR ZERO FOR INVISIBLE
- * POSITIONING FUNCTION.
- * CURRENT - CURRENT LINE.
- *
- * EXIT CURRENT - DECREMENTED.
- * LINEBUF - TEXT MOVE HERE IF BASE ADDRESS NONZERO.
- *
- * CALLS BK.
- *
- * USES P<MVLNBUF>.
- #
- CONTROL IFEQ MULTI,1;
- WIOSTAT(0); # ACCUMULATE LINE ACCESES #
- CONTROL FI;
- P<MVLNBUF>=LOC(LINEBUF);
- BK;
- P<MVLNBUF>=0;
- IOEND
- PROC POS;
- IOBEGIN(POS)
- #
- ** POS - EXTERNAL INTERFACE FOR RANDOM MOVEMENT.
- *
- * POS INTERFACES TO THE POSR ROUTINE TO GO TO ANY LINE
- * FROM THE CURRENT POSITION. POS ALSO CONTROLS THE BASE
- * ADDRESS FOR MVLNBUF AND ACCUMULATES STATISTICS.
- *
- * ENTRY P<LINEBUF> - WHERE TO PUT TEXT OR ZERO FOR INVISIBLE
- * POSITIONING FUNCTION.
- * NEWCURL - DESIRED LINE.
- * CURRENT - PREVIOUS CURRENT LINE.
- *
- * EXIT CURRENT - MATCHES NEWCURL.
- * LINEBUF - TEXT MOVE HERE IF BASE ADDRESS NONZERO.
- *
- * CALLS POSR.
- *
- * USES P<MVLNBUF>.
- #
- CONTROL IFEQ MULTI,1;
- WIOSTAT(0); # ACCUMULATE LINE ACCESES #
- CONTROL FI;
- P<MVLNBUF>=LOC(LINEBUF);
- IF NEWCURL EQ CURRENT-1 THEN BK;
- ELSE IF NEWCURL EQ CURRENT+1 THEN FW;
- ELSE IF NEWCURL NQ CURRENT THEN POSR;
- ELSE # JUST READOUT SAME LINE #
- BEGIN
- P<FROM> = LOC(BFPRU[PACACHE[PALVL]]) + PADISP[PALVL];
- DUMB = MOVELN(FROM,LINEBUF);
- END
- P<MVLNBUF>=0;
- IOEND # OF POS #
- PAGE
- PROC SPLITTOP;
- IOBEGIN(SPLITTOP)
- #
- ** SPLITTOP - SPLIT ROOT SECTOR TO MAKE NEW LEVEL.
- *
- * SPLITTOP IS USED WHEN THE ROOT SECTOR OVERFLOWS. THE ROOT
- * SECTOR MUST ALWAYS EXIST AT DISK ADDRESS 1, THUS THE METHOD
- * USED TO SPLIT IT IS DIFFERENT FROM THAT USED FOR ANY OTHER
- * SECTOR. THE EXISTING CONTENTS OF THE ROOT SECTOR ARE
- * PLACED IN TWO NEW SECTORS, AND THE ROOT SECTOR IS
- * RECONSTRUCTED AS A DIRECTORY POINTING TO THESE TWO NEW
- * SECTORS. THUS THE OVERALL TREE STRUCTURE IS DEEPENED BY
- * ONE LEVEL.
- *
- * HOWEVER, SPLITTOP DOES NOT PROVIDE ALL THIS ALGORITHM.
- * SPLITTOP DOES PRODUCE A NEW TREE LEVEL WITH A REBUILT ROOT,
- * BUT STOPS SHORT OF FITTING THE OVERFLOWED TEXT INTO A PAIR
- * OF SECTORS. SPLITTOP PLACES THE PRE-OVERFLOW SECTOR
- * CONTENT INTO A SINGLE SECTOR AT THE NEW INTERMEDIATE TREE
- * LEVEL, AND ESTABLISHES THIS AS THE CURRENT TREE PATH LEVEL.
- * THE CALLER IS THEN RESPONSIBLE TO USE ONE OF THE OTHER
- * SECTOR SPLITTING ALGORITHMS TO GET THE TEXT ACTUALLY SPLIT
- * INTO TWO SECTORS. THESE OTHER ALGORITHMS WILL UPDATE THE
- * NEW ROOT TO POINT TO THE OVERFLOW SECTOR.
- *
- * ENTRY PL - MUST EQUAL ZERO.
- * PADEPTH[0] - INDICATE HIGH WATER MARK OF TREE DEPTH.
- * PALVL - CURRENT DEEPEST TREE LEVEL ON PATH.
- * ALL PATH CONTROLS - SETUP.
- * CACHE - AT LEAST ONE FRAME MUST BE AVAILABLE TO
- * BE CLAIMED.
- *
- * EXIT PL - ONE.
- * PALVL - INCREMENTED.
- * PADEPTH[0] - INCREMENETED.
- * ALL PATH CONTROLS - SHUFFLED TO DEEPER LEVELS.
- * CACHE - ONE FRAME ALLOCATED FOR NEW LEVEL 0.
- * ROOT SECTOR CACHE FRAME - BUILT AS DIRECTORY WITH
- * ONE ENTRY POINTING TO INTERMEDIATE SECTOR.
- * PATH LEVEL 1 - BUILT AS INTERMEDIATE TREE LEVEL
- * USING SAME CACHE FRAME AS FORMER ROOT LEVEL,
- * BUT ASSIGNED A NEWLY ALLOCATED DISK ADDRESS.
- * MARKED AS ALTERED SO NEW DISK ADDRESS CAN BE
- * EVENTUALLY WRITTEN TO DISK.
- *
- * CALLS TRAGIC, ALLOC, ALLOCCACHE, MOVEWD.
- *
- * USES P<PRU>.
- #
- IF PADEPTH[0] GQ MAXDEPTH THEN TRAGIC(" FILE TOO LARGE.$");
- PADEPTH[0] = PADEPTH[0] + 1;
- FOR PL = PALVL STEP -1 UNTIL 0 DO # SLIDE PATH UP #
- BEGIN
- PAFIRST[PL+1] = PAFIRST[PL];
- PALAST[PL+1] = PALAST[PL];
- PADISP[PL+1] = PADISP[PL];
- PAHEAD[PL+1] = PAHEAD[PL];
- PACACHE[PL+1] = PACACHE[PL];
- END
- PL = 1; # STEP UP PL & PALVL #
- PALVL = PALVL + 1;
- PATOP[1] = FALSE; # FIX UP OLD TOP #
- PADIRTY[1] = FALSE;
- PADA[1] = 0;
- ALLOC;
- ALLOCCACHE;
- PADIRTY[1] = TRUE;
- P<FROM> = LOC(BFPRU[PACACHE[0]]) + 1;
- P<TOO> = LOC(BFPRU[PACACHE[1]]) + 1;
- MOVEWD(PAFINAL[0],FROM,TOO);
- PADATA[0] = FALSE; # BUILD NEW TOP #
- PADIR[0] = TRUE;
- PADIRTY[0] = TRUE;
- PAFINAL[0] = 1;
- P<PRU> = LOC(BFPRU[PACACHE[0]]);
- DIRDA[1] = PADA[1];
- DIRNL[1] = PALAST[1] - PAFIRST[1] + 1;
- PADISP[0] = 1;
- IOEND
- PAGE
- PROC SPLITAPEND;
- IOBEGIN(SPLITAPEND)
- #
- ** SPLITAPEND - SPLIT SECTOR JUST AFTER CURRENT CONTENT.
- *
- * SPLITAPEND IS USED TO OVERFLOW ANY NON-ROOT SECTOR UNDER
- * THE CONDITION THAT THE OVERFLOW TEXT BELONGS JUST AFTER ALL
- * OF THE TEXT ALREADY CONTAINED IN THE SECTOR. THUS, THE
- * SECTOR REMAINS JUST AS IT IS, AND A NEW SECTOR IS
- * CONSTRUCTED WHICH CONTAINS PRECISELY THE OVERFLOW TEXT.
- * SINCE NO EXISTING TEXT LEAVES THE SECTOR, THERE IS NO NEED
- * TO DISCARD IT AND BUILD TWO COMPLETELY NEW SECTORS. THUS,
- * SPLITAPEND IS MORE EFFICIENT THAN SPLITBEFORE OR
- * SPLITAFTER.
- *
- * THE NEWLY BUILT SECTOR BECOMES THE CURRENT SECTOR FOR THIS
- * LEVEL OF THE TREE. THE ORIGINAL SECTOR IS RELEASED FROM
- * OWNERSHIP.
- *
- * SPLITAPEND REQUIRES THAT AT LEAST ONE CACHE FRAME IS
- * AVAILABLE FOR ALLOCATION.
- *
- * SPLITAPEND FINISHES ITS PROCESSING BY SETTING UP PARAMETERS
- * FOR THE POSSIBLE CALLING OF ANY SPLIT ROUTINE FOR THE NEXT
- * HIGHER LEVEL. NOTE THAT ALL SPLIT ROUTINES ANTICIPATE THAT
- * THE CALLER WILL ITERATE SO LONG AS PARAMETERS INDICATE THAT
- * MORE SPLITTING NEEDS TO BE DONE. SINCE EACH SPLIT ROUTINE
- * DECREMENTS THE CURRENT TREE LEVEL, THE EFFECT IS TO WORK
- * FROM THE BOTTOM OF THE TREE TOWARDS THE ROOT, SPLITTING
- * UNTIL A LEVEL IS REACHED WHERE EVERYTHING FITS.
- *
- * ENTRY P<NEW> - LOCATION OF OVERFLOW TEXT.
- * NWNEW - NUMBER OF WORDS IN OVERFLOW TEXT.
- * PL - CURRENT LEVEL IN TREE PATH.
- * ALL PATH CONTROLS SETUP.
- * ALL CACHE CONTROLS SETUP.
- *
- * EXIT PL - DECREMENTED.
- * SECTOR AT ORIGINAL TREE LEVEL REBUILT TO CONTAIN
- * OVERFLOW TEXT.
- * PREVIOUS SECTOR AT ORIGINAL TREE LEVEL RELEASED.
- * NWNEW, NEWBEFORE, NWAFTER - SET FOR ITERATION.
- * NEWDA, NEWNL - SET FOR ITERATION.
- * DISP, PADISP[NEW PL] - INCREMENTED FOR ITERATION.
- *
- * CALLS ALLOC, ALLOCCACHE, MOVEWD.
- *
- * USES P<TOO>.
- #
- CLEAN; # CLEAN OLD BLOCK #
- ALLOC; # BUILD NEW BLOCK #
- ALLOCCACHE;
- P<TOO> = LOC(BFPRU[PACACHE[PL]]) + 1;
- MOVEWD(NWNEW,NEW,TOO);
- PAFINAL[PL] = NWNEW;
- PADIRTY[PL] = TRUE;
- PADISP[PL] = 1; # FIX UP PATH #
- PAFIRST[PL] = FIRST;
- PALAST[PL] = LAST;
- NEWDA[0] = PADA[PL]; # BUILD NEW DIR ENTRY #
- NEWNL[0] = PALAST[PL] - PAFIRST[PL] + 1;
- NWNEW = 1;
- PL = PL - 1; # SET UP NEXT PASS #
- NWBEFORE = PADISP[PL];
- NWAFTER = PAFINAL[PL] - PADISP[PL];
- DISP = PADISP[PL] + 1;
- PADISP[PL] = DISP;
- IOEND
- PAGE
- PROC SPLITBEFORE;
- IOBEGIN(SPLITBEFORE)
- #
- ** SPLITBEFORE - SPLIT SECTOR JUST BEFORE INSERTION POINT.
- *
- * SPLITBEFORE IS USED TO OVERFLOW ANY NON-ROOT SECTOR UNDER
- * THE CONDITION THAT THE OVERFLOW TEXT MUST BE INSERTED
- * SOMEWHERE IN THE MIDDLE OF THE TEXT ALREADY CONTAINED IN
- * THE SECTOR, AND NEW TEXT WOULD NOT FIT WITHIN THE FIRST
- * SECTOR OF THE NEW PAIR. THUS, THE SECTOR IS SPLIT JUST IN
- * FRONT OF THE INSERTION POINT, AND THE SECOND SECTOR
- * RESULTING FROM THE SPLIT WILL START WITH THE OVERFLOW TEXT
- * AND CONTINUE WITH THE REMAINING TEXT SPLIT OUT OF THE
- * ORIGINAL SECTOR.
- *
- * SINCE SOME EXISTING TEXT MUST BE REMOVED FROM THE CURRENT
- * SECTOR, IT IS NOT POSSIBLE TO KEEP USING THE SAME SECTOR,
- * UNDER THE RULE THAT NOTHING CAN BE POINTED TO WITHOUT FIRST
- * EXISTING ON DISK. THEREFORE, TWO COMPLETELY NEW SECTORS
- * ARE CREATED AND THE ORIGINAL SECTOR BECOMES A FRAGMENT.
- * SINCE THE INSERTED TEXT GOES INTO THE SECOND SECTOR OF THE
- * NEW PAIR, THAT IS THE SECTOR WHICH IS LEFT AS THE CURRENT
- * SECTOR FOR THIS TREE PATH LEVEL.
- *
- * SPLITBEFORE REQUIRES THAT AT LEAST ONE CACHE FRAME IS
- * AVAILABLE FOR ALLOCATION. THE EXISTING CACHE FRAME FOR
- * THIS TREE LEVEL IS RECYCLED TO PROVIDE THE SECOND SECTOR OF
- * CAPACITY. THE EXISTING CACHE FRAME IS FIRST SUBJECTED TO
- * THE NORMAL "CLEAN" ROUTINE TO ASSURE THAT ANY PENDING
- * CHANGES ARE FLUSHED TO DISK.
- *
- * SPLITBEFORE FINISHES ITS PROCESSING BY SETTING UP PARAMETERS
- * FOR THE POSSIBLE CALLING OF ANY SPLIT ROUTINE FOR THE NEXT
- * HIGHER LEVEL. NOTE THAT ALL SPLIT ROUTINES ANTICIPATE THAT
- * THE CALLER WILL ITERATE SO LONG AS PARAMETERS INDICATE THAT
- * MORE SPLITTING NEEDS TO BE DONE. SINCE EACH SPLIT ROUTINE
- * DECREMENTS THE CURRENT TREE LEVEL, THE EFFECT IS TO WORK
- * FROM THE BOTTOM OF THE TREE TOWARDS THE ROOT, SPLITTING
- * UNTIL A LEVEL IS REACHED WHERE EVERYTHING FITS.
- *
- * ENTRY P<NEW> - LOCATION OF OVERFLOW TEXT.
- * NWNEW - NUMBER OF WORDS IN OVERFLOW TEXT.
- * PL - CURRENT LEVEL IN TREE PATH.
- * ALL PATH CONTROLS SETUP.
- * ALL CACHE CONTROLS SETUP.
- *
- * EXIT PL - DECREMENTED.
- * SECTOR AT ORIGINAL TREE LEVEL REBUILT TO CONTAIN
- * OVERFLOW TEXT AND SPLIT-OFF ORGINAL TEXT.
- * PREVIOUS SECTOR AT ORIGINAL TREE LEVEL RELEASED.
- * NWNEW, NEWBEFORE, NWAFTER - SET FOR ITERATION.
- * NEWDA, NEWNL - SET FOR ITERATION.
- * DISP, PADISP[NEW PL] - INCREMENTED FOR ITERATION.
- *
- * CALLS ALLOC, ALLOCCACHE, MOVEWD, LAST.
- *
- * USES P<TOO>.
- #
- P<FROM> = LOC(BFPRU[PACACHE[PL]]) + 1; # SAVE OLD DATA #
- MOVEWD(PAFINAL[PL],FROM,OBF);
- DEALLOC; # FREE UP OLD BLOCK #
- ALLOC; # BUILD OFF BLOCK #
- P<TOO> = LOC(BFPRU[PACACHE[PL]]) + 1;
- MOVEWD(NWBEFORE,OBF,TOO);
- PAFINAL[PL] = NWBEFORE;
- ODA = PADA[PL]; # REMEMBER THIS #
- ONL = FIRST - PAFIRST[PL];
- PADIRTY[PL] = TRUE; # GET RID OF OFF BLOCK #
- CLEAN;
- ALLOC; # BUILD NEW BLOCK #
- ALLOCCACHE;
- P<TOO> = LOC(BFPRU[PACACHE[PL]]) + 1;
- MOVEWD(NWNEW,NEW,TOO);
- P<FROM> = LOC(OBF) + DISP-1;
- P<TOO> = LOC(BFPRU[PACACHE[PL]]) + NWNEW + 1;
- MOVEWD(NWAFTER,FROM,TOO);
- PAFINAL[PL] = NWNEW + NWAFTER;
- PADIRTY[PL] = TRUE;
- PADISP[PL] = PADISP[PL] - NWBEFORE; # FIX UP PATH #
- PAFIRST[PL] == FIRST;
- PALAST[PL] = PALAST[PL] + NL;
- LAST = PALAST[PL];
- NEWDA[0] = ODA; # BUILD NEW DIR ENTRIES #
- NEWNL[0] = ONL;
- NEWDA[1] = PADA[PL];
- NEWNL[1] = PALAST[PL] - PAFIRST[PL] + 1;
- NWNEW = 2;
- PL = PL - 1; # SET UP NEXT PASS #
- NWBEFORE = PADISP[PL] - 1;
- NWAFTER = PAFINAL[PL] - PADISP[PL];
- DISP = PADISP[PL] + 1;
- PADISP[PL] = DISP;
- IOEND
- PAGE
- PROC SPLITAFTER;
- IOBEGIN(SPLITAFTER)
- #
- ** SPLITAFTER - SPLIT SECTOR JUST AFTER INSERTION POINT.
- *
- * SPLITAFTER IS USED TO OVERFLOW ANY NON-ROOT SECTOR UNDER
- * THE CONDITION THAT THE OVERFLOW TEXT MUST BE INSERTED
- * SOMEWHERE IN THE MIDDLE OF THE TEXT ALREADY CONTAINED IN
- * THE SECTOR, AND NEW TEXT WOULD FIT WITHIN THE FIRST
- * SECTOR OF THE NEW PAIR. THUS, THE SECTOR IS SPLIT JUST
- * BEYOND THE INSERTED TEXT, AND THE SECOND SECTOR
- * RESULTING FROM THE SPLIT WILL START WITH THE REMAINING
- * TEXT SPLIT OUT OF THE ORGINAL SECTOR.
- *
- * SINCE SOME EXISTING TEXT MUST BE REMOVED FROM THE CURRENT
- * SECTOR, IT IS NOT POSSIBLE TO KEEP USING THE SAME SECTOR,
- * UNDER THE RULE THAT NOTHING CAN BE POINTED TO WITHOUT FIRST
- * EXISTING ON DISK. THEREFORE, TWO COMPLETELY NEW SECTORS
- * ARE CREATED AND THE ORIGINAL SECTOR BECOMES A FRAGMENT.
- * SINCE THE INSERTED TEXT GOES INTO THE FIRST SECTOR OF THE
- * NEW PAIR, THAT IS THE SECTOR WHICH IS LEFT AS THE CURRENT
- * SECTOR FOR THIS TREE PATH LEVEL.
- *
- * SPLITAFTER REQUIRES THAT AT LEAST ONE CACHE FRAME IS
- * AVAILABLE FOR ALLOCATION. THE EXISTING CACHE FRAME FOR
- * THIS TREE LEVEL IS RECYCLED TO PROVIDE THE SECOND SECTOR OF
- * CAPACITY. THE EXISTING CACHE FRAME IS FIRST SUBJECTED TO
- * THE NORMAL "CLEAN" ROUTINE TO ASSURE THAT ANY PENDING
- * CHANGES ARE FLUSHED TO DISK.
- *
- * SPLITAFTER FINISHES ITS PROCESSING BY SETTING UP PARAMETERS
- * FOR THE POSSIBLE CALLING OF ANY SPLIT ROUTINE FOR THE NEXT
- * HIGHER LEVEL. NOTE THAT ALL SPLIT ROUTINES ANTICIPATE THAT
- * THE CALLER WILL ITERATE SO LONG AS PARAMETERS INDICATE THAT
- * MORE SPLITTING NEEDS TO BE DONE. SINCE EACH SPLIT ROUTINE
- * DECREMENTS THE CURRENT TREE LEVEL, THE EFFECT IS TO WORK
- * FROM THE BOTTOM OF THE TREE TOWARDS THE ROOT, SPLITTING
- * UNTIL A LEVEL IS REACHED WHERE EVERYTHING FITS.
- *
- * ENTRY P<NEW> - LOCATION OF OVERFLOW TEXT.
- * NWNEW - NUMBER OF WORDS IN OVERFLOW TEXT.
- * PL - CURRENT LEVEL IN TREE PATH.
- * ALL PATH CONTROLS SETUP.
- * ALL CACHE CONTROLS SETUP.
- *
- * EXIT PL - DECREMENTED.
- * SECTOR AT ORIGINAL TREE LEVEL REBUILT TO CONTAIN
- * OVERFLOW TEXT AND SPLIT-OFF ORGINAL TEXT.
- * PREVIOUS SECTOR AT ORIGINAL TREE LEVEL RELEASED.
- * NWNEW, NEWAFTER, NWAFTER - SET FOR ITERATION.
- * NEWDA, NEWNL - SET FOR ITERATION.
- * DISP, PADISP[NEW PL] - INCREMENTED FOR ITERATION.
- *
- * CALLS ALLOC, ALLOCCACHE, MOVEWD, CLEAN, DEALLOC.
- *
- * USES P<TOO>, FIRST, LAST.
- #
- P<FROM> = LOC(BFPRU[PACACHE[PL]]) + 1; # SAVE OLD DATA #
- MOVEWD(PAFINAL[PL],FROM,OBF);
- DEALLOC; # FREE UP OLD BLOCK #
- ALLOC; # BUILD OFF BLOCK #
- P<FROM> = LOC(OBF) + DISP-1;
- P<TOO> = LOC(BFPRU[PACACHE[PL]]) + 1;
- MOVEWD(NWAFTER,FROM,TOO);
- PAFINAL[PL] = NWAFTER;
- ODA = PADA[PL]; # REMEMBER THIS #
- ONL = PALAST[PL] + NL - LAST;
- PADIRTY[PL] = TRUE; # GET RID OF OFF BLOCK #
- CLEAN;
- ALLOC; # BUILD NEW BLOCK #
- ALLOCCACHE;
- P<TOO> = LOC(BFPRU[PACACHE[PL]]) + 1;
- MOVEWD(NWBEFORE,OBF,TOO);
- P<TOO> = LOC(BFPRU[PACACHE[PL]]) + NWBEFORE + 1;
- MOVEWD(NWNEW,NEW,TOO);
- PAFINAL[PL] = NWBEFORE + NWNEW;
- PADIRTY[PL] = TRUE;
- FIRST = PAFIRST[PL]; # FIX UP PATH #
- LAST == PALAST[PL];
- LAST = LAST + NL;
- NEWDA[0] = PADA[PL]; # BUILD NEW DIR ENTRIES #
- NEWNL[0] = PALAST[PL] - PAFIRST[PL] + 1;
- NEWDA[1] = ODA;
- NEWNL[1] = ONL;
- NWNEW = 2;
- PL = PL - 1; # SET UP NEXT PASS #
- NWBEFORE = PADISP[PL] - 1;
- NWAFTER = PAFINAL[PL] - PADISP[PL];
- DISP = PADISP[PL] + 1;
- IOEND
- PAGE
- PROC CHANGE; # CHANGE TREE #
- IOBEGIN(CHANGE)
- #
- ** CHANGE - APPLY CHANGES TO TREE STRUCTURE.
- *
- * CHANGE IS THE PRINCIPAL ALGORITHM USED TO MANIPULATE THE
- * TREE STRUCTURE. CHANGE IS DESIGNED TO BE CALLED BY THE
- * INS, REP, AND DEL ENTRY POINTS. THE ALGORITHM WORKS IN
- * THREE PHASES. THE FIRST PHASE TAKES CARE OF CASES WHERE AN
- * INSERTION OF A LINE OR THE REPLACEMENT OF A LINE WITH AN
- * ENLARGED VERSION WILL CAUSE THE CURRENT DATA SECTOR (THE
- * BOTTOM LEVEL OF THE TREE STRUCTURE) TO OUTGROW THE SECTOR
- * CAPACITY AND CAUSE SPLITTING INTO TWO SECTORS. THIS CAUSES
- * ADDITIONAL DIRECTORY ENTRIES TO BE REQUIRED IN THE HIGHER
- * TREE LEVELS, WHICH CAN IN TURN CAUSE ONE OR MORE DIRECTORY
- * LEVELS TO BE SPLIT INTO MULTIPLE SECTORS. IN THE EXTREME
- * CASE, THE ROOT LEVEL OF THE TREE MAY OVERFLOW, IN WHICH
- * CASE A NEW INTERMEDIATE LEVEL OF THE TREE MUST BE CREATED,
- * WITH THE ROOT SECTOR CONVERTED INTO A DIRECTORY FOR THE
- * INTERMEDIATE LEVEL.
- *
- * AFTER THE FIRST PHASE HAS EXHAUSTED ITS ITERATION, THE
- * SECOND PHASE TAKES OVER, IDENTIFYING ANY TREE LEVEL
- * STARTING WITH THE DATA LEVEL WHICH HAS BECOME EMPTY AS THE
- * RESULT OF DELETIONS. THE SECOND PHASE IS THUS MUTUALLY
- * EXCLUSIVE OF THE FIRST PHASE.
- *
- * THE THIRD PHASE IS A CLEANUP OPERATION. WHILE EACH OF THE
- * FIRST TWO PHASES MAY BE A NO-OP, (AND AT LEAST ONE OF THE
- * FIRST TWO PHASES WILL INDEED BE A NO-OP), THE THIRD PHASE
- * ALWAYS IS IN EFFECT. THE CLEANUP OPERATION CONSISTS OF THE
- * APPLICATION OF LEFT-OVER CHANGES. LEFTOVER CHANGES MAY
- * CONSTITUTE THE ENTIRE CHANGE IF NEITHER PRELIMINARY PHASE
- * WAS NEEDED, OR IF ONE OF THE FIRST TWO PHASES WAS USED,
- * THEN IT WILL HAVE LEFT RESIDUAL CHANGES TO BE APPLIED ONE
- * LEVEL CLOSER TO THE ROOT THAN THE LAST LEVEL AFFECTED BY
- * THE SPLITTING OR COLLAPSING.
- *
- * ACTUAL APPLICATION OF CHANGES, WHETHER PERFORMED BY THE
- * THIRD PHASE OF THE CHANGE ROUTINE, OR WITHIN ONE OF THE
- * SPLIT ROUTINES SELECTED BY THE FIRST PHASE OF THE CHANGE
- * ROUTINE, SIMPLY CONSIST OF OPENING UP A GAP AT THE RIGHT
- * MEMORY LOCATION, OF ZERO, POSITIVE, OR NEGATIVE LENGTH, AND
- * MOVING IN THE TEXT OF THE CHANGE, WHICH CAN CONSIST OF ZERO
- * OR MORE WORDS.
- *
- * THE CLEANUP PHASE ALSO INCREMENTS OR DECREMENTS THE COUNT
- * OF LINES BRACKETED BY EACH LEVEL OF THE TREE.
- *
- * ENTRY PALVL - DEEPEST LEVEL IN TREE STRUCTURE.
- * PL - CURRENT TREE LEVEL MUST EQUAL PALVL.
- * NL - CHANGE IN NUMBER OF LINES IN WORKFILE.
- * NWBEFORE - NUMBER OF WORDS BEFORE POINT OF CHANGE.
- * NWAFTER - NUMBER OF WORDS AFTER POINT OF CHANGE.
- * NWNEW - NUMBER OF WORDS IN CHANGED TEXT.
- * DISP - POINTS JUST AFTER CURRENT LINE.
- * LINEBUF - CONTAINS TEXT OF CHANGE.
- * ALL PATH CONTROLS - SETUP.
- * ALL CACHE CONTROLS - SETUP.
- *
- * EXIT PL - ZERO.
- * PALVL - INCREMENTED/DECREMENTED IF TREE DEPTH CHANGED.
- * DISP, CURNW - BRACKET NEW CURRENT LINE.
- * ALL PATH, CACHE CONTROLS - UPDATED.
- * FET AND CIRCULAR BUFFER USED IF NEEDED.
- *
- * CALLS COUNTCACHE, FLUSHCACHE, SPLITTOP, SPLITAPEND,
- * SPLITBEFORE, SPLITAFTER, RECLAIMCACHE, DEALLOC, CLEAN,
- * MOVEWD.
- *
- * USES P<NEW>, P<FROM>, P<TOO>, FIRST, LAST, NWNEW,
- * NWBEFORE, NWAFTER, NL.
- #
- P<NEW> = LOC(LINEBUF); # SET THINGS UP #
- FIRST = CURRENT + NL;
- LAST = FIRST;
- CURNW = NWNEW;
- FOR PL = PL WHILE NWBEFORE+NWNEW+NWAFTER GR 63 DO
- BEGIN # DO ALL SPLITS #
- IF COUNTCACHE LQ 2 THEN FLUSHCACHE;
- IF PL EQ 0 THEN SPLITTOP;
- IF NWBEFORE EQ PAFINAL[PL] THEN SPLITAPEND;
- ELSE IF NWBEFORE+NWNEW LQ 63 THEN SPLITAFTER;
- ELSE SPLITBEFORE;
- RECLAIMCACHE;
- P<NEW> = LOC(NDIR);
- END
- FOR PL = PL WHILE NWBEFORE+NWNEW+NWAFTER EQ 0 DO
- BEGIN # DO ALL COLLAPSING #
- DEALLOC;
- CLEAN; # TO FREE UP CACHE FRAME #
- PALVL = PALVL - 1;
- PL = PL - 1;
- NWBEFORE = PADISP[PL] - 1;
- NWAFTER = PAFINAL[PL] - PADISP[PL];
- DISP = PADISP[PL] + 1;
- END
- P<FROM> = LOC(BFPRU[PACACHE[PL]]) + DISP; # SLIDE AFTER #
- P<TOO> = LOC(BFPRU[PACACHE[PL]]) + NWBEFORE +NWNEW + 1;
- MOVEWD(NWAFTER,FROM,TOO);
- P<TOO> = LOC(BFPRU[PACACHE[PL]]) + NWBEFORE + 1; # MOVE IN NEW #
- MOVEWD(NWNEW,NEW,TOO);
- PAFINAL[PL] = NWBEFORE + NWNEW + NWAFTER;
- PADIRTY[PL] = TRUE;
- PALAST[PL] = PALAST[PL] + NL; # FIX UP PATH #
- FOR PL = PL-1 STEP -1 UNTIL 0 DO # UPDATE HIGHER DIRS #
- BEGIN
- P<PRU> = LOC(BFPRU[PACACHE[PL]]);
- DIRNL[PADISP[PL]] = DIRNL[PADISP[PL]] + NL;
- PADIRTY[PL] = TRUE;
- PALAST[PL] = PALAST[PL] + NL;
- END
- CURRENT = CURRENT + NL; # UPDATE CURRENT #
- IOEND
- PAGE
- PROC INS;
- IOBEGIN(INS)
- #
- ** INS - INTERFACE FOR INSERTION OF LINES.
- *
- * ENTRY CURRENT - CURRENT LINE.
- * LINEBUF - LINE IMAGE.
- * ALL PATH AND CACHE CONTROLS SETUP.
- *
- * EXIT CURRENT - INCREMENETED.
- * ALL PATH AND CACHE CONTROL UPDATED.
- *
- * CALLS LINESZ, CHANGE, WIOSTAT.
- *
- * USES PL, DISP, NL, NWBEFORE, NWNEW, NWAFTER, DISP.
- #
- CONTROL IFEQ MULTI,1;
- WIOSTAT(0); # ACCUMULATE LINE ACCESES #
- CONTROL FI;
- PL = PALVL; # STANDARD INITCHANGE #
- DISP = PADISP[PL];
- NL = 1;
- NWBEFORE = DISP + CURNW - 1;
- NWNEW = LINESZ(LINEBUF);
- NWAFTER = PAFINAL[PL] - DISP - CURNW + 1;
- DISP = DISP + CURNW;
- PADISP[PL] = DISP;
- CHANGE;
- IOEND
- PROC REP;
- IOBEGIN(REP)
- #
- ** REP - INTERFACE FOR REPLACEMENT OF LINES.
- *
- * ENTRY CURRENT - CURRENT LINE.
- * LINEBUF - LINE IMAGE.
- * ALL PATH AND CACHE CONTROLS SETUP.
- *
- * EXIT CURRENT - UNCHANGED.
- * ALL PATH AND CACHE CONTROL UPDATED.
- *
- * CALLS LINESZ, CHANGE, WIOSTAT.
- *
- * USES PL, DISP, NL, NWBEFORE, NWNEW, NWAFTER, DISP.
- #
- CONTROL IFEQ MULTI,1;
- WIOSTAT(0); # ACCUMULATE LINE ACCESES #
- CONTROL FI;
- PL = PALVL; # STANDARD INITCHANGE #
- DISP = PADISP[PL];
- NL = 0;
- NWBEFORE = DISP - 1;
- NWNEW = LINESZ(LINEBUF);
- NWAFTER = PAFINAL[PL] - DISP - CURNW + 1;
- DISP = DISP + CURNW;
- CHANGE;
- IOEND
- PROC DEL;
- IOBEGIN(DEL)
- #
- ** DEL - INTERFACE FOR DELETION OF LINES.
- *
- * ENTRY CURRENT - CURRENT LINE.
- * ALL PATH AND CACHE CONTROLS SETUP.
- * DELETCTL - POST-POSITIONING INCREMENT.
- *
- * EXIT CURRENT - INCREMENTED IF DELETCTL WAS ONE.
- * LINEBUF - NEW CURRENT LINE IS READ UP.
- * ALL PATH AND CACHE CONTROL UPDATED.
- * DELETCTL - FORCED ZERO IF DELETED LAST LINE.
- *
- * CALLS CHANGE, WIOSTAT, POSR.
- *
- * USES PL, DISP, NL, NWBEFORE, NWNEW, NWAFTER, DISP,
- * P<MVLNBUF>, NEWCURL.
- #
- CONTROL IFEQ MULTI,1;
- WIOSTAT(0); # ACCUMULATE LINE ACCESES #
- CONTROL FI;
- PL = PALVL; # STANDARD INITCHANGE #
- DISP = PADISP[PL];
- NL = -1;
- NWBEFORE = DISP - 1;
- NWNEW = 0;
- NWAFTER = PAFINAL[PL] - DISP - CURNW + 1;
- DISP = DISP + CURNW;
- CHANGE;
- IF PALAST[0] LQ CURRENT THEN DELETCTL=0;
- CURRENT=CURRENT+DELETCTL;
- NEWCURL=CURRENT;
- P<MVLNBUF>=LOC(LINEBUF);
- POSR;
- P<MVLNBUF>=0;
- IOEND
- PAGE
- PROC INIT;
- BEGIN
- #
- ** INIT - INITIALIZE MEMORY CELLS FOR WORKIO.
- *
- * ENTRY NO CONDITIONS.
- *
- * EXIT P<LINEBUF> -POINTS TO LIN ARRAY.
- * ALL ELEMENTS OF PATH ARRAY - NOMINAL.
- * ALL CACHE CONTROLS - NOMINAL.
- * READ LIST (RDLIST, RDIN, RDOUT) - EMPTY.
- * FLAGS (IOACT, IOREAD, IOWRITE) - FALSE.
- * ARRAYLEN, DATALEN, ARRAYPRUS, DATAPRUS - INITIALIZED.
- * SEGEMENTVER - ZEROED OUT.
- #
- P<LINEBUF>=LOC(LIN);
- FOR PL = 1 STEP 1 UNTIL MAXDEPTH DO # INIT PATH #
- BEGIN
- PAFIRST[PL] = 0;
- PALAST[PL] = 0;
- PADISP[PL] = 0;
- PAHEAD[PL] = 0;
- END
- FOR PL = 0 STEP 1 UNTIL MAXCACHE DO # INIT CACHE CTL #
- BEGIN
- CACHEOWNED[PL]=FALSE; CACHEDIRTY[PL]=FALSE;
- CACHEAGE[PL]=-1;
- BFHEAD[PL]=0;
- END
- FOR RDIN = 0 STEP 1 UNTIL RDLIM DO RDLIST[RDIN] = 0;
- IOACT = FALSE; # INIT IO #
- IOAPEND = FALSE;
- IOWRITE = FALSE;
- IOREAD = FALSE;
- CURNW = 0;
- SEGMENTVER=0;
- ARRAYLEN=LOC(ARRAYEND)-LOC(ARRAYSTART);
- ARRAYPRUS=(ARRAYLEN+O"77")/O"100";
- DATALEN=LOC(DATAEND)-LOC(DATASTART);
- DATAPRUS=(DATALEN+O"77")/O"100";
- END
- PAGE
- PROC RESUMIO;
- IOBEGIN(RESUMIO)
- #
- ** RESUMIO - RESUME EDITOR STATUS FROM LEFTOVER WORKFILE.
- *
- * RESUMIO ATTEMPTS TO VALIDATE A FILE AS CONTAINING THE TEXT
- * AND STATUS LEFT BY A PREVIOUS EDIT SESSION, OR BY A
- * SINGLE/MULTI USER TRANSITION. SINCE THE SCALAR AND ARRAY
- * DATA SEGMENTS CONTAIN NEARLY ALL EDITOR DATA, SUCCESSFUL
- * EXECUTION OF RESUMIO CHANGES EVERYTHING.
- *
- * THE FOLLOWING CONDITIONS ARE REQUIRED TO VALIDATE AN
- * APPARENT WORKFILE AS A LEGITIMATE BASIS FOR RESUMPTION --
- *
- * 1. THE FIRST WORD MUST BE FORMATTED AS A ROOT SECTOR
- * HEADER WORD. THE DISK ADDRESS FIELD MUST BE ONE AND
- * THE TOP FLAG MUST BE ON AND THE DIRECTORY AND DATA
- * FLAGS MUST BE UNEQUAL.
- *
- * 2. THE FIRST RECORD OF THE FILE MUST BE OF LENGTH
- * 64 WORDS LONGER THAN THE SCALAR DATA SEGMENT, AND
- * THE SECOND RECORD OF THE FILE MUST EXACTLY MATCH
- * THE LENGTH OF THE ARRAY SEGMENT.
- *
- * 3. THE SEGMENTLEN1 AND SEGMENTLEN2 FIELDS OF THE SCALAR
- * SEGMENT MUST MATCH THE ABOVE LENGTHS, AND THE
- * SEGMENTVER FIELD MUST MATCH THE VERSION NUMBER
- * COMPILED INTO THIS PROGRAM.
- *
- * AFTER READING UP ALL EDITOR DATA, THE FOLLOWING WORKIO
- * CONTROLS ARE RE-INITIALIZED - THE PATH VECTOR IS REFRESHED
- * TO MATCH THE CURRENT LINE, THE SCHEDULING FLAGS (IOACT,
- * IOREAD, ETC.) ARE CLEARED, MAXDA AND DANEXT ARE BASED ON
- * FILE SIZE, AND SEGMENTVER IS CLEARED. THE WORKFILE IS THEN
- * IMMEDIATELY CHECKPOINTED SO THAT IT CANNOT BE RESUMED
- * AGAIN, THUS INTERLOCKING IT.
- *
- * ENTRY NO CONDITIONS.
- *
- * EXIT EVERYTHING IN THE WHOLE EDITOR IS CHANGED.
- * IORESUMED - SUCCESS/FAILURE INDICATOR.
- *
- * CALLS INIT, INITFET, BUFUSAGE, ALLOCCACHE, RDWBUF, READ,
- * WAIT, TRAGIC, SKIPEI, POSR, CLEANALL.
- #
- INIT;
- IORESUMED=FALSE;
- INITFET(DISK,DSKSIZ);
- REWIND(FET,0); # TRY TO READ PRU 1 #
- WAIT;
- READ(FET,0);
- WAIT;
- IF BUFUSAGE GR O"100" THEN
- BEGIN
- PL=0;
- PADA[0]=1;
- ALLOCCACHE;
- P<TOO>=LOC(BFPRU[PACACHE[0]]);
- RDWBUF(O"100");
- PAHEAD[0] = BFHEAD[PACACHE[0]];
- END
- IF PADA[0] EQ 1 AND PATOP[0]
- AND BOOLDIFF(PADIR[0],PADATA[0]) THEN
- BEGIN
- # READ FIRST FOUR WORDS TO VERIFY SEGMENT DESCRIPTORS #
- P<TOO>=LOC(DATASTART);
- NWNEW=BUFUSAGE;
- NWNEW=MIN(NWNEW,4);
- RDWBUF(NWNEW);
- IORESUMED=FALSE;
- IF SEGMENTVER NQ IOVERSION OR SEGMENTLEN1 NQ DATALEN
- OR SEGMENTLEN2 NQ ARRAYLEN THEN IORET
- # SEGMENT DESCRIPTORS VALID, READ REST OF SCALAR SEGMENT #
- P<TOO>=LOC(DATASTART)+4;
- NWNEW=BUFUSAGE;
- NWNEW=MIN(DATALEN-4,NWNEW);
- RDWBUF(NWNEW);
- READ(FET,0);
- WAIT;
- # READ ARRAY SEGMENT #
- P<TOO>=LOC(ARRAYSTART);
- NWNEW=BUFUSAGE;
- NWNEW=MIN(ARRAYLEN,NWNEW);
- RDWBUF(NWNEW);
- IF ABORTED THEN TRAGIC(ERRSTRING);
- SKIPEI(FET,0);
- WAIT;
- MAXDA=FETCRI-1;
- DANEXT=FETCRI;
- PADISP[0] = 1; # SET UP PATH[0] #
- PAFIRST[0] = 0;
- PALAST[0] = -1;
- P<PRU> = LOC(BFPRU[PACACHE[0]]);
- IF PADIR[0] THEN
- BEGIN
- FOR DISP = 1 STEP 1 UNTIL PAFINAL[0]
- DO PALAST[0] = PALAST[0] + DIRNL[DISP];
- END
- ELSE # NOTE INTERNAL CHARSET SIGN BIT USAGE #
- BEGIN
- FOR DISP = 1 STEP 1 UNTIL PAFINAL[0]
- DO IF B<0,1>DATWORD[DISP] NQ 0 THEN PALAST[0] = PALAST[0] + 1;
- END
- IORESUMED=TRUE; # RESET FLAGS READ WITH DATA #
- IOACT=FALSE;
- IOREAD=FALSE;
- IOWRITE=FALSE;
- IOAPEND=FALSE;
- PALVL = 0; # BUILD REST OF PATH #
- NEWCURL=0;
- P<MVLNBUF>=LOC(LINEBUF);
- POSR;
- P<MVLNBUF>=0;
- SEGMENTVER=0; # INTERLOCK FILE ONWESHIP #
- CLEANALL;
- END
- IOEND
- PAGE
- CONTROL IFEQ SINGLE,1;
- PROC INITIO;
- IOBEGIN(INITIO)
- #
- ** INITIO - FORMAT A NEW WORKFILE.
- *
- * INITIO IS USED TO BUILD A WORKFILE FROM SCRATCH OR TO
- * DISCARD OLD WORKFILE CONTENT AND REFRESH IT.
- *
- * ENTRY NO CONDITIONS.
- *
- * EXIT FILE INITIALIZED.
- * ALL PATH CONTROLS NOMINAL.
- * ALL CACHE CONTROL NOMINAL.
- * MAXDA - ZERO
- * DANEXT - FIRST ALLOCATABLE DISK ADDRESS RIGHT AFTER
- * ROOT SECTOR, AND SCALAR AND ARRAY DATA SEGMENTS.
- * IORESUMED - TRUE TO SHOW WORKIO ACTIVE.
- * SEGMENTVER - ZERO IN MEMORY AND ON DISK TO INTERLOCK.
- *
- * CALLS INITFET, EVICT, WAIT, INIT, ALLOCCACHE, CLEANALL.
- #
- INITFET(DISK,DSKSIZ);
- EVICT(FET,0);
- WAIT;
- INIT;
- MAXDA = 0; # SET MAXDA AND DANEXT #
- DANEXT = 2+DATAPRUS+ARRAYPRUS;
- PAHEAD[0] = 0; # BUILD TOP BLOCK #
- PADATA[0] = TRUE;
- PATOP[0] = TRUE;
- PADIRTY[0] = TRUE;
- PADA[0] = 1;
- PAFINAL[0] = 1;
- PL=0;
- ALLOCCACHE;
- P<PRU> = LOC(BFPRU[PACACHE[0]]);
- DATWORD[1] = NULLIN;
- CURNW = 1;
- PADEPTH[0] = 0;
- PADISP[0] = 1; # SET UP PATH #
- PAFIRST[0] = 0;
- PALAST[0] = 0;
- PALVL = 0;
- CURRENT = 0;
- IORESUMED=TRUE; # SHOW WORKIO ALIVE #
- SEGMENTVER = 0; # INTERLOCK FILE OWNERSHIP #
- CLEANALL;
- IOEND
- CONTROL FI;
- PAGE
- PROC CHECKIO;
- IOBEGIN(CHECKIO)
- #
- ** CHECKIO - CHECKPOINT WORKFILE.
- *
- * CHECKIO IS USED TO ASSURE THAT ALL MEMORY DATA IS FULLY
- * WRITTEN TO DISK. THIS CAN BE USED TO PREPARE FOR END OF
- * JOB STEP OR FOR TRANSITION BETWEEN SINGLE AND MULTIPLE USER
- * VERSIONS OF THE EDITOR. BY CHECKPOINTING THE WORKFILE, IT
- * BECOMES POSSIBLE TO EXECUTE THE RESUMIO ROUTINE AND FULLY
- * RESTORE THE EDITOR STATUS.
- *
- * ENTRY IORESUMED - SHOWS WHETHER WORKFILE MANAGER EVER ACTIVE.
- * CURRENT - CURRENT LINE ORDINAL.
- *
- * EXIT SEGMENTVER, SEGMENTLEN1, SEGMENTLEN2 - SETUP.
- * CACHE FLUSHED, FET AND CIRCULAR BUFFER COMPLETE.
- *
- * CALLS CLEANALL.
- #
- IF NOT IORESUMED THEN IORET # WORKIO NEVER ALIVE #
- SAVECURL=CURRENT;
- SEGMENTVER = IOVERSION; # SHOW VALID WORKFILE FORMAT #
- SEGMENTLEN1 = DATALEN;
- SEGMENTLEN2 = ARRAYLEN;
- CLEANALL; # WRITE OUT WHOLE PATH #
- IOEND
- END TERM
cdc/nos2.source/opl871/fsework.txt ยท Last modified: 2023/08/05 17:24 by Site Administrator