*DECK MGBGCLT 
USETEXT NIPDEF
USETEXT AT
USETEXT FREETAB 
USETEXT PARAMP
USETEXT PT
USETEXT STATTAB 
USETEXT STATTB2 
USETEXT TNT 
      PRGM MGBGCLT;          # GARBAGE COLLECTION 
                               MOVE BUFFER IN USE TO LOWER ADDRESSES   #
  
 STARTIMS;
 #
*1DC  MGBGCLT 
*     1. PROC NAME           AUTHOR              DATE 
*          MGBGCLT           Y. HSIEH            77/02/10 
* 
*     2. FUNCTIONAL DESCRIPTION.
*        THIS ROUTINE IS RESPONSIBLE FOR GARBAGE COLLECTING.
*        WHEN IT IS CALLED BY XEXEC WHEN THE NUMBER OF BUFFERS AND
*        SIZE OF FREE BUFFER CHAIN EXCEED THE LIMITS DEFINED BY 
*        INSTALLATION.
* 
*     3. METHOD USED. 
*        SCAN ALL THE FREE BUFFERS IN FREE CHAIN. 
*        IF FOUND MOVABLE BUFFERS FOLLOWED IT, THEN MOVE ALL THE
*        MOVABLE BUFFERS TO A LARGE ENOUGH FREE BUFFER AT LOWER 
*        ADDRESS BY CALLING COMPASS ROUTINE OMOVE.
*        AFTER MOVE, CALL MAJPTR TO ADJUST POINTERS, AND CALL MRELS 
*        TO RELEASE UNUSED SPACE TO FREE CHAIN. 
*        AFTER ALL THE FREE BUFFERS HAVE BEEN CHECKED,
*        SEE WHETHER THE LAST BUFFER SIZE EXCEEDS 1000B WORDS, IF SO
*        RELEASE ALL THE CORE BUT 500B WORDS TO SYSTEM. 
* 
*     4. ENTRY PARAMETERS.
*          FRENOFB           INITIAL NUMBER OF EMPTY BUFFERS
*          PARAMP1           = 0 NO PRU BUFFER SHOULD BE MOVED. 
*                            = 1 PRU BUFFER IS ALLOWABLE FOR MOVING.
* 
*     5. EXIT PARAMETERS. 
*          MTIM              =0,INITIALIZES ELAPSED TIME FOR REDUCING FL
* 
*     6. COMDECKS CALLED AND SYMPL TEXTS USED.
*        FREETAB   NIPDEF    OSIZE     STATTB2
*        AT                  APPLICATION TABLE
*        STATTAB             STATISTICS TABLE 
*        TNT                 TERMINAL NODE TABLE
* 
*     7. ROUTINES CALLED. 
*          MACQ              GET FREE BUFFER
*          MAJPTR            ADJUST BUFFER POINTERS AFTER MOVE
*          MRELS             RELEASE BLOCK TO FREE POOL 
*          OCFL              MAKE MEMORY REQUEST TO SYSTEM
*          OMOVE             COMPASS FAST MEMORY MOVE ROUTINE 
*          OTIME             GET SYSTEM RTIME 
*          XTRACE            RECORD CALL
*          MCLRIL            CLEAR INTERLOCK
*          MSETIL            REQUEST INTERLOCK
* 
*     8. DAYFILE MESSAGES.   NONE 
* 
*        W A R N I N G - THE TOTAL SIZE OF THE GARBAGE COLLECTION 
*                        ROUTINES (MAJPTR, MCHKPTR, MGBGCLT, AND
*                        MDRPTR) WITH THE DELAY OPTION TURNED ON
*                        CAN NOT EXCEED THE PRIMARY AND SECONDARY 
*CALL OSIZE 
* 
*        THIS OVERLAY IS CALLED BY XEXEC. 
* 
 #
 STOPIMS; 
# 
 PARAMETERS 
                NONE
# 
# 
 EXTERNAL VARIABLES 
# 
 XREF BEGIN 
      PROC MAJPTR;           # ADJUST BUFFER PTRS AFTER MOVE           #
      PROC MACQ;             # GET FREE BUFFER                         #
      PROC MCLRIL;           # CLEAR INTERLOCK                         #
      PROC MRELS;            # RETURN BLOCK TO FREE POOL               #
      PROC MSETIL;           # REQUEST INTERLOCK                       #
      PROC OCFL;             # MAKE MEMORY REQUEST TO OP SYSTEM        #
      PROC OMOVE;            # COMPASS FAST MEMORY MOVE ROUTINE        #
      PROC OTIME;            # GET SYSTEM RTIME                        #
      PROC XTRACE;           # RECORD CALL                             #
      LABEL RJMAIN;          # RETURN ADDRESS IN OVLCALL               #
      END 
