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
  1. PROC FSEWORK;
  2. BEGIN
  3.  
  4.  
  5. #
  6. *** FSEWORK - WORKFILE ACCESS METHOD FOR FULL SCREEN EDITOR.
  7. *
  8. * COPYRIGHT CONTROL DATA SYSTEMS INC. 1992.
  9. #
  10.  
  11. DEF LISTCON #0#;
  12.  
  13. CONTROL EJECT; # UNIVERSAL DEFINITIONS #
  14.  
  15. *IFCALL SINGLE,COMFSGL
  16. *IFCALL ONLY,COMFONL
  17. *IFCALL MULTI,COMFMLT
  18. *CALL COMFFSE
  19.  
  20.  
  21. CONTROL IFEQ MULTI,1;
  22. DEF RECALL(AA) #SMFRCL(AA)#;
  23. DEF DELAY #SMFDLY#;
  24. XREF PROC SMFRCL;
  25. XREF PROC SMFDLY;
  26. CONTROL FI;
  27. CONTROL IFEQ SINGLE,1;
  28. XREF PROC RECALL;
  29. DEF DELAY #RECALL(0)#;
  30. CONTROL FI;
  31.  
  32. XREF # SYSTEM PROCS #
  33. BEGIN
  34. PROC WRITE;
  35. PROC REWRITE;
  36. PROC RPHR;
  37. PROC RPHRLS;
  38. PROC SKIPEI;
  39. PROC REWIND;
  40. PROC READ;
  41. PROC WRITER;
  42. PROC WRITEW;
  43. PROC REWRITR;
  44. CONTROL IFEQ SINGLE,1;
  45. PROC EVICT;
  46. CONTROL FI;
  47. END
  48.  
  49. XREF # COMPASS PROCS #
  50. BEGIN
  51. PROC MOVEWD;
  52. PROC EXCHWD;
  53. FUNC MOVELN;
  54. FUNC LINESZ;
  55. END
  56.  
  57. XREF
  58. BEGIN
  59. *CALL COMFXSB
  60. END
  61.  
  62. XDEF
  63. BEGIN
  64. *CALL COMFXWK
  65. END
  66.  
  67. # COMMON DATA #
  68.  
  69. CONTROL IFEQ MULTI,1;
  70. XREF ARRAY RENTSTK [1:MAXREENT]; # SUBROUTINE STACK #
  71. BEGIN
  72. ITEM RSTK;
  73. END
  74. XREF ITEM RSTKPTR;
  75. XREF PROC WIOSTAT;
  76. CONTROL FI;
  77.  
  78. *CALL COMFDS1
  79. *CALL COMFVD2
  80. *CALL COMFDS2
  81. PAGE
  82.  
  83.  
  84. PROC INITFET(BUFF,LEN); # INITIALIZE FET #
  85. BEGIN
  86. #
  87. ** INITFET - INITIALIZE FILE ENVIRONMENT TABLE.
  88. *
  89. * INITFET IS SPECIALIZED FOR THE WORKFILE MANAGER. THE FET
  90. * IS ASSUMED TO BE MAPPED BY THE BASED ARRAY "FET". THE
  91. * LENGTH OF THE FET IS ASSUMED TO BE AT LEAST SEVEN WORDS,
  92. * AND RANDOM I/O FLAGS WILL BE SET.
  93. *
  94. * ENTRY BUFF - THE ARRAY PROVIDED AS A BUFFER.
  95. * LEN - INTEGER LENGTH OF BUFFER.
  96. *
  97. * EXIT FET - INITIALIZED FOR RANDOM I/O.
  98. * QUARTER - INITIALIZED AS APPROX LEN/4.
  99. #
  100. ARRAY BUFF;;
  101. ITEM LEN;
  102. QUARTER=(LEN+O"300")/4;
  103. FETNAM = WORKNAM;
  104. FETCOD = 0;
  105. FETDUN = TRUE;
  106. FETR = TRUE;
  107. FETW = FALSE;
  108. FETOUT = LOC(BUFF); FETLIM = LOC(BUFF) + LEN;
  109. FETL = 2;
  110. FETFIR = LOC(BUFF); FETIN = LOC(BUFF);
  111. END
  112.  
  113.  
  114. FUNC BUFAVAIL I;
  115. BEGIN
  116. #
  117. ** BUFAVAIL - FUNCTION TO COMPUTE BUFFER FREE SPACE.
  118. *
  119. * BUFAVAIL COMPUTES THE SPACE AVAILABLE IN THE CIRCULAR
  120. * BUFFER ASSIGNED TO THE FET MAPPED BY THE BASED ARRAY
  121. * "FET".
  122. *
  123. * ENTRY FET - FET.
  124. *
  125. * EXIT BUFAVAIL - WORDS OF SPACE STILL AVAILABLE FOR DATA.
  126. #
  127. IF FETIN LS FETOUT THEN BUFAVAIL=FETOUT-FETIN;
  128. ELSE BUFAVAIL=(FETLIM-FETFIR)-(FETIN-FETOUT);
  129. END
  130.  
  131.  
  132. FUNC BUFUSAGE I;
  133. BEGIN
  134. #
  135. ** BUFUSAGE - FUNCTION TO COMPUTE BUFFER UTILIZATION.
  136. *
  137. * BUFUSAGE IS THE COUTERPART TO BUFAVAIL, COMPUTING THE
  138. * NUMBER OF WORDS ALREADY USED IN THE CIRCULAR BUFFER
  139. * ASSIGNED TO THE FET MAPPED BY BASED ARRAY "FET".
  140. *
  141. * ENTRY FET - FET.
  142. *
  143. * EXIT BUFUSAGE - RESULT.
  144. #
  145. IF FETIN GQ FETOUT THEN BUFUSAGE=FETIN-FETOUT;
  146. ELSE BUFUSAGE=(FETLIM-FETFIR)-(FETOUT-FETIN);
  147. END
  148.  
  149.  
  150. FUNC LSTUSAGE I;
  151. BEGIN
  152. #
  153. ** LSTUSAGE - COMPUTE UTILIZATION OF READ LIST.
  154. *
  155. * LSTUSAGE COMPUTES THE NUMBER OF WORDS USED IN THE READ
  156. * LIST.
  157. *
  158. * ENTRY RDIN, RDOUT - BOUNDS FOR PORTION OF LIST USED.
  159. * LSTSIZE - SIZE OF LIST.
  160. *
  161. * EXIT LSTUSAGE - RESULT.
  162. #
  163. LSTUSAGE=RDIN-RDOUT;
  164. IF RDIN LS RDOUT THEN LSTUSAGE=LSTSIZE-1-RDOUT+RDIN;
  165. END
  166.  
  167.  
  168. FUNC LSTAVAIL I;
  169. BEGIN
  170. #
  171. ** LSTAVAIL - COMPUTE SPACE AVAILABLE IN READ LIST.
  172. *
  173. * LSTAVAIL COMPUTES THE NUMBER OF WORDS AVAILABLE FOR USE
  174. * IN THE RANDOM READ LIST.
  175. *
  176. * ENTRY - RDIN, RDOUT, LSTSIZE - CONTROL READ LIST.
  177. *
  178. * EXIT LSTAVAIL - RESULT.
  179. *
  180. * CALLS LSTUSAGE.
  181. #
  182. LSTAVAIL=LSTSIZE-1-LSTUSAGE;
  183. END
  184.  
  185.  
  186. PROC RDWBUF(LENGTH);
  187. BEGIN
  188. #
  189. ** RDWBUF - READ WORDS FROM BUFFER WITH NO I/O.
  190. *
  191. * RDWBUF FUNCTIONS AS A SPECIALIZED READW MACRO. A STANDARD
  192. * FET IS ASSUMED AND THE DATA TRANSFER WORKING BUFFER IS
  193. * ASSUMED TO BE MAPPED BY A STANDARD BASED ARRAY. MOST
  194. * IMPORTANT, THIS ROUTINE IS GUARANTEED TO NEVER CALL CIO.
  195. * THE CALLER IS RESPONSIBLE TO ASSURE THAT THE CIRCULAR
  196. * BUFFER HAS ENOUGH DATA TO SATISFY THE REQUEST.
  197. *
  198. * ENTRY LENGTH - AMMOUNT OF DATA NEEDED.
  199. * FET - FET AND CIRCULAR BUFFER HAVE ENOUGH DATA.
  200. * TOO - MAPPED TO USER'S WORKING BUFFER.
  201. *
  202. * EXIT FET - INDICATES DATA TRANSFERRED.
  203. * TOO - DATA IS TRANSFERRED.
  204. *
  205. * CALLS MOVEWD, TRAGIC, BUFUSAGE.
  206. *
  207. * USES FROM.
  208. #
  209. ITEM LENGTH, X1;
  210. IF BUFUSAGE LS LENGTH OR LENGTH LS 0 THEN
  211. BEGIN
  212. TRAGIC(" WORKFILE BUFFER EMPTY ON READ.$");
  213. END
  214. P<FROM>=FETOUT;
  215. IF FETIN GR FETOUT OR FETLIM-FETOUT GR LENGTH THEN
  216. BEGIN
  217. MOVEWD(LENGTH,FROM,TOO);
  218. FETOUT=FETOUT+LENGTH;
  219. END
  220. ELSE
  221. BEGIN
  222. X1=FETLIM-FETOUT;
  223. MOVEWD(X1,FROM,TOO);
  224. P<TOO>=LOC(TOO)+X1;
  225. X1=LENGTH-X1;
  226. P<FROM>=FETFIR;
  227. MOVEWD(X1,FROM,TOO);
  228. FETOUT=FETFIR+X1;
  229. END
  230. END
  231.  
  232.  
  233. PROC WTWBUF(LENGTH);
  234. BEGIN
  235. #
  236. ** WTWBUF - WRITE WORDS TO BUFFER WTH NO I/O.
  237. *
  238. * WTWBUF PERFORMS THE ROLE OF THE WRITEW MACRO, BUT IS
  239. * SPECIALIZED TO USE AN ASSUMED FET AND WORKING BUFFER, AND
  240. * IS GUARANTEED TO NEVER PERFORM ANY CIO CALLS. THE CALLER
  241. * IS RESPONSIBLE TO ASSURE THE CIRCULAR BUFFER HAS ROOM TO
  242. * ACCEPT THE DATA.
  243. *
  244. * ENTRY LENGTH - NUMBER OF WORDS.
  245. * FET - THE CIRCULAR BUFFER HAS ROOM.
  246. * FROM - MAPPED ONTO WORKING BUFFER.
  247. *
  248. * EXIT FET - THE CIRCULAR BUFFER HAS DATA.
  249. *
  250. * CALLS BUFAVAIL, TRAGIC, MOVEWD.
  251. *
  252. * USES TOO.
  253. #
  254. ITEM LENGTH, X1;
  255. IF BUFAVAIL LS LENGTH OR LENGTH LS 0 THEN
  256. BEGIN
  257. TRAGIC(" WORKFILE BUFFER FULL ON WRITE.$");
  258. END
  259. P<TOO>=FETIN;
  260. IF FETOUT GR FETIN OR FETLIM-FETIN GR LENGTH THEN
  261. BEGIN
  262. MOVEWD(LENGTH,FROM,TOO);
  263. FETIN=FETIN+LENGTH;
  264. END
  265. ELSE
  266. BEGIN
  267. X1=FETLIM-FETIN;
  268. MOVEWD(X1,FROM,TOO);
  269. P<FROM>=LOC(FROM)+X1;
  270. X1=LENGTH-X1;
  271. P<TOO>=FETFIR;
  272. MOVEWD(X1,FROM,TOO);
  273. FETIN=FETFIR+X1;
  274. END
  275. END
  276.  
  277. PROC WAIT;
  278. IOBEGIN(WAIT)
  279. #
  280. ** WAIT - WAIT (RECALL) FOR I/O TO FINISH.
  281. *
  282. * WAIT DELAYS THIS TASK UNTIL THE FET IS FOUND TO INDICATE
  283. * COMPLETION OF A PREVIOUS I/O OPERATION. WAIT IS A NO-OP
  284. * IF THE FET ALREADY INDICATES COMPLETION.
  285. *
  286. * ENTRY FETDUN - SHOWS WHETHER DELAYS REALLY NEEDED.
  287. *
  288. * EXIT FETDUN - TRUE.
  289. *
  290. * CALLS RECALL.
  291. #
  292. IF NOT FETDUN THEN
  293. BEGIN
  294. RECALL(FET);
  295. END
  296. IOEND
  297.  
  298.  
  299. PROC DISOWNCACHE(PARM);
  300. BEGIN
  301. #
  302. ** DISOWNCACHE - RELEASE CACHE FRAME FROM OWNERSHIP.
  303. *
  304. * DISOWNCACHE IS USED TO RELEASE A PAGE FROM OWNERSHIP BY
  305. * A LEVEL OF THE TREE STRUCTURE. RELEASE OF A PAGE MAKES
  306. * IT ELIGIBLE TO BE FLUSHED OUT OF MEMORY (AND POSSIBLY
  307. * REWRITTEN BACK TO DISK) ANYTIME THE FLUSHCACHE ROUTINE
  308. * IS NEEDED. DISOWNCACHE ALSO SETS THE AGE FOR THE PAGE
  309. * SO THAT FLUSHCACHE CAN DO ANY REWRITES IN THE MANDATORY
  310. * ORDER OF RELEASE. THE GLOBAL AGE COUNTER IS INCREMENTED.
  311. *
  312. * ENTRY PARM - TREE LEVEL.
  313. * CACHEOWNED[PARM] - TRUE FOR NON-TRIVIAL OPERATON.
  314. * AGECOUNT - HIGHEST AGE YET ASSIGNED TO ANY PAGE.
  315. *
  316. * EXIT AGECOUNT - INCREMENTED.
  317. * CACHEOWNED[PARM] - FALSE.
  318. * CACHEAGE[PARM] - SETUP.
  319. #
  320. ITEM PARM;
  321. IF PARM LS 0 OR NOT CACHEOWNED[PARM] THEN RETURN;
  322. CACHEOWNED[PARM]=FALSE;
  323. AGECOUNT=AGECOUNT+1;
  324. CACHEAGE[PARM]=AGECOUNT;
  325. END # OF DISOWNCACHE #
  326.  
  327.  
  328. FUNC COUNTCACHE;
  329. BEGIN
  330. #
  331. ** COUNTCACHE - DETERMINE HOW MANY CACHE FRAMES ARE NOT USED.
  332. *
  333. * COUNTCACHE TELLS THE CALLER HOW MANY CACHE FRAMES ARE
  334. * NEITHER OWNED BY ANY TREE LEVEL NOR CONTAIN DATA, WHICH
  335. * HAS BEEN ALTERED IN THE CACHE BUT NOT YET ON DISK.
  336. *
  337. * ENTRY CACHEOWNED[ALL] - SETUP.
  338. * CACHEDIRTY[ALL] - SETUP.
  339. *
  340. * EXIT COUNTCACHE - RESULT.
  341. #
  342. ITEM I, J;
  343. J=0;
  344. FOR I=0 STEP 1 UNTIL MAXCACHE DO IF NOT
  345. (CACHEDIRTY[I] OR CACHEOWNED[I]) THEN J=J+1;
  346. COUNTCACHE=J;
  347. END # OF COUNTCACHE #
  348.  
  349.  
  350. PROC SEARCHCACHE(M);
  351. BEGIN
  352. #
  353. ** SEARCHCACHE - DETERMINE BEST CACHEFRAME TO TAKE OVER.
  354. *
  355. * SEARCHCACHE TESTS ALL CACHE FRAMES FOR THOSE WHICH ARE
  356. * AVAILABLE TO BE CLAIMED AND USED FOR DIFFERENT DATA THAN
  357. * PRESENTLY IN MEMORY. THE OLDEST AVAILABLE FRAME IS
  358. * CONSIDERED THE BEST CANDIDATE FOR RECYCLE. A FRAME
  359. * IS AVAILABLE IF IT IS NEITHER CURRENTLY OWNED BY ANY TREE
  360. * LEVEL NOR CONTAINS DATA ALTERED IN MEMORY BUT NOT ON DISK.
  361. *
  362. * ENTRY CACHEOWNED[ALL] - SETUP.
  363. * CACHEDIRTY[ALL] - SETUP.
  364. * CACHEAGE[ALL] - SETUP FOR UNOWNED, UNDIRTY FRAMES.
  365. *
  366. * EXIT M - CHOSEN FRAME.
  367. *
  368. * CALLS TRAGIC.
  369. #
  370. ITEM K,L,M;
  371. M=-1;
  372. K=999999999;
  373. FOR L=0 STEP 1 UNTIL MAXCACHE DO
  374. BEGIN
  375. IF CACHEAGE[L] LS K AND
  376. NOT (CACHEDIRTY[L] OR CACHEOWNED[L]) THEN
  377. BEGIN # SEARCH OLDEST AVAIL PAGE #
  378. M=L;
  379. K=CACHEAGE[L];
  380. END
  381. END
  382. IF M LS 0 THEN TRAGIC(" ALL WORKFILE BUFFERS ARE FULL.$");
  383. END # OF SEARCHCACHE #
  384.  
  385.  
  386. PROC ALLOCCACHE;
  387. BEGIN
  388. #
  389. ** ALLOCCACHE - LAY CLAIM TO A CACHE FRAME.
  390. *
  391. * ALLOCCACHE IS CALLED TO CLAIM A FRAME OF MEMORY IN THE
  392. * DISK CACHE, AND ATTACH IT TO A PARTICULAR TREE LEVEL.
  393. * THE DISK ADDRESS OF THE DISK DATA IS SAVED IN THE HEADER
  394. * WORD OF THE CACHE FRAME, SO IT CAN BE MATCHED FOR
  395. * PURPOSES OF AVOIDING DISK READS.
  396. *
  397. * ENTRY PL - CURRENT TREE LEVEL.
  398. * PADA[PL] - DISK ADDRESS ASSIGNED FOR REAL DATA.
  399. *
  400. * EXIT PACACHE[PL] - WHICH CACHE FRAME WAS SELECTED.
  401. * BFDA[PL] - DISK ADDRESS IS STORED IN CACHE FRAME.
  402. *
  403. * CALLS SEARCHCACHE.
  404. #
  405. ITEM TMP1;
  406. SEARCHCACHE(TMP1);
  407. PACACHE[PL]=TMP1;
  408. CACHEOWNED[TMP1]=TRUE;
  409. BFDA[TMP1]=PADA[PL];
  410. END # OF ALLOCCACHE #
  411.  
  412.  
  413. PROC RECLAIMCACHE;
  414. BEGIN
  415. #
  416. ** RECLAIMCACHE - IDENTIFY CACHE FRAME WRONGLY RELEASED.
  417. *
  418. * RECLAIMCACHE IS USED TO MATCH A TREE LEVEL TO A CACHE
  419. * FRAME WHICH CONTAINS THE VIRTUAL DISK SECTOR FOR THE
  420. * TREE LEVEL, AND REESTABLISH OWNERSHIP. THIS IS DONE
  421. * BECAUSE THERE ARE SITUATIONS WHERE A PAGE MUST BE
  422. * TEMPORARILY RELEASED FROM OWNERSHIP SO IT CAN BE WRITTEN
  423. * TO DISK, BUT FORFEITURE OF OWNERSHIP IS NOT INTENDED
  424. * FOR ANY OTHER REASON. RECLAIMCACHE CAN BE CALLED AFTER
  425. * A SEQUENCE OF DISOWNCACHE AND FLUSHCACHE, AND THE TREE
  426. * LEVELS ARE THEN AS THEY WERE BUT DATA ALTERATIONS ARE
  427. * UP TO DATE ON DISK. REMEMBER THAT THE ORDER IN WHICH PAGES
  428. * CAN BE UPDATED TO DISK DEPENDS ON THE TREE HIERARCHY, SO
  429. * IT IS SOMETIMES NECESSARY TO GO THRU THIS SEQUENCE WITH ONE
  430. * TREE LEVEL IN ORDER TO ACHIEVE THE ACTUAL PURPOSE OF
  431. * WRITING A DIFFERENCE TREE LEVEL TO DISK.
  432. *
  433. * ENTRY PL - CURRENT TREE LEVEL.
  434. * PALVL - DEEPEST VALID TREE LEVEL.
  435. * CACHEOWNED[ALL], PACACHE[ALL], BFDA[ALL] - SETUP.
  436. *
  437. * EXIT CACHEOWNED[PL THRU PALVL] - TRUE.
  438. *
  439. * CALLS TRAGIC.
  440. *
  441. * USES TPL.
  442. #
  443. FOR TPL=PL STEP 1 UNTIL PALVL DO
  444. BEGIN
  445. IF CACHEOWNED[PACACHE[TPL]] THEN TEST TPL;
  446. IF BFDA[PACACHE[TPL]] NQ PADA[TPL] THEN
  447. BEGIN
  448. TRAGIC(" WORKFILE BUFFER CONTAINS WRONG TEXT.$");
  449. END
  450. CACHEOWNED[PACACHE[TPL]]=TRUE;
  451. END
  452. END # OF RECLAIMCACHE #
  453. PAGE
  454. PROC MOVEIO;
  455. BEGIN
  456. #
  457. ** MOVEIO - INITIATE ANY CIO CALLS AS NEEDED.
  458. *
  459. * MOVEIO IS CALLED ANY TIME CIO CALLS ARE KNOWN TO BE
  460. * NECESSARY, AND CAN ALSO BE CALLED ANY TIME CIO CALLS MIGHT
  461. * BE DESIRABLE. MOVEIO BECOMES A NO-OP IF A CIO CALL IS
  462. * ALREADY IN PROGRESS, OR IF NO CIO CALL IS NEEDED. THE
  463. * CALLER IS RESPONSIBLE TO PREPARE THE FET AND CIRCULAR
  464. * BUFFER IN ALL WAYS EXCEPT THE CHOICE OF CIO FUNCTION CODE.
  465. *
  466. * WRITES ARE INITIATED WHEN THE IOWRITE FLAG HAS BEEN
  467. * PREPARED TO INDICATE THAT WRITES ARE NEEDED, THE FET IS NOT
  468. * PREVIOUSLY INTERLOCKED, AND THE CIRCULAR BUFFER CONTAINS
  469. * SOME DATA. READS ARE INITIATED WHEN THE IOREAD FLAG HAS
  470. * BEEN PREPARED TO INDICATE THAT READS ARE NEEDED, THE FET IS
  471. * NOT PREVIOUSLY INTERLOCKED, AND THE RDIN/RDOUT POINTERS
  472. * INDICATE THERE IS A NON-TRIVIAL LIST OF PRUS STILL AWAITING
  473. * READS.
  474. *
  475. * MOVEIO ALSO PERFORMS THE FUNCTION OF RECOGNIZING THAT ALL
  476. * DESIRED I/O HAS BEEN COMPLETED, SUCH AS ALL WRITEABLE DATA
  477. * REMOVED FROM CIRCULAR BUFFER OR ALL READABLE PRUS REMOVED
  478. * FROM READ LIST. UNDER THESE CONDITIONS, MOVEIO CLEARS THE
  479. * IOXXXX FLAGS SO THAT NO FURTHER DESIRE FOR CIO CALLS WILL
  480. * BE INDICATED, UNTIL AND UNLESS SOMEONE TURNS THE FLAGS ON
  481. * AGAIN.
  482. *
  483. * IN THE CASES WHERE THE CIRCULAR BUFFER CONTAINS DATA TO BE
  484. * WRITTEN, THE ACTUAL CIO FUNCTION CODE IS CHOSEN FROM FOUR
  485. * POSSIBILITIES BASED ON EXTENSION/ALTERATION OF THE FILE AND
  486. * NEED OR NON-NEED FOR END-OF-RECORD TO BE WRITTEN. WHEN THE
  487. * DISK IS TO BE READ, THE FUNCTION CODE IS ALWAYS "RPHRLS",
  488. * AKA "READ PRUS RANDOMLY BY LIST".
  489. *
  490. * NOTE THAT MOVEIO NEVER WAITS FOR ANY CIO TO COMPLETE, THUS
  491. * MOVEIO IS NOT A REENTRANT ROUTINE.
  492. *
  493. * ENTRY FETDUN - WHETHER ANY PREVIOUS I/O IS DONE.
  494. * IOACT - WHETHER I/O SHOULD BE DONE SOMETIME SOON.
  495. * IOWRITE - WHETHER I/O NEEDED IS A WRITE.
  496. * IOREAD - WHETHER I/O NEEDED IS A READ.
  497. * IOAPEND - WHETHER WRITE IS TO EXTEND FILE OR ALTER.
  498. * IOWRTEOR - WHETHER WRITE IS TO PRODUCE EOR.
  499. * FETIN, FETOUT - INDICATE WHETHER UNWRITTEN DATA IS
  500. * STILL IN THE BUFFER.
  501. * RDIN, RDOUT - INDICATE WHETHER THERE ARE PRUS
  502. * IDENTIFIED IN READ LIST AS DESIRABLE TO READ,
  503. * BUT NOT YET READ IN.
  504. * FETLA, FETLAW - CURRENT POSITION IN READ LIST.
  505. * RDLIST[ALL] - SETUP.
  506. * CIOCOUNT - ACCOUNTING ACCUMULATOR.
  507. * MAXDA, LASTDA - USED TO DETERMINE VALIDITY OF
  508. * WRITE PARAMETERS, WHEN CONSISTENCY CHECKING
  509. * IS ENABLED IN THE SOURCE CODE.
  510. * FETCRI - USED WITH MAXDA AND LASTDA FOR VALIDITY.
  511. *
  512. * EXIT FETDUN - FALSE IF A CIO CALL STARTED UP.
  513. * CIOCOUNT - INCREMENTED IF CIO CALLED.
  514. * IOACT, IOREAD, IOWRITE, IOAPEND - CLEARED IF AND
  515. * ONLY IF ALL MOVEIO DETERMINES THAT ALL
  516. * PREVIOUSLY REQUESTED I/O HAS COMPLETED.
  517. *
  518. * CALLS WRITE, REWRITE, WRITER, REWRITR, RPHRLS, TRAGIC.
  519. #
  520. ITEM I;
  521. SWITCH CALLWRITE WRTFUNC,RWRTFUNC,WRTRFUNC,RWRTRFUNC;
  522.  
  523. IF IOACT AND FETDUN THEN
  524. BEGIN
  525.  
  526. IF IOWRITE AND FETIN NQ FETOUT THEN # WRITE NOT DONE #
  527. BEGIN
  528. CIOCOUNT = CIOCOUNT + 1;
  529.  
  530. I=1;
  531. IF IOAPEND THEN I=0;
  532. IF IOWRTEOR THEN I=I+2;
  533. IOWRTEOR=FALSE;
  534. GOTO CALLWRITE[I];
  535.  
  536. WRTFUNC:
  537. WRITE(FET,0);
  538. RETURN;
  539.  
  540. RWRTFUNC:
  541. FETEP = TRUE; # SET ERROR PROCESSING BIT #
  542. REWRITE(FET,0);
  543. FETEP = FALSE; # CLEAR ERROR PROCESSING BIT #
  544. IF FETAT EQ O"22" THEN
  545. BEGIN # IF FATAL ERROR #
  546. TRAGIC(" WORKFILE BUFFER EMPTY ON REWRITE.$");
  547. END
  548. RETURN;
  549.  
  550. WRTRFUNC:
  551. WRITER(FET,0);
  552. RETURN;
  553.  
  554. RWRTRFUNC:
  555. FETEP = TRUE; # SET ERROR PROCESSING BIT #
  556. REWRITR(FET,0);
  557. FETEP = FALSE; # CLEAR ERROR PROCESSING BIT #
  558. IF FETAT EQ O"22" THEN
  559. BEGIN # IF FATAL ERROR #
  560. TRAGIC(" WORKFILE BUFFER EMPTY ON REWRITER. $");
  561. END
  562. RETURN;
  563.  
  564. END
  565.  
  566. ELSE IF IOREAD AND RDIN NQ RDOUT THEN # READ NOT DONE #
  567. BEGIN
  568. IF FETLA EQ LOC(RDLIST[RDLIM])
  569. THEN FETLAW = LOC(RDLIST[0]);
  570.  
  571. IF FETLA NQ LOC(RDLIST[RDIN]) THEN
  572. BEGIN
  573. CIOCOUNT = CIOCOUNT + 1;
  574. RPHRLS(FET,0);
  575. END
  576. END
  577.  
  578. ELSE # READ AND WRITE DONE #
  579. BEGIN
  580.  
  581. CONTROL IFGQ PARANOIA,5;
  582. IF IOWRITE THEN # CHECK WRITE CRI #
  583. BEGIN
  584. IF IOAPEND THEN
  585. BEGIN
  586. IF FETCRI NQ MAXDA+1 THEN
  587. BEGIN
  588. TRAGIC(" FILE SIZE INCORRECT.$");
  589. END
  590. END
  591. ELSE
  592. BEGIN
  593. IF FETCRI NQ LASTDA+1 THEN
  594. BEGIN
  595. TRAGIC(" RANDOM ADDRESS INCORRECT.$");
  596. END
  597. END
  598. END
  599. CONTROL FI;
  600.  
  601. IOACT = FALSE;
  602. IOWRITE = FALSE; IOAPEND = FALSE;
  603. IOREAD = FALSE;
  604. END
  605.  
  606. END
  607. END
  608. PAGE
  609. PROC PAUSEIO;
  610. IOBEGIN(PAUSEIO)
  611. #
  612. ** PAUSEIO - AWAIT AND/OR ENFORCE CIO COMPLETION.
  613. *
  614. * PAUSEIO IS CALLED FOR ONE OF THREE REASONS: (1) THE CALLER
  615. * HAS STARTED SOME I/O VIA MOVEIO AND NEEDS TO WAIT FOR IT TO
  616. * FINISH, OR (2) THE CALLER NEEDS SOME OLD I/O TO FINISH SO
  617. * THAT THE FET CAN BE USED TO INITIATE NEW DESIRED I/O, OR
  618. * (3) THE CALLER NEEDS SOME OLD I/O TO FINISH, TO FREE THE
  619. * CIRCULAR BUFFER AND READ LIST SO THOSE MEMORY RESOURCES CAN
  620. * BE MANAGED AND POSSIBLY RE-ASSIGNED.
  621. *
  622. * PAUSEIO THEREFORE GUARANTEES THAT ANY WRITEABLE DATA IN THE
  623. * CIRCULAR BUFFER REALLY GETS WRITTEN, AND THAT ANY INITIATED
  624. * READS ARE FINISHED WITH THE DATA DISCARDED AND THE CIRCULAR
  625. * BUFFER EMPTY. PAUSEIO IS ALLOWED TO HANDLE READS WHICH
  626. * HAVE BEEN REQUESTED BUT NOT YET INITIATED BY SIMPLE
  627. * CANCELLATION. THUS, PAUSEIO IS MEANINGFUL TO THE TYPE 1
  628. * CALLER ONLY FOR THE WRITE DIRECTION - THE READ DIRECTION IS
  629. * A THROWAWAY WHILE THE WRITE DIRECTION HAS ASSURANCE OF
  630. * COMPLETION.
  631. *
  632. * SINCE THE TYPE 3 CALLER OFTEN DOES NOT KNOW HOW (OR IS NOT
  633. * ALLOWED) TO DETERMINE IF THE MEMORY RESOURCES ARE ALREADY
  634. * AVAILABLE FOR REASSIGNMENT, PAUSEIO CAN BE CALLED CASUALLY,
  635. * AND WILL NO-OP ITSELF IF THE DESIRED CONDITIONS ARE ALREADY
  636. * TRUE.
  637. *
  638. * PAUSEIO ALSO ZEROES OUT FETCHGUIDE. THIS IS USED TO CONTROL
  639. * THE QUANTITY OF DATA PREFETCHED AS A FUNCTION OF HOW MUCH
  640. * SUCCESS WE HAVE HAD IN UTILIZING PREFETCHED DATA IN RECENT
  641. * HISTORY. A PAUSEIO CALL IS REGARDED AS AN ADMISSION THAT
  642. * ANY CURRENT PREFETCHING HAS LOST ALL RELEVANCE.
  643. *
  644. * ENTRY IOREAD - WHETHER WE WERE PREVIOUSLY TRYING TO READ
  645. * SOMETHING WHICH MUST NOW BE THROWN AWAY.
  646. * IOWRITE - WHETHER WE HAD PREVIOUSLY REQUESTED THAT
  647. * SOMETHING BE WRITTEN, WHICH MUST NOW BE BROUGHT
  648. * TO FASTEST POSSIBLE COMPLETION.
  649. * RDIN, RDOUT - BRACKET ACTIVE SEGMENT OF READ LIST.
  650. * FETIN, FETOUT - BRACKET CIRCULAR BUFFER DATA.
  651. *
  652. * EXIT IOREAD, IOWRITE, IOACT - GUARANTEED FALSE.
  653. * FET - CIRCULAR BUFFER GUARANTEED EMPTY.
  654. * RDLIST[ALL], RDIN, RDOUT - GUARANTEED EMPTY.
  655. * FETCHGUIDE - ZEROED.
  656. *
  657. * CALLS WAIT, MOVEIO.
  658. #
  659. ITEM I, J, K;
  660.  
  661. FETCHGUIDE=0;
  662.  
  663. IF IOREAD THEN
  664. BEGIN
  665. WAIT; # FOR ACTIVE TRANSFER TO FINISH #
  666. FOR I = RDIN WHILE I NQ RDOUT DO # CLEAN OUT READLIST #
  667. BEGIN
  668. I = I - 1;
  669. IF I LS 0 THEN I = RDLIM - 1;
  670. RDLIST[I] = 0;
  671. END
  672. FETOUT = FETIN; # ABANDON CIRCULAR BUFFER CONTENT #
  673. IOACT = FALSE;
  674. IOREAD = FALSE;
  675. END
  676.  
  677. ELSE IF IOWRITE THEN
  678. BEGIN
  679. WHYLE IOWRITE DO
  680. BEGIN
  681. MOVEIO;
  682. WAIT;
  683. END
  684. END
  685.  
  686. IOEND
  687. PAGE
  688. PROC SETREAD((DA));
  689. BEGIN
  690. #
  691. ** SETREAD - ADD DISK ADDRESS TO READ LIST.
  692. *
  693. * SETREAD PERFORMS FET INITIALIZATION AS NEEDED, TO ASSURE
  694. * THAT THE BUFFER AND FET ARE TURNED AROUND TO THE INPUT
  695. * DIRECTION, AND APPENDS THE SPECIFIED DISK ADDRESS ONTO THE
  696. * READ LIST. THE CALLER IS RESPONSIBLE TO ASSURE THAT
  697. * SETREAD WILL NOT ENCOUNTER A FULL READ LIST. THE CALLER IS
  698. * ALLOWED TO CALL SETREAD FOR AN ADDRESS ALREADY LISTED, IN
  699. * WHICH CASE SETREAD NO-OPS ITSELF. THE USER IS REQUIRED TO
  700. * PROVIDE AN IN-BOUNDS DISK ADDRESS, AND TO HAVE USED PAUSEIO
  701. * TO COMPLETE ANY PREVIOUS OUTPUT ACTIVITIES.
  702. *
  703. * ENTRY DA - SECTOR NUMBER FOR DESIRED PRU.
  704. * IOREAD - WHETHER FET ALREADY INITIALIZED FOR INPUT.
  705. * IOWRITE, MAXDA - WHEN CONSISTENCY CHECKING IS ENABLED,
  706. * THESE ARE USED TO VERIFY VALIDITY.
  707. * RDIN, RDOUT - BRACKET ACTIVE SEGMENT OF READ LIST.
  708. * RDLIST[ALL] - SETUP FOR EXISTING DISK ADDRESSES
  709. * AND WITH ZEROES IN EXCESS LIST AREAS.
  710. *
  711. * EXIT IOREAD, IOACT - TRUE.
  712. * FET AND CIRCULAR BUFFER - VALID FOR MOVEIO CALL.
  713. * RDIN, RDOUT - UPDATED FOR ENLARGED READ LIST.
  714. * RDLIST[NEW RDIN-1] - DISK ADDRESS STORED HERE.
  715. *
  716. * CALLS TRAGIC, INITFET.
  717. #
  718. ITEM DA;
  719. ITEM P;
  720.  
  721. CONTROL IFGQ PARANOIA,5;
  722. IF DA LQ 0 OR DA GR MAXDA THEN
  723. BEGIN
  724. TRAGIC(" OUT OF BOUNDS PRU ADDRESS ON READ (1).$");
  725. END
  726. IF IOWRITE THEN TRAGIC(" WORKFILE BUFFER FULL ON READ.$");
  727. CONTROL FI;
  728.  
  729. IF NOT IOREAD THEN
  730. BEGIN
  731. INITFET(DISK,DSKSIZ);
  732.  
  733. RDIN = 0;
  734. RDOUT = 0;
  735. FETLAW = LOC(RDLIST[0]);
  736.  
  737. IOACT = TRUE;
  738. IOREAD = TRUE;
  739. END
  740.  
  741. FOR P = RDOUT WHILE RDLIST[P] NQ DA DO
  742. BEGIN
  743. IF P EQ RDIN THEN
  744. BEGIN
  745. RDLIST[RDIN] = DA;
  746. RDIN = RDIN + 1;
  747. IF RDIN EQ RDLIM THEN RDIN = 0;
  748. CONTROL IFGQ PARANOIA,5;
  749. IF RDIN EQ RDOUT THEN TRAGIC(" RPHRLS LIST BUFFER IS FULL.$");
  750. CONTROL FI;
  751. END
  752.  
  753. ELSE
  754. BEGIN
  755. P = P + 1;
  756. IF P EQ RDLIM THEN P = 0;
  757. END
  758.  
  759. END
  760.  
  761. END
  762. PAGE
  763. PROC PREFETCH((DD));
  764. BEGIN
  765. #
  766. ** ARRANGE READ LIST FOR SEVERAL PREFETCHES.
  767. *
  768. * PREFETCH SHOULD BE CALLED ONCE PER SECTOR PROCESSED, BY
  769. * THOSE PROCESSES WHICH ACT UPON POTENTIALLY LARGE SERIES OF
  770. * DISK SECTORS IN EITHER THE FORWARD OR BACKWARD LOGICAL
  771. * ORDER OF TEXT IN THE FILE. THE LOGICAL ORDER CAN BE QUITE
  772. * DIFFERENT FROM THE PHYSICAL ORDER DUE TO THE TREE LINKAGES.
  773. *
  774. * PREFETCH DETERMINES SEVERAL DISK ADDRESSES WHOSE NEED IS
  775. * ANTICIPATED ON BEHALF OF THE CALLER, AND USES SETREAD TO
  776. * ARRANGE THAT SUCH SECTORS CAN BE READ IN THE LOGICAL ORDER.
  777. * IT IS THE CALLING PROCESSES RESPONSIBILITY TO OCCASIONALLY
  778. * CALL MOVEIO FOR ACTUAL INITIATION OF CIO.
  779. *
  780. * TO MINIMIZE OVERHEAD, PREFETCH CHOOSES A DEPTH OF
  781. * PREFETCHING BASED ON APPARENT RECENT SUCCESS IN UTILIZING
  782. * PREFETCHED DATA, AND SUCCESSIVELY UPDATES THE DEPTH OF
  783. * PREFETCH. THIS DEPTH INDICATOR MAY BE CLEARED BY PAUSEIO
  784. * IN RECOGNITION OF THE ABANDONMENT OF A READ, OR BY THE
  785. * CALLER WHEN A LOGICAL BREAK IN SEQUENTIAL PROCESSING IS
  786. * KNOWN TO OCCUR.
  787. *
  788. * TO MINIMIZE OVERHEAD, PREFETCH ATTEMPTS TO PRODUCE EITHER
  789. * ZERO OR SEVERAL NEW ENTRIES IN THE READ LIST, AND ATTEMPTS
  790. * TO NO-OP ITSELF WHEN IT IS RECOGNIZED THAT ONLY ONE OR A
  791. * FEW ENTRIES COULD BE PRODUCED. PREFETCH MUST KEEP THE
  792. * DEPTH OF PREFETCHING WITHIN THE LEGAL BOUNDS OF THE SETREAD
  793. * ROUTINE.
  794. *
  795. * THE DEPTH OF PREFETCHING IS LIMITED TO THE SMALLEST OF THE
  796. * FOLLOWING FACTORS - (1) THE FETCHGUIDE QUANTITY, WHICH
  797. * REPRESENTS RECENT SUCCESS, (2) THE LEGAL LIMITS IMPOSED BY
  798. * SETREAD, AND (3) ONE AND A HALF TIMES THE SIZE OF THE
  799. * CIRCULAR BUFFER. PREFETCHING IS SET UP ONLY WHEN THE
  800. * EXISTING QUEUE IS LESS THAN HALF THE DESIRED DEPTH. FOR
  801. * LARGER QUEUES, IT IS ANTICIPATED THE QUEUE WILL BE SHRUNK
  802. * BACK DOWN AT SOME FUTURE CALL TO PREFETCH, AT WHICH TIME
  803. * A LARGE BATCH OF QUEUE ENTIRES CAN BE PRODUCED.
  804. *
  805. * ONCE PREFETCH DECIDES TO SET UP A BATCH OF READ LIST QUEUE
  806. * ENTRIES, IT IDENTIFIES THE SECTORS TO BE READ AS ALL DATA
  807. * (BOTTOM) LEVEL PRUS, POINTED TO BY THE NEXT-TO-BOTTOM
  808. * DIRECTORY, LOGICALLY ADJACENT TO THE CURRENT DATA SECTOR IN
  809. * THE SPECIFIED DIRECTION. PREFETCH ALSO CAN QUEUE THE NEXT
  810. * LOGICALLY ADJACENT NEXT-TO-BOTTOM DIRECTORY, BY LOOKING
  811. * ANOTHER LEVEL TOWARDS THE ROOT OF THE TREE.
  812. *
  813. * ENTRY FETCHGUIDE - CURRENT GUIDELINE FOR DEPTH.
  814. * RDIN, RDOUT - DESCRIBE CURRENT READ LIST.
  815. * DSKSIZ - CIRCULAR BUFFER SIZE.
  816. * PALVL - DEEPEST TREE LEVEL CURRENTLY VALID.
  817. * PACACHE[ALL] - CACHE FRAMES AT EACH TREE LEVEL.
  818. * BFPRU[ALL] - DISK ADDRESSES FOR EACH FRAME.
  819. * PAFINAL[ALL] - LAST WORDS IN EACH SECTOR OF TREE.
  820. * IOWRITE - WHETHER FET INTERLOCKED FOR OUTPUT.
  821. *
  822. * EXIT RDLIST[ALL], RDIN, RDOUT - UPDATED.
  823. * FETCHGUIDE - INCREMENTED UNLESS DIRECTORY INCLUDED.
  824. *
  825. * CALLS LSTAVAIL, LSTUSAGE, MIN, MAX, SETREAD.
  826. *
  827. * USES P<PRU> WITH RESTORATION.
  828. #
  829. ITEM DD,N;
  830. ITEM DSTOP;
  831. ITEM DONE B;
  832. ITEM TMPPRU;
  833. ITEM TMPPL,TMPD;
  834. ITEM I;
  835.  
  836. IF FETCHGUIDE LS 0 OR IOWRITE THEN RETURN;
  837.  
  838. FETCHGUIDE=FETCHGUIDE+2;
  839. N=LSTAVAIL;
  840. N=MIN(N-3,3*DSKSIZ/O"200");
  841. N=MIN(N,FETCHGUIDE);
  842.  
  843. IF LSTUSAGE LQ N/2 THEN
  844. BEGIN
  845. TMPPRU = P&lt;PRU>;
  846.  
  847. DONE = FALSE;
  848. FOR TMPPL = PALVL-1 STEP -1 WHILE TMPPL GQ 0 AND NOT DONE DO
  849. BEGIN
  850. TMPD = PADISP[TMPPL] + DD;
  851. P&lt;PRU> = LOC(BFPRU[PACACHE[TMPPL]]);
  852.  
  853. IF DD GR 0 THEN DSTOP = MIN(PAFINAL[TMPPL]+1,TMPD+N);
  854. ELSE DSTOP = MAX(0,TMPD-N);
  855.  
  856. IF DSTOP EQ TMPD+N*DD THEN DONE = TRUE;
  857. ELSE FETCHGUIDE=-1;
  858. N=1;
  859.  
  860. FOR TMPD = TMPD STEP DD WHILE TMPD NQ DSTOP DO
  861. BEGIN
  862. FOR I=0 STEP 1 UNTIL MAXCACHE DO
  863. BEGIN
  864. IF BFDA[I] EQ DIRDA[TMPD] THEN TEST TMPD;
  865. END
  866. SETREAD(DIRDA[TMPD]);
  867. END
  868.  
  869. END
  870.  
  871. P&lt;PRU> = TMPPRU;
  872. END
  873. END
  874. PAGE
  875. PROC READPA;
  876. IOBEGIN(READPA)
  877. #
  878. ** READPA - READ NEXT DEEPER TREE PATH SECTOR.
  879. *
  880. * READPA IS USED TO ACCESS THE SECTOR OF DIRECTORY OR DATA
  881. * FOR A SPECIFIED LEVEL OF THE TREE. THE HIGHER LEVELS OF
  882. * THE TREE MUST ALREADY BE PROPERLY FILLED IN. ANY RESIDUAL
  883. * SECTOR IN THE CURRENT TREE LEVEL MUST BE PROPERLY RELEASED
  884. * FROM OWNERSHIP, SO THAT READPA WILL NOT NEED TO CONCERN
  885. * ITSELF WITH THE UPDATING OF ALTERED DATA TO DISK. THE
  886. * CALLER DOES NOT NEED TO SETUP THE FET AND CIRCULAR BUFFER
  887. * FOR INPUT, AND READPA WILL TAKE CARE OF THAT IF NEEDED.
  888. *
  889. * WHEN POSSIBLE, READPA WILL ACCESS THE DESIRED DISK SECTOR
  890. * BY SIMPLY IDENTIFYING IT IN CACHE AND CLAIMING OWNERSHIP OF
  891. * THE RIGHT CACHE FRAME. WHEN THE CACHE DOES NOT PROVIDE THE
  892. * NECESSARY DATA, READPA WILL READ IT FROM DISK. IF THE FET
  893. * AND CIRCULAR BUFFER ARE PREVIOUSLY INTERLOCKED FOR PENDING
  894. * OUTPUT, READPA WILL ASSURE THAT THE UNFINISHED WRITES GET
  895. * DONE. IF THE FET IS ALREADY SETUP FOR INPUT BUT HAS THE
  896. * WRONG DISK ADDRESS COMING IN AT THE FRONT OF THE CIRCULAR
  897. * BUFFER, READPA WILL DISCARD SUCH INCORRECT INPUT AND
  898. * REINITIALIZE TO INPUT THE RIGHT DISK ADDRESS. IF THE FET
  899. * IS ALREADY SET UP FOR INPUT WITH THE RIGHT SECTOR IN OR
  900. * COMING INTO THE CIRCULAR BUFFER, READPA WILL MAKE USE OF
  901. * THAT CIO ACTIVITY.
  902. *
  903. * IF READPA READS THE SECTOR FROM DISK, IT CLEANS UP THE
  904. * RANDOM READ LIST AFTERWARDS, ATTEMPTING TO SHUFFLE THE
  905. * ACTIVE SEGMENT OF THE READ LIST TO MAXIMIZE THE REMAINING
  906. * LIST CAPACITY BEFORE WRAPAROUND. READPA ALSO CHECKS TO SEE
  907. * IF THE BUFFER IS SUFFICIENTLY EMPTY WITH A SUFFICIENTLY
  908. * FULL PREFETCH LIST SO THAT ANTICIPATORY READS SHOULD BE
  909. * STARTED.
  910. *
  911. * ENTRY TEMP - SECTOR NUMBER.
  912. * PL - CURRENT PATH LEVEL.
  913. * PACACHE[ALL] - CACHE FRAMES CURRENTLY OWNED.
  914. * CACHEOWNED[ALL] - SETUP.
  915. * BFDA[ALL] - IDENTIFY SECTOR ADDRESSES EACH FRAME.
  916. * BFHEAD[ALL] - HEADER WORDS FOR EACH CACHED SECTOR.
  917. * ACCTPRU - PRU TRANSFER COUNT.
  918. * IOWRITE - WHETHER FET ALREADY SET FOR WRITES.
  919. * RDIN, RDOUT - READ LIST BRACKETING.
  920. * RDLIST[ALL] - SETUP.
  921. * IOREAD - WHETHER SOME READ ALREADY SCHEDULED.
  922. * FETCHGUIDE - PREFETCH QUANTITY GUIDELINE.
  923. * QUARTER - APPROX ONE FOURTH BUFFER SIZE.
  924. *
  925. * EXIT PACACHE[PL] - INDICATES CACHE FRAME WITH SECTOR.
  926. * CACHEOWNED[PACACHE[PL]] - TRUE.
  927. * ANY OLD CACHE FRAMES MAY HAVE BEEN FLUSHED TO
  928. * DISK AND/OR REASSIGNED IN MEMORY.
  929. * PAHEAD[PL] - HEADER WORD.
  930. * IOWRITE - FALSE IF NOT CACHE HIT.
  931. * IOREAD - POSSIBLY CHANGED.
  932. * RDOUT - ADVANCED IF DISK READ DONE.
  933. * RDIN - RDIN AND RDOUT POSSIBLY RELOCATED IF READ
  934. * DONE AND CIO TERMINATED.
  935. * ACCTPRU - INCREMENTED IF NO CACHE HIT.
  936. * FETCHGUIDE - POSSIBLY NEW VALUE.
  937. * ANTICIPATORY CIO POSSIBLY CALLED.
  938. *
  939. * CALLS TRAGIC, COUNTCACHE, FLUSHCACHE, DISOWNCACHE,
  940. * WIOSTAT, PAUSEIO, ALLOCCACHE, SETREAD, MOVEIO,
  941. * DELAY, RECALL, RDWBUF, BUFUSAGE.
  942. *
  943. * USES P<TOO>.
  944. #
  945. ITEM X1;
  946.  
  947. CONTROL IFGQ PARANOIA,5;
  948. IF PADIRTY[PL] THEN TRAGIC(" ALTERED PRU WAS NOT REWRITTEN.$");
  949. CONTROL FI;
  950.  
  951. IF COUNTCACHE LQ 2 THEN FLUSHCACHE;
  952.  
  953. # FIRST RELEASE CURRENTLY OWNED SECTOR IF ANY #
  954. DISOWNCACHE(PACACHE[PL]);
  955.  
  956. FOR X1=0 STEP 1 UNTIL MAXCACHE DO
  957. BEGIN # TRY TO FIND IN CACHE #
  958. IF BFDA[X1] EQ TEMP THEN # GOT IT #
  959. BEGIN
  960. CONTROL IFGQ PARANOIA,5;
  961. IF CACHEOWNED[X1] THEN
  962. BEGIN
  963. TRAGIC(" WORKFILE BUFFER ALLOCATED TWICE.$");
  964. END
  965. CONTROL FI;
  966. PACACHE[PL]=X1;
  967. CACHEOWNED[X1]=TRUE;
  968. PAHEAD[PL] = BFHEAD[X1];
  969. CONTROL IFEQ MULTI,1;
  970. WIOSTAT(1); # ACCUMULATE CACHE HITS #
  971. CONTROL FI;
  972. IORET
  973. END
  974. END
  975.  
  976. CONTROL IFEQ MULTI,1;
  977. WIOSTAT(2); # ACCUMULATE SECTORS READ #
  978. ACCTPRU=ACCTPRU+1;
  979. CONTROL FI;
  980.  
  981. IF IOWRITE THEN # DO ANY PENDING WRITES #
  982. BEGIN
  983. PAUSEIO;
  984. CONTROL IFEQ MULTI,1;
  985. WIOSTAT(3); # ACCUMULATE FLUSHED WRITES #
  986. CONTROL FI;
  987. END
  988.  
  989. CONTROL IFGQ PARANOIA,5;
  990. IF TEMP LQ 0 OR TEMP GR MAXDA THEN
  991. BEGIN
  992. TRAGIC(" OUT OF BOUNDS PRU ADDRESS ON READ (2).$");
  993. END
  994. CONTROL FI;
  995.  
  996. PADA[PL] = TEMP;
  997. ALLOCCACHE;
  998.  
  999. IF IOREAD AND RDLIST[RDOUT] NQ TEMP THEN
  1000. BEGIN
  1001. PAUSEIO;
  1002. CONTROL IFEQ MULTI,1;
  1003. WIOSTAT(4); # ACCUMULATE READ REJECTS #
  1004. CONTROL FI;
  1005. END
  1006.  
  1007. IF NOT IOREAD THEN
  1008. BEGIN
  1009. SETREAD(TEMP);
  1010. FETCHGUIDE=2;
  1011. END
  1012.  
  1013. WHYLE FETIN EQ FETOUT DO
  1014. BEGIN
  1015. CONTROL IFEQ MULTI,1;
  1016. WIOSTAT(10); # ACCUMULATE NOT ALREADY IN BUFFER #
  1017. CONTROL FI;
  1018. MOVEIO;
  1019. CONTROL IFEQ MULTI,1;
  1020. WAIT;
  1021. CONTROL FI;
  1022. CONTROL IFEQ SINGLE,1;
  1023. IF NOT FETDUN THEN DELAY;
  1024. CONTROL FI;
  1025. END
  1026.  
  1027. P&lt;TOO> = LOC(BFPRU[PACACHE[PL]]);
  1028. RDWBUF(O"100");
  1029. PAHEAD[PL] = BFHEAD[PACACHE[PL]];
  1030.  
  1031. CONTROL IFGQ PARANOIA,5;
  1032. IF TEMP NQ RDLIST[RDOUT] THEN
  1033. BEGIN
  1034. TRAGIC(" RANDOM READ LIST INCORRECT.$");
  1035. END
  1036. IF PADA[PL] NQ TEMP THEN TRAGIC(" PRU CONTENT INCORRECT.$");
  1037. IF PADIRTY[PL] THEN
  1038. BEGIN
  1039. TRAGIC(" STATUS FLAGS SHOULD HAVE BEEN CLEARED.$");
  1040. END
  1041. CONTROL FI;
  1042.  
  1043. RDLIST[RDOUT] = 0;
  1044. IF RDOUT EQ RDLIM-1 THEN RDOUT = 0;
  1045. ELSE RDOUT = RDOUT + 1;
  1046. IF FETDUN AND RDIN EQ RDOUT THEN
  1047. BEGIN
  1048. RDIN=0;
  1049. RDOUT=0;
  1050. FETCHGUIDE=ABS(FETCHGUIDE);
  1051. END
  1052.  
  1053. IF BUFUSAGE LQ QUARTER THEN MOVEIO;
  1054.  
  1055. IOEND
  1056. PAGE
  1057. PROC ALLOC;
  1058. BEGIN
  1059. #
  1060. ** ALLOC - ASSIGN DISK ADDRESS.
  1061. *
  1062. * ALLOC IS CALLED WHEN A NEW SECTOR MUST BE CREATED. THE
  1063. * NEXT PRU OFF THE LOGICAL END OF THE FILE IS CHOSEN. NOTE
  1064. * THAT THE LOGICAL END OF THE FILE REPRESENTS THOSE ADDRESSES
  1065. * WHICH HAVE BEEN ALLOCATED. THE PHYSICAL END OF THE FILE
  1066. * REPRESENTS THOSE ADDRESSES ACTUALLY WRITTEN ONTO THE FILE,
  1067. * AND CAN BE A SMALLER NUMBER THAN THE LOGICAL END.
  1068. *
  1069. * ENTRY PL - CURRENT PATH LEVEL.
  1070. * DANEXT - ALLOCATION THRESHOLD.
  1071. *
  1072. * EXIT PADA[PL] - SETUP.
  1073. * DANEXT - INCREMENTED.
  1074. *
  1075. * CALLS TRAGIC.
  1076. #
  1077. CONTROL IFGQ PARANOIA,5;
  1078. IF PADIRTY[PL] THEN TRAGIC(" OLD SECTOR MUST BE WRITTEN.$");
  1079. CONTROL FI;
  1080. PADA[PL] = DANEXT;
  1081. DANEXT = DANEXT + 1;
  1082. END
  1083.  
  1084.  
  1085. PROC DEALLOC;
  1086. BEGIN
  1087. #
  1088. ** DEALLOC - DISCARD DISK SECTOR.
  1089. *
  1090. * DEALLOC IS USED TO DISCARD A DISK SECTOR WHICH CAN NO
  1091. * LONGER BE USED. THIS CAN BE NEEDED WHEN A SECTOR HAS
  1092. * OVERFLOWED AND HAS BEEN SPLIT INTO TWO NEW SECTORS. IF THE
  1093. * ROOT SECTOR NEEDS TO BE SPLIT, A COMPLETE NEW TREE LEVEL IS
  1094. * CREATED WITH NEW SECTORS, THE ROOT SECTOR IS MODIFIED TO
  1095. * BECOME A DIRECTORY FOR THE NEW LEVEL, AND NO DEALLOCATION
  1096. * IS NEEDED. IF A NON-ROOT SECTOR NEEDS TO BE SPLIT EXACTLY
  1097. * AT (JUST AFTER) ITS EXISTING LAST FIELD, THEN THAT SECTOR
  1098. * IS PRESERVED WITHOUT DEALLOCATION AND A NEW SECTOR IS
  1099. * CREATED FOR THE OVERFLOW CONTENT. BUT IF A NON-ROOT SECTOR
  1100. * MUST BE SPLIT SOMEWHERE IN THE MIDDLE OF ITS EXISTING
  1101. * CONTENT, IT MUST BE DEALLOCATED AND BE REPLACED BY TWO
  1102. * COMPLETELY NEW SECTORS.
  1103. *
  1104. * THE REASON FOR DEALLOCATION IS THAT NOTHING MUST BE ALLOWED
  1105. * TO BE POINTED TO UNTIL AND UNLESS IT ALREADY EXISTS, AS
  1106. * UPDATED TO DISK ALTHOUGH NOT NECESSARILY AS CACHED IN
  1107. * MEMORY. SINCE A NON-ROOT SECTOR IS POINTED TO BE
  1108. * HIGHER-LEVEL DIRECOTRIES, IT CANNOT BE TOTALLY REFORMATTED
  1109. * IN PLACE, THEREFORE IT IS LEFT AS IS AND NEW SECTORS
  1110. * REPLACE IT. THE DIRECTORIES WHICH POINT TO THE DISCARDED
  1111. * SECTOR WILL EVENTUALLY BE UPDATED THEMSELVES. UNTIL THEN,
  1112. * THOSE HIGHER DIRECTORIES MAY BE OUT OF DATE BUT AT LEAST
  1113. * POINT TO A VALID DATA STRUCTURE.
  1114. *
  1115. * ENTRY PL - CURRENT TREE LEVEL.
  1116. *
  1117. * EXIT PADA[PL] - CLEARED AWAY.
  1118.  
  1119. *
  1120. * CALLS TRAGIC.
  1121. #
  1122. CONTROL IFGQ PARANOIA,5;
  1123. IF PL EQ 0 OR PADA[PL] EQ 0 THEN
  1124. BEGIN
  1125. TRAGIC(" SECTOR CANNOT BE DEALLOCATED.$");
  1126. END
  1127. CONTROL FI;
  1128. PADA[PL] = 0;
  1129. PADIRTY[PL] = FALSE;
  1130. END
  1131.  
  1132.  
  1133. PROC SETWRITE(PARM);
  1134. BEGIN
  1135. #
  1136. ** SETWRITE - SCHEDULE EXTENSION/ALTERATION OF FILE.
  1137. *
  1138. * SETWRITE INITIALIZES THE FET FOR OUTPUT. IT SETS THE IOACT
  1139. * FLAG TO INDICATE THAT I/O IS SCHEDULED, SETS IOWRITE TO
  1140. * INDICATE THAT THE I/O SHALL BE AN OUTPUT FUNCTION, AND
  1141. * SETS OR CLEARS IOAPEND ACCORDING TO WHETHER THE SECTOR TO
  1142. * BE WRITTEN IS WITHIN THE CURRENT PHYSICAL BOUNDARIES OF THE
  1143. * FILE OR REPRESENTS AN EXTENSION OF PHYSICAL SIZE.
  1144. *
  1145. * ENTRY PARM - DISK ADDRESS TO BE WRITTEN.
  1146. * MAXDA - CURRENT PHYSICAL SIZE OF FILE.
  1147. *
  1148. * EXIT FET - INITIALIZED WITH EMPTY CIRCULAR BUFFER.
  1149. * IOACT - TRUE.
  1150. * IOWRITE - TRUE.
  1151. * IOAPEND - TRUE OR FALSE BASED ON PARM AND MAXDA.
  1152. * LASTDA - SET TO KEEP TRACK OF WHERE WE ARE IN FILE.
  1153. * FETRR - SETUP.
  1154. *
  1155. * CALLS INITFET.
  1156. #
  1157. ITEM PARM;
  1158.  
  1159. INITFET(DISK,DSKSIZ);
  1160.  
  1161. IOACT = TRUE;
  1162. IOWRITE = TRUE;
  1163.  
  1164. IF PARM GR MAXDA THEN
  1165. BEGIN
  1166. IOAPEND = TRUE;
  1167. FETRR = LOC(DUMB);
  1168. END
  1169.  
  1170. ELSE
  1171. BEGIN
  1172. IOAPEND = FALSE;
  1173. FETRR = PARM;
  1174. LASTDA = PARM - 1;
  1175. END
  1176.  
  1177. END
  1178. PAGE
  1179. PROC TRYWRITE(PARM,FLAG);
  1180. BEGIN
  1181. #
  1182. ** TRYWRITE - TRANSMIT SECTOR TO CIRCULAR BUFFER.
  1183. *
  1184. * TRYWRITE ATTEMPTS TO TRANSMIT A SECTOR TO THE CIRCULAR
  1185. * BUFFER. IT MAY FAIL TO DO SO IF THE CIRCULAR BUFFER ALREADY
  1186. * CONTAINS SECTORS FOR WHICH THIS SECTOR IS NOT CONTIGUOUS.
  1187. * THE CALLER SHOULD CALL PAUSEIO WHEN TRYWRITE FAILS, AND
  1188. * THEN CALL THIS ROUTINE AGAIN. TRYWRITE CANNOT FAIL IF
  1189. * PAUSEIO IS USED.
  1190. *
  1191. * ENTRY P<FROM> - POINTS TO TEXT OF SECTOR.
  1192. * PARM - DISK ADDRESS.
  1193. * MAXDA - PHYSICAL FILE SIZE.
  1194. * LASTDA - MOST RECENT DISK ADDRESS TRANSMITTED.
  1195. *
  1196. *
  1197. * EXIT P<FROM> - POSSIBLY DESTROYED.
  1198. * MAXDA - INCREMENTED IF FILE EXTENDED.
  1199. * LASTDA - INCREMENTED IF CONTIGUOUS EARLIER OUTPUT.
  1200. * FET - GUARANTEED SETUP FOR OUTPUT WITH THIS SECTOR
  1201. * OF TEXT IN CIRCULAR BUFFER. EXISTING FET SETUP
  1202. * AND CIRCULAR BUFFER CONTENT, IF ANY, ARE NOT
  1203. * DISTURBED WITH REGARD TO EARLIER OUTPUT.
  1204. * FLAG - TRUE IF THIS SECTOR TRANSMITTED. FALSE IF
  1205. * UNABLE TO TRANSMIT DUE TO DISCONTIGUITY WITH
  1206. * EARLIER OUTPUT.
  1207. * IOACT, IOWRITE - TRUE.
  1208. * IOAPEND - SETUP.
  1209. *
  1210. * CALLS SETWRITE, WTWBUF.
  1211. #
  1212. ITEM PARM, FLAG B, ZERO = 0; # ZERO IS A CONSTANT #
  1213.  
  1214. FLAG = TRUE;
  1215.  
  1216. IF NOT IOWRITE THEN SETWRITE(PARM);
  1217.  
  1218. IF IOAPEND THEN
  1219. BEGIN
  1220.  
  1221. IF MAXDA+1 LS PARM THEN # ADD PADDING SECTOR #
  1222. BEGIN
  1223. MAXDA = MAXDA + 1;
  1224. P&lt;FROM>=LOC(ZERO);
  1225. WTWBUF(O"100");
  1226. END
  1227.  
  1228. ELSE IF MAXDA+1 EQ PARM THEN # ADD REAL SECTOR #
  1229. BEGIN
  1230. MAXDA = MAXDA+1;
  1231. WTWBUF(O"100");
  1232. END
  1233.  
  1234. ELSE
  1235. BEGIN
  1236. FLAG = FALSE;
  1237. END
  1238. END
  1239.  
  1240. ELSE
  1241. BEGIN
  1242.  
  1243. IF LASTDA+1 EQ PARM AND PARM LQ MAXDA THEN
  1244. BEGIN
  1245. LASTDA = LASTDA+1;
  1246. WTWBUF(O"100");
  1247. END
  1248.  
  1249. ELSE
  1250. BEGIN
  1251. FLAG = FALSE;
  1252. END
  1253. END
  1254.  
  1255. END
  1256. PAGE
  1257. PROC FLUSHCACHE;
  1258. IOBEGIN(FLUSHCACHE)
  1259. #
  1260. ** FLUSHCACHE - UPDATE ALTERED CACHE FRAMES TO DISK.
  1261. *
  1262. * FLUSHCACHE IS OBLIGATED TO ASSURE THAT ALL ALTERED, UNOWNED
  1263. * CACHE PAGES BECOME UNALTERED IN CACHE. THIS REQUIRES THAT
  1264. * SUCH PAGES BE TRANSMITTED TO THE CIRCULAR BUFFER. THIS IN
  1265. * TURN CAN BE DONE ONLY IN ORDER OF AGE AND IN ADDRESS ORDER.
  1266. *
  1267. * UNALTERED FRAMES DO NOT NEED TO BE UPDATED TO DISK. OWNED
  1268. * FRAMES CANNOT YET BE UPDATED - IN THE AGE-RESTRICTED ORDER
  1269. * OF UPDATE, OWNED PAGES CAN BE THOUGHT OF AS HAVING THE
  1270. * WORST AGE CATEGORY.
  1271. *
  1272. * EACH SECTOR CAN BE TRANSMITTED TO THE CIRCULAR BUFFER IF
  1273. * THE BUFFER AND FET ARE AVAILABLE FOR OUTPUT, AND IF THE
  1274. * BUFFER IS EITHER EMPTY OR HAS ONE OR MORE SECTORS ALREADY IN
  1275. * IT FOR WHICH THE NEW SECTOR IS CONTIGOUS IN ADDRESS. IF THE
  1276. * FET IS ALREADY CLAIMED FOR INPUT PROCESSING, PAUSEIO CAN BE
  1277. * CALLED TO STOP AND DISCARD SUCH INPUT. FOR SPANNED
  1278. * ADDRESSES, WE MUST CALL PAUSEIO. THIS LOGIC IS PROVIDED BY
  1279. * INSPECTING THE FLAG RETURNED BY TRYWRITE, AND CALLING
  1280. * TRYWRITE A SECOND TIME WITH PAUSEIO, WHEN TRYWRITE FAILED.
  1281. *
  1282. * BECAUSE THE ALLOCATION OF NEW SECTORS AT THE LOGICAL END OF
  1283. * THE FILE CAN RUN SEVERAL UNITS AHEAD OF THE ACTUAL
  1284. * EXTENDING OF THE PHYSICAL END OF THE FILE, AND BECAUSE THE
  1285. * AGE-DEPENDENT ORDERING MIGHT REQUIRE A HIGH ADDRESS SECTOR
  1286. * TO BE WRITTEN BEFORE A LOWER ADDRESS SECTOR MAY BE LEGALLY
  1287. * WRITTEN, A SITUATION CAN ARISE WHERE A SECTOR MUST BE
  1288. * WRITTEN SEVERAL ADDRESSES BEYOND THE CURRENT PHYSICAL END
  1289. * OF FILE. WHEN THIS OCCURS, FLUSHCACHE RECOGNIZES THE
  1290. * SITUATION AND PADS THE PHYSICAL END OUT TO WITHIN ONE
  1291. * SECTOR OF THE SECTOR THAT MUST BE NEXT WRITTEN. THE
  1292. * INTERMEDIATE SECTORS THUS GET A DISK IMAGE WHICH IS NOT UP
  1293. * TO DATE IN ANY WAY WHATSOEVER. THIS IS NOT A PROBLEM - THE
  1294. * UP TO DATE FRAMES FOR SUCH PADDING WILL EVENTUALLY BE
  1295. * RELEASED FOR ACTUAL DISK UPDATE. THE CONTENT OF PADDING
  1296. * SECTORS IS INNOCUOUS, TO FOLLOW THE RULE THAT NOTHING CAN
  1297. * BE POINTED TO ON DISK UNTIL THE OBJECT ITSELF IS UP TO DATE
  1298. * ON DISK.
  1299. *
  1300. * ENTRY CACHEDIRTY[ALL] - SETUP.
  1301. * CACHEAGE[ALL] - SETUP.
  1302. * CACHEOWNED[ALL] - SETUP.
  1303. * BFDA[ALL] - SETUP.
  1304. * IOREAD - WHETHER OBSOLETE INPUT SCHEDULED.
  1305. * IOACT - WHETHER ANY PREVIOUS I/O SCHEDULED.
  1306. * FETDUN - FET INTERLOCK.
  1307. * IOAPEND - WHETHER A PREVIOUS WRITE EXTENDS.
  1308. * QUARTER - APPROX ONE FOURTH BUFFER CAPACITY.
  1309. * ACCTPRU - SECTOR TRANSFER ACCUMULATOR.
  1310. * MAXDA - FILE PHYSICAL BOUNDARY.
  1311. *
  1312. * EXIT ALL ALTERED AND UNOWNED CACHE FRAMES OUTPUT TO DISK
  1313. * OR BUFFERED FOR OUTPUT.
  1314. * IOREAD - FORCED FALSE IF ANY OUTPUT NEEDED.
  1315. * IOACT, IOWRITE, IOAPEND - POSSIBLY TRUE.
  1316. * CACHEDIRTY[ALL] - FALSE WHERE CACHEOWNED IS FALSE.
  1317. * ACCTPRU - INCREMENTED FOR ANY WORK DONE.
  1318. * MAXDA - INCREMENTED IF FILE EXTENDED.
  1319. *
  1320. * CALLS WIOSTAT, PUSHTEMP, POPTEMP, PAUSEIO, BUFAVAIL,
  1321. * MOVEIO, WAIT, DELAY, TRYWRITE, TRAGIC.
  1322. *
  1323. * USES P<FROM>, TEMP(RESTORED).
  1324. #
  1325. ITEM TMP1, TMP2, BOOL B;
  1326. CONTROL IFEQ MULTI,1;
  1327. WIOSTAT(5); # ACCUMULATE CACHE FLUSHES #
  1328. CONTROL FI;
  1329.  
  1330. PUSHTEMP;
  1331.  
  1332. FLUSHLOOP:
  1333.  
  1334. TMP1=999999999;
  1335. TEMP=-1;
  1336. FOR TMP2=0 STEP 1 UNTIL MAXCACHE DO
  1337. BEGIN # SEARCH FOR OLDEST DIRTY #
  1338. IF CACHEDIRTY[TMP2] AND CACHEAGE[TMP2] LS TMP1
  1339. AND NOT CACHEOWNED[TMP2] THEN
  1340. BEGIN
  1341. TEMP=TMP2;
  1342. TMP1=CACHEAGE[TMP2];
  1343. END
  1344. END
  1345. IF TEMP LS 0 THEN # NO MORE FLUSH NEEDED #
  1346. BEGIN
  1347. POPTEMP;
  1348. IORET
  1349. END
  1350.  
  1351. CACHEDIRTY[TEMP]=FALSE;
  1352. IF BFDA[TEMP] EQ 0 THEN GOTO FLUSHLOOP;
  1353.  
  1354. IF IOREAD THEN # COMPLETE ANY INPUT #
  1355. BEGIN
  1356. PAUSEIO;
  1357. CONTROL IFEQ MULTI,1;
  1358. WIOSTAT(6); # ACCUMULATE READ REJECTS #
  1359. CONTROL FI;
  1360. END
  1361.  
  1362. WRITELOOP:
  1363.  
  1364. WHYLE IOACT AND BUFAVAIL LS O"100" DO
  1365. BEGIN # NEED ROOM IN BUFFER #
  1366. MOVEIO;
  1367. CONTROL IFEQ MULTI,1;
  1368. WAIT;
  1369. CONTROL FI;
  1370. CONTROL IFEQ SINGLE,1;
  1371. IF NOT FETDUN THEN DELAY;
  1372. CONTROL FI;
  1373. END
  1374.  
  1375. CONTROL IFEQ MULTI,1;
  1376. WIOSTAT(7); # ACCUMULATE SECTORS WRITTEN #
  1377. ACCTPRU=ACCTPRU+1;
  1378. CONTROL FI;
  1379.  
  1380. P&lt;FROM>=LOC(BFPRU[TEMP]);
  1381. TRYWRITE(BFDA[TEMP],BOOL);
  1382. IF NOT BOOL THEN
  1383. BEGIN # ONE FAILURE ALLOWED, NOT TWO #
  1384. PAUSEIO;
  1385. CONTROL IFEQ MULTI,1;
  1386. WIOSTAT(8); # ACCUMULATE DISCONTIGUOUS WRITES #
  1387. CONTROL FI;
  1388. P&lt;FROM>=LOC(BFPRU[TEMP]);
  1389. TRYWRITE(BFDA[TEMP],BOOL);
  1390. IF NOT BOOL THEN TRAGIC(" UNABLE TO WRITE FROM BUFFER.$");
  1391. END
  1392.  
  1393. # EITHER ADD MORE PADDING FOR THIS FLUSH OR FLUSH ANOTHER #
  1394. IF IOAPEND AND MAXDA LS BFDA[TEMP] THEN
  1395. BEGIN
  1396. CONTROL IFEQ MULTI,1;
  1397. WIOSTAT(9); # ACCUMULATE PADDING SECTORS #
  1398. CONTROL FI;
  1399. GOTO WRITELOOP;
  1400. END
  1401. IF BUFAVAIL LQ QUARTER THEN MOVEIO;
  1402. GOTO FLUSHLOOP;
  1403.  
  1404. IOEND # OF FLUSHCACHE #
  1405.  
  1406.  
  1407. PROC CLOSEOUT;
  1408. IOBEGIN(CLOSEOUT)
  1409. #
  1410. ** CLOSEOUT - FINISH UPDATE OF DISK.
  1411. *
  1412. * WORKFILE CLOSEOUT CONDITIONS HAVE BEEN DETECTED. UNDER
  1413. * CLOSEOUT CONDITIONS, WE MUST WRITE NOT ONLY THE ZERO-LEVEL
  1414. * SECTOR, BUT ALSO THE DATA SEGMENT (RIGHT AFTER ROOT SECTOR)
  1415. * FOLLOWED BY EOR THEN ARRAY SEGMENT THEN A SECOND EOR.
  1416. *
  1417. * THE CLOSEOUT ROUTINE WRITES THE TWO BINARY SEGMENTS, BUT
  1418. * REQUIRES THAT THE CALLER FIRST FLUSH ALL TREE STRUCTURE
  1419. * SECTORS TO DISK OR AT LEAST TO THE CIRCULAR BUFFER. THE
  1420. * CALLER SHOULD USE THE CLEAN ROUTINE WITH PL=0 TO MEET THAT
  1421. * REQUIREMENT. THE CLOSEOUT ROUTINE DEPENDS ON THE RULE THAT
  1422. * THE ROOT SECTOR OF THE TREE STRUCTURE MUST BE THE LAST
  1423. * (CHRONOLOGICALLY) TO BE FREED FOR UPDATE TO DISK, AND
  1424. * DEPENDS ON THE RULE THAT THE ROOT SECTOR IS AT DISK ADDRESS
  1425. * 1 AND THEREFORE IS CONTIGUOUS WITH NO PREVIOUSLY RELEASED
  1426. * SECTORS. THUS, CLOSEOUT EXPECTS THAT ALL SECTORS EXCEPT
  1427. * THE ROOT HAVE BEEN ACTUALLY WRITTEN TO DISK, AND THE ROOT
  1428. * SECTOR IS EXPECTED TO BE SCHEDULED FOR UPDATE BUT STILL IS
  1429. * PRESENT IN THE CIRCULAR BUFFER.
  1430. *
  1431. * CLOSEOUT INTERCEPTS THE ISSUANCE OF CIO FUNCTION CODES FOR
  1432. * THE UPDATE OF THE ROOT SECTOR, AND AFTER APPENDING THE
  1433. * SCALAR DATA SEGMENT ONTO THE ROOT SECTOR IN THE CIRCULAR
  1434. * BUFFER, CLOSEOUT CALLS PAUSEIO (AND THUS MOVEIO) SUCH THAT
  1435. * ONE WRITE WITH END OF RECORD OCCURS. THEN CLOSEOUT
  1436. * CONSTRUCTS A NEW CIRCULAR BUFFER IMAGE FOR THE ARRAY
  1437. * SEGMENT, AND USES PAUSEIO A SECOND TIME TO WRITE ANOTHER
  1438. * MULTIPLE SECTOR RECORD.
  1439. *
  1440. * ENTRY CLEAN HAS BEEN CALLED WITH PL=0.
  1441. * IOAPEND - WHETHER FILE PRESENTLY EMPTY.
  1442. * LASTDA, MAXDA - LOGICAL AND PHYSICAL FILE SIZES.
  1443. * DATALEN, ARRAYLEN - LENGTHS OF BINARY SEGMENTS.
  1444. * DATAPRUS, ARRAYPRUS - LENGTHS IN SECTORS.
  1445. *
  1446. * EXIT FILE COMPLETELY DRAINED TO DISK, FET INACTIVE.
  1447. * LASTDA, MAXDA - ONE OF THESE TWO IS INCREMENTED.
  1448. *
  1449. * CALLS FLUSHCACHE, WTWBUF, PAUSEIO, INITFET.
  1450. *
  1451. * USES P<FROM>, IOWRITE, IOWRTEOR, IOAPEND, IOACT.
  1452. #
  1453. FLUSHCACHE; # PUT SECTOR 1 (ROOT PRU) INTO BUFFER #
  1454. IOWRTEOR=TRUE; # WRITE ROOT PRU PLUS DATA SEGMENT #
  1455. P&lt;FROM>=LOC(DATASTART);
  1456. WTWBUF(DATALEN);
  1457. IF IOAPEND THEN MAXDA=MAXDA+DATAPRUS;
  1458. ELSE LASTDA=LASTDA+DATAPRUS;
  1459. PAUSEIO;
  1460. INITFET(DISK,DSKSIZ); # NOW SET UP FOR ARRAYS #
  1461. IOACT=TRUE;
  1462. IOWRITE=TRUE;
  1463. IF FETCRI GR MAXDA THEN
  1464. BEGIN
  1465. IOAPEND=TRUE;
  1466. FETRR=LOC(DUMB);
  1467. MAXDA=MAXDA+ARRAYPRUS;
  1468. END
  1469. ELSE
  1470. BEGIN
  1471. IOAPEND=FALSE;
  1472. FETRR=FETCRI;
  1473. LASTDA=LASTDA+ARRAYPRUS;
  1474. END
  1475. IOWRTEOR=TRUE;
  1476. P&lt;FROM>=LOC(ARRAYSTART);
  1477. WTWBUF(ARRAYLEN);
  1478. PAUSEIO;
  1479. IOEND # OF CLOSEOUT #
  1480. PAGE
  1481. PROC CLEAN;
  1482. IOBEGIN(CLEAN)
  1483. #
  1484. ** CLEAN - DISCONNECT SECTOR FROM LOWEST TREE LEVEL.
  1485. *
  1486. * CLEAN IS CALLED WHENEVER A ROUTINE WISHES TO DISCARD THE
  1487. * SECTOR PRESENTLY ASSOCIATED WITH A TREE LEVEL. THIS CAN BE
  1488. * DONE ONLY IN THE REVERSE ORDER OF THE TREE HIERARCHY, IE,
  1489. * THE BOTTOM LEVEL FIRST AND THE ROOT LEVEL LAST. THE EFFECT
  1490. * OF CALLING CLEAN IS TO DISCONNECT THE SECTOR FROM THE TREE
  1491. * STRUCTURE BY FREEING THE CACHE FRAME FROM OWNERSHIP, FIRST
  1492. * DISCONNECTING ANY TREE LEVELS LOWER THAN THE CURRENT LEVEL.
  1493. *
  1494. * IF THE TREE LEVEL WAS PREVIOUSLY FLAGGED AS ALTERED, THE
  1495. * FREED CACHE FRAME IS SIMILARLY FLAGGED. ALL HEADER WORD
  1496. * DATA IS COPIED FROM THE TREE CONTROL VECTOR TO THE SECTOR
  1497. * IMAGE IN CACHE.
  1498. *
  1499. * ENTRY PL - LEVEL TO BE FREED.
  1500. * PALVL - DEEPEST ACTIVE TREE LEVEL.
  1501. * PAHEAD[ALL] - HEADER WORDS IN TREE VECTOR.
  1502. * PACACHE[ALL] - SETUP.
  1503. * CACHEOWNED[ALL] - SETUP.
  1504. * PADIRTY[ALL] - ALTERATION FLAG.
  1505. *
  1506. * EXIT THIS LEVEL AND ALL DEEPER LEVELS FREED.
  1507. * CACHEOWNED[ANY] - FORCED TRUE FOR THOSE FREED.
  1508. * CACHEDIRTY[ANY] - FORCED TRUE FOR THOSE FREED
  1509. * WITH PADIRTY TRUE.
  1510. * CACHEAGE[ANY] - INITIALIZED FOR THOSE FREED.
  1511. *
  1512. * CALLS DROPIT(INTERNAL), DISOWNCACHE.
  1513. *
  1514. * USES TPL.
  1515. #
  1516.  
  1517. PROC DROPIT;
  1518. BEGIN
  1519. IF CACHEOWNED[PACACHE[TPL]] THEN BFHEAD[PACACHE[TPL]]=PAHEAD[TPL];
  1520. DISOWNCACHE(PACACHE[TPL]);
  1521. END # OF DROPIT #
  1522.  
  1523. # START OF MAIN CODE #
  1524.  
  1525. IF PADIRTY[PL] THEN
  1526. BEGIN
  1527. FOR TPL = PALVL STEP -1 UNTIL PL DO
  1528. BEGIN
  1529. IF PADIRTY[TPL] THEN
  1530. BEGIN
  1531. PADIRTY[TPL]=FALSE;
  1532. CACHEDIRTY[PACACHE[TPL]]=TRUE;
  1533. DROPIT;
  1534. END
  1535. ELSE DROPIT;
  1536. END
  1537. END
  1538. ELSE
  1539. BEGIN
  1540. FOR TPL=PALVL STEP -1 UNTIL PL DO DROPIT;
  1541. END
  1542.  
  1543. IOEND
  1544.  
  1545.  
  1546. PROC CLEANALL;
  1547. IOBEGIN(CLEANALL)
  1548. #
  1549. ** CLEANALL - CLEAN ENTIRE TREE STRUCTURE AND DATA SEGEMENTS.
  1550. *
  1551. * CLEANALL IS USED TO INITIATE CLOSEOUT OF THE WORKFILE
  1552. * MANAGER. THE ENTIRE TREE STRUCTURE IS CLEANED WITH ANY
  1553. * ALTERED SECTORS WRITTEN TO DISK, AND THE SCALAR AND ARRAY
  1554. * DATA SEGMENTS ARE UPDATED.
  1555. *
  1556. * ENTRY CACHEOWNED[ALL] - SETUP.
  1557. * PACACHE[ALL] - SETUP.
  1558. * PADIRTY[ALL] - SETUP.
  1559. * PAHEAD[ALL] -SETUP.
  1560. * PALVL - DEEPEST TREE LEVEL.
  1561. *
  1562. * EXIT PL - ZERO.
  1563. * CACHEDIRTY[ALL] - FALSE.
  1564. * FET AND CIRCULAR BUFFER - COMPLETE/EMPTY.
  1565. * PADIRTY[ALL] - FALSE.
  1566. *
  1567. * CALLS CLEAN, CLOSEOUT, RECLAIMCACHE.
  1568. #
  1569. PADIRTY[0]=TRUE;
  1570. PL=0;
  1571. CLEAN;
  1572. CLOSEOUT;
  1573. RECLAIMCACHE;
  1574. IOEND # OF CLEANALL #
  1575. PAGE
  1576. PROC BK;
  1577. IOBEGIN(BK)
  1578. #
  1579. ** BK - BACK UP ONE LINE.
  1580. *
  1581. * BK IS ORGANIZED INTO THREE OPERATIONAL PHASES. THE FIRST
  1582. * PHASE DETERMINES WHETHER THE CURRENT TREE PATH ALREADY
  1583. * CONTAINS THE SECTOR WITH THE DESIRED LINE OF TEXT, AND IF
  1584. * NOT, IT CLEANS AWAY AS MANY TREE LEVELS AS NECESSARY, FROM
  1585. * THE BOTTOM TOWARDS THE ROOT, UNTIL WE ARE IN A DIRECTORY
  1586. * WHOSE SPHERE OF INFLUENCE INCLUDES THE DESIRED LINE.
  1587. *
  1588. * THE SECOND PHASE ASSURES THAT WE HAVE A FULL DEPTH TREE
  1589. * STRUCTURE CONTAINING THE RIGHT SECTOR AT THE DATA (BOTTOM)
  1590. * LEVEL. IF THE FIRST PHASE WAS NON-TRIVIAL, THEN THE SECOND
  1591. * PHASE WILL ALSO HAVE REAL WORK TO PERFORM, WORKING BACK
  1592. * TOWARD DEEP TREE LEVELS, READING IN EACH SECTOR NEEDED.
  1593. * THE SECOND PHASE IS A NO-OP IF THE FIRST PHASE WAS A NO-OP
  1594. * AND IF THE TREE ALREADY EXISTS ALL THE WAY DOWN TO THE DATA
  1595. * LEVEL. HOWEVER, THE FIRST PHASE COULD HAVE BEEN A NO-OP
  1596. * FOR AN INCOMPLETE TREE PATH, IN WHICH CASE THE SECOND PHASE
  1597. * MUST DEEPEN THE TREE PATH.
  1598. *
  1599. * THE THIRD PHASE SCANS THE DATA SECTOR TO FIND THE RIGHT
  1600. * LINE IMAGE. THE INTERNAL LINE IMAGE FORMAT USES THE SIGN
  1601. * BIT TO INDICATE WORDS WHICH ARE THE LAST WORDS OF LINES.
  1602. *
  1603. * ENTRY CURRENT - CURRENT LINE.
  1604. * PALVL - DEEPEST TREE LEVEL.
  1605. * ALL PATH AND CACHE CONTROLS SETUP.
  1606. * P<MVLNBUF> - WHERE TO PUT LINE OF TEXT.
  1607. * DISP, CURNW - DESCRIBE WORD OFFSET AND LENGTH OF
  1608. * PREVIOUS CURRENT LINE.
  1609. *
  1610. * EXIT CURRENT - DECREMENTED.
  1611. * MVLNBUF - CONTAINS LINE OF TEXT.
  1612. * PALVL - NEW VALUE FOR DEEPEST TREE LEVEL.
  1613. * ALL PATH CONTROLS - MAY CONTROL DIFFERENT SECTORS
  1614. * FOR DEEPER TREE LEVELS.
  1615. * ALL CACHE CONTROLS - MAY CONTROL DIFFERENT SECTORS.
  1616. * FET, CIRCULAR BUFFER, READ LIST - MAY CONTROL
  1617. * A PREFETCH OPERATION.
  1618. * CURNW - SIZE OF NEW LINE.
  1619. * DISP - OFFSET OF NEW LINE.
  1620. *
  1621. * CALLS TRAGIC, CLEAN, PUSHTEMP, READPA, POPTEMP, PREFETCH,
  1622. * MOVELN.
  1623. *
  1624. * USES TEMP(RESTORED), P<PRU>, PL.
  1625. #
  1626. IF CURRENT LQ 0 THEN TRAGIC(" BAK BEFORE START OF FILE.$");
  1627.  
  1628. CURRENT = CURRENT - 1;
  1629.  
  1630. FOR PL = PALVL WHILE PAFIRST[PL] GR CURRENT DO
  1631. BEGIN
  1632. CLEAN;
  1633. PL = PL - 1;
  1634. END
  1635.  
  1636. P&lt;PRU> = LOC(BFPRU[PACACHE[PL]]);
  1637.  
  1638. DISP = PADISP[PL] - 1;
  1639. CONTROL IFGQ PARANOIA,5;
  1640. IF DISP LQ 0 THEN TRAGIC(" DIRECTORY BLOCK POINTER TOO SMALL.$");
  1641. CONTROL FI;
  1642. PADISP[PL] = DISP;
  1643.  
  1644. IF PADIR[PL] THEN
  1645. BEGIN
  1646. FOR PL = PL WHILE PADIR[PL] DO
  1647. BEGIN
  1648. PL = PL + 1;
  1649. PALVL = PL;
  1650.  
  1651. PUSHTEMP;
  1652. TEMP=DIRDA[DISP];
  1653. READPA;
  1654. POPTEMP;
  1655.  
  1656. PAFIRST[PL] = CURRENT - DIRNL[DISP] + 1;
  1657. PALAST[PL] = CURRENT;
  1658.  
  1659. P&lt;PRU> = LOC(BFPRU[PACACHE[PL]]);
  1660.  
  1661. DISP = PAFINAL[PL];
  1662. PADISP[PL] = DISP;
  1663. END
  1664.  
  1665. PREFETCH(-1);
  1666. END
  1667.  
  1668. # NOTE THIS CODE REQUIRES INTERNAL CHARSET USAGE OF SIGN BIT #
  1669. FOR DISP = DISP - 1 WHILE DISP NQ 0 AND B&lt;0,1>DATWORD[DISP] EQ 0
  1670. DO DISP = DISP - 1;
  1671.  
  1672. PADISP[PL] = DISP + 1;
  1673. P&lt;FROM> = LOC(BFPRU[PACACHE[PALVL]]) + PADISP[PALVL];
  1674. CURNW = MOVELN(FROM,MVLNBUF);
  1675.  
  1676. IOEND
  1677. PAGE
  1678. PROC FW;
  1679. IOBEGIN(FW)
  1680. #
  1681. ** FW - ADVANCE ONE LINE.
  1682. *
  1683. * FW IS ORGANIZED INTO THREE OPERATIONAL PHASES. THE FIRST
  1684. * PHASE DETERMINES WHETHER THE CURRENT TREE PATH ALREADY
  1685. * CONTAINS THE SECTOR WITH THE DESIRED LINE OF TEXT, AND IF
  1686. * NOT, IT CLEANS AWAY AS MANY TREE LEVELS AS NECESSARY, FROM
  1687. * THE BOTTOM TOWARDS THE ROOT, UNTIL WE ARE IN A DIRECTORY
  1688. * WHOSE SPHERE OF INFLUENCE INCLUDES THE DESIRED LINE.
  1689. *
  1690. * THE SECOND PHASE ASSURES THAT WE HAVE A FULL DEPTH TREE
  1691. * STRUCTURE CONTAINING THE RIGHT SECTOR AT THE DATA (BOTTOM)
  1692. * LEVEL. IF THE FIRST PHASE WAS NON-TRIVIAL, THEN THE SECOND
  1693. * PHASE WILL ALSO HAVE REAL WORK TO PERFORM, WORKING BACK
  1694. * TOWARD DEEP TREE LEVELS, READING IN EACH SECTOR NEEDED.
  1695. * THE SECOND PHASE IS A NO-OP IF THE FIRST PHASE WAS A NO-OP
  1696. * AND IF THE TREE ALREADY EXISTS ALL THE WAY DOWN TO THE DATA
  1697. * LEVEL. HOWEVER, THE FIRST PHASE COULD HAVE BEEN A NO-OP
  1698. * FOR AN INCOMPLETE TREE PATH, IN WHICH CASE THE SECOND PHASE
  1699. * MUST DEEPEN THE TREE PATH.
  1700. *
  1701. * THE THIRD PHASE IDENTIFIES THE CORRECT LINE IMAGE WITHIN
  1702. * THE DATA SECTOR. THE MECHANISM USED DEPENDS ON WHETHER THE
  1703. * SECOND PHASE WAS ACTUALLY PERFORMED, SINCE FOR A NO-OP THE
  1704. * DISP AND CURNW PARAMETERS FOR THE PREVIOUS CURRENT LINE
  1705. * PROVIDE ALL INFORMATION REQUIRED TO ADVANCE ONE LINE.
  1706. *
  1707. * ENTRY CURRENT - CURRENT LINE.
  1708. * PALVL - DEEPEST TREE LEVEL.
  1709. * ALL PATH AND CACHE CONTROLS SETUP.
  1710. * P<MVLNBUF> - WHERE TO PUT LINE OF TEXT.
  1711. * DISP, CURNW - DESCRIBE WORD OFFSET AND LENGTH OF
  1712. * PREVIOUS CURRENT LINE.
  1713. *
  1714. * EXIT CURRENT - INCREMENTED.
  1715. * MVLNBUF - CONTAINS LINE OF TEXT.
  1716. * PALVL - NEW VALUE FOR DEEPEST TREE LEVEL.
  1717. * ALL PATH CONTROLS - MAY CONTROL DIFFERENT SECTORS
  1718. * FOR DEEPER TREE LEVELS.
  1719. * ALL CACHE CONTROLS - MAY CONTROL DIFFERENT SECTORS.
  1720. * FET, CIRCULAR BUFFER, READ LIST - MAY CONTROL
  1721. * A PREFETCH OPERATION.
  1722. * CURNW - SIZE OF NEW LINE.
  1723. * DISP - OFFSET OF NEW LINE.
  1724. *
  1725. * CALLS TRAGIC, CLEAN, PUSHTEMP, READPA, POPTEMP, PREFETCH,
  1726. * MOVELN.
  1727. *
  1728. * USES TEMP(RESTORED), P<PRU>, PL.
  1729. #
  1730.  
  1731. IF CURRENT GQ PALAST[0] THEN TRAGIC(" FWD BEYOND END OF FILE.$");
  1732.  
  1733. CURRENT = CURRENT + 1;
  1734.  
  1735. FOR PL = PALVL WHILE PALAST[PL] LS CURRENT DO
  1736. BEGIN
  1737. CLEAN;
  1738. PL = PL - 1;
  1739. END
  1740.  
  1741. P&lt;PRU> = LOC(BFPRU[PACACHE[PL]]);
  1742.  
  1743. DISP = PADISP[PL];
  1744.  
  1745. IF PADIR[PL] THEN
  1746. BEGIN
  1747. DISP = DISP + 1;
  1748. CONTROL IFGQ PARANOIA,5;
  1749. IF DISP GR PAFINAL[PL] THEN
  1750. BEGIN
  1751. TRAGIC(" DIRECTORY BLOCK POINTER TOO LARGE (1).$");
  1752. END
  1753. CONTROL FI;
  1754. PADISP[PL] = DISP;
  1755.  
  1756. FOR PL = PL WHILE PADIR[PL] DO
  1757. BEGIN
  1758. PL = PL + 1;
  1759. PALVL = PL;
  1760.  
  1761. PUSHTEMP;
  1762. TEMP=DIRDA[DISP];
  1763. READPA;
  1764. POPTEMP;
  1765.  
  1766. PAFIRST[PL] = CURRENT;
  1767. PALAST[PL] = CURRENT + DIRNL[DISP] - 1;
  1768.  
  1769. P&lt;PRU> = LOC(BFPRU[PACACHE[PL]]);
  1770.  
  1771. DISP = 1;
  1772. PADISP[PL] = 1;
  1773. END
  1774.  
  1775. PREFETCH(+1);
  1776. END
  1777.  
  1778. ELSE PADISP[PL] = DISP + CURNW;
  1779.  
  1780. P&lt;FROM> = LOC(BFPRU[PACACHE[PALVL]]) + PADISP[PALVL];
  1781. CURNW = MOVELN(FROM,MVLNBUF);
  1782.  
  1783. IOEND
  1784. PAGE
  1785. PROC POSR;
  1786. IOBEGIN(POSR)
  1787. #
  1788. ** POSR - POSITION TO A RANDOMLY SELECTED LINE.
  1789. *
  1790. * POSR IS ORGANIZED INTO THREE OPERATIONAL PHASES. THE FIRST
  1791. * PHASE DETERMINES WHETHER THE CURRENT TREE PATH ALREADY
  1792. * CONTAINS THE SECTOR WITH THE DESIRED LINE OF TEXT, AND IF
  1793. * NOT, IT CLEANS AWAY AS MANY TREE LEVELS AS NECESSARY, FROM
  1794. * THE BOTTOM TOWARDS THE ROOT, UNTIL WE ARE IN A DIRECTORY
  1795. * WHOSE SPHERE OF INFLUENCE INCLUDES THE DESIRED LINE.
  1796. *
  1797. * THE SECOND PHASE ASSURES THAT WE HAVE A FULL DEPTH TREE
  1798. * STRUCTURE CONTAINING THE RIGHT SECTOR AT THE DATA (BOTTOM)
  1799. * LEVEL. IF THE FIRST PHASE WAS NON-TRIVIAL, THEN THE SECOND
  1800. * PHASE WILL ALSO HAVE REAL WORK TO PERFORM, WORKING BACK
  1801. * TOWARD DEEP TREE LEVELS, READING IN EACH SECTOR NEEDED.
  1802. * THE SECOND PHASE IS A NO-OP IF THE FIRST PHASE WAS A NO-OP
  1803. * AND IF THE TREE ALREADY EXISTS ALL THE WAY DOWN TO THE DATA
  1804. * LEVEL. HOWEVER, THE FIRST PHASE COULD HAVE BEEN A NO-OP
  1805. * FOR AN INCOMPLETE TREE PATH, IN WHICH CASE THE SECOND PHASE
  1806. * MUST DEEPEN THE TREE PATH.
  1807. *
  1808. * THE THIRD PHASE SCANS THE DATA SECTOR TO FIND THE RIGHT
  1809. * LINE IMAGE. THE INTERNAL LINE IMAGE FORMAT USES THE SIGN
  1810. * BIT TO INDICATE WORDS WHICH ARE THE LAST WORDS OF LINES.
  1811. *
  1812. * ENTRY NEWCURL - DESIRED LINE.
  1813. * PALVL - DEEPEST TREE LEVEL.
  1814. * ALL PATH AND CACHE CONTROLS SETUP.
  1815. * P<MVLNBUF> - WHERE TO PUT LINE OF TEXT.
  1816. * DISP, CURNW - DESCRIBE WORD OFFSET AND LENGTH OF
  1817. * PREVIOUS CURRENT LINE.
  1818. *
  1819. * EXIT CURRENT - MATCHES NEWCURL.
  1820. * MVLNBUF - CONTAINS LINE OF TEXT.
  1821. * PALVL - NEW VALUE FOR DEEPEST TREE LEVEL.
  1822. * ALL PATH CONTROLS - MAY CONTROL DIFFERENT SECTORS
  1823. * FOR DEEPER TREE LEVELS.
  1824. * ALL CACHE CONTROLS - MAY CONTROL DIFFERENT SECTORS.
  1825. * FET, CIRCULAR BUFFER, READ LIST - MAY CONTROL
  1826. * A PREFETCH OPERATION.
  1827. * CURNW - SIZE OF NEW LINE.
  1828. * DISP - OFFSET OF NEW LINE.
  1829. *
  1830. * CALLS TRAGIC, CLEAN, PUSHTEMP, READPA, POPTEMP, PREFETCH,
  1831. * MOVELN.
  1832. *
  1833. * USES TEMP(RESTORED), P<PRU>, PL.
  1834. #
  1835.  
  1836. IF NEWCURL LS 0 OR NEWCURL GR PALAST[0] THEN
  1837. BEGIN
  1838. TRAGIC(" LINE NOT FOUND IN FILE.$");
  1839. END
  1840.  
  1841. PUSHTEMP;
  1842.  
  1843. CURRENT = NEWCURL;
  1844.  
  1845. FOR PL=PALVL WHILE
  1846. NOT(CURRENT GQ PAFIRST[PL] AND CURRENT LQ PALAST[PL]) DO
  1847. BEGIN
  1848. CLEAN;
  1849. PL = PL - 1;
  1850. END
  1851.  
  1852. P&lt;PRU> = LOC(BFPRU[PACACHE[PL]]);
  1853.  
  1854. FOR PL = PL WHILE PADIR[PL] DO
  1855. BEGIN
  1856. TEMP = PAFIRST[PL];
  1857.  
  1858. FOR DISP = 1 WHILE CURRENT GQ TEMP+DIRNL[DISP] DO
  1859. BEGIN
  1860. TEMP = TEMP + DIRNL[DISP];
  1861. DISP = DISP + 1;
  1862. END
  1863.  
  1864. CONTROL IFGQ PARANOIA,5;
  1865. IF DISP GR PAFINAL[PL] THEN
  1866. BEGIN
  1867. TRAGIC(" DIRECTORY BLOCK POINTER TOO LARGE (2).$");
  1868. END
  1869. CONTROL FI;
  1870. PADISP[PL] = DISP;
  1871.  
  1872. PL = PL + 1;
  1873. PALVL = PL;
  1874.  
  1875. PAFIRST[PL] = TEMP;
  1876. PALAST[PL] = TEMP + DIRNL[DISP] - 1;
  1877.  
  1878. PUSHTEMP;
  1879. TEMP=DIRDA[DISP];
  1880. READPA;
  1881. POPTEMP;
  1882.  
  1883. P&lt;PRU> = LOC(BFPRU[PACACHE[PL]]);
  1884.  
  1885. END
  1886.  
  1887. TEMP = PAFIRST[PL];
  1888.  
  1889. FOR DISP = 1 WHILE CURRENT NQ TEMP DO
  1890. BEGIN
  1891. # NOTE THIS CODE REQUIRES INTERNAL CHARSET USAGE OF SIGN BIT #
  1892. IF B&lt;0,1>DATWORD[DISP] NQ 0 THEN TEMP = TEMP + 1;
  1893. DISP = DISP + 1;
  1894. END
  1895.  
  1896. CONTROL IFGQ PARANOIA,5;
  1897. IF DISP GR PAFINAL[PL] THEN
  1898. BEGIN
  1899. TRAGIC(" DIRECTORY BLOCK POINTER TOO LARGE (3).$");
  1900. END
  1901. CONTROL FI;
  1902.  
  1903. PADISP[PL] = DISP;
  1904.  
  1905. P&lt;FROM> = LOC(BFPRU[PACACHE[PALVL]]) + PADISP[PALVL];
  1906. CURNW = MOVELN(FROM,MVLNBUF);
  1907.  
  1908. POPTEMP;
  1909.  
  1910. IOEND
  1911. PAGE
  1912.  
  1913. PROC FWD;
  1914. IOBEGIN(FWD)
  1915. #
  1916. ** FWD - EXTERNAL INTERFACE FOR FORWARD MOVEMENT.
  1917. *
  1918. * FWD INTERFACES TO THE FW ROUTINE TO ADVANCE ONE LINE
  1919. * FROM THE CURRENT POSITION. FWD ALSO CONTROLS THE BASE
  1920. * ADDRESS FOR MVLNBUF AND ACCUMULATES STATISTICS.
  1921. *
  1922. * ENTRY P<LINEBUF> - WHERE TO PUT TEXT OR ZERO FOR INVISIBLE
  1923. * POSITIONING FUNCTION.
  1924. * CURRENT - CURRENT LINE.
  1925. *
  1926. * EXIT CURRENT - INCREMENTED.
  1927. * LINEBUF - TEXT MOVE HERE IF BASE ADDRESS NONZERO.
  1928. *
  1929. * CALLS FW.
  1930. *
  1931. * USES P<MVLNBUF>.
  1932. #
  1933.  
  1934. CONTROL IFEQ MULTI,1;
  1935. WIOSTAT(0); # ACCUMULATE LINE ACCESES #
  1936. CONTROL FI;
  1937.  
  1938. P&lt;MVLNBUF>=LOC(LINEBUF);
  1939. FW;
  1940. P&lt;MVLNBUF>=0;
  1941. IOEND
  1942.  
  1943. PROC BAK;
  1944. IOBEGIN(BAK)
  1945. #
  1946. ** FWD - EXTERNAL INTERFACE FOR BACKWARD MOVEMENT.
  1947. *
  1948. * BAK INTERFACES TO THE BK ROUTINE TO REGRESS ONE LINE
  1949. * FROM THE CURRENT POSITION. BAK ALSO CONTROLS THE BASE
  1950. * ADDRESS FOR MVLNBUF AND ACCUMULATES STATISTICS.
  1951. *
  1952. * ENTRY P<LINEBUF> - WHERE TO PUT TEXT OR ZERO FOR INVISIBLE
  1953. * POSITIONING FUNCTION.
  1954. * CURRENT - CURRENT LINE.
  1955. *
  1956. * EXIT CURRENT - DECREMENTED.
  1957. * LINEBUF - TEXT MOVE HERE IF BASE ADDRESS NONZERO.
  1958. *
  1959. * CALLS BK.
  1960. *
  1961. * USES P<MVLNBUF>.
  1962. #
  1963.  
  1964. CONTROL IFEQ MULTI,1;
  1965. WIOSTAT(0); # ACCUMULATE LINE ACCESES #
  1966. CONTROL FI;
  1967.  
  1968. P&lt;MVLNBUF>=LOC(LINEBUF);
  1969. BK;
  1970. P&lt;MVLNBUF>=0;
  1971. IOEND
  1972.  
  1973. PROC POS;
  1974. IOBEGIN(POS)
  1975. #
  1976. ** POS - EXTERNAL INTERFACE FOR RANDOM MOVEMENT.
  1977. *
  1978. * POS INTERFACES TO THE POSR ROUTINE TO GO TO ANY LINE
  1979. * FROM THE CURRENT POSITION. POS ALSO CONTROLS THE BASE
  1980. * ADDRESS FOR MVLNBUF AND ACCUMULATES STATISTICS.
  1981. *
  1982. * ENTRY P<LINEBUF> - WHERE TO PUT TEXT OR ZERO FOR INVISIBLE
  1983. * POSITIONING FUNCTION.
  1984. * NEWCURL - DESIRED LINE.
  1985. * CURRENT - PREVIOUS CURRENT LINE.
  1986. *
  1987. * EXIT CURRENT - MATCHES NEWCURL.
  1988. * LINEBUF - TEXT MOVE HERE IF BASE ADDRESS NONZERO.
  1989. *
  1990. * CALLS POSR.
  1991. *
  1992. * USES P<MVLNBUF>.
  1993. #
  1994.  
  1995. CONTROL IFEQ MULTI,1;
  1996. WIOSTAT(0); # ACCUMULATE LINE ACCESES #
  1997. CONTROL FI;
  1998.  
  1999. P&lt;MVLNBUF>=LOC(LINEBUF);
  2000. IF NEWCURL EQ CURRENT-1 THEN BK;
  2001. ELSE IF NEWCURL EQ CURRENT+1 THEN FW;
  2002. ELSE IF NEWCURL NQ CURRENT THEN POSR;
  2003. ELSE # JUST READOUT SAME LINE #
  2004. BEGIN
  2005. P&lt;FROM> = LOC(BFPRU[PACACHE[PALVL]]) + PADISP[PALVL];
  2006. DUMB = MOVELN(FROM,LINEBUF);
  2007. END
  2008. P&lt;MVLNBUF>=0;
  2009. IOEND # OF POS #
  2010. PAGE
  2011. PROC SPLITTOP;
  2012. IOBEGIN(SPLITTOP)
  2013. #
  2014. ** SPLITTOP - SPLIT ROOT SECTOR TO MAKE NEW LEVEL.
  2015. *
  2016. * SPLITTOP IS USED WHEN THE ROOT SECTOR OVERFLOWS. THE ROOT
  2017. * SECTOR MUST ALWAYS EXIST AT DISK ADDRESS 1, THUS THE METHOD
  2018. * USED TO SPLIT IT IS DIFFERENT FROM THAT USED FOR ANY OTHER
  2019. * SECTOR. THE EXISTING CONTENTS OF THE ROOT SECTOR ARE
  2020. * PLACED IN TWO NEW SECTORS, AND THE ROOT SECTOR IS
  2021. * RECONSTRUCTED AS A DIRECTORY POINTING TO THESE TWO NEW
  2022. * SECTORS. THUS THE OVERALL TREE STRUCTURE IS DEEPENED BY
  2023. * ONE LEVEL.
  2024. *
  2025. * HOWEVER, SPLITTOP DOES NOT PROVIDE ALL THIS ALGORITHM.
  2026. * SPLITTOP DOES PRODUCE A NEW TREE LEVEL WITH A REBUILT ROOT,
  2027. * BUT STOPS SHORT OF FITTING THE OVERFLOWED TEXT INTO A PAIR
  2028. * OF SECTORS. SPLITTOP PLACES THE PRE-OVERFLOW SECTOR
  2029. * CONTENT INTO A SINGLE SECTOR AT THE NEW INTERMEDIATE TREE
  2030. * LEVEL, AND ESTABLISHES THIS AS THE CURRENT TREE PATH LEVEL.
  2031. * THE CALLER IS THEN RESPONSIBLE TO USE ONE OF THE OTHER
  2032. * SECTOR SPLITTING ALGORITHMS TO GET THE TEXT ACTUALLY SPLIT
  2033. * INTO TWO SECTORS. THESE OTHER ALGORITHMS WILL UPDATE THE
  2034. * NEW ROOT TO POINT TO THE OVERFLOW SECTOR.
  2035. *
  2036. * ENTRY PL - MUST EQUAL ZERO.
  2037. * PADEPTH[0] - INDICATE HIGH WATER MARK OF TREE DEPTH.
  2038. * PALVL - CURRENT DEEPEST TREE LEVEL ON PATH.
  2039. * ALL PATH CONTROLS - SETUP.
  2040. * CACHE - AT LEAST ONE FRAME MUST BE AVAILABLE TO
  2041. * BE CLAIMED.
  2042. *
  2043. * EXIT PL - ONE.
  2044. * PALVL - INCREMENTED.
  2045. * PADEPTH[0] - INCREMENETED.
  2046. * ALL PATH CONTROLS - SHUFFLED TO DEEPER LEVELS.
  2047. * CACHE - ONE FRAME ALLOCATED FOR NEW LEVEL 0.
  2048. * ROOT SECTOR CACHE FRAME - BUILT AS DIRECTORY WITH
  2049. * ONE ENTRY POINTING TO INTERMEDIATE SECTOR.
  2050. * PATH LEVEL 1 - BUILT AS INTERMEDIATE TREE LEVEL
  2051. * USING SAME CACHE FRAME AS FORMER ROOT LEVEL,
  2052. * BUT ASSIGNED A NEWLY ALLOCATED DISK ADDRESS.
  2053. * MARKED AS ALTERED SO NEW DISK ADDRESS CAN BE
  2054. * EVENTUALLY WRITTEN TO DISK.
  2055. *
  2056. * CALLS TRAGIC, ALLOC, ALLOCCACHE, MOVEWD.
  2057. *
  2058. * USES P<PRU>.
  2059. #
  2060. IF PADEPTH[0] GQ MAXDEPTH THEN TRAGIC(" FILE TOO LARGE.$");
  2061. PADEPTH[0] = PADEPTH[0] + 1;
  2062.  
  2063. FOR PL = PALVL STEP -1 UNTIL 0 DO # SLIDE PATH UP #
  2064. BEGIN
  2065. PAFIRST[PL+1] = PAFIRST[PL];
  2066. PALAST[PL+1] = PALAST[PL];
  2067. PADISP[PL+1] = PADISP[PL];
  2068. PAHEAD[PL+1] = PAHEAD[PL];
  2069. PACACHE[PL+1] = PACACHE[PL];
  2070. END
  2071.  
  2072. PL = 1; # STEP UP PL & PALVL #
  2073. PALVL = PALVL + 1;
  2074.  
  2075. PATOP[1] = FALSE; # FIX UP OLD TOP #
  2076. PADIRTY[1] = FALSE;
  2077. PADA[1] = 0;
  2078. ALLOC;
  2079. ALLOCCACHE;
  2080. PADIRTY[1] = TRUE;
  2081. P&lt;FROM> = LOC(BFPRU[PACACHE[0]]) + 1;
  2082. P&lt;TOO> = LOC(BFPRU[PACACHE[1]]) + 1;
  2083. MOVEWD(PAFINAL[0],FROM,TOO);
  2084.  
  2085. PADATA[0] = FALSE; # BUILD NEW TOP #
  2086. PADIR[0] = TRUE;
  2087. PADIRTY[0] = TRUE;
  2088. PAFINAL[0] = 1;
  2089. P&lt;PRU> = LOC(BFPRU[PACACHE[0]]);
  2090. DIRDA[1] = PADA[1];
  2091. DIRNL[1] = PALAST[1] - PAFIRST[1] + 1;
  2092.  
  2093. PADISP[0] = 1;
  2094. IOEND
  2095. PAGE
  2096. PROC SPLITAPEND;
  2097. IOBEGIN(SPLITAPEND)
  2098. #
  2099. ** SPLITAPEND - SPLIT SECTOR JUST AFTER CURRENT CONTENT.
  2100. *
  2101. * SPLITAPEND IS USED TO OVERFLOW ANY NON-ROOT SECTOR UNDER
  2102. * THE CONDITION THAT THE OVERFLOW TEXT BELONGS JUST AFTER ALL
  2103. * OF THE TEXT ALREADY CONTAINED IN THE SECTOR. THUS, THE
  2104. * SECTOR REMAINS JUST AS IT IS, AND A NEW SECTOR IS
  2105. * CONSTRUCTED WHICH CONTAINS PRECISELY THE OVERFLOW TEXT.
  2106. * SINCE NO EXISTING TEXT LEAVES THE SECTOR, THERE IS NO NEED
  2107. * TO DISCARD IT AND BUILD TWO COMPLETELY NEW SECTORS. THUS,
  2108. * SPLITAPEND IS MORE EFFICIENT THAN SPLITBEFORE OR
  2109. * SPLITAFTER.
  2110. *
  2111. * THE NEWLY BUILT SECTOR BECOMES THE CURRENT SECTOR FOR THIS
  2112. * LEVEL OF THE TREE. THE ORIGINAL SECTOR IS RELEASED FROM
  2113. * OWNERSHIP.
  2114. *
  2115. * SPLITAPEND REQUIRES THAT AT LEAST ONE CACHE FRAME IS
  2116. * AVAILABLE FOR ALLOCATION.
  2117. *
  2118. * SPLITAPEND FINISHES ITS PROCESSING BY SETTING UP PARAMETERS
  2119. * FOR THE POSSIBLE CALLING OF ANY SPLIT ROUTINE FOR THE NEXT
  2120. * HIGHER LEVEL. NOTE THAT ALL SPLIT ROUTINES ANTICIPATE THAT
  2121. * THE CALLER WILL ITERATE SO LONG AS PARAMETERS INDICATE THAT
  2122. * MORE SPLITTING NEEDS TO BE DONE. SINCE EACH SPLIT ROUTINE
  2123. * DECREMENTS THE CURRENT TREE LEVEL, THE EFFECT IS TO WORK
  2124. * FROM THE BOTTOM OF THE TREE TOWARDS THE ROOT, SPLITTING
  2125. * UNTIL A LEVEL IS REACHED WHERE EVERYTHING FITS.
  2126. *
  2127. * ENTRY P<NEW> - LOCATION OF OVERFLOW TEXT.
  2128. * NWNEW - NUMBER OF WORDS IN OVERFLOW TEXT.
  2129. * PL - CURRENT LEVEL IN TREE PATH.
  2130. * ALL PATH CONTROLS SETUP.
  2131. * ALL CACHE CONTROLS SETUP.
  2132. *
  2133. * EXIT PL - DECREMENTED.
  2134. * SECTOR AT ORIGINAL TREE LEVEL REBUILT TO CONTAIN
  2135. * OVERFLOW TEXT.
  2136. * PREVIOUS SECTOR AT ORIGINAL TREE LEVEL RELEASED.
  2137. * NWNEW, NEWBEFORE, NWAFTER - SET FOR ITERATION.
  2138. * NEWDA, NEWNL - SET FOR ITERATION.
  2139. * DISP, PADISP[NEW PL] - INCREMENTED FOR ITERATION.
  2140. *
  2141. * CALLS ALLOC, ALLOCCACHE, MOVEWD.
  2142. *
  2143. * USES P<TOO>.
  2144. #
  2145. CLEAN; # CLEAN OLD BLOCK #
  2146.  
  2147. ALLOC; # BUILD NEW BLOCK #
  2148. ALLOCCACHE;
  2149. P&lt;TOO> = LOC(BFPRU[PACACHE[PL]]) + 1;
  2150. MOVEWD(NWNEW,NEW,TOO);
  2151. PAFINAL[PL] = NWNEW;
  2152. PADIRTY[PL] = TRUE;
  2153.  
  2154. PADISP[PL] = 1; # FIX UP PATH #
  2155. PAFIRST[PL] = FIRST;
  2156. PALAST[PL] = LAST;
  2157.  
  2158. NEWDA[0] = PADA[PL]; # BUILD NEW DIR ENTRY #
  2159. NEWNL[0] = PALAST[PL] - PAFIRST[PL] + 1;
  2160. NWNEW = 1;
  2161.  
  2162. PL = PL - 1; # SET UP NEXT PASS #
  2163. NWBEFORE = PADISP[PL];
  2164. NWAFTER = PAFINAL[PL] - PADISP[PL];
  2165. DISP = PADISP[PL] + 1;
  2166. PADISP[PL] = DISP;
  2167. IOEND
  2168. PAGE
  2169. PROC SPLITBEFORE;
  2170. IOBEGIN(SPLITBEFORE)
  2171. #
  2172. ** SPLITBEFORE - SPLIT SECTOR JUST BEFORE INSERTION POINT.
  2173. *
  2174. * SPLITBEFORE IS USED TO OVERFLOW ANY NON-ROOT SECTOR UNDER
  2175. * THE CONDITION THAT THE OVERFLOW TEXT MUST BE INSERTED
  2176. * SOMEWHERE IN THE MIDDLE OF THE TEXT ALREADY CONTAINED IN
  2177. * THE SECTOR, AND NEW TEXT WOULD NOT FIT WITHIN THE FIRST
  2178. * SECTOR OF THE NEW PAIR. THUS, THE SECTOR IS SPLIT JUST IN
  2179. * FRONT OF THE INSERTION POINT, AND THE SECOND SECTOR
  2180. * RESULTING FROM THE SPLIT WILL START WITH THE OVERFLOW TEXT
  2181. * AND CONTINUE WITH THE REMAINING TEXT SPLIT OUT OF THE
  2182. * ORIGINAL SECTOR.
  2183. *
  2184. * SINCE SOME EXISTING TEXT MUST BE REMOVED FROM THE CURRENT
  2185. * SECTOR, IT IS NOT POSSIBLE TO KEEP USING THE SAME SECTOR,
  2186. * UNDER THE RULE THAT NOTHING CAN BE POINTED TO WITHOUT FIRST
  2187. * EXISTING ON DISK. THEREFORE, TWO COMPLETELY NEW SECTORS
  2188. * ARE CREATED AND THE ORIGINAL SECTOR BECOMES A FRAGMENT.
  2189. * SINCE THE INSERTED TEXT GOES INTO THE SECOND SECTOR OF THE
  2190. * NEW PAIR, THAT IS THE SECTOR WHICH IS LEFT AS THE CURRENT
  2191. * SECTOR FOR THIS TREE PATH LEVEL.
  2192. *
  2193. * SPLITBEFORE REQUIRES THAT AT LEAST ONE CACHE FRAME IS
  2194. * AVAILABLE FOR ALLOCATION. THE EXISTING CACHE FRAME FOR
  2195. * THIS TREE LEVEL IS RECYCLED TO PROVIDE THE SECOND SECTOR OF
  2196. * CAPACITY. THE EXISTING CACHE FRAME IS FIRST SUBJECTED TO
  2197. * THE NORMAL "CLEAN" ROUTINE TO ASSURE THAT ANY PENDING
  2198. * CHANGES ARE FLUSHED TO DISK.
  2199. *
  2200. * SPLITBEFORE FINISHES ITS PROCESSING BY SETTING UP PARAMETERS
  2201. * FOR THE POSSIBLE CALLING OF ANY SPLIT ROUTINE FOR THE NEXT
  2202. * HIGHER LEVEL. NOTE THAT ALL SPLIT ROUTINES ANTICIPATE THAT
  2203. * THE CALLER WILL ITERATE SO LONG AS PARAMETERS INDICATE THAT
  2204. * MORE SPLITTING NEEDS TO BE DONE. SINCE EACH SPLIT ROUTINE
  2205. * DECREMENTS THE CURRENT TREE LEVEL, THE EFFECT IS TO WORK
  2206. * FROM THE BOTTOM OF THE TREE TOWARDS THE ROOT, SPLITTING
  2207. * UNTIL A LEVEL IS REACHED WHERE EVERYTHING FITS.
  2208. *
  2209. * ENTRY P<NEW> - LOCATION OF OVERFLOW TEXT.
  2210. * NWNEW - NUMBER OF WORDS IN OVERFLOW TEXT.
  2211. * PL - CURRENT LEVEL IN TREE PATH.
  2212. * ALL PATH CONTROLS SETUP.
  2213. * ALL CACHE CONTROLS SETUP.
  2214. *
  2215. * EXIT PL - DECREMENTED.
  2216. * SECTOR AT ORIGINAL TREE LEVEL REBUILT TO CONTAIN
  2217. * OVERFLOW TEXT AND SPLIT-OFF ORGINAL TEXT.
  2218. * PREVIOUS SECTOR AT ORIGINAL TREE LEVEL RELEASED.
  2219. * NWNEW, NEWBEFORE, NWAFTER - SET FOR ITERATION.
  2220. * NEWDA, NEWNL - SET FOR ITERATION.
  2221. * DISP, PADISP[NEW PL] - INCREMENTED FOR ITERATION.
  2222. *
  2223. * CALLS ALLOC, ALLOCCACHE, MOVEWD, LAST.
  2224. *
  2225. * USES P<TOO>.
  2226. #
  2227.  
  2228. P&lt;FROM> = LOC(BFPRU[PACACHE[PL]]) + 1; # SAVE OLD DATA #
  2229. MOVEWD(PAFINAL[PL],FROM,OBF);
  2230.  
  2231. DEALLOC; # FREE UP OLD BLOCK #
  2232.  
  2233. ALLOC; # BUILD OFF BLOCK #
  2234. P&lt;TOO> = LOC(BFPRU[PACACHE[PL]]) + 1;
  2235. MOVEWD(NWBEFORE,OBF,TOO);
  2236. PAFINAL[PL] = NWBEFORE;
  2237.  
  2238. ODA = PADA[PL]; # REMEMBER THIS #
  2239. ONL = FIRST - PAFIRST[PL];
  2240.  
  2241. PADIRTY[PL] = TRUE; # GET RID OF OFF BLOCK #
  2242. CLEAN;
  2243.  
  2244. ALLOC; # BUILD NEW BLOCK #
  2245. ALLOCCACHE;
  2246. P&lt;TOO> = LOC(BFPRU[PACACHE[PL]]) + 1;
  2247. MOVEWD(NWNEW,NEW,TOO);
  2248. P&lt;FROM> = LOC(OBF) + DISP-1;
  2249. P&lt;TOO> = LOC(BFPRU[PACACHE[PL]]) + NWNEW + 1;
  2250. MOVEWD(NWAFTER,FROM,TOO);
  2251. PAFINAL[PL] = NWNEW + NWAFTER;
  2252. PADIRTY[PL] = TRUE;
  2253.  
  2254. PADISP[PL] = PADISP[PL] - NWBEFORE; # FIX UP PATH #
  2255. PAFIRST[PL] == FIRST;
  2256. PALAST[PL] = PALAST[PL] + NL;
  2257. LAST = PALAST[PL];
  2258.  
  2259. NEWDA[0] = ODA; # BUILD NEW DIR ENTRIES #
  2260. NEWNL[0] = ONL;
  2261. NEWDA[1] = PADA[PL];
  2262. NEWNL[1] = PALAST[PL] - PAFIRST[PL] + 1;
  2263. NWNEW = 2;
  2264.  
  2265. PL = PL - 1; # SET UP NEXT PASS #
  2266. NWBEFORE = PADISP[PL] - 1;
  2267. NWAFTER = PAFINAL[PL] - PADISP[PL];
  2268. DISP = PADISP[PL] + 1;
  2269. PADISP[PL] = DISP;
  2270. IOEND
  2271. PAGE
  2272. PROC SPLITAFTER;
  2273. IOBEGIN(SPLITAFTER)
  2274. #
  2275. ** SPLITAFTER - SPLIT SECTOR JUST AFTER INSERTION POINT.
  2276. *
  2277. * SPLITAFTER IS USED TO OVERFLOW ANY NON-ROOT SECTOR UNDER
  2278. * THE CONDITION THAT THE OVERFLOW TEXT MUST BE INSERTED
  2279. * SOMEWHERE IN THE MIDDLE OF THE TEXT ALREADY CONTAINED IN
  2280. * THE SECTOR, AND NEW TEXT WOULD FIT WITHIN THE FIRST
  2281. * SECTOR OF THE NEW PAIR. THUS, THE SECTOR IS SPLIT JUST
  2282. * BEYOND THE INSERTED TEXT, AND THE SECOND SECTOR
  2283. * RESULTING FROM THE SPLIT WILL START WITH THE REMAINING
  2284. * TEXT SPLIT OUT OF THE ORGINAL SECTOR.
  2285. *
  2286. * SINCE SOME EXISTING TEXT MUST BE REMOVED FROM THE CURRENT
  2287. * SECTOR, IT IS NOT POSSIBLE TO KEEP USING THE SAME SECTOR,
  2288. * UNDER THE RULE THAT NOTHING CAN BE POINTED TO WITHOUT FIRST
  2289. * EXISTING ON DISK. THEREFORE, TWO COMPLETELY NEW SECTORS
  2290. * ARE CREATED AND THE ORIGINAL SECTOR BECOMES A FRAGMENT.
  2291. * SINCE THE INSERTED TEXT GOES INTO THE FIRST SECTOR OF THE
  2292. * NEW PAIR, THAT IS THE SECTOR WHICH IS LEFT AS THE CURRENT
  2293. * SECTOR FOR THIS TREE PATH LEVEL.
  2294. *
  2295. * SPLITAFTER REQUIRES THAT AT LEAST ONE CACHE FRAME IS
  2296. * AVAILABLE FOR ALLOCATION. THE EXISTING CACHE FRAME FOR
  2297. * THIS TREE LEVEL IS RECYCLED TO PROVIDE THE SECOND SECTOR OF
  2298. * CAPACITY. THE EXISTING CACHE FRAME IS FIRST SUBJECTED TO
  2299. * THE NORMAL "CLEAN" ROUTINE TO ASSURE THAT ANY PENDING
  2300. * CHANGES ARE FLUSHED TO DISK.
  2301. *
  2302. * SPLITAFTER FINISHES ITS PROCESSING BY SETTING UP PARAMETERS
  2303. * FOR THE POSSIBLE CALLING OF ANY SPLIT ROUTINE FOR THE NEXT
  2304. * HIGHER LEVEL. NOTE THAT ALL SPLIT ROUTINES ANTICIPATE THAT
  2305. * THE CALLER WILL ITERATE SO LONG AS PARAMETERS INDICATE THAT
  2306. * MORE SPLITTING NEEDS TO BE DONE. SINCE EACH SPLIT ROUTINE
  2307. * DECREMENTS THE CURRENT TREE LEVEL, THE EFFECT IS TO WORK
  2308. * FROM THE BOTTOM OF THE TREE TOWARDS THE ROOT, SPLITTING
  2309. * UNTIL A LEVEL IS REACHED WHERE EVERYTHING FITS.
  2310. *
  2311. * ENTRY P<NEW> - LOCATION OF OVERFLOW TEXT.
  2312. * NWNEW - NUMBER OF WORDS IN OVERFLOW TEXT.
  2313. * PL - CURRENT LEVEL IN TREE PATH.
  2314. * ALL PATH CONTROLS SETUP.
  2315. * ALL CACHE CONTROLS SETUP.
  2316. *
  2317. * EXIT PL - DECREMENTED.
  2318. * SECTOR AT ORIGINAL TREE LEVEL REBUILT TO CONTAIN
  2319. * OVERFLOW TEXT AND SPLIT-OFF ORGINAL TEXT.
  2320. * PREVIOUS SECTOR AT ORIGINAL TREE LEVEL RELEASED.
  2321. * NWNEW, NEWAFTER, NWAFTER - SET FOR ITERATION.
  2322. * NEWDA, NEWNL - SET FOR ITERATION.
  2323. * DISP, PADISP[NEW PL] - INCREMENTED FOR ITERATION.
  2324. *
  2325. * CALLS ALLOC, ALLOCCACHE, MOVEWD, CLEAN, DEALLOC.
  2326. *
  2327. * USES P<TOO>, FIRST, LAST.
  2328. #
  2329.  
  2330. P&lt;FROM> = LOC(BFPRU[PACACHE[PL]]) + 1; # SAVE OLD DATA #
  2331. MOVEWD(PAFINAL[PL],FROM,OBF);
  2332.  
  2333. DEALLOC; # FREE UP OLD BLOCK #
  2334.  
  2335. ALLOC; # BUILD OFF BLOCK #
  2336. P&lt;FROM> = LOC(OBF) + DISP-1;
  2337. P&lt;TOO> = LOC(BFPRU[PACACHE[PL]]) + 1;
  2338. MOVEWD(NWAFTER,FROM,TOO);
  2339. PAFINAL[PL] = NWAFTER;
  2340.  
  2341. ODA = PADA[PL]; # REMEMBER THIS #
  2342. ONL = PALAST[PL] + NL - LAST;
  2343.  
  2344. PADIRTY[PL] = TRUE; # GET RID OF OFF BLOCK #
  2345. CLEAN;
  2346.  
  2347. ALLOC; # BUILD NEW BLOCK #
  2348. ALLOCCACHE;
  2349. P&lt;TOO> = LOC(BFPRU[PACACHE[PL]]) + 1;
  2350. MOVEWD(NWBEFORE,OBF,TOO);
  2351. P&lt;TOO> = LOC(BFPRU[PACACHE[PL]]) + NWBEFORE + 1;
  2352. MOVEWD(NWNEW,NEW,TOO);
  2353. PAFINAL[PL] = NWBEFORE + NWNEW;
  2354. PADIRTY[PL] = TRUE;
  2355.  
  2356. FIRST = PAFIRST[PL]; # FIX UP PATH #
  2357. LAST == PALAST[PL];
  2358. LAST = LAST + NL;
  2359.  
  2360. NEWDA[0] = PADA[PL]; # BUILD NEW DIR ENTRIES #
  2361. NEWNL[0] = PALAST[PL] - PAFIRST[PL] + 1;
  2362. NEWDA[1] = ODA;
  2363. NEWNL[1] = ONL;
  2364. NWNEW = 2;
  2365.  
  2366. PL = PL - 1; # SET UP NEXT PASS #
  2367. NWBEFORE = PADISP[PL] - 1;
  2368. NWAFTER = PAFINAL[PL] - PADISP[PL];
  2369. DISP = PADISP[PL] + 1;
  2370. IOEND
  2371. PAGE
  2372. PROC CHANGE; # CHANGE TREE #
  2373. IOBEGIN(CHANGE)
  2374. #
  2375. ** CHANGE - APPLY CHANGES TO TREE STRUCTURE.
  2376. *
  2377. * CHANGE IS THE PRINCIPAL ALGORITHM USED TO MANIPULATE THE
  2378. * TREE STRUCTURE. CHANGE IS DESIGNED TO BE CALLED BY THE
  2379. * INS, REP, AND DEL ENTRY POINTS. THE ALGORITHM WORKS IN
  2380. * THREE PHASES. THE FIRST PHASE TAKES CARE OF CASES WHERE AN
  2381. * INSERTION OF A LINE OR THE REPLACEMENT OF A LINE WITH AN
  2382. * ENLARGED VERSION WILL CAUSE THE CURRENT DATA SECTOR (THE
  2383. * BOTTOM LEVEL OF THE TREE STRUCTURE) TO OUTGROW THE SECTOR
  2384. * CAPACITY AND CAUSE SPLITTING INTO TWO SECTORS. THIS CAUSES
  2385. * ADDITIONAL DIRECTORY ENTRIES TO BE REQUIRED IN THE HIGHER
  2386. * TREE LEVELS, WHICH CAN IN TURN CAUSE ONE OR MORE DIRECTORY
  2387. * LEVELS TO BE SPLIT INTO MULTIPLE SECTORS. IN THE EXTREME
  2388. * CASE, THE ROOT LEVEL OF THE TREE MAY OVERFLOW, IN WHICH
  2389. * CASE A NEW INTERMEDIATE LEVEL OF THE TREE MUST BE CREATED,
  2390. * WITH THE ROOT SECTOR CONVERTED INTO A DIRECTORY FOR THE
  2391. * INTERMEDIATE LEVEL.
  2392. *
  2393. * AFTER THE FIRST PHASE HAS EXHAUSTED ITS ITERATION, THE
  2394. * SECOND PHASE TAKES OVER, IDENTIFYING ANY TREE LEVEL
  2395. * STARTING WITH THE DATA LEVEL WHICH HAS BECOME EMPTY AS THE
  2396. * RESULT OF DELETIONS. THE SECOND PHASE IS THUS MUTUALLY
  2397. * EXCLUSIVE OF THE FIRST PHASE.
  2398. *
  2399. * THE THIRD PHASE IS A CLEANUP OPERATION. WHILE EACH OF THE
  2400. * FIRST TWO PHASES MAY BE A NO-OP, (AND AT LEAST ONE OF THE
  2401. * FIRST TWO PHASES WILL INDEED BE A NO-OP), THE THIRD PHASE
  2402. * ALWAYS IS IN EFFECT. THE CLEANUP OPERATION CONSISTS OF THE
  2403. * APPLICATION OF LEFT-OVER CHANGES. LEFTOVER CHANGES MAY
  2404. * CONSTITUTE THE ENTIRE CHANGE IF NEITHER PRELIMINARY PHASE
  2405. * WAS NEEDED, OR IF ONE OF THE FIRST TWO PHASES WAS USED,
  2406. * THEN IT WILL HAVE LEFT RESIDUAL CHANGES TO BE APPLIED ONE
  2407. * LEVEL CLOSER TO THE ROOT THAN THE LAST LEVEL AFFECTED BY
  2408. * THE SPLITTING OR COLLAPSING.
  2409. *
  2410. * ACTUAL APPLICATION OF CHANGES, WHETHER PERFORMED BY THE
  2411. * THIRD PHASE OF THE CHANGE ROUTINE, OR WITHIN ONE OF THE
  2412. * SPLIT ROUTINES SELECTED BY THE FIRST PHASE OF THE CHANGE
  2413. * ROUTINE, SIMPLY CONSIST OF OPENING UP A GAP AT THE RIGHT
  2414. * MEMORY LOCATION, OF ZERO, POSITIVE, OR NEGATIVE LENGTH, AND
  2415. * MOVING IN THE TEXT OF THE CHANGE, WHICH CAN CONSIST OF ZERO
  2416. * OR MORE WORDS.
  2417. *
  2418. * THE CLEANUP PHASE ALSO INCREMENTS OR DECREMENTS THE COUNT
  2419. * OF LINES BRACKETED BY EACH LEVEL OF THE TREE.
  2420. *
  2421. * ENTRY PALVL - DEEPEST LEVEL IN TREE STRUCTURE.
  2422. * PL - CURRENT TREE LEVEL MUST EQUAL PALVL.
  2423. * NL - CHANGE IN NUMBER OF LINES IN WORKFILE.
  2424. * NWBEFORE - NUMBER OF WORDS BEFORE POINT OF CHANGE.
  2425. * NWAFTER - NUMBER OF WORDS AFTER POINT OF CHANGE.
  2426. * NWNEW - NUMBER OF WORDS IN CHANGED TEXT.
  2427. * DISP - POINTS JUST AFTER CURRENT LINE.
  2428. * LINEBUF - CONTAINS TEXT OF CHANGE.
  2429. * ALL PATH CONTROLS - SETUP.
  2430. * ALL CACHE CONTROLS - SETUP.
  2431. *
  2432. * EXIT PL - ZERO.
  2433. * PALVL - INCREMENTED/DECREMENTED IF TREE DEPTH CHANGED.
  2434. * DISP, CURNW - BRACKET NEW CURRENT LINE.
  2435. * ALL PATH, CACHE CONTROLS - UPDATED.
  2436. * FET AND CIRCULAR BUFFER USED IF NEEDED.
  2437. *
  2438. * CALLS COUNTCACHE, FLUSHCACHE, SPLITTOP, SPLITAPEND,
  2439. * SPLITBEFORE, SPLITAFTER, RECLAIMCACHE, DEALLOC, CLEAN,
  2440. * MOVEWD.
  2441. *
  2442. * USES P<NEW>, P<FROM>, P<TOO>, FIRST, LAST, NWNEW,
  2443. * NWBEFORE, NWAFTER, NL.
  2444. #
  2445. P&lt;NEW> = LOC(LINEBUF); # SET THINGS UP #
  2446. FIRST = CURRENT + NL;
  2447. LAST = FIRST;
  2448. CURNW = NWNEW;
  2449.  
  2450. FOR PL = PL WHILE NWBEFORE+NWNEW+NWAFTER GR 63 DO
  2451. BEGIN # DO ALL SPLITS #
  2452. IF COUNTCACHE LQ 2 THEN FLUSHCACHE;
  2453. IF PL EQ 0 THEN SPLITTOP;
  2454. IF NWBEFORE EQ PAFINAL[PL] THEN SPLITAPEND;
  2455. ELSE IF NWBEFORE+NWNEW LQ 63 THEN SPLITAFTER;
  2456. ELSE SPLITBEFORE;
  2457. RECLAIMCACHE;
  2458. P&lt;NEW> = LOC(NDIR);
  2459. END
  2460.  
  2461. FOR PL = PL WHILE NWBEFORE+NWNEW+NWAFTER EQ 0 DO
  2462. BEGIN # DO ALL COLLAPSING #
  2463. DEALLOC;
  2464. CLEAN; # TO FREE UP CACHE FRAME #
  2465. PALVL = PALVL - 1;
  2466. PL = PL - 1;
  2467. NWBEFORE = PADISP[PL] - 1;
  2468. NWAFTER = PAFINAL[PL] - PADISP[PL];
  2469. DISP = PADISP[PL] + 1;
  2470. END
  2471.  
  2472. P&lt;FROM> = LOC(BFPRU[PACACHE[PL]]) + DISP; # SLIDE AFTER #
  2473. P&lt;TOO> = LOC(BFPRU[PACACHE[PL]]) + NWBEFORE +NWNEW + 1;
  2474. MOVEWD(NWAFTER,FROM,TOO);
  2475.  
  2476. P&lt;TOO> = LOC(BFPRU[PACACHE[PL]]) + NWBEFORE + 1; # MOVE IN NEW #
  2477. MOVEWD(NWNEW,NEW,TOO);
  2478.  
  2479. PAFINAL[PL] = NWBEFORE + NWNEW + NWAFTER;
  2480. PADIRTY[PL] = TRUE;
  2481. PALAST[PL] = PALAST[PL] + NL; # FIX UP PATH #
  2482.  
  2483. FOR PL = PL-1 STEP -1 UNTIL 0 DO # UPDATE HIGHER DIRS #
  2484. BEGIN
  2485. P&lt;PRU> = LOC(BFPRU[PACACHE[PL]]);
  2486. DIRNL[PADISP[PL]] = DIRNL[PADISP[PL]] + NL;
  2487. PADIRTY[PL] = TRUE;
  2488. PALAST[PL] = PALAST[PL] + NL;
  2489. END
  2490.  
  2491. CURRENT = CURRENT + NL; # UPDATE CURRENT #
  2492.  
  2493. IOEND
  2494. PAGE
  2495.  
  2496. PROC INS;
  2497. IOBEGIN(INS)
  2498. #
  2499. ** INS - INTERFACE FOR INSERTION OF LINES.
  2500. *
  2501. * ENTRY CURRENT - CURRENT LINE.
  2502. * LINEBUF - LINE IMAGE.
  2503. * ALL PATH AND CACHE CONTROLS SETUP.
  2504. *
  2505. * EXIT CURRENT - INCREMENETED.
  2506. * ALL PATH AND CACHE CONTROL UPDATED.
  2507. *
  2508. * CALLS LINESZ, CHANGE, WIOSTAT.
  2509. *
  2510. * USES PL, DISP, NL, NWBEFORE, NWNEW, NWAFTER, DISP.
  2511. #
  2512. CONTROL IFEQ MULTI,1;
  2513. WIOSTAT(0); # ACCUMULATE LINE ACCESES #
  2514. CONTROL FI;
  2515.  
  2516. PL = PALVL; # STANDARD INITCHANGE #
  2517. DISP = PADISP[PL];
  2518.  
  2519. NL = 1;
  2520. NWBEFORE = DISP + CURNW - 1;
  2521. NWNEW = LINESZ(LINEBUF);
  2522. NWAFTER = PAFINAL[PL] - DISP - CURNW + 1;
  2523. DISP = DISP + CURNW;
  2524.  
  2525. PADISP[PL] = DISP;
  2526.  
  2527. CHANGE;
  2528. IOEND
  2529.  
  2530. PROC REP;
  2531. IOBEGIN(REP)
  2532. #
  2533. ** REP - INTERFACE FOR REPLACEMENT OF LINES.
  2534. *
  2535. * ENTRY CURRENT - CURRENT LINE.
  2536. * LINEBUF - LINE IMAGE.
  2537. * ALL PATH AND CACHE CONTROLS SETUP.
  2538. *
  2539. * EXIT CURRENT - UNCHANGED.
  2540. * ALL PATH AND CACHE CONTROL UPDATED.
  2541. *
  2542. * CALLS LINESZ, CHANGE, WIOSTAT.
  2543. *
  2544. * USES PL, DISP, NL, NWBEFORE, NWNEW, NWAFTER, DISP.
  2545. #
  2546.  
  2547. CONTROL IFEQ MULTI,1;
  2548. WIOSTAT(0); # ACCUMULATE LINE ACCESES #
  2549. CONTROL FI;
  2550.  
  2551. PL = PALVL; # STANDARD INITCHANGE #
  2552. DISP = PADISP[PL];
  2553.  
  2554. NL = 0;
  2555. NWBEFORE = DISP - 1;
  2556. NWNEW = LINESZ(LINEBUF);
  2557. NWAFTER = PAFINAL[PL] - DISP - CURNW + 1;
  2558. DISP = DISP + CURNW;
  2559.  
  2560. CHANGE;
  2561. IOEND
  2562.  
  2563. PROC DEL;
  2564. IOBEGIN(DEL)
  2565. #
  2566. ** DEL - INTERFACE FOR DELETION OF LINES.
  2567. *
  2568. * ENTRY CURRENT - CURRENT LINE.
  2569. * ALL PATH AND CACHE CONTROLS SETUP.
  2570. * DELETCTL - POST-POSITIONING INCREMENT.
  2571. *
  2572. * EXIT CURRENT - INCREMENTED IF DELETCTL WAS ONE.
  2573. * LINEBUF - NEW CURRENT LINE IS READ UP.
  2574. * ALL PATH AND CACHE CONTROL UPDATED.
  2575. * DELETCTL - FORCED ZERO IF DELETED LAST LINE.
  2576. *
  2577. * CALLS CHANGE, WIOSTAT, POSR.
  2578. *
  2579. * USES PL, DISP, NL, NWBEFORE, NWNEW, NWAFTER, DISP,
  2580. * P<MVLNBUF>, NEWCURL.
  2581. #
  2582.  
  2583. CONTROL IFEQ MULTI,1;
  2584. WIOSTAT(0); # ACCUMULATE LINE ACCESES #
  2585. CONTROL FI;
  2586.  
  2587. PL = PALVL; # STANDARD INITCHANGE #
  2588. DISP = PADISP[PL];
  2589.  
  2590. NL = -1;
  2591. NWBEFORE = DISP - 1;
  2592. NWNEW = 0;
  2593. NWAFTER = PAFINAL[PL] - DISP - CURNW + 1;
  2594. DISP = DISP + CURNW;
  2595.  
  2596. CHANGE;
  2597.  
  2598. IF PALAST[0] LQ CURRENT THEN DELETCTL=0;
  2599. CURRENT=CURRENT+DELETCTL;
  2600. NEWCURL=CURRENT;
  2601. P&lt;MVLNBUF>=LOC(LINEBUF);
  2602. POSR;
  2603. P&lt;MVLNBUF>=0;
  2604.  
  2605. IOEND
  2606. PAGE
  2607. PROC INIT;
  2608. BEGIN
  2609. #
  2610. ** INIT - INITIALIZE MEMORY CELLS FOR WORKIO.
  2611. *
  2612. * ENTRY NO CONDITIONS.
  2613. *
  2614. * EXIT P<LINEBUF> -POINTS TO LIN ARRAY.
  2615. * ALL ELEMENTS OF PATH ARRAY - NOMINAL.
  2616. * ALL CACHE CONTROLS - NOMINAL.
  2617. * READ LIST (RDLIST, RDIN, RDOUT) - EMPTY.
  2618. * FLAGS (IOACT, IOREAD, IOWRITE) - FALSE.
  2619. * ARRAYLEN, DATALEN, ARRAYPRUS, DATAPRUS - INITIALIZED.
  2620. * SEGEMENTVER - ZEROED OUT.
  2621. #
  2622. P&lt;LINEBUF>=LOC(LIN);
  2623.  
  2624. FOR PL = 1 STEP 1 UNTIL MAXDEPTH DO # INIT PATH #
  2625. BEGIN
  2626. PAFIRST[PL] = 0;
  2627. PALAST[PL] = 0;
  2628. PADISP[PL] = 0;
  2629. PAHEAD[PL] = 0;
  2630. END
  2631.  
  2632. FOR PL = 0 STEP 1 UNTIL MAXCACHE DO # INIT CACHE CTL #
  2633. BEGIN
  2634. CACHEOWNED[PL]=FALSE; CACHEDIRTY[PL]=FALSE;
  2635. CACHEAGE[PL]=-1;
  2636. BFHEAD[PL]=0;
  2637. END
  2638.  
  2639. FOR RDIN = 0 STEP 1 UNTIL RDLIM DO RDLIST[RDIN] = 0;
  2640.  
  2641. IOACT = FALSE; # INIT IO #
  2642. IOAPEND = FALSE;
  2643. IOWRITE = FALSE;
  2644. IOREAD = FALSE;
  2645.  
  2646. CURNW = 0;
  2647.  
  2648. SEGMENTVER=0;
  2649. ARRAYLEN=LOC(ARRAYEND)-LOC(ARRAYSTART);
  2650. ARRAYPRUS=(ARRAYLEN+O"77")/O"100";
  2651. DATALEN=LOC(DATAEND)-LOC(DATASTART);
  2652. DATAPRUS=(DATALEN+O"77")/O"100";
  2653.  
  2654. END
  2655. PAGE
  2656. PROC RESUMIO;
  2657. IOBEGIN(RESUMIO)
  2658. #
  2659. ** RESUMIO - RESUME EDITOR STATUS FROM LEFTOVER WORKFILE.
  2660. *
  2661. * RESUMIO ATTEMPTS TO VALIDATE A FILE AS CONTAINING THE TEXT
  2662. * AND STATUS LEFT BY A PREVIOUS EDIT SESSION, OR BY A
  2663. * SINGLE/MULTI USER TRANSITION. SINCE THE SCALAR AND ARRAY
  2664. * DATA SEGMENTS CONTAIN NEARLY ALL EDITOR DATA, SUCCESSFUL
  2665. * EXECUTION OF RESUMIO CHANGES EVERYTHING.
  2666. *
  2667. * THE FOLLOWING CONDITIONS ARE REQUIRED TO VALIDATE AN
  2668. * APPARENT WORKFILE AS A LEGITIMATE BASIS FOR RESUMPTION --
  2669. *
  2670. * 1. THE FIRST WORD MUST BE FORMATTED AS A ROOT SECTOR
  2671. * HEADER WORD. THE DISK ADDRESS FIELD MUST BE ONE AND
  2672. * THE TOP FLAG MUST BE ON AND THE DIRECTORY AND DATA
  2673. * FLAGS MUST BE UNEQUAL.
  2674. *
  2675. * 2. THE FIRST RECORD OF THE FILE MUST BE OF LENGTH
  2676. * 64 WORDS LONGER THAN THE SCALAR DATA SEGMENT, AND
  2677. * THE SECOND RECORD OF THE FILE MUST EXACTLY MATCH
  2678. * THE LENGTH OF THE ARRAY SEGMENT.
  2679. *
  2680. * 3. THE SEGMENTLEN1 AND SEGMENTLEN2 FIELDS OF THE SCALAR
  2681. * SEGMENT MUST MATCH THE ABOVE LENGTHS, AND THE
  2682. * SEGMENTVER FIELD MUST MATCH THE VERSION NUMBER
  2683. * COMPILED INTO THIS PROGRAM.
  2684. *
  2685. * AFTER READING UP ALL EDITOR DATA, THE FOLLOWING WORKIO
  2686. * CONTROLS ARE RE-INITIALIZED - THE PATH VECTOR IS REFRESHED
  2687. * TO MATCH THE CURRENT LINE, THE SCHEDULING FLAGS (IOACT,
  2688. * IOREAD, ETC.) ARE CLEARED, MAXDA AND DANEXT ARE BASED ON
  2689. * FILE SIZE, AND SEGMENTVER IS CLEARED. THE WORKFILE IS THEN
  2690. * IMMEDIATELY CHECKPOINTED SO THAT IT CANNOT BE RESUMED
  2691. * AGAIN, THUS INTERLOCKING IT.
  2692. *
  2693. * ENTRY NO CONDITIONS.
  2694. *
  2695. * EXIT EVERYTHING IN THE WHOLE EDITOR IS CHANGED.
  2696. * IORESUMED - SUCCESS/FAILURE INDICATOR.
  2697. *
  2698. * CALLS INIT, INITFET, BUFUSAGE, ALLOCCACHE, RDWBUF, READ,
  2699. * WAIT, TRAGIC, SKIPEI, POSR, CLEANALL.
  2700. #
  2701. INIT;
  2702. IORESUMED=FALSE;
  2703. INITFET(DISK,DSKSIZ);
  2704.  
  2705. REWIND(FET,0); # TRY TO READ PRU 1 #
  2706. WAIT;
  2707. READ(FET,0);
  2708. WAIT;
  2709.  
  2710. IF BUFUSAGE GR O"100" THEN
  2711. BEGIN
  2712. PL=0;
  2713. PADA[0]=1;
  2714. ALLOCCACHE;
  2715. P&lt;TOO>=LOC(BFPRU[PACACHE[0]]);
  2716. RDWBUF(O"100");
  2717. PAHEAD[0] = BFHEAD[PACACHE[0]];
  2718. END
  2719.  
  2720. IF PADA[0] EQ 1 AND PATOP[0]
  2721. AND BOOLDIFF(PADIR[0],PADATA[0]) THEN
  2722. BEGIN
  2723.  
  2724. # READ FIRST FOUR WORDS TO VERIFY SEGMENT DESCRIPTORS #
  2725. P&lt;TOO>=LOC(DATASTART);
  2726. NWNEW=BUFUSAGE;
  2727. NWNEW=MIN(NWNEW,4);
  2728. RDWBUF(NWNEW);
  2729. IORESUMED=FALSE;
  2730. IF SEGMENTVER NQ IOVERSION OR SEGMENTLEN1 NQ DATALEN
  2731. OR SEGMENTLEN2 NQ ARRAYLEN THEN IORET
  2732.  
  2733. # SEGMENT DESCRIPTORS VALID, READ REST OF SCALAR SEGMENT #
  2734. P&lt;TOO>=LOC(DATASTART)+4;
  2735. NWNEW=BUFUSAGE;
  2736. NWNEW=MIN(DATALEN-4,NWNEW);
  2737. RDWBUF(NWNEW);
  2738. READ(FET,0);
  2739. WAIT;
  2740.  
  2741. # READ ARRAY SEGMENT #
  2742. P&lt;TOO>=LOC(ARRAYSTART);
  2743. NWNEW=BUFUSAGE;
  2744. NWNEW=MIN(ARRAYLEN,NWNEW);
  2745. RDWBUF(NWNEW);
  2746.  
  2747. IF ABORTED THEN TRAGIC(ERRSTRING);
  2748.  
  2749. SKIPEI(FET,0);
  2750. WAIT;
  2751. MAXDA=FETCRI-1;
  2752. DANEXT=FETCRI;
  2753.  
  2754. PADISP[0] = 1; # SET UP PATH[0] #
  2755. PAFIRST[0] = 0;
  2756. PALAST[0] = -1;
  2757. P&lt;PRU> = LOC(BFPRU[PACACHE[0]]);
  2758. IF PADIR[0] THEN
  2759. BEGIN
  2760. FOR DISP = 1 STEP 1 UNTIL PAFINAL[0]
  2761. DO PALAST[0] = PALAST[0] + DIRNL[DISP];
  2762. END
  2763. ELSE # NOTE INTERNAL CHARSET SIGN BIT USAGE #
  2764. BEGIN
  2765. FOR DISP = 1 STEP 1 UNTIL PAFINAL[0]
  2766. DO IF B&lt;0,1>DATWORD[DISP] NQ 0 THEN PALAST[0] = PALAST[0] + 1;
  2767. END
  2768.  
  2769. IORESUMED=TRUE; # RESET FLAGS READ WITH DATA #
  2770. IOACT=FALSE;
  2771. IOREAD=FALSE;
  2772. IOWRITE=FALSE;
  2773. IOAPEND=FALSE;
  2774.  
  2775. PALVL = 0; # BUILD REST OF PATH #
  2776. NEWCURL=0;
  2777. P&lt;MVLNBUF>=LOC(LINEBUF);
  2778. POSR;
  2779. P&lt;MVLNBUF>=0;
  2780.  
  2781. SEGMENTVER=0; # INTERLOCK FILE ONWESHIP #
  2782. CLEANALL;
  2783.  
  2784. END
  2785.  
  2786. IOEND
  2787. PAGE
  2788.  
  2789. CONTROL IFEQ SINGLE,1;
  2790.  
  2791. PROC INITIO;
  2792. IOBEGIN(INITIO)
  2793. #
  2794. ** INITIO - FORMAT A NEW WORKFILE.
  2795. *
  2796. * INITIO IS USED TO BUILD A WORKFILE FROM SCRATCH OR TO
  2797. * DISCARD OLD WORKFILE CONTENT AND REFRESH IT.
  2798. *
  2799. * ENTRY NO CONDITIONS.
  2800. *
  2801. * EXIT FILE INITIALIZED.
  2802. * ALL PATH CONTROLS NOMINAL.
  2803. * ALL CACHE CONTROL NOMINAL.
  2804. * MAXDA - ZERO
  2805. * DANEXT - FIRST ALLOCATABLE DISK ADDRESS RIGHT AFTER
  2806. * ROOT SECTOR, AND SCALAR AND ARRAY DATA SEGMENTS.
  2807. * IORESUMED - TRUE TO SHOW WORKIO ACTIVE.
  2808. * SEGMENTVER - ZERO IN MEMORY AND ON DISK TO INTERLOCK.
  2809. *
  2810. * CALLS INITFET, EVICT, WAIT, INIT, ALLOCCACHE, CLEANALL.
  2811. #
  2812. INITFET(DISK,DSKSIZ);
  2813. EVICT(FET,0);
  2814. WAIT;
  2815.  
  2816. INIT;
  2817. MAXDA = 0; # SET MAXDA AND DANEXT #
  2818. DANEXT = 2+DATAPRUS+ARRAYPRUS;
  2819.  
  2820. PAHEAD[0] = 0; # BUILD TOP BLOCK #
  2821. PADATA[0] = TRUE;
  2822. PATOP[0] = TRUE;
  2823. PADIRTY[0] = TRUE;
  2824. PADA[0] = 1;
  2825. PAFINAL[0] = 1;
  2826. PL=0;
  2827. ALLOCCACHE;
  2828. P&lt;PRU> = LOC(BFPRU[PACACHE[0]]);
  2829. DATWORD[1] = NULLIN;
  2830. CURNW = 1;
  2831.  
  2832. PADEPTH[0] = 0;
  2833. PADISP[0] = 1; # SET UP PATH #
  2834. PAFIRST[0] = 0;
  2835. PALAST[0] = 0;
  2836. PALVL = 0;
  2837. CURRENT = 0;
  2838. IORESUMED=TRUE; # SHOW WORKIO ALIVE #
  2839.  
  2840. SEGMENTVER = 0; # INTERLOCK FILE OWNERSHIP #
  2841. CLEANALL;
  2842.  
  2843. IOEND
  2844.  
  2845. CONTROL FI;
  2846. PAGE
  2847. PROC CHECKIO;
  2848. IOBEGIN(CHECKIO)
  2849. #
  2850. ** CHECKIO - CHECKPOINT WORKFILE.
  2851. *
  2852. * CHECKIO IS USED TO ASSURE THAT ALL MEMORY DATA IS FULLY
  2853. * WRITTEN TO DISK. THIS CAN BE USED TO PREPARE FOR END OF
  2854. * JOB STEP OR FOR TRANSITION BETWEEN SINGLE AND MULTIPLE USER
  2855. * VERSIONS OF THE EDITOR. BY CHECKPOINTING THE WORKFILE, IT
  2856. * BECOMES POSSIBLE TO EXECUTE THE RESUMIO ROUTINE AND FULLY
  2857. * RESTORE THE EDITOR STATUS.
  2858. *
  2859. * ENTRY IORESUMED - SHOWS WHETHER WORKFILE MANAGER EVER ACTIVE.
  2860. * CURRENT - CURRENT LINE ORDINAL.
  2861. *
  2862. * EXIT SEGMENTVER, SEGMENTLEN1, SEGMENTLEN2 - SETUP.
  2863. * CACHE FLUSHED, FET AND CIRCULAR BUFFER COMPLETE.
  2864. *
  2865. * CALLS CLEANALL.
  2866. #
  2867. IF NOT IORESUMED THEN IORET # WORKIO NEVER ALIVE #
  2868.  
  2869. SAVECURL=CURRENT;
  2870. SEGMENTVER = IOVERSION; # SHOW VALID WORKFILE FORMAT #
  2871. SEGMENTLEN1 = DATALEN;
  2872. SEGMENTLEN2 = ARRAYLEN;
  2873. CLEANALL; # WRITE OUT WHOLE PATH #
  2874.  
  2875. IOEND
  2876.  
  2877.  
  2878. END TERM