(* ---------------------------------------------------------------------------- * $Id: MASSTOR.mip,v 1.6 1996/06/08 18:26:52 pesch Exp $ * ---------------------------------------------------------------------------- * This file is part of MAS. * ---------------------------------------------------------------------------- * Copyright (c) 1989 - 1995 Universitaet Passau * ---------------------------------------------------------------------------- * $Log: MASSTOR.mip,v $ * Revision 1.6 1996/06/08 18:26:52 pesch * Removed unused code, minor corrections. * * Revision 1.5 1995/11/04 20:40:03 pesch * Renamed massignal.m? to massig.m? because of conflict with MASSIGNAL.m? * on certain OS. * * Revision 1.4 1995/10/13 16:02:13 pesch * Fixed error: sigsetmask() at wrong places caused SIGUSR1 to be blocked * permanently. * * Revision 1.3 1995/09/12 17:51:53 pesch * Changed mpsignal to massignal. * * Revision 1.2 1995/03/24 15:36:13 pesch * Changed inital message. * * Revision 1.1 1995/03/06 16:23:42 pesch * Replaced MASSTOR.mi by MASSTOR.mip. * Modified to work with new reuse library, too. * Modified procedure CLOCK. * Modified procedure GC to be more portable. Constant stackoff * is no longer needed (but local variables of GC are still not considered * during garbage collection). GC will now probably work independent of * direction of stack growth. * * Revision 1.9 1994/04/14 16:47:56 dolzmann * Syntactical errors (founded by Mocka) corrected. * * Revision 1.8 1994/04/12 13:23:14 pesch * Added comment to earlier revision (CLOCK has been modified). * * Revision 1.7 1994/03/30 11:34:59 pesch * Renamed SIGMASK to SigMask. SIGMASK was already defined in AIX signal.h. * * Revision 1.6 1994/03/11 16:04:23 pesch * Added support for SIGUSR1 as a method to get information about * the status of a running program. * Modified CLOCK to return only user-time (not user+system) in ms (not cs). * * Revision 1.5 1993/07/21 12:32:11 kredel * Fix for HP port * * Revision 1.4 1992/10/16 13:47:55 kredel * Errors found by Mocka * * Revision 1.3 1992/10/15 16:24:59 kredel * Changed rcsid variable * * Revision 1.2 1992/02/12 17:31:57 pesch * Moved CONST definition to the right place * * Revision 1.1 1992/01/22 15:10:40 kredel * Initial revision * * ---------------------------------------------------------------------------- *) IMPLEMENTATION MODULE MASSTOR; (* MAS Storage Implementation Module. *) (* Import lists and Definitions *) FROM clock IMPORT ClocK; FROM MASCONF IMPORT KBCell; FROM MASELEM IMPORT GAMMAINT, MASEXP, MASMAX, MASODD; FROM MASERR IMPORT DebugProcessor, ERROR, ErrorHandler, confusion, fatal, harmless, severe, spotless; FROM MASmtc IMPORT getstck, gettoc; FROM massig IMPORT SIGUSR1, SigMask, sigblock, signal, sigsetmask; FROM StdIO IMPORT ReadC, ReadI, WriteC, WriteFlush, WriteI, WriteN, WriteNl, WriteS; FROM Strings IMPORT ArrayToString, Concatenate, IntToString, StringToArray, tString; FROM SYSTEM IMPORT ADDRESS, ADR, BYTE, TSIZE; FROM Times IMPORT CpuTime; #ifdef OLD_MTC FROM SysCalls IMPORT Alloc; #else FROM System IMPORT SysAlloc; #endif CONST maxerr = 20; (* maximal number of errors allowed *) blocklen = 12*1024; (* not to small, but less than 64 K *) proclen = 12*1024; (* stack size, do not know how much is necessary *) sysres = 160*1024; (* reserved for system > 16K + editor *) tomax = 10; (* allow 10 GC retries before halt *) rhomin = 500; (* some free space must be provided *) stackOK = 1024; (* stack must have some rest to continue *) CONST rcsidi = "$Id: MASSTOR.mip,v 1.6 1996/06/08 18:26:52 pesch Exp $"; CONST copyrighti = "Copyright (c) 1989 - 1995 Universitaet Passau"; TYPE ADDRLW = POINTER TO LONGCARD; P1 = PROCEDURE(GAMMAINT); PS = PROCEDURE(ARRAY OF CHAR); VAR (*The cell fields FIRST and RED are implemented as follows FIRST(I) = LIST((SPACE-BETA1)+I)$^$) RED(I) = LIST((SPACE-BETA)+I)$^$) *) Csize, Lsize: GAMMAINT; (* sizes of cells and lists *) BETA2, NUP: GAMMAINT; AVAIL, Globalvars: LIST; SPACEB, SPACEB1: GAMMAINT; toview, eh, marks: GAMMAINT; SPACE, SPACEEND, STACK, STACKEND, Tstack: ADDRESS; (*$S- No stack check *) PROCEDURE FIRST(L: LIST): LIST; (*First. L is a non-null list. a is the first element of L. *) VAR s: ADDRLW; BEGIN (*1*) (*DEBUG*) #ifndef NO_FIRST_ADDRESS_CHECK IF (L < BETA) OR (BETA2 <= L) THEN WL; WI(L); ERROR(severe,"FIRST address out of range, value = "); RETURN(0); END; #endif (*GUBED*) (*2*) s:=ADDRESS(SPACEB1+L); RETURN(LIST(s^)); (*4*) END FIRST; PROCEDURE RED(L: LIST): LIST; (*Reductum. L is a non-null list. Returns the reductum of L. *) VAR s: ADDRLW; BEGIN (*1*) (*DEBUG*) #ifndef NO_RED_ADDRESS_CHECK IF (L < BETA) OR (BETA2 <= L) THEN WL; WI(L); ERROR(severe,"RED address out of range, value = "); RETURN(SIL); END; (*GUBED*) #endif (*2*) s:=ADDRESS(SPACEB+L); RETURN(LIST(s^)); (*4*) END RED; PROCEDURE SFIRST(L,a: LIST); (*Set first. L is a non-null list. a is an object. The first element of L is changed to a. *) VAR s: ADDRLW; BEGIN (*1*) (*DEBUG*) #ifndef NO_SFIRST_ADDRESS_CHECK IF (L < BETA) OR (BETA2 <= L) THEN WL; WI(L); ERROR(severe,"SFIRST address out of range, value = "); RETURN; END; (*GUBED*) #endif (*2*) (*DEBUG *) #ifdef SFIRST_CONTENTS_ADDRESS_CHECK IF (a < -BETA) OR (BETA2 <= a) THEN WL; WI(a); ERROR(severe,"SFIRST contents out of range, value = "); RETURN; END; (*GUBED*) #endif (*3*) s:=ADDRESS(SPACEB1+L); s^:=LONGCARD(a); RETURN; (*4*) END SFIRST; PROCEDURE SRED(L,LP: LIST); (*Set reductum. L is a non-null list. LP is a list. The reductum of L is changed to LP. *) VAR s: ADDRLW; BEGIN #ifdef SRED_ADDRESS_CHECK (*1*) (*DEBUG*) IF (L < BETA) OR (BETA2 <= L) THEN WL; WI(L); ERROR(severe,"SRED address out of range, value = "); RETURN; END; (*GUBED*) #endif (*3*) s:=ADDRESS(SPACEB+L); s^:=LONGCARD(LP); RETURN; (*4*) END SRED; (*$S+ Stack check on *) PROCEDURE ADV(L: LIST; VAR a,LP: LIST); (*Advance. L is a non-null list. a=FIRST(L) and LP=RED(L). *) BEGIN (*1*) a:=FIRST(L); LP:=RED(L); RETURN; (*4*) END ADV; PROCEDURE ALLOCATESPACE(VAR S: ADDRESS; VAR AMNT: LONGINT); (*Allocate Space for list processing. S is the address, where the allocated space starts. AMNT is the desired number of bytes to be allocated, on return this parameter shows, how much space was actually allocated. The intention of this procedure is to reflect the allocation algorithms of the different Modula-2 run time packages. *) VAR p2, d, amnt: LONGCARD; a,i: CARDINAL; SP: ADDRESS; t: BOOLEAN; BEGIN (*1*) (*Initialize. *) amnt:=0; IF AMNT > 0 THEN amnt:=LONGCARD(AMNT) END; p2:=blocklen; d:=(amnt DIV p2)+1; (*ceiling*) amnt:=d*p2; (*d = number of blocks*) (* (*2*) (*Find maximal available Heap. *) WHILE (amnt >= p2) AND (NOT CreateHeap(amnt,TRUE)) DO amnt:=amnt-p2; (*may be slow ?*) END; (*leave some space for system!!!!!*) amnt:=amnt-sysres; t:=CreateHeap(amnt,TRUE); *) (*3*) (*Allocate maximal chunk. *) (* WS("Alloc, amnt "); WI(GAMMAINT(amnt)); WL; *) #ifdef OLD_MTC S:=Alloc(amnt); (*base address and length*) #else S:=SysAlloc(amnt); (*base address and length*) #endif (* WS("Alloc, S "); WI(GAMMAINT(S)); WL; *) AMNT:=LONGINT(amnt); (*4*) END ALLOCATESPACE; PROCEDURE CELLS(): GAMMAINT; (*Cells. Returns the used cells since storage initialization. *) VAR a,c: GAMMAINT; BEGIN (*1*) (*Add currently used cells to previously used cells. *) a:=NU-LENGTH(AVAIL); c:=GCCC+a; RETURN(c); (*2*) END CELLS; PROCEDURE CLOCK(): GAMMAINT; (*Clock. Returns the current CPU clock reading in milliseconds. Intervalls are system dependent. *) BEGIN RETURN(GAMMAINT(ClocK())); END CLOCK; PROCEDURE COMP(a,L: LIST): LIST; (*Composition. a is an object. L is a list. Returns the composition of a and L. *) VAR M: LIST; m: INTEGER; BEGIN m:=sigblock(SigMask(SIGUSR1)); (* block SIGUSR1 *) (*1*) (*Is AVAIL empty? *) IF AVAIL = SIL THEN GC() END; (*2*) (*Get new cell. *) M:=AVAIL; AVAIL:=RED(M); (*3*) (*Store a and L. *) SFIRST(M,a); SRED(M,L); m:=sigsetmask(m); (* restore old signal mask *) RETURN(M); (*6*) END COMP; PROCEDURE DEQUE(L: LIST): LIST; (*Dequeue. L is a non empty queue representing list. Returns a, the first object from the queue. L is updated. *) VAR a, M, MP: LIST; BEGIN (*1*) (*Get a. *) M:=RED(L); ADV(M,a,MP); (*2*) (*Update L. *) IF MP = SIL THEN SFIRST(L,L) END; SRED(L,MP); RETURN(a); (*3*) END DEQUE; PROCEDURE ENQUE(a,L: LIST); (*Enqueue. a is an object. L is a queue representing list. Appends a to the quque L. *) VAR M, MP: LIST; BEGIN (*1*) (*Compose tail. *) M:=COMP(a,SIL); (*3*) (*Update queue. *) MP:=FIRST(L); SRED(MP,M); SFIRST(L,M); (*4*) END ENQUE; PROCEDURE NEWQUE(): LIST; (*New Queue. Returns a new empty queue. *) VAR M: LIST; BEGIN (*1*) (*Compose anchor. *) M:=COMP(0,SIL); (*2*) (*Set pointer to last. *) SFIRST(M,M); RETURN(M); (*4*) END NEWQUE; PROCEDURE EMPTYQUE(M: LIST): BOOLEAN; (*Empty Queue. Tests if a queue is empty. *) VAR t: BOOLEAN; BEGIN (*1*) (*Test reductum of anchor. *) t:=( RED(M) = SIL ); RETURN(t); (*4*) END EMPTYQUE; PROCEDURE GETLONGINT(A: LONGINT): LONGINT; (*GET A LONG INTEGER FROM SPECIFIED ADDRESS. REGARDELESS IF ADDRESS IS ON A WORD BOUNDARY. *) VAR AL: LONGINT; XP, YP: POINTER TO BYTE; EINZ: ADDRESS; BEGIN (*1*) (*Initialize*) XP:=ADR(AL); YP:=ADDRESS(A); EINZ:=ADDRESS(1); (*2*) (*Copy bytes*) (*OVERLAY WITH VARIABLE ALLIGNED ON CORRECT BOUNDARY*) XP^:=YP^; (*1. BYTE*) XP:=ADDRESS(XP)+EINZ; YP:=ADDRESS(YP)+EINZ; XP^:=YP^; (*2. BYTE*) XP:=ADDRESS(XP)+EINZ; YP:=ADDRESS(YP)+EINZ; XP^:=YP^; (*3. BYTE*) XP:=ADDRESS(XP)+EINZ; YP:=ADDRESS(YP)+EINZ; XP^:=YP^; (*4. BYTE*) (*3*) (*Finish.*) RETURN(AL); (*4*) END GETLONGINT; PROCEDURE GC(); (*Garbage collection. All list cells accessible from stack are marked. Then a new available cell list is formed from the unmarked cells and the marks are removed. If gcm=1 a report is written on ounit. If the number of reclaimed cells is no more than nu/rho then a message is written on munit and a stop occurs. *) VAR CSTACK, BS, ES: GAMMAINT; a, I, J, K, L, LP, T, N, T1, I1, I2, I3: LIST; m: INTEGER; (* CSTACK must be first, m last variable in declaration, to get correct stack position *) BEGIN (*1*) (*Initialize and information. *) T1:=CLOCK(); m:=sigblock(SigMask(SIGUSR1)); (* block SIGUSR1 during gc *) IF GCM = 1 THEN ERROR(spotless,"Garbage collection ..."); (*TEST SysInfo; Consistence; TEST*) END; (* CSTACK:=GAMMAINT(getstck())+stackoff; *) BS:=SIL; ES:=SIL; AVAIL:=SIL; marks:=0; (*2*) (*Mark cells accessible from Globalvars list. *) LP:=Globalvars; WHILE LP <> SIL DO ADV(LP,I,LP); a:=GETLONGINT(I); MARK(a); END; LP:=Globalvars; IF LP <> SIL THEN MARK(LP) END; (* Mark itself. *) (*4*) (*Mark cells accessible from global variables. *) (* I1:=GAMMAINT(BasePageAddress^.BssBase); I3:=I1+GAMMAINT(BasePageAddress^.BssLen); MARKRANGE(I1,I3); *) (*5*) (*Mark cells accessible from current stack, last mark ! *) IF ADR(CSTACK) < STACKEND THEN (* Stack grows to smaller adresses *) IF ADR(CSTACK) > ADR(m) THEN CSTACK := GAMMAINT(ADR(CSTACK))+4; ELSE CSTACK := GAMMAINT(ADR(m))+4; END; MARKRANGE(CSTACK,GAMMAINT(STACKEND)); ELSE (* Stack grows to greater adresses *) IF ADR(CSTACK) < ADR(m) THEN CSTACK := GAMMAINT(ADR(CSTACK))-4; ELSE CSTACK := GAMMAINT(ADR(m))-4; END; MARKRANGE(GAMMAINT(STACKEND),CSTACK); END; (*6*) (*Reclaim unmarked cells.*) N:=0; I:=NUP-Csize; K:=Csize; WHILE I >= K DO J:=BETA+I; LP:=RED(J); IF LP > 0 THEN SRED(J,AVAIL); AVAIL:=J; (*DEBUG*) SFIRST(J,0); (*GUBED*) N:=N+1; ELSE SRED(J,-LP) END; I:=I-Csize; END; (*7*) (*Increment counters.*) T:=CLOCK()-T1; TAU:=TAU+T; GCC:=GCC+1; GCCC:=GCCC+N; (*8*) (*Optional report.*) (*TEST WS("end of Reclaim."); WL; Consistence; TEST*) IF GCM = 1 THEN WS(" "); WI(N); WS(" cells, "); WI(T); WS(" milliseconds."); (*Escape;*) ERROR(spotless,"... GC completed."); END; m:=sigsetmask(m); (* restore old signal mask *) (*9*) (*Stop ? *) IF N > (NU DIV RHO) THEN toview:=0; RETURN END; toview:=toview+1; IF (toview > tomax) OR (N < rhomin) THEN ERROR(confusion,"Garbage Collection: No free cells reclaimed."); ELSE ERROR(fatal,"Garbage Collection: Too few cells reclaimed."); END; (*0*) END GC; PROCEDURE InitSTOR(n: GAMMAINT); (*Initialize storage system. n is the number of requested kilo bytes. *) VAR i, j, k: GAMMAINT; s, s1: tString; sa: ARRAY[0..50] OF CHAR; BEGIN (*2*) (*Set parameters and message. *) RHO:=10; TAU:=0; GCC:=0; GCCC:=0; GCM:=1; (* WS("InitSTOR, n= "); WI(n); WL; *) IF GCM = 1 THEN IntToString(n,s); ArrayToString("Storage initalization (",s1); Concatenate(s1,s); ArrayToString(" kB) ...",s); Concatenate(s1,s); StringToArray(s1,sa); ERROR(spotless,sa); END; Lsize:=TSIZE(LIST); Csize:=2*Lsize; BETA:=MASEXP(2,29); BETA1:=BETA-Lsize; SIL:=BETA; TAU0:=CLOCK(); toview:=0; (*3*) (*Allocate space for cells and processes. *) n:=n*1024; NU:=n DIV Csize; NUP:=NU*Csize; ALLOCATESPACE(SPACE,NUP); IF SPACE = NIL THEN AVAIL:=BETA; ERROR(confusion,"No Storage Available."); RETURN END; (*5*) (*Initialize range pointers. *) SPACEEND:=SPACE+ADDRESS(NUP); NU:=NUP DIV Csize; IF NU <= 0 THEN AVAIL:=BETA; ERROR(confusion,"No Storage Available."); RETURN END; BETA2:=BETA+NUP; SPACEB:=GAMMAINT(SPACE)-BETA; SPACEB1:=GAMMAINT(SPACE)-BETA1; (*6*) (*Create available cell list. *) AVAIL:=BETA+Csize; i:=Csize; k:=NUP-Csize; WHILE i <= k DO j:=BETA+i; SRED(j,j+Csize); (*DEBUG*) SFIRST(j,0); (*GUBED*) i:=i+Csize; END; SRED(j,SIL); (*7*) (*Initialize process work list to current stack. *) Globalvars:=SIL; Tstack:=STACKEND-proclen; Tstack:=Tstack+stackOK; (*8*) (*TEST WS("Module MASSTOR initialized."); WL; SysInfo; TEST*) IF GCM = 1 THEN ERROR(spotless,"... completed."); END; (*8*) END InitSTOR; PROCEDURE Consistence; (*Check consistency of cell space. *) VAR n, I, J, K, L, LP: LIST; BEGIN (*1*) (* initialize *) n:=0; WL; WS("Cell consistence check ..."); WL; I:=NUP-Csize; K:=Csize; (*2*) (* consistency check *) WHILE I >= K DO J:=BETA+I; LP:=RED(J); L:=FIRST(J); IF (LP < BETA) OR (BETA2 <= LP) THEN n:=n+1; WS("invalid reductum at "); WI(J); WS(" contents "); WI(L); WS(" "); WI(LP); WL; END; IF (L < -BETA) OR (BETA2 <= L) THEN n:=n+1; WS("invalid first at "); WI(J); WS(" contents "); WI(L); WS(" "); WI(LP); WL; END; I:=I-Csize; END; (*3*) (* message *) WI(n); WS(" invalid value(s)."); WL; (*7*) END Consistence; PROCEDURE INV(L: LIST): LIST; (*Inverse. L is a list. The inverse of L is returned. The list L is modified. *) VAR M, MP, MPP: LIST; BEGIN (*1*) M:=BETA; MP:=L; WHILE MP <> SIL DO MPP:=RED(MP); SRED(MP,M); M:=MP; MP:=MPP; END; RETURN(M); (*4*) END INV; PROCEDURE LENGTH(L: LIST): GAMMAINT; (*Length. L is a list. Returns length(L). *) VAR LP: LIST; n: GAMMAINT; BEGIN (*1*) n:=0; LP:=L; WHILE LP > SIL DO LP:=RED(LP); n:=n+1; END; RETURN(n); (*4*) END LENGTH; PROCEDURE LIST1(a: LIST): LIST; (*List, 1 element. a is an object. L is the list (a). *) VAR L: LIST; BEGIN (*1*) L:=COMP(a,SIL); RETURN(L); (*4*) END LIST1; PROCEDURE LISTVAR(VAR L: LIST); (*List variable. L is a list. The address of L is made accessible to the garbage collector. *) VAR s: GAMMAINT; BEGIN (*1*) s:=GAMMAINT(ADR(L)); Globalvars:=COMP(s,Globalvars); (*2*) END LISTVAR; PROCEDURE MARK(L: LIST); (*Mark. L is a non-null list such that every cell of L which is accessible from an already marked cell of L is itself already marked. Mark marks every unmarked cell of L. *) VAR AL, LP, LS: LIST; BEGIN (*1*) (*check if in range. *) IF (L <= BETA) OR (BETA2 <= L) OR ((L MOD Csize) <> 0) THEN RETURN END; (*2*) (*probably a list pointer. *) LP:=L; (*TEST WS("MARK = "); WH(L); WS(". "); TEST*) WHILE LP <> SIL DO LS:=RED(LP); IF (LS < BETA) OR (BETA2 <= LS) THEN RETURN; END; (*IF LS < 0 THEN RETURN; END;*) SRED(LP,-LS); AL:=FIRST(LP); (*TEST marks:=marks+1; TEST*) MARK(AL); LP:=LS; END; (*4*) END MARK; PROCEDURE MARKRANGE(B, E: LIST); (*Mark range. Mark all lists in range from B to E. *) VAR I, E1, a: LIST; BEGIN (*1*) (*initialize. *) I:=B; E1:=E-Lsize; (*TEST WS("marking in range "); WI(I); WS(" to "); WI(E1); WL; TEST*) (*2*) (*mark any lists. *) WHILE I <= E1 DO a:=GETLONGINT(I); (* IF (a > BETA) AND (BETA2 > a) AND ((a MOD Csize) = 0) THEN WS("I, a = "); WH(I); WS(", "); WH(a); (*WS(", len "); WI(LENGTH(a));*) WL; END; *) MARK(a); (* Must step by 1 because of CHARs and BYTes. *) I:=I+1; END; (*TEST WS("marks = "); WI(marks); WS(" end of mark range."); WL; TEST*) (*4*) END MARKRANGE; PROCEDURE DumpStack; (*Dump Stack. Dump objects on current stack. *) VAR I, E, a: LIST; c: CHAR; BEGIN (*1*) (*initialize. *) I:=GAMMAINT(getstck()); E:=I+1000; WL; WS("Stack Dump: "); WL; (*2*) (*dump objects. *) WHILE I <= E DO a:=GETLONGINT(I); WI(I); WS(" = "); DumpObj(a); WL; WS("(e)nd, <ENTER> ? "); c:=InChar(); IF (c = 'e') OR (c = 'E') THEN RETURN END; (* Must step by 1 because of CHARs and BYTes. *) I:=I+1; END; (*4*) END DumpStack; PROCEDURE DumpObj(L: LIST); (*Dump Object. The object L is dumped. *) VAR AL, LP, LS, i: LIST; BEGIN (*1*) (*check if atom or in range to be list. *) IF (L <= BETA) OR (BETA2 <= L) THEN WI(L); RETURN END; IF ((L MOD Csize) <> 0) THEN WI(L); RETURN END; (*2*) (*probably a list pointer. *) LP:=L; i:=0; WS("("); WHILE LP <> SIL DO LS:=RED(LP); IF (LS < BETA) OR (BETA2 <= LS) THEN RETURN; END; (*IF LS < 0 THEN RETURN; END;*) AL:=FIRST(LP); i:=i+1; IF i >= 5 THEN i:=0; WL END; DumpObj(AL); IF LS <> SIL THEN WS(", ") END; LP:=LS; END; WS(")"); (*4*) END DumpObj; PROCEDURE SUBLIST(A,B: LIST): BOOLEAN; (*Sub-list, check if A is equal to some reductum of B. Returns TRUE, if the test is true, else FALSE. *) VAR BP: LIST; t: BOOLEAN; BEGIN (*1*) (*Initialize*) BP:=B; t:=FALSE; WHILE BP <> SIL DO IF A = BP THEN t:=TRUE; RETURN(t); END; BP:=RED(BP); END; (*2*) (*Finish.*) RETURN(t); (*3*) END SUBLIST; PROCEDURE TIME(): GAMMAINT; (*Time. Returns the CLOCK minus the garbage collection time TAU. Intervalls are system dependent. *) VAR T: GAMMAINT; BEGIN (*1*) T:=CLOCK(); T:=T-TAU; RETURN(T); (*2*) END TIME; (* Test procedures *) PROCEDURE SysInfo; (*System Information. *) VAR a, b, bp, i, c: GAMMAINT; BEGIN (*1*) (*general info. *) WI(NU); WS(" CELLS IN SPACE."); WL; WS("NUMBER OF BYTES ALLOCATED = "); WH(NUP); WL; WS("ADDRESS OF ALLOCATED AREA = "); WH(GAMMAINT(SPACE)); WL; WS("BETA = "); WH(BETA); WL; WS("BETA2 = "); WH(BETA2); WL; (* (*2*) (*global data info. *) b:=GAMMAINT(BasePageAddress^.BssBase); bp:=GAMMAINT(ADDRESS(b)+ADDRESS(BasePageAddress^.BssLen)); WS("BSS START = "); WI(b); WL; WS("BSS END = "); WI(bp); WL; *) (*3*) (*storage info. *) WS("SPACE BEGIN = "); WH(GAMMAINT(SPACE)); WL; WS("SPACE END = "); WH(GAMMAINT(SPACEEND)); WL; (*4*) (*stack info. *) STACK:=ADDRESS(getstck()); WS("STACK END = "); WH(GAMMAINT(STACKEND)); WL; WS("STACK A1 = "); WH(GAMMAINT(STACK)); WL; (*5*) (*register info. *) a:=GAMMAINT(gettoc()); WS("TOC A2 = "); WH(a); WL; (*7*) END SysInfo; PROCEDURE WI(a: GAMMAINT); (*Utility. *) BEGIN (*1*) WriteI(a,1); (*Dependes on MASELEM. *) (*4*) END WI; PROCEDURE WH(a: GAMMAINT); (*Utility. *) BEGIN (*1*) WriteI(a,1); WriteS(" "); WriteN(a,1,16); (*Dependes on MASELEM. *) (*4*) END WH; PROCEDURE WS(s: ARRAY OF CHAR); (*Utility. *) BEGIN (*1*) WriteS(s); WriteFlush; (*9*) END WS; PROCEDURE WL(); (*Utility. *) BEGIN (*1*) WriteNl; WriteFlush; (*4*) END WL; PROCEDURE InChar(): CHAR; VAR c: CHAR; BEGIN (*1*) c:=ReadC(); IF ORD(c) <= 10 THEN c:=ReadC() END; RETURN(c); (*2*) END InChar; PROCEDURE Escape; VAR c: CHAR; BEGIN (*1*) c:=ReadC(); IF ORD(c) <= 10 THEN c:=ReadC(); END; IF ORD(c) = 27 THEN ERROR(severe,"ESC key pressed.") END; (*2*) END Escape; (*TEST PROCEDURE Summary(); (*MASSTOR Summary. *) VAR L, ML, NL, TL: LIST; c: INTEGER; BEGIN (*1*) WL; (*2*) ML:=GCC; NL:=GCCC; TL:=TAU; WI(ML); WS(" garbage collections, "); WI(NL); WS(" cells reclaimed, in "); WI(TL); WS(" milliseconds."); WL; (*3*) NL:=CELLS(); TL:=TIME()-TAU0; WI(NL); WS(" cells used, in "); WI(TL); WS(" milliseconds."); WL; (*4*) TL:=CLOCK()-TAU0; WI(NU); WS(" cells allocated. "); WS("Total time "); WI(TL); WS(" milliseconds."); WL; (*5*) END Summary; PROCEDURE TestSTOR(); (*Test Storage. *) VAR L: LIST; i, a, b: GAMMAINT; BEGIN (*1*) L:=SIL; b:=NU-1000; FOR i:=1 TO b DO L:=COMP(i,L); END; IF LENGTH(L) <> b THEN WS("Error in MASSTOR."); WL; END; i:=b; WHILE L <> SIL DO ADV(L,a,L); IF i <> a THEN WS("Error in MASSTOR."); WL; WI(i); WS(" "); WI(a); WS(" "); WI(L); WL; END; i:=i-1; END; WS("Test 1 in MASSTOR ended."); WL; (*2*) L:=SIL; FOR i:=1 TO b DO L:=COMP(i,L); END; i:=b; WHILE L <> SIL DO ADV(L,a,L); IF i <> a THEN WS("Error in MASSTOR."); WL; WI(i); WS(" "); WI(a); WS(" "); WI(L); WL; END; i:=i-1; END; WS("Test 2 in MASSTOR ended."); WL; (*4*) END TestSTOR; TEST*) (* MASSTOR module initialization. *) PROCEDURE SetSTACKEND(); (* Set STACKEND. The global variable STACKEND is set.*) VAR s: ADDRESS; BEGIN s:=ADR(s); STACKEND:=s END SetSTACKEND; BEGIN (*1*)(* STACKEND:=getstck();*) (*remember stack address*) SetSTACKEND; (*2*) InitSTOR(KBCell); (*4*) (*TEST eh:=ErrorHandler(TestSTOR); WS("nach error handler 1"); WL; SysInfo; eh:=ErrorHandler(TestSTOR); WS("nach error handler 2"); WL; SysInfo; Summary; TEST*) END MASSTOR. (* -EOF- *)