# 
 LOCAL VARIABLES
# 
      ITEM FLAG B;           # TRUE IF A FUNCTION LIST EXISTS          #
      ITEM FREBUF;           # LOCATION OF CURRENT FREE BUFFER         #
      ITEM INITNOB;          # INITIAL NO OF EMPTY BUFFERS             #
      ITEM INTERLOCK B;      # TRUE IF INTERLOCK PIP REQUIRED          #
      ITEM RELBUF;           # FWA OF BUFFER RELEASE TO FREE CHAIN     #
      ITEM TEMP;             # TEMPORARY WORD                          #
      ITEM TEMP1;            # TEMPORARY WORD                          #
      DEF  RTBUF  #2#;       # REDUCE  FL IF GQ 640 WORDS FOR RTBUF SEC#
  
      CONTROL IFEQ STAT,1;
        ARRAY STIME P(1);    # RTIME BUFFER FOR STARTING TIME          #
          BEGIN 
          ITEM SSECS U(0,00,24); # STARTING TIME IN SECONDS            #
          ITEM SMILS U(0,24,36); # STARTING TIME IN MILLESECONDS       #
          END 
        ARRAY ETIME P(1);    # RTIME BUFFER FOR ENDING TIME            #
          BEGIN 
          ITEM EMILS U(0,24,36); # ENDING TIME IN MILLESECONDS         #
          END 
  
        ITEM STTEMP;         # TEMPORARY STATISTICS VARIABLE           #
      CONTROL FI; 
  
#**********************************************************************#
      BEGIN 
      CONTROL IFEQ DEBUG,1; 
        XTRACE("MGBGC") ; 
      CONTROL FI; 
  
      CONTROL IFEQ STAT,1;   # STATISTICS ON                           #
# 
        DETERMINE AVG NO OF EMPTY BUFFERS AND WORDS 
# 
        OTIME(STIME);                   # GET CURRENT RTIME            #
        TEMP = SSECS[0] - TIMEGBG;  # ELAPSED TIME SINCE LAST CALL     #
        ST$FWT = ST$FWT + TEMP*FRESFB[0]; # TIME * NO OF FREE WORDS    #
        ST$FBT = ST$FBT + TEMP*FRENOFB[0]; # TIME * NO OF FREE BUFS    #
        TIMEGBG = SSECS[0];             # RESET TIMER FOR NEXT CALL    #
# 
        STORE INITIAL NO OF FREE WORDS AND BUFFERS
# 
        INITNOB = FRENOFB[0]; # INITIAL NO OF EMPTY BUFFERS            #
      CONTROL FI; 
  
  
# 
 STEP 1           SCAN FREE CHAIN FOR FOLLOWING MOVABLE BUFFERS 
# 
  
      P<FREEBUF> = 0; 
      REDUCEFL = 0; 
  
      FOR FREBUF = LOC(FREFBFP[0])
      DO
  
        BEGIN 
        FREBUF = FRBFBFP[FREBUF];       # LOCATION OF NEXT FREE BUFFER #
  
NEXT: 
        IF FREBUF NQ LOC(FREFBFP[0])    # REACH END OF FREE CHAIN      #
        THEN
  
          BEGIN 
          MOLD = FREBUF + FRBBS[FREBUF];  # FWA OF BUF FOLLOW FREE BUF #
          IF MOLD LS CTLSLWA
          THEN
            BEGIN 
            MSIZE = 0;                  # SIZE OF MOVABLE BLOCK        #
            FLAG = FALSE;               # PRESET TO NO FUNCTION LIST   #
                                        # BUFFER WITHIN MOVABLE BLOCK  #
  
            INTERLOCK = FALSE;  # NO INTERLOCK REQUIRED                #
            FOR TEMP = MOLD WHILE TEMP LS CTLSLWA 
            DO
              BEGIN 
              IF FRBMV[TEMP]
                  OR FRBID[TEMP] EQ 0 
                  OR (FRBID[TEMP] EQ PRUBIDVALUE AND
                      NOT PRUMOVE)
              THEN
                BEGIN 
                IF MSIZE EQ 0           # NO MOVABLE BUF FOUND         #
                THEN
                  TEST FREBUF;
                ELSE
                  GOTO FIND;
                END 
  
              ELSE
                BEGIN 
                MSIZE = MSIZE + FRBBS[TEMP];# INCREASE MOVE SIZE       #
                IF FRBID[TEMP] EQ FLIDVALUE 
                THEN
                  FLAG = TRUE;          # FUNCTION LIST BUFFER EXISTS  #
                IF FRBID[TEMP] EQ TNTIDVALUE OR 
                   FRBID[TEMP] EQ NCNTIDVALUE OR
                   FRBID[TEMP] EQ PCNBIDVALUE  OR 
                   FRBID[TEMP] EQ PRUBIDVALUE OR
                  FRBID[0] EQ PRUSPECID OR
                   FRBID[TEMP] EQ LLCBIDVALUE 
                THEN
                  INTERLOCK = TRUE;  # INTERLOCK REQUIRED FOR MOVE     #
                TEMP = TEMP + FRBBS[TEMP];  # FWA OF NEXT BUFFER       #
                END 
  
              END 
  
# 
 STEP 2           LOOK FOR A BIG ENOUGH FREE BLK TO MOVE TO 
# 
  
FIND: 
            FOR MNEW = LOC(FREFBFP[0])
            DO
              BEGIN 
  
              MNEW = FRBFBFP[MNEW]; 
              IF MNEW EQ FREBUF OR FRBBS[MNEW] GQ MSIZE 
              THEN
                GOTO FOUND; 
  
              END 
  
FOUND:  
            IF MNEW EQ FREBUF # REACHED CURRENT FREE BUFFER            #
              AND (( TEMP LS CTLSLWA  # NEXT BUFFER EXISTS             #
              AND FRBMV[TEMP] ) # AND IS NON-MOVABLE                   #
              OR FLAG ) # NEXT BUFFER IS A FUNCTION LIST BUFFER        #
            THEN # OMIT THIS FRUITLESS MOVE                            #
              TEST FREBUF;
  
# 
 STEP 3           UPDATE FREETAB INFO AND DELINK FREE BLK FOUND 
                  MOVE BLK TO IT AND RELEASE EXTRA SPACE
# 
            IF MNEW NQ FREBUF 
            THEN
              MACQ(MSIZE, MNEW, FALSE); 
            ELSE
              BEGIN 
              TEMP = FRBBS[MNEW]; 
              MACQ(TEMP, MNEW, FALSE);
              END 
  
            CONTROL IFEQ STAT,1; # STATISTICS ON                       #
              ST$GBWM = ST$GBWM + MSIZE; # INCR CNT OF NO OF WDS MOVED #
            CONTROL FI; 
  
            IF INTERLOCK     # BUF USED BY PIP TO MOVE                 #
            THEN
              MSETIL(0);     # INTERLOCK ALL PIP-S                     #
            OMOVE;                      # MEMORY MOVE                  #
  
            IF MNEW NQ FREBUF           # MOVE TO LOWER ADDR FREE BUF  #
            THEN
              BEGIN 
              RELBUF = MOLD;
              FRBBS[RELBUF] = MSIZE;
              END 
            ELSE
              BEGIN 
              RELBUF = MNEW + MSIZE;
              FRBBS[RELBUF] = TEMP; 
              FREBUF = RELBUF;
              END 
  
            MRELS(RELBUF);
            MAJPTR;                     # ADJUST BUFFER POINTERS       #
            GOTO NEXT;                  # CHECK NEXT FREE BUFFER       #
            END 
  
          END 
  
        GOTO DONE;                      # EXIT FROM LOOP               #
        END 
  
# 
 STEP 4           ALL MOVE DONE, CHECK SIZE OF LAST FREE BLOCK
                  IF MORE THAN 2*RSBUF THEN RELEASE RSBUF TO SYSTEM 
# 
  
DONE: 
      P<AT> = PTAT[0];                  # RESET AT BASED ARRAY POINTER #
      P<TNT> = PTTNT[0];                # RESET TNT BASED ARRAY POINTER#
      MCLRIL;                           # CLEAR NIP/PIP INTERLOCK      #
      CONTROL IFEQ STAT,1;   # STATISTICS ON                           #
# 
        RECORD ANY CHANGES IN NO OF FREE BUFFERS OR WORDS 
# 
        ST$GBGC = ST$GBGC + INITNOB-FRENOFB[0]; 
        OTIME(ETIME);        # GET SYSTEM TIME AFTER GARBAGE COLLECTION#
        STTEMP = EMILS[0] - SMILS[0];  # TIME SPENT IN MOVING BUFFERS  #
        ST$TMG = ST$TMG + STTEMP;  # TOTAL TIME SPENT MOVING BUFFERS   #
        IF ST$LMG LS STTEMP 
        THEN                 # FOUND LARGER TIME INTERVAL MOVING BUFFER#
          BEGIN 
          ST$LMG = STTEMP;   # NEW LARGEST TIME INTERVAL               #
          END 
  
      CONTROL FI; 
  
      IF FREFBBP + FRBBS[FREFBBP] EQ CTLSLWA # NO NONMOVABLE BK AT END #
      THEN
        BEGIN 
        HRL = HRLV3;                    # ASSUME REGULATION LEVEL 3    #
        IF MAXFL - FREFBBP LS BUFLV3
        THEN                            # CRITICAL BUFFER SHORTAGE     #
          BEGIN 
          HRL = HRLV2;                  # BUFFER REGULATION LEVEL 0    #
          IF MAXFL - FREFBBP LS BUFLV2
          THEN                          # SEVERE BUFFER SHORTAGE       #
            BEGIN 
            HRL = HRLV1;                # BUFFER REGULATION LEVEL 1    #
            IF MAXFL - FREFBBP LS BUFLV1
            THEN                        # MODERATE BUFFER SHORTAGE     #
              BEGIN 
              HRL = HRLV0;              # BUFFER REGULATION LEVEL 2    #
              END 
            END 
          END 
  
  
        IF FRBBS[FREFBBP] GQ 2*RSBUF    # LAST FREE BLK TOO BIG        #
        THEN
          BEGIN 
  
          CONTROL IFEQ DELAY,1;         # ASSEMBLE ONLY IF DELAY OPTION#
          IF MTIM NQ 0 AND RTSECS-MTIM GQ RTBUF     # EXCEED ELAPSE TIM#
          THEN
            BEGIN 
            MTIM = 0;                   # RESET ELAPS TIM FOR REDUCE FL#
          CONTROL FI; 
  
  
            CONTROL IFEQ STAT,1; # STATISTICS ON                       #
              ST$FLT = ST$FLT + (SSECS[0] - TIMECFL) * (CTLSLWA/64);
              TIMECFL = SSECS[0];   # RESET TIMER FOR NEXT OCFL CALL   #
            CONTROL FI; 
  
            TEMP1 = (FREFBBP[0]+RSBUF+63)/64*64; # NEW CTLSLWA         #
            TEMP = CTLSLWA - TEMP1; # EXTRA SPACE TO RELEASE           #
            CTLSLWA = TEMP1;
            CONTROL IFEQ STAT,1;       # STATISTICS ON                 #
            ST$FLX   = ST$FLX  + 1;    # INCR NO OF TIMES FL DECREASED #
            ST$FLWX  = ST$FLWX + TEMP; # INCR TOTAL OF WDS DECREASED   #
            CONTROL FI; 
            OCFL(CTLSLWA);             # CHANGE PROGRAM LENGTH         #
  
            FREMFL = FALSE;             # CLEAR NIP REACH MAX FL FLAG  #
            FRESFB = FRESFB - TEMP;     # REDUCE FREE CHAIN SIZE       #
            FRBBS[FREFBBP] = FRBBS[FREFBBP] - TEMP;  # LAST FREE BUF SZ#
  
            CONTROL IFEQ DELAY,1; 
            END 
  
          ELSE
            BEGIN 
            IF MTIM EQ 0
            THEN
              BEGIN 
              MTIM = RTSECS;            # SET ELAPSE TIME FOR REDUCE FL#
              END 
  
            END 
  
          GOTO RJMAIN;
            CONTROL FI; 
  
          END 
  
        END 
  
      CONTROL IFEQ DELAY,1; 
      MTIM = 0;                         # RESET ELAPS TIM FOR REDUCE FL#
      CONTROL FI; 
  
      GOTO RJMAIN;
  
      END 
TERM
